# Giving an agent project a durable owner

Author: Chris Chabot
Canonical URL: https://chabot.dev/blog/giving-an-agent-project-a-durable-owner/
Published: 2026-11-03

What has to change when a coding conversation becomes a project that keeps running while you are elsewhere: a coordinator added to existing threads, a record that outlives any one conversation, and an interface that won't infer one state from another.

A conversation with a coding agent is a good way to get one thing done and a poor way to keep track of anything larger. While you are in the conversation the transcript is all the record you need: you asked for something, the agent did it, and you can scroll up to see how. Start five of those conversations on the same body of work, go away for a day, and the transcripts still contain the answers to what you want to know when you come back, but nothing connects them and nobody is responsible for them. What changed while I was away? What is waiting for me? What happens next if I do nothing? You can reconstruct all of that by reading, and the longer the work runs, the less likely you are to do it.

Those three questions became the requirement for the project system I designed in September 2026 and directed into production over the following weeks, with coding agents doing much of the implementation. A project had to answer them without anyone having to perform transcript archaeology, and each answer had to link to the evidence behind it. The orchestration runtimes I worked on earlier that year, some of them since retired, were mostly concerned with what a restart must not decide twice. This was a different problem, and as much a product problem as a runtime one: the work now carries on while the person responsible for it is somewhere else, so something has to own it between their visits.

## Adding an owner to what already existed

There were two obvious ways to build this and we took neither. One was a new project container with its own idea of what a workspace is. The platform already had a project identity with a workspace and configuration attached, and a second container would have given us two answers to the question of what a project is, so we added an explicit coordination mode to the identity that existed and left execution, workspace durability, metadata and inference in the services that already owned them, several of which are my colleagues' work rather than mine.

The other was to let a capable assistant on your laptop drive the whole thing. The design does let you start work from Claude Code and carry on from your phone, because the browser and an operator interface expose the same cloud project, but Claude Code is only a client in that arrangement, in the same position as the browser. It doesn't host the execution and it isn't an authority on the project's state, which is what makes it safe to close the laptop.

What we added was a coordinator: one continuing conversation that talks with you, owns the outcome and directs the work without doing it, backed by a durable brief, shared decisions and a place to see what needs attention. It routes work into ordinary threads, the same complete agents, with their own context, compaction and tools, that people were already using one at a time. The system was built around those threads and projects came afterwards, and I have been insistent that workers remain full agents rather than sub-agents with a longer brief, which is a large enough subject that I've written about it separately. The default behaviour was meant to be quiet: an explicit goal, bounded parallel work and updates when something changes meaningfully. A project also stopped being defined by a repository. It can hold code, research, documents or a mixture, and a repository is context and a place to execute.

The largest prerequisite in the client had nothing to do with agents. Transcript and composer state had to become independent for each open thread, because a second pane on top of state that assumes one open thread risks sending your message, or loading history, against the wrong one. The first slice the design recommended was correspondingly small: switch on coordination for one existing project, send it a goal through the operator interface, see the same coordinator conversation in the web app, start two bounded workers, steer one of them from a second pane, and recover the project after a gateway restart. That exercises the defining behaviour before anybody builds a large dashboard to look at it.

## Coming back

The coordinator's conversation can restart without taking the project with it, because the project's snapshots, history, library and control records live in its own workspace, and a local mirror lets the gateway serve a stopped project's saved state without waking its workers. Looking at a paused project doesn't unpause anything.

Say you asked a project yesterday for a schema migration and a short report on what it will cost to run, and you are now looking at your phone. A direct link, or the directory's "needs you" scope, gets you to the project, and that scope is narrow on purpose: it leaves out coordinator review and generic recovery counts, which aren't asking you for anything. The project page opens on the goal, the current work and a summary of what is waiting for your decision.

The work view is where a reassuring summary would be most tempting. The migration's commit may well have landed, but source review, landing and deployment are separate facts and none of them amounts to your acceptance, so the card says only whether the task is running, waiting, failed or paused by you, and its detail lists the delivery predicates as required, waived or verified. You can see that deployment is still required and still unverified instead of inferring the opposite from a green tick. This is the design's first rule carried through the product: a running agent doesn't establish progress, an open pull request doesn't establish passing checks, and a merged pull request doesn't establish deployment.

