[{"data":1,"prerenderedAt":3183},["ShallowReactive",2],{"navigation":3,"\u002Fguides\u002Fagents\u002Fbuilding-agents":169,"\u002Fguides\u002Fagents\u002Fbuilding-agents-surround":3178},[4,28,85,127,157],{"title":5,"path":6,"stem":7,"children":8,"icon":27},"Getting Started","\u002Fgetting-started","1.getting-started\u002F1.index",[9,12,17,22],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-house",{"title":13,"path":14,"stem":15,"icon":16},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":18,"path":19,"stem":20,"icon":21},"Quick start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start","i-lucide-zap",{"title":23,"path":24,"stem":25,"icon":26},"Architecture","\u002Fgetting-started\u002Farchitecture","1.getting-started\u002F4.architecture","i-lucide-layers","i-lucide-rocket",{"title":29,"icon":30,"path":31,"stem":32,"children":33,"page":84},"Concepts","i-lucide-lightbulb","\u002Fconcepts","2.concepts",[34,39,44,49,54,59,64,69,74,79],{"title":35,"path":36,"stem":37,"icon":38},"Durable agents","\u002Fconcepts\u002Fdurable-agents","2.concepts\u002F1.durable-agents","i-lucide-infinity",{"title":40,"path":41,"stem":42,"icon":43},"Glossary","\u002Fconcepts\u002Fglossary","2.concepts\u002F10.glossary","i-lucide-book-a",{"title":45,"path":46,"stem":47,"icon":48},"Restate in five minutes","\u002Fconcepts\u002Frestate-primer","2.concepts\u002F2.restate-primer","i-lucide-cpu",{"title":50,"path":51,"stem":52,"icon":53},"Entities & addressing","\u002Fconcepts\u002Fentities-addressing","2.concepts\u002F3.entities-addressing","i-lucide-at-sign",{"title":55,"path":56,"stem":57,"icon":58},"Timelines & events","\u002Fconcepts\u002Ftimelines-events","2.concepts\u002F4.timelines-events","i-lucide-list-ordered",{"title":60,"path":61,"stem":62,"icon":63},"Projections & the catalog","\u002Fconcepts\u002Fprojections-catalog","2.concepts\u002F5.projections-catalog","i-lucide-database",{"title":65,"path":66,"stem":67,"icon":68},"Workspaces & execution","\u002Fconcepts\u002Fworkspaces","2.concepts\u002F6.workspaces","i-lucide-terminal",{"title":70,"path":71,"stem":72,"icon":73},"Harnesses","\u002Fconcepts\u002Fharnesses","2.concepts\u002F7.harnesses","i-lucide-plug",{"title":75,"path":76,"stem":77,"icon":78},"Multi-agent patterns","\u002Fconcepts\u002Fmulti-agent","2.concepts\u002F8.multi-agent","i-lucide-network",{"title":80,"path":81,"stem":82,"icon":83},"Lifecycle & control","\u002Fconcepts\u002Flifecycle","2.concepts\u002F9.lifecycle","i-lucide-sliders-horizontal",false,{"title":86,"icon":87,"path":88,"stem":89,"children":90,"page":84},"Guides","i-lucide-book-open","\u002Fguides","3.guides",[91,106],{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":84},"Agents","i-lucide-bot","\u002Fguides\u002Fagents","3.guides\u002F1.agents",[97,101],{"title":98,"path":99,"stem":100,"icon":93},"Building agents","\u002Fguides\u002Fagents\u002Fbuilding-agents","3.guides\u002F1.agents\u002F1.building-agents",{"title":102,"path":103,"stem":104,"icon":105},"Frontend integration","\u002Fguides\u002Fagents\u002Ffrontend-integration","3.guides\u002F1.agents\u002F2.frontend-integration","i-lucide-monitor",{"title":107,"icon":108,"path":109,"stem":110,"children":111,"page":84},"Operations","i-lucide-server-cog","\u002Fguides\u002Foperations","3.guides\u002F2.operations",[112,117,122],{"title":113,"path":114,"stem":115,"icon":116},"Self-hosting","\u002Fguides\u002Foperations\u002Fself-hosting","3.guides\u002F2.operations\u002F1.self-hosting","i-lucide-server",{"title":118,"path":119,"stem":120,"icon":121},"Auth & API keys","\u002Fguides\u002Foperations\u002Fauth-api-keys","3.guides\u002F2.operations\u002F2.auth-api-keys","i-lucide-key-round",{"title":123,"path":124,"stem":125,"icon":126},"Backup & restore","\u002Fguides\u002Foperations\u002Fbackup-restore","3.guides\u002F2.operations\u002F3.backup-restore","i-lucide-database-backup",{"title":128,"icon":129,"path":130,"stem":131,"children":132,"page":84},"Reference","i-lucide-book-marked","\u002Freference","4.reference",[133,138,143,148,153],{"title":134,"path":135,"stem":136,"icon":137},"Event schema","\u002Freference\u002Fevents","4.reference\u002F1.events","i-lucide-list-tree",{"title":139,"path":140,"stem":141,"icon":142},"Addressing","\u002Freference\u002Faddressing","4.reference\u002F2.addressing","i-lucide-map-pin",{"title":144,"path":145,"stem":146,"icon":147},"Gateway HTTP API","\u002Freference\u002Fgateway-api","4.reference\u002F3.gateway-api","i-lucide-webhook",{"title":149,"path":150,"stem":151,"icon":152},"CLI","\u002Freference\u002Fcli","4.reference\u002F4.cli","i-lucide-square-terminal",{"title":154,"path":155,"stem":156,"icon":83},"Configuration","\u002Freference\u002Fconfiguration","4.reference\u002F5.configuration",{"title":158,"path":159,"stem":160,"children":161,"icon":163},"Contributing","\u002Fcontributing","5.contributing\u002F1.index",[162,164],{"title":158,"path":159,"stem":160,"icon":163},"i-lucide-git-pull-request",{"title":165,"path":166,"stem":167,"icon":168},"The package map","\u002Fcontributing\u002Fpackage-map","5.contributing\u002F2.package-map","i-lucide-boxes",{"id":170,"title":98,"body":171,"description":3171,"extension":3172,"links":3173,"meta":3174,"navigation":3175,"path":99,"seo":3176,"stem":100,"__hash__":3177},"docs\u002F3.guides\u002F1.agents\u002F1.building-agents.md",{"type":172,"value":173,"toc":3147},"minimark",[174,196,201,204,525,536,540,556,559,574,594,598,608,647,649,656,740,748,752,755,763,848,861,923,1099,1117,1119,1134,1137,1144,1165,1168,1174,1178,1181,1199,1206,1209,1419,1526,1529,1666,1677,1689,1693,1696,1785,1809,1820,1824,1834,1904,1974,1987,1991,2000,2143,2148,2152,2161,2164,2191,2544,2562,2576,2580,2598,2607,2743,2753,2765,2769,2778,2990,3016,3043,3061,3074,3109,3113,3125,3131,3135,3143],[175,176,177,178,182,183,187,188,191,192,195],"p",{},"An agent is one ",[179,180,181],"code",{},"defineAgent({...})"," call: you declare its type, the shape of its spawn arguments and state, which ",[184,185,186],"a",{"href":71},"harness"," runs its model loop, and which tools it can use. ",[179,189,190],{},"serve(...)"," compiles that definition into a running service and registers it with the ",[184,193,194],{"href":145},"gateway",". This page builds one end to end, then covers each piece in depth.",[197,198,200],"h2",{"id":199},"a-complete-agent","A complete agent",[175,202,203],{},"Here is a working agent in full. It researches a topic, and when a message arrives it keeps going. Every field is explained below; read it once to see the shape.",[205,206,212],"pre",{"className":207,"code":208,"filename":209,"language":210,"meta":211,"style":211},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { defineAgent, native } from \"@teaspill\u002Fagents-sdk\";\nimport { z } from \"zod\";\n\nexport const researcher = defineAgent({\n  type: \"researcher\",\n  spawnSchema: z.object({ topic: z.string() }),\n  state: z.object({ findings: z.array(z.string()).default([]) }),\n  harness: native({\n    model: \"claude-sonnet-4-5\",\n    systemPrompt:\n      \"Research the topic you were spawned with. Record findings, then finish.\",\n    ingressUrl: process.env.TEASPILL_INGRESS_URL!,\n  }),\n});\n","agents\u002Fresearcher.ts","ts","",[179,213,214,256,279,286,311,331,375,429,443,460,469,482,506,516],{"__ignoreMap":211},[215,216,219,223,227,231,234,237,240,243,246,250,253],"span",{"class":217,"line":218},"line",1,[215,220,222],{"class":221},"s7zQu","import",[215,224,226],{"class":225},"sMK4o"," {",[215,228,230],{"class":229},"sTEyZ"," defineAgent",[215,232,233],{"class":225},",",[215,235,236],{"class":229}," native",[215,238,239],{"class":225}," }",[215,241,242],{"class":221}," from",[215,244,245],{"class":225}," \"",[215,247,249],{"class":248},"sfazB","@teaspill\u002Fagents-sdk",[215,251,252],{"class":225},"\"",[215,254,255],{"class":225},";\n",[215,257,259,261,263,266,268,270,272,275,277],{"class":217,"line":258},2,[215,260,222],{"class":221},[215,262,226],{"class":225},[215,264,265],{"class":229}," z",[215,267,239],{"class":225},[215,269,242],{"class":221},[215,271,245],{"class":225},[215,273,274],{"class":248},"zod",[215,276,252],{"class":225},[215,278,255],{"class":225},[215,280,282],{"class":217,"line":281},3,[215,283,285],{"emptyLinePlaceholder":284},true,"\n",[215,287,289,292,296,299,302,305,308],{"class":217,"line":288},4,[215,290,291],{"class":221},"export",[215,293,295],{"class":294},"spNyl"," const",[215,297,298],{"class":229}," researcher ",[215,300,301],{"class":225},"=",[215,303,230],{"class":304},"s2Zo4",[215,306,307],{"class":229},"(",[215,309,310],{"class":225},"{\n",[215,312,314,318,321,323,326,328],{"class":217,"line":313},5,[215,315,317],{"class":316},"swJcz","  type",[215,319,320],{"class":225},":",[215,322,245],{"class":225},[215,324,325],{"class":248},"researcher",[215,327,252],{"class":225},[215,329,330],{"class":225},",\n",[215,332,334,337,339,341,344,347,349,352,355,357,359,361,364,367,370,373],{"class":217,"line":333},6,[215,335,336],{"class":316},"  spawnSchema",[215,338,320],{"class":225},[215,340,265],{"class":229},[215,342,343],{"class":225},".",[215,345,346],{"class":304},"object",[215,348,307],{"class":229},[215,350,351],{"class":225},"{",[215,353,354],{"class":316}," topic",[215,356,320],{"class":225},[215,358,265],{"class":229},[215,360,343],{"class":225},[215,362,363],{"class":304},"string",[215,365,366],{"class":229},"() ",[215,368,369],{"class":225},"}",[215,371,372],{"class":229},")",[215,374,330],{"class":225},[215,376,378,381,383,385,387,389,391,393,396,398,400,402,405,408,410,412,415,417,420,423,425,427],{"class":217,"line":377},7,[215,379,380],{"class":316},"  state",[215,382,320],{"class":225},[215,384,265],{"class":229},[215,386,343],{"class":225},[215,388,346],{"class":304},[215,390,307],{"class":229},[215,392,351],{"class":225},[215,394,395],{"class":316}," findings",[215,397,320],{"class":225},[215,399,265],{"class":229},[215,401,343],{"class":225},[215,403,404],{"class":304},"array",[215,406,407],{"class":229},"(z",[215,409,343],{"class":225},[215,411,363],{"class":304},[215,413,414],{"class":229},"())",[215,416,343],{"class":225},[215,418,419],{"class":304},"default",[215,421,422],{"class":229},"([]) ",[215,424,369],{"class":225},[215,426,372],{"class":229},[215,428,330],{"class":225},[215,430,432,435,437,439,441],{"class":217,"line":431},8,[215,433,434],{"class":316},"  harness",[215,436,320],{"class":225},[215,438,236],{"class":304},[215,440,307],{"class":229},[215,442,310],{"class":225},[215,444,446,449,451,453,456,458],{"class":217,"line":445},9,[215,447,448],{"class":316},"    model",[215,450,320],{"class":225},[215,452,245],{"class":225},[215,454,455],{"class":248},"claude-sonnet-4-5",[215,457,252],{"class":225},[215,459,330],{"class":225},[215,461,463,466],{"class":217,"line":462},10,[215,464,465],{"class":316},"    systemPrompt",[215,467,468],{"class":225},":\n",[215,470,472,475,478,480],{"class":217,"line":471},11,[215,473,474],{"class":225},"      \"",[215,476,477],{"class":248},"Research the topic you were spawned with. Record findings, then finish.",[215,479,252],{"class":225},[215,481,330],{"class":225},[215,483,485,488,490,493,495,498,500,503],{"class":217,"line":484},12,[215,486,487],{"class":316},"    ingressUrl",[215,489,320],{"class":225},[215,491,492],{"class":229}," process",[215,494,343],{"class":225},[215,496,497],{"class":229},"env",[215,499,343],{"class":225},[215,501,502],{"class":229},"TEASPILL_INGRESS_URL",[215,504,505],{"class":225},"!,\n",[215,507,509,512,514],{"class":217,"line":508},13,[215,510,511],{"class":225},"  }",[215,513,372],{"class":229},[215,515,330],{"class":225},[215,517,519,521,523],{"class":217,"line":518},14,[215,520,369],{"class":225},[215,522,372],{"class":229},[215,524,255],{"class":225},[175,526,527,528,531,532,535],{},"That is a deployable agent. ",[179,529,530],{},"defineAgent"," returns an ",[179,533,534],{},"AgentDefinition","; the rest of this page is the rulebook for filling it in.",[197,537,539],{"id":538},"defineagent-field-by-field","defineAgent, field by field",[175,541,542,544,545,548,549,552,553,555],{},[179,543,530],{}," takes one object. ",[179,546,547],{},"type",", ",[179,550,551],{},"state",", and ",[179,554,186],{}," are required; everything else is optional.",[557,558,547],"h3",{"id":547},[175,560,561,562,565,566,569,570,573],{},"The agent type — a stable, lowercase name that identifies this kind of agent everywhere: in ",[184,563,564],{"href":51},"entity URLs",", in the ",[184,567,568],{"href":61},"catalog",", in every command. It must match ",[179,571,572],{},"^[a-z0-9][a-z0-9_-]{0,47}$",". An invalid type throws at definition time.",[205,575,577],{"className":207,"code":576,"language":210,"meta":211,"style":211},"type: \"researcher\",\n",[179,578,579],{"__ignoreMap":211},[215,580,581,584,586,588,590,592],{"class":217,"line":218},[215,582,547],{"class":583},"sBMFI",[215,585,320],{"class":225},[215,587,245],{"class":225},[215,589,325],{"class":248},[215,591,252],{"class":225},[215,593,330],{"class":225},[557,595,597],{"id":596},"spawnschema","spawnSchema",[175,599,600,601,607],{},"A ",[184,602,606],{"href":603,"rel":604},"https:\u002F\u002Fzod.dev",[605],"nofollow","Zod"," schema for the arguments passed when the agent is spawned. teaspill validates spawn arguments against it before the agent ever wakes; bad arguments are rejected cleanly at the door, with no retry and no partial agent. Omit it for an agent that takes no arguments.",[205,609,611],{"className":207,"code":610,"language":210,"meta":211,"style":211},"spawnSchema: z.object({ topic: z.string() }),\n",[179,612,613],{"__ignoreMap":211},[215,614,615,617,619,621,623,625,627,629,631,633,635,637,639,641,643,645],{"class":217,"line":218},[215,616,597],{"class":583},[215,618,320],{"class":225},[215,620,265],{"class":229},[215,622,343],{"class":225},[215,624,346],{"class":304},[215,626,307],{"class":229},[215,628,351],{"class":225},[215,630,354],{"class":316},[215,632,320],{"class":225},[215,634,265],{"class":229},[215,636,343],{"class":225},[215,638,363],{"class":304},[215,640,366],{"class":229},[215,642,369],{"class":225},[215,644,372],{"class":229},[215,646,330],{"class":225},[557,648,551],{"id":551},[175,650,651,652,655],{},"A Zod schema for the agent's persisted state — the memory it carries across wakes, deploys, and crashes. Keep it bounded: state is durable working memory, not a log (the full history lives on the ",[184,653,654],{"href":56},"timeline","). This field is required.",[205,657,659],{"className":207,"code":658,"language":210,"meta":211,"style":211},"state: z.object({\n  findings: z.array(z.string()).default([]),\n  summary: z.string().optional(),\n}),\n",[179,660,661,677,707,732],{"__ignoreMap":211},[215,662,663,665,667,669,671,673,675],{"class":217,"line":218},[215,664,551],{"class":583},[215,666,320],{"class":225},[215,668,265],{"class":229},[215,670,343],{"class":225},[215,672,346],{"class":304},[215,674,307],{"class":229},[215,676,310],{"class":225},[215,678,679,682,684,686,688,690,692,694,696,698,700,702,705],{"class":217,"line":258},[215,680,681],{"class":316},"  findings",[215,683,320],{"class":225},[215,685,265],{"class":229},[215,687,343],{"class":225},[215,689,404],{"class":304},[215,691,407],{"class":229},[215,693,343],{"class":225},[215,695,363],{"class":304},[215,697,414],{"class":229},[215,699,343],{"class":225},[215,701,419],{"class":304},[215,703,704],{"class":229},"([])",[215,706,330],{"class":225},[215,708,709,712,714,716,718,720,723,725,728,730],{"class":217,"line":281},[215,710,711],{"class":316},"  summary",[215,713,320],{"class":225},[215,715,265],{"class":229},[215,717,343],{"class":225},[215,719,363],{"class":304},[215,721,722],{"class":229},"()",[215,724,343],{"class":225},[215,726,727],{"class":304},"optional",[215,729,722],{"class":229},[215,731,330],{"class":225},[215,733,734,736,738],{"class":217,"line":288},[215,735,369],{"class":225},[215,737,372],{"class":229},[215,739,330],{"class":225},[175,741,742,743,747],{},"Changing this schema after agents are live has rules — see ",[184,744,746],{"href":745},"#state-revisions","state revisions"," below.",[557,749,751],{"id":750},"inboxschemas","inboxSchemas",[175,753,754],{},"Optional Zod schemas for inbound messages, keyed by an application-defined message kind. They are carried into the registration manifest as typed metadata.",[175,756,757,758,762],{},"By default — with no schema — the platform delivers a send body to your agent verbatim, and the model loop expects the ",[759,760,761],"strong",{},"canonical message shape",": the same content-block structure the timeline records.",[205,764,768],{"className":765,"code":766,"language":767,"meta":211,"style":211},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F The default accepted body — what teaspill\u002Fspawn, send, and the CLI produce:\n{ \"kind\": \"message\", \"content\": [{ \"type\": \"text\", \"text\": \"one more angle: green vs black tea\" }] }\n","json",[179,769,770,776],{"__ignoreMap":211},[215,771,772],{"class":217,"line":218},[215,773,775],{"class":774},"sHwdD","\u002F\u002F The default accepted body — what teaspill\u002Fspawn, send, and the CLI produce:\n",[215,777,778,780,782,785,787,789,791,794,796,798,800,803,805,807,810,812,814,816,818,820,823,825,827,829,831,833,835,837,840,842,845],{"class":217,"line":258},[215,779,351],{"class":225},[215,781,245],{"class":225},[215,783,784],{"class":294},"kind",[215,786,252],{"class":225},[215,788,320],{"class":225},[215,790,245],{"class":225},[215,792,793],{"class":248},"message",[215,795,252],{"class":225},[215,797,233],{"class":225},[215,799,245],{"class":225},[215,801,802],{"class":294},"content",[215,804,252],{"class":225},[215,806,320],{"class":225},[215,808,809],{"class":225}," [{",[215,811,245],{"class":225},[215,813,547],{"class":583},[215,815,252],{"class":225},[215,817,320],{"class":225},[215,819,245],{"class":225},[215,821,822],{"class":248},"text",[215,824,252],{"class":225},[215,826,233],{"class":225},[215,828,245],{"class":225},[215,830,822],{"class":583},[215,832,252],{"class":225},[215,834,320],{"class":225},[215,836,245],{"class":225},[215,838,839],{"class":248},"one more angle: green vs black tea",[215,841,252],{"class":225},[215,843,844],{"class":225}," }]",[215,846,847],{"class":225}," }\n",[175,849,850,851,853,854,856,857,860],{},"A schema keyed ",[179,852,419],{}," (or ",[179,855,793],{},") adds one extra check: when a message is a ",[759,858,859],{},"single text block whose text is itself JSON",", that JSON is validated against the schema before the wake commits, and a mismatch is rejected cleanly at the door. Any other shape — multiple blocks, non-text content, or text that isn't JSON — passes through unvalidated.",[205,862,864],{"className":207,"code":863,"language":210,"meta":211,"style":211},"inboxSchemas: {\n  \u002F\u002F Validates the JSON carried inside a single-text-block message.\n  default: z.object({ note: z.string() }),\n},\n",[179,865,866,875,880,918],{"__ignoreMap":211},[215,867,868,870,872],{"class":217,"line":218},[215,869,751],{"class":583},[215,871,320],{"class":225},[215,873,874],{"class":225}," {\n",[215,876,877],{"class":217,"line":258},[215,878,879],{"class":774},"  \u002F\u002F Validates the JSON carried inside a single-text-block message.\n",[215,881,882,885,888,891,893,895,897,899,902,904,906,908,910,912,914,916],{"class":217,"line":281},[215,883,884],{"class":221},"  default",[215,886,887],{"class":316},": ",[215,889,890],{"class":229},"z",[215,892,343],{"class":225},[215,894,346],{"class":304},[215,896,307],{"class":316},[215,898,351],{"class":225},[215,900,901],{"class":316}," note",[215,903,320],{"class":225},[215,905,265],{"class":229},[215,907,343],{"class":225},[215,909,363],{"class":304},[215,911,366],{"class":316},[215,913,369],{"class":225},[215,915,372],{"class":316},[215,917,330],{"class":225},[215,919,920],{"class":217,"line":288},[215,921,922],{"class":225},"},\n",[205,924,926],{"className":765,"code":925,"language":767,"meta":211,"style":211},"\u002F\u002F Accepted: the text block's text parses and matches { note: string }.\n{ \"kind\": \"message\", \"content\": [{ \"type\": \"text\", \"text\": \"{\\\"note\\\":\\\"focus on green tea\\\"}\" }] }\n\n\u002F\u002F Rejected: the JSON is present but the wrong shape.\n{ \"kind\": \"message\", \"content\": [{ \"type\": \"text\", \"text\": \"{\\\"foo\\\":1}\" }] }\n",[179,927,928,933,1016,1020,1025],{"__ignoreMap":211},[215,929,930],{"class":217,"line":218},[215,931,932],{"class":774},"\u002F\u002F Accepted: the text block's text parses and matches { note: string }.\n",[215,934,935,937,939,941,943,945,947,949,951,953,955,957,959,961,963,965,967,969,971,973,975,977,979,981,983,985,987,989,991,994,997,999,1001,1003,1006,1008,1010,1012,1014],{"class":217,"line":258},[215,936,351],{"class":225},[215,938,245],{"class":225},[215,940,784],{"class":294},[215,942,252],{"class":225},[215,944,320],{"class":225},[215,946,245],{"class":225},[215,948,793],{"class":248},[215,950,252],{"class":225},[215,952,233],{"class":225},[215,954,245],{"class":225},[215,956,802],{"class":294},[215,958,252],{"class":225},[215,960,320],{"class":225},[215,962,809],{"class":225},[215,964,245],{"class":225},[215,966,547],{"class":583},[215,968,252],{"class":225},[215,970,320],{"class":225},[215,972,245],{"class":225},[215,974,822],{"class":248},[215,976,252],{"class":225},[215,978,233],{"class":225},[215,980,245],{"class":225},[215,982,822],{"class":583},[215,984,252],{"class":225},[215,986,320],{"class":225},[215,988,245],{"class":225},[215,990,351],{"class":248},[215,992,993],{"class":229},"\\\"",[215,995,996],{"class":248},"note",[215,998,993],{"class":229},[215,1000,320],{"class":248},[215,1002,993],{"class":229},[215,1004,1005],{"class":248},"focus on green tea",[215,1007,993],{"class":229},[215,1009,369],{"class":248},[215,1011,252],{"class":225},[215,1013,844],{"class":225},[215,1015,847],{"class":225},[215,1017,1018],{"class":217,"line":281},[215,1019,285],{"emptyLinePlaceholder":284},[215,1021,1022],{"class":217,"line":288},[215,1023,1024],{"class":774},"\u002F\u002F Rejected: the JSON is present but the wrong shape.\n",[215,1026,1027,1029,1031,1033,1035,1037,1039,1041,1043,1045,1047,1049,1051,1053,1055,1057,1059,1061,1063,1065,1067,1069,1071,1073,1075,1077,1079,1081,1083,1085,1088,1090,1093,1095,1097],{"class":217,"line":313},[215,1028,351],{"class":225},[215,1030,245],{"class":225},[215,1032,784],{"class":294},[215,1034,252],{"class":225},[215,1036,320],{"class":225},[215,1038,245],{"class":225},[215,1040,793],{"class":248},[215,1042,252],{"class":225},[215,1044,233],{"class":225},[215,1046,245],{"class":225},[215,1048,802],{"class":294},[215,1050,252],{"class":225},[215,1052,320],{"class":225},[215,1054,809],{"class":225},[215,1056,245],{"class":225},[215,1058,547],{"class":583},[215,1060,252],{"class":225},[215,1062,320],{"class":225},[215,1064,245],{"class":225},[215,1066,822],{"class":248},[215,1068,252],{"class":225},[215,1070,233],{"class":225},[215,1072,245],{"class":225},[215,1074,822],{"class":583},[215,1076,252],{"class":225},[215,1078,320],{"class":225},[215,1080,245],{"class":225},[215,1082,351],{"class":248},[215,1084,993],{"class":229},[215,1086,1087],{"class":248},"foo",[215,1089,993],{"class":229},[215,1091,1092],{"class":248},":1}",[215,1094,252],{"class":225},[215,1096,844],{"class":225},[215,1098,847],{"class":225},[175,1100,1101,1104,1105,1108,1109,1112,1113,1116],{},[759,1102,1103],{},"Accepting shorthand bodies."," If you'd rather let callers send loose shorthand like ",[179,1106,1107],{},"{ \"text\": \"…\" }"," instead of the canonical shape, fold it into a canonical message before your agent sees it — the platform never rewrites payloads for you. The reference deployment does exactly this and exports the helper it uses, ",[179,1110,1111],{},"normalizeLooseMessage",", which turns ",[179,1114,1115],{},"{ text }"," (or any object) into a single-text-block message; it wraps its agent loop's message handling with it, so every demo agent accepts shorthand. Copy that approach when you want the same. This is a deployment-side convenience, not a stable SDK export — treat the reference deployment as the pattern to lift.",[557,1118,186],{"id":186},[175,1120,1121,1122,1125,1126,1129,1130,343],{},"The engine that runs the model loop: ",[179,1123,1124],{},"native(...)"," or ",[179,1127,1128],{},"claudeAgentSdk(...)",". This is the one field you swap to change engines — nothing else in the definition changes. See ",[184,1131,1133],{"href":1132},"#choosing-a-harness","choosing a harness",[557,1135,1136],{"id":1136},"tools",[175,1138,1139,1140,1143],{},"Your own tool definitions, appended ",[759,1141,1142],{},"after"," the platform and workspace tools the harness already provides. Reach for this when your agent needs a capability teaspill doesn't ship — a domain API, a search index, a calculator.",[205,1145,1147],{"className":207,"code":1146,"language":210,"meta":211,"style":211},"tools: [myWeatherTool, mySearchTool],\n",[179,1148,1149],{"__ignoreMap":211},[215,1150,1151,1153,1155,1158,1160,1163],{"class":217,"line":218},[215,1152,1136],{"class":583},[215,1154,320],{"class":225},[215,1156,1157],{"class":229}," [myWeatherTool",[215,1159,233],{"class":225},[215,1161,1162],{"class":229}," mySearchTool]",[215,1164,330],{"class":225},[557,1166,1167],{"id":1167},"tenant",[175,1169,1170,1171,343],{},"The default tenant for this type's entities. One deployment is one tenant, so you rarely set this; it defaults to ",[179,1172,1173],{},"\"default\"",[197,1175,1177],{"id":1176},"choosing-a-harness","Choosing a harness",[175,1179,1180],{},"Two harnesses, both durable, differing in who owns the loop. Pick per agent:",[1182,1183,1184,1192],"ul",{},[1185,1186,1187,1191],"li",{},[759,1188,1189],{},[179,1190,1124],{}," — the default. teaspill owns the loop, works with any model provider, and records the finest-grained recovery. Start here.",[1185,1193,1194,1198],{},[759,1195,1196],{},[179,1197,1128],{}," — runs the loop through the Claude Agent SDK, for when you specifically want Claude Code's session and compaction behavior inside a durable agent.",[175,1200,1201,1202,1205],{},"The trade-offs live in ",[184,1203,1204],{"href":71},"Concepts → Harnesses","; the configuration is below.",[557,1207,1124],{"id":1208},"native",[205,1210,1212],{"className":207,"code":1211,"language":210,"meta":211,"style":211},"native({\n  model: \"claude-sonnet-4-5\",        \u002F\u002F the model id string, or a full model object\n  provider: \"anthropic\",             \u002F\u002F default for string model ids\n  systemPrompt: \"…\",                 \u002F\u002F API-level system prompt (never timeline history)\n  contextBudgetTokens: 150_000,      \u002F\u002F crossing it triggers summarization\n  maxSteps: 40,                      \u002F\u002F hard cap on model steps per run\n  reasoning: \"medium\",               \u002F\u002F provider thinking level (optional)\n  temperature: 0.2,                  \u002F\u002F optional\n  maxTokens: 4096,                   \u002F\u002F optional per-response cap\n  platform: true,                    \u002F\u002F platform tools (default all; or { include }, or false)\n  workspace: false,                  \u002F\u002F workspace tools (default off — see below)\n  ingressUrl: process.env.TEASPILL_INGRESS_URL!, \u002F\u002F needed for spawn_agent \u002F send_message\n})\n",[179,1213,1214,1222,1240,1259,1278,1294,1309,1328,1343,1358,1374,1389,1412],{"__ignoreMap":211},[215,1215,1216,1218,1220],{"class":217,"line":218},[215,1217,1208],{"class":304},[215,1219,307],{"class":229},[215,1221,310],{"class":225},[215,1223,1224,1227,1229,1231,1233,1235,1237],{"class":217,"line":258},[215,1225,1226],{"class":316},"  model",[215,1228,320],{"class":225},[215,1230,245],{"class":225},[215,1232,455],{"class":248},[215,1234,252],{"class":225},[215,1236,233],{"class":225},[215,1238,1239],{"class":774},"        \u002F\u002F the model id string, or a full model object\n",[215,1241,1242,1245,1247,1249,1252,1254,1256],{"class":217,"line":281},[215,1243,1244],{"class":316},"  provider",[215,1246,320],{"class":225},[215,1248,245],{"class":225},[215,1250,1251],{"class":248},"anthropic",[215,1253,252],{"class":225},[215,1255,233],{"class":225},[215,1257,1258],{"class":774},"             \u002F\u002F default for string model ids\n",[215,1260,1261,1264,1266,1268,1271,1273,1275],{"class":217,"line":288},[215,1262,1263],{"class":316},"  systemPrompt",[215,1265,320],{"class":225},[215,1267,245],{"class":225},[215,1269,1270],{"class":248},"…",[215,1272,252],{"class":225},[215,1274,233],{"class":225},[215,1276,1277],{"class":774},"                 \u002F\u002F API-level system prompt (never timeline history)\n",[215,1279,1280,1283,1285,1289,1291],{"class":217,"line":313},[215,1281,1282],{"class":316},"  contextBudgetTokens",[215,1284,320],{"class":225},[215,1286,1288],{"class":1287},"sbssI"," 150_000",[215,1290,233],{"class":225},[215,1292,1293],{"class":774},"      \u002F\u002F crossing it triggers summarization\n",[215,1295,1296,1299,1301,1304,1306],{"class":217,"line":333},[215,1297,1298],{"class":316},"  maxSteps",[215,1300,320],{"class":225},[215,1302,1303],{"class":1287}," 40",[215,1305,233],{"class":225},[215,1307,1308],{"class":774},"                      \u002F\u002F hard cap on model steps per run\n",[215,1310,1311,1314,1316,1318,1321,1323,1325],{"class":217,"line":377},[215,1312,1313],{"class":316},"  reasoning",[215,1315,320],{"class":225},[215,1317,245],{"class":225},[215,1319,1320],{"class":248},"medium",[215,1322,252],{"class":225},[215,1324,233],{"class":225},[215,1326,1327],{"class":774},"               \u002F\u002F provider thinking level (optional)\n",[215,1329,1330,1333,1335,1338,1340],{"class":217,"line":431},[215,1331,1332],{"class":316},"  temperature",[215,1334,320],{"class":225},[215,1336,1337],{"class":1287}," 0.2",[215,1339,233],{"class":225},[215,1341,1342],{"class":774},"                  \u002F\u002F optional\n",[215,1344,1345,1348,1350,1353,1355],{"class":217,"line":445},[215,1346,1347],{"class":316},"  maxTokens",[215,1349,320],{"class":225},[215,1351,1352],{"class":1287}," 4096",[215,1354,233],{"class":225},[215,1356,1357],{"class":774},"                   \u002F\u002F optional per-response cap\n",[215,1359,1360,1363,1365,1369,1371],{"class":217,"line":462},[215,1361,1362],{"class":316},"  platform",[215,1364,320],{"class":225},[215,1366,1368],{"class":1367},"sfNiH"," true",[215,1370,233],{"class":225},[215,1372,1373],{"class":774},"                    \u002F\u002F platform tools (default all; or { include }, or false)\n",[215,1375,1376,1379,1381,1384,1386],{"class":217,"line":471},[215,1377,1378],{"class":316},"  workspace",[215,1380,320],{"class":225},[215,1382,1383],{"class":1367}," false",[215,1385,233],{"class":225},[215,1387,1388],{"class":774},"                  \u002F\u002F workspace tools (default off — see below)\n",[215,1390,1391,1394,1396,1398,1400,1402,1404,1406,1409],{"class":217,"line":484},[215,1392,1393],{"class":316},"  ingressUrl",[215,1395,320],{"class":225},[215,1397,492],{"class":229},[215,1399,343],{"class":225},[215,1401,497],{"class":229},[215,1403,343],{"class":225},[215,1405,502],{"class":229},[215,1407,1408],{"class":225},"!,",[215,1410,1411],{"class":774}," \u002F\u002F needed for spawn_agent \u002F send_message\n",[215,1413,1414,1416],{"class":217,"line":508},[215,1415,369],{"class":225},[215,1417,1418],{"class":229},")\n",[1420,1421,1422,1435],"table",{},[1423,1424,1425],"thead",{},[1426,1427,1428,1432],"tr",{},[1429,1430,1431],"th",{},"Field",[1429,1433,1434],{},"Meaning",[1436,1437,1438,1449,1461,1471,1481,1491,1509],"tbody",{},[1426,1439,1440,1446],{},[1441,1442,1443],"td",{},[179,1444,1445],{},"model",[1441,1447,1448],{},"Model id (or a full model object). Required.",[1426,1450,1451,1456],{},[1441,1452,1453],{},[179,1454,1455],{},"provider",[1441,1457,1458,1459,343],{},"Provider for string model ids. Default ",[179,1460,1251],{},[1426,1462,1463,1468],{},[1441,1464,1465],{},[179,1466,1467],{},"systemPrompt",[1441,1469,1470],{},"The model's system prompt. It is never the timeline — history is folded in separately.",[1426,1472,1473,1478],{},[1441,1474,1475],{},[179,1476,1477],{},"contextBudgetTokens",[1441,1479,1480],{},"Cache-inclusive budget; crossing it triggers summarization and the run continues on the folded context.",[1426,1482,1483,1488],{},[1441,1484,1485],{},[179,1486,1487],{},"maxSteps",[1441,1489,1490],{},"Hard cap on model steps in a single run.",[1426,1492,1493,1502],{},[1441,1494,1495,1498,1499],{},[179,1496,1497],{},"platform"," \u002F ",[179,1500,1501],{},"workspace",[1441,1503,1504,1505,343],{},"Which built-in toolsets to expose — see ",[184,1506,1508],{"href":1507},"#restricting-tools","restricting tools",[1426,1510,1511,1516],{},[1441,1512,1513],{},[179,1514,1515],{},"ingressUrl",[1441,1517,1518,1519,1498,1522,1525],{},"Where the agent reaches other agents. Required for ",[179,1520,1521],{},"spawn_agent",[179,1523,1524],{},"send_message","; omit for a leaf agent that only replies.",[557,1527,1128],{"id":1528},"claudeagentsdk",[205,1530,1532],{"className":207,"code":1531,"language":210,"meta":211,"style":211},"claudeAgentSdk({\n  model: \"claude-sonnet-4-5\",\n  systemPrompt: \"…\",                 \u002F\u002F replaces the Claude Code preset\n  sessionStore: \"\u002Fdata\u002Fcasdk-sessions\", \u002F\u002F durable session dir on a volume → warm resume\n  maxTurns: 30,                      \u002F\u002F hard cap on SDK turns per run\n  forceCold: false,                  \u002F\u002F ops lever: cold-rebuild every wake, no code change\n  platform: true,\n  workspace: false,\n  ingressUrl: process.env.TEASPILL_INGRESS_URL!,\n})\n",[179,1533,1534,1543,1557,1574,1593,1608,1622,1632,1642,1660],{"__ignoreMap":211},[215,1535,1536,1539,1541],{"class":217,"line":218},[215,1537,1538],{"class":304},"claudeAgentSdk",[215,1540,307],{"class":229},[215,1542,310],{"class":225},[215,1544,1545,1547,1549,1551,1553,1555],{"class":217,"line":258},[215,1546,1226],{"class":316},[215,1548,320],{"class":225},[215,1550,245],{"class":225},[215,1552,455],{"class":248},[215,1554,252],{"class":225},[215,1556,330],{"class":225},[215,1558,1559,1561,1563,1565,1567,1569,1571],{"class":217,"line":281},[215,1560,1263],{"class":316},[215,1562,320],{"class":225},[215,1564,245],{"class":225},[215,1566,1270],{"class":248},[215,1568,252],{"class":225},[215,1570,233],{"class":225},[215,1572,1573],{"class":774},"                 \u002F\u002F replaces the Claude Code preset\n",[215,1575,1576,1579,1581,1583,1586,1588,1590],{"class":217,"line":288},[215,1577,1578],{"class":316},"  sessionStore",[215,1580,320],{"class":225},[215,1582,245],{"class":225},[215,1584,1585],{"class":248},"\u002Fdata\u002Fcasdk-sessions",[215,1587,252],{"class":225},[215,1589,233],{"class":225},[215,1591,1592],{"class":774}," \u002F\u002F durable session dir on a volume → warm resume\n",[215,1594,1595,1598,1600,1603,1605],{"class":217,"line":313},[215,1596,1597],{"class":316},"  maxTurns",[215,1599,320],{"class":225},[215,1601,1602],{"class":1287}," 30",[215,1604,233],{"class":225},[215,1606,1607],{"class":774},"                      \u002F\u002F hard cap on SDK turns per run\n",[215,1609,1610,1613,1615,1617,1619],{"class":217,"line":333},[215,1611,1612],{"class":316},"  forceCold",[215,1614,320],{"class":225},[215,1616,1383],{"class":1367},[215,1618,233],{"class":225},[215,1620,1621],{"class":774},"                  \u002F\u002F ops lever: cold-rebuild every wake, no code change\n",[215,1623,1624,1626,1628,1630],{"class":217,"line":377},[215,1625,1362],{"class":316},[215,1627,320],{"class":225},[215,1629,1368],{"class":1367},[215,1631,330],{"class":225},[215,1633,1634,1636,1638,1640],{"class":217,"line":431},[215,1635,1378],{"class":316},[215,1637,320],{"class":225},[215,1639,1383],{"class":1367},[215,1641,330],{"class":225},[215,1643,1644,1646,1648,1650,1652,1654,1656,1658],{"class":217,"line":445},[215,1645,1393],{"class":316},[215,1647,320],{"class":225},[215,1649,492],{"class":229},[215,1651,343],{"class":225},[215,1653,497],{"class":229},[215,1655,343],{"class":225},[215,1657,502],{"class":229},[215,1659,505],{"class":225},[215,1661,1662,1664],{"class":217,"line":462},[215,1663,369],{"class":225},[215,1665,1418],{"class":229},[175,1667,1668,1669,1672,1673,1676],{},"The ",[179,1670,1671],{},"sessionStore"," directory is what makes resumes ",[759,1674,1675],{},"warm",": point it at a volume that survives restarts. Omit it and the agent keeps an in-process session that every fresh process rebuilds from the timeline — correct, just slower on the first turn. The heavy Claude Agent SDK dependency loads lazily on the first run only, so selecting this harness costs nothing until an agent actually runs.",[996,1678,1679],{},[175,1680,1681,1682,1684,1685,1688],{},"Both harnesses expose the same platform, workspace, and developer tools, and route every side-effecting tool call through the same exactly-once guarantee. A ",[179,1683,325],{}," on the native harness can spawn a ",[179,1686,1687],{},"summarizer"," on the Claude Agent SDK harness and neither notices.",[197,1690,1692],{"id":1691},"the-platform-tools","The platform tools",[175,1694,1695],{},"Every harness gives the model six coordination tools. You don't write them — they are the agent's built-in vocabulary for working with other agents and ending its turn.",[1420,1697,1698,1708],{},[1423,1699,1700],{},[1426,1701,1702,1705],{},[1429,1703,1704],{},"Tool",[1429,1706,1707],{},"What it does",[1436,1709,1710,1724,1738,1748,1761,1775],{},[1426,1711,1712,1717],{},[1441,1713,1714],{},[179,1715,1716],{},"spawn_agent(type, args, id?, workspace?)",[1441,1718,1719,1720,1723],{},"Spawn a child and return its id ",[759,1721,1722],{},"immediately"," — never its result.",[1426,1725,1726,1731],{},[1441,1727,1728],{},[179,1729,1730],{},"send_message(to, message, mode?)",[1441,1732,1733,1734,1737],{},"Fire-and-forget message to another agent by ",[184,1735,1736],{"href":51},"entity URL","; returns on enqueue.",[1426,1739,1740,1745],{},[1441,1741,1742],{},[179,1743,1744],{},"list_children()",[1441,1746,1747],{},"Read-only view of this agent's known children.",[1426,1749,1750,1755],{},[1441,1751,1752],{},[179,1753,1754],{},"wait(reason?)",[1441,1756,1757,1758,1760],{},"Yield the turn. Returns ",[759,1759,1722],{}," — it does not block.",[1426,1762,1763,1768],{},[1441,1764,1765],{},[179,1766,1767],{},"finish(result?, summary?)",[1441,1769,1770,1771,1774],{},"End the turn and mark the run complete; ",[179,1772,1773],{},"result"," goes to the parent.",[1426,1776,1777,1782],{},[1441,1778,1779],{},[179,1780,1781],{},"set_status(status)",[1441,1783,1784],{},"Update the agent's short status line; non-terminal.",[175,1786,1787,1788,887,1791,1802,1803,1125,1805,1808],{},"The mental model behind them is the whole ",[184,1789,1790],{"href":36},"wake model",[759,1792,1793,1794,1797,1798,1801],{},"spawn returns an id now, the child's result arrives later as a ",[179,1795,1796],{},"child_finished"," message on a future wake, and ",[179,1799,1800],{},"wait"," never blocks."," Agents never poll — they spawn or send what they need, call ",[179,1804,1800],{},[179,1806,1807],{},"finish",", and end the turn; the runtime re-wakes them when input arrives.",[175,1810,1811,1813,1814,1817,1818,343],{},[179,1812,1524],{}," also accepts ",[179,1815,1816],{},"mode: \"steer\"",", which lets one agent nudge another mid-turn — a parent redirecting a child it just spawned. If the recipient isn't mid-turn, the steer degrades to an ordinary message. This is agent-to-agent only; see ",[184,1819,75],{"href":76},[197,1821,1823],{"id":1822},"the-workspace-tools","The workspace tools",[175,1825,1826,1827,1830,1831,1833],{},"An agent that needs a filesystem and a shell gets five more tools when you set ",[179,1828,1829],{},"workspace: true"," on the harness. They run inside the agent's ",[184,1832,1501],{"href":66}," — a sandboxed environment fixed at spawn time.",[1420,1835,1836,1844],{},[1423,1837,1838],{},[1426,1839,1840,1842],{},[1429,1841,1704],{},[1429,1843,1707],{},[1436,1845,1846,1856,1866,1876,1894],{},[1426,1847,1848,1853],{},[1441,1849,1850],{},[179,1851,1852],{},"bash(command, …)",[1441,1854,1855],{},"Run a shell command; returns the exit code and a tail of the output (the full output streams out of band).",[1426,1857,1858,1863],{},[1441,1859,1860],{},[179,1861,1862],{},"read_file(path)",[1441,1864,1865],{},"Read a UTF-8 text file, relative to the workspace root.",[1426,1867,1868,1873],{},[1441,1869,1870],{},[179,1871,1872],{},"write_file(path, content)",[1441,1874,1875],{},"Create or overwrite a file; parent directories are created.",[1426,1877,1878,1883],{},[1441,1879,1880],{},[179,1881,1882],{},"edit_file(path, old_string, new_string)",[1441,1884,1885,1886,1889,1890,1893],{},"Replace text where ",[179,1887,1888],{},"old_string"," matches ",[759,1891,1892],{},"exactly once",", or fail loudly.",[1426,1895,1896,1901],{},[1441,1897,1898],{},[179,1899,1900],{},"ls(path?)",[1441,1902,1903],{},"List a directory; defaults to the workspace root.",[205,1905,1907],{"className":207,"code":1906,"language":210,"meta":211,"style":211},"harness: native({\n  model: \"claude-sonnet-4-5\",\n  workspace: true,   \u002F\u002F adds bash \u002F read_file \u002F write_file \u002F edit_file \u002F ls\n  ingressUrl: process.env.TEASPILL_INGRESS_URL!,\n}),\n",[179,1908,1909,1921,1935,1948,1966],{"__ignoreMap":211},[215,1910,1911,1913,1915,1917,1919],{"class":217,"line":218},[215,1912,186],{"class":583},[215,1914,320],{"class":225},[215,1916,236],{"class":304},[215,1918,307],{"class":229},[215,1920,310],{"class":225},[215,1922,1923,1925,1927,1929,1931,1933],{"class":217,"line":258},[215,1924,1226],{"class":316},[215,1926,320],{"class":225},[215,1928,245],{"class":225},[215,1930,455],{"class":248},[215,1932,252],{"class":225},[215,1934,330],{"class":225},[215,1936,1937,1939,1941,1943,1945],{"class":217,"line":281},[215,1938,1378],{"class":316},[215,1940,320],{"class":225},[215,1942,1368],{"class":1367},[215,1944,233],{"class":225},[215,1946,1947],{"class":774},"   \u002F\u002F adds bash \u002F read_file \u002F write_file \u002F edit_file \u002F ls\n",[215,1949,1950,1952,1954,1956,1958,1960,1962,1964],{"class":217,"line":288},[215,1951,1393],{"class":316},[215,1953,320],{"class":225},[215,1955,492],{"class":229},[215,1957,343],{"class":225},[215,1959,497],{"class":229},[215,1961,343],{"class":225},[215,1963,502],{"class":229},[215,1965,505],{"class":225},[215,1967,1968,1970,1972],{"class":217,"line":313},[215,1969,369],{"class":225},[215,1971,372],{"class":229},[215,1973,330],{"class":225},[175,1975,1976,1977,548,1980,548,1983,1986],{},"Every write (",[179,1978,1979],{},"bash",[179,1981,1982],{},"write_file",[179,1984,1985],{},"edit_file",") happens exactly once no matter how the run is retried; reads need no such guarantee.",[197,1988,1990],{"id":1989},"restricting-tools","Restricting tools",[175,1992,1993,1994,1996,1997,1999],{},"Both ",[179,1995,1497],{}," and ",[179,1998,1501],{}," accept the same three forms, so you can hand each agent exactly the tools it should have:",[205,2001,2003],{"className":207,"code":2002,"language":210,"meta":211,"style":211},"\u002F\u002F All platform tools (the default):\nplatform: true,\n\n\u002F\u002F A subset — a leaf agent that answers but never spawns:\nplatform: { include: [\"send_message\", \"wait\", \"finish\", \"set_status\"] },\n\n\u002F\u002F None — a purely deterministic agent with no coordination tools:\nplatform: false,\n\n\u002F\u002F Read-only workspace access:\nworkspace: { include: [\"read_file\", \"ls\"] },\n",[179,2004,2005,2010,2020,2024,2029,2081,2085,2090,2100,2104,2109],{"__ignoreMap":211},[215,2006,2007],{"class":217,"line":218},[215,2008,2009],{"class":774},"\u002F\u002F All platform tools (the default):\n",[215,2011,2012,2014,2016,2018],{"class":217,"line":258},[215,2013,1497],{"class":583},[215,2015,320],{"class":225},[215,2017,1368],{"class":1367},[215,2019,330],{"class":225},[215,2021,2022],{"class":217,"line":281},[215,2023,285],{"emptyLinePlaceholder":284},[215,2025,2026],{"class":217,"line":288},[215,2027,2028],{"class":774},"\u002F\u002F A subset — a leaf agent that answers but never spawns:\n",[215,2030,2031,2033,2035,2037,2040,2042,2045,2047,2049,2051,2053,2055,2057,2059,2061,2063,2065,2067,2069,2071,2074,2076,2079],{"class":217,"line":313},[215,2032,1497],{"class":583},[215,2034,320],{"class":225},[215,2036,226],{"class":225},[215,2038,2039],{"class":583}," include",[215,2041,320],{"class":225},[215,2043,2044],{"class":316}," [",[215,2046,252],{"class":225},[215,2048,1524],{"class":248},[215,2050,252],{"class":225},[215,2052,233],{"class":225},[215,2054,245],{"class":225},[215,2056,1800],{"class":248},[215,2058,252],{"class":225},[215,2060,233],{"class":225},[215,2062,245],{"class":225},[215,2064,1807],{"class":248},[215,2066,252],{"class":225},[215,2068,233],{"class":225},[215,2070,245],{"class":225},[215,2072,2073],{"class":248},"set_status",[215,2075,252],{"class":225},[215,2077,2078],{"class":316},"] ",[215,2080,922],{"class":225},[215,2082,2083],{"class":217,"line":333},[215,2084,285],{"emptyLinePlaceholder":284},[215,2086,2087],{"class":217,"line":377},[215,2088,2089],{"class":774},"\u002F\u002F None — a purely deterministic agent with no coordination tools:\n",[215,2091,2092,2094,2096,2098],{"class":217,"line":431},[215,2093,1497],{"class":583},[215,2095,320],{"class":225},[215,2097,1383],{"class":1367},[215,2099,330],{"class":225},[215,2101,2102],{"class":217,"line":445},[215,2103,285],{"emptyLinePlaceholder":284},[215,2105,2106],{"class":217,"line":462},[215,2107,2108],{"class":774},"\u002F\u002F Read-only workspace access:\n",[215,2110,2111,2113,2115,2117,2119,2121,2123,2125,2128,2130,2132,2134,2137,2139,2141],{"class":217,"line":471},[215,2112,1501],{"class":583},[215,2114,320],{"class":225},[215,2116,226],{"class":225},[215,2118,2039],{"class":583},[215,2120,320],{"class":225},[215,2122,2044],{"class":316},[215,2124,252],{"class":225},[215,2126,2127],{"class":248},"read_file",[215,2129,252],{"class":225},[215,2131,233],{"class":225},[215,2133,245],{"class":225},[215,2135,2136],{"class":248},"ls",[215,2138,252],{"class":225},[215,2140,2078],{"class":316},[215,2142,922],{"class":225},[175,2144,2145,2146,343],{},"Restricting tools is the cleanest way to shape behavior: a worker that must never spawn children simply doesn't get ",[179,2147,1521],{},[197,2149,2151],{"id":2150},"onwake","onWake",[175,2153,2154,2156,2157,2160],{},[179,2155,2151],{}," is an optional hook that runs ",[759,2158,2159],{},"before"," the harness, deterministically, on every wake. Use it for logic that shouldn't cost a model call: routing, validation, pure state machines, or the deterministic agents you write for testing.",[175,2162,2163],{},"The hook receives a context with the entity URL, what woke it, the bounded canonical context, a replay-stable clock, and methods to emit events, send, and spawn. It returns one of two outcomes:",[1182,2165,2166,2175],{},[1185,2167,2168,2171,2172,2174],{},[759,2169,2170],{},"Return falsy"," — your emitted events land first, then the harness runs the model as usual (",[179,2173,2151],{},"-then-harness).",[1185,2176,2177,2183,2184,2187,2188,2190],{},[759,2178,2179,2180],{},"Return ",[179,2181,2182],{},"{ handled: true }"," — the wake is fully handled and ",[759,2185,2186],{},"no model runs"," (",[179,2189,2151],{},"-only).",[205,2192,2195],{"className":207,"code":2193,"filename":2194,"language":210,"meta":211,"style":211},"import { defineAgent, native } from \"@teaspill\u002Fagents-sdk\";\nimport { z } from \"zod\";\n\nexport const echo = defineAgent({\n  type: \"echo\",\n  state: z.object({}),\n  harness: native({ model: \"claude-sonnet-4-5\" }),\n  onWake: async (ctx) => {\n    const last = ctx.canonicalContext.at(-1);\n    if (last?.type === \"message\") {\n      await ctx.emit([\n        { type: \"message\", payload: { role: \"assistant\", content: last.payload.content } },\n      ]);\n      return { handled: true }; \u002F\u002F deterministic — no model call\n    }\n    \u002F\u002F fall through to the harness for anything else\n  },\n});\n","agents\u002Fecho.ts",[179,2196,2197,2221,2241,2245,2262,2277,2298,2327,2350,2386,2415,2430,2490,2497,2517,2523,2529,2535],{"__ignoreMap":211},[215,2198,2199,2201,2203,2205,2207,2209,2211,2213,2215,2217,2219],{"class":217,"line":218},[215,2200,222],{"class":221},[215,2202,226],{"class":225},[215,2204,230],{"class":229},[215,2206,233],{"class":225},[215,2208,236],{"class":229},[215,2210,239],{"class":225},[215,2212,242],{"class":221},[215,2214,245],{"class":225},[215,2216,249],{"class":248},[215,2218,252],{"class":225},[215,2220,255],{"class":225},[215,2222,2223,2225,2227,2229,2231,2233,2235,2237,2239],{"class":217,"line":258},[215,2224,222],{"class":221},[215,2226,226],{"class":225},[215,2228,265],{"class":229},[215,2230,239],{"class":225},[215,2232,242],{"class":221},[215,2234,245],{"class":225},[215,2236,274],{"class":248},[215,2238,252],{"class":225},[215,2240,255],{"class":225},[215,2242,2243],{"class":217,"line":281},[215,2244,285],{"emptyLinePlaceholder":284},[215,2246,2247,2249,2251,2254,2256,2258,2260],{"class":217,"line":288},[215,2248,291],{"class":221},[215,2250,295],{"class":294},[215,2252,2253],{"class":229}," echo ",[215,2255,301],{"class":225},[215,2257,230],{"class":304},[215,2259,307],{"class":229},[215,2261,310],{"class":225},[215,2263,2264,2266,2268,2270,2273,2275],{"class":217,"line":313},[215,2265,317],{"class":316},[215,2267,320],{"class":225},[215,2269,245],{"class":225},[215,2271,2272],{"class":248},"echo",[215,2274,252],{"class":225},[215,2276,330],{"class":225},[215,2278,2279,2281,2283,2285,2287,2289,2291,2294,2296],{"class":217,"line":333},[215,2280,380],{"class":316},[215,2282,320],{"class":225},[215,2284,265],{"class":229},[215,2286,343],{"class":225},[215,2288,346],{"class":304},[215,2290,307],{"class":229},[215,2292,2293],{"class":225},"{}",[215,2295,372],{"class":229},[215,2297,330],{"class":225},[215,2299,2300,2302,2304,2306,2308,2310,2313,2315,2317,2319,2321,2323,2325],{"class":217,"line":377},[215,2301,434],{"class":316},[215,2303,320],{"class":225},[215,2305,236],{"class":304},[215,2307,307],{"class":229},[215,2309,351],{"class":225},[215,2311,2312],{"class":316}," model",[215,2314,320],{"class":225},[215,2316,245],{"class":225},[215,2318,455],{"class":248},[215,2320,252],{"class":225},[215,2322,239],{"class":225},[215,2324,372],{"class":229},[215,2326,330],{"class":225},[215,2328,2329,2332,2334,2337,2339,2343,2345,2348],{"class":217,"line":431},[215,2330,2331],{"class":304},"  onWake",[215,2333,320],{"class":225},[215,2335,2336],{"class":294}," async",[215,2338,2187],{"class":225},[215,2340,2342],{"class":2341},"sHdIc","ctx",[215,2344,372],{"class":225},[215,2346,2347],{"class":294}," =>",[215,2349,874],{"class":225},[215,2351,2352,2355,2358,2361,2364,2366,2369,2371,2374,2376,2379,2382,2384],{"class":217,"line":445},[215,2353,2354],{"class":294},"    const",[215,2356,2357],{"class":229}," last",[215,2359,2360],{"class":225}," =",[215,2362,2363],{"class":229}," ctx",[215,2365,343],{"class":225},[215,2367,2368],{"class":229},"canonicalContext",[215,2370,343],{"class":225},[215,2372,2373],{"class":304},"at",[215,2375,307],{"class":316},[215,2377,2378],{"class":225},"-",[215,2380,2381],{"class":1287},"1",[215,2383,372],{"class":316},[215,2385,255],{"class":225},[215,2387,2388,2391,2393,2396,2399,2401,2404,2406,2408,2410,2413],{"class":217,"line":462},[215,2389,2390],{"class":221},"    if",[215,2392,2187],{"class":316},[215,2394,2395],{"class":229},"last",[215,2397,2398],{"class":225},"?.",[215,2400,547],{"class":229},[215,2402,2403],{"class":225}," ===",[215,2405,245],{"class":225},[215,2407,793],{"class":248},[215,2409,252],{"class":225},[215,2411,2412],{"class":316},") ",[215,2414,310],{"class":225},[215,2416,2417,2420,2422,2424,2427],{"class":217,"line":471},[215,2418,2419],{"class":221},"      await",[215,2421,2363],{"class":229},[215,2423,343],{"class":225},[215,2425,2426],{"class":304},"emit",[215,2428,2429],{"class":316},"([\n",[215,2431,2432,2435,2438,2440,2442,2444,2446,2448,2451,2453,2455,2458,2460,2462,2465,2467,2469,2472,2474,2476,2478,2481,2483,2485,2487],{"class":217,"line":484},[215,2433,2434],{"class":225},"        {",[215,2436,2437],{"class":316}," type",[215,2439,320],{"class":225},[215,2441,245],{"class":225},[215,2443,793],{"class":248},[215,2445,252],{"class":225},[215,2447,233],{"class":225},[215,2449,2450],{"class":316}," payload",[215,2452,320],{"class":225},[215,2454,226],{"class":225},[215,2456,2457],{"class":316}," role",[215,2459,320],{"class":225},[215,2461,245],{"class":225},[215,2463,2464],{"class":248},"assistant",[215,2466,252],{"class":225},[215,2468,233],{"class":225},[215,2470,2471],{"class":316}," content",[215,2473,320],{"class":225},[215,2475,2357],{"class":229},[215,2477,343],{"class":225},[215,2479,2480],{"class":229},"payload",[215,2482,343],{"class":225},[215,2484,802],{"class":229},[215,2486,239],{"class":225},[215,2488,2489],{"class":225}," },\n",[215,2491,2492,2495],{"class":217,"line":508},[215,2493,2494],{"class":316},"      ])",[215,2496,255],{"class":225},[215,2498,2499,2502,2504,2507,2509,2511,2514],{"class":217,"line":518},[215,2500,2501],{"class":221},"      return",[215,2503,226],{"class":225},[215,2505,2506],{"class":316}," handled",[215,2508,320],{"class":225},[215,2510,1368],{"class":1367},[215,2512,2513],{"class":225}," };",[215,2515,2516],{"class":774}," \u002F\u002F deterministic — no model call\n",[215,2518,2520],{"class":217,"line":2519},15,[215,2521,2522],{"class":225},"    }\n",[215,2524,2526],{"class":217,"line":2525},16,[215,2527,2528],{"class":774},"    \u002F\u002F fall through to the harness for anything else\n",[215,2530,2532],{"class":217,"line":2531},17,[215,2533,2534],{"class":225},"  },\n",[215,2536,2538,2540,2542],{"class":217,"line":2537},18,[215,2539,369],{"class":225},[215,2541,372],{"class":229},[215,2543,255],{"class":225},[175,2545,2546,2547,2549,2550,2552,2553,2555,2556,2558,2559,2561],{},"An ",[179,2548,2151],{}," hook that always returns ",[179,2551,2182],{}," never reaches the harness, so the ",[179,2554,186],{}," config above is inert — ",[179,2557,530],{}," still requires the field, but its ",[179,2560,1445],{}," is never called and no provider credential is needed. This is exactly how deterministic, fully testable agents are built.",[2563,2564,2565],"tip",{},[175,2566,2567,2568,2571,2572,2575],{},"Read the clock through ",[179,2569,2570],{},"ctx.now()"," and never ",[179,2573,2574],{},"Date.now()",", so the hook replays identically after a crash.",[197,2577,2579],{"id":2578},"state-revisions","State revisions",[175,2581,2582,2583,2586,2587,2590,2591,2594,2595,343],{},"State schemas are ",[759,2584,2585],{},"additive-only within a revision",". A live agent persists state shaped by the revision it was spawned under, so a running deployment may only widen that shape in backward-compatible ways — ",[759,2588,2589],{},"add optional fields",". Removing a field, changing a field's type, or adding a ",[759,2592,2593],{},"required"," field is breaking, and requires a new ",[179,2596,2597],{},"revision",[175,2599,2600,2602,2603,2606],{},[179,2601,530],{}," enforces this at definition time against a ",[179,2604,2605],{},"baseline"," — the currently-deployed revision and schema — so a mistake is a loud build error, never silent state corruption at runtime.",[205,2608,2610],{"className":207,"code":2609,"language":210,"meta":211,"style":211},"defineAgent({\n  type: \"researcher\",\n  revision: 1,\n  state: z.object({ findings: z.array(z.string()) }),\n  baseline: { revision: 1, state: previouslyDeployedStateSchema },\n  \u002F\u002F …\n});\n\u002F\u002F Adding an OPTIONAL field here is fine.\n\u002F\u002F Removing\u002Fretyping a field, or adding a required one, throws StateRevisionError\n\u002F\u002F unless you bump to revision: 2.\n",[179,2611,2612,2620,2634,2646,2687,2715,2720,2728,2733,2738],{"__ignoreMap":211},[215,2613,2614,2616,2618],{"class":217,"line":218},[215,2615,530],{"class":304},[215,2617,307],{"class":229},[215,2619,310],{"class":225},[215,2621,2622,2624,2626,2628,2630,2632],{"class":217,"line":258},[215,2623,317],{"class":316},[215,2625,320],{"class":225},[215,2627,245],{"class":225},[215,2629,325],{"class":248},[215,2631,252],{"class":225},[215,2633,330],{"class":225},[215,2635,2636,2639,2641,2644],{"class":217,"line":281},[215,2637,2638],{"class":316},"  revision",[215,2640,320],{"class":225},[215,2642,2643],{"class":1287}," 1",[215,2645,330],{"class":225},[215,2647,2648,2650,2652,2654,2656,2658,2660,2662,2664,2666,2668,2670,2672,2674,2676,2678,2681,2683,2685],{"class":217,"line":288},[215,2649,380],{"class":316},[215,2651,320],{"class":225},[215,2653,265],{"class":229},[215,2655,343],{"class":225},[215,2657,346],{"class":304},[215,2659,307],{"class":229},[215,2661,351],{"class":225},[215,2663,395],{"class":316},[215,2665,320],{"class":225},[215,2667,265],{"class":229},[215,2669,343],{"class":225},[215,2671,404],{"class":304},[215,2673,407],{"class":229},[215,2675,343],{"class":225},[215,2677,363],{"class":304},[215,2679,2680],{"class":229},"()) ",[215,2682,369],{"class":225},[215,2684,372],{"class":229},[215,2686,330],{"class":225},[215,2688,2689,2692,2694,2696,2699,2701,2703,2705,2708,2710,2713],{"class":217,"line":313},[215,2690,2691],{"class":316},"  baseline",[215,2693,320],{"class":225},[215,2695,226],{"class":225},[215,2697,2698],{"class":316}," revision",[215,2700,320],{"class":225},[215,2702,2643],{"class":1287},[215,2704,233],{"class":225},[215,2706,2707],{"class":316}," state",[215,2709,320],{"class":225},[215,2711,2712],{"class":229}," previouslyDeployedStateSchema ",[215,2714,922],{"class":225},[215,2716,2717],{"class":217,"line":333},[215,2718,2719],{"class":774},"  \u002F\u002F …\n",[215,2721,2722,2724,2726],{"class":217,"line":377},[215,2723,369],{"class":225},[215,2725,372],{"class":229},[215,2727,255],{"class":225},[215,2729,2730],{"class":217,"line":431},[215,2731,2732],{"class":774},"\u002F\u002F Adding an OPTIONAL field here is fine.\n",[215,2734,2735],{"class":217,"line":445},[215,2736,2737],{"class":774},"\u002F\u002F Removing\u002Fretyping a field, or adding a required one, throws StateRevisionError\n",[215,2739,2740],{"class":217,"line":462},[215,2741,2742],{"class":774},"\u002F\u002F unless you bump to revision: 2.\n",[175,2744,2745,2746,2749,2750,2752],{},"Bumping the revision applies the new shape to ",[759,2747,2748],{},"new instances only","; existing agents keep their revision until they archive. When you don't know the deployed schema, omit ",[179,2751,2605],{}," — the first deploy has nothing to compare against.",[996,2754,2755],{},[175,2756,2757,2758,1996,2761,2764],{},"The standalone helpers ",[179,2759,2760],{},"diffStateSchema",[179,2762,2763],{},"assertStateRevision"," are exported if you want to run the same check in your own tooling or CI.",[197,2766,2768],{"id":2767},"serving-and-registration","Serving and registration",[175,2770,2771,2773,2774,2777],{},[179,2772,190],{}," compiles your definitions into running services, binds them, listens, and — when you give it ",[179,2775,2776],{},"registration"," — registers the deployment with the gateway.",[205,2779,2782],{"className":207,"code":2780,"filename":2781,"language":210,"meta":211,"style":211},"import { serve } from \"@teaspill\u002Fagents-sdk\";\nimport { researcher } from \".\u002Fagents\u002Fresearcher.js\";\nimport { summarizer } from \".\u002Fagents\u002Fsummarizer.js\";\n\nawait serve({\n  agents: [researcher, summarizer],\n  deps: platformDeps,  \u002F\u002F the deployment's plumbing — see below\n  port: 9080,\n  registration: {\n    gatewayUrl: process.env.TEASPILL_GATEWAY_URL!,\n    \u002F\u002F The URL Restate dials for every invocation — forwarded as-is, no rewrite.\n    deploymentUrl: \"http:\u002F\u002Fhost.docker.internal:9080\",\n    apiKey: process.env.TEASPILL_API_KEY,\n  },\n});\n","deploy.ts",[179,2783,2784,2805,2827,2849,2853,2864,2881,2896,2908,2917,2937,2942,2958,2978,2982],{"__ignoreMap":211},[215,2785,2786,2788,2790,2793,2795,2797,2799,2801,2803],{"class":217,"line":218},[215,2787,222],{"class":221},[215,2789,226],{"class":225},[215,2791,2792],{"class":229}," serve",[215,2794,239],{"class":225},[215,2796,242],{"class":221},[215,2798,245],{"class":225},[215,2800,249],{"class":248},[215,2802,252],{"class":225},[215,2804,255],{"class":225},[215,2806,2807,2809,2811,2814,2816,2818,2820,2823,2825],{"class":217,"line":258},[215,2808,222],{"class":221},[215,2810,226],{"class":225},[215,2812,2813],{"class":229}," researcher",[215,2815,239],{"class":225},[215,2817,242],{"class":221},[215,2819,245],{"class":225},[215,2821,2822],{"class":248},".\u002Fagents\u002Fresearcher.js",[215,2824,252],{"class":225},[215,2826,255],{"class":225},[215,2828,2829,2831,2833,2836,2838,2840,2842,2845,2847],{"class":217,"line":281},[215,2830,222],{"class":221},[215,2832,226],{"class":225},[215,2834,2835],{"class":229}," summarizer",[215,2837,239],{"class":225},[215,2839,242],{"class":221},[215,2841,245],{"class":225},[215,2843,2844],{"class":248},".\u002Fagents\u002Fsummarizer.js",[215,2846,252],{"class":225},[215,2848,255],{"class":225},[215,2850,2851],{"class":217,"line":288},[215,2852,285],{"emptyLinePlaceholder":284},[215,2854,2855,2858,2860,2862],{"class":217,"line":313},[215,2856,2857],{"class":221},"await",[215,2859,2792],{"class":304},[215,2861,307],{"class":229},[215,2863,310],{"class":225},[215,2865,2866,2869,2871,2874,2876,2879],{"class":217,"line":333},[215,2867,2868],{"class":316},"  agents",[215,2870,320],{"class":225},[215,2872,2873],{"class":229}," [researcher",[215,2875,233],{"class":225},[215,2877,2878],{"class":229}," summarizer]",[215,2880,330],{"class":225},[215,2882,2883,2886,2888,2891,2893],{"class":217,"line":377},[215,2884,2885],{"class":316},"  deps",[215,2887,320],{"class":225},[215,2889,2890],{"class":229}," platformDeps",[215,2892,233],{"class":225},[215,2894,2895],{"class":774},"  \u002F\u002F the deployment's plumbing — see below\n",[215,2897,2898,2901,2903,2906],{"class":217,"line":431},[215,2899,2900],{"class":316},"  port",[215,2902,320],{"class":225},[215,2904,2905],{"class":1287}," 9080",[215,2907,330],{"class":225},[215,2909,2910,2913,2915],{"class":217,"line":445},[215,2911,2912],{"class":316},"  registration",[215,2914,320],{"class":225},[215,2916,874],{"class":225},[215,2918,2919,2922,2924,2926,2928,2930,2932,2935],{"class":217,"line":462},[215,2920,2921],{"class":316},"    gatewayUrl",[215,2923,320],{"class":225},[215,2925,492],{"class":229},[215,2927,343],{"class":225},[215,2929,497],{"class":229},[215,2931,343],{"class":225},[215,2933,2934],{"class":229},"TEASPILL_GATEWAY_URL",[215,2936,505],{"class":225},[215,2938,2939],{"class":217,"line":471},[215,2940,2941],{"class":774},"    \u002F\u002F The URL Restate dials for every invocation — forwarded as-is, no rewrite.\n",[215,2943,2944,2947,2949,2951,2954,2956],{"class":217,"line":484},[215,2945,2946],{"class":316},"    deploymentUrl",[215,2948,320],{"class":225},[215,2950,245],{"class":225},[215,2952,2953],{"class":248},"http:\u002F\u002Fhost.docker.internal:9080",[215,2955,252],{"class":225},[215,2957,330],{"class":225},[215,2959,2960,2963,2965,2967,2969,2971,2973,2976],{"class":217,"line":508},[215,2961,2962],{"class":316},"    apiKey",[215,2964,320],{"class":225},[215,2966,492],{"class":229},[215,2968,343],{"class":225},[215,2970,497],{"class":229},[215,2972,343],{"class":225},[215,2974,2975],{"class":229},"TEASPILL_API_KEY",[215,2977,330],{"class":225},[215,2979,2980],{"class":217,"line":518},[215,2981,2534],{"class":225},[215,2983,2984,2986,2988],{"class":217,"line":2519},[215,2985,369],{"class":225},[215,2987,372],{"class":229},[215,2989,255],{"class":225},[175,2991,1668,2992,2995,2996,2999,3000,3003,3004,3007,3008,3011,3012,3015],{},[179,2993,2994],{},"deps"," object (",[179,2997,2998],{},"CompileDeps",") carries the connections the deployment supplies: the projection outbox and the notifier that move an agent's activity out to the ",[184,3001,3002],{"href":61},"timeline and catalog",", plus optional pieces like ",[179,3005,3006],{},"emitDelta"," (live token streaming) and ",[179,3009,3010],{},"archiveCatalog",". You rarely build these by hand — the ",[184,3013,3014],{"href":166},"reference deployment"," wires them all from public APIs, and copying it is the intended starting point.",[3017,3018,3019],"warning",{},[175,3020,1668,3021,3024,3025,3028,3029,3032,3033,3036,3037,3039,3040,3042],{},[179,3022,3023],{},"deploymentUrl"," is the address ",[759,3026,3027],{},"Restate dials to reach your service",", forwarded verbatim with no rewriting. It must be reachable from inside the stack: use the compose service name on the network, or ",[179,3030,3031],{},"host.docker.internal:\u003Cport>"," for a host-run service in development. Registering ",[179,3034,3035],{},"localhost"," is the classic mistake — the container's ",[179,3038,3035],{}," is not your host. See ",[184,3041,113],{"href":114}," for the full networking rules.",[3044,3045,3046],"caution",{},[175,3047,3048,3049,3052,3053,2187,3055,3057,3058,3060],{},"Resurrection — bringing an ",[184,3050,3051],{"href":81},"archived agent"," back with a new message — requires an archive catalog wired into ",[179,3054,2994],{},[179,3056,3010],{},"). Without it, an agent can archive but can never come back. The reference deployment wires this for you; if you assemble ",[179,3059,2994],{}," yourself, include it.",[175,3062,3063,3066,3067,3073],{},[179,3064,3065],{},"serve"," does a single registration attempt and throws on failure. For local development, let the ",[184,3068,3069,3072],{"href":150},[179,3070,3071],{},"teaspill dev"," CLI"," drive it instead — it waits for the gateway to be healthy and retries registration with backoff, which removes the boot-order race.",[3075,3076,3077],"accordion",{},[3078,3079,3082],"accordion-item",{"icon":3080,"label":3081},"i-lucide-microscope","What the deployment dependencies actually do",[175,3083,3084,3085,3087,3088,3090,3091,3093,3094,3097,3098,3101,3102,3105,3106,3108],{},"Each ",[179,3086,530],{}," is a template; ",[179,3089,3065],{}," compiles it against ",[179,3092,2994],{}," to produce the live service. The ",[759,3095,3096],{},"outbox"," is the one-way path that copies every canonical event an agent emits out to the timeline stream and the catalog, exactly once. The ",[759,3099,3100],{},"notifier"," delivers messages and wake signals between agents. The ",[759,3103,3104],{},"archive catalog"," persists an agent's complete state when it archives and reads it back to resurrect it. Timing knobs — the idle-archive delay, chunk sizes — also ride on ",[179,3107,2994],{},". Because these are injected rather than baked in, the very same agent definition runs unchanged against real infrastructure in production and against fakes in a test.",[197,3110,3112],{"id":3111},"testing-your-agent","Testing your agent",[175,3114,2546,3115,3117,3118,3121,3122,3124],{},[179,3116,534],{}," exposes ",[179,3119,3120],{},"compileConfig(deps)",", which produces the configuration the coordination layer runs — so you can drive an agent's handlers directly with fake dependencies and a fake context, no live stack required. ",[179,3123,2151],{},"-only agents are the easiest to test this way, since they never call a model.",[175,3126,3127,3128,3130],{},"For end-to-end behavior — crash-resume, fan-out gather, workspace-exec durability — the conformance kit ships ready-made deterministic agents and the scenario checks that assert on them; the ",[184,3129,3014],{"href":166}," serves them, and its own suite runs entirely offline.",[197,3132,3134],{"id":3133},"next-steps","Next steps",[175,3136,3137,3138,3140,3141,343],{},"Your agents are running. To spawn them, watch their timelines, and stream their activity into a UI, continue to ",[184,3139,102],{"href":103},". To deploy the stack they run on, see ",[184,3142,113],{"href":114},[3144,3145,3146],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":211,"searchDepth":218,"depth":258,"links":3148},[3149,3150,3159,3163,3164,3165,3166,3167,3168,3169,3170],{"id":199,"depth":258,"text":200},{"id":538,"depth":258,"text":539,"children":3151},[3152,3153,3154,3155,3156,3157,3158],{"id":547,"depth":281,"text":547},{"id":596,"depth":281,"text":597},{"id":551,"depth":281,"text":551},{"id":750,"depth":281,"text":751},{"id":186,"depth":281,"text":186},{"id":1136,"depth":281,"text":1136},{"id":1167,"depth":281,"text":1167},{"id":1176,"depth":258,"text":1177,"children":3160},[3161,3162],{"id":1208,"depth":281,"text":1124},{"id":1528,"depth":281,"text":1128},{"id":1691,"depth":258,"text":1692},{"id":1822,"depth":258,"text":1823},{"id":1989,"depth":258,"text":1990},{"id":2150,"depth":258,"text":2151},{"id":2578,"depth":258,"text":2579},{"id":2767,"depth":258,"text":2768},{"id":3111,"depth":258,"text":3112},{"id":3133,"depth":258,"text":3134},"Define an agent with the Agents SDK — schemas, harness, tools, the onWake hook, state revisions, and serving it to the gateway.","md",null,{},{"icon":93},{"title":98,"description":3171},"uybGfD88D7H5obkzIL2JhO-bmouVIC7NKS0JNrzl53U",[3179,3181],{"title":80,"path":81,"stem":82,"description":3180,"icon":83,"children":-1},"Active, idle, archived — and the four verbs for intervening from outside, including bringing an archived agent back.",{"title":102,"path":103,"stem":104,"description":3182,"icon":105,"children":-1},"Spawn agents, read and live-follow their timelines, subscribe to the catalog, and mint browser read tokens with the frontend SDK.",1784473424390]