[{"data":1,"prerenderedAt":2790},["ShallowReactive",2],{"docs-nav":3,"docs-article-engineering\u002Fsystem-design\u002Fworkflows\u002Fsignals-search":797},[4,17,27,44,55,67,75,82,94,106,114,122,129,135,144,153,161,169,177,189,202,211,218,229,240,248,260,268,276,286,296,305,314,323,331,337,343,350,356,364,371,378,383,393,401,410,415,422,432,439,444,451,458,462,467,475,487,499,509,516,525,533,539,545,551,557,563,567,579,593,603,614,621,626,633,640,646,653,658,665,673,678,686,692,699,704,710,721,730,740,747,753,761,767,776,782,791],{"path":5,"title":6,"description":7,"group":8,"section":6,"order":9,"tags":10,"lastUpdated":16},"\u002Fagents\u002Fagentic-crm","Agentic CRM","Research brief and build plan for an AgencyCore agentic CRM layer, rendered as an interactive page — the core operating loop, the target architecture, the typed-tool risk gateway, the proposed-actions review queue, and the four-slice MVP.","Agents",0,[11,12,13,14,15],"crm","agents","ai","architecture","research","2026-06-12",{"path":18,"title":19,"description":20,"group":8,"section":21,"order":22,"tags":23,"lastUpdated":26},"\u002Fagents\u002Fchat","Chat agent","High-level system design of the AgencyCore chat agent — core components, data flow, and the two abstractions that hold it together.","Reference",1,[12,14,24,25],"chat","system-design","2026-05-13",{"path":28,"title":29,"description":30,"group":8,"section":31,"order":32,"tags":33,"lastUpdated":43},"\u002Fagents\u002Fcompany-enrichment","Company Enrichment","The company enrichment workflow - a cache-first read in front of the company intelligence database that fills firmographic, contact and technographic facts via a fixed-order provider waterfall, and writes every resolved fact back with provenance so the first org pays once and every later search rides free.","Enrichment",2,[12,34,35,36,37,38,39,40,41,42],"workflow","enrichment","companies","waterfall","cache","intelligence-database","firmographics","provenance","sonar","2026-06-10",{"path":45,"title":46,"description":47,"group":8,"section":48,"order":9,"tags":49,"lastUpdated":54},"\u002Fagents\u002Fcompany-sonar","Company Signals","Signal-first company discovery for marketing agencies, on the Claude Agent SDK, with a global intelligence cache and deterministic composite scoring.","Company Sonar",[12,34,42,50,51,52,35,53,14],"company-search","signals","agent-sdk","scoring","2026-06-08",{"path":56,"title":57,"description":58,"group":8,"section":48,"order":22,"tags":59,"lastUpdated":66},"\u002Fagents\u002Fcompany-sonar\u002Fsignal-monitoring","Company Signals Monitoring","Realtime signal capture layer on top of the data graph. Detects hot events, scores them with a Claude managed agent against each agency's ICP, fans out alerts.",[14,51,60,61,62,63,64,65],"intel","icp","alerts","monitoring","sse","managed-agents","2026-06-09",{"path":68,"title":69,"description":70,"group":8,"section":71,"order":22,"tags":72,"lastUpdated":74},"\u002Fagents\u002Fconcepts\u002Fchat-agent-design-principles","Designing chat agents","The 2026 playbook for production chat agents that reach into internal systems via tools — context engineering, memory, tool design, when to add complexity.","Concepts",[12,14,24,73],"context-engineering","2026-05-14",{"path":76,"title":77,"description":78,"group":8,"section":71,"order":32,"tags":79,"lastUpdated":74},"\u002Fagents\u002Fconcepts\u002Fsystem-prompt-architecture","System prompt architecture","How to structure a production chat agent system prompt — eight sections, what each one does, and the rules vendors converge on.",[12,80,81],"prompt-engineering","system-prompt",{"path":83,"title":84,"description":85,"group":8,"section":84,"order":9,"tags":86,"lastUpdated":54},"\u002Fagents\u002Fenvoy","Envoy","High-level system design for the AI outreach engine — the sequence step state machine, the human-in-the-loop draft approval gate, multi-source context enrichment, and the inbox sentiment flow, rendered as an interactive page.",[12,87,88,89,90,91,92,93,14],"envoy","outreach","sales-engagement","sequences","state-machine","human-in-the-loop","nylas",{"path":95,"title":96,"description":97,"group":8,"section":98,"order":9,"tags":99,"lastUpdated":16},"\u002Fagents\u002Fheadhunter","Headhunter","The AI talent-search pipeline on one page - the production six-step design with its current-title relevance gate, and the 2.0 system design with internal-first waterfall sourcing, a pluggable source registry, automatic entity resolution, and a people intelligence graph that compounds every run.","General Search",[12,34,100,101,14,25,102,37,103,104,105],"headhunter","recruiting","multi-source","entity-resolution","people-intelligence","flywheel",{"path":107,"title":108,"description":109,"group":8,"section":21,"order":32,"tags":110,"lastUpdated":113},"\u002Fagents\u002Fpaperclip","Paperclip","Architecture deep dive into the Paperclip orchestration system.",[12,14,111,112],"orchestration","paperclip","2026-04-20",{"path":115,"title":116,"description":117,"group":8,"section":31,"order":22,"tags":118,"lastUpdated":16},"\u002Fagents\u002Fpeople-enrichment","People Enrichment","The people enrichment workflow - a cache-first read in front of the people intelligence database that fills profile, contact and employment facts via a fixed-order provider waterfall, keyed on the LinkedIn URL, and writes every resolved fact back with provenance so the first org pays once and every later search rides free. The fill step Headhunter and People Signals both call.",[12,34,35,119,37,38,39,120,41,100,121],"people","linkedin","people-sonar",{"path":123,"title":124,"description":125,"group":8,"section":126,"order":9,"tags":127,"lastUpdated":54},"\u002Fagents\u002Fpeople-sonar","People Signals","Signal-first people discovery for marketing agencies, built on the headhunter pipeline, with a composite score weighted by signal strength, source reputation, recency, and ICP fit.","People Sonar",[12,34,121,128,51,100,35,53,14],"people-search",{"path":130,"title":131,"description":132,"group":8,"section":126,"order":22,"tags":133,"lastUpdated":54},"\u002Fagents\u002Fpeople-sonar\u002Fpeople-signal-monitoring","People Signals Monitoring","Forward-looking design for the push layer that tracks known people - champions, past contacts, target-company decision-makers - and fires a warm lead the moment they change jobs, get promoted, or their company has an event.",[14,51,60,119,63,134],"warm-leads",{"path":136,"title":137,"description":138,"group":139,"section":140,"order":22,"tags":141,"lastUpdated":143},"\u002Fengineering\u002Fguides\u002Fagent-execution-stack","The Agent Execution Stack","Durable workflows over pluggable agent backends — how AgencyCore runs AI agents on Inngest over a webhook-driven Claude Managed Agents backend.","Engineering","Guides",[12,142,14,25],"inngest","2026-06-25",{"path":145,"title":146,"description":147,"group":139,"section":140,"order":9,"tags":148,"lastUpdated":143},"\u002Fengineering\u002Fguides\u002Fagent-runtime","Agent runtime","How AgencyCore runs AI agents on a provider-neutral runtime — the abstraction layer that lets us swap the agent backend, with Claude managed agents as the current provider.",[12,149,14,150,151,152,25],"runtime","anthropic","claude","providers",{"path":154,"title":155,"description":156,"group":139,"section":21,"order":157,"tags":158,"lastUpdated":160},"\u002Fengineering\u002Freference\u002Fagno-to-agent-sdk-migration","Agno → Claude Agent SDK migration","System-design spec for moving the ac-python-api workflow engine off Agno onto Anthropic's Claude Agent SDK \u002F Managed Agents, tiered by control-flow shape.",10,[12,14,159,52,65],"migration","2026-06-06",{"path":162,"title":163,"description":164,"group":139,"section":21,"order":22,"tags":165,"lastUpdated":54},"\u002Fengineering\u002Freference\u002Fcloudflare-agent-sandbox","Cloudflare agent sandbox","Cloudflare's Workers-based agent platform, evaluated as an alternative sandbox for our Agno workflows.",[12,166,167,168,159],"sandbox","cloudflare","workers",{"path":170,"title":171,"description":172,"group":139,"section":21,"order":32,"tags":173,"lastUpdated":176},"\u002Fengineering\u002Freference\u002Fvirtual-filesystem-rag","Virtual filesystem for AI assistants","How ChromaFs provides AI agents with structured file access.",[12,174,14,175],"rag","chromafs","2026-04-18",{"path":178,"title":179,"description":180,"group":139,"section":181,"order":182,"tags":183,"lastUpdated":188},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fcapabilities\u002Fstate-and-knowledge","State and knowledge","What a run may know. One deterministic context builder over application state, knowledge and memory, one owner for every fact, and memory that is written through a tool.","Agentic platform",11,[184,185,186,11,187],"context","memory","knowledge","pgvector","2026-08-31",{"path":190,"title":191,"description":192,"group":139,"section":181,"order":157,"tags":193,"lastUpdated":201},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fcapabilities\u002Ftools-and-integrations","Tools and integrations","A tool is the one way an agent reaches the world. AgencyCore owns the model facing contract, the invoke path, the credentials and the result boundary.",[194,195,196,197,198,199,200],"tools","integrations","mcp","agno","policy","security","idempotency","2026-09-04",{"path":203,"title":204,"description":205,"group":139,"section":181,"order":22,"tags":206,"lastUpdated":210},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fcontract","Platform contract","One platform behind chat, interactive channels, triggers, approvals and background runs, with one Agno runtime, one tool layer, one state layer, and three cross-cutting planes.",[12,14,197,142,194,207,149,208,198,209],"skills","channels","observability","2026-09-02",{"path":212,"title":181,"description":213,"group":139,"section":214,"order":22,"tags":215,"lastUpdated":201},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform","The whole agentic platform on one page - who starts a run, the one boundary every run passes, how the work executes, and what comes back.","System design",[12,14,216,197,142,217,198],"overview","runs",{"path":219,"title":220,"description":221,"group":139,"section":181,"order":222,"tags":223,"lastUpdated":228},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Fagent-access","Agent access (CLI and MCP)","How an outside AI agent reaches AgencyCore. The ac CLI works today as a user seat. An MCP server is planned and not designed.",6,[224,196,12,151,225,226,227],"cli","access","auth","todo","2026-08-18",{"path":230,"title":231,"description":232,"group":139,"section":181,"order":233,"tags":234,"lastUpdated":239},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Fchannel-gateway","Channel gateway","The only layer that knows both an interactive channel and the platform. One message shape converges inbound, one intent shape diverges outbound, and no model call happens here.",3,[208,235,236,237,238,199],"slack","web","identity","sessions","2026-08-30",{"path":241,"title":242,"description":243,"group":139,"section":181,"order":244,"tags":245,"lastUpdated":210},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Ffront-door","Front door","The conversational control layer. It turns a request into one structured decision, then deterministic application code answers or hands work to RunManager.",4,[246,247,197,184,198,217],"front-door","routing",{"path":249,"title":250,"description":251,"group":139,"section":181,"order":32,"tags":252,"lastUpdated":259},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Fsurfaces","Surfaces","Every product surface and its API contract. Web chat goes through the gateway; every schema-native surface calls the domain API.",[253,254,24,255,256,257,258,217,64],"surfaces","api","approvals","prospects","saved-searches","builder","2026-09-03",{"path":261,"title":262,"description":263,"group":139,"section":181,"order":264,"tags":265,"lastUpdated":188},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Ftriggers","Triggers","A Run with no person. Every producer emits one Event, matching is deterministic, and dispatch reuses RunManager, Policy and Inngest.",5,[266,267,142,200],"triggers","events",{"path":269,"title":270,"description":271,"group":139,"section":181,"order":272,"tags":273,"lastUpdated":259},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fplanes\u002Fidempotency","Idempotency","One durable PostgreSQL key service prevents duplicate effects and freezes mutable input before selected Run starts. A Run start is guarded by a unique index on the Run row.",14,[200,217,194,274,275],"webhooks","reliability",{"path":277,"title":278,"description":279,"group":139,"section":181,"order":280,"tags":281,"lastUpdated":285},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fplanes\u002Fobservability-and-operations","Observability and operations","One run row, one span tree and one usage meter. Sentry reports system failure; AgencyCore spans explain what the agent did.",13,[209,217,282,283,64,284],"spans","usage","sentry","2026-08-26",{"path":287,"title":288,"description":289,"group":139,"section":181,"order":290,"tags":291,"lastUpdated":295},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fplanes\u002Fpolicy-and-governance","Policy and governance","One deterministic plane answers may this happen, at three checkpoints, with one grant model, one approval model and one decision log.",12,[198,292,255,293,294],"permissions","limits","governance","2026-08-25",{"path":297,"title":6,"description":298,"group":139,"section":299,"order":22,"tags":300,"lastUpdated":210},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fagentic-crm","The AgencyCore CRM loop for turning signals and discovery into qualified organization prospects, CRM relationships and outreach.","Agentic products",[11,301,51,302,256,35,303,304,87],"lead-generation","intelligence","signals-search","email-sequence",{"path":306,"title":307,"description":308,"group":139,"section":299,"order":264,"tags":309,"lastUpdated":188},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fbuilder-chat","Front door builder chat","Conversational authoring for organization-specific Agent and Workflow definitions, entered through the normal Front Door and backed by the existing DefinitionService.",[310,311,246,12,312,313,198],"authoring","definitions","workflows","templates",{"path":315,"title":316,"description":317,"group":139,"section":181,"order":318,"tags":319,"lastUpdated":201},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fcapability-contracts","Company, People and Signals contracts","The five Phase 7 product capabilities, their bounded inputs, stable references, permissions and results.",21,[320,321,119,51,322],"capabilities","company","contracts",{"path":324,"title":325,"description":326,"group":139,"section":181,"order":327,"tags":328,"lastUpdated":330},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fcapability-scenarios","Capability design scenarios","Normal, failure and recovery cases for the Phase 7 capability contracts, with implementation owners.",22,[320,329,321,119,51],"validation","2026-09-05",{"path":332,"title":333,"description":334,"group":139,"section":299,"order":233,"tags":335,"lastUpdated":210},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Femail-sequence","Email sequence workflow","Envoy durable outreach for one or many people, with fresh context, approvals, reply waits, follow-ups and Nylas transport.",[336,87,34,142,93,255],"email",{"path":338,"title":339,"description":340,"group":139,"section":299,"order":244,"tags":341,"lastUpdated":188},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fgeneral-chat","Front door general chat","The default conversational answer path for AgencyCore. It answers from supplied context, cites what it used, asks when context is insufficient, and delegates real work through the normal Front Door.",[24,246,186,184,247,342],"citations",{"path":344,"title":345,"description":346,"group":139,"section":299,"order":222,"tags":347,"lastUpdated":188},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fhuman-review","Human review inbox","One product page for every agentic action that is paused because a person must authorize an exact proposal. It is a view over the shared approval primitive, not a second review system.",[348,255,349,198,12],"human-review","inbox",{"path":351,"title":352,"description":353,"group":139,"section":299,"order":32,"tags":354,"lastUpdated":259},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fsignals-search","Signals Search","One bounded discovery workflow that finds companies, verifies signals, finds relevant people, and produces evidence-backed organization prospects without prematurely creating CRM records.",[303,355,36,119,51,302,256,11,35],"discovery",{"path":357,"title":358,"description":359,"group":139,"section":299,"order":360,"tags":361,"lastUpdated":188},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fworkflow-visualizer","Workflow visualizer","One constrained workflow graph, reused to author a draft, read a published definition, and watch a Run. Build mode edits the draft; run mode overlays Run and span state on the frozen snapshot.",7,[312,362,258,311,217,282,363,255],"visualizer","graph",{"path":365,"title":366,"description":367,"group":139,"section":181,"order":368,"tags":369,"lastUpdated":201},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fruntime\u002Fdefinitions","Runtime definitions","Editable drafts, one published configuration per definition, template forks, deterministic validation, and the Run snapshot that keeps in flight work stable.",8,[149,311,329,370],"publishing",{"path":372,"title":373,"description":374,"group":139,"section":181,"order":375,"tags":376,"lastUpdated":259},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fruntime\u002Fexecution","Runtime execution","The Run record, the Inngest step boundaries, agent segments, workflow nodes, approvals, cancellation, failure handling and live events.",9,[149,217,197,142,255,377,64],"cancellation",{"path":379,"title":380,"description":381,"group":139,"section":181,"order":360,"tags":382,"lastUpdated":285},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fruntime","Agentic runtime","One Run contract, one Agno agent runtime, one deterministic workflow model, and the component boundaries that keep the framework replaceable.",[149,217,197,312,207,142],{"path":384,"title":385,"description":386,"group":139,"section":387,"order":244,"tags":388,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Fcompany-context","Company context","L3. Company state, knowledge and memory are three different things. One deterministic builder turns them into one brief.","Mission Control",[389,390,186,185,184,391,11],"mission-control","company-state","retrieval","2026-08-12",{"path":394,"title":395,"description":396,"group":139,"section":387,"order":22,"tags":397,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Fexperience","Experience","L6. Where a person observes and controls the company, and the one rule that keeps the UI out of the business.",[389,398,399,255,400],"ui","control-plane","activity",{"path":402,"title":403,"description":404,"group":139,"section":387,"order":222,"tags":405,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Ffoundation","Foundation","L1. Generic infrastructure with no business logic in it. The test is that another product could run on it unchanged.",[389,406,407,408,267,409,226,209],"infrastructure","database","queue","storage",{"path":411,"title":387,"description":412,"group":139,"section":214,"order":233,"tags":413,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control","The internal Company OS. Six layers and one policy plane put a person in control of company state and of autonomous execution.",[389,414,14,12,312,198,399],"company-os",{"path":416,"title":417,"description":418,"group":139,"section":387,"order":32,"tags":419,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Fintelligence","Intelligence","L5. The agent is the primitive. A skill is how it works, a tool is how it reaches the world, and the two are never the same thing.",[389,12,207,420,421],"planning","reasoning",{"path":423,"title":424,"description":425,"group":139,"section":387,"order":368,"tags":426,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Fmetrics-and-connectors","Metrics and connectors","A worked example across every layer. Three vendors, one metric pipeline, three views, and the rule that decides what we store.",[389,427,195,428,429,284,430,431],"metrics","stripe","posthog","ingest","dashboards",{"path":433,"title":434,"description":435,"group":139,"section":387,"order":233,"tags":436,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Forchestration","Orchestration","L4. Workflow, run, step, trigger and event. Five nouns that turn a decision into durable execution.",[389,312,217,266,267,437,438],"durability","retry",{"path":440,"title":288,"description":441,"group":139,"section":387,"order":360,"tags":442,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Fpolicy-and-governance","A plane, not a layer. One place decides what an agent may do, under what conditions, and how much. Human approval is one of its three answers.",[389,198,294,255,292,293,443],"audit",{"path":445,"title":191,"description":446,"group":139,"section":387,"order":264,"tags":447,"lastUpdated":392},"\u002Fengineering\u002Fsystem-design\u002Fmission-control\u002Ftools-and-integrations","L2. One contract for every capability. The tool is the only route to the world, and it is where policy, audit and tenancy meet.",[389,194,195,448,449,450],"adapters","registry","credentials",{"path":452,"title":453,"description":454,"group":139,"section":455,"order":22,"tags":456,"lastUpdated":210},"\u002Fengineering\u002Fsystem-design\u002Fworkflows\u002Fcompany-search","Company search","Implementation notes for company.search. Search resolves and gates company identities; enrichment is a separate capability.","Workflows",[321,457,142,42],"search",{"path":459,"title":31,"description":460,"group":139,"section":455,"order":233,"tags":461,"lastUpdated":210},"\u002Fengineering\u002Fsystem-design\u002Fworkflows\u002Fenrichment","Reusable company and people enrichment workflows with canonical Intelligence write-back, existing tier freshness and bounded asynchronous email.",[35,321,119,142],{"path":463,"title":464,"description":465,"group":139,"section":455,"order":32,"tags":466,"lastUpdated":259},"\u002Fengineering\u002Fsystem-design\u002Fworkflows\u002Fpeople-search","People search","Implementation notes for people.search. Bounded company scope and persona gates return selectable person identities without enrichment.",[119,457,142,100],{"path":468,"title":469,"description":470,"group":139,"section":455,"order":244,"tags":471,"lastUpdated":474},"\u002Fengineering\u002Fsystem-design\u002Fworkflows\u002Fsignals-search","Signals search","Superseded. The earlier on-demand buying-signal search component, kept as a record of the design that the agentic platform Signals Search workflow replaces.",[51,12,142,472,473],"intelligence-databases","superseded","2026-08-28",{"path":476,"title":477,"description":478,"group":479,"section":480,"order":481,"tags":482,"lastUpdated":66},"\u002Flearnings\u002Fagentic-sdlc","The agentic SDLC","How AI agents move from autocomplete to owning the loop across the software lifecycle, and why that shifts the bottleneck from coding to verification.","Learnings",null,30,[12,483,484,485,486],"sdlc","engineering","verification","review",{"path":488,"title":489,"description":490,"group":479,"section":480,"order":491,"tags":492,"lastUpdated":498},"\u002Flearnings\u002Fagi-to-asi","From AGI to ASI","What lies beyond human-level AI. The four technological pathways from AGI to artificial superintelligence, the formal ceiling that bounds them, and the six bottlenecks that could stall the climb - distilled from the DeepMind report.",50,[493,494,495,496,497],"ai-futures","asi","agi","scaling","recursive-self-improvement","2026-06-19",{"path":500,"title":501,"description":502,"group":479,"section":480,"order":503,"tags":504,"lastUpdated":66},"\u002Flearnings\u002Fai-native-company-playbook","AI native company playbook","Why AI should be the operating system your company runs on, not a tool it uses, and the concrete practices that follow - closed loops, a queryable org, software factories, and token maxing.",40,[505,506,12,507,508],"ai-native","company-building","gtm","founders",{"path":510,"title":511,"description":512,"group":479,"section":480,"order":157,"tags":513,"lastUpdated":54},"\u002Flearnings\u002Fbuying-intent-signals","Buying intent signals","How buyers leak their intent before they ever fill in a form, and how to read those signals before the window closes.",[514,51,507,515],"intent","sales",{"path":517,"title":518,"description":519,"group":479,"section":480,"order":520,"tags":521,"lastUpdated":54},"\u002Flearnings\u002Fcold-outbound-system","Cold outbound system","A high-level study of an open-source 29-skill cold email system, organized into five sequential tracks from ICP to iteration.",20,[522,523,507,524],"outbound","cold-email","systems",{"path":526,"title":527,"description":528,"group":479,"section":480,"order":529,"tags":530,"lastUpdated":532},"\u002Flearnings\u002Fswan-gtm-skills-architecture","Swan GTM skills architecture","A research note on Swan AI's foundations and maps model for GTM agents, with ASCII diagrams and ideas AgencyCore can borrow.",60,[507,12,73,531,14],"swan","2026-07-01",{"path":534,"title":535,"description":536,"group":387,"section":480,"order":272,"tags":537,"lastUpdated":43},"\u002Fmission-control\u002Fciops-agent","CIOps agent","High-level system architecture and design notes for the Mission Control CIOps agent.",[389,12,538,14],"ciops",{"path":540,"title":541,"description":542,"group":387,"section":480,"order":182,"tags":543,"lastUpdated":43},"\u002Fmission-control\u002Fcostops-agent","CostOps agent","High-level system architecture and design notes for the Mission Control CostOps agent.",[389,12,544,14],"finops",{"path":546,"title":547,"description":548,"group":387,"section":480,"order":520,"tags":549,"lastUpdated":54},"\u002Fmission-control\u002Fdashboard","Dashboard","The Mission Control product UI - a dark cockpit with a fleet-nav rail, company-state grid, a working escalation queue, live ledger and a global kill switch.",[389,12,550,398],"dashboard",{"path":552,"title":553,"description":554,"group":387,"section":480,"order":280,"tags":555,"lastUpdated":43},"\u002Fmission-control\u002Fproduct-analytics-agent","ProductAnalytics agent","High-level system architecture and design notes for the Mission Control ProductAnalytics agent.",[389,12,556,14],"product-analytics",{"path":558,"title":559,"description":560,"group":387,"section":480,"order":290,"tags":561,"lastUpdated":43},"\u002Fmission-control\u002Frevenueops-agent","RevenueOps agent","High-level system architecture and design notes for the Mission Control RevenueOps agent.",[389,12,562,14],"revops",{"path":564,"title":214,"description":565,"group":387,"section":480,"order":157,"tags":566,"lastUpdated":54},"\u002Fmission-control\u002Fsystem-design","One screen for the whole company, watched by a guardrailed fleet of ops agents that explain, propose, act and learn overnight.",[389,12,544,14],{"path":568,"title":569,"description":570,"group":571,"section":480,"order":32,"tags":572,"lastUpdated":578},"\u002Fproduct-design\u002Fonboarding-flow","Onboarding flow","Product design for the signup wizard and how TAM building folds into it. Analyzes the flow today (account, profile, company), the gap (no ICP, empty dashboard), and the integration of a new \"who you sell to\" ICP step plus a build-and-reveal screen that lands the user on a populated, ranked list.","Product Design",[573,61,574,575,576,577],"onboarding","tam","activation","ux","user-journey","2026-06-11",{"path":580,"title":581,"description":582,"group":571,"section":480,"order":233,"tags":583,"lastUpdated":592},"\u002Fproduct-design\u002Fpricing-entitlements","Pricing tiers, entitlements and usage credits","Specification for subscription tiers with gated platform access: composable plan entitlements, a unified usage-credit currency, plan-sourced limits, per-module trials and a two-ticket delivery plan built on the Stripe billing foundation. Written for discussion; the Linear document is the canonical copy with ticket links.",[584,585,586,587,588,589,590,591],"pricing","entitlements","billing","credits","subscriptions","plans","seats","trials","2026-07-06",{"path":594,"title":595,"description":596,"group":571,"section":480,"order":233,"tags":597,"lastUpdated":578},"\u002Fproduct-design\u002Fsales-signals-ux","Designing Signals","Product design for the sales-signals experience in ac-frontend: the 14-type taxonomy and its color system, the anatomy of a signal card across four densities, the 0-10 lead score scale, the origin tag (sonar pull vs proactive push), the seven surfaces where signals render (launchpad, sonar app, company detail, timeline, activities, data layer, Envoy), and the interaction rules that keep them consistent.",[51,576,598,11,42,599,600,601,602],"design-system","lead-score","origin","pull","push",{"path":604,"title":605,"description":606,"group":607,"section":608,"order":244,"tags":609,"lastUpdated":43},"\u002Fproprietary-data\u002Fcrm\u002Factivities","Activities","Deep dive on crm_activities, the interaction + task log of the CRM — where it is served from, how a row is born and read, and its full schema, relationships and rules.","Proprietary data","CRM",[11,610,611,612,613],"activities","tasks","data-model","schema",{"path":615,"title":616,"description":617,"group":607,"section":608,"order":264,"tags":618,"lastUpdated":43},"\u002Fproprietary-data\u002Fcrm\u002Fcommunications","Communications","Deep dive on crm_communications and crm_communication_events, the unified email\u002Fcall\u002Fmessage log and its per-message engagement tracking — where it is served from, the outbound message lifecycle, and the full schema, relationships and rules.",[11,619,336,620,612],"communications","engagement",{"path":622,"title":623,"description":624,"group":607,"section":608,"order":22,"tags":625,"lastUpdated":43},"\u002Fproprietary-data\u002Fcrm\u002Fcompanies","Companies","Deep dive on crm_companies, the account record at the centre of the CRM — where it is served from, how a row is born and read, and its full schema, relationships and rules.",[11,36,612,613,14],{"path":627,"title":628,"description":629,"group":607,"section":608,"order":233,"tags":630,"lastUpdated":43},"\u002Fproprietary-data\u002Fcrm\u002Fdeals","Deals","Deep dive on the deal pipeline — crm_deals, crm_pipeline_stages and crm_pipeline_config. Where it is served from, the life of a deal, and its full schema, relationships and rules.",[11,631,632,612,613],"deals","pipeline",{"path":634,"title":635,"description":636,"group":607,"section":608,"order":222,"tags":637,"lastUpdated":43},"\u002Fproprietary-data\u002Fcrm\u002Flists","Lists","Deep dive on crm_lists and crm_list_members, the static or dynamic member collections of the CRM — where they are served from, how a list and its members come to be and are read, and their schema, relationships and rules.",[11,638,639,612,613],"lists","segments",{"path":641,"title":642,"description":643,"group":607,"section":608,"order":32,"tags":644,"lastUpdated":43},"\u002Fproprietary-data\u002Fcrm\u002Fpeople","People","Deep dive on crm_people, the contact record of the CRM — where it is served from, how a row is born and read, and its full schema, relationships and rules.",[11,119,645,612,613],"contacts",{"path":647,"title":648,"description":649,"group":607,"section":608,"order":368,"tags":650,"lastUpdated":43},"\u002Fproprietary-data\u002Fcrm\u002Fsaved-filters","Saved filters","Deep dive on crm_saved_filters, the named reusable filter snapshots over the company, person and signal list views — where it is served from, how a saved view is born and applied, and its full schema, relationships and rules.",[11,651,652,612,613],"saved-filters","views",{"path":654,"title":655,"description":656,"group":607,"section":608,"order":360,"tags":657,"lastUpdated":578},"\u002Fproprietary-data\u002Fcrm\u002Fsignals","Signals","Deep dive on the signals tables - signals, company_signals and person_signals, the CRM's sales-intelligence layer. Where signals are served from, how one is born and attached, and the full schema, relationships and rules.",[11,51,302,612,613],{"path":659,"title":660,"description":661,"group":607,"section":662,"order":22,"tags":663,"lastUpdated":43},"\u002Fproprietary-data\u002Fintelligence-databases\u002Fcompany-intelligence-database","Company Intelligence Database","Decided architecture for ENG-669, the cross-org company intelligence layer that acts as a read-through cache in front of enrichment providers, with public-facts-only privacy and provenance-tracked write-back.","Intelligence databases",[14,60,36,51,38,664],"eng-669",{"path":666,"title":667,"description":668,"group":607,"section":662,"order":244,"tags":669,"lastUpdated":578},"\u002Fproprietary-data\u002Fintelligence-databases\u002Forg-signal-feed","Org Signal Feed","The per-org activation layer on top of the shared signals store. One immutable intel_signals row fans out to many orgs through scoring (signal-type weight times ICP fit times recency decay) and materializes as ranked, tiered rows in intel_org_signal_feed - the only org-scoped, RLS-per-org table of the signal stack, the door the launchpad, inbox and digest all read through. Signals enter by two ingest classes - a user's sonar pull (ungated) or an automated push (gated by threshold plus an optional competitor-ICP check) - logged in intel_signal_ingests, and each feed row records its origin.",[14,60,51,670,53,671,672,575,430,601,602,600],"feed","decay","rls",{"path":674,"title":675,"description":676,"group":607,"section":662,"order":32,"tags":677,"lastUpdated":578},"\u002Fproprietary-data\u002Fintelligence-databases\u002Fpeople-intelligence-database","People Intelligence Database","Decided architecture for the cross-org people intelligence layer - a read-through cache in front of headhunter research and Hunter email lookups, with LinkedIn-URL identity, append-only employment edges, per-tier freshness stamps on the flat profile, shared intel_sources provenance, unified intel_signals, and a GDPR erasure path.",[14,60,119,51,38,100],{"path":679,"title":680,"description":681,"group":607,"section":662,"order":233,"tags":682,"lastUpdated":578},"\u002Fproprietary-data\u002Fintelligence-databases\u002Fsignals-intelligence-database","Signals Intelligence Database","Decided v1 architecture for the unified signal store - one polymorphic append-only intel_signals table that holds both company and person signals, with a shared taxonomy, source-ranked provenance, an intel_signal_ingests log that records which pipeline found each signal, decay at read time, and a person-to-company rollup so a champion job change surfaces on the company feed.",[14,60,51,683,671,684,670,685,41,601,602],"polymorphic","taxonomy","ingests",{"path":687,"title":688,"description":689,"group":607,"section":480,"order":9,"tags":690,"lastUpdated":16},"\u002Fproprietary-data\u002Foverview","Data Layer Overview","The AgencyCore data layer in one map - the org-scoped CRM plane in production today and the global intelligence plane designed to sit in front of it, with interactive diagrams of both, the end-to-end data flow, freshness and precedence rules, the privacy seam, and the rollout path.",[691,14,60,11,51,38,25,216],"data-layer",{"path":693,"title":694,"description":695,"group":696,"section":480,"order":9,"tags":697,"lastUpdated":54},"\u002Froadmap","Roadmap - June 2026","June 2026 product plan across four themes. The spine is moving our agents onto an isolated sandbox runtime and rebuilding the core agents and workflows on it, then standing up a read-through intelligence data store and shipping the Stripe billing system. Knowledge base, assistant, and credit tracking carry into the July roadmap.","Roadmap",[698,420],"roadmap",{"path":700,"title":701,"description":702,"group":696,"section":480,"order":22,"tags":703,"lastUpdated":54},"\u002Froadmap\u002Fjuly-2026","Roadmap - July 2026","July 2026 product plan across three themes, all carried over from June. Building on June's sandbox runtime, July grounds the agents in a knowledge base, launches the AI chat assistant, and meters every action with per-action credit tracking that reconciles into the Stripe billing system shipped in June.",[698,420],{"path":705,"title":706,"description":707,"group":696,"section":480,"order":32,"tags":708,"lastUpdated":532},"\u002Froadmap\u002Fjune-2026-slides","Roadmap slides - June 2026","Board-review slide deck for the June 2026 product roadmap, rendered directly from the original PPTX in the docs site.",[698,420,709],"slides",{"path":711,"title":712,"description":713,"group":714,"section":8,"order":520,"tags":715,"lastUpdated":16},"\u002Fsymphony\u002Fagents\u002Fdevops-agent","DevOps agent","Interactive design for a Slack-first Symphony DevOps agent that wraps production promotion, rollback, audit, and operational jobs behind policy gates, typed runbooks, and an auditable ledger.","Symphony",[716,235,717,718,719,720],"symphony","devops","production","runbooks","operations",{"path":722,"title":723,"description":724,"group":714,"section":8,"order":157,"tags":725,"lastUpdated":16},"\u002Fsymphony\u002Fagents\u002Foncall-agent","Oncall agent","Interactive design for a Symphony oncall agent that turns Sentry incidents into rich Linear tickets, investigates with Codex, opens fix PRs, and resolves Sentry after merge.",[716,284,726,727,728,729],"linear","oncall","incident-response","codex",{"path":731,"title":732,"description":733,"group":714,"section":734,"order":157,"tags":735,"lastUpdated":16},"\u002Fsymphony\u002Fhousekeeping\u002Fcodex-vacuum","Codex vacuum","Interactive design for the Symphony housekeeping timer that checkpoints and vacuums Codex sqlite stores on the VPS.","Housekeeping",[716,736,737,729,738,739],"timed-jobs","housekeeping","sqlite","vps",{"path":741,"title":742,"description":743,"group":714,"section":734,"order":481,"tags":744,"lastUpdated":16},"\u002Fsymphony\u002Fhousekeeping\u002Fhost-cleanup","Host cleanup","Interactive design for the Symphony housekeeping timer that removes stale \u002Ftmp debris, vacuums the journal, and optionally cleans the apt package cache.",[716,736,737,739,745,746],"disk","cleanup",{"path":748,"title":749,"description":750,"group":714,"section":734,"order":520,"tags":751,"lastUpdated":16},"\u002Fsymphony\u002Fhousekeeping\u002Fworkspace-cleanup","Workspace cleanup","Interactive design for the Symphony housekeeping timer that prunes idle per-issue workspaces after their TTL.",[716,736,737,752,746,739],"workspaces",{"path":754,"title":755,"description":756,"group":714,"section":480,"order":9,"tags":757,"lastUpdated":66},"\u002Fsymphony","Symphony orchestration","How AgencyCore runs OpenAI Symphony as a long-running daemon that turns Linear tickets into isolated, autonomous Codex runs, reviewed by Claude and merged by humans. High-level workflow, system architecture, and the engineer playbook.",[716,729,726,758,111,739,759,760],"claude-review","qa","automation",{"path":762,"title":763,"description":764,"group":714,"section":214,"order":22,"tags":765,"lastUpdated":392},"\u002Fsymphony\u002Fsystem-design\u002Fhigh-level-design","High-level design","The Symphony daemon end to end — the standing agent workforce and its label-routed workflows, then the runtime that polls, dispatches, runs and writes back.",[716,14,111,12,729,726,766],"systemd",{"path":768,"title":769,"description":770,"group":714,"section":771,"order":503,"tags":772,"lastUpdated":16},"\u002Fsymphony\u002Ftimed-jobs\u002Fdaily-security-agent","Daily security agent","Interactive design for a report-only Symphony timed job that reviews the last 24h of commits, scans the system for vulnerabilities, and opens focused follow-up tickets.","Timed jobs",[716,199,736,729,773,774,775],"semgrep","threat-model","ownership",{"path":777,"title":778,"description":779,"group":714,"section":771,"order":481,"tags":780,"lastUpdated":16},"\u002Fsymphony\u002Ftimed-jobs\u002Fdaily-sentry-triage","Daily Sentry triage","Interactive design for the Symphony timed job that performs read-only Sentry triage, deduplicates existing tracked clusters, and creates focused ENG bugs for new actionable errors.",[716,736,284,209,781,726],"triage",{"path":783,"title":784,"description":785,"group":714,"section":771,"order":157,"tags":786,"lastUpdated":16},"\u002Fsymphony\u002Ftimed-jobs\u002Fnightly-local-staging-e2e","Nightly local staging E2E","Interactive design for the Symphony timed job that seeds local Supabase, runs ac-frontend Playwright E2E against the local staging stack, uploads evidence, and cleans artifacts.",[716,736,787,788,789,790],"e2e","playwright","staging","frontend",{"path":792,"title":793,"description":794,"group":714,"section":771,"order":520,"tags":795,"lastUpdated":16},"\u002Fsymphony\u002Ftimed-jobs\u002Fnightly-staging-qa","Nightly staging QA","Interactive design for the Symphony timed job that seeds a staging QA Linear issue, runs an agent-browser crawl, validates feature-map coverage, and files focused follow-up work.",[716,736,789,759,796,726],"agent-browser",{"id":798,"title":469,"body":799,"customComponent":480,"description":470,"extension":2778,"group":139,"lastUpdated":474,"meta":2779,"navigation":1968,"order":244,"path":468,"related":2780,"section":455,"seo":2786,"stem":2787,"tags":2788,"__hash__":2789},"docs\u002Fengineering\u002Fsystem-design\u002Fworkflows\u002Fsignals-search.md",{"type":800,"value":801,"toc":2753},"minimark",[802,805,836,850,853,858,865,943,965,977,983,987,994,1005,1011,1016,1140,1146,1161,1186,1190,1195,1198,1205,1280,1290,1293,1297,1301,1304,1308,1314,1324,1334,1347,1350,1354,1357,1363,1373,1380,1418,1444,1481,1512,1516,1525,1529,1569,1587,1591,1594,1675,1678,1682,1696,1703,1707,1710,1722,1727,1772,1775,1804,1812,1818,1822,1827,1883,1889,1893,1900,2115,2124,2133,2197,2203,2206,2210,2450,2454,2516,2520,2526,2530,2650,2659,2663,2749],[803,804,469],"h1",{"id":303},[806,807,808,820],"blockquote",{},[809,810,811,815,816,819],"p",{},[812,813,814],"strong",{},"Superseded."," Read\n",[817,818,352],"a",{"href":351},"\ninstead. That page is the current design. It replaces the split between Sonar\ncompany discovery and Headhunter people discovery with one bounded workflow.",[809,821,822,823,827,828,831,832,835],{},"This page records the earlier Inngest component. It names\n",[824,825,826],"code",{},"workflow.signals_search",", ",[824,829,830],{},"components\u002Fsignals\u002F"," and ",[824,833,834],{},"src\u002Fagents\u002Fsignals\u002F",",\nwhich the agentic platform replaces. Read it for history, not to build from.",[809,837,838,841,842,845,846,849],{},[812,839,840],{},"Status:"," superseded · ",[812,843,844],{},"Superseded:"," 2026-08-28 · ",[812,847,848],{},"Original date:"," 2026-08-12",[851,852],"hr",{},[854,855,857],"h2",{"id":856},"_1-what-were-building","1. What we're building",[809,859,860,861,864],{},"On-demand search for buying signals across companies and people, packaged as a ",[812,862,863],{},"reusable component"," rather than a standalone app.",[866,867,868,881],"table",{},[869,870,871],"thead",{},[872,873,874,878],"tr",{},[875,876,877],"th",{},"Requirement",[875,879,880],{},"How it lands",[882,883,884,897,909,917,925,935],"tbody",{},[872,885,886,890],{},[887,888,889],"td",{},"Search for all kinds of buying signals",[887,891,892,893,896],{},"Free-text query + optional ",[824,894,895],{},"signal_types[]"," filter",[872,898,899,902],{},[887,900,901],{},"Company and person signals both",[887,903,904,905,908],{},"One polymorphic store, ",[824,906,907],{},"subject_type"," discriminates",[872,910,911,914],{},[887,912,913],{},"Always extract the company, and the person when named",[887,915,916],{},"Extraction contract on the agent, resolution deterministic",[872,918,919,922],{},[887,920,921],{},"No enrichment inside the extraction",[887,923,924],{},"Agent may not assert what the source doesn't state",[872,926,927,932],{},[887,928,929],{},[812,930,931],{},"The signal must be actionable",[887,933,934],{},"A follow-up stage resolves and enriches the subject (§6)",[872,936,937,940],{},[887,938,939],{},"Reusable from a workflow step or from chat",[887,941,942],{},"Inngest component + typed payload, callers deferred",[809,944,945,946,952,953,956,957,960,961,964],{},"This is the ",[812,947,948,951],{},[824,949,950],{},"on-demand search"," producer"," from the decided ",[817,954,955],{"href":679},"signals intelligence database",". It defines ",[812,958,959],{},"no new storage",". It writes into the existing ",[824,962,963],{},"intel_signals"," spine alongside the manual, monitor and scraper producers.",[809,966,967,968,827,971,831,974,976],{},"A signal on its own is a fact with no address. \"Acme raised a Series B\" is useful only when we hold Acme's domain, its firmographics, and the people to contact. So the workflow does not stop at the write. It hands every new subject to ",[817,969,970],{"href":452},"company search",[817,972,973],{"href":463},"people search",[817,975,35],{"href":459},". That follow-up is §6.",[809,978,979,982],{},[812,980,981],{},"Out of scope, deliberately:"," per-org scoring and feed materialization (lives above the store), and the caller surfaces (workflow step \u002F chat \u002F user-composed workflow — designed for, not built yet).",[854,984,986],{"id":985},"_2-the-core-decision-route-by-detection-mechanism","2. The core decision: route by detection mechanism",[809,988,989,990,993],{},"The twelve signal types don't differ by topic. They differ by ",[812,991,992],{},"how the fact is detected",", and only one of the two mechanisms is a search problem.",[809,995,996,997,1000,1001,1004],{},"An agent with web search reads published prose. It ",[812,998,999],{},"cannot establish an absence or a delta."," ",[824,1002,1003],{},"started_meta_ads"," means the company had no ads yesterday and has ads today; no quantity of web search proves the \"yesterday\" half. Same for a creative-count jump, a tech-stack change, a profile change. An agent handed one of those types emits plausible output with no way to know it's wrong — the worst failure mode available, because nothing downstream can catch it either.",[809,1006,1007,1008],{},"Routing those types away from the agent is a ~20-line rule and it deletes the entire failure class. ",[812,1009,1010],{},"It is a larger quality lever than any tooling, prompting or model choice applied to the agent itself.",[1012,1013,1015],"h3",{"id":1014},"_21-taxonomy-by-lane","2.1 Taxonomy by lane",[866,1017,1018,1037],{},[869,1019,1020],{},[872,1021,1022,1025,1028,1031,1034],{},[875,1023,1024],{},"Lane",[875,1026,1027],{},"Subject",[875,1029,1030],{},"Types",[875,1032,1033],{},"Mechanism",[875,1035,1036],{},"Instrument",[882,1038,1039,1065,1087,1115],{},[872,1040,1041,1046,1048,1059,1062],{},[887,1042,1043],{},[812,1044,1045],{},"A · open-web read",[887,1047,321],{},[887,1049,1050,827,1053,827,1056],{},[824,1051,1052],{},"funding_round",[824,1054,1055],{},"executive_change",[824,1057,1058],{},"rebrand_or_relaunch",[887,1060,1061],{},"evidence exists as published prose",[887,1063,1064],{},"managed agent + search\u002Ffetch",[872,1066,1067,1071,1074,1082,1084],{},[887,1068,1069],{},[812,1070,1045],{},[887,1072,1073],{},"person",[887,1075,1076,827,1079],{},[824,1077,1078],{},"thought_leadership",[824,1080,1081],{},"speaking_event",[887,1083,1061],{},[887,1085,1086],{},"the same agent, the same session",[872,1088,1089,1094,1096,1109,1112],{},[887,1090,1091],{},[812,1092,1093],{},"B · fetched snapshot",[887,1095,321],{},[887,1097,1098,827,1100,827,1103,827,1106],{},[824,1099,1003],{},[824,1101,1102],{},"scaled_meta_ads",[824,1104,1105],{},"hired_growth_role",[824,1107,1108],{},"new_tech_stack",[887,1110,1111],{},"a delta needs yesterday's snapshot",[887,1113,1114],{},"deterministic collectors against real APIs",[872,1116,1117,1121,1123,1134,1137],{},[887,1118,1119],{},[812,1120,1093],{},[887,1122,1073],{},[887,1124,1125,827,1128,827,1131],{},[824,1126,1127],{},"job_change",[824,1129,1130],{},"promotion",[824,1132,1133],{},"tenure_milestone",[887,1135,1136],{},"a delta needs yesterday's snapshot, a tenure needs today's",[887,1138,1139],{},"licensed provider, fetched live",[809,1141,1142,1145],{},[812,1143,1144],{},"The subject is a second axis, not a second lane."," Both subject types appear in both lanes, so the routing rule stays one rule: it splits by detection mechanism only. The subject decides which follow-up runs in §6, and nothing else.",[809,1147,1148,1149,1152,1153,1156,1157,1160],{},"A type asked of the wrong lane is ",[812,1150,1151],{},"rejected, never guessed",". A caller passing ",[824,1154,1155],{},"signal_types: [started_meta_ads]"," to lane A gets an explicit rejection in ",[824,1158,1159],{},"rejected_types",", not an invented signal.",[809,1162,1163,1169,1170,1173,1174,1177,1178,831,1180,1182,1183],{},[812,1164,1165,1166,1168],{},"On ",[824,1167,1133],{},":"," it's arithmetic, so it looks like a third \"derived\" lane. It isn't. The arithmetic is trivial; the ",[812,1171,1172],{},"role start date is what goes stale",". Derived from a cached ",[824,1175,1176],{},"intel_people"," row it is confidently wrong — the person may have moved months ago, and we'd nudge them about a job they left. It belongs in lane B, derived from the same live provider fetch that already supplies ",[824,1179,1127],{},[824,1181,1130],{},". ",[812,1184,1185],{},"Freshness is a precondition on the read, not a lane in the taxonomy.",[854,1187,1189],{"id":1188},"_3-architecture","3. Architecture",[1191,1192],"doc-diagram",{"caption":1193,"name":1194},"Lane A reads the open web through an agent. Lane B fetches snapshots. Both append through one write path.","signals-search-component",[809,1196,1197],{},"The ASCII below is the spine only.",[809,1199,1200,1201,1204],{},"Four Inngest functions, each invoked through ",[824,1202,1203],{},"step_invoke_typed",", plus three workflows it calls:",[866,1206,1207,1220],{},[869,1208,1209],{},[872,1210,1211,1214,1217],{},[875,1212,1213],{},"Component",[875,1215,1216],{},"Kind",[875,1218,1219],{},"Owns",[882,1221,1222,1234,1252,1265],{},[872,1223,1224,1228,1231],{},[887,1225,1226],{},[824,1227,826],{},[887,1229,1230],{},"orchestrator",[887,1232,1233],{},"preflight, run lifecycle, routing, fan-out, follow-up, finalize",[872,1235,1236,1241,1246],{},[887,1237,1238],{},[824,1239,1240],{},"component.signals.search",[887,1242,1243],{},[812,1244,1245],{},"agent",[887,1247,1248,1249],{},"plan → search → fetch → extract. ",[812,1250,1251],{},"No DB writes.",[872,1253,1254,1259,1262],{},[887,1255,1256],{},[824,1257,1258],{},"component.signals.collect.*",[887,1260,1261],{},"deterministic",[887,1263,1264],{},"snapshot fetch + diff, one per source",[872,1266,1267,1272,1274],{},[887,1268,1269],{},[824,1270,1271],{},"component.signals.ingest",[887,1273,1261],{},[887,1275,1276,1277],{},"normalize → dedup → append. ",[812,1278,1279],{},"The one write path.",[1281,1282,1287],"pre",{"className":1283,"code":1285,"language":1286},[1284],"language-text","workflow\u002Fsignals_search.requested\n        ↓\n  workflow.signals_search\n    1 prepare + preflight        budget guard, mock flag\n    2 start run                  workflow_runs + SSE\n    3 route signal_types[]       split by detection mechanism\n    4 invoke lanes               ctx.group.parallel, one lane may degrade alone\n    5 invoke signals.ingest      one write path for every lane\n    6 follow up                  resolve + enrich each new subject   ← §6\n    7 finalize                   counts, funnel, SSE done\n        ↓\n  ┌─ A · agent ──────────┐   ┌─ B · collectors (4) ─┐   ┌─ manual entry ─┐\n  └──────────┬───────────┘   └──────────┬───────────┘   └───────┬────────┘\n             └──────────────────────────┴───────────────────────┘\n                                  ↓\n                        component.signals.ingest\n                     normalize → dedup → append (INSERT only)\n                                  ↓\n              intel_sources · intel_signals · intel_signal_sources\n                                  ↓\n                      follow-up, by subject_type\n              company_search · people_search · enrichment\n","text",[824,1288,1285],{"__ignoreMap":1289},"",[809,1291,1292],{},"The split is what makes it reusable: callers see typed payloads, never internals. The agent inside lane A can be swapped for a deterministic Exa\u002FParallel fan-out without touching a caller or the write path.",[854,1294,1296],{"id":1295},"_4-lane-a-the-agent-component","4. Lane A — the agent component",[1012,1298,1300],{"id":1299},"_41-why-an-agent-here-and-nowhere-else","4.1 Why an agent here and nowhere else",[809,1302,1303],{},"The five lane-A types share one property: evidence is unstructured prose scattered across sources with no common API. A funding announcement lives in a press release, a trade publication, a company blog, or a filing. A hand-written query planner underfits that variety — exactly the case an agent handles well. Everything in lane B has a real API, and where a real API exists you want deterministic code driving it, not a model.",[1012,1305,1307],{"id":1306},"_42-prompt-strategy-one-prompt-five-sections","4.2 Prompt strategy — one prompt, five sections",[1281,1309,1312],{"className":1310,"code":1311,"language":1286},[1284],"## funding_round\nsources: crunchbase, techcrunch, press releases, regulatory filings\nNOT a match: a VC fund closing its own fund (the investor, not the target)\ndate: the announcement date, not the article publish date\npayload: { amount, currency, round, investors[] }\n",[824,1313,1311],{"__ignoreMap":1289},[809,1315,1316,1319,1320,1323],{},[812,1317,1318],{},"One session covers every requested type."," The prompt's active sections are the requested types; the agent plans ",[812,1321,1322],{},"at least one query family per requested type before deepening any one",", and labels an extracted signal by the section rules — never by which query surfaced the source. Both rules exist because a multi-type call otherwise degenerates: the agent burns the search cap on the first productive type, or it mislabels a funding article as an exec change because that's what it was looking for.",[809,1325,1326,1329,1330,1333],{},[812,1327,1328],{},"No per-type managed-agent skills yet."," Skills earn their provisioning cost when a type needs its own eval gate; each one adds a ",[824,1331,1332],{},"provision_all"," cycle and drift risk. Extract a section into a skill when:",[1335,1336,1337,1341,1344],"ul",{},[1338,1339,1340],"li",{},"a type regresses and the failure can't be localized without an isolated eval",[1338,1342,1343],{},"its rules outgrow ~15 lines and start crowding the shared grounding rules",[1338,1345,1346],{},"the type count passes ~8 and the prompt stops being readable",[809,1348,1349],{},"Same call already made on the sonar extractor: narrow prompt, eval-gated, no skill layer.",[1012,1351,1353],{"id":1352},"_43-tools-two-shared-not-per-type","4.3 Tools — two, shared, not per type",[809,1355,1356],{},"Two tools in the agent's context, three providers behind them:",[1281,1358,1361],{"className":1359,"code":1360,"language":1286},[1284],"search(query, objective, lookback_days, allowed_domains[], category?)\n   └─ Exa + Parallel, deterministic fan-out, merged and deduped by URL\nfetch(url)\n   └─ Firecrawl, via the sanitized wrapper\n",[824,1362,1360],{"__ignoreMap":1289},[809,1364,1365,1368,1369,1372],{},[812,1366,1367],{},"The agent picks the query, not the vendor."," It has no feedback loop on which index recalls better — it never sees what the other one would have returned — and the independent benchmark puts Exa, Parallel and Firecrawl in a statistical tie, so there is no correct choice to learn. Exposing three search tools would add tool-definition tokens, a decision per call, and a hidden variable in every eval. Exa's category filter is exposed as the ",[824,1370,1371],{},"category"," parameter and routed internally: capability, not vendor.",[809,1374,1375,1376,1379],{},"Fan-out is keyed to ",[824,1377,1378],{},"depth",", so the policy is deterministic and evaluable:",[866,1381,1382,1392],{},[869,1383,1384],{},[872,1385,1386,1389],{},[875,1387,1388],{},"Depth",[875,1390,1391],{},"Policy",[882,1393,1394,1404],{},[872,1395,1396,1401],{},[887,1397,1398],{},[824,1399,1400],{},"quick",[887,1402,1403],{},"Exa; Parallel only on thin results",[872,1405,1406,1415],{},[887,1407,1408,1411,1412],{},[824,1409,1410],{},"standard"," · ",[824,1413,1414],{},"deep",[887,1416,1417],{},"both, merged",[809,1419,1420,1427,1428,1431,1432,1435,1436,1439,1440,1443],{},[812,1421,1422,1423,1426],{},"Why ",[824,1424,1425],{},"fetch"," is Firecrawl."," Lane A reads press releases, company blogs and trade pubs — JS-heavy and often unscrapeable. ",[824,1429,1430],{},"src\u002Fshared\u002Fcompany\u002Fsanitized_firecrawl_tools.py"," already handles that surface: full markdown, injection sanitizing (HTML comments + zero-width chars stripped), error absorption so the agent doesn't retry-loop on a dead URL, a 50k char cap, ",[824,1433,1434],{},"firecrawl_rate_limit"," at 5\u002Fs, and ",[824,1437,1438],{},"FIRECRAWL_SCRAPE_COST_PER_PAGE"," in ",[824,1441,1442],{},"vendor_pricing",". Exa\u002FParallel contents cover search results, not arbitrary fetches.",[809,1445,1446,1453,1454,1457,1458,1461,1462,1465,1466,1469,1470,1472,1473,1476,1477,1480],{},[812,1447,1448,1449,1452],{},"Not the hosted MCP servers, the vendor CLIs, or the model-native ",[824,1450,1451],{},"web_search","."," See §9 — vendor limits are reactive (Exa 10 QPS, Parallel 600\u002Fmin), our limiters sit under them (",[824,1455,1456],{},"exa_rate_limit"," 8\u002Fs, ",[824,1459,1460],{},"parallel_rate_limit"," 5\u002Fs) and are Redis-backed so one account budget divides across concurrent runs; and provider spend has to reach ",[824,1463,1464],{},"ai_usage_log"," for data we resell. An uncapped Exa burst turned 38s of work into a 443s retry stall (run ",[824,1467,1468],{},"a1e68be1","). Model-native ",[824,1471,1451],{}," fails separately: its results come back as ",[824,1474,1475],{},"encrypted_content",", so it cannot populate ",[824,1478,1479],{},"intel_sources.payload"," at all.",[806,1482,1483],{},[809,1484,1485,1491,1492,1495,1496,1499,1500,1503,1504,1507,1508,1511],{},[812,1486,1487,1488,1168],{},"Two prerequisites, both in ",[824,1489,1490],{},"src\u002Fclients\u002Fparallel_client.py"," it wires ",[812,1493,1494],{},"no rate limiter"," (",[824,1497,1498],{},"parallel_rate_limit()"," exists but its only caller is ",[824,1501,1502],{},"workflow_engine\u002F...\u002Fpeople_parallel_tools.py",") and ",[812,1505,1506],{},"no sanitizer"," (Exa has ",[824,1509,1510],{},"SanitizedExaTools",", Firecrawl has its wrapper; Parallel excerpts reach the agent raw). Both land before §12 step 4.",[1012,1513,1515],{"id":1514},"_44-guardrails","4.4 Guardrails",[809,1517,1518,1411,1521,1524],{},[824,1519,1520],{},"effort",[824,1522,1523],{},"task_budget"," · a max-search count stated in the prompt · the existing agent-run reaper. Cost is otherwise unbounded, and that is the main risk this lane carries relative to the deterministic pipelines we've been converging on.",[1012,1526,1528],{"id":1527},"_45-what-the-agent-must-never-do","4.5 What the agent must never do",[1335,1530,1531,1544,1550,1564],{},[1338,1532,1533,1536,1537,1439,1540,1543],{},[812,1534,1535],{},"Emit a type outside the 12-value intel taxonomy."," Distinct from the 13-value CRM ",[824,1538,1539],{},"SignalType",[824,1541,1542],{},"src\u002Fshared\u002Fsignal_types.py","; needs its own module + alias table on the same pattern.",[1338,1545,1546,1549],{},[812,1547,1548],{},"Assert a field the fetched source doesn't state."," No inferred country, size, funding total, revenue.",[1338,1551,1552,1555,1556,1559,1560,1563],{},[812,1553,1554],{},"Resolve entity identity."," It emits ",[824,1557,1558],{},"company_domain"," \u002F ",[824,1561,1562],{},"person_linkedin_url","; resolution is deterministic.",[1338,1565,1566],{},[812,1567,1568],{},"Write to the database.",[809,1570,1571,1572,1575,1576,1579,1580,1582,1583,1586],{},"Returns two artifacts: ",[824,1573,1574],{},"sources.json"," (provider responses ",[812,1577,1578],{},"verbatim"," → ",[824,1581,1479],{},", the replay and takedown record) and ",[824,1584,1585],{},"signals.json"," (extracted rows referencing sources by index).",[854,1588,1590],{"id":1589},"_5-lane-b-the-collectors","5. Lane B — the collectors",[809,1592,1593],{},"Each polls a real API, stores a snapshot, emits signals from the diff. All deterministic, no model.",[866,1595,1596,1608],{},[869,1597,1598],{},[872,1599,1600,1603,1606],{},[875,1601,1602],{},"Collector",[875,1604,1605],{},"Source",[875,1607,1030],{},[882,1609,1610,1626,1640,1657],{},[872,1611,1612,1617,1620],{},[887,1613,1614],{},[824,1615,1616],{},"collect.meta_ads",[887,1618,1619],{},"Meta Ad Library API",[887,1621,1622,827,1624],{},[824,1623,1003],{},[824,1625,1102],{},[872,1627,1628,1633,1636],{},[887,1629,1630],{},[824,1631,1632],{},"collect.job_boards",[887,1634,1635],{},"Greenhouse, Lever",[887,1637,1638],{},[824,1639,1105],{},[872,1641,1642,1647,1650],{},[887,1643,1644],{},[824,1645,1646],{},"collect.tech_stack",[887,1648,1649],{},"fetch + fingerprint diff",[887,1651,1652,1654,1655],{},[824,1653,1108],{},", the sitemap half of ",[824,1656,1058],{},[872,1658,1659,1664,1667],{},[887,1660,1661],{},[824,1662,1663],{},"collect.people_diff",[887,1665,1666],{},"licensed people-data provider",[887,1668,1669,827,1671,827,1673],{},[824,1670,1127],{},[824,1672,1130],{},[824,1674,1133],{},[809,1676,1677],{},"These are the same mechanism the monitor and scraper producers need, so they were always going to be built. This design only asserts the search agent shouldn't duplicate them.",[1012,1679,1681],{"id":1680},"_51-on-linkedin","5.1 On LinkedIn",[809,1683,1684,1685,1688,1689,1559,1691,1559,1693,1695],{},"There is ",[812,1686,1687],{},"no legitimate LinkedIn API or MCP"," for post search or profile-change feeds. The official APIs don't expose them; anything that does is a scraper wrapper — a ToS violation, aggressively blocked, and a poor foundation for a proprietary database we resell. The path for ",[824,1690,1127],{},[824,1692,1130],{},[824,1694,1133],{}," is a licensed provider (CoreSignal-class, already wired) polled on a schedule and diffed.",[809,1697,1698,1699,1702],{},"For these types ",[812,1700,1701],{},"the binding constraint is data licensing, not agent capability"," — no skill, tool or subagent moves it.",[854,1704,1706],{"id":1705},"_6-follow-up-make-the-signal-actionable","6. Follow-up — make the signal actionable",[809,1708,1709],{},"A signal is a fact about a subject. Nobody can act on it until the subject has an address.",[809,1711,1712,1714,1715,1718,1719,1721],{},[824,1713,1052],{}," on ",[824,1716,1717],{},"acme.com"," is useful when we hold the firmographics and the people to contact. ",[824,1720,1127],{}," on a LinkedIn URL is useful when we hold the new employer and a work email. The ingest step writes the fact. The follow-up step makes it usable.",[809,1723,1724],{},[812,1725,1726],{},"The follow-up runs after ingest, and only for a subject that needs it.",[866,1728,1729,1740],{},[869,1730,1731],{},[872,1732,1733,1737],{},[875,1734,1735],{},[824,1736,907],{},[875,1738,1739],{},"Follow-up",[882,1741,1742,1757],{},[872,1743,1744,1748],{},[887,1745,1746],{},[824,1747,321],{},[887,1749,1750,1753,1754],{},[824,1751,1752],{},"company_search"," in resolve mode, then ",[824,1755,1756],{},"enrichment(subject_type=company)",[872,1758,1759,1763],{},[887,1760,1761],{},[824,1762,1073],{},[887,1764,1765,1753,1768,1771],{},[824,1766,1767],{},"people_search",[824,1769,1770],{},"enrichment(subject_type=person)",", then the employer roll-up",[809,1773,1774],{},"Three rules keep the cost bounded.",[1776,1777,1778,1788,1794],"ol",{},[1338,1779,1780,1783,1784,1787],{},[812,1781,1782],{},"Skip a subject we already hold and that is fresh."," Enrichment already owns the freshness rule, so the follow-up passes ",[824,1785,1786],{},"refresh: stale"," and lets it decide. A well-known company costs one read.",[1338,1789,1790,1793],{},[812,1791,1792],{},"The search runs in resolve mode, not discovery mode."," It takes a name or a URL and returns one identity. It runs no planner agent and no vendor search. Discovery mode is for a brief; a signal already names its subject.",[1338,1795,1796,1799,1800,1803],{},[812,1797,1798],{},"The follow-up is a dispatch, not a block."," It fires after ",[824,1801,1802],{},"complete_workflow_run",", in the same shape as the two trailing lanes on Sonar and Headhunter. The signal roster appears at once. The addresses fill in behind it.",[809,1805,1806,1000,1809,1811],{},[812,1807,1808],{},"A person signal also enriches the employer.",[824,1810,1127],{}," names a new company. That company is often new to us. The roll-up resolves it and enriches it, so the person signal seeds a company we can sell to.",[809,1813,1814,1817],{},[824,1815,1816],{},"follow_up: none"," turns the whole stage off. A monitor that re-checks known companies every night does not need it.",[854,1819,1821],{"id":1820},"_7-the-shared-write-path","7. The shared write path",[809,1823,1824,1826],{},[824,1825,1271],{},", identical for every producer:",[1776,1828,1829,1856,1877],{},[1338,1830,1831,1834,1835,1579,1837,827,1840,1579,1842,1844,1845,1847,1848,1851,1852,1855],{},[812,1832,1833],{},"Normalize"," — resolve ",[824,1836,1558],{},[824,1838,1839],{},"intel_companies",[824,1841,1562],{},[824,1843,1176],{},". Stamp ",[824,1846,907],{}," + ",[824,1849,1850],{},"subject_id",". Write ",[824,1853,1854],{},"related_company_id"," so a person signal rolls up to the employer feed.",[1338,1857,1858,1861,1862,1865,1866,1868,1869,1872,1873,1876],{},[812,1859,1860],{},"Dedup"," — ",[824,1863,1864],{},"dedup_key = hash(subject · type · observed window)",", enforced by a unique index. MISS appends a new ",[824,1867,963],{}," row. HIT appends ",[812,1870,1871],{},"no"," signal and instead attaches the new outlet as an ",[824,1874,1875],{},"intel_signal_sources"," link, so a second outlet reporting the same raise never doubles the fact.",[1338,1878,1879,1882],{},[812,1880,1881],{},"Append"," — INSERT only. No UPDATE, no DELETE. Decay applied at read time.",[809,1884,1885,1886,1452],{},"Adding a collector therefore adds ",[812,1887,1888],{},"no write code",[854,1890,1892],{"id":1891},"_8-data-contracts","8. Data contracts",[809,1894,1895,1896,1899],{},"A call carries ",[812,1897,1898],{},"a list of types, not one type"," — see §9. The accounting fields are therefore per-type, or a five-type run reports one number and no one can tell which section failed.",[1281,1901,1905],{"className":1902,"code":1903,"language":1904,"meta":1289,"style":1289},"language-python shiki shiki-themes github-dark","class SignalSearchInput(InngestPayload):\n    run_context: ComponentRunContext\n    query: str\n    signal_types: list[IntelSignalType] | None   # None → agent picks within lane A\n    lookback_days: int = 30\n    geo: str | None = None\n    target_per_type: int = 10    # per requested type, NOT a run total\n    depth: Literal[\"quick\", \"standard\", \"deep\"] = \"standard\"\n    require_company: bool = True\n    emit_progress: bool = True\n    follow_up: Literal[\"none\", \"resolve\", \"enrich\"] = \"enrich\"   # §6\n\n\nclass ExtractedSignal(BaseModel):\n    signal_type: IntelSignalType\n    description: str\n    observed_at: date            # when the event happened, NOT when it was published\n    source_ref: int              # index into sources[]\n    snippet: str\n    company_domain: str | None\n    person_linkedin_url: str | None\n\n\nclass PerTypeResult(BaseModel):\n    signal_count: int\n    queries_run: int\n    zero_result_reason: str | None   # why THIS type came back empty\n\n\nclass SignalSearchResult(InngestPayload):\n    sources: list[RawSource]                        # verbatim provider payloads\n    signals: list[ExtractedSignal]\n    per_type: dict[IntelSignalType, PerTypeResult]  # attribution per requested type\n    queries_run: int                                # run total\n    rejected_types: list[IntelSignalType]           # asked for, but not lane A\n    zero_result_reason: str | None                  # whole-run failure only\n    follow_up: FollowUpSummary                      # subjects resolved \u002F enriched \u002F skipped\n    usage: AgentUsage\n","python",[824,1906,1907,1914,1919,1924,1929,1934,1939,1944,1949,1954,1959,1964,1970,1974,1979,1985,1991,1997,2003,2009,2014,2019,2023,2028,2034,2040,2046,2052,2057,2062,2067,2073,2079,2085,2091,2097,2103,2109],{"__ignoreMap":1289},[1908,1909,1911],"span",{"class":1910,"line":22},"line",[1908,1912,1913],{},"class SignalSearchInput(InngestPayload):\n",[1908,1915,1916],{"class":1910,"line":32},[1908,1917,1918],{},"    run_context: ComponentRunContext\n",[1908,1920,1921],{"class":1910,"line":233},[1908,1922,1923],{},"    query: str\n",[1908,1925,1926],{"class":1910,"line":244},[1908,1927,1928],{},"    signal_types: list[IntelSignalType] | None   # None → agent picks within lane A\n",[1908,1930,1931],{"class":1910,"line":264},[1908,1932,1933],{},"    lookback_days: int = 30\n",[1908,1935,1936],{"class":1910,"line":222},[1908,1937,1938],{},"    geo: str | None = None\n",[1908,1940,1941],{"class":1910,"line":360},[1908,1942,1943],{},"    target_per_type: int = 10    # per requested type, NOT a run total\n",[1908,1945,1946],{"class":1910,"line":368},[1908,1947,1948],{},"    depth: Literal[\"quick\", \"standard\", \"deep\"] = \"standard\"\n",[1908,1950,1951],{"class":1910,"line":375},[1908,1952,1953],{},"    require_company: bool = True\n",[1908,1955,1956],{"class":1910,"line":157},[1908,1957,1958],{},"    emit_progress: bool = True\n",[1908,1960,1961],{"class":1910,"line":182},[1908,1962,1963],{},"    follow_up: Literal[\"none\", \"resolve\", \"enrich\"] = \"enrich\"   # §6\n",[1908,1965,1966],{"class":1910,"line":290},[1908,1967,1969],{"emptyLinePlaceholder":1968},true,"\n",[1908,1971,1972],{"class":1910,"line":280},[1908,1973,1969],{"emptyLinePlaceholder":1968},[1908,1975,1976],{"class":1910,"line":272},[1908,1977,1978],{},"class ExtractedSignal(BaseModel):\n",[1908,1980,1982],{"class":1910,"line":1981},15,[1908,1983,1984],{},"    signal_type: IntelSignalType\n",[1908,1986,1988],{"class":1910,"line":1987},16,[1908,1989,1990],{},"    description: str\n",[1908,1992,1994],{"class":1910,"line":1993},17,[1908,1995,1996],{},"    observed_at: date            # when the event happened, NOT when it was published\n",[1908,1998,2000],{"class":1910,"line":1999},18,[1908,2001,2002],{},"    source_ref: int              # index into sources[]\n",[1908,2004,2006],{"class":1910,"line":2005},19,[1908,2007,2008],{},"    snippet: str\n",[1908,2010,2011],{"class":1910,"line":520},[1908,2012,2013],{},"    company_domain: str | None\n",[1908,2015,2016],{"class":1910,"line":318},[1908,2017,2018],{},"    person_linkedin_url: str | None\n",[1908,2020,2021],{"class":1910,"line":327},[1908,2022,1969],{"emptyLinePlaceholder":1968},[1908,2024,2026],{"class":1910,"line":2025},23,[1908,2027,1969],{"emptyLinePlaceholder":1968},[1908,2029,2031],{"class":1910,"line":2030},24,[1908,2032,2033],{},"class PerTypeResult(BaseModel):\n",[1908,2035,2037],{"class":1910,"line":2036},25,[1908,2038,2039],{},"    signal_count: int\n",[1908,2041,2043],{"class":1910,"line":2042},26,[1908,2044,2045],{},"    queries_run: int\n",[1908,2047,2049],{"class":1910,"line":2048},27,[1908,2050,2051],{},"    zero_result_reason: str | None   # why THIS type came back empty\n",[1908,2053,2055],{"class":1910,"line":2054},28,[1908,2056,1969],{"emptyLinePlaceholder":1968},[1908,2058,2060],{"class":1910,"line":2059},29,[1908,2061,1969],{"emptyLinePlaceholder":1968},[1908,2063,2064],{"class":1910,"line":481},[1908,2065,2066],{},"class SignalSearchResult(InngestPayload):\n",[1908,2068,2070],{"class":1910,"line":2069},31,[1908,2071,2072],{},"    sources: list[RawSource]                        # verbatim provider payloads\n",[1908,2074,2076],{"class":1910,"line":2075},32,[1908,2077,2078],{},"    signals: list[ExtractedSignal]\n",[1908,2080,2082],{"class":1910,"line":2081},33,[1908,2083,2084],{},"    per_type: dict[IntelSignalType, PerTypeResult]  # attribution per requested type\n",[1908,2086,2088],{"class":1910,"line":2087},34,[1908,2089,2090],{},"    queries_run: int                                # run total\n",[1908,2092,2094],{"class":1910,"line":2093},35,[1908,2095,2096],{},"    rejected_types: list[IntelSignalType]           # asked for, but not lane A\n",[1908,2098,2100],{"class":1910,"line":2099},36,[1908,2101,2102],{},"    zero_result_reason: str | None                  # whole-run failure only\n",[1908,2104,2106],{"class":1910,"line":2105},37,[1908,2107,2108],{},"    follow_up: FollowUpSummary                      # subjects resolved \u002F enriched \u002F skipped\n",[1908,2110,2112],{"class":1910,"line":2111},38,[1908,2113,2114],{},"    usage: AgentUsage\n",[809,2116,2117,2120,2121,2123],{},[824,2118,2119],{},"target_per_type"," is per requested type because a run total silently shrinks each type's quota as the list grows — five types against a total of 25 is five each, and ",[824,2122,1414],{}," stops meaning anything.",[809,2125,2126,2128,2129,2132],{},[824,2127,1378],{}," maps to agent controls so callers never touch them. Budget and search cap ",[812,2130,2131],{},"scale with the number of requested types",", for the same reason:",[866,2134,2135,2150],{},[869,2136,2137],{},[872,2138,2139,2141,2144,2147],{},[875,2140,1388],{},[875,2142,2143],{},"Effort",[875,2145,2146],{},"Base task budget",[875,2148,2149],{},"Base max searches",[882,2151,2152,2167,2182],{},[872,2153,2154,2158,2161,2164],{},[887,2155,2156],{},[824,2157,1400],{},[887,2159,2160],{},"low",[887,2162,2163],{},"30k",[887,2165,2166],{},"8",[872,2168,2169,2173,2176,2179],{},[887,2170,2171],{},[824,2172,1410],{},[887,2174,2175],{},"medium",[887,2177,2178],{},"80k",[887,2180,2181],{},"25",[872,2183,2184,2188,2191,2194],{},[887,2185,2186],{},[824,2187,1414],{},[887,2189,2190],{},"high",[887,2192,2193],{},"250k",[887,2195,2196],{},"80",[1281,2198,2201],{"className":2199,"code":2200,"language":1286},[1284],"task_budget  = base × (1 + 0.5 × (n_types − 1))    capped at 2× base\nmax_searches = base × (1 + 0.5 × (n_types − 1))    capped at 2× base\n",[824,2202,2200],{"__ignoreMap":1289},[809,2204,2205],{},"Sub-linear on purpose: types share a corpus, so the second type costs far less than the first. The 2× cap keeps a five-type call from being five times the bill. Both the multiplier and the cap are guesses until §10 Q4 is measured.",[854,2207,2209],{"id":2208},"_9-decisions-and-rejected-alternatives","9. Decisions and rejected alternatives",[866,2211,2212,2225],{},[869,2213,2214],{},[872,2215,2216,2219,2222],{},[875,2217,2218],{},"Decision",[875,2220,2221],{},"Rejected",[875,2223,2224],{},"Why",[882,2226,2227,2238,2257,2272,2283,2294,2305,2318,2353,2364,2375,2389,2400,2411,2422,2433],{},[872,2228,2229,2232,2235],{},[887,2230,2231],{},"Route by detection mechanism",[887,2233,2234],{},"send all 12 types to the agent",[887,2236,2237],{},"absence and delta aren't searchable; the agent can't know it's wrong",[872,2239,2240,2243,2246],{},[887,2241,2242],{},"Many types per call",[887,2244,2245],{},"one type per call",[887,2247,2248,2249,2252,2253,2256],{},"the search corpus is shared. Per-type calls replan, re-query overlapping terms, and refetch the same URLs with no cache between sibling sessions. A single call also keeps mixed-lane requests (",[824,2250,2251],{},"[funding_round, started_meta_ads]",") inside the component instead of pushing routing onto every caller — and ",[824,2254,2255],{},"signal_types: None"," is already multi-type, so a scalar contract couldn't express its own default.",[872,2258,2259,2262,2265],{},[887,2260,2261],{},"Fan out by lane, never by type",[887,2263,2264],{},"orchestrator fans out one agent invoke per type",[887,2266,2267,2268,2271],{},"same reason. Per-type fan-out re-earns exactly the cost the shared corpus saves, and buys only isolation — which evals get by running single-type without the runtime doing so. Fan-out stays available as a later scaling axis over ",[812,2269,2270],{},"targets or query batches",", not types.",[872,2273,2274,2277,2280],{},[887,2275,2276],{},"One agent, one prompt, five sections",[887,2278,2279],{},"one subagent per type",[887,2281,2282],{},"cost multiplies and cross-type evidence reuse is lost — one funding article routinely evidences three types",[872,2284,2285,2288,2291],{},[887,2286,2287],{},"Two shared tools",[887,2289,2290],{},"one tool or MCP per type",[887,2292,2293],{},"per-type tools only pay off where a structured API exists, and exactly there the deterministic collector is the right instrument",[872,2295,2296,2299,2302],{},[887,2297,2298],{},"Two tools, three providers behind them",[887,2300,2301],{},"one tool per vendor, agent picks",[887,2303,2304],{},"the agent has no feedback loop on index quality and the engines benchmark as a statistical tie — the \"choice\" would be noise, plus a hidden variable in every eval",[872,2306,2307,2312,2315],{},[887,2308,2309,2311],{},[824,2310,1425],{}," = Firecrawl",[887,2313,2314],{},"Exa \u002F Parallel contents",[887,2316,2317],{},"those cover search results, not arbitrary URLs; the sanitized Firecrawl wrapper already handles JS pages, injection stripping, dead-URL absorption and cost metering",[872,2319,2320,2323,2333],{},[887,2321,2322],{},"Wrap our own Exa\u002FParallel clients",[887,2324,2325,2326,827,2329,2332],{},"hosted MCP servers (",[824,2327,2328],{},"mcp.exa.ai",[824,2330,2331],{},"search.parallel.ai","); the official Parallel CLI in the sandbox",[887,2334,2335,2336,2339,2340,2343,2344,2347,2348,1559,2350,2352],{},"Not because the vendors advise it — they're neutral, and the usual \"MCP for agent-driven calls, API for deterministic ones\" framing arguably favours MCP here. It turns on requirements the vendors don't address: ",[812,2337,2338],{},"proactive pacing"," under a per-account ceiling (their limits are enforced reactively by 429), ",[812,2341,2342],{},"one rate budget shared across concurrent Inngest runs"," (an MCP session is blind to its siblings), and ",[812,2345,2346],{},"per-run cost attribution"," into ",[824,2349,1464],{},[824,2351,1442],{}," for data we resell. MCP genuinely wins on maintenance and on being native to Managed Agents; those don't outweigh billing we can't see.",[872,2354,2355,2358,2361],{},[887,2356,2357],{},"Prompt sections now, skills later",[887,2359,2360],{},"per-type skills from day one",[887,2362,2363],{},"skills earn their provisioning cost only at an isolated eval gate",[872,2365,2366,2369,2372],{},[887,2367,2368],{},"Licensed provider for people signals",[887,2370,2371],{},"LinkedIn MCP or scraper",[887,2373,2374],{},"no legitimate API exists; constraint is licensing, not capability",[872,2376,2377,2383,2386],{},[887,2378,2379,2380,2382],{},"Write into the ",[824,2381,963],{}," spine",[887,2384,2385],{},"new tables owned by this component",[887,2387,2388],{},"the store is decided and shared with three other producers",[872,2390,2391,2394,2397],{},[887,2392,2393],{},"Search and ingest as separate components",[887,2395,2396],{},"one component that searches and writes",[887,2398,2399],{},"chat needs a read-only search, a composing workflow would double-write, and the agent must stay swappable",[872,2401,2402,2405,2408],{},[887,2403,2404],{},"Follow up by calling search + enrichment",[887,2406,2407],{},"resolve and enrich inside the ingest step",[887,2409,2410],{},"ingest is the one write path and it must stay deterministic and cheap; resolve and enrich are owned elsewhere, and duplicating them here would fork two waterfalls",[872,2412,2413,2416,2419],{},[887,2414,2415],{},"The follow-up is a trailing dispatch",[887,2417,2418],{},"block the run until every subject is enriched",[887,2420,2421],{},"the signal roster is useful at once; enrichment adds 50 to 150 seconds per person for the email lane alone",[872,2423,2424,2427,2430],{},[887,2425,2426],{},"Resolve mode on the search workflows",[887,2428,2429],{},"a private resolver inside signals",[887,2431,2432],{},"a second resolver drifts from the one that search uses, and dedup then splits",[872,2434,2435,2441,2447],{},[887,2436,2437,2438,2440],{},"New ",[824,2439,830],{}," package",[887,2442,2443,2444],{},"placing it under ",[824,2445,2446],{},"components\u002Fcompany\u002F",[887,2448,2449],{},"rows are signal-first; company and people components are consumers, not parents",[854,2451,2453],{"id":2452},"_10-open-questions","10. Open questions",[1776,2455,2456,2469,2479,2497,2506],{},[1338,2457,2458,2461,2462,2464,2465,2468],{},[812,2459,2460],{},"Identity creation policy."," When the agent surfaces a signal for a company absent from ",[824,2463,1839],{},", does normalize create the entity or drop the signal? Dropping loses real signals; creating means an agent extraction seeds the intelligence DB. The §6 follow-up shifts this: normalize can create an ",[812,2466,2467],{},"identity-only"," row and let the follow-up fill it from real sources, so the seeded row is never an agent's guess for long. It does not remove the question, because a wrong identity still creates a row that the follow-up then fails to resolve.",[1338,2470,2471,2474,2475,2478],{},[812,2472,2473],{},"Undated signals."," Decay runs off ",[824,2476,2477],{},"observed_at",". When a source states no date: drop, fall back to source publish date, or store with a confidence marker? A silent fallback corrupts decay.",[1338,2480,2481,2484,2485,2488,2489,2492,2493,2496],{},[812,2482,2483],{},"Ingest provenance and feed materialization."," The decided DB design includes ",[824,2486,2487],{},"intel_signal_ingests"," (one row per discovery, so a run can list every signal it surfaced including re-finds) and ",[824,2490,2491],{},"intel_org_signal_feed"," (per-org scored copy). ",[812,2494,2495],{},"Neither is written by this component today."," Without the ingest log, a dedup hit leaves no record that this run found the signal — so the Signals app can't list its own results. Either both come back into scope, or a run-scoped results table replaces them.",[1338,2498,2499,2502,2503,2505],{},[812,2500,2501],{},"Cost ceiling per run."," Sets ",[824,2504,1523],{}," and the search cap, and calibrates the §8 per-type scaling multiplier. Unset, lane A is the only unbounded cost in the design.",[1338,2507,2508,2515],{},[812,2509,2510,2511,2514],{},"Cap on ",[824,2512,2513],{},"len(signal_types)","?"," Moot while lane A holds five types — asking for all of them is the normal case. It stops being moot if the taxonomy grows: at some type count a single session's context can no longer hold the sections plus the fetched corpus, and that is the point where per-type fan-out becomes right after all. Revisit at the same threshold as the §4.2 skill-extraction trigger (~8 types).",[854,2517,2519],{"id":2518},"_11-package-layout","11. Package layout",[1281,2521,2524],{"className":2522,"code":2523,"language":1286},[1284],"src\u002Finngest_functions\u002F\n  workflows\u002Fsignals_search\u002F\n    signals_search.py            orchestrator\n    steps\u002F{prepare,route,follow_up,finalize}.py\n  components\u002Fsignals\u002F\n    search.py                    lane A, agent\n    ingest.py                    normalize → dedup → append\n    collect\u002F{meta_ads,job_boards,tech_stack,people_diff}.py\n    schemas.py\nsrc\u002Fagents\u002Fsignals\u002F\n    open_web_search.py           agent spec + prompt\nsrc\u002Fshared\u002F\n    intel_signal_types.py        the 12-value vocabulary + aliases\n",[824,2525,2523],{"__ignoreMap":1289},[854,2527,2529],{"id":2528},"_12-build-order","12. Build order",[866,2531,2532,2545],{},[869,2533,2534],{},[872,2535,2536,2539,2542],{},[875,2537,2538],{},"#",[875,2540,2541],{},"Step",[875,2543,2544],{},"Why first",[882,2546,2547,2563,2575,2586,2603,2616,2628,2639],{},[872,2548,2549,2552,2560],{},[887,2550,2551],{},"1",[887,2553,2554,1847,2557],{},[824,2555,2556],{},"intel_signal_types.py",[824,2558,2559],{},"schemas.py",[887,2561,2562],{},"every other piece types against it",[872,2564,2565,2568,2572],{},[887,2566,2567],{},"2",[887,2569,2570],{},[824,2571,1271],{},[887,2573,2574],{},"the write contract; unblocks all four producers",[872,2576,2577,2580,2583],{},[887,2578,2579],{},"3",[887,2581,2582],{},"Routing rule in the orchestrator",[887,2584,2585],{},"cheapest lever, and it gates what lane A ever sees",[872,2587,2588,2591,2600],{},[887,2589,2590],{},"3.5",[887,2592,2593,2596,2597,2599],{},[824,2594,2595],{},"parallel_client",": wire ",[824,2598,1460],{}," + a sanitizer",[887,2601,2602],{},"lane A is otherwise uncapped against 600\u002Fmin and feeds raw excerpts to the agent (§4.3)",[872,2604,2605,2608,2613],{},[887,2606,2607],{},"4",[887,2609,2610,2612],{},[824,2611,1240],{}," + agent spec",[887,2614,2615],{},"the new capability",[872,2617,2618,2621,2625],{},[887,2619,2620],{},"5",[887,2622,2623],{},[824,2624,1663],{},[887,2626,2627],{},"3 of 7 lane-B types from one provider fetch",[872,2629,2630,2633,2636],{},[887,2631,2632],{},"6",[887,2634,2635],{},"Remaining collectors",[887,2637,2638],{},"ad library, job boards, tech stack",[872,2640,2641,2644,2647],{},[887,2642,2643],{},"7",[887,2645,2646],{},"The follow-up step (§6)",[887,2648,2649],{},"needs resolve mode on both search workflows and the freshness rule in enrichment",[809,2651,2652,2653,2655,2656,2658],{},"Resolve open questions 1 and 4 before step 4. Question 3 blocks any UI that lists a run's own results. Step 7 depends on ",[817,2654,35],{"href":459}," build step 4; without the freshness rule the follow-up cannot correct an employer that a ",[824,2657,1127],{}," signal just invalidated.",[854,2660,2662],{"id":2661},"_13-references","13. References",[1335,2664,2665,2681,2689,2697,2705,2713,2724,2732,2743],{},[1338,2666,2667,1495,2673,2676,2677,2680],{},[817,2668,2672],{"href":2669,"rel":2670},"https:\u002F\u002Fexa.ai\u002Fdocs\u002Freference\u002Frate-limits",[2671],"nofollow","Exa — rate limits",[824,2674,2675],{},"\u002Fsearch"," 10 QPS, ",[824,2678,2679],{},"\u002Fcontents"," 100 QPS)",[1338,2682,2683,2688],{},[817,2684,2687],{"href":2685,"rel":2686},"https:\u002F\u002Fdocs.parallel.ai\u002Fgetting-started\u002Frate-limits",[2671],"Parallel — API rate limits"," (Search 600\u002Fmin; GET reads don't count)",[1338,2690,2691,2696],{},[817,2692,2695],{"href":2693,"rel":2694},"https:\u002F\u002Fexa.ai\u002Fdocs\u002Freference\u002Fexa-mcp",[2671],"Exa MCP"," — the rejected option",[1338,2698,2699,2704],{},[817,2700,2703],{"href":2701,"rel":2702},"https:\u002F\u002Fdocs.parallel.ai\u002Fintegrations\u002Fmcp\u002Fsearch-mcp",[2671],"Parallel Search MCP"," — basic mode, ~25k chars\u002Fcall, filters go in query text",[1338,2706,2707,2712],{},[817,2708,2711],{"href":2709,"rel":2710},"https:\u002F\u002Fdocs.parallel.ai\u002Fintegrations\u002Fcli",[2671],"Parallel CLI"," — official, agent-targeted; also rejected (§9)",[1338,2714,2715,2720,2721,2723],{},[817,2716,2719],{"href":2717,"rel":2718},"https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fagents-and-tools\u002Ftool-use\u002Fweb-search-tool",[2671],"Anthropic web search tool"," — results return as ",[824,2722,1475],{},"; rejected (§4.3)",[1338,2725,2726,2731],{},[817,2727,2730],{"href":2728,"rel":2729},"https:\u002F\u002Faimultiple.com\u002Fagentic-search",[2671],"AIMultiple agentic search benchmark"," — Brave 14.89 · Firecrawl 14.58 · Exa 14.39 · Parallel 14.21\u002F13.50; top four statistically tied",[1338,2733,2734,2739,2740,2742],{},[817,2735,2738],{"href":2736,"rel":2737},"https:\u002F\u002Fwww.firecrawl.dev\u002Fpricing",[2671],"Firecrawl pricing"," — subscription credits, so ",[824,2741,1438],{}," assumes a tier",[1338,2744,2745,2748],{},[817,2746,2747],{"href":679},"Signals intelligence database"," — the decided store this writes into",[2750,2751,2752],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":1289,"searchDepth":32,"depth":233,"links":2754},[2755,2756,2759,2760,2767,2770,2771,2772,2773,2774,2775,2776,2777],{"id":856,"depth":32,"text":857},{"id":985,"depth":32,"text":986,"children":2757},[2758],{"id":1014,"depth":233,"text":1015},{"id":1188,"depth":32,"text":1189},{"id":1295,"depth":32,"text":1296,"children":2761},[2762,2763,2764,2765,2766],{"id":1299,"depth":233,"text":1300},{"id":1306,"depth":233,"text":1307},{"id":1352,"depth":233,"text":1353},{"id":1514,"depth":233,"text":1515},{"id":1527,"depth":233,"text":1528},{"id":1589,"depth":32,"text":1590,"children":2768},[2769],{"id":1680,"depth":233,"text":1681},{"id":1705,"depth":32,"text":1706},{"id":1820,"depth":32,"text":1821},{"id":1891,"depth":32,"text":1892},{"id":2208,"depth":32,"text":2209},{"id":2452,"depth":32,"text":2453},{"id":2518,"depth":32,"text":2519},{"id":2528,"depth":32,"text":2529},{"id":2661,"depth":32,"text":2662},"md",{},[2781,2782,2783,2784,2785],"engineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fsignals-search","engineering\u002Fsystem-design\u002Fworkflows\u002Fcompany-search","engineering\u002Fsystem-design\u002Fworkflows\u002Fpeople-search","engineering\u002Fsystem-design\u002Fworkflows\u002Fenrichment","proprietary-data\u002Fintelligence-databases\u002Fsignals-intelligence-database",{"title":469,"description":470},"engineering\u002Fsystem-design\u002Fworkflows\u002Fsignals-search",[51,12,142,472,473],"AgZtzvIjc49VIKGt0tbtoOflK9vjYfOX9uD5FMyeSYw",1788650199981]