Daedalus

An autonomous coding pipeline that takes one issue from claim to commit, with the controls that make that safe to leave unattended.

Problem

An agent that writes code end to end is straightforward when the source issue has a solid specification. What is hard is everything that can go wrong when no human sits in the loop: unreviewed code that ships, an agent that edits files it was never asked to touch, token cost with no ceiling, and a run that loops on a problem it cannot solve instead of stopping.

Daedalus is my answer to that. It picks up one tracked issue, writes the code, runs the tests, and commits, with nobody driving in between. The hard part is the controls: what makes a run reviewable, honest about its scope, bounded in cost, and able to stop itself.

Architecture

The unit of work is one issue from the backlog. Three coordinated agents move it from claim to commit, and a set of hooks sits underneath them, where most of the control actually lives.

[tracked issue]
      │
      ▼
[orchestrator]  claims, plans, coordinates; never edits code
      │
      ▼
[implementer]  writes the failing test, then the change (test-first)
      │
      ▼
[review gate]  no edit tools, no implementer context; judges the diff cold
      │            reruns tests + lint, checks each acceptance criterion
      ▼
  APPROVE ──▶ quality gates ──▶ commit (issue reference)
  REJECT  ──▶ re-spawn implementer with findings (bounded retries)
      │
      ▼
  blocked-with-reason  (a valid terminal state)

HOOKS (underneath all three)
  scope + path protection · commit gate · turn caps · budget ceiling

The orchestrator coordinates and never edits code. The implementer writes the change test-first and holds the whole change in one context. The review gate is a separate agent with no edit tools and none of the development session's context, so it judges the diff cold: it reruns the project's configured test and lint commands itself, reads the issue body, confirms each acceptance criterion, and returns APPROVE or REJECT with findings tied to file and line.

The pipeline fans out at exactly one point, and only where the work is genuinely independent: on a change flagged high-risk, three reviewers run at once with separate goals (security, regressions, test adequacy), all judging the same finished diff, and all three must approve. Implementation never fans out, because a single code change is shared-context work.

Controls for an unattended run

Each control is enforced by the harness, not requested in a prompt. A prompt that asks an agent to stay in scope is a suggestion; a hook that denies the edit is a control.

  • Reviewability. Every run prints its evidence to the transcript: test output, lint output, the verdict, the diff status, and each tracker change. Coming back to a finished run means reading what it ran and what the reviewer concluded.
  • Scope honesty. The review gate auto-rejects any file changed outside the plan. Path-protection hooks deny edits to environment files, lockfiles, the .git directory, and CI config, and block force pushes and history resets. A commit hook refuses until the test and lint gates have passed recently.
  • Bounded cost. The implementer runs at most 25 turns, the reviewer at most 12, the orchestrator inside a roughly 40-turn budget. The expensive three-reviewer fan-out runs only on high-risk changes.
  • A clean stop. On rejection the orchestrator re-spawns the implementer with the findings, up to three cycles. After that, or on repeated identical failures, a spec that contradicts the code, or a near-exhausted budget, it marks the issue blocked with a written reason and stops. A blocked task with a recorded reason is a legitimate outcome.

Three learnings

  1. 1. Name the actions you do not want and enforce them mechanically. The failure mode that worried me most was the agent that makes tests pass by changing the wrong thing: weakening a test, mutating CI to slip a bad build through. None of the defenses depend on the agent choosing to behave, because a reviewer that auto-rejects from its own context is a control and a prompt is not.
  2. 2. Parallelize by dependency structure, not by how many agents you can spawn. The published data on multi-agent systems shows the gains land on breadth-first, independent-direction work; a single code change is the opposite, its parts depend on each other. So implementation stays in one agent, and the fan-out is reserved for independent judgments of a finished diff.
  3. 3. Make stopping a first-class outcome. The run that neither finishes nor stops is the one that burns budget for nothing. Bounded retries plus a blocked-with-reason terminal state are what keep "autonomous" from meaning "unbounded," and the configured human-approval boundary holds: when set to commit locally and wait for review, the pipeline does not push or open a pull request no matter what would be convenient.

Links