The first state store is always one table called sessions with a JSON blob in it. It works, right up until someone asks how long a customer's uploaded invoice is retained, and the honest answer is "the same as everything else, because it is all in the blob".

Agent systems store at least four distinct things. They are routinely treated as one because they arrive through the same code path.

What you are actually storing

State typeTypical lifetimeSafe to reuse on resume?Deletion driven by
Conversation stateThe sessionYes, it is the transcriptUser or session expiry
Task stateThe runOnly the committed stepsRun completion plus a debug window
Durable memoryIndefiniteYes, but re-verify factsExplicit user action or policy
ArtifactsLonger than the runRead yes, rewrite noWorkspace lifecycle plus retention rules

Once the columns differ, the argument for a single ungoverned store disappears. A transcript that lives as long as a session and a customer document that must be purgeable within thirty days do not belong in the same bucket just because the same request created them.

Resume is where the mixing hurts

The interesting question is what a resumed run is allowed to trust.

A run that dies mid-flight and restarts will happily reload its cached plan, its earlier tool results and its intermediate reasoning. Some of that is still true. The plan probably is. A tool result captured ninety seconds before a timeout probably is not, because the world moved while the job was dead.

So mark state as durable or ephemeral at write time rather than deciding at read time. Committed steps and their idempotency keys survive a resume. Cached reads and half-finished intermediates get discarded and re-fetched. Getting this wrong is quiet: the run completes, the output looks plausible, and it was computed against a snapshot nobody realises is stale.

Artifacts need provenance, not just a bucket

Files, plans, generated reports and exported data outlive the run that produced them, which means someone will eventually hold one and need to know where it came from.

Store every artifact with the run ID that created it, the identity the run acted under, the workspace it belongs to, and the inputs it derived from. That is four fields, and they turn an unexplained file into something you can audit, attribute, expire or delete on request.

An artifact you cannot trace back to a run is a liability you are storing on purpose. The hard part is deciding, per state type, how long it lives and who may reach it, and that has to happen before the traffic does.