Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

agent-loop

A delegation framework for AI coding agents: a set of agent definitions that turn one AI assistant into a small, disciplined team with a strict chain of responsibility. Built to run as subagents under OpenCode, but the patterns (tiers, loop, reports, recovery) are portable to any agent system that supports spawning child sessions.

The design priorities, in order: nothing gets read or rewritten silently, no work is lost when a session dies mid-flight, raw detail never floods the conversation, and a human is always the final authority.


1. What this is

Instead of one agent doing everything in one long session, agent-loop splits the work into specialized tiers. Each tier has exactly one job, a strict scope of files it may touch, and a duty to report what it did. Parent tiers spawn child tiers; children never spawn further children (except the two dispatching tiers listed below).

Tier Role Spawned by
manager Owns the conversation with the human operator: receives a task, dispatches exactly one orchestrator for it, relays results back, approves commits. Never edits code itself. the human operator
orchestrator Owns one task end-to-end: dispatches gather for research, chunks the work, dispatches one implement child per chunk, verifies independently, closes the report. manager
gather Read-only research: charts the surface before anything changes, validates every assumption against the actual code, returns findings with file:line evidence. Never edits. orchestrator
implement The only code-writing tier: executes exactly one small, self-contained chunk, re-checks the directive's assumptions before the first edit, then builds and tests. orchestrator
poller Watches long-running jobs (builds, tests, deploys) by polling on a schedule instead of blocking; detects stalls and hangs and reports them upward. orchestrator
document-master Sole writer of the durable documentation: distills finished reports into the canon, keeps summaries faithful, keeps pointers terse. manager

The gather, implement, poller, and document-master tiers are leaves: they do the work, report, and stop. They never spawn delegates of their own.

2. The loop

Every task runs the same five steps:

  1. Gather — the orchestrator dispatches a gather delegate, which reads only the code the task touches, verifies every assumption in the brief against what is actually on disk, and returns findings with file:line evidence. Any mismatch is named, not silently reconciled.
  2. Plan — the orchestrator reads the gather output and splits the work into small, self-contained chunks, each with its own directive: the goal, the authorized files, and the assumptions the implement child must re-verify. One chunk is small enough to finish in one session without guessing.
  3. Implement — one implement delegate per chunk. Before its first edit it checks the directive's assumptions against the real code; then it makes minimal, targeted edits and appends its own report section as it goes, so the record survives even if the session dies.
  4. Verify — the implement tier runs the package's build and tests and, for UI/service changes, checks the rebuilt or redeployed artifact — a green compile alone is never accepted as proof. The exact pass/fail line is captured verbatim. The orchestrator then verifies independently; the implement tier is the sole executor, so its recorded output is the only verification record.
  5. Report — one shared report file per task. Each tier appends its section in order (below), and a one-line digest climbs to the manager while the raw detail stays on disk.

Work is delivered as STATUS: COMPLETE or STATUS: PARTIAL with the remainder — a delegate that cannot finish everything says exactly what is left, rather than handing up half-information.

3. Reports: digests climb, detail stays put

One shared report file per task lives in <WORKSPACE>/reports/, named {unix_timestamp}-{report_title}.md. Sections are owned by tier and appended in order:

  1. Header — dispatch title, goal, problem.
  2. DIRECTIVE (orchestrator) — the dispatch title verbatim plus the assumptions the brief carries.
  3. GATHER (orchestrator, after research) — per-assumption CONFIRMED or DEVIATED, with file:line.
  4. IMPLEMENT (each implement child appends its own) — what, why, how, files touched, dead code purged, the build/test command run and its pass/fail line.
  5. ORCHESTRATOR NOTES — what completed, deviations and judgment calls, independent verification verdict, commit-readiness.
  6. LOG POINTERS (long jobs only) — the logfile path plus the specific lines carrying the outcome. The log body itself is never inlined.

Raw detail — file bodies, diffs, build logs — stops at the tier that produced it. What climbs is the hand-up block: one line per report in the orchestrator's return to the manager, shaped [absolute path] — digest (notable details / deviations / assumptions verified). The manager relays that line verbatim to the human, and the document-master later consumes the full files from disk. Big writes into reports are always chunked, never one monolithic write.

4. Resume / stall protocol

A delegate that stalls — empty return, aborted stream, wedged session — is resumed, never respawned. Respawning starts a fresh session that discards the delegate's preserved work and re-does what it already finished.

