[{"data":1,"prerenderedAt":3015},["ShallowReactive",2],{"docs-nav":3,"docs-article-engineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Fchannel-gateway":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":231,"body":799,"customComponent":480,"description":232,"extension":3001,"group":139,"lastUpdated":239,"meta":3002,"navigation":1381,"order":233,"path":230,"related":3003,"section":181,"seo":3011,"stem":3012,"tags":3013,"__hash__":3014},"docs\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Fchannel-gateway.md",{"type":800,"value":801,"toc":2966},"minimark",[802,806,810,816,821,918,921,932,942,946,953,956,1109,1112,1116,1126,1129,1141,1145,1151,1188,1237,1338,1341,1344,1348,1358,1456,1492,1497,1500,1535,1538,1542,1551,1610,1617,1624,1628,1674,1681,1690,1694,1737,1743,1747,1792,1796,1802,1808,1812,1919,1922,1929,1933,1938,1945,1949,1960,1970,1973,1977,1983,1990,1993,1997,2000,2006,2024,2028,2034,2037,2040,2070,2073,2113,2116,2127,2131,2134,2147,2150,2154,2160,2241,2244,2248,2307,2311,2317,2320,2323,2326,2426,2440,2455,2458,2462,2577,2581,2755,2759,2854,2857,2886,2890,2905,2909,2962],[803,804,231],"h1",{"id":805},"channel-gateway",[807,808,809],"p",{},"The Channel Gateway connects an interactive conversational channel to AgencyCore. It turns a vendor payload into one platform message. It turns one platform intent into a vendor message.",[811,812,813],"blockquote",{},[807,814,815],{},"One message shape in. One intent shape out. No model call, no prompt, and no business rule inside.",[817,818,820],"h2",{"id":819},"scope","Scope",[822,823,824,843],"table",{},[825,826,827],"thead",{},[828,829,830,834,837,840],"tr",{},[831,832,833],"th",{},"Channel",[831,835,836],{},"V1",[831,838,839],{},"Inbound",[831,841,842],{},"Outbound",[844,845,846,864,880,892,904],"tbody",{},[828,847,848,852,855,861],{},[849,850,851],"td",{},"Web chat",[849,853,854],{},"yes",[849,856,857],{},[858,859,860],"code",{},"WebChannelAdapter",[849,862,863],{},"SSE streams, not the Gateway",[828,865,866,869,872,877],{},[849,867,868],{},"Slack",[849,870,871],{},"later",[849,873,874],{},[858,875,876],{},"SlackChannelAdapter",[849,878,879],{},"Gateway delivery",[828,881,882,885,887,890],{},[849,883,884],{},"Telegram",[849,886,871],{},[849,888,889],{},"one more adapter",[849,891,879],{},[828,893,894,897,899,901],{},[849,895,896],{},"WhatsApp",[849,898,871],{},[849,900,889],{},[849,902,903],{},"Gateway delivery, window constrained",[828,905,906,909,912,915],{},[849,907,908],{},"Email",[849,910,911],{},"never",[849,913,914],{},"Nylas producer",[849,916,917],{},"email Tool",[807,919,920],{},"Ship web chat first. Remote interactive channels are deferred until the web-first interface slice proves the request, approval and Run progress loop. A later channel is one adapter and one connection type. It is not a new subsystem.",[807,922,923,927,928,931],{},[924,925,926],"strong",{},"Web chat is inbound only."," The browser holds an authenticated SSE connection, so the platform answers on the conversation stream and the Run stream. Only a remote channel needs Gateway delivery. See ",[929,930,253],"a",{"href":249},".",[807,933,934,937,938,941],{},[924,935,936],{},"Email is not a channel here."," Nylas owns email transport. Inbound email becomes a ",[929,939,940],{"href":261},"Trigger"," event, and outbound email is a Tool call.",[817,943,945],{"id":944},"what-the-web-slice-builds","What the web slice builds",[807,947,948,949,952],{},"⚠️ ",[924,950,951],{},"Most of this page describes a remote channel, and the web slice builds none of it."," Web chat is a first-party authenticated client. It sends no vendor payload, so it has no signature to verify, no workspace to resolve, no external user to link, no external thread to map, and no message to deliver back. A component whose only implementation skips its own job is a component the reader must still understand.",[807,954,955],{},"So the web slice builds two things from this page, and defers the rest with Slack.",[822,957,958,971],{},[825,959,960],{},[828,961,962,965,968],{},[831,963,964],{},"Part",[831,966,967],{},"Web slice",[831,969,970],{},"Why",[844,972,973,986,1001,1014,1026,1042,1057,1069,1091],{},[828,974,975,980,983],{},[849,976,977],{},[858,978,979],{},"NormalizedMessage",[849,981,982],{},"build",[849,984,985],{},"The Front Door contract. It is what makes a later channel one adapter.",[828,987,988,996,998],{},[849,989,990,993,994],{},[858,991,992],{},"InboundAdapter"," + ",[858,995,860],{},[849,997,982],{},[849,999,1000],{},"One decoder, called by the conversation route.",[828,1002,1003,1008,1011],{},[849,1004,1005],{},[858,1006,1007],{},"WebhookRouter",[849,1009,1010],{},"defer",[849,1012,1013],{},"There is no webhook. The route is authenticated, and it enqueues directly.",[828,1015,1016,1021,1023],{},[849,1017,1018],{},[858,1019,1020],{},"InboundWorker",[849,1022,1010],{},[849,1024,1025],{},"Identity and session are already resolved by the session token.",[828,1027,1028,1033,1035],{},[849,1029,1030],{},[858,1031,1032],{},"ChannelIdentityService",[849,1034,1010],{},[849,1036,1037,1038,1041],{},"The Supabase user id ",[924,1039,1040],{},"is"," the platform user id.",[828,1043,1044,1049,1051],{},[849,1045,1046],{},[858,1047,1048],{},"ChannelSessionService",[849,1050,1010],{},[849,1052,1053,1056],{},[858,1054,1055],{},"conversation_id"," is in the path. Nothing maps onto it.",[828,1058,1059,1064,1066],{},[849,1060,1061],{},[858,1062,1063],{},"ChannelActionHandler",[849,1065,1010],{},[849,1067,1068],{},"Approvals resolve in Human Review.",[828,1070,1071,1086,1088],{},[849,1072,1073,1076,1077,1076,1080,1076,1083],{},[858,1074,1075],{},"ChannelNotifier",", ",[858,1078,1079],{},"OutboundAdapter",[858,1081,1082],{},"ChannelCapabilities",[858,1084,1085],{},"OutboundIntent",[849,1087,1010],{},[849,1089,1090],{},"Web chat answers on SSE, so it needs no delivery.",[828,1092,1093,1104,1106],{},[849,1094,1095,1076,1098,1076,1101],{},[858,1096,1097],{},"agent.channel_connections",[858,1099,1100],{},"_identities",[858,1102,1103],{},"_sessions",[849,1105,1010],{},[849,1107,1108],{},"Nothing writes them.",[807,1110,1111],{},"Read every section below as the design a remote channel lands against. The web slice inherits the shapes, not the machinery.",[817,1113,1115],{"id":1114},"boundary","Boundary",[1117,1118,1124],"pre",{"className":1119,"code":1121,"language":1122,"meta":1123},[1120],"language-text","      vendor                                            platform\n        │                                                   ▲\n        │  webhook                                          │ NormalizedMessage\n        ▼                                                   │\n   WebhookRouter ─ verify ─ decode ─ claim ─ enqueue ─ ACK   │\n                                              │             │\n                                              ▼             │\n                                        InboundWorker ──────┘\n                                              │\n                                              └─ ChannelActionHandler ─> ApprovalService\n\n        ▲                                                   │\n        │  vendor message                                   │ OutboundIntent\n        │                                                   ▼\n   adapter.send() \u003C───────────── ChannelNotifier \u003C──── Run events\n","text","",[858,1125,1121],{"__ignoreMap":1123},[807,1127,1128],{},"The adapter knows vendor payloads and vendor limits. It does not know Agents, prompts, Tools, workflows or policy rules.",[807,1130,1131,1133,1134,1136,1137,1140],{},[858,1132,1007],{}," and ",[858,1135,1020],{}," are ",[924,1138,1139],{},"one seam split by a deadline",", not two stages of thought. Every vendor retries a slow answer, and identity plus session resolution is slower than the ACK budget allows. So the router does only what must happen before the ACK, and the worker does the rest. Read them as one component with a durable hand-off in the middle.",[817,1142,1144],{"id":1143},"core-code","Core code",[1117,1146,1149],{"className":1147,"code":1148,"language":1122,"meta":1123},[1120],"src\u002Fagentic\u002Fentry_control\u002Fchannels\u002F\n  adapters\u002F\n    base.py        InboundAdapter, OutboundAdapter, ChannelCapabilities\n    web.py         WebChannelAdapter                       \u003C- the web slice\n    slack.py       SlackChannelAdapter\n  models.py        InboundEvent, NormalizedMessage, OutboundIntent, ChannelSession\n  webhooks.py      WebhookRouter: verify, decode, claim, enqueue, ACK\n  inbound.py       InboundWorker: identity, session, normalize, dispatch\n  identity.py      ChannelIdentityService, link tokens\n  sessions.py      ChannelSessionService\n  actions.py       ChannelActionHandler\n  outbound.py      ChannelNotifier\n  repositories.py  connections, identities, sessions\n",[858,1150,1148],{"__ignoreMap":1123},[807,1152,948,1153,1163,1164,1167,1168,1171,1172,1174,1175,1178,1179,1182,1183,1187],{},[924,1154,1155,1156,1159,1160,931],{},"The path is ",[858,1157,1158],{},"src\u002Fagentic\u002F",", and it is not ",[858,1161,1162],{},"src\u002Fdomains\u002F"," The import-linter contract in ",[858,1165,1166],{},"ac-python-api\u002Fpyproject.toml"," binds ",[858,1169,1170],{},"src.agentic"," as its source module. A package under ",[858,1173,1162],{}," sits outside it, so it could import ",[858,1176,1177],{},"src.domains.chat"," while ",[858,1180,1181],{},"lint-imports"," stayed green, which is the one thing the contract exists to stop. See ",[929,1184,1186],{"href":1185},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fcontract#coexistence-with-the-live-agent-stack","coexistence",", rule 3.",[807,1189,1190,1193,1194,1196,1197,1200,1201,1076,1204,1076,1206,1076,1208,1133,1211,1213,1214,1217,1218,1221,1222,1225,1226,1229,1230,1233,1234,931],{},[858,1191,1192],{},"entry_control"," is a new top-level package under ",[858,1195,1170],{},", so it joins the source list of the ",[858,1198,1199],{},"src.agentic.surfaces is the top layer"," contract, and it takes a contract of its own: ",[858,1202,1203],{},"services",[858,1205,294],{},[858,1207,149],{},[858,1209,1210],{},"shared",[858,1212,320],{}," may not import it. ",[858,1215,1216],{},"inngest_functions"," is not in that list and cannot be: the registry imports the module that builds each function, exactly as ",[858,1219,1220],{},"inngest_functions\u002F__init__.py"," imports ",[858,1223,1224],{},"runtime\u002Finngest\u002Fexecute.py"," for ",[858,1227,1228],{},"run.execute",". ",[858,1231,1232],{},"inngest_app"," is not in it either, because the direction is ",[858,1235,1236],{},"entry_control -> inngest_app",[822,1238,1239,1249],{},[825,1240,1241],{},[828,1242,1243,1246],{},[831,1244,1245],{},"Component",[831,1247,1248],{},"Job",[844,1250,1251,1260,1269,1278,1287,1299,1308,1317,1326],{},[828,1252,1253,1257],{},[849,1254,1255],{},[858,1256,992],{},[849,1258,1259],{},"Read the workspace id, verify a request, decode an event",[828,1261,1262,1266],{},[849,1263,1264],{},[858,1265,1079],{},[849,1267,1268],{},"Send one intent, within what the channel can render",[828,1270,1271,1275],{},[849,1272,1273],{},[858,1274,1082],{},[849,1276,1277],{},"What one channel can render, as data. Outbound only",[828,1279,1280,1284],{},[849,1281,1282],{},[858,1283,1007],{},[849,1285,1286],{},"Verify, claim the delivery id, enqueue durably, then ACK",[828,1288,1289,1293],{},[849,1290,1291],{},[858,1292,1020],{},[849,1294,1295,1296,1298],{},"Resolve identity and session, build one ",[858,1297,979],{},", call the Front Door",[828,1300,1301,1305],{},[849,1302,1303],{},[858,1304,1032],{},[849,1306,1307],{},"Map an external user to a platform user, and unlink one",[828,1309,1310,1314],{},[849,1311,1312],{},[858,1313,1048],{},[849,1315,1316],{},"Map an external conversation or thread to a platform conversation",[828,1318,1319,1323],{},[849,1320,1321],{},[858,1322,1063],{},[849,1324,1325],{},"Turn a button press into one approval decision",[828,1327,1328,1332],{},[849,1329,1330],{},[858,1331,1075],{},[849,1333,1334,1335,1337],{},"Turn a Run event into one ",[858,1336,1085],{}," and send it",[807,1339,1340],{},"No manager class sits above these parts.",[817,1342,1343],{"id":322},"Contracts",[1345,1346,1347],"h3",{"id":448},"Adapters",[807,1349,1350,1351,1353,1354,1357],{},"Inbound and outbound are two protocols, not one. Web chat answers on SSE and never sends through the Gateway, so a single protocol would force ",[858,1352,860],{}," to carry a ",[858,1355,1356],{},"send"," it must refuse.",[1117,1359,1363],{"className":1360,"code":1361,"language":1362,"meta":1123,"style":1123},"language-python shiki shiki-themes github-dark","class InboundAdapter(Protocol):\n    channel: Channel\n\n    def external_workspace_id(self, request: IncomingRequest) -> str:\n        \"\"\"Read the workspace id from the raw payload. Nothing is trusted yet.\"\"\"\n\n    def verify(self, request: IncomingRequest, connection: ChannelConnection) -> None:\n        \"\"\"Raise on a bad signature, a stale timestamp, or a wrong token.\"\"\"\n\n    def decode(self, request: IncomingRequest) -> InboundEvent | None:\n        \"\"\"Return None for an event this channel ignores.\"\"\"\n\n\nclass OutboundAdapter(Protocol):\n    channel: Channel\n    capabilities: ChannelCapabilities\n\n    async def send(self, session: ChannelSession, intent: OutboundIntent) -> DeliveryResult: ...\n","python",[858,1364,1365,1372,1377,1383,1388,1393,1397,1402,1407,1411,1416,1421,1425,1429,1434,1439,1445,1450],{"__ignoreMap":1123},[1366,1367,1369],"span",{"class":1368,"line":22},"line",[1366,1370,1371],{},"class InboundAdapter(Protocol):\n",[1366,1373,1374],{"class":1368,"line":32},[1366,1375,1376],{},"    channel: Channel\n",[1366,1378,1379],{"class":1368,"line":233},[1366,1380,1382],{"emptyLinePlaceholder":1381},true,"\n",[1366,1384,1385],{"class":1368,"line":244},[1366,1386,1387],{},"    def external_workspace_id(self, request: IncomingRequest) -> str:\n",[1366,1389,1390],{"class":1368,"line":264},[1366,1391,1392],{},"        \"\"\"Read the workspace id from the raw payload. Nothing is trusted yet.\"\"\"\n",[1366,1394,1395],{"class":1368,"line":222},[1366,1396,1382],{"emptyLinePlaceholder":1381},[1366,1398,1399],{"class":1368,"line":360},[1366,1400,1401],{},"    def verify(self, request: IncomingRequest, connection: ChannelConnection) -> None:\n",[1366,1403,1404],{"class":1368,"line":368},[1366,1405,1406],{},"        \"\"\"Raise on a bad signature, a stale timestamp, or a wrong token.\"\"\"\n",[1366,1408,1409],{"class":1368,"line":375},[1366,1410,1382],{"emptyLinePlaceholder":1381},[1366,1412,1413],{"class":1368,"line":157},[1366,1414,1415],{},"    def decode(self, request: IncomingRequest) -> InboundEvent | None:\n",[1366,1417,1418],{"class":1368,"line":182},[1366,1419,1420],{},"        \"\"\"Return None for an event this channel ignores.\"\"\"\n",[1366,1422,1423],{"class":1368,"line":290},[1366,1424,1382],{"emptyLinePlaceholder":1381},[1366,1426,1427],{"class":1368,"line":280},[1366,1428,1382],{"emptyLinePlaceholder":1381},[1366,1430,1431],{"class":1368,"line":272},[1366,1432,1433],{},"class OutboundAdapter(Protocol):\n",[1366,1435,1437],{"class":1368,"line":1436},15,[1366,1438,1376],{},[1366,1440,1442],{"class":1368,"line":1441},16,[1366,1443,1444],{},"    capabilities: ChannelCapabilities\n",[1366,1446,1448],{"class":1368,"line":1447},17,[1366,1449,1382],{"emptyLinePlaceholder":1381},[1366,1451,1453],{"class":1368,"line":1452},18,[1366,1454,1455],{},"    async def send(self, session: ChannelSession, intent: OutboundIntent) -> DeliveryResult: ...\n",[822,1457,1458,1469],{},[825,1459,1460],{},[828,1461,1462,1465,1467],{},[831,1463,1464],{},"Adapter",[831,1466,839],{},[831,1468,842],{},[844,1470,1471,1482],{},[828,1472,1473,1477,1479],{},[849,1474,1475],{},[858,1476,860],{},[849,1478,854],{},[849,1480,1481],{},"no. SSE answers, so it needs no capabilities either",[828,1483,1484,1488,1490],{},[849,1485,1486],{},[858,1487,876],{},[849,1489,854],{},[849,1491,854],{},[807,1493,1494,1496],{},[858,1495,1082],{}," sits on the outbound half, because every field it holds describes rendering. A channel we only receive from declares none.",[807,1498,1499],{},"The router owns the order of the inbound calls. Neither adapter reads a database table.",[1117,1501,1503],{"className":1360,"code":1502,"language":1362,"meta":1123,"style":1123},"@dataclass(frozen=True)\nclass ChannelCapabilities:\n    edits: bool        # the channel can update a message it already sent\n    buttons: bool      # the channel can render actions\n    threads: bool\n    max_text: int      # characters in one message\n",[858,1504,1505,1510,1515,1520,1525,1530],{"__ignoreMap":1123},[1366,1506,1507],{"class":1368,"line":22},[1366,1508,1509],{},"@dataclass(frozen=True)\n",[1366,1511,1512],{"class":1368,"line":32},[1366,1513,1514],{},"class ChannelCapabilities:\n",[1366,1516,1517],{"class":1368,"line":233},[1366,1518,1519],{},"    edits: bool        # the channel can update a message it already sent\n",[1366,1521,1522],{"class":1368,"line":244},[1366,1523,1524],{},"    buttons: bool      # the channel can render actions\n",[1366,1526,1527],{"class":1368,"line":264},[1366,1528,1529],{},"    threads: bool\n",[1366,1531,1532],{"class":1368,"line":222},[1366,1533,1534],{},"    max_text: int      # characters in one message\n",[807,1536,1537],{},"Capability belongs to the adapter and the connection. It never belongs to an Agent.",[1345,1539,1541],{"id":1540},"inbound-event","Inbound event",[1117,1543,1545],{"className":1360,"code":1544,"language":1362,"meta":1123,"style":1123},"InboundEvent = MessageReceived | ActionReceived | ConnectionRevoked\n",[858,1546,1547],{"__ignoreMap":1123},[1366,1548,1549],{"class":1368,"line":22},[1366,1550,1544],{},[1117,1552,1554],{"className":1360,"code":1553,"language":1362,"meta":1123,"style":1123},"@dataclass(frozen=True)\nclass MessageReceived:\n    external_event_id: str\n    external_user_id: str\n    external_conversation_id: str\n    external_thread_id: str | None\n    text: str\n    addressed: bool                    # a DM, a mention, or a reply in a Gateway thread\n    from_bot: bool\n    attachment_count: int\n    occurred_at: datetime\n",[858,1555,1556,1560,1565,1570,1575,1580,1585,1590,1595,1600,1605],{"__ignoreMap":1123},[1366,1557,1558],{"class":1368,"line":22},[1366,1559,1509],{},[1366,1561,1562],{"class":1368,"line":32},[1366,1563,1564],{},"class MessageReceived:\n",[1366,1566,1567],{"class":1368,"line":233},[1366,1568,1569],{},"    external_event_id: str\n",[1366,1571,1572],{"class":1368,"line":244},[1366,1573,1574],{},"    external_user_id: str\n",[1366,1576,1577],{"class":1368,"line":264},[1366,1578,1579],{},"    external_conversation_id: str\n",[1366,1581,1582],{"class":1368,"line":222},[1366,1583,1584],{},"    external_thread_id: str | None\n",[1366,1586,1587],{"class":1368,"line":360},[1366,1588,1589],{},"    text: str\n",[1366,1591,1592],{"class":1368,"line":368},[1366,1593,1594],{},"    addressed: bool                    # a DM, a mention, or a reply in a Gateway thread\n",[1366,1596,1597],{"class":1368,"line":375},[1366,1598,1599],{},"    from_bot: bool\n",[1366,1601,1602],{"class":1368,"line":157},[1366,1603,1604],{},"    attachment_count: int\n",[1366,1606,1607],{"class":1368,"line":182},[1366,1608,1609],{},"    occurred_at: datetime\n",[807,1611,1612,1613,1616],{},"Only a ",[858,1614,1615],{},"MessageReceived"," can become conversational input. A button press and an uninstall go to deterministic handlers. They never pretend to be chat.",[807,1618,1619,1620,1623],{},"An edit, a delete and a reaction decode to ",[858,1621,1622],{},"None"," in V1. The platform drops them.",[1345,1625,1627],{"id":1626},"normalized-message","Normalized message",[1117,1629,1631],{"className":1360,"code":1630,"language":1362,"meta":1123,"style":1123},"@dataclass(frozen=True)\nclass NormalizedMessage:\n    channel: Channel\n    message_id: str          # platform id; the Run start key derives from it\n    organization_id: UUID\n    user_id: UUID            # always a verified person\n    conversation_id: UUID\n    text: str\n    occurred_at: datetime\n",[858,1632,1633,1637,1642,1646,1651,1656,1661,1666,1670],{"__ignoreMap":1123},[1366,1634,1635],{"class":1368,"line":22},[1366,1636,1509],{},[1366,1638,1639],{"class":1368,"line":32},[1366,1640,1641],{},"class NormalizedMessage:\n",[1366,1643,1644],{"class":1368,"line":233},[1366,1645,1376],{},[1366,1647,1648],{"class":1368,"line":244},[1366,1649,1650],{},"    message_id: str          # platform id; the Run start key derives from it\n",[1366,1652,1653],{"class":1368,"line":264},[1366,1654,1655],{},"    organization_id: UUID\n",[1366,1657,1658],{"class":1368,"line":222},[1366,1659,1660],{},"    user_id: UUID            # always a verified person\n",[1366,1662,1663],{"class":1368,"line":360},[1366,1664,1665],{},"    conversation_id: UUID\n",[1366,1667,1668],{"class":1368,"line":368},[1366,1669,1589],{},[1366,1671,1672],{"class":1368,"line":375},[1366,1673,1609],{},[807,1675,1676,1677,1680],{},"The Front Door receives no vendor field. There is no ",[858,1678,1679],{},"channel_context",", so a Slack thread id cannot leak into routing logic.",[807,1682,1683,1686,1687,1689],{},[858,1684,1685],{},"user_id"," is not optional. An unverified sender produces no ",[858,1688,979],{},", so no downstream layer must test an identity state.",[1345,1691,1693],{"id":1692},"outbound-intent","Outbound intent",[1117,1695,1697],{"className":1360,"code":1696,"language":1362,"meta":1123,"style":1123},"@dataclass(frozen=True)\nclass OutboundIntent:\n    conversation_id: UUID\n    kind: Literal['message', 'progress', 'approval', 'error']\n    dedupe_key: str\n    text: str | None = None\n    approval_id: UUID | None = None\n    actions: list[Action] = field(default_factory=list)\n",[858,1698,1699,1703,1708,1712,1717,1722,1727,1732],{"__ignoreMap":1123},[1366,1700,1701],{"class":1368,"line":22},[1366,1702,1509],{},[1366,1704,1705],{"class":1368,"line":32},[1366,1706,1707],{},"class OutboundIntent:\n",[1366,1709,1710],{"class":1368,"line":233},[1366,1711,1665],{},[1366,1713,1714],{"class":1368,"line":244},[1366,1715,1716],{},"    kind: Literal['message', 'progress', 'approval', 'error']\n",[1366,1718,1719],{"class":1368,"line":264},[1366,1720,1721],{},"    dedupe_key: str\n",[1366,1723,1724],{"class":1368,"line":222},[1366,1725,1726],{},"    text: str | None = None\n",[1366,1728,1729],{"class":1368,"line":360},[1366,1730,1731],{},"    approval_id: UUID | None = None\n",[1366,1733,1734],{"class":1368,"line":368},[1366,1735,1736],{},"    actions: list[Action] = field(default_factory=list)\n",[807,1738,1739,1740,931],{},"Meaning is stable. Presentation varies. Slack renders buttons; a weaker channel renders a link to ",[929,1741,1742],{"href":344},"Human Review",[1345,1744,1746],{"id":1745},"session","Session",[1117,1748,1750],{"className":1360,"code":1749,"language":1362,"meta":1123,"style":1123},"@dataclass(frozen=True)\nclass ChannelSession:\n    id: UUID\n    connection_id: UUID\n    organization_id: UUID\n    conversation_id: UUID\n    external_conversation_id: str\n    external_thread_key: str   # '' when the channel has no thread\n    channel: Channel\n",[858,1751,1752,1756,1761,1766,1771,1775,1779,1783,1788],{"__ignoreMap":1123},[1366,1753,1754],{"class":1368,"line":22},[1366,1755,1509],{},[1366,1757,1758],{"class":1368,"line":32},[1366,1759,1760],{},"class ChannelSession:\n",[1366,1762,1763],{"class":1368,"line":233},[1366,1764,1765],{},"    id: UUID\n",[1366,1767,1768],{"class":1368,"line":244},[1366,1769,1770],{},"    connection_id: UUID\n",[1366,1772,1773],{"class":1368,"line":264},[1366,1774,1655],{},[1366,1776,1777],{"class":1368,"line":222},[1366,1778,1665],{},[1366,1780,1781],{"class":1368,"line":360},[1366,1782,1579],{},[1366,1784,1785],{"class":1368,"line":368},[1366,1786,1787],{},"    external_thread_key: str   # '' when the channel has no thread\n",[1366,1789,1790],{"class":1368,"line":375},[1366,1791,1376],{},[817,1793,1795],{"id":1794},"inbound-path","Inbound path",[1117,1797,1800],{"className":1798,"code":1799,"language":1122,"meta":1123},[1120],"vendor webhook\n   │\n   ├─ adapter.external_workspace_id()  -> resolve the connection\n   ├─ adapter.verify()                 -> signature and timestamp window\n   ├─ adapter.decode()                 -> InboundEvent, or None to drop\n   ├─ IdempotencyService.claim(organization_id, 'webhook.\u003Cchannel>',\n   │                           external_event_id, sha256(raw_body))\n   ├─ durable enqueue                  -> Inngest, concurrency key = session key\n   └─ ACK                              -> under 3 seconds, no model call\n                │\n                ▼\n          InboundWorker\n                ├─ MessageReceived   -> identity -> session -> NormalizedMessage -> FrontDoorService\n                ├─ ActionReceived    -> ChannelActionHandler\n                └─ ConnectionRevoked -> disable the connection, unlink its identities\n",[858,1801,1799],{"__ignoreMap":1123},[807,1803,1804,1807],{},[924,1805,1806],{},"ACK first, then process."," The webhook handler never waits for a model call.",[1345,1809,1811],{"id":1810},"admission-checks-in-order","Admission checks, in order",[822,1813,1814,1824],{},[825,1815,1816],{},[828,1817,1818,1821],{},[831,1819,1820],{},"Check",[831,1822,1823],{},"Drop reason",[844,1825,1826,1839,1849,1859,1869,1879,1889,1899,1909],{},[828,1827,1828,1831],{},[849,1829,1830],{},"The workspace maps to an enabled connection",[849,1832,1833,1076,1836],{},[858,1834,1835],{},"unknown_connection",[858,1837,1838],{},"connection_disabled",[828,1840,1841,1844],{},[849,1842,1843],{},"The signature is valid",[849,1845,1846],{},[858,1847,1848],{},"bad_signature",[828,1850,1851,1854],{},[849,1852,1853],{},"The timestamp is inside 5 minutes",[849,1855,1856],{},[858,1857,1858],{},"replay",[828,1860,1861,1864],{},[849,1862,1863],{},"The event decodes to a supported kind",[849,1865,1866],{},[858,1867,1868],{},"unsupported_event",[828,1870,1871,1874],{},[849,1872,1873],{},"The sender is a person, not a bot or this app",[849,1875,1876],{},[858,1877,1878],{},"bot_sender",[828,1880,1881,1884],{},[849,1882,1883],{},"The message addresses us",[849,1885,1886],{},[858,1887,1888],{},"not_addressed",[828,1890,1891,1894],{},[849,1892,1893],{},"The text is inside the size limit",[849,1895,1896],{},[858,1897,1898],{},"too_large",[828,1900,1901,1904],{},[849,1902,1903],{},"The delivery id is new",[849,1905,1906],{},[858,1907,1908],{},"duplicate",[828,1910,1911,1914],{},[849,1912,1913],{},"The body matches the hash the delivery id was claimed for",[849,1915,1916],{},[858,1917,1918],{},"hash_mismatch",[807,1920,1921],{},"Every drop carries one reason, and the platform counts it. A silent no-op looks the same as a broken install.",[807,1923,1924,1926,1927,931],{},[858,1925,1918],{}," is the one drop a person must look at. The vendor re-sent one delivery id with different content, so the delivery is not a duplicate and the key already answers for another body. See ",[929,1928,200],{"href":269},[1345,1930,1932],{"id":1931},"addressing","Addressing",[807,1934,1935,1936,931],{},"A direct message always addresses us. A message in a shared channel addresses us only when it mentions the app, or when it replies inside a thread that the Gateway already answers. Everything else drops as ",[858,1937,1888],{},[807,1939,1940,1941,1944],{},"This rule keeps a busy channel cheap. It also stops the bot loop, together with the ",[858,1942,1943],{},"from_bot"," check.",[1345,1946,1948],{"id":1947},"idempotency-and-ordering","Idempotency and ordering",[807,1950,1951,1952,1955,1956,1959],{},"The vendor delivery id is the one dedupe key. Claim it under the shared ",[858,1953,1954],{},"webhook.\u003Cprovider>"," scope, as ",[858,1957,1958],{},"webhook.\u003Cchannel>",", and complete the claim only after the enqueue succeeds. A failed enqueue must leave the claim unfinished, so the vendor retry still works.",[807,1961,1962,1965,1966,1969],{},[858,1963,1964],{},"NormalizedMessage.message_id"," seeds the Run start key. The Front Door builds ",[858,1967,1968],{},"StartRunCommand.idempotency_key"," from it, so one Slack message can never start two Runs.",[807,1971,1972],{},"The queue holds one worker per session key. Two fast messages in one thread therefore run in order, and two Front Door turns never interleave in one conversation.",[1345,1974,1976],{"id":1975},"attachments","Attachments",[807,1978,1979,1982],{},[924,1980,1981],{},"The current V1 slice reads text only, and web chat is not an exception."," The worker counts attachments, records the count on the conversation message, and answers once that the platform cannot read a file here. No file passes through an adapter, and no conversation upload exists. The same rule applies when remote channels land.",[807,1984,1985,1986,1989],{},"A file still reaches the platform as an organization knowledge source, through the ordinary upload surface. That path belongs to ",[929,1987,1988],{"href":178},"state and knowledge",", and it attaches to an organization, never to one conversation.",[807,1991,1992],{},"Conversation attachments are deferred. They add a per-conversation knowledge scope, a retention rule and an ingestion path, and no V1 product need requires them.",[817,1994,1996],{"id":1995},"identity-and-sessions","Identity and sessions",[807,1998,1999],{},"An identity row exists, or it does not. There is no state column.",[1117,2001,2004],{"className":2002,"code":2003,"language":1122,"meta":1123},[1120],"row present   -> verified. The person becomes an actor identity.\nrow absent    -> unknown.  The person starts no Run.\nunlink        -> the row is deleted, and the person is unknown again.\n",[858,2005,2003],{"__ignoreMap":1123},[807,2007,2008,2009,2012,2013,2016,2017,2020,2021,931],{},"The Gateway hands an ",[924,2010,2011],{},"actor identity"," to the Front Door. ",[858,2014,2015],{},"RunManager"," mints the ",[858,2018,2019],{},"Principal",", because the intersection needs the definition and the Run ID. See ",[929,2022,2023],{"href":372},"runtime execution",[1345,2025,2027],{"id":2026},"linking","Linking",[1117,2029,2032],{"className":2030,"code":2031,"language":1122,"meta":1123},[1120],"message from an unknown sender\n   -> the Gateway answers once with one link\n      \u002Fchannels\u002Flink?token=\u003Csigned>\n   -> the token holds connection_id + external_user_id\n   -> it expires in 15 minutes, and it works one time\n   -> the person signs in, then confirms\n   -> ChannelIdentityService.link() writes the row\n   -> the platform does not replay the first message\n",[858,2033,2031],{"__ignoreMap":1123},[807,2035,2036],{},"The platform answers at most one link invitation per external user per hour. A shared channel therefore cannot become a spam source.",[807,2038,2039],{},"The first message is not replayed on purpose. A stale intent is worse than one more sentence from the person.",[1117,2041,2043],{"className":1360,"code":2042,"language":1362,"meta":1123,"style":1123},"class ChannelIdentityService:\n    async def resolve(self, connection_id: UUID, external_user_id: str) -> ChannelIdentity | None: ...\n    async def issue_link_token(self, connection_id: UUID, external_user_id: str) -> str: ...\n    async def link(self, token: str, user: AuthenticatedUser) -> ChannelIdentity: ...\n    async def unlink(self, identity_id: UUID) -> None: ...\n",[858,2044,2045,2050,2055,2060,2065],{"__ignoreMap":1123},[1366,2046,2047],{"class":1368,"line":22},[1366,2048,2049],{},"class ChannelIdentityService:\n",[1366,2051,2052],{"class":1368,"line":32},[1366,2053,2054],{},"    async def resolve(self, connection_id: UUID, external_user_id: str) -> ChannelIdentity | None: ...\n",[1366,2056,2057],{"class":1368,"line":233},[1366,2058,2059],{},"    async def issue_link_token(self, connection_id: UUID, external_user_id: str) -> str: ...\n",[1366,2061,2062],{"class":1368,"line":244},[1366,2063,2064],{},"    async def link(self, token: str, user: AuthenticatedUser) -> ChannelIdentity: ...\n",[1366,2066,2067],{"class":1368,"line":264},[1366,2068,2069],{},"    async def unlink(self, identity_id: UUID) -> None: ...\n",[1345,2071,2072],{"id":238},"Sessions",[1117,2074,2076],{"className":1360,"code":2075,"language":1362,"meta":1123,"style":1123},"class ChannelSessionService:\n    async def resolve_or_create(\n        self,\n        connection: ChannelConnection,\n        external_conversation_id: str,\n        external_thread_id: str | None = None,\n    ) -> ChannelSession: ...\n",[858,2077,2078,2083,2088,2093,2098,2103,2108],{"__ignoreMap":1123},[1366,2079,2080],{"class":1368,"line":22},[1366,2081,2082],{},"class ChannelSessionService:\n",[1366,2084,2085],{"class":1368,"line":32},[1366,2086,2087],{},"    async def resolve_or_create(\n",[1366,2089,2090],{"class":1368,"line":233},[1366,2091,2092],{},"        self,\n",[1366,2094,2095],{"class":1368,"line":244},[1366,2096,2097],{},"        connection: ChannelConnection,\n",[1366,2099,2100],{"class":1368,"line":264},[1366,2101,2102],{},"        external_conversation_id: str,\n",[1366,2104,2105],{"class":1368,"line":222},[1366,2106,2107],{},"        external_thread_id: str | None = None,\n",[1366,2109,2110],{"class":1368,"line":360},[1366,2111,2112],{},"    ) -> ChannelSession: ...\n",[807,2114,2115],{},"A unique database constraint resolves a race between two concurrent messages. The service inserts, ignores a conflict, then reads the winner. No distributed lock exists.",[807,2117,2118,2119,2122,2123,2126],{},"The thread key uses ",[858,2120,2121],{},"''"," for a channel with no thread. A ",[858,2124,2125],{},"NULL"," would make every row distinct, so the constraint would not hold.",[1345,2128,2130],{"id":2129},"a-shared-thread","A shared thread",[807,2132,2133],{},"A Slack thread can hold two people. The session maps that thread to one conversation, and the conversation is shared. The principal is not shared.",[2135,2136,2137,2141,2144],"ul",{},[2138,2139,2140],"li",{},"The conversation records who created it.",[2138,2142,2143],{},"Each message records its own sender.",[2138,2145,2146],{},"Each turn uses the principal of the person who wrote that message.",[807,2148,2149],{},"So user B reads the shared history of the thread, and user B reads no CRM row that user B may not read.",[817,2151,2153],{"id":2152},"outbound-path","Outbound path",[1117,2155,2158],{"className":2156,"code":2157,"language":1122,"meta":1123},[1120],"durable    Run event        -> ChannelNotifier -> adapter.send()\ntransient  live event       -> progress relay  -> adapter.send()   (best effort)\n",[858,2159,2157],{"__ignoreMap":1123},[822,2161,2162,2175],{},[825,2163,2164],{},[828,2165,2166,2169,2172],{},[831,2167,2168],{},"Intent",[831,2170,2171],{},"Source",[831,2173,2174],{},"Delivery",[844,2176,2177,2190,2202,2214,2227],{},[828,2178,2179,2184,2187],{},[849,2180,2181],{},[858,2182,2183],{},"message",[849,2185,2186],{},"a Front Door answer, or a Run result",[849,2188,2189],{},"durable, at least once, deduped",[828,2191,2192,2197,2200],{},[849,2193,2194],{},[858,2195,2196],{},"approval",[849,2198,2199],{},"an approval row is created",[849,2201,2189],{},[828,2203,2204,2209,2212],{},[849,2205,2206],{},[858,2207,2208],{},"error",[849,2210,2211],{},"a Run failed",[849,2213,2189],{},[828,2215,2216,2221,2224],{},[849,2217,2218],{},[858,2219,2220],{},"progress",[849,2222,2223],{},"live Run events",[849,2225,2226],{},"best effort, at most once, throttled",[828,2228,2229,2234,2239],{},[849,2230,2231,2233],{},[858,2232,2196],{}," update",[849,2235,2236],{},[858,2237,2238],{},"agent\u002Fapproval.resolved",[849,2240,2189],{},[807,2242,2243],{},"A durable intent travels as its own Inngest event, so a worker restart cannot lose the answer. A progress update travels on the transient live-event transport, and the platform drops it under load.",[1345,2245,2247],{"id":2246},"rules","Rules",[2135,2249,2250,2253,2275,2282,2289,2295,2298,2301],{},[2138,2251,2252],{},"Delivery status is not Run status. A Run can succeed while Slack is down.",[2138,2254,2255,2256,2259,2260,2263,2264,2259,2267,2270,2271,2274],{},"A ",[858,2257,2258],{},"429"," or a ",[858,2261,2262],{},"5xx"," retries with backoff. A ",[858,2265,2266],{},"token_revoked",[858,2268,2269],{},"channel_not_found"," marks the connection ",[858,2272,2273],{},"degraded"," and raises an ops alert.",[2138,2276,2277,2278,2281],{},"Text longer than ",[858,2279,2280],{},"capabilities.max_text"," splits into ordered chunks.",[2138,2283,2284,2285,2288],{},"A channel without ",[858,2286,2287],{},"buttons"," renders a link to Human Review.",[2138,2290,2284,2291,2294],{},[858,2292,2293],{},"edits"," sends no progress at all.",[2138,2296,2297],{},"Progress edits one message, at most one time per 5 seconds.",[2138,2299,2300],{},"A conversation with no session drops the intent. Web chat has its own stream.",[2138,2302,2303,2304,2306],{},"An approval resolved in Human Review still clears the channel buttons. The notifier reads ",[858,2305,2238],{},", so no channel keeps a live button on a decided row.",[817,2308,2310],{"id":2309},"channel-actions","Channel actions",[1117,2312,2315],{"className":2313,"code":2314,"language":1122,"meta":1123},[1120],"ActionReceived(approval_id, decision)\n   -> resolve the identity        unknown -> answer with the link invitation\n   -> ApprovalService.resolve(approval_id, decision, actor)\n   -> update the original message with the outcome\n",[858,2316,2314],{"__ignoreMap":1123},[807,2318,2319],{},"The Gateway never writes the approval row. It calls the approval domain, and the domain checks TTL, authority and the argument hash. Every presentation resolves the same approval id, so silence is never consent.",[807,2321,2322],{},"A second press returns the current state. It is not an error.",[817,2324,2325],{"id":612},"Data model",[822,2327,2328,2341],{},[825,2329,2330],{},[828,2331,2332,2335,2338],{},[831,2333,2334],{},"Table",[831,2336,2337],{},"Key columns",[831,2339,2340],{},"Constraint",[844,2342,2343,2373,2400],{},[828,2344,2345,2349,2368],{},[849,2346,2347],{},[858,2348,1097],{},[849,2350,2351,1076,2354,1076,2357,1076,2360,1076,2363,1076,2365],{},[858,2352,2353],{},"organization_id",[858,2355,2356],{},"channel",[858,2358,2359],{},"external_workspace_id",[858,2361,2362],{},"credentials_ref",[858,2364,320],{},[858,2366,2367],{},"status",[849,2369,2370],{},[858,2371,2372],{},"unique(channel, external_workspace_id)",[828,2374,2375,2380,2395],{},[849,2376,2377],{},[858,2378,2379],{},"agent.channel_identities",[849,2381,2382,1076,2385,1076,2387,1076,2390,1076,2392],{},[858,2383,2384],{},"connection_id",[858,2386,2353],{},[858,2388,2389],{},"external_user_id",[858,2391,1685],{},[858,2393,2394],{},"linked_at",[849,2396,2397],{},[858,2398,2399],{},"unique(connection_id, external_user_id)",[828,2401,2402,2407,2421],{},[849,2403,2404],{},[858,2405,2406],{},"agent.channel_sessions",[849,2408,2409,1076,2411,1076,2413,1076,2415,1076,2418],{},[858,2410,2384],{},[858,2412,2353],{},[858,2414,1055],{},[858,2416,2417],{},"external_conversation_id",[858,2419,2420],{},"external_thread_key",[849,2422,2423],{},[858,2424,2425],{},"unique(connection_id, external_conversation_id, external_thread_key)",[807,2427,948,2428,2431,2432,2434,2435,2439],{},[924,2429,2430],{},"All three tables are deferred with the remote channels."," The web slice creates none of them: it resolves identity from the session token and reads ",[858,2433,1055],{}," from the path. ",[929,2436,2438],{"href":2437},"\u002Fengineering\u002Fsystem-design\u002Fagentic-platform\u002Fcontract#data-model","contract.md"," lists the tables the current slice does create.",[807,2441,2442,2444,2445,1076,2448,2450,2451,2454],{},[858,2443,2367],{}," is ",[858,2446,2447],{},"enabled",[858,2449,2273],{}," or ",[858,2452,2453],{},"revoked",". Credentials live in the vault, and the row holds only a reference.",[807,2456,2457],{},"One workspace maps to one organization. A second organization that installs the same workspace receives a clear error. This keeps identity resolution unambiguous.",[817,2459,2461],{"id":2460},"failure-handling","Failure handling",[822,2463,2464,2474],{},[825,2465,2466],{},[828,2467,2468,2471],{},[831,2469,2470],{},"Failure",[831,2472,2473],{},"Behaviour",[844,2475,2476,2488,2496,2507,2518,2526,2534,2542,2550,2561,2569],{},[828,2477,2478,2481],{},[849,2479,2480],{},"Bad signature",[849,2482,2483,2484,2487],{},"Reject with ",[858,2485,2486],{},"401",". Record the attempt. Enqueue nothing.",[828,2489,2490,2493],{},[849,2491,2492],{},"Stale timestamp",[849,2494,2495],{},"Reject as a replay, even when the signature is valid.",[828,2497,2498,2501],{},[849,2499,2500],{},"Unknown workspace",[849,2502,2483,2503,2506],{},[858,2504,2505],{},"404",". Do not create a connection.",[828,2508,2509,2512],{},[849,2510,2511],{},"Enqueue fails",[849,2513,2514,2515,2517],{},"Return ",[858,2516,2262],{}," and leave the claim unfinished, so the vendor retries.",[828,2519,2520,2523],{},[849,2521,2522],{},"Duplicate delivery",[849,2524,2525],{},"ACK with success. Enqueue nothing.",[828,2527,2528,2531],{},[849,2529,2530],{},"Unknown sender",[849,2532,2533],{},"Answer with one link invitation. Start no Run.",[828,2535,2536,2539],{},[849,2537,2538],{},"Front Door fails",[849,2540,2541],{},"The turn fails. Send one error intent. Create no Run.",[828,2543,2544,2547],{},[849,2545,2546],{},"Delivery fails, retryable",[849,2548,2549],{},"Retry with backoff inside the notifier. Run state does not change.",[828,2551,2552,2555],{},[849,2553,2554],{},"Delivery fails, terminal",[849,2556,2557,2558,2560],{},"Mark the connection ",[858,2559,2273],{},". Alert ops. Run state does not change.",[828,2562,2563,2566],{},[849,2564,2565],{},"Connection revoked mid-Run",[849,2567,2568],{},"The Run continues. The result lands in Run Explorer only.",[828,2570,2571,2574],{},[849,2572,2573],{},"Person unlinked mid-Run",[849,2575,2576],{},"The Run continues under its frozen principal. The next message needs a new link.",[817,2578,2580],{"id":2579},"stress-tests","Stress tests",[822,2582,2583,2593],{},[825,2584,2585],{},[828,2586,2587,2590],{},[831,2588,2589],{},"Scenario",[831,2591,2592],{},"What the design does",[844,2594,2595,2607,2615,2626,2637,2648,2656,2664,2675,2683,2691,2699,2710,2718,2726,2737,2747],{},[828,2596,2597,2600],{},[849,2598,2599],{},"Slack retries the same delivery 3 times",[849,2601,2602,2603,2606],{},"The claim on ",[858,2604,2605],{},"external_event_id"," admits one. The other two ACK and stop.",[828,2608,2609,2612],{},[849,2610,2611],{},"Two messages arrive 200 ms apart in one thread",[849,2613,2614],{},"The session key limits the queue to one worker, so the turns stay ordered.",[828,2616,2617,2620],{},[849,2618,2619],{},"The bot answer triggers a new inbound event",[849,2621,2622,2623,2625],{},"The ",[858,2624,1943],{}," check drops it. No loop starts.",[828,2627,2628,2631],{},[849,2629,2630],{},"A person edits the message during the Run",[849,2632,2633,2634,2636],{},"The edit decodes to ",[858,2635,1622],{},". The Run keeps its original input.",[828,2638,2639,2642],{},[849,2640,2641],{},"A stranger writes in a shared channel",[849,2643,2644,2645,2647],{},"The message drops as ",[858,2646,1888],{},", or it receives one link invitation. No Run starts.",[828,2649,2650,2653],{},[849,2651,2652],{},"Two people talk in one Slack thread",[849,2654,2655],{},"One conversation, two principals. Each turn reads under its own sender.",[828,2657,2658,2661],{},[849,2659,2660],{},"A Run takes 40 minutes",[849,2662,2663],{},"One throttled progress edit, then one durable result message. Slack rate limits hold.",[828,2665,2666,2669],{},[849,2667,2668],{},"The answer is 30,000 characters",[849,2670,2671,2672,931],{},"The adapter splits it into ordered chunks under ",[858,2673,2674],{},"max_text",[828,2676,2677,2680],{},[849,2678,2679],{},"Two people press Approve at the same time",[849,2681,2682],{},"The approval row transitions one time. The second press reads the resolved state.",[828,2684,2685,2688],{},[849,2686,2687],{},"An unlinked person presses Approve",[849,2689,2690],{},"The action is refused, and the person receives the link invitation.",[828,2692,2693,2696],{},[849,2694,2695],{},"A person without authority presses Approve",[849,2697,2698],{},"The approval domain refuses. The Gateway renders the reason.",[828,2700,2701,2704],{},[849,2702,2703],{},"The workspace uninstalls while a Run waits",[849,2705,2706,2707,2709],{},"Delivery stops, the connection turns ",[858,2708,2453],{},", and Human Review still resolves the approval.",[828,2711,2712,2715],{},[849,2713,2714],{},"The worker dies after the vendor send",[849,2716,2717],{},"The dedupe key stops a second post on retry.",[828,2719,2720,2723],{},[849,2721,2722],{},"The same person works in two workspaces",[849,2724,2725],{},"Two identity rows, one per connection. Each carries its own organization.",[828,2727,2728,2731],{},[849,2729,2730],{},"A vendor sends a message with no thread id",[849,2732,2733,2734,2736],{},"The thread key is ",[858,2735,2121],{},", so the unique constraint still holds.",[828,2738,2739,2742],{},[849,2740,2741],{},"A person approves in Human Review, not in Slack",[849,2743,2744,2746],{},[858,2745,2238],{}," updates the Slack message, so the buttons do not stay live.",[828,2748,2749,2752],{},[849,2750,2751],{},"A person uploads a file in Slack",[849,2753,2754],{},"The count is recorded, and the platform answers that it reads text only.",[817,2756,2758],{"id":2757},"v1-decisions","V1 decisions",[822,2760,2761,2771],{},[825,2762,2763],{},[828,2764,2765,2768],{},[831,2766,2767],{},"Decision",[831,2769,2770],{},"V1 choice",[844,2772,2773,2781,2789,2796,2804,2811,2819,2827,2838,2846],{},[828,2774,2775,2778],{},[849,2776,2777],{},"Channels",[849,2779,2780],{},"Web chat now. Slack next",[828,2782,2783,2786],{},[849,2784,2785],{},"Identity states",[849,2787,2788],{},"Present or absent. No state column",[828,2790,2791,2793],{},[849,2792,2530],{},[849,2794,2795],{},"One link invitation. No Run, and no service actor",[828,2797,2798,2801],{},[849,2799,2800],{},"Message edits, deletes, reactions",[849,2802,2803],{},"Dropped",[828,2805,2806,2808],{},[849,2807,1976],{},[849,2809,2810],{},"Counted, then dropped, in every channel. Deferred to a later version",[828,2812,2813,2816],{},[849,2814,2815],{},"Inbound ordering",[849,2817,2818],{},"One worker per session key",[828,2820,2821,2824],{},[849,2822,2823],{},"Outbound answer, approval, error",[849,2825,2826],{},"Durable Inngest event, deduped",[828,2828,2829,2832],{},[849,2830,2831],{},"Outbound progress",[849,2833,2834,2835,2837],{},"Best effort, one edit per 5 seconds, only when ",[858,2836,2293],{}," is true",[828,2839,2840,2843],{},[849,2841,2842],{},"Approval buttons",[849,2844,2845],{},"Slack only. Human Review is the floor",[828,2847,2848,2851],{},[849,2849,2850],{},"Workspace to organization",[849,2852,2853],{},"One to one",[817,2855,2247],{"id":2856},"rules-1",[2135,2858,2859,2862,2865,2868,2871,2874,2877,2880,2883],{},[2138,2860,2861],{},"Interactive chat belongs here. Email does not.",[2138,2863,2864],{},"The Gateway degrades presentation. Agent behaviour stays channel independent.",[2138,2866,2867],{},"An unverified person never becomes an actor identity, and never starts a Run.",[2138,2869,2870],{},"No model call, prompt, plan, tool selection or business rule lives in this package.",[2138,2872,2873],{},"The Front Door receives no vendor field.",[2138,2875,2876],{},"A durable enqueue must succeed before the claim completes.",[2138,2878,2879],{},"A database constraint resolves every race. No distributed lock exists.",[2138,2881,2882],{},"Delivery telemetry is not product Run state.",[2138,2884,2885],{},"Web chat has no private path around the Gateway inbound, and it needs no Gateway outbound.",[817,2887,2889],{"id":2888},"open-decisions","Open decisions",[2891,2892,2893,2896,2899,2902],"ol",{},[2138,2894,2895],{},"Does Slack Socket Mode remove the public webhook endpoint for a self-hosted install, or does the HTTP path stay the only one?",[2138,2897,2898],{},"When does a shared thread need its own privacy rule, beyond the per-sender principal?",[2138,2900,2901],{},"Which channel earns the third adapter: Telegram for reach, or WhatsApp for the customer request?",[2138,2903,2904],{},"Should a link invitation carry the first message, so the person does not repeat it? V1 says no.",[817,2906,2908],{"id":2907},"minimum-contract-tests","Minimum contract tests",[2135,2910,2911,2914,2917,2920,2923,2926,2929,2932,2935,2938,2941,2944,2947,2950,2953,2956,2959],{},[2138,2912,2913],{},"Every adapter rejects an invalid signature and a stale timestamp.",[2138,2915,2916],{},"One vendor delivery id enqueues at most one durable message.",[2138,2918,2919],{},"A failed enqueue leaves the claim unfinished, so a retry still works.",[2138,2921,2922],{},"Concurrent session creation returns one session row.",[2138,2924,2925],{},"A message with no thread id and a message in a thread create two sessions.",[2138,2927,2928],{},"An unknown sender starts no Run, and receives at most one invitation per hour.",[2138,2930,2931],{},"An unlinked identity cannot regain an actor identity without a fresh link.",[2138,2933,2934],{},"A message from a bot never reaches the Front Door.",[2138,2936,2937],{},"An unaddressed channel message never reaches the Front Door.",[2138,2939,2940],{},"Two ordered messages in one thread produce two ordered turns.",[2138,2942,2943],{},"One Slack message produces one Run under duplicate delivery.",[2138,2945,2946],{},"A repeated outbound send with one dedupe key posts one message.",[2138,2948,2949],{},"A revoked connection stops delivery and fails no Run.",[2138,2951,2952],{},"Two approval presses produce one state transition.",[2138,2954,2955],{},"An approval resolved outside the channel clears the channel buttons.",[2138,2957,2958],{},"No vendor field reaches Front Door decision logic.",[2138,2960,2961],{},"Email cannot register as a Channel Gateway adapter.",[2963,2964,2965],"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":1123,"searchDepth":32,"depth":233,"links":2967},[2968,2969,2970,2971,2972,2979,2985,2990,2993,2994,2995,2996,2997,2998,2999,3000],{"id":819,"depth":32,"text":820},{"id":944,"depth":32,"text":945},{"id":1114,"depth":32,"text":1115},{"id":1143,"depth":32,"text":1144},{"id":322,"depth":32,"text":1343,"children":2973},[2974,2975,2976,2977,2978],{"id":448,"depth":233,"text":1347},{"id":1540,"depth":233,"text":1541},{"id":1626,"depth":233,"text":1627},{"id":1692,"depth":233,"text":1693},{"id":1745,"depth":233,"text":1746},{"id":1794,"depth":32,"text":1795,"children":2980},[2981,2982,2983,2984],{"id":1810,"depth":233,"text":1811},{"id":1931,"depth":233,"text":1932},{"id":1947,"depth":233,"text":1948},{"id":1975,"depth":233,"text":1976},{"id":1995,"depth":32,"text":1996,"children":2986},[2987,2988,2989],{"id":2026,"depth":233,"text":2027},{"id":238,"depth":233,"text":2072},{"id":2129,"depth":233,"text":2130},{"id":2152,"depth":32,"text":2153,"children":2991},[2992],{"id":2246,"depth":233,"text":2247},{"id":2309,"depth":32,"text":2310},{"id":612,"depth":32,"text":2325},{"id":2460,"depth":32,"text":2461},{"id":2579,"depth":32,"text":2580},{"id":2757,"depth":32,"text":2758},{"id":2856,"depth":32,"text":2247},{"id":2888,"depth":32,"text":2889},{"id":2907,"depth":32,"text":2908},"md",{},[3004,3005,3006,3007,3008,3009,3010],"engineering\u002Fsystem-design\u002Fagentic-platform","engineering\u002Fsystem-design\u002Fagentic-platform\u002Fcontract","engineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Fsurfaces","engineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Ffront-door","engineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Ftriggers","engineering\u002Fsystem-design\u002Fagentic-platform\u002Fruntime\u002Fexecution","engineering\u002Fsystem-design\u002Fagentic-platform\u002Fproducts\u002Fhuman-review",{"title":231,"description":232},"engineering\u002Fsystem-design\u002Fagentic-platform\u002Finterfaces\u002Fchannel-gateway",[208,235,236,237,238,199],"yInLWRLnaHl3eLXT9Ad1QQqUjjVpVMa2wk-bQuM_suc",1788650190287]