535 lines
19 KiB
Markdown
535 lines
19 KiB
Markdown
# 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
|
||
|
||
```text
|
||
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 `1ca9d64` passes `go test ./...`, `go build ./...`, and
|
||
`go vet ./...`.
|
||
- The coordinator reports 28 historical tasks: 22 blocked, 5 completed, and
|
||
1 failed, with no queued or leased work.
|
||
- One `workpc-opencode` worker is online, but its installed binary was built
|
||
from `95a96d8` with 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.md` and 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:
|
||
|
||
```text
|
||
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:
|
||
|
||
1. append one observable release/failure event;
|
||
2. route that event through the normal retry accounting path;
|
||
3. command the owning worker to close the exact pane when reachable;
|
||
4. retain last-pane evidence even when cleanup cannot be confirmed;
|
||
5. 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:
|
||
|
||
```text
|
||
(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-e2e` cannot receive a `correx` lease.
|
||
- Restarting the coordinator preserves worker identity and pending commands.
|
||
- `go test ./...`, `go build ./...`, and `go 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`, or
|
||
`unknown`.
|
||
|
||
---
|
||
|
||
## 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 `TaskCompleted` only 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.md` with 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`, and `learned`
|
||
are 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.
|
||
|
||
1. Deploy matching coordinator and worker revisions.
|
||
2. Confirm build revisions through the API.
|
||
3. Register one `test-e2e` OpenCode worker.
|
||
4. Run a task lasting longer than one lease-renewal interval.
|
||
5. Confirm no duplicate pane or prompt.
|
||
6. Complete it and verify gate, commit, push, report, event, pane closure, and
|
||
worktree cleanup.
|
||
7. Force a worker restart during the completion transaction and verify
|
||
idempotent recovery.
|
||
8. Force one context rotation and verify successor consumption.
|
||
9. Force one worker-offline expiry and bounded retry.
|
||
10. Run a task for a second configured project.
|
||
11. Ingest one disposable Vikunja task and verify reflection.
|
||
12. 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 ./...`, and `go 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:
|
||
|
||
1. **Token goal:** zero model-token orchestration overhead; implementation and
|
||
explicitly requested review remain legitimate token spend.
|
||
2. **Review:** opt-in for ordinary code, required only for configured
|
||
high-risk work.
|
||
3. **Completion signal:** a minimal marker; the worker authors the report.
|
||
4. **Rotation:** no model-authored handoff for ordinary context thresholds.
|
||
5. **Milestone rotation:** disabled in the token-minimal profile.
|
||
6. **Affinity:** hard; a task waits rather than running on an unconfigured
|
||
machine or checkout.
|
||
7. **Delivery:** a verified remote SHA is mandatory before `TaskCompleted`.
|
||
|
||
Changing any of these defaults should update this file and the binding spec
|
||
before implementation.
|
||
|