Workflow Engine · ac-python-api · Headhunter pipeline

People Signals

People Signals finds the person worth contacting right now - someone who just changed jobs, was promoted into a buyer role, published thought leadership, or spoke at a relevant event - and scores each by how strongly that signal predicts a reachable, in-market decision-maker for the agency running the search. It runs on the existing headhunter spine plus a signal-extraction and substantiation layer, with a composite score computed in code.

Runtime Headhunter pipelineAnchor company + openScoring deterministic compositeStorage staging-first
ICP + signal typesDiscover · substantiate · score·person_signalsworkflow_run_people
00

What People Signals does

Company Signals finds the company; People Signals finds the person, and the moment. End users are marketing agencies doing cold outreach: account-level intent says "Acme is buying" but not who to call. People Signals surfaces a specific decision-maker because of a career event - a job change, a promotion, a talk - then scores them by how strongly that event predicts a reachable, in-market buyer. The signal is the entry point, not the filter: a five-day-old "just became CMO" beats a CMO who has held the seat six years.

6
Signal types
job change → tenure
2
Discovery anchors
company + open
1
Reused spine
headhunter pipeline
0
LLM-emitted scores
composite in code
KEYThe signal-first bet, at the person grain

A person is worth an agency's attention at the moment a career event creates budget, authority, or a warm door - not because they sit on a static title list. People Signals treats intent as perishable: it discovers dated career events, substantiates them against real evidence, weights them by source trust and freshness, and ranks against the agency's own ICP. It reuses the headhunter machinery wholesale and adds only the signal layer.

01

System design

One People Signals search is a closed loop, mirroring Company Signals at the person grain. A brief leaves the frontend, the API opens a run on the Claude Agents Platform, which discovers and resolves signal-rich people then fans out per person to the enrichment agent - enrich the person, resolve and enrich the new company, and write the facts back. Results return along two paths: per-field patch frames stream live to fill the table (emit → run-SSE → apply) while resolved cells persist durably to workflow_run_people and the people intelligence DB. A later search skips enrichment for any person already cached. Follow the arrows, or click any stage to trace it.

POST /workflows/runbrief · ICP · offerkick off runhost-side toolsfan out per personone pipeline eachresolved cellsprofile + companyper-field framesrun SSE · keyed by idpersist · paralleldurable rowsfinish · final readworkflow_run_people1Frontendlive cell tableac-frontend2API + run serviceFastAPI · workflow engineac-python-api3Discovery + scorestrategist · signals · resolveClaude Agent SDK4Enrichment agentfan-out per personenrichment agent5Frame emitterper-field patch framesSSE · emit6Run-SSE to cell tablefrontend applies framesSSE · apply7Databasedurable write-backSupabase
02

Agent workflow

The detailed breakdown of one search as a tiered map - one colour per repo, top to bottom along the data path. Search career-event signals from the public sources; once found, the run fans out per person to the enrichment agent (enrich the person, then resolve and enrich the new company); each enrichment writes back to the intel layer with provenance; then per-field frames stream to the live table. Hover any container for what it owns, or trace one person down the happy path.

Claude Agent SDKac-python-apiac-backendac-frontendexternalsyncasync
Signal sources
Discovery — search the sources
Resolve + dedup (host code)
Enrichment fan-out — per person
Intelligence write-back (Postgres)
Composite score (host code)
Save-back + frame stream
Surface
03

The pipeline

A deterministic skeleton over the headhunter spine; discovery is the one agentic stretch and it is hard-capped. Switch the discovery anchor, then play the run or click any node to inspect it.

Answers "Who at my target companies just became worth contacting?"

1

Query build

deterministic
deterministic

Expands the ICP (titles, seniority, geo) and the chosen signal types into Exa / Parallel queries per company. No LLM - reuses the headhunter query_builder.

ICP + companies + signal typesper-company query set
  • title expansion (CMO -> full forms)
  • signal templates per type
  • recency window baked in
Why reuse headhunter and not build fresh: the per-company orchestrator, Exa / Parallel fan-out, extraction batching, Firecrawl, and Hunter.io email already find people well. People Signals adds exactly one new idea - emit and substantiate the dated career event alongside the person - and a scoring layer. Everything else is the proven spine.
04

Signal-first queries

Headhunter queries match a filter ("CMOs at these 50 companies"). People Signals queries hunt the event. Each signal type expands into its own templates - pick one to see what the query builder emits. Placeholders fill from the ICP and the company set.

queries for job change
  • "{name}" appointed / named {title} 2026
  • new {title} at {company}
  • {company} welcomes {title}
  • "joined {company} as {title}"
The recency window is baked into every template - the builder appends the year and date-bounds the search so a stale event never surfaces as fresh. Open-anchor runs drop the {company} placeholder and cast across the ICP.
05

