[{"data":1,"prerenderedAt":1932},["ShallowReactive",2],{"navigation":3,"\u002Fguides\u002Fagents\u002Ffrontend-integration":169,"\u002Fguides\u002Fagents\u002Ffrontend-integration-surround":1927},[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":102,"body":171,"description":1920,"extension":1921,"links":1922,"meta":1923,"navigation":1924,"path":103,"seo":1925,"stem":104,"__hash__":1926},"docs\u002F3.guides\u002F1.agents\u002F2.frontend-integration.md",{"type":172,"value":173,"toc":1906},"minimark",[174,191,210,215,218,258,266,273,277,287,610,628,650,654,672,901,925,936,940,953,960,1078,1089,1098,1102,1112,1115,1136,1142,1210,1217,1287,1297,1301,1304,1328,1353,1358,1377,1392,1396,1402,1558,1591,1595,1598,1856,1876,1880,1890,1894,1902],[175,176,177,178,182,183,186,187,190],"p",{},"The frontend SDK connects a browser or a Node backend to a running deployment: spawn and command agents, materialize an agent's ",[179,180,181],"a",{"href":56},"timeline"," into UI collections, and subscribe to the ",[179,184,185],{"href":61},"catalog"," as live-updating queries. Everything goes through the ",[179,188,189],{"href":145},"gateway"," — the SDK never touches internal services directly.",[192,193,194],"note",{},[175,195,196,197,201,202,205,206,209],{},"The teaspill packages aren't published to npm yet — ",[198,199,200],"code",{},"@teaspill\u002Ffrontend-sdk"," and the rest are consumed as workspace packages inside the monorepo. Today you build your app in the repo and depend on them with ",[198,203,204],{},"\"@teaspill\u002Ffrontend-sdk\": \"workspace:*\"",", the way the ",[179,207,208],{"href":19},"quick start"," sets up its agents package.",[211,212,214],"h2",{"id":213},"three-clients-one-per-route-family","Three clients, one per route family",[175,216,217],{},"The SDK is three small clients, each mapping to one gateway surface:",[219,220,221,235,247],"ul",{},[222,223,224,230,231,234],"li",{},[225,226,227],"strong",{},[198,228,229],{},"createActionsClient"," — writes: spawn, send, control, through ",[198,232,233],{},"\u002Fapi\u002F*",". Requires an API key.",[222,236,237,242,243,246],{},[225,238,239],{},[198,240,241],{},"createAgentTimeline"," — reads one entity's history and live tail, through ",[198,244,245],{},"\u002Fstreams\u002F*",".",[222,248,249,254,255,246],{},[225,250,251],{},[198,252,253],{},"createAgentCatalog"," — reads the entity registry as live queries, through ",[198,256,257],{},"\u002Fshapes\u002F*",[175,259,260,261,265],{},"Reads can use a browser ",[179,262,264],{"href":263},"#auth-in-the-browser","read token","; writes always require a full credential, because writes never bypass your backend.",[175,267,268,269,272],{},"Under the actions and timeline clients is a ",[225,270,271],{},"pure reducer"," — no I\u002FO, no clock — that folds the raw event stream into typed collections. It runs unchanged in the browser, on a server, and in tests.",[211,274,276],{"id":275},"the-actions-client","The actions client",[175,278,279,280,282,283,286],{},"Commands go through the gateway's ",[198,281,233],{}," routes. Every command answers with the entity's canonical ",[198,284,285],{},"url"," and the URL of its timeline stream — feed that straight into the timeline reader.",[288,289,294],"pre",{"className":290,"code":291,"language":292,"meta":293,"style":293},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { createActionsClient } from \"@teaspill\u002Ffrontend-sdk\";\n\nconst actions = createActionsClient({\n  baseUrl: GATEWAY_URL,\n  auth: { apiKey: process.env.TEASPILL_API_KEY! }, \u002F\u002F server-side credential\n});\n\n\u002F\u002F Spawn returns the new entity + its stream URL.\nconst { url, streamUrl } = await actions.spawn({\n  type: \"researcher\",\n  args: { topic: \"the history of tea\" },\n});\n\n\u002F\u002F Send a follow-up message (the payload is your agent's inbox shape).\nawait actions.send(url, { note: \"focus on green vs black\" });\n\n\u002F\u002F Control verbs: interrupt | pause | resume | archive.\nawait actions.interrupt(url, \"wrong topic\");\n","ts","",[198,295,296,331,338,360,376,414,425,430,436,472,489,514,523,528,534,572,577,583],{"__ignoreMap":293},[297,298,301,305,309,313,316,319,322,325,328],"span",{"class":299,"line":300},"line",1,[297,302,304],{"class":303},"s7zQu","import",[297,306,308],{"class":307},"sMK4o"," {",[297,310,312],{"class":311},"sTEyZ"," createActionsClient",[297,314,315],{"class":307}," }",[297,317,318],{"class":303}," from",[297,320,321],{"class":307}," \"",[297,323,200],{"class":324},"sfazB",[297,326,327],{"class":307},"\"",[297,329,330],{"class":307},";\n",[297,332,334],{"class":299,"line":333},2,[297,335,337],{"emptyLinePlaceholder":336},true,"\n",[297,339,341,345,348,351,354,357],{"class":299,"line":340},3,[297,342,344],{"class":343},"spNyl","const",[297,346,347],{"class":311}," actions ",[297,349,350],{"class":307},"=",[297,352,312],{"class":353},"s2Zo4",[297,355,356],{"class":311},"(",[297,358,359],{"class":307},"{\n",[297,361,363,367,370,373],{"class":299,"line":362},4,[297,364,366],{"class":365},"swJcz","  baseUrl",[297,368,369],{"class":307},":",[297,371,372],{"class":311}," GATEWAY_URL",[297,374,375],{"class":307},",\n",[297,377,379,382,384,386,389,391,394,396,399,401,404,407,410],{"class":299,"line":378},5,[297,380,381],{"class":365},"  auth",[297,383,369],{"class":307},[297,385,308],{"class":307},[297,387,388],{"class":365}," apiKey",[297,390,369],{"class":307},[297,392,393],{"class":311}," process",[297,395,246],{"class":307},[297,397,398],{"class":311},"env",[297,400,246],{"class":307},[297,402,403],{"class":311},"TEASPILL_API_KEY",[297,405,406],{"class":307},"!",[297,408,409],{"class":307}," },",[297,411,413],{"class":412},"sHwdD"," \u002F\u002F server-side credential\n",[297,415,417,420,423],{"class":299,"line":416},6,[297,418,419],{"class":307},"}",[297,421,422],{"class":311},")",[297,424,330],{"class":307},[297,426,428],{"class":299,"line":427},7,[297,429,337],{"emptyLinePlaceholder":336},[297,431,433],{"class":299,"line":432},8,[297,434,435],{"class":412},"\u002F\u002F Spawn returns the new entity + its stream URL.\n",[297,437,439,441,443,446,449,452,454,457,460,463,465,468,470],{"class":299,"line":438},9,[297,440,344],{"class":343},[297,442,308],{"class":307},[297,444,445],{"class":311}," url",[297,447,448],{"class":307},",",[297,450,451],{"class":311}," streamUrl ",[297,453,419],{"class":307},[297,455,456],{"class":307}," =",[297,458,459],{"class":303}," await",[297,461,462],{"class":311}," actions",[297,464,246],{"class":307},[297,466,467],{"class":353},"spawn",[297,469,356],{"class":311},[297,471,359],{"class":307},[297,473,475,478,480,482,485,487],{"class":299,"line":474},10,[297,476,477],{"class":365},"  type",[297,479,369],{"class":307},[297,481,321],{"class":307},[297,483,484],{"class":324},"researcher",[297,486,327],{"class":307},[297,488,375],{"class":307},[297,490,492,495,497,499,502,504,506,509,511],{"class":299,"line":491},11,[297,493,494],{"class":365},"  args",[297,496,369],{"class":307},[297,498,308],{"class":307},[297,500,501],{"class":365}," topic",[297,503,369],{"class":307},[297,505,321],{"class":307},[297,507,508],{"class":324},"the history of tea",[297,510,327],{"class":307},[297,512,513],{"class":307}," },\n",[297,515,517,519,521],{"class":299,"line":516},12,[297,518,419],{"class":307},[297,520,422],{"class":311},[297,522,330],{"class":307},[297,524,526],{"class":299,"line":525},13,[297,527,337],{"emptyLinePlaceholder":336},[297,529,531],{"class":299,"line":530},14,[297,532,533],{"class":412},"\u002F\u002F Send a follow-up message (the payload is your agent's inbox shape).\n",[297,535,537,540,542,544,547,550,552,554,557,559,561,564,566,568,570],{"class":299,"line":536},15,[297,538,539],{"class":303},"await",[297,541,462],{"class":311},[297,543,246],{"class":307},[297,545,546],{"class":353},"send",[297,548,549],{"class":311},"(url",[297,551,448],{"class":307},[297,553,308],{"class":307},[297,555,556],{"class":365}," note",[297,558,369],{"class":307},[297,560,321],{"class":307},[297,562,563],{"class":324},"focus on green vs black",[297,565,327],{"class":307},[297,567,315],{"class":307},[297,569,422],{"class":311},[297,571,330],{"class":307},[297,573,575],{"class":299,"line":574},16,[297,576,337],{"emptyLinePlaceholder":336},[297,578,580],{"class":299,"line":579},17,[297,581,582],{"class":412},"\u002F\u002F Control verbs: interrupt | pause | resume | archive.\n",[297,584,586,588,590,592,595,597,599,601,604,606,608],{"class":299,"line":585},18,[297,587,539],{"class":303},[297,589,462],{"class":311},[297,591,246],{"class":307},[297,593,594],{"class":353},"interrupt",[297,596,549],{"class":311},[297,598,448],{"class":307},[297,600,321],{"class":307},[297,602,603],{"class":324},"wrong topic",[297,605,327],{"class":307},[297,607,422],{"class":311},[297,609,330],{"class":307},[175,611,612,613,615,616,619,620,623,624,627],{},"A target can be the canonical ",[198,614,285],{},", a short form ",[198,617,618],{},"\"\u002Fa\u002Fresearcher\u002F\u003Cid>\"",", or ",[198,621,622],{},"{ type, id }",". Pass an ",[198,625,626],{},"idempotencyKey"," in the per-request options to make a retried command safe. Because writes require a full credential, run the actions client from your backend (or a trusted proxy), not from untrusted browser code.",[192,629,630],{},[175,631,632,633,635,636,635,639,642,643,646,647,649],{},"The control verbs are ",[198,634,594],{},", ",[198,637,638],{},"pause",[198,640,641],{},"resume",", and ",[198,644,645],{},"archive"," — the same four covered in ",[179,648,80],{"href":81},". There is no \"steer\" from the browser; steering is an agent-to-agent delivery mode only.",[211,651,653],{"id":652},"reading-a-timeline","Reading a timeline",[175,655,656,658,659,635,662,635,665,635,668,671],{},[198,657,241],{}," reads an entity's timeline stream, folds every event through the reducer, and exposes a subscribable snapshot of typed collections — ",[198,660,661],{},"messages",[198,663,664],{},"toolCalls",[198,666,667],{},"runs",[198,669,670],{},"children",", and more.",[288,673,675],{"className":290,"code":674,"language":292,"meta":293,"style":293},"import { createAgentTimeline } from \"@teaspill\u002Ffrontend-sdk\";\n\nconst timeline = createAgentTimeline(`${GATEWAY_URL}${streamUrl}`, {\n  auth: { token: () => refreshReadToken() }, \u002F\u002F browser read token, refreshed per request\n  deltas: true,                              \u002F\u002F also follow the live token stream\n  onDrift: (d) => console.warn(\"timeline drift\", d),\n});\n\ntimeline.subscribe((s) => {\n  render(s.timeline.messages, s.timeline.liveDeltas);\n});\n",[198,676,677,698,702,735,766,782,824,832,836,858,893],{"__ignoreMap":293},[297,678,679,681,683,686,688,690,692,694,696],{"class":299,"line":300},[297,680,304],{"class":303},[297,682,308],{"class":307},[297,684,685],{"class":311}," createAgentTimeline",[297,687,315],{"class":307},[297,689,318],{"class":303},[297,691,321],{"class":307},[297,693,200],{"class":324},[297,695,327],{"class":307},[297,697,330],{"class":307},[297,699,700],{"class":299,"line":333},[297,701,337],{"emptyLinePlaceholder":336},[297,703,704,706,709,711,713,715,718,721,724,727,730,732],{"class":299,"line":340},[297,705,344],{"class":343},[297,707,708],{"class":311}," timeline ",[297,710,350],{"class":307},[297,712,685],{"class":353},[297,714,356],{"class":311},[297,716,717],{"class":307},"`${",[297,719,720],{"class":311},"GATEWAY_URL",[297,722,723],{"class":307},"}${",[297,725,726],{"class":311},"streamUrl",[297,728,729],{"class":307},"}`",[297,731,448],{"class":307},[297,733,734],{"class":307}," {\n",[297,736,737,739,741,743,746,748,751,754,757,760,763],{"class":299,"line":362},[297,738,381],{"class":365},[297,740,369],{"class":307},[297,742,308],{"class":307},[297,744,745],{"class":353}," token",[297,747,369],{"class":307},[297,749,750],{"class":307}," ()",[297,752,753],{"class":343}," =>",[297,755,756],{"class":353}," refreshReadToken",[297,758,759],{"class":311},"() ",[297,761,762],{"class":307},"},",[297,764,765],{"class":412}," \u002F\u002F browser read token, refreshed per request\n",[297,767,768,771,773,777,779],{"class":299,"line":378},[297,769,770],{"class":365},"  deltas",[297,772,369],{"class":307},[297,774,776],{"class":775},"sfNiH"," true",[297,778,448],{"class":307},[297,780,781],{"class":412},"                              \u002F\u002F also follow the live token stream\n",[297,783,784,787,789,792,796,798,800,803,805,808,810,812,815,817,819,822],{"class":299,"line":416},[297,785,786],{"class":353},"  onDrift",[297,788,369],{"class":307},[297,790,791],{"class":307}," (",[297,793,795],{"class":794},"sHdIc","d",[297,797,422],{"class":307},[297,799,753],{"class":343},[297,801,802],{"class":311}," console",[297,804,246],{"class":307},[297,806,807],{"class":353},"warn",[297,809,356],{"class":311},[297,811,327],{"class":307},[297,813,814],{"class":324},"timeline drift",[297,816,327],{"class":307},[297,818,448],{"class":307},[297,820,821],{"class":311}," d)",[297,823,375],{"class":307},[297,825,826,828,830],{"class":299,"line":427},[297,827,419],{"class":307},[297,829,422],{"class":311},[297,831,330],{"class":307},[297,833,834],{"class":299,"line":432},[297,835,337],{"emptyLinePlaceholder":336},[297,837,838,840,842,845,847,849,852,854,856],{"class":299,"line":438},[297,839,181],{"class":311},[297,841,246],{"class":307},[297,843,844],{"class":353},"subscribe",[297,846,356],{"class":311},[297,848,356],{"class":307},[297,850,851],{"class":794},"s",[297,853,422],{"class":307},[297,855,753],{"class":343},[297,857,734],{"class":307},[297,859,860,863,865,867,869,871,873,875,877,880,882,884,886,889,891],{"class":299,"line":474},[297,861,862],{"class":353},"  render",[297,864,356],{"class":365},[297,866,851],{"class":311},[297,868,246],{"class":307},[297,870,181],{"class":311},[297,872,246],{"class":307},[297,874,661],{"class":311},[297,876,448],{"class":307},[297,878,879],{"class":311}," s",[297,881,246],{"class":307},[297,883,181],{"class":311},[297,885,246],{"class":307},[297,887,888],{"class":311},"liveDeltas",[297,890,422],{"class":365},[297,892,330],{"class":307},[297,894,895,897,899],{"class":299,"line":491},[297,896,419],{"class":307},[297,898,422],{"class":311},[297,900,330],{"class":307},[175,902,903,904,906,907,909,910,913,914,916,917,920,921,924],{},"The snapshot's ",[198,905,181],{}," holds the materialized collections; ",[198,908,888],{}," holds the in-flight ",[179,911,912],{"href":56},"token deltas"," — the streaming fragments of a message the model is still producing. Render ",[198,915,888],{}," for the typing-in-progress effect; each one is replaced by its finalized message the moment that event lands. Set ",[198,918,919],{},"deltas: true"," to open the sibling live stream; leave it off for a read-only history view. Call ",[198,922,923],{},"timeline.close()"," when the view unmounts.",[175,926,927,928,931,932,935],{},"The reducer's collections are deliberately lossy — they keep what a UI renders, not the exact event sequence. If you need the raw events themselves (the conformance kit's gapless\u002Fexactly-once checks are the motivating case), pass an ",[198,929,930],{},"onEvents(events, state)"," callback: it fires with each applied batch of parsed events, in stream order, before the reducer folds them. Per-",[198,933,934],{},"seq"," dedup is the caller's to apply at this layer.",[211,937,939],{"id":938},"auth-in-the-browser","Auth in the browser",[175,941,942,943,946,947,949,950,952],{},"Writes need a full API key, so they stay on your backend. For ",[225,944,945],{},"reads",", the gateway can verify a short-lived read token, letting a browser read ",[198,948,245],{}," and ",[198,951,257],{}," directly without proxying every byte through your server.",[175,954,955,956,959],{},"You mint tokens server-side with ",[198,957,958],{},"mintReadToken"," and hand them to the browser:",[288,961,964],{"className":290,"code":962,"filename":963,"language":292,"meta":293,"style":293},"import { mintReadToken } from \"@teaspill\u002Fagents-sdk\";\n\nconst token = await mintReadToken({\n  \u002F\u002F One prefix covers this entity's timeline AND deltas. Include the trailing slash.\n  pfx: \"\u002Fstreams\u002Ft\u002Fdefault\u002Fagents\u002Fresearcher\u002F\u003Cid>\u002F\",\n  ttlSeconds: 300,                       \u002F\u002F keep it short — reconnecting is cheap\n  secret: process.env.GATEWAY_JWT_SECRET!, \u002F\u002F must match the gateway's secret\n});\n","server: \u002Fapi\u002Fstream-token",[198,965,966,988,992,1009,1014,1030,1046,1070],{"__ignoreMap":293},[297,967,968,970,972,975,977,979,981,984,986],{"class":299,"line":300},[297,969,304],{"class":303},[297,971,308],{"class":307},[297,973,974],{"class":311}," mintReadToken",[297,976,315],{"class":307},[297,978,318],{"class":303},[297,980,321],{"class":307},[297,982,983],{"class":324},"@teaspill\u002Fagents-sdk",[297,985,327],{"class":307},[297,987,330],{"class":307},[297,989,990],{"class":299,"line":333},[297,991,337],{"emptyLinePlaceholder":336},[297,993,994,996,999,1001,1003,1005,1007],{"class":299,"line":340},[297,995,344],{"class":343},[297,997,998],{"class":311}," token ",[297,1000,350],{"class":307},[297,1002,459],{"class":303},[297,1004,974],{"class":353},[297,1006,356],{"class":311},[297,1008,359],{"class":307},[297,1010,1011],{"class":299,"line":362},[297,1012,1013],{"class":412},"  \u002F\u002F One prefix covers this entity's timeline AND deltas. Include the trailing slash.\n",[297,1015,1016,1019,1021,1023,1026,1028],{"class":299,"line":378},[297,1017,1018],{"class":365},"  pfx",[297,1020,369],{"class":307},[297,1022,321],{"class":307},[297,1024,1025],{"class":324},"\u002Fstreams\u002Ft\u002Fdefault\u002Fagents\u002Fresearcher\u002F\u003Cid>\u002F",[297,1027,327],{"class":307},[297,1029,375],{"class":307},[297,1031,1032,1035,1037,1041,1043],{"class":299,"line":416},[297,1033,1034],{"class":365},"  ttlSeconds",[297,1036,369],{"class":307},[297,1038,1040],{"class":1039},"sbssI"," 300",[297,1042,448],{"class":307},[297,1044,1045],{"class":412},"                       \u002F\u002F keep it short — reconnecting is cheap\n",[297,1047,1048,1051,1053,1055,1057,1059,1061,1064,1067],{"class":299,"line":427},[297,1049,1050],{"class":365},"  secret",[297,1052,369],{"class":307},[297,1054,393],{"class":311},[297,1056,246],{"class":307},[297,1058,398],{"class":311},[297,1060,246],{"class":307},[297,1062,1063],{"class":311},"GATEWAY_JWT_SECRET",[297,1065,1066],{"class":307},"!,",[297,1068,1069],{"class":412}," \u002F\u002F must match the gateway's secret\n",[297,1071,1072,1074,1076],{"class":299,"line":432},[297,1073,419],{"class":307},[297,1075,422],{"class":311},[297,1077,330],{"class":307},[175,1079,1080,1081,1084,1085,1088],{},"The token authorizes exactly one path prefix, and only for reads — it can never spawn, send, or control. Pass a ",[198,1082,1083],{},"token()"," ",[225,1086,1087],{},"function"," (not a string) to the timeline and catalog clients: the SDK re-evaluates it per request, so a long-lived subscription picks up fresh tokens automatically. On a 401 the streams are resumable, so reconnecting with a new token is cheap and loses nothing.",[175,1090,1091,1092,1095,1096,246],{},"The trailing slash on ",[198,1093,1094],{},"pfx"," matters: it gives a clean entity boundary so the token can't leak to a neighbor whose id shares the prefix. The full flow — enabling the JWT secret on the gateway, CORS, TTLs — is in ",[179,1097,118],{"href":119},[211,1099,1101],{"id":1100},"fast-join-joining-a-long-timeline-cheaply","Fast-join: joining a long timeline cheaply",[175,1103,1104,1105,1108,1109,246],{},"A UI that opens an hour-old conversation shouldn't replay every event from zero. A ",[179,1106,1107],{"href":56},"snapshot"," carries the entity's complete state at a point in the timeline, so you can join at the latest snapshot and fold forward from there. That is ",[225,1110,1111],{},"fast-join",[175,1113,1114],{},"The catalog row for an entity carries the two values you need:",[219,1116,1117,1126],{},[222,1118,1119,1122,1123,1125],{},[198,1120,1121],{},"snapshotOffset"," — the ",[198,1124,934],{}," of the latest snapshot (its position in the numbered history).",[222,1127,1128,1131,1132,1135],{},[198,1129,1130],{},"snapshotStreamOffset"," — an ",[225,1133,1134],{},"opaque"," byte offset that lets the reader seek straight to that snapshot record instead of scanning from the beginning.",[175,1137,1138,1139,369],{},"Pass both as ",[198,1140,1141],{},"fromSnapshot",[288,1143,1145],{"className":290,"code":1144,"language":292,"meta":293,"style":293},"const timeline = createAgentTimeline(streamUrl, {\n  fromSnapshot: { seq: row.snapshotOffset, offset: row.snapshotStreamOffset },\n});\n",[198,1146,1147,1164,1202],{"__ignoreMap":293},[297,1148,1149,1151,1153,1155,1157,1160,1162],{"class":299,"line":300},[297,1150,344],{"class":343},[297,1152,708],{"class":311},[297,1154,350],{"class":307},[297,1156,685],{"class":353},[297,1158,1159],{"class":311},"(streamUrl",[297,1161,448],{"class":307},[297,1163,734],{"class":307},[297,1165,1166,1169,1171,1173,1176,1178,1181,1183,1185,1187,1190,1192,1194,1196,1199],{"class":299,"line":333},[297,1167,1168],{"class":365},"  fromSnapshot",[297,1170,369],{"class":307},[297,1172,308],{"class":307},[297,1174,1175],{"class":365}," seq",[297,1177,369],{"class":307},[297,1179,1180],{"class":311}," row",[297,1182,246],{"class":307},[297,1184,1121],{"class":311},[297,1186,448],{"class":307},[297,1188,1189],{"class":365}," offset",[297,1191,369],{"class":307},[297,1193,1180],{"class":311},[297,1195,246],{"class":307},[297,1197,1198],{"class":311},"snapshotStreamOffset ",[297,1200,1201],{"class":307},"},\n",[297,1203,1204,1206,1208],{"class":299,"line":340},[297,1205,419],{"class":307},[297,1207,422],{"class":311},[297,1209,330],{"class":307},[175,1211,1212,1213,1216],{},"The helper ",[198,1214,1215],{},"fromSnapshotForRow(row)"," builds this object from a catalog row for you, handling every case:",[288,1218,1220],{"className":290,"code":1219,"language":292,"meta":293,"style":293},"import { fromSnapshotForRow } from \"@teaspill\u002Ffrontend-sdk\";\n\nconst timeline = createAgentTimeline(streamUrl, {\n  fromSnapshot: fromSnapshotForRow(row), \u002F\u002F undefined if the entity never snapshotted\n});\n",[198,1221,1222,1243,1247,1263,1279],{"__ignoreMap":293},[297,1223,1224,1226,1228,1231,1233,1235,1237,1239,1241],{"class":299,"line":300},[297,1225,304],{"class":303},[297,1227,308],{"class":307},[297,1229,1230],{"class":311}," fromSnapshotForRow",[297,1232,315],{"class":307},[297,1234,318],{"class":303},[297,1236,321],{"class":307},[297,1238,200],{"class":324},[297,1240,327],{"class":307},[297,1242,330],{"class":307},[297,1244,1245],{"class":299,"line":333},[297,1246,337],{"emptyLinePlaceholder":336},[297,1248,1249,1251,1253,1255,1257,1259,1261],{"class":299,"line":340},[297,1250,344],{"class":343},[297,1252,708],{"class":311},[297,1254,350],{"class":307},[297,1256,685],{"class":353},[297,1258,1159],{"class":311},[297,1260,448],{"class":307},[297,1262,734],{"class":307},[297,1264,1265,1267,1269,1271,1274,1276],{"class":299,"line":362},[297,1266,1168],{"class":365},[297,1268,369],{"class":307},[297,1270,1230],{"class":353},[297,1272,1273],{"class":311},"(row)",[297,1275,448],{"class":307},[297,1277,1278],{"class":412}," \u002F\u002F undefined if the entity never snapshotted\n",[297,1280,1281,1283,1285],{"class":299,"line":378},[297,1282,419],{"class":307},[297,1284,422],{"class":311},[297,1286,330],{"class":307},[175,1288,1289,1290,1293,1294,1296],{},"The ",[198,1291,1292],{},"offset"," is a token, never a number — pass it through verbatim, never do arithmetic on it. When it's present the reader seeks straight to the snapshot; when it's absent (an entity that hasn't snapshotted yet) the reader scans from the start and the reducer skips everything below ",[198,1295,934],{}," — correct either way, just not as cheap. Collections then cover the post-join window; the pre-snapshot history is a separate full read if you ever need it.",[211,1298,1300],{"id":1299},"ordering-guarantees-you-get-for-free","Ordering guarantees you get for free",[175,1302,1303],{},"The reducer makes a mid-stream join behave exactly like a full replay. Three rules do the work, and you don't implement any of them:",[1305,1306,1307,1316,1322],"ol",{},[222,1308,1309,1312,1313,1315],{},[225,1310,1311],{},"Duplicates are dropped."," If an event arrives with a ",[198,1314,934],{}," already applied, the reducer discards it and counts it. Duplicate events are normal, not an error — you never handle them yourself.",[222,1317,1318,1321],{},[225,1319,1320],{},"Snapshot-join equals replay."," Joining at a snapshot and folding forward yields the same collections, entity state, and post-join window as reading from event 0.",[222,1323,1324,1327],{},[225,1325,1326],{},"The finalized event always wins."," Live token deltas merge as they stream, but the instant the finalized message, reasoning, or tool call lands, it supersedes the buffer and every later fragment for it. The committed history is always the truth on screen.",[1329,1330,1331],"accordion",{},[1332,1333,1336],"accordion-item",{"icon":1334,"label":1335},"i-lucide-microscope","Where duplicate events come from",[175,1337,1338,1339,1341,1342,1344,1345,1349,1350,1352],{},"The streams server persists its writer-dedup state on a debounce. If it crashes inside that window, an append it already acknowledged can be re-admitted after restart, so the same event can appear twice in a read — byte-identical, with the same ",[198,1340,934],{},". Because every event embeds its ",[198,1343,934],{},", dropping the second copy is always safe, and the reducer does it for you. A ",[1346,1347,1348],"em",{},"gap"," in ",[198,1351,934],{},", by contrast, is never normal — the reducer surfaces it as drift.",[1354,1355,1357],"h3",{"id":1356},"drift-and-history-holes","Drift and history holes",[175,1359,1360,1361,1364,1365,1368,1369,1372,1373,1376],{},"The timeline is numbered ",[198,1362,1363],{},"0, 1, 2, …"," with no gaps, so a ",[225,1366,1367],{},"forward gap"," means something went wrong. The reducer surfaces it through the ",[198,1370,1371],{},"onDrift"," callback and a ",[198,1374,1375],{},"drift"," field on the snapshot, then keeps applying events so the UI still shows the live tail. The right response is to offer the user a reload rather than trusting a partial view.",[175,1378,1379,1380,1383,1384,1387,1388,1391],{},"One discontinuity is sanctioned. After a catastrophic loss of stream history, recovery writes a snapshot marked as a ",[225,1381,1382],{},"history hole"," — a marked gap that says \"history is missing here\" instead of pretending otherwise. The reducer jumps across it without raising drift and sets ",[198,1385,1386],{},"historyHole"," on the snapshot. Render a visible marker where ",[198,1389,1390],{},"s.timeline.historyHole"," is true so the gap is honest to the reader.",[211,1393,1395],{"id":1394},"catalog-subscriptions","Catalog subscriptions",[175,1397,1398,1399,1401],{},"The catalog is the live registry of entities. ",[198,1400,253],{}," subscribes to it as a filtered, live-updating query — the source for lists and dashboards (conversation detail comes from timelines).",[288,1403,1405],{"className":290,"code":1404,"language":292,"meta":293,"style":293},"import { createAgentCatalog } from \"@teaspill\u002Ffrontend-sdk\";\n\nconst catalog = createAgentCatalog({\n  baseUrl: GATEWAY_URL,\n  filter: { type: \"researcher\", status: \"active\" },\n  auth: { token: () => refreshReadToken() },\n});\n\ncatalog.subscribe((s) => renderList(s.rows));\n",[198,1406,1407,1428,1432,1447,1457,1493,1515,1523,1527],{"__ignoreMap":293},[297,1408,1409,1411,1413,1416,1418,1420,1422,1424,1426],{"class":299,"line":300},[297,1410,304],{"class":303},[297,1412,308],{"class":307},[297,1414,1415],{"class":311}," createAgentCatalog",[297,1417,315],{"class":307},[297,1419,318],{"class":303},[297,1421,321],{"class":307},[297,1423,200],{"class":324},[297,1425,327],{"class":307},[297,1427,330],{"class":307},[297,1429,1430],{"class":299,"line":333},[297,1431,337],{"emptyLinePlaceholder":336},[297,1433,1434,1436,1439,1441,1443,1445],{"class":299,"line":340},[297,1435,344],{"class":343},[297,1437,1438],{"class":311}," catalog ",[297,1440,350],{"class":307},[297,1442,1415],{"class":353},[297,1444,356],{"class":311},[297,1446,359],{"class":307},[297,1448,1449,1451,1453,1455],{"class":299,"line":362},[297,1450,366],{"class":365},[297,1452,369],{"class":307},[297,1454,372],{"class":311},[297,1456,375],{"class":307},[297,1458,1459,1462,1464,1466,1469,1471,1473,1475,1477,1479,1482,1484,1486,1489,1491],{"class":299,"line":378},[297,1460,1461],{"class":365},"  filter",[297,1463,369],{"class":307},[297,1465,308],{"class":307},[297,1467,1468],{"class":365}," type",[297,1470,369],{"class":307},[297,1472,321],{"class":307},[297,1474,484],{"class":324},[297,1476,327],{"class":307},[297,1478,448],{"class":307},[297,1480,1481],{"class":365}," status",[297,1483,369],{"class":307},[297,1485,321],{"class":307},[297,1487,1488],{"class":324},"active",[297,1490,327],{"class":307},[297,1492,513],{"class":307},[297,1494,1495,1497,1499,1501,1503,1505,1507,1509,1511,1513],{"class":299,"line":416},[297,1496,381],{"class":365},[297,1498,369],{"class":307},[297,1500,308],{"class":307},[297,1502,745],{"class":353},[297,1504,369],{"class":307},[297,1506,750],{"class":307},[297,1508,753],{"class":343},[297,1510,756],{"class":353},[297,1512,759],{"class":311},[297,1514,1201],{"class":307},[297,1516,1517,1519,1521],{"class":299,"line":427},[297,1518,419],{"class":307},[297,1520,422],{"class":311},[297,1522,330],{"class":307},[297,1524,1525],{"class":299,"line":432},[297,1526,337],{"emptyLinePlaceholder":336},[297,1528,1529,1531,1533,1535,1537,1539,1541,1543,1545,1548,1551,1553,1556],{"class":299,"line":438},[297,1530,185],{"class":311},[297,1532,246],{"class":307},[297,1534,844],{"class":353},[297,1536,356],{"class":311},[297,1538,356],{"class":307},[297,1540,851],{"class":794},[297,1542,422],{"class":307},[297,1544,753],{"class":343},[297,1546,1547],{"class":353}," renderList",[297,1549,1550],{"class":311},"(s",[297,1552,246],{"class":307},[297,1554,1555],{"class":311},"rows))",[297,1557,330],{"class":307},[175,1559,1560,1563,1564,635,1567,635,1570,642,1573,1576,1577,635,1579,635,1581,635,1583,1586,1587,1590],{},[198,1561,1562],{},"filter"," combines scalar equalities on ",[198,1565,1566],{},"type",[198,1568,1569],{},"parent",[198,1571,1572],{},"status",[198,1574,1575],{},"tenant",". Each row carries the entity's ",[198,1578,285],{},[198,1580,1572],{},[198,1582,1569],{},[198,1584,1585],{},"headSeq",", and the two fast-join offsets above — so a list view already holds everything needed to open any row into a fast-joined timeline. For anything richer than scalar equality, the ",[198,1588,1589],{},"where"," escape hatch takes a positional-parameter clause.",[211,1592,1594],{"id":1593},"react-bindings","React bindings",[175,1596,1597],{},"React bindings live behind a separate entry point, so the framework-agnostic core never imports React. They are lifecycle glue around the same stores.",[288,1599,1603],{"className":1600,"code":1601,"language":1602,"meta":293,"style":293},"language-tsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { useAgentTimeline, useAgentCatalog } from \"@teaspill\u002Ffrontend-sdk\u002Freact\";\n\nfunction AgentView({ streamUrl }: { streamUrl: string }) {\n  const { timeline } = useAgentTimeline(streamUrl, {\n    auth: { token: refreshReadToken },\n    deltas: true,\n  });\n  const { rows } = useAgentCatalog({ filter: { type: \"researcher\" } });\n\n  return (\n    \u003CConversation\n      messages={timeline.messages}\n      streaming={timeline.liveDeltas}\n      drift={timeline.drift}\n    \u002F>\n  );\n}\n","tsx",[198,1604,1605,1632,1636,1667,1691,1708,1719,1728,1773,1777,1785,1793,1810,1825,1840,1845,1852],{"__ignoreMap":293},[297,1606,1607,1609,1611,1614,1616,1619,1621,1623,1625,1628,1630],{"class":299,"line":300},[297,1608,304],{"class":303},[297,1610,308],{"class":307},[297,1612,1613],{"class":311}," useAgentTimeline",[297,1615,448],{"class":307},[297,1617,1618],{"class":311}," useAgentCatalog",[297,1620,315],{"class":307},[297,1622,318],{"class":303},[297,1624,321],{"class":307},[297,1626,1627],{"class":324},"@teaspill\u002Ffrontend-sdk\u002Freact",[297,1629,327],{"class":307},[297,1631,330],{"class":307},[297,1633,1634],{"class":299,"line":333},[297,1635,337],{"emptyLinePlaceholder":336},[297,1637,1638,1640,1643,1646,1649,1652,1654,1656,1658,1662,1665],{"class":299,"line":340},[297,1639,1087],{"class":343},[297,1641,1642],{"class":353}," AgentView",[297,1644,1645],{"class":307},"({",[297,1647,1648],{"class":794}," streamUrl",[297,1650,1651],{"class":307}," }:",[297,1653,308],{"class":307},[297,1655,1648],{"class":365},[297,1657,369],{"class":307},[297,1659,1661],{"class":1660},"sBMFI"," string",[297,1663,1664],{"class":307}," })",[297,1666,734],{"class":307},[297,1668,1669,1672,1674,1677,1679,1681,1683,1685,1687,1689],{"class":299,"line":362},[297,1670,1671],{"class":343},"  const",[297,1673,308],{"class":307},[297,1675,1676],{"class":311}," timeline",[297,1678,315],{"class":307},[297,1680,456],{"class":307},[297,1682,1613],{"class":353},[297,1684,356],{"class":365},[297,1686,726],{"class":311},[297,1688,448],{"class":307},[297,1690,734],{"class":307},[297,1692,1693,1696,1698,1700,1702,1704,1706],{"class":299,"line":378},[297,1694,1695],{"class":365},"    auth",[297,1697,369],{"class":307},[297,1699,308],{"class":307},[297,1701,745],{"class":365},[297,1703,369],{"class":307},[297,1705,756],{"class":311},[297,1707,513],{"class":307},[297,1709,1710,1713,1715,1717],{"class":299,"line":416},[297,1711,1712],{"class":365},"    deltas",[297,1714,369],{"class":307},[297,1716,776],{"class":775},[297,1718,375],{"class":307},[297,1720,1721,1724,1726],{"class":299,"line":427},[297,1722,1723],{"class":307},"  }",[297,1725,422],{"class":365},[297,1727,330],{"class":307},[297,1729,1730,1732,1734,1737,1739,1741,1743,1745,1748,1751,1753,1755,1757,1759,1761,1763,1765,1767,1769,1771],{"class":299,"line":432},[297,1731,1671],{"class":343},[297,1733,308],{"class":307},[297,1735,1736],{"class":311}," rows",[297,1738,315],{"class":307},[297,1740,456],{"class":307},[297,1742,1618],{"class":353},[297,1744,356],{"class":365},[297,1746,1747],{"class":307},"{",[297,1749,1750],{"class":365}," filter",[297,1752,369],{"class":307},[297,1754,308],{"class":307},[297,1756,1468],{"class":365},[297,1758,369],{"class":307},[297,1760,321],{"class":307},[297,1762,484],{"class":324},[297,1764,327],{"class":307},[297,1766,315],{"class":307},[297,1768,315],{"class":307},[297,1770,422],{"class":365},[297,1772,330],{"class":307},[297,1774,1775],{"class":299,"line":438},[297,1776,337],{"emptyLinePlaceholder":336},[297,1778,1779,1782],{"class":299,"line":474},[297,1780,1781],{"class":303},"  return",[297,1783,1784],{"class":365}," (\n",[297,1786,1787,1790],{"class":299,"line":491},[297,1788,1789],{"class":307},"    \u003C",[297,1791,1792],{"class":1660},"Conversation\n",[297,1794,1795,1798,1801,1803,1805,1807],{"class":299,"line":516},[297,1796,1797],{"class":343},"      messages",[297,1799,1800],{"class":307},"={",[297,1802,181],{"class":311},[297,1804,246],{"class":307},[297,1806,661],{"class":311},[297,1808,1809],{"class":307},"}\n",[297,1811,1812,1815,1817,1819,1821,1823],{"class":299,"line":525},[297,1813,1814],{"class":343},"      streaming",[297,1816,1800],{"class":307},[297,1818,181],{"class":311},[297,1820,246],{"class":307},[297,1822,888],{"class":311},[297,1824,1809],{"class":307},[297,1826,1827,1830,1832,1834,1836,1838],{"class":299,"line":530},[297,1828,1829],{"class":343},"      drift",[297,1831,1800],{"class":307},[297,1833,181],{"class":311},[297,1835,246],{"class":307},[297,1837,1375],{"class":311},[297,1839,1809],{"class":307},[297,1841,1842],{"class":299,"line":536},[297,1843,1844],{"class":307},"    \u002F>\n",[297,1846,1847,1850],{"class":299,"line":574},[297,1848,1849],{"class":365},"  )",[297,1851,330],{"class":307},[297,1853,1854],{"class":299,"line":579},[297,1855,1809],{"class":307},[175,1857,1858,1859,635,1861,635,1864,1867,1868,1871,1872,1875],{},"Each hook subscribes on mount and tears down on unmount. The subscription restarts when the stream URL or the structural options (",[198,1860,1141],{},[198,1862,1863],{},"deltas",[198,1865,1866],{},"live",") change; callbacks and auth are read fresh each render without restarting. Pass ",[198,1869,1870],{},"null"," or ",[198,1873,1874],{},"undefined"," for the URL or options to render without subscribing — useful while the stream URL is still loading.",[211,1877,1879],{"id":1878},"server-side-rendering","Server-side rendering",[175,1881,1882,1883,1886,1887,1889],{},"The reducer is pure — no I\u002FO, no clock — so it runs on a server as readily as in a browser. Fold a batch of events into a ",[198,1884,1885],{},"TimelineState"," to render an initial HTML view, then hydrate the client with a live ",[198,1888,241],{}," that continues from the snapshot's offset. Keep read tokens on the server for the SSR pass and mint a fresh, short-lived one for the browser to take over.",[211,1891,1893],{"id":1892},"next-steps","Next steps",[175,1895,1896,1897,1899,1900,246],{},"You can now drive agents and stream them into a UI. To stand up the deployment behind the gateway, see ",[179,1898,113],{"href":114},"; for the read-token flow in full, see ",[179,1901,118],{"href":119},[1903,1904,1905],"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 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 .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 .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}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":293,"searchDepth":300,"depth":333,"links":1907},[1908,1909,1910,1911,1912,1913,1916,1917,1918,1919],{"id":213,"depth":333,"text":214},{"id":275,"depth":333,"text":276},{"id":652,"depth":333,"text":653},{"id":938,"depth":333,"text":939},{"id":1100,"depth":333,"text":1101},{"id":1299,"depth":333,"text":1300,"children":1914},[1915],{"id":1356,"depth":340,"text":1357},{"id":1394,"depth":333,"text":1395},{"id":1593,"depth":333,"text":1594},{"id":1878,"depth":333,"text":1879},{"id":1892,"depth":333,"text":1893},"Spawn agents, read and live-follow their timelines, subscribe to the catalog, and mint browser read tokens with the frontend SDK.","md",null,{},{"icon":105},{"title":102,"description":1920},"PploOMyPdrZL2k9IzqrvIqoijj8VeefDt09xc9blEzM",[1928,1930],{"title":98,"path":99,"stem":100,"description":1929,"icon":93,"children":-1},"Define an agent with the Agents SDK — schemas, harness, tools, the onWake hook, state revisions, and serving it to the gateway.",{"title":113,"path":114,"stem":115,"description":1931,"icon":116,"children":-1},"Run the teaspill stack yourself — the five infrastructure services, your two deployed planes, and the one networking rule that bites everyone.",1784473426322]