Decisions fail differently, because they go stale. A routine technical question a worker asked last night may since have been overtaken by events, and you shouldn't have to answer it this morning just because it was asked. The coordinator's attention observer follows unfinished reviews, failed commands and changed instructions, and it can withdraw a routine question once the evidence shows it is obsolete, while leaving alone the decisions that really are yours and any explicit stop. In a controlled single-worker fixture it did exactly that, and the work was accepted without anyone stepping in. Later I wrote down the other half of the arrangement, a list of what the coordinator resolves for itself and never brings to you: finding repositories and environments, restarting or rerouting a stalled thread, getting finished work reviewed and landed, and keeping project memory and library documents current. An owner that hands every obstacle back to you is a notification system.

The report is in the Library, with its versions, the task that produced it and its evidence, and being published there doesn't make it verified. If you gave the coordinator a constraint yesterday, the project separates three things that are easy to conflate: whether the note was saved, whether it was delivered over the transport, and whether the agent acknowledged it. It stops short of claiming that a saved note affected an answer, because nothing observes that.

Spending has to keep working when everything else has failed. Each paid request needs a certified maximum cost before it is dispatched, uncertain charges stay on the books, and neither a restart nor a replacement worker can clear a spending stop; raising the lifetime limit takes a new number from you. Because admission counts settled spend plus that one request's maximum, other requests already in flight can still produce a bounded overshoot, and the limit is described that way rather than as a hard ceiling. Recovery gives up after five fruitless attempts without a new result from a service, and exhausting a review budget leaves the work unapproved. Usage, which has its own tab in the workspace, keeps this passive safety ledger apart from stored budgets and metering: the server authorizes each read, overlays fresh ledger values even when metering is cached, and creates no account and dispatches no work in doing so.

## Keeping your place

Someone who comes back to long-running work uses an interface differently from someone who sits in it. They arrive through a link, often on a phone, in the middle of something, and what they need is to land where the link said and not lose what they were doing. Much of the October work went into making that true. Directory search, scope and sort, workspace tabs and settings sections all use validated URLs, so a link lands where it says it will, and on a phone a direct link selects the workspace instead of leaving you on the conversation. Tabs carry visible names rather than relying on you to remember an icon, and the 42/58 split between conversation and workspace is only an initial value, so the proportions you set last time win. Searches, settings drafts and the identity of a mutation whose outcome is still unknown survive moving around within the project session, and typing in a search doesn't rerender the coordinator's transcript, which by then may be very long.

Being clear about what isn't kept is part of the same job. Drafts live in memory for the browser session and raw file bytes aren't persisted, so a reload loses unsent bytes and the interface doesn't promise otherwise. An upload whose outcome is unknown stays marked as unknown, a retry doesn't republish anything already confirmed, and interrupted setup remains discoverable through control state on the server rather than a checkpoint in the browser, so after a reload you open the project the server already created and review its Library instead of creating it a second time.

## What checking it found

We checked this in two ways, and the difference between them is the same one the product draws. A browser running against the real project pages with deterministic local fixtures could edit and navigate, and it exposed old 44-pixel icon slots clipping the new named tabs. A signed-in walk through the deployed application covered the directory and its scopes, a project's summary, versioned Library results with their provenance, instruction revisions, delivery receipts and a reload at phone size, and it only read. That can tell you whether the product reports its state truthfully, and it can't tell you what pressing a button does, so creating a project, uploading files, starting work and changing a budget rest on the fixtures and automated tests. A landed commit isn't a verified deployment, and a passing fixture isn't production.

A model reviewing the source and screenshots then prompted a list of corrections. The Paused scope had claimed to include every project stopped by the lifetime ledger and now filters exactly the paused lifecycle. Delivery copy now distinguishes an acknowledgement that's unavailable, and a failed read of authority now describes itself as a failed read. Each of those was the interface saying slightly more than it knew, which is the defect the whole design is arranged against.

A personal agent turns out to be the same problem. It has threads it controls and work that continues while you are elsewhere, so in every way that matters here it has always been a project, and I want personal agents running on this engine rather than on a second one built beside it.
