19 KiB
Orchestra — Token-Minimal Unattended Workflow Plan
Status: proposed
Written: 2026-07-29
Objective: deliver the intended unattended workflow while spending model
tokens only on useful implementation or review work. Routing, supervision,
continuity, Git delivery, reporting, quota accounting, and operator summaries
must be deterministic.
This plan is forward-looking. AUDIT.md remains the defect record, but claims
in either document must be verified against the live call path and a real
worker-owned checkout.
1. Target workflow
Vikunja task
→ deterministic ingest and eligibility mapping
→ router selects a project-compatible, reachable worker/harness
→ worker synchronizes the correct project checkout
→ worker writes and commits immutable TASK.md
→ harness reads TASK.md and performs the task
→ worker supervises lease, approvals, context, and liveness
→ deterministic quality gate
→ worker commits and pushes the result
→ optional review stage
→ transactional TaskCompleted
→ Vikunja reflection and morning brief
The operator is interrupted only for:
- a real harness approval that cannot be safely pre-authorized;
- a blocker requiring a human decision;
- failed deterministic gates after the configured retry policy;
- exhausted or uncertain quota;
- an integrity failure involving the checkout, handoff, or pushed anchor.
Token boundary
Model tokens are permitted for:
- implementing the task;
- reasoning about a blocker;
- an explicitly requested independent review;
- a small semantic handoff only when deterministic state is insufficient.
Model tokens are not permitted for:
- task routing or prioritization;
- worker/project selection;
- lease renewal;
- Git inspection, commits, pushes, or cleanup;
- ordinary threshold handoffs;
- completion reports and receipts;
- quality-gate execution;
- quota aggregation;
- standups, briefs, or task-source reflection.
2. Current baseline
As observed on 2026-07-29:
- Source
1ca9d64passesgo test ./...,go build ./..., andgo vet ./.... - The coordinator reports 28 historical tasks: 22 blocked, 5 completed, and 1 failed, with no queued or leased work.
- One
workpc-opencodeworker is online, but its installed binary was built from95a96d8with a modified worktree, not current source. - The worker is fixed to
/tmp/test-e2e; it is not safe for arbitrary workpc-affine projects. - Three tasks recorded as completed still have live idle OpenCode agents.
- Their worker session mappings are gone, so Orchestra cannot manage those panes through the normal lifecycle.
- Completed worktrees retain
.orchestra-report.md; two contain uncommitted task output, and their task branches were not pushed. - Federated completion receipts record
consumed: 0. - Worker leases expire after 30 minutes and have no renewal path.
- Canonical handoff semantic fields are validated and stored, but successors
are told only to inspect
TASK.mdand Git history; the semantic fields are not consumed. - Automatic Vikunja ingestion and guarded reflection are not implemented.
Operational conclusion: do not run a valuable real task until Milestones 1–3 are proven. Do not close the existing live panes during implementation or investigation without explicit operator approval.
3. Design principles
3.1 One authoritative instruction
TASK.md is the only task instruction supplied to a harness. It contains:
- immutable task identity and source;
- title and complete description;
- checkable acceptance criteria;
- project-specific quality-gate command or reference;
- the minimal completion signal;
- the prohibition against editing
TASK.md.
The initial launch prompt should be bounded and stable:
Read TASK.md at the worktree root and execute it.
Do not inject the title and description again. A pickup prompt may add only
the bounded continuity facts that are not already derivable from TASK.md
and the checkout.
3.2 Completion is a transaction
A task is not complete merely because a report marker exists. The worker must persist and advance these idempotent phases:
completion_requested
→ gate_passed
→ result_committed
→ result_pushed
→ report_uploaded
→ completion_appended
→ pane_closed
→ worktree_cleaned
Each phase records its evidence before advancing. Restart resumes the first unfinished phase. Repeating a completed phase must be safe.
TaskCompleted is emitted only after the pushed anchor is verified against
the configured remote.
3.3 The plane authors mechanical evidence
Replace the prose .orchestra-report.md contract with a zero- or
near-zero-content completion signal such as .orchestra/done. The worker
generates the canonical completion report from:
- task ID, project, worker, harness, and pane;
- base SHA, result SHA, branch, and remote;
- clean/dirty state and diffstat;
- quality-gate commands, exit codes, and timestamps;
- artifact hashes;
- native usage receipts for every lease interval;
- rotation count;
- cleanup outcome.
The agent does not spend a turn narrating information the worker can prove.
3.4 Leases describe ownership, not wall-clock task duration
Workers renew leases while they can prove all of the following:
- the worker is authenticated and healthy;
- the exact task/session mapping is still durable;
- the expected pane exists;
- the expected harness agent remains attached;
- the task version and lease owner still match.
The coordinator accepts renewal only from the current lease owner using a version guard. Renewal extends the deadline without creating a new attempt.
Expiry or worker-offline handling must:
- append one observable release/failure event;
- route that event through the normal retry accounting path;
- command the owning worker to close the exact pane when reachable;
- retain last-pane evidence even when cleanup cannot be confirmed;
- prevent a replacement session from starting until ownership is resolved or explicitly fenced.
3.5 Workers resolve projects locally
A worker must not have one global repository for every task it can lease. Machine-local configuration resolves:
(machine, task.project)
→ local base checkout
→ local worktree root
→ Git remote
→ quality-gate profile
The worker rejects a lease before starting a pane if the project is absent from its local registry. The router must also avoid offering such a lease.
3.6 Rotation is deterministic by default
Ordinary context-threshold rotation should not ask the model to write a handoff. The worker derives:
- Git anchor and branch;
- changed files and diffstat;
- last successful and failing commands;
- gate results;
- repeated tool calls and detected thrash;
- remaining acceptance criteria from
TASK.md.
A semantic handoff prompt is reserved for:
- thrash where the failed approach is not mechanically clear;
- a human-facing blocker;
- unresolved design choices;
- manual rotation explicitly requesting judgment.
Milestone rotation is disabled by default in the token-minimal policy. Rotate for hard context pressure, thrash, quota failure, or a genuinely independent next phase.
4. Milestone 1 — Establish version and ownership truth
Work
- Embed build revision, build time, and dirty status in both binaries.
- Publish coordinator build information in diagnostics.
- Include worker build information in registration and heartbeat.
- Show source revision separately for coordinator and each worker.
- Persist worker health fields: local herdr status, active task, active pane, last error, and check time.
- Make worker registration declare supported projects as well as capacity.
- Reject leases when worker project support is absent.
- Document one deployment command and one verification command for each binary.
Acceptance
- The UI/API shows the exact coordinator and worker revisions.
- A stale worker is visible as stale without SSH.
- A worker configured only for
test-e2ecannot receive acorrexlease. - Restarting the coordinator preserves worker identity and pending commands.
go test ./...,go build ./..., andgo vet ./...pass.
5. Milestone 2 — Fix leases and session fencing
Work
- Add a version-guarded worker lease-renewal endpoint.
- Renew from the worker heartbeat loop only after local pane/session validation.
- Persist renewal and cleanup errors in the worker health model.
- Route every expiry and pane-exit release through
Router.HandleEvent. - Count genuine expiry/crash releases against retry policy.
- Do not count rotations or successful stage transfers as failures.
- Add a durable cleanup command for remote workers.
- Retain pane identity and cleanup state after terminal task transitions.
- Fence replacement startup when an old pane may still own the checkout.
Acceptance
- A disposable task can remain leased for more than 30 minutes without being restarted.
- Stopping the worker causes one expiry/release and one bounded retry.
- Restarting the worker recovers the existing session instead of starting a duplicate.
- A replacement lease never overlaps an unfenced predecessor pane.
- The task record says whether cleanup is
closed,unreachable, orunknown.
6. Milestone 3 — Transactional completion and delivery
Work
- Introduce the minimal completion signal.
- Define per-project gate profiles in configuration.
- Persist the completion transaction phases.
- Run gates in the worker-owned checkout.
- Refuse completion on a dirty or failing result unless policy explicitly permits an exception.
- Commit result work on the task branch with deterministic metadata.
- Push the result branch and verify the remote SHA.
- Generate the canonical completion report mechanically.
- Upload the report and a real native usage receipt.
- Append
TaskCompletedonly after remote verification. - Close the exact pane, remove transient markers, and clean the worktree.
- Make every phase idempotent under worker or coordinator restart.
Acceptance
A task shown as completed proves:
- configured gates passed;
- the result commit exists;
- the configured remote contains the reported SHA;
- the completion report matches that SHA;
- quota consumption is non-zero when the harness reported usage;
- no managed agent remains attached;
- the worktree is removed or has an explicit cleanup error.
Also prove that a failure between any two phases resumes safely without a duplicate prompt, duplicate commit, duplicate completion event, or lost pane.
7. Milestone 4 — Token-minimal launch and continuity
Work
- Stop duplicating title and description in the launch prompt.
- Extend
TASK.mdwith acceptance criteria, gate profile, and completion signal. - Replace ordinary threshold handoff prompting with a mechanically generated checkpoint.
- Store a compact execution ledger with the handoff artifact.
- On pickup, inject or materialize the bounded continuity fields the successor actually needs.
- Ensure
next,remaining,dead_ends,open_questions, andlearnedare either consumed or removed from the schema; never produce unused context. - Keep semantic handoff prompts only for thrash, blockers, open decisions, and manual requests.
- Add rotation policy configuration, with milestone rotation off in the token-minimal profile.
Acceptance
- The initial task description enters model context once.
- Ordinary threshold rotation requires no extra model turn.
- The successor receives every retained semantic handoff field.
- Pickup verifies
TASK.md, the pushed anchor, and the execution ledger. - A forced rotation continues from the recorded next action without repeating a recorded dead end.
- Usage receipts distinguish productive task tokens from rotation overhead.
8. Milestone 5 — Real project-aware federation
Work
- Define per-machine project checkout configuration.
- Teach workers to select repo, worktree root, remote, and gate profile by
task.project. - Validate that the selected local checkout corresponds to the configured project before creating a pane.
- Account quota by host and harness.
- Run all Git validation and cleanup on the worker that owns the checkout.
- Retire the remaining Design A bridge deployment after confirming there are no consumers.
Acceptance
- One worker can safely execute two configured projects.
- An unknown or mismatched project fails before model launch and consumes zero model tokens.
- A real homesrv/workpc transfer validates the anchor on workpc, pushes it to homesrv, and picks it up from a fresh checkout.
- Coordinator code never runs Git validation against a remote worker path.
9. Milestone 6 — Vikunja as the automatic task source
Work
- Implement Vikunja as a provider-port adapter.
- Map eligible lists/projects, labels, and statuses to Orchestra projects and capabilities.
- Deduplicate ingest using a stable Vikunja external key.
- Poll or subscribe without creating duplicate tasks.
- Reflect completion, failure, and blockers back to Vikunja.
- Mark reflected updates so they cannot loop back into ingestion.
- Retain the Vikunja record as an external view; Orchestra remains canonical for execution state.
Acceptance
- Creating one eligible Vikunja task creates exactly one Orchestra task.
- Repeated polling creates no duplicate.
- Ineligible tasks consume zero model tokens.
- Completion updates the original Vikunja task only after the pushed result is verified.
- Blockers and failures are reflected with actionable evidence.
10. Milestone 7 — Optional writer/reviewer workflow
This stage is optional because review consumes useful model tokens by design. It should add no orchestration-token overhead.
Default policy
- Mechanical tasks: deterministic gates only.
- Normal code tasks: writer plus gates; review is opt-in by project or task.
- High-risk/correlation tasks: writer followed by an independent reviewer.
Work
- Represent implementation and review as explicit workflow stages rather than pretending the writer's first marker means terminal completion.
- Anchor review to the pushed writer SHA.
- Route review by capability and independence policy.
- On acceptance, finalize the original task.
- On requested changes, return the task to implementation with structured findings and the reviewed anchor.
- Bound review loops and escalate after the configured limit.
- Never ask a model to summarize a review already represented by structured findings and Git evidence.
Acceptance
- Reviewer always inspects the exact pushed writer SHA.
- Writer and reviewer cannot accidentally share the same live context when independence is required.
- Accepted review produces one terminal completion.
- Requested changes preserve findings across the next writer lease.
- Review can be disabled without changing the base task lifecycle.
11. Milestone 8 — Operator surface and morning brief
Work
- Separate active work, needs-attention items, and historical E2E residue.
- Lead task details with diagnosis, last activity, pane state, and next safe action.
- Show completion transaction phase and pushed anchor.
- Show worker-local herdr truth separately from coordinator probes.
- Expose real quota windows and uncertainty.
- Keep the morning brief a deterministic projection over events and receipts.
- Add filters for project, source, worker, state, blocker class, and age.
- Add a documented frontend build step that keeps embedded assets synchronized.
Acceptance
- An operator can distinguish queued, running, approval-blocked, retrying, delivery-in-progress, and completed work without reading logs.
- Every enabled control reaches a tested backend action.
- The brief names completed pushed SHAs, failures, blockers, pending approvals, quota consumption, and sync state.
- No model call is used to generate the brief.
12. Live proof sequence
Use disposable tasks and avoid destructive calls against pre-existing panes.
- Deploy matching coordinator and worker revisions.
- Confirm build revisions through the API.
- Register one
test-e2eOpenCode worker. - Run a task lasting longer than one lease-renewal interval.
- Confirm no duplicate pane or prompt.
- Complete it and verify gate, commit, push, report, event, pane closure, and worktree cleanup.
- Force a worker restart during the completion transaction and verify idempotent recovery.
- Force one context rotation and verify successor consumption.
- Force one worker-offline expiry and bounded retry.
- Run a task for a second configured project.
- Ingest one disposable Vikunja task and verify reflection.
- Only after all previous steps pass, queue a low-risk real task.
For each live proof, record:
- task ID and external key;
- coordinator and worker revisions;
- pane and harness session IDs;
- event sequence;
- local and remote Git SHAs;
- gate commands and results;
- usage receipt;
- cleanup result.
13. Required automated coverage
In addition to package tests:
- completion transaction fault-injection tests at every phase boundary;
- lease-renewal, expiry, fencing, and retry tests;
- worker restart with a live session;
- coordinator restart with an active worker;
- project/repository mismatch rejection;
- real handoff consumption, not validation alone;
- non-zero federated quota receipts;
- completion cleanup and remote-SHA verification;
- Vikunja deduplication and reflection-loop prevention;
- an end-to-end worker test that exercises launch through pushed completion;
go test ./...,go build ./..., andgo vet ./...;- frontend build, typecheck, lint, and browser smoke once UI work resumes.
Tests that stop at an isolated package seam do not prove completion. At least one test must traverse the same coordinator → router → worker → herdr adapter → Git → coordinator path used in deployment.
14. Deferred work
Do not prioritize these before the live proof sequence succeeds:
- UI cosmetics beyond diagnosis and safe controls;
- additional notification channels;
- model-generated standups or summaries;
- automatic task decomposition;
- cheap-model subdelegation;
- speculative capability vocabularies;
- schema/backend optimization that is not required by a real run;
- more harnesses before one harness completes the lifecycle reliably.
15. Decisions to ratify
Defaults used by this plan:
- Token goal: zero model-token orchestration overhead; implementation and explicitly requested review remain legitimate token spend.
- Review: opt-in for ordinary code, required only for configured high-risk work.
- Completion signal: a minimal marker; the worker authors the report.
- Rotation: no model-authored handoff for ordinary context thresholds.
- Milestone rotation: disabled in the token-minimal profile.
- Affinity: hard; a task waits rather than running on an unconfigured machine or checkout.
- Delivery: a verified remote SHA is mandatory before
TaskCompleted.
Changing any of these defaults should update this file and the binding spec before implementation.