Recovery has three steps:

  1. Find the session id. Look it up in the session database under <OPENCODE_DATA> (the delegate's session was auto-titled from its dispatch title, which is the recovery key). If you already hold the id, skip this.
  2. Resume the same delegate. Dispatch again with the same task id and a status query: what is done, what remains, continue the rest.
  3. Verify identity. The returned task id must equal the id you passed. A mismatch means a fresh session was spawned silently — that counts as a failed resume attempt.

The same stalled delegate is force-resumed up to 10 attempts. After the 10th failure: stop all work and escalate to the human operator.

5. Escalation to the human

The loop is built to stop and ask rather than improvise. A delegate escalates and halts when:

  • a directive's assumption contradicts the code on disk (missing file, mismatched signature, unexpected test failure), or a change is needed outside its authorized file scope;
  • work would require touching files or decisions it was not granted;
  • anything would re-open a decision the operator has locked;
  • the 10th resume attempt of a stalled delegate fails.

Only the human operator approves commits, expands scope, or re-opens locked decisions. Every other conflict resolves into a questions report, not a guess.

6. Placeholders used in this repo

The sanitized files in this repo use three path placeholders. Substitute your own values:

Placeholder Meaning
<WORKSPACE> Your project workspace root — where your repos, reports, and orchestration docs live.
<OPENCODE_CONFIG> Your opencode config directory — where opencode.json and agent definitions go.
<OPENCODE_DATA> Your opencode data directory — the session database lives here.

Agent frontmatter also carries three model placeholders: <PRIMARY_MODEL> (used by manager, orchestrator, and document-master), <SUBAGENT_MODEL> (used by gather and poller), and <IMPLEMENT_MODEL> (used by implement). Point each at whatever model routes you want for that role — heavier models for dispatching and documentation, lighter/faster ones for research and polling is the default shape.

7. Rule glossary

The live system names its standing rules with opaque IDs. In this public copy every ID has been replaced by a plain phrase, used identically everywhere that rule appears. This table is the mapping; it is the only place in this repo where the original IDs appear.

Original ID Phrase used in the files What it means
R-08 consult the reports archive first Search past reports before re-investigating anything; push detail into reports and keep pointers terse.
R-19 regenerate generated files, never hand-edit Rebuild generated artifacts (e.g. protobuf output) with the official toolchain; never edit them by hand.
R-23 chart the surface before changing it Map the code you are about to touch — callers, dependencies, behavior — before editing it.
R-28 delegation concurrency Enforce the delegation limit for your setup: where tiers share one resident model on a single slot, only one delegate may be in flight ever.
R-29 validate on-touch Treat summaries as provisional: check claims against the code at the moment you act, and hand raw data up instead of judging it in place.
R-30 return PARTIAL with the remainder If you cannot finish everything, return what you completed and state exactly what remains.
R-31 poll, never block Watch long-running jobs on a polling schedule; never sit blocking a session on one job.
R-36 accuracy over agreement Prefer technical accuracy over agreement; disagree and verify when warranted.
R-43 read durable docs fully Read the canon and other durable documents in full before acting on them — no skimming.
R-46 never deliver half-information Deliver complete, verified findings, or explicitly mark every gap; never blur the two.
R-ABORT stop and report the mismatch When reality contradicts the directive, stop and return a deviation report — do not improvise.
R-DELIVERY-INTEGRITY verbatim output, never compile-green Verify on the rebuilt/redeployed artifact and record the verbatim pass/fail lines; a green compile alone proves nothing.
R-NO-SKIP attempt every question Attempt every assigned question; skipping silently is forbidden.
R-LONGEVITY / R-ONE-PATH / R-OVERHAUL right long-term solution, one path Ship the durable fix with a single code path — no legacy fallbacks, compat shims, or stubs.
R-NO-SCOPE-CREEP edit only authorized files Stay strictly inside the file scope the chunk directive grants.
R-DIAGNOSE-WITH-LOGS diagnose with logs, then remove them Instrument with prefixed diagnostic logs, reproduce, fix, then delete all of them and confirm zero remain.

Unification notes:

  • R-38 / R-39 — the source material is genuinely ambiguous: both IDs introduce one combined zone-discipline clause. Both IDs were dropped in this copy; the combined prose is kept ("stable zone exempt; volatile zone budget-capped").
  • R-29 unifies three consistent uses: the manager treats summaries as provisional, gather checks claims on-touch, and the poller defers judgment upward ("hand raw data up; the manager decides"). The single phrase validate on-touch covers all three.
  • R-08 unifies "search the reports archive before re-investigating" with "push detail into reports, keep pointers terse". The single phrase consult the reports archive first covers both.

8. Installing / adopting

  1. Copy the agent definitions. Copy the files from agents/ into <OPENCODE_CONFIG>/agent/ (manager.md, orchestrator.md, gather.md, implement.md, poller.md, document-master.md). The names are unprefixed here; keep them or add your own prefix — either way, keep each delegate's session title derived from its dispatch title, since that title is the recovery key for the resume protocol.
  2. Set your model routes. In each agent's frontmatter, replace <PRIMARY_MODEL>, <SUBAGENT_MODEL>, and <IMPLEMENT_MODEL> with your own model IDs, and wire the corresponding providers/models into <OPENCODE_CONFIG>/opencode.json.
  3. Set your provider API key via an environment variable and reference it from the config (e.g. "apiKey": "env:MY_PROVIDER_KEY") — never commit a raw key.

After that, talk to the manager tier: give it a task, and the loop takes over.


This is a sanitized public copy of a working production system. The operator's live system contains additional product-specific rules, documents, and configuration not included here.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors