Skip to content

feat(todo): give sessions a durable plan - #17

Merged
Steel-tech merged 6 commits into
mainfrom
claude/best-in-class-github-commit-ksgga0
Aug 19, 2026
Merged

feat(todo): give sessions a durable plan#17
Steel-tech merged 6 commits into
mainfrom
claude/best-in-class-github-commit-ksgga0

Conversation

@Steel-tech

@Steel-tech Steel-tech commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

The todo tool tracks a session's plan in the store (schema v8), not the
model's context window, so it survives crashes, resumes, and future
compaction like everything else.

Two choices carry the design, both house patterns from the pen:

  • Deterministic item ids (uuidv5 of session + call_id + index) make a
    replayed add converge on the same rows instead of duplicating them,
    so the whole tool is replay-safe.
  • The store owns the one-active-item invariant: marking an item
    in_progress returns any other active item to pending, in the same
    transaction. Items resolve by id prefix, mirroring session resolution.

Every action returns the rendered plan, so the model always acts on
current state. docs/TOOLS.md maps the rest of a best-in-class tool
catalog onto the durability contract and sequences what comes next
(job, pen worktree isolation, ask, hashline edits, ast-grep, ...).

Co-Authored-By: Claude noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01KoSjfcJPjXpkVLTS2Vxwwr

Summary by CodeRabbit

  • New Features
    • Added background child-agent execution with status checks, waiting, cancellation, recovery, and worktree isolation.
    • Added durable todo plans with add, start, complete, remove, and list actions.
    • Added interactive questions with selectable options and detached-mode support.
    • Enhanced file tools with hashline-based edits, directory listings, HTTP(S) reads, size limits, and clearer errors.
  • Documentation
    • Documented available tools, child execution, worktrees, plans, recovery, and sandbox behavior.

claude added 6 commits August 19, 2026 04:56
The `todo` tool tracks a session's plan in the store (schema v8), not the
model's context window, so it survives crashes, resumes, and future
compaction like everything else.

Two choices carry the design, both house patterns from the pen:

- Deterministic item ids (uuidv5 of session + call_id + index) make a
  replayed `add` converge on the same rows instead of duplicating them,
  so the whole tool is replay-safe.
- The store owns the one-active-item invariant: marking an item
  in_progress returns any other active item to pending, in the same
  transaction. Items resolve by id prefix, mirroring session resolution.

Every action returns the rendered plan, so the model always acts on
current state. docs/TOOLS.md maps the rest of a best-in-class tool
catalog onto the durability contract and sequences what comes next
(job, pen worktree isolation, ask, hashline edits, ast-grep, ...).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoSjfcJPjXpkVLTS2Vxwwr
The pen's `agent` tool gains the two flags that complete the durable
multi-agent story, plus the coordination plane to drive them:

- `worktree: true` runs a work child in its own git worktree on its own
  `bullpen/<child-id>` branch — the CLI's `--bg --worktree` behavior,
  now available per child. Placement mirrors the CLI resume path
  (record before create; locate decides on replay), so a replayed spawn
  reattaches to the same tree. Isolated children get a sandbox rebased
  onto their worktree with the linked-worktree git dirs widened in.
  Worktrees follow the store's directory, so isolated stores (tests,
  $BULLPEN_HOME) keep their worktrees beside their database.

- `background: true` dispatches the child and returns immediately. The
  child runs in this process but coordinates through the store like
  everything else, so crashes leave the same recoverable state as any
  session. Cancellation is cooperative — a oneshot into the child's
  select loop — so a cancelled child records its own terminal state.

- The `job` tool exposes the coordination plane to the model: `list`
  derives each child's state from stored status plus pid liveness,
  `wait` polls the store to a terminal state and returns the child's
  recorded answer, `cancel` signals a background child, which finishes
  as failed and stays resumable.

Inspect, isolated, and background children are all parallel-safe; only
a work child in the shared checkout stays serial.

Plumbing: `pid_alive` moves from the CLI into `store::status` and the
worktree module moves from the CLI into the harness, so both sides of
the coordination plane share one definition of liveness and placement.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoSjfcJPjXpkVLTS2Vxwwr
The `ask` tool puts one structured question to the human driving the
run. It is transport-agnostic: the application injects an `Asker`, and
the CLI's implementation prints to stderr — never into the answer
stream on stdout — and reads one line from the terminal on a blocking
thread. Options render as a numbered list, and the tool owns the
number-to-option mapping so every transport gets it identically.

A run with nobody on the other end (background, `--json`, piped stdin)
registers the *detached* variant: the model still sees the tool, and a
call fails immediately with the reason — decide and note the
assumption — instead of blocking on input nobody will ever type, or
surfacing a bare unknown-tool error.

