Worksoftware

Ledger

Orchestrates headless Claude Code agents through a fixed research → plan → implement → validate → review → ship pipeline, with git worktree isolation, file-ownership locks, and human review gates.

DateJul 1, 2026
Statuscomplete
Tagsagents, orchestration, go

The problem with one long agent session

A single Claude Code session handling a big, multi-file change loses context, overwrites its own earlier work, and needs constant hand-holding. ledger is the antidote: instead of one agent doing everything serially, it runs a team of headless agents through a fixed pipeline, each isolated in its own git worktree, gated on human review at the points that matter.

The fixed pipeline

research → plan → implement → validate → review → ship always runs in that order. That’s a deliberate tradeoff against freeform loops (SWE-agent, aider --architect):

  • You lose the agent’s freedom to skip validation mid-run.
  • You gain a pipeline that’s predictable to review — every stage produces an artifact you can gate on, and a stuck or wrong agent fails one bounded stage instead of the whole run.

For large changes where the failure mode you’re avoiding is “confidently wrong across 20 files,” predictability wins.

The hard parts

  • Isolation without collision — each agent gets its own worktree, plus a shared ownership registry so two agents never write the same file at once. A worker requests ownership of a path before touching it.
  • Failure recovery — a failed worker is killed and respawned (up to a retry cap) rather than leaving the pipeline stuck.
  • Model routing — a one-off “best model for this job” decision at each stage.
  • A TUI you can actually operate — a split-pane Bubble Tea interface with an agent tree, a live journal stream, review gates (a/r/e), and a /btw primitive to kill an agent and relay a message to its replacement.
// Ownership is mutual-exclusion over paths — request, then release.
func (r *Registry) Request(agentID, path string) (bool, error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	if owner, ok := r.locks[path]; ok && owner != agentID {
		return false, nil
	}
	r.locks[path] = agentID
	return true, nil
}

Status

M0–M10 implemented, including model routing and the TUI, with tests that exercise the real claude CLI end to end. Deliberately scoped out for v1: multi-orchestrator coordination and a user-configurable pipeline shape.