Schema Migrations for Long-Lived AI Agents
Agent state survives longer than prompts. Version memories, plans, tool calls, and approvals so tomorrow's code can safely read yesterday's decisions.
Your agent remembers a task for three weeks. Your deployment remembers it for three seconds.
That mismatch is where ugly failures live. Schema migrations for long-lived AI agents must handle old memories, plans, approvals, tool calls, and checkpoints after the code that created them is gone. If you version only the database table, you have missed half the system.
Which Schemas Are Actually Persistent?
Map every artifact that can outlive one request:
| Artifact | Hidden compatibility risk |
|---|---|
| memory record | old scope or trust meaning |
| plan checkpoint | removed step type |
| tool call | renamed field or changed unit |
| approval | authority no longer valid |
| retrieval chunk | stale embedding or parser version |
| event log | new code interprets old event differently |
| model output | unversioned JSON shape |
Give each artifact an explicit schema_version. Do not infer version from timestamps or application releases. Hotfixes and backfills destroy that assumption.
Should You Migrate on Read or in Place?
Both patterns work, and both can hurt.
An in-place migration makes the active database consistent, simplifies queries, and fails visibly during deployment. It can also lock large tables, destroy original evidence, and make rollback hard.
Migration on read preserves old records and supports gradual rollout. It adds runtime complexity and can leave rarely accessed records broken for months.
The practical pattern is hybrid:
- write only the newest schema;
- read the newest plus a bounded set of older versions;
- transform old records through pure migration functions;
- backfill asynchronously;
- remove compatibility code only after measurement shows zero old reads.
How Do You Write a Safe Migrator?
Make every step deterministic, idempotent, and observable.
type MemoryV1 = { schema_version: 1; text: string; user_id: string };
type MemoryV2 = {
schema_version: 2;
content: string;
owner: { type: "user"; id: string };
scope: "global";
};
function v1ToV2(old: MemoryV1): MemoryV2 {
return {
schema_version: 2,
content: old.text,
owner: { type: "user", id: old.user_id },
scope: "global"
};
}
That scope: "global" default is a policy decision, not plumbing. If old records lack enough evidence, use an unknown state and require safer behavior. Never invent authority during migration.
Hash before and after records, count transforms by version, and keep a dead-letter path for items that cannot be upgraded automatically.
How Do Tool Schemas Evolve?
Tool changes are more dangerous than ordinary API changes because a model plans from the description. Renaming recipient to to can break stored plans even if the new tool works perfectly.
Keep versioned tool contracts:
{
"tool": "invoice.send",
"version": 3,
"arguments": {
"invoice_id": "inv_42",
"destination": {"type": "email", "value": "redacted"}
}
}
At execution time, validate that a stored plan’s tool version is still supported. If not, re-plan from current intent and current authorization. Do not silently map a destructive call when semantics changed.
How Do You Preserve Approval Meaning?
Approval is bound to a specific action, scope, destination, amount, and time. A migration that broadens any of those fields must invalidate the approval.
Store a digest of the human-visible proposal with the approval record. After migration, recompute the digest. If it differs, ask again. This is annoying and correct.
Permissions also expire independently of schema version. Revalidate current authority before resuming a task from an old checkpoint.
How Do You Roll Out Without Breaking Live Tasks?
Use dual readers before dual writers. Deploy code that understands old and new formats, then switch writes, then backfill. Add metrics for reads by schema version, migration failures, resumed-task failures, and approval invalidations.
Test with production-shaped snapshots that have been scrubbed of sensitive data. Include incomplete plans, duplicated events, missing optional fields, and records created during past incidents. Happy-path fixtures are useless here.
Run a shadow migrator first. It should transform and validate without committing. Compare counts and semantic invariants: same owner, same scope, same pending external action, and no new permission.
When Is the Migration Finished?
Not when the SQL command exits. It is finished when:
- all active readers understand the new version;
- new writes use only the new version;
- backfill errors are resolved;
- no old-version reads appear through the retention window;
- paused tasks resume safely;
- rollback has been tested or the migration is proven irreversible and accepted.
Long-lived agents turn application state into a durable behavioral contract. Version that contract explicitly. Migrate conservatively. When old data is ambiguous, reduce authority instead of guessing.
> Want more like this?
Get the best AI insights delivered weekly.
By subscribing, you agree to our Privacy Policy. You can unsubscribe at any time.
> Related Articles
pgvector Can Return 4 of Your 10 Matches—Where Did the Rest Go?
A filtered vector search can quietly starve your AI app of evidence. pgvector has a fix, but builders need to measure recall and latency before trusting it.
Agent Memory Consolidation Scheduling: When to Merge, Summarize or Forget
Your agent doesn't need more memory — it needs a maintenance schedule. Here's how to build merge, summarize, and decay policies that keep long-term agents sharp instead of senile.
LLM Output Schema Evolution: Migrating Producers and Consumers Without a Flag Day
Your JSON schema will change. Here's how to evolve LLM output contracts safely — with dual readers, shadow validation, and staged rollouts instead of a risky big-bang cutover.
Most Read
- 1 Kimi K3.1 Pro: China's Open-Weight Model Just Caught the Frontier
- 2 OpenAI Is Buying the Bottleneck: Can Orchestra Bio Cut a 15-Year Drug Timeline?
- 3 1,068 Tokens Per Second: Can Mercury 3 Change How LLMs Generate Text?
- 4 Same Price, Better Coding: How Good Is DeepSeek V4.1 Flash 1017?
- 5 Used OpenCode? Should You Rotate Your API Key After the Console Breach?
Latest News
- Claude Code Left Secrets in 1,122 GitHub Files—Check This Setting
- Gemini Omni 1.2 Flash Makes 15-Second Video Cheaper—Then Comes the Edit
- GPT-6 Cyber Can Build Exploits—But Builders Face a Different Test
- 1,122 GitHub Files Exposed Secrets—What Did “Don't Ask Again” Save?
- Gemini Omni 1.2 Flash Offers $1.05 Clips—What Does That Buy You?
- GPT-6 Cyber Hits 48.5% on ExploitGym—Who Gets the Keys?
Tags
> Stay in the loop
Weekly AI tools & insights.