Development record
Autonomous Routines Assemble From One Versioned Template
Press Release
abcd now assembles the prompts that drive autonomous maintenance loops. A repository's recurring bug-hunt or plan-drain routine is no longer a hand-written wall of text:
abcd routine renderdetects the repo's toolchain, gate commands, and working-tier layout, fills a versioned archetype template, and emits the finished routine prompt plus a host-ready schedule manifest. The safety invariants every loop needs — state comments trusted only from the repo's own maintainers, resumption of a pushed branch that never got its pull request, a bounded wait on CI, one round per scheduled run — are baked into the template, not remembered per repo. When the template improves, the whole fleet re-renders in one pass."I had six repos hunting bugs on a schedule, and every prompt was a slightly different vintage," said Alice, a maintainer. "One of them was told to commit into a directory the repo ignores. Now they all render from the same template, and when I fix the template I have fixed the fleet."
Why This Matters
A fleet audit of eight live routines found three prompt generations with divergent safety properties: different stop sentinels, merge gates with and without a bounded CI wait, single- and multi-round pacing, and one prompt instructing every round to commit a decision log into a path its repository gitignores. None of these differences was a decision — each was drift from hand-assembly. Re-hardening the fleet meant editing every routine individually, a full session of expert attention for changes that were mechanically identical.
A live bug-hunt loop on this repository's own state issue (#197) independently found three more invariants a hand-assembled prompt is prone to miss, none caught by the original fleet audit because none had happened yet: an orchestration-side cleanup racing a still-running reviewer subagent's own git operations in a shared checkout (round 8, recovered only by chance from a dangling stash); a stop-streak counter that could not tell three rounds of convergent diagnosis — each one narrowing the same root cause — from three rounds that learned nothing, and declared the loop wedged when it was actually converging on a correct fix; and a then-blocked bug (iss-186/PR #203, since resolved) that kept resurfacing at STATE step 3's automatic PR-resumption every round until a human happened to intervene by hand, with no way for the loop to set it aside and work on something else in the meantime. A hand-assembled prompt fixes the instance in front of it; only a shared template propagates the fix to every routine that hasn't hit that failure yet.
The assembly is deterministic work sitting outside the binary. Detecting a toolchain from its manifest, finding where the tracked decision log lives, choosing gate commands, slotting a hunt focus into a template — all of it is exactly the kind of behaviour the transport-agnostic core exists to own, and today it lives in an unversioned, untestable prompt-assembly skill on one person's machine. Under wired or it isn't done, the discipline exists but nothing in abcd carries it.
The split follows the house boundary: the binary owns detection, the template, and rendering; the plugin page owns the interview (focus, cadence, merge authorisation) and hands the rendered artefact to whatever the host uses to schedule it. The binary never contacts a scheduling service.
What's In Scope
- A versioned routine template with archetypes — bug hunt (security / correctness / docs / all focuses) and plan drain — carrying the safety invariants: maintainer-only trust for loop-state comments, pushed-branch- without-PR resumption, bounded CI wait, one-round-per-run default with an explicit capped multi-round variant, refuter count, stop conditions, and public-artifact hygiene (iss-178): session URLs and harness attribution footers are banned from all public text, and because the harness can append them outside the model's own words, every created pull request, issue, and comment is re-read as stored and stripped by edit before the round continues.
- Working-tree isolation: every subagent that inspects, builds, tests, or diffs repository state — each hunt angle, each verify candidate, the fix itself, every pre-PR and merge-gate review — runs in its own dedicated git worktree, never the orchestrator's own checkout and never another subagent's. The orchestrator never mutates or discards state a subagent may still be reading; when several reviews of one diff are dispatched together, it waits for all of them to return before acting on any single verdict.
- Root-cause escalation in place of blunt strike-counting: a stop-eligible BLOCK that traces to the same underlying coupling as an earlier BLOCK — not merely the same bug, the same mechanism — is diagnostic progress, not failure, and does not by itself count toward the loop's stop streak. It instead queues a mandatory structural-fix attempt (removing the coupling, not special-casing around it, through the same unrelaxed review gates) for the next round; only a BLOCK on that structural attempt is a genuine stop.
- Ledger shelving: a bug (or its already-open, already-blocked PR) that a stop or an exhausted root-cause escalation rules out of autonomous reach is marked needs-human in the loop-state ledger once, not rediscovered every round — excluded from future picking and from automatic PR-resumption until a trusted comment or ledger edit clears it, so the round that follows works on the next fixable thing instead of re-litigating the same block.
abcd routine render: repo detection (toolchain and gate commands from the manifest; tracked-versus-ignored working tiers, so a rendered prompt can never instruct a commit into an ignored path; platform caveats for cross-compiled targets) plus deterministic output — same repo, same template version, byte-identical render.- A neutral schedule manifest alongside the prompt (name, cadence, repo, model routing), for the host front door to translate.
- A plugin page front door that interviews, renders through the binary, and hands off to the host's scheduler.
- An optional release on completion template switch, default off, offered explicitly by the interview: when the loop reaches its drained stop (the configured run of nitpick-only rounds) and substantive fixes have merged since the last release, the closing round initiates the repository's release flow instead of only posting the stop sentinel. The routine never bypasses a release gate — in an abcd-managed repo that means the changelog-driven release gate runs exactly as it would for a human-initiated cut.
- Merge-lifecycle invariants for the loop's own pull requests. Auto-merge eligibility splits on additive versus editing, never on "documentation versus code": a change qualifies only when every path it touches is a new record file or an append to the decision log, the diff carries no deletions, the record gate is green, and it is a single commit. Anything that rewrites an existing claim — published documentation, the brief, the changelog — stays behind the run's explicit merge authorisation, because that is where a repository's post-merge corrections cluster: they fix false claims about the system, which no deterministic gate catches. The eligible set is an allowlist of inert paths, never a denylist of source extensions — in an abcd-managed repo the plugin command pages, the rules file, the lint configuration and the agent-instruction router are all markdown or JSON that change behaviour, so a "no source touched" test fails open on every one of them. Intent drafts count as additive: the lifecycle already gates at promotion, so a second gate at merge is redundant.
- The up-to-date requirement is load-bearing and is never relaxed. A queued auto-merge whose base moves waits indefinitely, and the tempting fix — dropping the strict status-check policy — is the one change the template forbids: strict is what re-runs the record gate against the merged result, and that is the only place a record id minted concurrently on two branches becomes visible, since each branch passes in isolation and the mint lock is a filesystem lock that does not span checkouts. The loop clears the stall by updating the branch, which preserves the gate.
- The loop's platform calls live in the rendered prompt, never in the binary. Arming auto-merge, polling merge state, updating a stale branch, and re-reading a created artefact are host-executed steps carrying the host's own credentials, so the binary acquires no platform CLI dependency. A repository-scoped credential that a scaffolded workflow needs is consumed by that workflow, never held or read by abcd.
Acceptance Criteria
- Given a Go repository with a
Makefilepreflight target, When Alice runsabcd routine renderwith the all-dimensions hunt archetype, Then the emitted prompt contains that repo's actual gate commands and every template safety invariant, and rendering twice produces byte-identical output. - Given a repository whose candidate decision-log path is gitignored, When a routine is rendered for it, Then the prompt directs round records to the loop-state issue only and contains no instruction to commit into an ignored path.
- Given a fleet rendered at template version N, When Bob re-renders it at version N+1, Then each routine's prompt differs from its predecessor only by the template change.
- Given the plugin page interview, When Carol completes it, Then the rendered prompt and schedule manifest are produced by the binary alone, with no network call made by the binary.
- Given the interview's defaults accepted, When a routine is rendered, Then it contains no release step; Given release on completion switched on, When the loop's final stop follows rounds that merged substantive fixes, Then the rendered prompt directs the closing round to initiate the repository's release flow, subject to every release gate the repo declares.
- Given any archetype, When a routine is rendered, Then the prompt bans session URLs and harness attribution footers from every public artifact and directs a post-create re-read-and-strip of each pull request, issue, and comment the loop creates.
- Given a rendered bug-hunt archetype, When any round dispatches more than one subagent against the same ref (a multi-angle hunt, a paired pre-PR review, a merge-gate review pair), Then the prompt directs each to its own isolated git worktree and directs the orchestrator to wait for every dispatched subagent to return before mutating or discarding the state they inspected.
- Given a rendered bug-hunt archetype, When a second BLOCK traces to the same underlying coupling as an earlier BLOCK in the same round or a prior one, Then the prompt directs the next round to attempt a structural fix removing that coupling — through the same review gates, not a relaxed one — before counting the pair toward the loop's stop streak.
- Given a rendered bug-hunt archetype, When a bug or its open PR is ruled out of autonomous reach (a stop, or an exhausted root-cause escalation), Then the prompt directs it marked needs-human in the loop-state ledger and excluded from future picking and PR-resumption until a human clears it.
SOTA
Surveyed on 2026-10-23; sources, evidence tiers and the local fit risks are in the autonomous-loops SOTA note.
- The fleet re-render has a precedent. Copier records the answers and the
template version in an answers file inside the rendered project, and
copier updateregenerates from the new template version, diffs against the current project and re-applies the project's own changes, with conflicts shown inline (Copier docs). That is the shape of "re-render at version N+1, differing only by the template change". - One shared config, many repositories. Renovate presets are referenced as
extends: ["github>org/repo#1.2.3"], a tag pins the version, and an untagged reference follows the default branch (Renovate docs). A network read at render time is what the intent forbids, so the pattern informs the version pin, not the mechanism. - The host's routines version nothing across repositories. A scheduled task
is "a prompt, one or more repositories, and a set of connectors" saved per
account; runs push to
claude/branches, fire-endpoint text arrives wrapped as untrusted data, runs are capped per hour, a lost GitHub connection turns the task off after 72 hours, and a green run status does not mean the work succeeded (Claude Code scheduled tasks docs). The GitHub Action's fleet route is a reusable workflow each repository calls (Claude Code GitHub Actions docs). - State outside the model. Anthropic's long-running harness keeps a progress file and a JSON feature list, chosen because the model overwrites JSON less readily than Markdown, and says compaction is not sufficient (Anthropic engineering). The contrarian "same prompt in a while loop" (the Ralph loop) lists its own failure modes: placeholders, duplicated work from wrong searches, broken builds on waking, unusable on an existing codebase (Huntley, anecdotal).
- Per-sub-agent worktrees are a host primitive now.
isolation: worktreegives a sub-agent a locked temporary worktree, removed when unchanged, with edits, command cwd and git redirects into the main checkout blocked; the default location is.claude/worktrees/under the repository and aWorktreeCreatehook replaces the host's git creation entirely, at a cost: the host's automatic removal, marker and periodic sweep do not cover a hook-made worktree (the sweep "keeps any worktree without" the marker, "including a worktree aWorktreeCreatehook created"), so relocation needs a pairedWorktreeRemovehook or worktrees accumulate;.worktreeincludeis not processed, so the hook copies local files itself; the transcript stays at the launch directory; and the hook is host configuration written into the managed repository's settings. It applies on a local host only: a cloud scheduled task runs on a fresh clone in the vendor's machine, where there is no machine store, and keeps the host default inside its clone (Claude Code worktrees and hooks docs). - Conflict rates and the orchestrator-worker evidence are in the 2026-10-17 note and are not repeated.
Path 2: a native routine render shaped to Copier's update contract (an
answers record in the rendered repository's .abcd/ tier naming template
version and interview answers, a byte-identical render, an update that
re-renders and diffs), with the manifest-to-host step behind the host connector
so schedule configuration for one host never enters the core, and, on a local
host, sub-agent worktrees placed in abcd's machine store through the host's
WorktreeCreate hook with a paired WorktreeRemove hook (a cloud host has no
machine store and keeps the host default inside its own clone). No Go
dependency. The independent fit-challenge runs at plan time.
Local fit risk: the answers record must not alone authorise a merge. The
answers record lives in the rendered repository's committed .abcd/ tier. A
committed .abcd/ file is writable by any agent in the run and by any pull request, and the guard's protected-path list does not cover it, so the rule itd-97's SOTA section sets for auto applies here too: repository configuration can forbid a merge but should not alone arm one. Merge authorisation comes from a user-level layer the repository can only lower, or the answers record sits on a guard-protected path.
Open Questions
- Verb name and family:
abcd routineas its own verb, or a sub-verb of an existing family? - Does the binary emit only the neutral manifest, or also host-specific schedule configuration behind an adapter seam?
- Where fleet membership is recorded (which repos carry which routines at which template version) — per-repo record, user home, or nowhere?
- Whether the plan-drain archetype's work-queue contract (plan file wins, strike rules) is part of this intent or its own.
- What "initiate the release flow" means per repo — invoke the release machinery directly, or open the release cut as a final gated pull request — and how the closing round interacts with receipt-gated releases that need host-run semantic reviews.
- Whether the merge-lifecycle protocol ships only as rendered prompt steps, or also as a scaffolded workflow — and if the latter, whether that workflow takes a repository-scoped credential or points at a platform merge queue where the plan allows one.
- Whether a repository's merge style — collapsing a single-commit record change, keeping the history of a multi-commit branch — is declared by the template or detected per repo.
- Whether two peer sessions sharing one checkout are prevented by policy or by giving every session its own worktree, given that the orchestrator/subagent isolation rule above does not cover independent peers.
- Whether attribution-footer defence is detection, post-create stripping, or both, and whether a detection blocks the round or only annotates it.
- (SOTA 2026-10-23) Whether the per-repository answers record (Copier's precedent) is the fleet's only register, so that "which repos carry which routines at which version" is answered by walking the repositories, or whether the user's home also keeps an index.
- (SOTA 2026-10-23) Whether a rendered routine relocates the host's sub-agent
worktrees into abcd's machine store through a
WorktreeCreatehook, or accepts the host's default under the checkout; relocation costs a pairedWorktreeRemovehook (the host's cleanup, marker and sweep do not cover a hook-made worktree), the hook copying.worktreeincludefiles itself, and host settings written into the managed repository, and it applies to local hosts only.
Audit Notes
Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/.
Frontmatter
| id | itd-107 |
|---|---|
| type | intent |
| lifecycle | drafts |
| severity | minor |
.abcd/development/intents/drafts/itd-107-autonomous-routines-assemble-from-one.md
open on GitHub ↗ · commit history ↗
Referenced by8
- iss-172abcd-managed repos need PR-queue hygiene when branch protection requires up-to-date branches: a queued auto-merge PR whose base moved sits BEHIND forever because GitHub auto-merge never updates branches. Two delivery rungs per basics-built-in/SOTA-delegated: (1) protocol-level now — after arming auto-merge, poll mergeStateStatus and run gh pr update-branch on BEHIND (works with the agent's own token, CI triggers normally); (2) scaffolded CI later — abcd scaffolds an update-branch workflow into managed repos, which requires a PAT/GitHub-App secret because the default GITHUB_TOKEN's pushes do not trigger workflows (the recursion suppression trap), or points at a merge queue where the plan allows. Same scaffolding family as itd-93's release gate; same merged-work-hygiene family as itd-95.related
- iss-178Autonomous cloud runs in sibling repos leaked harness attribution footers and a live session URL into public GitHub artifacts: the harness auto-appends a 'Generated with' footer plus a session link when a PR or issue is created, overriding the repos' Assisted-by-only attribution policy (commit messages stayed clean; the leak surface was PR bodies and issue comments, plus GitHub's public edit history retaining the pre-scrub revision). Leak shape only - no session ids reproduced here. Two remedies needed: (a) every autonomous routine prompt must ban session URLs and harness footers in public text AND mandate a post-create re-read-and-strip of every PR/issue/comment the loop creates, because the append happens outside the model's own text; (b) abcd should detect the class - session-URL and harness-footer patterns belong with the shared privacy pattern set (iss-154 family / itd-74 banlist territory) so audit and docs-lint flag them in any committed or posted text.related
- iss-2608282124231752scanner.ScrubOutbound has no front door: it is defined, tested and documented as the outbound-artefact scrub, but no CLI command, plugin verb or routine prompt calls it, and internal/ cannot be imported from outside the module, so the posting-time half of the harness-leak class is unmitigated in practice. This is not an oversight in spc-45, which deliberately scopes a forge client out; the gap is that nothing hands the primitive to the party that does post. Two candidate shapes for a future change: a small stdin-reading verb (abcd scrub --label pr-body) that the autonomous routine prompts pipe every PR body, issue and comment through before posting; or wiring the primitive into whatever posting path lands with itd-107, so an assembled routine scrubs by construction. Until one lands, the operative control is the re-read-and-strip policy in scanner.OutboundPolicy, as AGENTS.md, iss-178 and spc-45 state.related
- iss-2610262037186224itd-107 keeps forge calls (arming auto-merge, re-reading created items) out of the binary so it needs no forge command-line tool; the build loop's binary already makes those calls through gh.related
- iss-2610262039022652itd-107 keeps arming auto-merge and polling merge state out of the binary; 38-land's binary verb arms and confirms merges itselfrelated
- iss-2610262042367104Persona Alice is a product thinker in itd-106 and a maintainer in itd-107related
- iss-2610262043063912itd-107 keeps the strict merge policy because ids minted on two branches can collide; itd-114 says such ids never collide.related
- itd-2610120738075547Work handed to a cloud session comes back, or says why notrelated
mentions9
- dcn-26081100000000012026-08-11 — Pull-request lifecycle automation for autonomous rounds settled
- dcn-26090100000000062026-09-01 — The strict up-to-date policy stays in front of the merge queue, and the branch update is automated instead (maintainer, ruling on iss-2609012202237613 against the two directions it names). Every auto-merge pull request opened tonight sat `BEHIND` outside the queue until a hand-run update, because auto-merge enqueues only a CLEAN pull request and the strict policy makes a behind pull request never CLEAN; the queue that exists to test a pull request against the current base therefore never received it. The queue's group commit does gate the merged result, so dropping strict would preserve the duplicate-id gate iss-172 records as an invariant, but the maintainer keeps strict and ships iss-172's first rung: `scripts/pr-keep-current.sh` walks every armed pull request and asks the forge to merge the base into any that is `BEHIND` and not queued, `--watch` repeating until none is armed. Rejected for now: relaxing strict (belt and braces are kept on purpose); a scaffolded update-branch workflow (rung 2, still needing a token whose pushes trigger checks, carried by itd-107). CONTRIBUTING no longer claims branches never need updating.
- iss-186capture.commitTransition writes the destination file before removing the source (workflow.go:255-273); a non-ENOENT os.Remove(src) failure (EPERM/EROFS/EIO — e.g. a read-only remount or restrictive ACL on the source status dir) returns an error after dst already landed, with no rollback of dst. The same issue id is now present in two status directories (e.g. both open/ and resolved/). findIssue (alloc.go:383) then rejects any further transition on that id as ErrDuplicateIssueID, so it can never again be resolved or wontfixed on a healthy filesystem — no repair verb exists; recovery requires manually deleting one copy. scanLedger-based reads (List/Status) do not dedupe either, so the id also double-counts. Confirmed with a real non-ENOENT unlink failure (ext4 immutable attribute on the source dir, which blocks unlink even as root, unlike chmod). Reproducing test: internal/core/capture/workflow_test.go, TestTransitionRemoveFailureDoesNotStrandIssueInTwoDirs.
- iss-381The delivery pipeline abcd runs on itself is hand-orchestrated and should be deterministic. This session hand-ran the full sequence: SOTA research -> itd-84 decomposition -> draft intent -> TWO independent adversarial reviews (design/feasibility + record-discipline) -> planning interview -> plan+spec -> test-first implementation -> TWO more adversarial reviews of the diff (ruthless + security) -> apply/refute findings -> gates (preflight, record-lint) -> atomic commits + PR -> resolve the ledger issue with provenance -> seed the deferred items back into the ledger. Every hand-off, gate, and review-pair was driven by judgement, not a deterministic harness. The individual stages already have records — itd-83 (the review bar fires itself), itd-84 (decompose before filing), itd-82 (ledger drain), itd-78 (intent-dependency graph) — but ALL are drafts/staged and NONE composes the others into one orchestrated pipeline. Honest constraint (loud-staging): the pipeline cannot be MORE automated than its stages, so full automation waits on those disciplines shipping; but the deterministic SCAFFOLD — the fixed stage order, the mandatory review-pair gate before plan and before merge, the hand-offs to the host for the human-in-the-loop steps, the ledger-seed-the-deferrals close-out — can be built now as a workflow/routine (itd-107 versioned-routine-template is the nearest delivery vehicle). Routing note: this is a big, cross-record idea, not a decomposed intent — it likely needs /abcd:ideate then itd-84 decomposition before it becomes filable, and it may reshape rather than duplicate itd-83/82/78.
- iss-2608210932052003abcd launches autonomous bug hunts (and other routines) for the user, opt-in — beyond handing the user a prompt to paste into a cloud routine. Today the bughunt is a Desktop prompt the user wires into an external cloud routine by hand; the direction is abcd owning the launch: the user opts in, and abcd assembles and starts the routine, applying the run contract it already governs (the human git identity per itd-131, the gates, the merge decision, the state issue). This is the realisation of the run seam — adr-27 (run is a pluggable seam, not a bespoke engine), itd-29 (the run operator surface: start/status/pause/resume/ship), itd-107 (routines assemble from one versioned template; the bughunt and a delivery-pipeline archetype), and the reframed iss-381 (the deterministic delivery pipeline survives as an itd-107 archetype, not an engine). When abcd launches the routine it sets the human git identity at launch, which is the clean mechanism the itd-131 identity gate points at for routine commits (vs today's prompt/env workaround). Big, cross-record capability — needs decomposition and likely ideate before it is filable; recorded so the direction is durable.
- itd-97The Facilitator Is a Mode, Not a Person
- itd-115A Ready PR Merges Without Ever Wedging BEHIND
- itd-148Every change starts in its own worktree in abcd's store: the primary checkout is a read-only surface, and abcd blocks mutations there for every session but a declared coordinator
- itd-152Autonomous cloud runs in sibling repos leaked harness attribution footers and a live session URL into public GitHub artifacts: the harness auto-appends a 'Generated with' footer plus a session link when a PR or issue is created, overriding the repos' Assisted-by-only attribution policy (commit messages stayed clean; the leak surface was PR bodies and issue comments, plus GitHub's public edit history retaining the pre-scrub revision). Leak shape only - no session ids reproduced here. Two remedies needed: (a) every autonomous routine prompt must ban session URLs and harness footers in public text AND mandate a post-create re-read-and-strip of every PR/issue/comment the loop creates, because the append happens outside the model's own text; (b) abcd should detect the class - session-URL and harness-footer patterns belong with the shared privacy pattern set (iss-154 family / itd-74 banlist territory) so audit and docs-lint flag them in any committed or posted text.