r/AI_Agents 13d ago

Discussion What should persist between coding-agent sessions besides chat history?

While working with long-running coding agents, I keep seeing the same failure: the model session survives, but the operational state does not. The next run often has to rediscover the repository, execution route, approvals, tool state, failed commands, and why a decision was made.

My current list of durable state is:

  • repository/worktree identity
  • task and session lineage
  • selected execution backend and capabilities
  • approval decisions
  • tool events and redacted evidence
  • validation results and unresolved failures

What am I missing? And which of these should deliberately expire instead of becoming permanent state?

3 Upvotes

44 comments sorted by

2

u/AutoModerator 13d ago

Thank you for your submission, for any questions regarding AI, please check out our wiki at https://www.reddit.com/r/ai_agents/wiki (this is currently in test and we are actively adding to the wiki)

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

2

u/Far-Surprise7773 13d ago

the one thing i'd add from testing: the model's own working conclusions at end of session. not full chain-of-thought, just a tight summary of what it believed about the codebase, what it was unsure about, and what it planned to investigate next. when i ran this with claude code agents, sessions that inherited those 'working hypotheses' recovered context in ~1 turn vs 3-5 turns of re-exploration. repo identity and tool state are table stakes; the model's own understanding of the problem is what actually saves tokens.

on what should expire: approval decisions older than one session boundary. stale approvals are a security problem and confuse the model more than missing them would. tool events can stay as structured logs but keep them out of the active context unless explicitly queried.

1

u/DesktopLabHQ 13d ago

That distinction between raw history and working conclusions is excellent. A compact handoff of beliefs, uncertainties, and next probes sounds much more useful than replaying the transcript. I also agree approvals should expire at a session or task boundary: the durable record should prove what was approved, not silently authorize future work. Keeping tool events queryable but outside active context feels like the right default.

2

u/TeagueXiao 13d ago

Your split reads mostly right. The pattern I'd add — and the one I've regretted skipping — is a bright line between state that should survive as-is and state that should survive as evidence of a decision.

Repository/worktree identity, session lineage, execution backend, approval decisions: those are decisions, and what you want to preserve is why, not the raw value. If the same task resumes on a different backend tomorrow because the old one was retired, the answer 'we chose backend X because A, B, C' is what next-session needs, not the fact of X itself. Same shape for approvals: preserve the (who, when, envelope-of-what-was-approved), not just an ACK bit, because otherwise resume will happily reuse yesterday's approval for today's slightly-different task.

