gofri Why two g's? When I was a kid my grandma called me Gofri, and the family picked it up. She said the G hard, almost twice, so I write it twice.

Logbook: durable task state for AI agent handoffs

My contribution
Design and implementation.
Scope
Durable task relationships, context, session ownership and lifecycle hooks.
Evidence
Implementation inspected at eb8d3ba; reconstructed examples are labelled.

Page by Julian Ramirez ·

A fresh agent session can read the repository and still miss the most important part of the work: what someone was trying to finish, which decision has already been made and what needs to happen next.

A conversation contains some of that information, but it is not necessarily a shared task record. Logbook gives work a durable structure that agents and people can both inspect. Tasks have state, sessions have ownership, and context can be attached to the work it explains.

The handoff becomes less about recreating a conversation and more about recovering a usable task. That is the design choice I find most consequential here.

My contribution and design scope

I built Logbook around persisted work items and explicit session ownership. The implementation makes task selection and context recovery inspectable instead of relying on conversation memory. The design scope here is continuity between sessions; the selection policy alone does not establish concurrency guarantees.

Give the next session something structured to recover

An epic, a story and a task answer different questions. The epic names a larger objective; the story groups a piece of that objective; the task identifies work someone can pick up. Logbook records those relationships rather than relying on a session to remember them.

Epic · discovery
Story · search
Task · wire query
Task · add empty state
Illustrative epic → story → taskIllustrative schematic
Sources & implementation notes

Structure alone is not enough. A task called “wire search” still leaves room for incompatible interpretations of the API, the empty state or the expected result. A context entry can carry that information and attach to an epic, story or task without requiring each one to repeat the entire explanation.

Context entry
Search contract
↳ Epic ↳ Story ↳ Task
One recorded entry · explicit attachmentsIllustrative schematic
Sources & implementation notes

This is where durable context earns its place. It should record decisions and constraints that change what the next session does, not simply archive every line of chat.

Understand how ownership affects task selection

“Give me the next task” sounds simple until several sessions are active. Should a session resume its own work, claim an unassigned task or take over work left behind by a session that is no longer alive?

At the inspected revision, Logbook checks those cases in order. It first looks for the current session’s in-progress work, then unassigned in-progress work, then work owned by a dead session. Only after those options does it select a sorted todo and promote it to in-progress.

Task · wire search in_progress sessionId: current contextEntryIds → search-contract
Task · wire search in_progress sessionId: unassigned → current contextEntryIds → search-contract
Task · wire search in_progress sessionId: dead → current contextEntryIds → search-contract
Task · wire search todo → in_progress sessionId: current contextEntryIds → search-contract
Ordered fallback cases · illustrativeIllustrative schematic
Sources & implementation notes

The selector tries own in-progress work, then unassigned in-progress work, then dead-session work, then sorted todos. This ordering is not proof of race-free concurrent claiming.

That ordering expresses a preference for continuity before starting something new. It does not establish race-free coordination between simultaneous claimants; task-selection policy and concurrency guarantees are separate questions.

Make the handoff survive the conversation

Now consider an illustrative handoff. Session A records an in-progress task and attaches its context. Later, session B starts after A is no longer alive. With no higher-priority candidate, B can reclaim the recorded task instead of guessing where to begin.

Task · wire search in_progress sessionId: A contextEntryIds → search-contract
write → shared record
Task · wire search in_progress sessionId: B contextEntryIds → search-contract
shared record → recover context
Illustrative handoff · A is no longer aliveIllustrative schematic
Sources & implementation notes

The important part is what B recovers: the task’s state and the references that make the work understandable. It does not recover an implicit agreement that nobody wrote down.

The backing JSONL records also give people an inspectable representation of state. A lifecycle change can be read in the stored data rather than inferred from an agent’s final message. These are entity records, however, so a readable current record should not be confused with a complete event history.

Let lifecycle changes trigger the next response

Once state is explicit, other behavior can react to it. The supplied hooks listen for task status changes: need_info triggers the notification hook, and pending_review triggers the review hook. Those exact conditions matter when configuring a workflow.

need_info → need-info-notify
pending_review → review-spawn
Built-in hook conditionsIllustrative schematic
Sources & implementation notes

The supplied notification hook listens for need_info, not a generic blocked status. Hooks react to task.status_changed events.

A hook cannot compensate for a task that has no useful context. The strongest handoff still starts with a clear next action, recorded constraints and an owner whose state can be understood.

Chest’s validation reports address the neighboring question: what evidence says the work is complete? Plot’s approval boundaries address whether the detailed work still follows agreed intent. Logbook supplies the durable record those conversations need to refer to.

Explore Logbook’s task and context model →