Also folds the new coordination surface into the README and marks the
coordination tranche done in docs/TOOLS.md.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoSjfcJPjXpkVLTS2Vxwwr
`read_file` output becomes `line#hash<TAB>content`: every line carries
an anchor made of its position plus the first four hex chars of its
SHA-256. `edit_file` keeps the exact-string mode and gains a `patch`
mode addressed by those anchors — hunks of replace / insert_after /
delete, spans via an inclusive `to`, anchor "0" to prepend at the top,
several hunks per call applied bottom-up with overlaps rejected.

An anchor is a claim about content, not just a position, which is what
makes edits against a drifted file safe:

- a *moved* line (hash found on exactly one line) is followed there and
  reported, instead of patching whatever now sits at the old number;
- a *changed* line (hash on zero or several lines) fails the call with
  fresh hashline context around the site, so the model re-anchors
  without another read — and never misapplies the edit.

Recovery trusts a hash only when it is unique in the file, so a
four-hex-char collision degrades to an explicit error, never a wrong
edit.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoSjfcJPjXpkVLTS2Vxwwr
`read_file` now reads whatever the path names. A directory renders a
sorted listing — directories first, sizes for files — instead of a bare
OS error. An http(s) URL is fetched with GET, the body bounded while it
streams (2 MiB) rather than after it lands, with the status carried in
the output and a non-success status carried in the error.

The sandbox's network capability governs URL reads exactly as it
governs shell commands: a sandbox that denies network refuses the
fetch outright.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoSjfcJPjXpkVLTS2Vxwwr
ARCHITECTURE's crate table, the parallel-scheduling note, the harness
module docs, and the README status row all predate the coordination and
hashline work; bring each in line with what actually ships.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KoSjfcJPjXpkVLTS2Vxwwr
@Steel-tech
Steel-tech merged commit 16be3e5 into main Aug 19, 2026
4 of 5 checks passed
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e13a741f-147f-4806-9a57-0a790046fab0

📥 Commits

Reviewing files that changed from the base of the PR and between b4a1cb7 and c18f212.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (20)
  • ARCHITECTURE.md
  • README.md
  • crates/cli/Cargo.toml
  • crates/cli/src/bg.rs
  • crates/cli/src/main.rs
  • crates/harness/Cargo.toml
  • crates/harness/src/job.rs
  • crates/harness/src/lib.rs
  • crates/harness/src/pen.rs
  • crates/harness/src/testutil.rs
  • crates/harness/src/todo.rs
  • crates/harness/src/worktree.rs
  • crates/store/Cargo.toml
  • crates/store/src/lib.rs
  • crates/store/src/status.rs
  • crates/tools/Cargo.toml
  • crates/tools/src/ask.rs
  • crates/tools/src/fs.rs
  • crates/tools/src/lib.rs
  • docs/TOOLS.md

📝 Walkthrough

Walkthrough

The change adds hashline file operations, durable session todos, child job coordination, worktree and background execution, process-liveness sharing, and interactive question handling. It also updates CLI registration, crate exports, dependencies, tests, and documentation.

Changes

Tools and execution

Layer / File(s) Summary
Hashline file tools
crates/tools/Cargo.toml, crates/tools/src/fs.rs
read_file now supports hashline output, directories, and bounded HTTP(S) reads. edit_file supports anchor-based patch operations, stale-anchor recovery, overlap validation, and exact-string replacement.
Durable session todos
crates/store/src/lib.rs, crates/harness/src/todo.rs
Schema version 8 adds ordered session todos. TodoTool supports add, start, done, remove, and list actions with deterministic IDs and replay-safe persistence.
Child execution and job control
crates/harness/src/job.rs, crates/harness/src/pen.rs, crates/harness/src/worktree.rs, crates/harness/src/status.rs, crates/cli/src/bg.rs, crates/cli/src/main.rs
PenTool dispatches worktree-isolated and background children. JobTool lists, waits for, and cancels children. Process-liveness checks use the shared store helper.
Interactive question handling
crates/tools/src/ask.rs, crates/tools/src/lib.rs, crates/cli/src/main.rs
Ask supports interactive and detached modes, numbered choices, free-text replies, and validation. The CLI uses terminal-backed TtyAsker when interactive input is available.
Architecture and tool documentation
ARCHITECTURE.md, README.md, docs/TOOLS.md
Documentation covers the new tools, child execution modes, durability rules, sandbox constraints, and roadmap items.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant PenTool
  participant Store
  participant JobTool
  participant ChildSession

  Agent->>PenTool: dispatch work child
  PenTool->>Store: create or recover child session
  PenTool->>ChildSession: start worktree or background execution
  ChildSession->>Store: record completion or failure
  Agent->>JobTool: list or wait
  JobTool->>Store: read child state
  JobTool->>ChildSession: wait for or cancel local child
  JobTool-->>Agent: return status or report
Loading

Possibly related PRs

  • StructuPath/bullpen#10: Introduced isolated state handling that this change extends with store-anchored worktree paths.
  • StructuPath/bullpen#14: Added earlier worktree functionality that this change relocates and extends for child and background sessions.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/best-in-class-github-commit-ksgga0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants