Beacon was the capstone of Palantir's American Tech Fellowship (Frontiers), May to July 2026, built on Foundry. It is a workbench for sourcing boutique advisory firms as acquisition targets, and it is being ported to Postgres and React so it can run anywhere.
What it does
A mandate states an intent: a kind of firm, a geography, an industry, a size cap. On the search page the analyst's facet picks become the interpretation of that intent, and the search yields a candidate universe of firms. Each firm then moves through a six-stage funnel: Discovered, In Review, Outreach, In Talks, and the terminal states Qualified and Rejected.
Between Discovered and a decision sits the enrichment desk. An agent fills in facts about each firm from ranked data sources; the analyst verifies or overrides them, reads the rubric score they imply, and makes the call. Rejections need a written rationale, and those rationales are where the system learns.
The home page is a start-of-day operations page rather than a dashboard: every card and number on it links to the surface that does the work, and it never promises work the linked page does not show.
Enrichment that abstains
Four providers observe each firm, each with its own coverage and error rate, ordered from most to least trusted. The reconciliation step has three outcomes and never picks a winner in a conflict.
| Providers agree | Result |
|---|---|
| No source knows | An abstained finding: the axis stays unknown |
| One value, from one or more sources | A proposed finding, marked high confidence when corroborated or at least 0.8 confident |
| Two or more values | A conflict pair: the two most trusted positions, both low confidence, sharing a conflict group |
An axis a human has already verified is never re-enriched. When the analyst overrides a finding, the agent's finding is marked rejected and the analyst's is inserted as verified, so the accuracy page can compute agreement, override and abstention rates per provider and per axis from the record rather than from memory.
The rubric
Nine axes, each scored 0 to 2, for a maximum of 18. Two models share six axes and differ on three: corporate-finance firms are read on coverage model, services and managing-director experience; capital-solutions firms on balance sheet, services fit and managing-director experience. Tiers are A, B, C or Rejected; an A goes to outreach, a strong B goes to outreach, a C is followed, and a score-based reject goes back to enrichment. Two hard rejects sit above the score: a generalist coverage model or conflicted services on one side, an advisory conflict or a firm that invests its own balance sheet on the other.
One function computes the score. The server persists snapshots with it and the desk previews with it, so the two cannot drift.
Rules grounded in rejections
A rejection carries a rationale. Rationales for firms still in Rejected are clustered into candidate rules of the form axis, operator, threshold, by Claude when it is available and by a keyword heuristic when it is not. A candidate only counts a rejection as support if that firm actually satisfies the predicate, and it needs at least four grounded supporters. Existing rules, including dismissed ones, are never re-proposed. The result is a pending proposed rule that also reports how many firms on the desk it would screen.
Unknown is not a failure. It is the reason the firm is on the desk at all.
Drift
Every terminal decision snapshots the score it was made on. New evidence rescores the firm. A qualified firm drifts on any tier change; a rejected firm drifts only when it improves, because the reason for passing may no longer hold. A rejected firm later acquired by a competitor raises a diverged-outcome event. Review resolves each event by re-engaging the firm, which moves it to Outreach, or by keeping it passed, with a rationale.
The port
| On Foundry | Now |
|---|---|
| Ontology Manager | One schema declaration; the DDL, the repository, API validation and the typed hooks all derive from it |
| Generated SDK and its React hooks | Drop-in hooks with the same names over TanStack Query, so page code changed only its imports |
| Actions | Named actions, each validated and run inside a single transaction |
| Backend | Postgres: in-process PGlite for tests and local work, hosted Postgres in production |
The frontend already calls a small HTTP API and expects a seed; neither exists in the repository yet, so the app does not run end to end today. The Claude clusterer is a type with a heuristic fallback, not a wired client. A pre-publish check fails the build if any file mentions the original employer, the licensed data vendors, the training stack's hosts, or the real firm names from the original data.
Status
The port began on 22 September 2026: fourteen commits so far, fifteen test files with 186 cases running against in-memory Postgres. There are no captures here until the API and seed land and the app runs. When it does, every screenshot will be of generic seed data.