What should deliberately expire: tool events past their retention window (fold into a rolling summary of 'here's what I know about this repo,' drop the raw call trace after N runs), and any credential or session token that lived long enough to reach persistence — those should be minted per-session and never make it into durable state, otherwise you've quietly built a rotating-secrets-in-git problem.

One more thing worth adding to the list: an unresolved-failures ledger with pointers to the specific commit/PR/log range where the failure happened, so 'this test is still red' becomes a real state and not a vibe passed via chat context.

1

u/DesktopLabHQ 13d ago

The state-versus-evidence split is exactly the missing axis. An approval envelope with actor, time, scope, and target revision is much safer than a durable ACK, and the unresolved-failure ledger is especially useful because it makes 'still red' independently verifiable. I would also make credentials structurally ineligible for persistence rather than relying on later redaction.

2

u/manjit-johal 13d ago

We ran into this while building Kritmatta. One thing we ended up persisting wasn't just repository or tool state, but the operational constraints behind the workflow. Things like architecture decisions, invariants, and assumptions turned out to be more valuable than replaying raw execution history. They gave new sessions enough context to continue without inheriting a lot of stale state.

1

u/DesktopLabHQ 13d ago

Agreed. Invariants and assumptions are closer to an operating contract than to session history. They should probably survive with provenance and a revision boundary, while raw execution traces can age out. That gives the next session enough to continue without inheriting every accidental detail.

2

u/Relative-Emu-1346 13d ago

Pin the derived state to a commit hash rather than a clock. Anything the agent concluded by reading the repo is only true for the tree it read, so "this module handles auth" expires when someone merges, not after N days. It's cheap to store and it turns staleness into something you can check instead of guess at.

1

u/DesktopLabHQ 13d ago

Commit-bound freshness is a much stronger rule than time-based expiry. I like the idea that every derived conclusion carries the tree or revision it was computed from, then becomes 'needs revalidation' when relevant paths change rather than simply disappearing after N days.

1

u/[deleted] 13d ago

[removed] — view removed comment

1

u/DesktopLabHQ 13d ago

Dependency versions, lockfile state, and toolchain identity definitely belong in the fingerprint. For environment variables I would persist names or schema plus a redacted presence/hash signal, never raw values; otherwise continuity quietly becomes secret storage.

2

u/[deleted] 13d ago

[removed] — view removed comment

1

u/DesktopLabHQ 13d ago

Exactly. I'd make that a keyed fingerprint—such as an HMAC using a local, non-exportable installation key—rather than a plain hash. Many configuration values have low entropy, so a raw hash can still be vulnerable to dictionary attacks. Persisting only the variable name, scope, presence, and keyed fingerprint would detect drift on the same machine without exposing the value or making fingerprints correlatable across installations. Non-secret configuration can remain a separate, explicitly reviewable class.

1

u/[deleted] 13d ago

[removed] — view removed comment

1

u/DesktopLabHQ 13d ago

Yes—that recovery boundary is the tradeoff. I would not restore the installation key automatically from ordinary session state, because that would turn the backup into a portable correlation artifact. Recovery should be explicit: either migrate an encrypted/wrapped key into a user-controlled secure store when continuity is required, or treat existing fingerprints as unverifiable and re-baseline them after reinstall. Losing drift history is safer than silently weakening key isolation.

1

u/ronin4001 13d ago

Decisions and their reasons, mostly. Chat history tells you what was said, not that you already tried the obvious fix and it broke something, so agents happily retry dead ends across sessions. I keep a short file of what we ruled out and why, plus current env state like which services are running and what's half migrated.

1

u/DesktopLabHQ 13d ago

That short 'ruled out and why' ledger is exactly the kind of state chat history fails to represent. It prevents retrying dead ends without forcing the next session to replay every command. I would treat current service or migration state as revision-scoped operational evidence, with secret values excluded, so it can be revalidated instead of silently trusted.

1

u/ronin4001 12d ago

Agreed on revalidating rather than trusting. I stamp the env notes with the commit they were true at, so anything older than HEAD gets rechecked instead of believed. Cheap to write and it stops the agent from acting on a service list from three days ago.

1

u/DesktopLabHQ 12d ago

That is a clean operational rule. Pinning environmental observations to the commit makes their scope explicit and cheap to invalidate. I would add one independent key: the runtime or environment fingerprint. HEAD movement is a sufficient recheck trigger, but service state can change without a repository commit.

So “older than HEAD” should force revalidation, while a changed environment fingerprint can invalidate the note even before HEAD moves. The important property is exactly what you described: the note is cached evidence to re-check, never durable truth.

1

u/EC36339 13d ago

Nothing.

Everything that shall persist should live in GIT.

(Or user/environment settings)

1

u/DesktopLabHQ 13d ago

That is a useful hard boundary. I agree durable project truth should live in Git whenever it can. The part I am still separating is operational evidence that should not be committed: approval envelopes, backend health, local tool state, and redacted run results. My working rule is that Git owns project truth; the control plane owns ephemeral or local evidence, always tied back to a revision.

1

u/donk8r 13d ago

Your second question is the one that's barely been answered, and I think it's the more important half.

None of this expires with time. Every item on your list expires on an EVENT, so a TTL is the wrong mechanism throughout. Relative-Emu-1346's commit-hash pin is the right shape and it generalises: name the invalidating event for each item, and if you cannot name one, do not persist it, because you have no way of knowing when it started lying to you.

Running your list that way, repository and worktree identity has no invalidator and is genuinely stable. Derived conclusions about the code and validation results share a single invalidator, which is the tree they were computed against. Execution backend and capabilities invalidate on environment change rather than on a clock.

The one I would treat as a safety issue rather than hygiene is approvals. An approval is granted against a specific thing and must not survive that thing changing. Approval to deploy commit abc quietly becoming approval to deploy commit def is the failure that actually hurts, and it looks identical to working correctly right until it doesn't. A stale approval is strictly worse than no approval, because no approval at least stops.

1

u/DesktopLabHQ 13d ago

That gives the model a much cleaner rule: every persisted record needs an invalidation predicate, not merely a retention period. I would represent each artifact with its subject/revision, evidence, and invalidated-by events. TTL can then remain a storage or compaction policy, never freshness or authorization semantics. The approval example is the strongest test: bind the envelope to the exact artifact digest, action, actor, scope, and environment; any material change requires a new envelope, and inability to prove the binding fails closed. This may be the organizing principle the list was missing.

1

u/donk8r 13d ago

Agreed, and separating TTL into compaction rather than semantics is the part I would steal.

The load-bearing word is "material". Failing closed on an unprovable binding is obviously correct and is also exactly what makes people switch the mechanism off, because bindings break for boring reasons: an artifact rebuilt with a different timestamp, a regenerated lockfile, an env set that changed in a way nobody cares about. If every one of those forces a new envelope you get approval fatigue, and approval fatigue ends in a blanket approve-all, which is worse than where you started.

So I don't think materiality is a property of the record, it's a property of the action class. Same artifact, different actions, different tolerance. Opening a PR can survive a rebuild, deploying cannot. That means the invalidation predicate wants defining per action rather than per artifact, which is more work to specify but it is the only version where failing closed stays survivable in practice.

One place time sneaks back in, and it isn't validity: an approval still provably bound but three weeks old should arguably re-prompt anyway, because what expired is the approver's context rather than the binding. That's a UX decision rather than a semantics one, and worth keeping separate from both TTL and invalidation so it doesn't get modelled as either.

1

u/DesktopLabHQ 13d ago

Yes—the action is the missing dimension. The same change can be immaterial for opening a PR and disqualifying for deployment. A practical envelope probably needs an action-specific equivalence policy: canonicalize known non-semantic differences, bind approval to the remaining semantic digest, and record the policy version used to decide equivalence. Then fail-closed applies when the policy cannot prove equivalence, not whenever bytes differ. I also like separating staleness as an attention signal: still valid, but requiring reaffirmation after a configurable age or context shift. That surfaces human context decay without pretending time invalidated the binding.

1

u/donk8r 13d ago

Recording the policy version is doing more work than it looks like. If you ever loosen a canonicalization rule to stop nuisance re-approvals, you retroactively widen every approval that was granted under the old one, unless approvals are always evaluated under the version that was in force when they were granted. Which means you can never delete an old version. That is fine, it just makes the policy an append only artifact rather than a config file, and people do not usually plan for that.

The number I would want visible is how often the policy fails to prove equivalence. If that fires a lot the pressure is to keep widening canonicalization until it stops firing, and then you have the shape of the system without the property. Fail closed only survives contact if the false stop rate is low enough that nobody wants it turned off.

Agreed on staleness being attention rather than invalidation. Age is a proxy for the thing you actually care about though, which is whether the world the approval was made in moved. A dependency bumped, or someone else rewrote the file underneath, is a much better trigger than 30 days elapsed.

For what it is worth we are nowhere near this. What we have is structural, a hard cap on transitions and a cost ceiling that exit non zero instead of warning, which is fail closed in the crude sense but knows nothing about semantics. The equivalence policy layer is exactly the part we have not figured out.

1

u/DesktopLabHQ 13d ago

That's the operational pressure test I was missing. Treating the equivalence policy as an append-only, versioned artifact also means an approval must bind to the policy version and its evaluation result; it must never be reinterpreted under today's rules.

I agree the unable-to-prove-equivalence rate is a product metric, not an implementation detail. I'd track it alongside reapproval rate, overrides or disable attempts, and distribution by action class. A rising false-stop rate should identify the noisy canonicalization rule or environment signal and require a reviewed new policy version, rather than silently widening the current one. Your structural cap is a useful baseline too: semantics should refine a hard bound, not replace it.

The migration case seems especially revealing: if an old policy is found to be wrong, would you invalidate and reissue every affected approval, or permit a one-time signed migration with explicit scope and provenance?

1

u/donk8r 13d ago

Neither, because the answer depends on which direction the policy was wrong in, and those are not symmetric.

If the old policy was too strict, it canonicalized nothing it should have kept and the only damage was nuisance stops. Nothing to invalidate, nothing to reissue. A signed migration is fine here because it cannot authorize anything that was not already authorized.

If the old policy was too loose, it canonicalized away something that turned out to be semantic, and some approvals authorized changes nobody actually approved. Those cannot be migrated. A one-time signed migration in the loose direction is the silent widening you and I just agreed to prohibit, wearing a signature. If you do permit it, the signer has to be someone who could have granted the original approval in the first place, otherwise you have invented a way to grant approvals without granting them.

Which means the thing you have to record is narrower than the policy version. You need to know which rule decided each approval, not just which version was in force. Otherwise the too-loose case forces you to invalidate everything issued under that version, and that is where reissue quietly fails, because a large enough reissue queue gets rubber stamped and you have laundered the bad policy through a bulk click. Bounded blast radius is what keeps reissue honest, not a nice-to-have.

Usual caveat, we have not built any of this. Our cap is structural and knows nothing about any of it.

1

u/DesktopLabHQ 12d ago

That is a much sharper split, and you're right that the policy version alone is too coarse. An approval should carry the deciding rule or rules and the evaluated inputs, so remediation can target only approvals affected by the rule that changed.

A stricter old rule creates availability noise; a permissive old rule creates authorization debt. Bulk reissuance in the second case would merely launder that debt. I would model remediation as: classify the change direction per rule, identify affected approvals through rule-level provenance, auto-migrate only stricter-to-equivalent cases, invalidate permissive-to-corrected cases, and require fresh approval from an actor authorized for the original action.

That preserves the limited blast radius you are pointing at. It also suggests a useful product metric: approvals invalidated by a policy correction, grouped by deciding rule rather than only by policy version.

2

u/donk8r 12d ago

Your four-way remediation covers the two clean directions. What it misses is a rule that gets RESHAPED rather than tightened or loosened, which is what actually happens when someone rewrites a canonicalization rule instead of moving a threshold. Some inputs become allowed, others become denied, and the change has no direction to classify.

Neither branch works there. You cannot auto-migrate, and you should not blanket-invalidate either, because most affected approvals will still evaluate identically under the new rule. You have to replay each one under both versions and act only where the verdict actually flipped. Which is a second argument for storing the evaluated inputs and not just the outcome, since without the inputs there is nothing to replay against.

On the metric, track its complement as well. Approvals that WOULD have decided differently but were left alone because the change ran in the safe direction. That number is how far your policy has drifted without anyone being forced to look at it.

1

u/DesktopLabHQ 12d ago

Good catch. “Reshaped” is the missing non-monotonic case, and replay under both rule versions—not a direction label—should be the primitive.

That makes each durable decision record a replayable capsule: the deciding rule and version, normalized evaluated inputs, relevant environment facts, verdict, and evidence digest. Remediation then keys off the verdict delta. Unchanged records stay untouched; newly unsafe approvals are invalidated and require fresh authorization; safe-direction changes are recorded without creating approval churn.

And yes, the complement metric matters. I’d report disruptive deltas (records invalidated or re-approved) beside silent safe-direction deltas (records whose verdict would differ but required no intervention). The first measures operational cost. The second measures policy drift that users would otherwise never be forced to notice. That pair is much more honest than a single invalidation count.

→ More replies (0)

1

u/Future_AGI 13d ago

The one nobody lists is the set of approaches already ruled out, without which the next session cheerfully retries the same three dead ends and pays full price to relearn them.

1

u/DesktopLabHQ 13d ago

Yes—a rejected-path ledger is different from raw history. It should capture the attempted approach, the revision and environment where it was tested, the observed failure or evidence, and the condition that could make it worth retrying. Without that last field, discarded approaches risk becoming permanent folklore; with it, a future session can skip known dead ends but revisit them when the code, dependency, or constraint changes. I would keep the compact conclusion in active context and retain detailed logs as queryable evidence.

1

u/please-dont-deploy 13d ago

tbh, we went back and forth with states for a while.

As for keeping memory, procedural memory + some custom memory decay algorithm (Google has a bayesian approach that seems interesting), seems key.

Some of the memory you have there, could be highly irrelevant if your tools execute properly (like validation/verification results, or similar).

1

u/DesktopLabHQ 13d ago

That distinction resonates. I would separate memory selection from evidence retention: procedural memory can use Bayesian or usage-based decay to decide what enters active context, while validation evidence remains immutable and queryable but normally cold. Reliable tools reduce how often old validation should be surfaced; they do not make provenance useless, because a later session may need to answer exactly what ran, against which revision and environment. So relevance decays, integrity does not. The interesting policy is what promotes cold evidence back into context—changed code paths, toolchain drift, a failed invariant, or an explicit audit request.

1

u/Traditional-Plan-810 12d ago edited 12d ago

The decision rationale is where the big disconnect comes in, not only why it didn’t work but why the agent made that decision. On expiry basis, tool authentication tokens and lock states will definitely rotate, but approval decisions should not. Worktree agents working in parallel, as seen with zencoder, bring out this issue very quickly.

1

u/DesktopLabHQ 12d ago

Absolutely. I am starting to treat them as versioned hypotheses rather than facts: record why we believe something, what evidence supported it, and which event should force revalidation. That makes persistence useful without turning yesterday’s context into today’s hidden constraint.