[{"data":1,"prerenderedAt":663},["ShallowReactive",2],{"navigation":3,"\u002Fguides\u002Foperations\u002Fbackup-restore":169,"\u002Fguides\u002Foperations\u002Fbackup-restore-surround":658},[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":123,"body":171,"description":651,"extension":652,"links":653,"meta":654,"navigation":655,"path":124,"seo":656,"stem":125,"__hash__":657},"docs\u002F3.guides\u002F2.operations\u002F3.backup-restore.md",{"type":172,"value":173,"toc":639},"minimark",[174,183,188,274,281,285,291,314,321,327,339,375,379,385,419,453,458,462,465,519,524,534,549,559,577,581,588,595,599,606,610,616,622,626,635],[175,176,177,178,182],"p",{},"teaspill keeps its state in three stores, and they hold different kinds of truth. Backing up is straightforward; the part worth understanding is what happens when you restore ",[179,180,181],"em",{},"some"," of them and not others — because the answer is deliberate, and knowing it lets you pick the right trade-off under pressure.",[184,185,187],"h2",{"id":186},"what-each-store-owns","What each store owns",[189,190,191,207],"table",{},[192,193,194],"thead",{},[195,196,197,201,204],"tr",{},[198,199,200],"th",{},"Store",[198,202,203],{},"Holds",[198,205,206],{},"Durability role",[208,209,210,236,251],"tbody",{},[195,211,212,216,233],{},[213,214,215],"td",{},"Postgres",[213,217,218,219,223,224,228,229,232],{},"The ",[220,221,222],"a",{"href":61},"catalog",": the registry row for every entity, plus the ",[225,226,227],"strong",{},"archive of record"," — the complete stored state of every agent that has ever ",[220,230,231],{"href":81},"archived",".",[213,234,235],{},"Archival by design. This is the durable source of truth for archived agents.",[195,237,238,241,248],{},[213,239,240],{},"durable-streams",[213,242,243,244,247],{},"The history store: every ",[220,245,246],{"href":56},"timeline"," and its live delta and workspace-output streams. Append-only, never read to decide what an agent does next.",[213,249,250],{},"The readable record. Losing it costs history, not control.",[195,252,253,256,271],{},[213,254,255],{},"Restate",[213,257,218,258,261,262,265,266,270],{},[225,259,260],{},"live working state"," of every ",[179,263,264],{},"active"," agent — its in-flight conversation, its ",[267,268,269],"code",{},"seq"," counter, its pending work. This is control-flow state, not an archive.",[213,272,273],{},"Deliberately a working cache, not a durable archive.",[175,275,276,277,280],{},"The asymmetry in that last column drives everything below: ",[225,278,279],{},"Postgres is archival by design; Restate is deliberately not."," An archived agent's full state lives in Postgres, so losing Restate is survivable for it. An agent that was still active kept its working state only in Restate — so losing Restate loses that agent's in-flight state, and there is nowhere else to recover it from. That is the intended cost model, not a gap in it.",[184,282,284],{"id":283},"taking-a-backup","Taking a backup",[175,286,287,290],{},[267,288,289],{},"scripts\u002Fbackup.sh"," captures all three stores from a running stack: a Postgres dump plus filesystem snapshots of the history and coordinator volumes.",[292,293,298],"pre",{"className":294,"code":295,"language":296,"meta":297,"style":297},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Full backup of the running stack into a timestamped directory:\nscripts\u002Fbackup.sh -d .\u002Fbackups\u002F2026-07-19\n","sh","",[267,299,300,308],{"__ignoreMap":297},[301,302,305],"span",{"class":303,"line":304},"line",1,[301,306,307],{},"# Full backup of the running stack into a timestamped directory:\n",[301,309,311],{"class":303,"line":310},2,[301,312,313],{},"scripts\u002Fbackup.sh -d .\u002Fbackups\u002F2026-07-19\n",[175,315,316,317,320],{},"By default the backup is ",[225,318,319],{},"quiesced",". Postgres is dumped live (its dump is always internally consistent), then the coordinator and history-store containers are briefly stopped while their volumes are copied, then restarted. The pause is typically seconds; wakes that arrive during it are retried by their callers, not lost. The result is a true point-in-time backup — all three stores reflect the same instant.",[175,322,218,323,326],{},[267,324,325],{},"--live"," flag skips the pause for zero downtime, at a cost:",[328,329,330],"caution",{},[175,331,332,334,335,338],{},[267,333,325],{}," copies the coordinator and history-store volumes while they are being written. The three stores' copies then land at slightly different instants — a ",[225,336,337],{},"torn backup",". The catalog can end up ahead of or behind what the history copy actually holds, and the coordinator's own on-disk state may be caught mid-write. The catalog-versus-history skew is the kind the running stack repairs itself once restored; the coordinator's internal consistency is not something it can repair after the fact. Use quiesced mode for anything you would actually restore from.",[175,340,341,342,345,346,349,350,353,354,345,357,360,361,345,364,367,368,370,371,374],{},"Useful flags: ",[267,343,344],{},"-d","\u002F",[267,347,348],{},"--dir"," sets the output directory (defaults to a timestamped directory under ",[267,351,352],{},"backups\u002F","), ",[267,355,356],{},"-p",[267,358,359],{},"--project"," and ",[267,362,363],{},"-f",[267,365,366],{},"--file"," override the Compose project name and file, and ",[267,369,325],{}," selects the torn-backup mode. Each backup directory gets a ",[267,372,373],{},"MANIFEST.txt"," the restore script reads.",[184,376,378],{"id":377},"restoring","Restoring",[175,380,381,384],{},[267,382,383],{},"scripts\u002Frestore.sh"," restores from a backup directory. It can restore all three stores or any subset — and the subset you pick is exactly what determines whether recovery is clean.",[292,386,388],{"className":294,"code":387,"language":296,"meta":297,"style":297},"# Full, clean recovery:\nscripts\u002Frestore.sh -d .\u002Fbackups\u002F2026-07-19 --all\n\n# A subset (read the matrix below before choosing this):\nscripts\u002Frestore.sh -d .\u002Fbackups\u002F2026-07-19 --postgres --streams\n",[267,389,390,395,400,407,413],{"__ignoreMap":297},[301,391,392],{"class":303,"line":304},[301,393,394],{},"# Full, clean recovery:\n",[301,396,397],{"class":303,"line":310},[301,398,399],{},"scripts\u002Frestore.sh -d .\u002Fbackups\u002F2026-07-19 --all\n",[301,401,403],{"class":303,"line":402},3,[301,404,406],{"emptyLinePlaceholder":405},true,"\n",[301,408,410],{"class":303,"line":409},4,[301,411,412],{},"# A subset (read the matrix below before choosing this):\n",[301,414,416],{"class":303,"line":415},5,[301,417,418],{},"scripts\u002Frestore.sh -d .\u002Fbackups\u002F2026-07-19 --postgres --streams\n",[175,420,421,422,425,426,425,429,432,433,436,437,345,440,443,444,345,446,360,448,345,450,452],{},"Select stores with ",[267,423,424],{},"--postgres",", ",[267,427,428],{},"--streams",[267,430,431],{},"--restate",", or ",[267,434,435],{},"--all"," (the default when you name none). ",[267,438,439],{},"-y",[267,441,442],{},"--yes"," skips the confirmation prompt for scripted use; ",[267,445,356],{},[267,447,359],{},[267,449,363],{},[267,451,366],{}," mirror the backup script.",[328,454,455],{},[175,456,457],{},"Restore is destructive to the stores it targets: it drops and recreates the catalog's objects and wholesale-overwrites the history and coordinator volumes. There is no undo — take a fresh backup first if you might want to roll back the restore itself.",[184,459,461],{"id":460},"what-combinations-restore-cleanly","What combinations restore cleanly",[175,463,464],{},"This is the load-bearing part. Restoring fewer than all three stores is supported, but each combination has a defined outcome.",[189,466,467,477],{},[192,468,469],{},[195,470,471,474],{},[198,472,473],{},"Restored",[198,475,476],{},"Outcome",[208,478,479,489,499,509],{},[195,480,481,486],{},[213,482,483],{},[225,484,485],{},"All three",[213,487,488],{},"Clean full recovery. The stack comes back exactly as it was.",[195,490,491,496],{},[213,492,493],{},[225,494,495],{},"Catalog + history, no coordinator",[213,497,498],{},"Archived agents fully recover; agents that were still active are lost — loudly.",[195,500,501,506],{},[213,502,503],{},[225,504,505],{},"Coordinator + catalog, no history",[213,507,508],{},"Everything keeps running; the timeline shows a marked gap where history is missing.",[195,510,511,516],{},[213,512,513],{},[225,514,515],{},"Coordinator only, or history only",[213,517,518],{},"Don't. Restore the catalog alongside either.",[520,521,523],"h3",{"id":522},"catalog-history-without-the-coordinator","Catalog + history, without the coordinator",[175,525,526,527,529,530,533],{},"Every agent that had ",[225,528,231],{}," at or before backup time recovers completely. Its full state lives in the catalog as the archive of record, so a message to it after restore ",[220,531,532],{"href":81},"resurrects"," it — same identity, same timeline, transparent to the caller.",[175,535,536,537,540,541,544,545,548],{},"Every agent that was ",[225,538,539],{},"active or idle but never archived"," is lost. Its working state existed only in the coordinator, which you did not restore. Crucially, this failure is ",[179,542,543],{},"loud",", not silent: a message to such an agent finds no live state and no archived state to recover from, and the send ",[225,546,547],{},"fails visibly"," — the sender sees an error rather than a message quietly vanishing. The agent's catalog row still lists it and its history is still readable, but it cannot be woken again.",[175,550,551,552,558],{},"If that class of loss is unacceptable for your deployment, you have two levers: always restore the coordinator alongside the catalog and history, or shorten the idle-archive window (set ",[220,553,555],{"href":554},"\u002Freference\u002Fconfiguration#agent-loop-and-executor",[267,556,557],{},"TEASPILL_IDLE_ARCHIVE_MS"," below the 30-minute default) so that less state is ever only-in-the-coordinator at any moment — the more aggressively agents archive, the more of them are safe in the catalog.",[560,561,562],"note",{},[175,563,564,565,568,569,572,573,576],{},"The coordinator also holds your ",[225,566,567],{},"deployment registrations"," — which agent-loop service serves which agent type. Any restore that leaves the coordinator empty (this combination, or a fresh coordinator volume) loses them too, so no spawn or send can route until you ",[225,570,571],{},"re-register your deployments"," — re-run ",[267,574,575],{},"teaspill dev"," or whatever registration step your deployment uses. A full restore brings the registrations back with the rest of the coordinator's state, so this only applies when you deliberately skip or reset it.",[520,578,580],{"id":579},"coordinator-catalog-without-history","Coordinator + catalog, without history",[175,582,583,584,587],{},"The inverse. Live working state and the registry come back, but the history store does not. ",[225,585,586],{},"Nothing about control flow breaks"," — history is never read to decide what an agent does, so agents keep running exactly as before. What is lost is the readable record for the affected window: a UI joining or replaying an affected timeline hits a gap.",[175,589,590,591,594],{},"teaspill handles this honestly rather than pretending. When the stack detects that history is missing where the catalog says it should exist, it writes a recovery snapshot that marks a ",[225,592,593],{},"history hole"," — a deliberate, labeled gap that says \"history is missing here\" instead of silently presenting an incomplete timeline. Clients treat it as a sanctioned jump and resume from there; your UI can render \"history gap\" at that point. Control flow survives unmodified; the timeline carries a documented hole.",[520,596,598],{"id":597},"any-other-subset","Any other subset",[175,600,601,602,605],{},"Restoring the coordinator or the history store ",[179,603,604],{},"without"," the catalog leaves you with no registry: nothing can be listed or woken. Restore the catalog alongside either for anything operational. The restore script does not block these combinations — it prints a warning and proceeds — but treat them as recovery of raw data, not a working deployment.",[184,607,609],{"id":608},"scheduling-backups","Scheduling backups",[175,611,612,613,615],{},"teaspill does not ship a scheduler — ",[267,614,289],{}," is a primitive you invoke. Wiring it to cron (or your platform's scheduled-job mechanism) is a deployment decision, because backup frequency and retention depend on how much in-flight work you are willing to lose and where you store the output. A quiesced backup on a cron schedule, shipped off-host, is a reasonable default.",[617,618,619],"tip",{},[175,620,621],{},"A backup you have never restored is a hypothesis, not a backup. Periodically restore into a throwaway stack and confirm the agents you care about come back — especially if you rely on the partial-restore behaviors above.",[184,623,625],{"id":624},"next-steps","Next steps",[175,627,628,629,631,632,634],{},"Backups protect a running deployment — see ",[220,630,113],{"href":114}," for the stack they run against, and ",[220,633,80],{"href":81}," for how archival (the thing that makes agents safe to lose the coordinator for) actually works.",[636,637,638],"style",{},"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);}",{"title":297,"searchDepth":304,"depth":310,"links":640},[641,642,643,644,649,650],{"id":186,"depth":310,"text":187},{"id":283,"depth":310,"text":284},{"id":377,"depth":310,"text":378},{"id":460,"depth":310,"text":461,"children":645},[646,647,648],{"id":522,"depth":402,"text":523},{"id":579,"depth":402,"text":580},{"id":597,"depth":402,"text":598},{"id":608,"depth":310,"text":609},{"id":624,"depth":310,"text":625},"What each store holds, how to capture a consistent backup, and exactly which restore combinations come back cleanly versus lossily — and why.","md",null,{},{"icon":126},{"title":123,"description":651},"sc3oTuYdeMNQblBq_Wvy9meroeD06gnNoO8NJ73fs_4",[659,661],{"title":118,"path":119,"stem":120,"description":660,"icon":121,"children":-1},"The server-side API key that authorizes everything, the optional read token that lets browsers read streams directly, and why authorization is yours to own.",{"title":134,"path":135,"stem":136,"description":662,"icon":137,"children":-1},"The canonical timeline event — envelope, the fifteen event types, token deltas, and the helpers exported from @teaspill\u002Fschema.",1784473426626]