The model does not need to run forever
A few days ago I wrote about the agent that never really logs off, and what happens to identity, delegated authority, memory and behaviour once an agent persists across days rather than minutes. That piece was about the governance problem.
This one is about the other side of it. How would you actually build one?
Not a demonstration where a coding agent runs in a terminal for six hours. A real persistent engineering agent: one that can pick up a Jira ticket, understand a system spread across several repositories, work on it over several days, survive restarts, wait for humans and for CI, resume when something changes, coordinate work across repository boundaries, and eventually produce a set of reviewable pull requests.
I have been thinking about this in the context of the Agentic Sprint, though the architecture is useful well beyond software delivery. The first design decision is the one that simplifies everything after it:
Do not make the model persistent. Make the work persistent.
In brief
- A persistent agent is not a long-lived model session. Processes die, credentials expire and models get replaced, so persistence has to live somewhere other than a conversation.
- The unit of work is the change, not the repository. A task that crosses six repositories needs a representation that exists outside any repository or model session.
- An explicit repository graph lets an agent reason about blast radius before it edits anything. Context tells an agent what exists; structure tells it what a change will touch.
AGENTS.mdis context, not enforcement. Instructions go to the model; authority is established by the infrastructure around it.- The checkpoint matters more than the conversation. If a fresh model instance cannot continue the task without the previous transcript, the system is not persistent yet.
- The right shape is a persistent orchestrator running persistent work through deliberately ephemeral workers.
- Sleeping is a feature. A persistent agent should be event-driven, not a loop asking whether anything has changed.
- Credentials should be leased for the length of a work item, not the length of the task. This is an authority lease applied to the engineering system itself.
1. Persistence is not an infinite session
The obvious implementation is to start a coding agent, give it a ticket, keep the process alive, keep feeding it context, and hope it finishes.
I do not think that is a good architecture, because everything it depends on is unreliable:
- processes die
- containers restart
- context windows fill
- authentication expires
- machines disappear
- providers have outages
- models get deprecated and replaced.
If the identity and memory of your engineering agent exist entirely inside one conversation, that conversation has accidentally become your workflow engine, your database and your state machine. It is none of those things, and it has no transactional guarantees.
The alternative is to demote the model. It becomes a cognitive runtime: something you invoke to reason, plan, write and review, and then discard. The persistent thing is the task.
GitHub / Jira
↓
Persistent orchestrator
↓
Durable task state
↓
Workspace and repository graph
↓
Coding agent (Claude, Codex, whatever comes next)
↓
Code, tests, pull request
↓
Checkpoint
↓
Durable task state2. The unit of work is the change, not the repository
Consider an ordinary enterprise application made of six repositories: shared-contracts, customer-api, identity-service, staff-portal, customer-portal and terraform-platform.
A ticket arrives:
JIRA-142: add corporate account status across onboarding.
A human engineer reads that and immediately understands it is not confined to one repository. The contract changes, the API follows, then two front ends, and there is probably an identity dependency in there too.
This is where many coding-agent demonstrations stop resembling real engineering environments. They assume the repository is the unit of work. It is not. The change is the unit of work, and repositories are simply boundaries the change crosses.
So the system needs to represent JIRA-142 independently of any model session or Git repository:
task_id: JIRA-142
objective: Add corporate account status across onboarding.
phase: implementation
status: active
repos:
- shared-contracts
- customer-api
- identity-service
- staff-portal
- customer-portal
work_items:
- id: WI-001
repo: shared-contracts
status: complete
- id: WI-002
repo: customer-api
status: running
depends_on: [WI-001]
- id: WI-003
repo: staff-portal
status: blocked
depends_on: [WI-001, WI-002]That is the important move. The state of the engineering task now exists outside the model. The agent can disappear, the container can disappear, the provider can have an outage. The task remains.
3. The repository graph matters more than the prompt
Multi-repository work introduces a second problem. Giving an agent access to six repositories is not the same as giving it an understanding of how they relate.
I would maintain an explicit repository graph:
repos:
shared-contracts:
type: library
consumers: [customer-api, staff-portal, customer-portal]
customer-api:
type: service
depends_on: [shared-contracts, identity-service]
identity-service:
type: service
staff-portal:
type: frontend
depends_on: [customer-api, shared-contracts]
customer-portal:
type: frontend
depends_on: [customer-api, shared-contracts]With that in place, a proposed modification to shared-contracts stops being "change this repository" and becomes a question about blast radius: three consumers, two of them transitively through the API.
Blast radius of a shared contract change
The blast radius of a change to a shared contract library: two front ends and one service consume it directly, and the front ends also depend on the service, so a contract change reaches five repositories through two paths.
- ChangedThe repository the work starts in
- shared-contractsLibrary
- Direct consumersRebuild and retest on a contract change
- customer-apiService
- staff-portalFrontend
- customer-portalFrontend
- Reached againThrough the service, on a second path
- staff-portalFrontend
- customer-portalFrontend
Blast radius: one contract change reaches five repositories, and two of them are reached twice, so the sequencing matters as much as the diff.
That graph can drive impact analysis before a line of code is written. This is one of the places where I think agentic software development still has to mature. A great deal of current effort goes into giving agents more context. At some point we have to give them more structure instead.
4. Instructions are context, infrastructure is authority
Repository-level files such as AGENTS.md, CLAUDE.md and an architecture note are genuinely useful, and I use the pattern myself. Each repository can explain its local responsibilities:
customer-api
Responsibility
Customer lifecycle and account operations.
Allowed dependencies
shared-contracts, identity-service
Forbidden
direct access to the identity database
breaking public contract changes
synchronous notification dependencies
Build
dotnet test Customer.slnThat is good context. It is not a boundary.
Writing "never modify the identity database directly" into a Markdown file does not prevent an agent from doing it. It is guidance presented to a probabilistic system, and guidance is not a control.
So I would use these files for context and enforce the things that matter somewhere the model cannot argue with. The orchestration layer, not the prompt, should determine:
- which repositories can be read
- which repositories can be written
- which commands can execute
- which network destinations can be reached
- which credentials are available
- whether a pull request can be opened
- whether a pull request can be merged
- whether a deployment is possible.
The model gets instructions. The infrastructure establishes authority. Those are different things, and conflating them is how an agent ends up with more reach than anyone intended.
5. Separate system reasoning from repository execution
The tempting architecture is one large agent with all six repositories mounted, and a prompt saying "implement JIRA-142". It might even work. I still would not make it the normal operating model.
I would split the roles by what they are allowed to touch.
Discovery reads everything and writes nothing
An architecture or discovery agent can read all six repositories and write to none of them. Its output is not code. It is:
- an impact analysis
- a dependency and sequencing plan
- architecture decisions worth recording
- a risk assessment
- acceptance criteria mapped to repositories
- a build plan.
Implementation reads widely and writes narrowly
Once a human accepts that plan, specialised implementation agents get enough context to reason globally and only enough authority to act locally:
Backend agent
read customer-api, shared-contracts, identity-service
write customer-api
can run tests, create a branch, commit, open a pull request
cannot modify identity-service, merge, deploy
Frontend agent
read staff-portal, shared-contracts, customer-api
write staff-portalThe asymmetry is the point. Wide reading produces good decisions. Narrow writing contains the damage when a decision is wrong.
6. Every task owns a workspace
I would not let an autonomous agent work in somebody's normal development clone. Every persistent task should get an isolated workspace, and Git worktrees suit this well:
/workspaces/JIRA-142/
shared-contracts/
customer-api/
identity-service/
staff-portal/
customer-portal/The orchestrator then has deterministic knowledge of where the work exists, which matters when it has to resume something three days later. It also makes parallelism straightforward: JIRA-142 and JIRA-151 can both touch customer-api without touching each other.
7. The checkpoint matters more than the conversation
This is the practical heart of it. At the end of every meaningful execution cycle, the agent writes a structured checkpoint:
JIRA-142 / WI-002 checkpoint
Objective Implement corporate account status API.
Completed Customer entity extended.
Mapping implemented.
GET endpoint updated.
Unit tests added.
Remaining Integration test failing: shared-contract package
1.17.0 has not reached CI.
Decisions ADR-142-03: represent AccountStatus as an enum
rather than a string.
Changed Customer.cs, AccountStatus.cs, CustomerMapper.cs
Tests 47 passed, 1 failed
Commit 8c27af9
Blocker Waiting for WI-001 package publication.
Next Resume integration tests after publication.Then shut the model down.
Three hours later the dependency lands. A different machine starts a different model instance. It reads the task state, the build plan, the checkpoint, the repository state and the diff, and continues.
I think of this as externalised cognition. The agent's important knowledge is never trapped inside its conversation, because the system continuously converts reasoning into durable artefacts.
Native session resumption still has value. If a coding agent can pick up the same thread, preserving that working context is a real optimisation. But treat it as exactly that, an optimisation, and hold the architecture to one test:
Could a completely new model instance continue this task without access to the previous conversation?
If the answer is no, the system is not persistent yet. It is a long conversation with good uptime.
That test also buys model portability. Today Codex, tomorrow Claude, next year something not yet released. The engineering task should not care.
The persistent task cycle
The cycle a persistent task repeats: an event wakes it, a worker is granted temporary authority, work happens, a checkpoint is written back to durable state, and the worker and its credentials are destroyed while the task sleeps.
- 01EventA merge, a CI result, an approval or a timer wakes the task.
- 02LeaseA worker starts and receives authority scoped to one work item.
- 03WorkThe model reads durable state and the checkpoint, then acts.
- 04CheckpointDecisions, evidence and the next action are written back.
- 05ExpireThe worker and its credentials are destroyed.
- 06SleepThe task persists and costs nothing until the next event.
The test: a new model instance, on a different machine, must be able to resume from step 03 without the previous conversation.
8. Persistent orchestrator, ephemeral workers
This leads somewhere that feels counterintuitive at first. I do not want one large persistent coding agent at all. I want a persistent orchestrator managing persistent work through ephemeral specialised agents.
Persistent orchestrator, ephemeral workers
A ticket enters discovery and architecture analysis, produces a build plan that a human approves, then fans out to contract, backend and frontend agents working in parallel, each producing a pull request, before converging through integration and quality assurance to a second human gate and release.
- TicketAn approved requirement enters the system.
- DiscoveryReads every repository, writes to none.
- Build planImpact, sequence, risk and acceptance criteria.
- Human approvalA person accepts the plan before any code changes.
- IntegrationThe changes are assembled and verified together.
- Quality assuranceIndependent checks against the acceptance criteria.
- Release authorityA human or policy gate decides whether it ships.
- ReleaseProtected branches and production controls still apply.
Every worker can die as soon as its job is done. The workflow stays alive.
Specialisation gets easier too, because the roles genuinely need different authority. An architecture agent needs breadth and no write access. A quality assurance agent should be able to trigger tests but not rewrite production code. A reviewer should be able to inspect every affected repository and modify none of them. Persistence lives at the orchestration level, and authority is scoped per role.
9. Events wake the agent, and sleeping is a feature
A persistent agent should not sit in a loop burning tokens asking whether anything has changed. Persistence should be event-driven.
When the backend agent reaches a blocker, the worker terminates and the task state becomes waiting_dependency. Later, GitHub emits a merge event for the pull request it was waiting on. The orchestrator receives the event, looks up the dependent work item, and schedules another execution. A fresh worker starts, reads the checkpoint and continues.
The same mechanism covers the whole surface a real engineering task waits on:
- a ticket is updated
- a pull request is approved or rejected
- CI succeeds or fails
- a security scan completes
- a human approval arrives
- a deployment completes
- a dependency is released
- a scheduled wake-up is reached.
So a persistent agent is asleep most of the time. That is not a limitation to engineer around. It is the correct behaviour, and it is what makes the running cost of a seven-day task proportional to the work rather than to the elapsed time.
10. Keep the model replaceable
Both Claude Code and Codex can serve as the execution runtime underneath this. I would not couple the orchestration system to either. A provider interface is enough:
CodingAgent
start()
resume()
execute()
checkpoint()
stop()with a ClaudeAdapter and a CodexAdapter behind it. Then an individual work item declares what it needs:
agent:
provider: codex
role: backend-implementationwhile another asks for a different provider in an analysis role. The interesting abstraction is not which model is being used. It is what role is being executed, against what context, with what authority. That question survives model generations.
This gives me a fairly strong architectural opinion:
- If replacing one model with another destroys the agent's memory, persistence is coupled to the wrong layer.
- If swapping providers means the system forgets why a pull request exists, state is coupled to the wrong layer.
- If restarting a container means rediscovering six repositories from scratch, context is coupled to the wrong layer.
The persistent system should own identity, objective, state, memory, workspace, authority, dependencies, decisions and checkpoints. The model should provide reasoning, planning, coding, review and analysis. That separation is the whole design.
11. A control plane, not a credential handout
I would not give every worker direct credentials for every underlying system. This is where the Model Context Protocol earns its place: instead of handing the model a database password, a GitHub token, Jira credentials and cloud keys, give it controlled tools.
task.get repo.inspect github.create_branch
task.checkpoint repo.checkout github.create_pr
approval.request ci.run policy.check
approval.status ci.statusThe agent asks to create a pull request. A control service decides whether that particular agent, in that role, at that moment, is permitted to. The model never holds broad infrastructure authority, and every consequential action passes a point where policy can be applied and the request recorded.
12. Lease the credentials too
There is a security consequence worth stating on its own. A persistent task may live for seven days. That does not mean its worker needs seven-day credentials.
When a worker wakes, give it temporary authority scoped to the work item:
Agent backend-agent-142-04
Can read customer-api, shared-contracts, identity-service
Can write customer-api, branch agent/JIRA-142
Can run approved build commands, commit, open a pull request
Cannot merge, deploy, change repository settings, read production secrets
Lifetime 45 minutesWhen the worker finishes, the credential expires. The persistent task survives; its operational authority does not.
This is exactly the authority lease idea applied to the engineering system itself, and the engineering system turns out to be an unusually good place to try it. The work is naturally bounded, the tooling already knows what a build needs, and the blast radius of getting it wrong is a failed pipeline rather than a payment.
13. Memory is not conversation history
Another mistake would be storing every previous model message and calling it memory. Useful persistent engineering memory is more structured than that, and it separates into at least four kinds:
| Kind | What it holds |
|---|---|
| Task | Objective, acceptance criteria, current phase, completed work, blockers, dependencies |
| Architectural | Decision records, system boundaries, repository relationships, API contracts, known constraints |
| Execution | Commits, test results, failed approaches, pull requests, build artefacts |
| Organisational | Coding standards, security policies, architecture principles, repository ownership, release requirements |
Conversation history can still exist. It just is not the canonical state, and nothing important should be recoverable only from it.
The failed approaches deserve a mention. A record of what was tried and did not work is one of the most valuable things a resumed agent can read, and it is precisely what gets lost when a session ends.
14. Keep the infrastructure boring
None of this needs exotic infrastructure. A first version can be a set of ordinary PostgreSQL tables: tasks, task runs, work items, dependencies, workspaces, repository state, agent runs, checkpoints, artefacts, approvals, decisions and events. Large artefacts go to object storage.
Git stays the source of truth for code. Jira stays the source of truth for business intent. GitHub stays the source of truth for review and merge state. The orchestrator stores the relationships between them, and that relationship is the valuable part.
You can prove the whole architecture with a workflow tool such as n8n: a ticket webhook creates a task and a workspace, launches a worker, captures the result, writes a checkpoint, and waits for a GitHub webhook to resume. That is enough to find out whether the design holds.
For a serious production implementation I would eventually want a durable workflow engine such as Temporal underneath. The reason has nothing to do with AI. Long-running workflows have to survive process failure, worker restarts, network partitions, timeouts, retries, human delays, multi-day waits, duplicate events and partial execution. Those are distributed-systems problems with well-understood solutions. Do not try to solve them with prompts.
15. Where this meets the methodology
This architecture is the implementation shape of something I have been developing as the Agentic Sprint, which turns autonomous delivery into a controlled workflow with explicit stage gates: requirement, discovery, impact analysis, build plan, human approval, parallel implementation, integration, quality assurance, a human or policy gate, and release. Each stage produces durable artefacts, each stage has defined authority, and each transition can be inspected. Agents come and go; the sprint persists.
Autonomous Loop covers a different part of the same problem: how a bounded execution loop keeps working, recovers its context and iterates toward an objective. Put the two together and you get something more useful than an infinitely running coding agent. You get a durable autonomous engineering process.
The governance ideas stop being theoretical here too. A persistent engineering actor for JIRA-142 has an identity, a declared purpose, an accountable owner, a lifetime, a set of readable and writable repositories, no merge or deployment authority, a current behavioural state and a last human attestation, which is the build-plan approval. It creates short-lived children, and each child receives less authority than its parent:
Authority(child) ⊆ Authority(parent)That is where Human Delegation Provenance becomes useful rather than abstract. The ticket establishes an organisational objective, the approved build plan establishes the human authorisation, the persistent actor carries that delegation, and the commits and pull requests at the end can retain provenance back to it. A reviewer can ask which human authorised the change that produced this diff, and get an answer that is evidence rather than an assertion.
Behavioural detection lands in the same place. A frontend agent that normally runs component tests, and then one afternoon reads SSH keys, reaches for cloud credentials, edits Terraform and contacts an unfamiliar endpoint, still has a perfectly valid identity. Its behaviour is what changed. That is the distinction behind continuous agent authority, and an engineering system is a good place to notice it, because the baseline is unusually legible: agents here have narrow, repetitive, well-understood jobs.
16. The interesting problem is not persistence
Building something that wakes a model every four hours is not difficult. The difficult part is deciding what happens after it wakes.
- What does it know?
- What changed while it was asleep?
- What authority does it currently hold?
- Which repositories are relevant now?
- What work is already complete?
- Which decisions are settled, and which are still open?
- What is it waiting for?
- What is it allowed to change?
- Who approves the next transition?
- How do we know another agent has not changed the same dependency underneath it?
- Can we reconstruct why the final code exists?
Those are the real persistent-agent problems, and none of them are model problems. They are systems-engineering problems, which is good news, because we know how to solve those.
The persistent agent is mostly ephemeral
There is an odd conclusion hiding in all of this. The best persistent agent is composed almost entirely of temporary things: temporary model sessions, temporary containers, temporary credentials, temporary worktrees, temporary tool permissions, temporary child agents.
What persists is narrower and more valuable: identity, purpose, state, history, authority lineage and memory.
So "persistent agent" is slightly the wrong name. What is actually being built is a persistent autonomous actor implemented through ephemeral execution. That architecture is more resilient, more model-agnostic, easier to secure, easier to audit, and, importantly, much easier to stop.
We have spent a lot of effort trying to make models remember more: longer context, better memory, persistent conversations. Those things are useful. But for serious autonomous systems the stronger move may be to let the model forget safely. Let it disappear. Preserve the decisions, the evidence, the state and the authority. Then wake whatever intelligence is best suited to the next piece of work.
The model does not need to run forever. The work does.
Open questions
I would rather publish this with the unresolved parts visible.
- How two persistent tasks touching the same repository should coordinate. Optimistic concurrency and a rebase is the obvious answer, and it is not obviously the right one when both changes are half-finished.
- Where the human gate sits when the build plan itself is wrong. Approving a plan is not the same as approving every change the plan implies.
- How much of the repository graph should be maintained by hand rather than derived from build files, and what happens when the two disagree.
- Whether a checkpoint should be written by the model, by the orchestrator observing the model, or by both, given that a model summarising its own work is exactly the maker-checker problem the methodology tries to avoid.
- How long organisational memory should live before it becomes a liability, since a coding standard that was corrected two years ago is now just a confident, wrong instruction.
Disclosure
I am a co-founder and CTO of Helixar. Human Delegation Provenance is Helixar research and open-specification work, published through Helixar under the Apache 2.0 licence, and it is an active IETF Internet-Draft rather than an adopted standard. The Agentic Sprint methodology and Autonomous Loop are my own independent work. This article describes an architecture I am arguing for, not a product, and no part of it should be read as a claim about any employer's systems.
Sources and attribution
- modelcontextprotocol.io/specificationmodelcontextprotocol.io
- docs.temporal.io/encyclopedia/detecting-workflow-failuresdocs.temporal.io
- git-scm.com/docs/git-worktreegit-scm.com
- GitHub Docs: about webhooksdocs.github.com
- arXiv preprint 2604.04522arxiv.org
- IETF Internet-Draft draft-helixar-hdp-agentic-delegationdatatracker.ietf.org
- theagenticsprint.comtheagenticsprint.com
- Helixar: hdphelixar.ai
Corrections and material updates are dated on this page.