1. the job we want back
  2. eli5: leaving the workbench
  3. the directory check
  4. closing the terminal
  5. an old review
engineering5 min

A Job Should Survive Its Agent

A directory check stopped us reopening our own task.

Listen to article
0:00
0:00

We were trying to reopen a coding task after its terminal had closed. Its saved task record was still on disk, and the replacement shell was in a subdirectory of the workspace where we had been working.

The launcher said it "already belongs to a different task or harness".

We hadn't reached the agent yet.

We had already fixed a version of this bug. Launching from a subdirectory worked while the original shell was alive. Once it had ended, the launcher took a separate recovery path which still expected us to be standing at the workspace root.

// the job we want back

In And Then There Were Graphs, we described a coding session that had run for sixty hours. It had begun with a product change, found missing database merges and ended up dealing with a staging prerequisite. Coming back to the product work meant remembering why those detours had been necessary and where they had stopped.

Opening a fresh chat means deciding how much of the old one to paste into it. By then it contains explanations we've ruled out and plans we've stopped following. I'd rather get back to the change we were making.

After an interruption

Finding the work again

Files, conversation and notes can be at different stages.

01

Working copy

The files as they are now.

02

Conversation

What was discussed and tried.

03

Task notes

Where we stopped, and why.

04

Review evidence

The files a reviewer checked.

A saved conversation can refer to files that have since changed.

// eli5: leaving the workbench

If you just want the idea: imagine coming back to a half-built cupboard. The cupboard is still there, along with yesterday's notes. Before carrying on, you'd check which piece the notes refer to and whether somebody else has been working on it. Reopening an agent session involves much the same checking.

// the directory check

With the names simplified, the failed launch looked like this:

The failed comparison

The directories in the failed launch

Recovery compared these paths and refused to continue.

Saved task root

workspacerecorded when the task started
investigation
≠paths did
not match

Replacement shell path

workspacesame parent
investigation current directory
Ordinary child directoryContinue if the task and ownership checks pass.
Nested Git repositoryThis recovery route stops here.
Directory names have been simplified.

We kept the saved root and changed recovery to accept an ordinary child directory. The awkward part was checking what sat between the two. A folder inside a workspace can be its own Git repository, with another session already writing to it.

Launcher recovery

Reopening the task

  1. 1
    Check the saved task

    Check task, harness and shell without changing the record.

  2. 2
    Check again before changing it

    Stop if the task or directory no longer matches.

  3. 3
    Keep a copy of the old record

    Archive it byte for byte.

  4. 4
    Record the replacement shell

    Retain the saved root and task details.

Task is still live

ReconnectReturn to the existing task.

New repository boundary

RefuseThis route cannot enter another working copy.

Plain umbrella directory

Other tasks may be runningSharing this folder does not give them ownership of this task.
The launcher's sequence for a task whose previous shell has ended.

// closing the terminal

We reproduced the refusal by creating a task in an isolated terminal, closing it, opening a replacement and moving into a child directory before using the normal launch command. A second case restarted the terminal service before trying the same recovery. Both failed before the repair and passed afterwards. We checked the resulting task record and the directory the command actually ran in.

The refusal tests covered a working copy with an owner still alive, paths outside the workspace, and real temporary Git repositories. Bare repositories and broken Git metadata had to be caught too. Those cases still stopped.

The repair passed 82 launcher checks and 11 tests using isolated terminal instances. The terminal tests used stand-in commands in place of agents. We also checked preparation against the affected live task, with terminal adapters substituted and writes blocked; the saved record stayed unchanged. We did not run the user's final continuation, so resuming the model conversation and completing the job remain untested here.

// an old review

In the earlier replay, a reviewer found a missed network error after twenty-nine focused tests had passed. We could reproduce it against the exact version they had reviewed.

An earlier review

Has anything changed since review?

CandidateFiles and artifactThe version the reviewer saw.

Same files and test conditions

The result still applies

Use it when deciding what to do next.

Changed files or test conditions

Check the new version

The old result needs checking again.
Check what was approved.An instruction to release may apply only to an earlier version.
Keeping the reviewed version with the review gives the next session something to compare.

The next test I'd run would leave an unfinished change in the workspace, alongside a review of an older version. Then I'd reopen the session and ask it where to continue. I want to see whether it notices the edit before relying on that review.

Back to blog