Composite scoring

The people score is computed in code - no override-rule prompt, no LLM-emitted number. Compose a few signals and watch it move; each weight here is a tunable constant in the real config. ICP fit is the headhunter qualifier; it gates hard, so a great signal on the wrong person still ranks low.

9/10
reach out now
fit × Σ( type × source × recency )
Σ raw 1.50× fit 1.30= adj 1.94
presets
ICP fit
0.90
0.59

Curve is illustrative of the deterministic formula - exact constants are tuned at build from eval data. The point: the number is reproducible code, not model judgement.

06

Signal taxonomy

v1 seed weights, tuned to outreach timing: events that create a fresh mandate or a warm door rank highest. They share the company SignalType enum - JOB_CHANGE, PROMOTION, TENURE are added; CONTENT, LEADERSHIP, EVENT are reused. Pick the agency's offer and watch the weights re-rank.

job change 0.90

Just joined or left a company - the warm-intro window. Strongest people signal for outreach timing. JOB_CHANGE

promotion 0.85

Promoted into a buyer role = fresh mandate, new budget authority, a reason to reach out now. PROMOTION

new decision-maker 0.80

Became a new CMO / VP at a target account. Reuses the company LEADERSHIP signal at the person grain. LEADERSHIP

thought leadership 0.60

Published or actively posting on a relevant topic = demonstrated focus and a personalization hook. CONTENT

speaking / event 0.50

Keynote, podcast, or conference slot. Timely, public, and easy to reference in the first line. EVENT

tenure milestone 0.45

Hit a ripe-to-move window (~2yr in seat). Soft signal, best stacked with another. TENURE

07

Reuse & enrichment

Almost nothing here is new. People Signals is the headhunter pipeline with a signal layer - the table maps what is reused as-is against the thin slice that is added.

StageReused as-isAdded for signals
Query buildquery_builder, title / geo expansionsignal-type query templates
Discoveryper-company orchestrator, PeopleExaTools, Parallel.aievent-led queries, dual anchor
Extractiontool-less batched extractionemit (person, signal) pairs
EnrichmentFirecrawl, Hunter.io, company-matchnothing
Trustsignal_substantiation.pypeople evidence patterns
Qualifytwo-pass qualifier -> ICP fitcomposite signal blend
PersistWorkflowRunPeopleServiceperson_signals + workflow_run_person_id
!Substantiate before you trust the event

LLMs will happily invent a job change from a vague sentence. Every event-class signal must pass a deterministic evidence check - the source text has to contain the move ("joined / appointed / named as", "promoted to") - or it is downgraded to a plain NEWS mention that cannot carry the score. This is the company substantiation gate, extended with people patterns.

08

Staging & storage

Discovery is noisy, so people land in staging first - exactly like Sonar prospects - and promote to CRM on review. This is also what finally fills the person_signals table, which has shipped empty, reserved for this work.

workflow_run_peoplestaging

Net-new discovered people land here first, in a review state. No unreviewed writes hit CRM - mirrors Sonar prospect staging.

signalsglobal

The dated career event: type · signal_date · source_url · snippet · source_agent. A new workflow_run_person_id column tags each signal to the staged person, mirroring the existing signals.workflow_run_company_id.

person_signalsglobal

The signal-to-person join. Built at promotion by looking up signals on workflow_run_person_id - exactly how company_signals is created from signals at add-to-CRM. Ships empty today, reserved for this.

crm_peopleper-org

On promote-to-CRM, the staged person becomes a CRM person and the person_signals join is written against person_id - mirrors _link_staging_signals_to_crm.

09

Design decisions

D1 · Anchor

Both, company-anchored primary

Per-company orchestrator hunts events at your CRM / Sonar list for precision; open signal search adds reach beyond it. Mirrors the headhunter companies-present + open-search split.

D2 · Taxonomy

Share the company SignalType enum

Add JOB_CHANGE, PROMOTION, TENURE; reuse CONTENT, LEADERSHIP, EVENT. One signal vocabulary, gated by subject; person_signals already mirrors company_signals.

D3 · Scoring

Deterministic composite

ICP fit x type weight x source reputation x recency decay, ~30d half-life. Source reputation matters: an official appointment beats the same claim on a scraped blog.

D4 · Storage

Staging-first, mirror Sonar

People to workflow_run_people; each signal tagged with workflow_run_person_id; the person_signals join is built on promote-to-CRM. Mirrors the Sonar staging lifecycle, keeps CRM clean.

Monitoring is the planned push half - see People Signals Monitoring for the watch-cohort design, and People Intelligence Database for the person data model this writes into.
AgencyCore · People Signals design specsignal-first people discovery · headhunter pipeline