TUTORIALS 9 min read

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.

By EgoistAI ·
Schema Migrations for Long-Lived AI Agents

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:

ArtifactHidden compatibility risk
memory recordold scope or trust meaning
plan checkpointremoved step type
tool callrenamed field or changed unit
approvalauthority no longer valid
retrieval chunkstale embedding or parser version
event lognew code interprets old event differently
model outputunversioned 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:

  1. write only the newest schema;
  2. read the newest plus a bounded set of older versions;
  3. transform old records through pure migration functions;
  4. backfill asynchronously;
  5. 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.

Share this article

> 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

Tags

AI agentsschema migrationsstate managementtool callingdatabasesproduction AI

> Stay in the loop

Weekly AI tools & insights.