# Conductor protocol — poor-man orchestration loop How the stack orchestrates headless pi workers to do work on itself. ## Role contracts Role authority is declared in role contracts, one file per role, under `roles/` (e.g. `roles/conductor-policy.json`). The repository root holds only first-class, bootstrap-required configuration; role contracts are tracked, versioned files whose changes arrive as reviewed commits. ## Roles | Role | Runs where | Powers | Never has | |---|---|---|---| | **Conductor** | host (assistant or owner) | git (clone/commit/push), task dispatch, review, verification suites, Gitea | nothing new | | **Worker** | container (headless pi via `scripts/run-task.sh`) | read/write/edit/bash inside its workspace; persistent session on request | git credentials, docker socket, host filesystem | ## The loop 1. **Decompose**: conductor turns a goal into worker tasks small enough to specify completely in one prompt (file paths, acceptance criteria, style constraints, verification the worker can run itself, e.g. `node --check`). 2. **Mirror**: conductor maintains the repo clone at `/workspaces/stack-repo` (host-side git; workers see it read-write through their workspace mount). 3. **Dispatch**: `scripts/run-task.sh run ` — worker edits the clone. Session name `worker-` keeps continuity across refinement rounds. 4. **Extract**: `git -C diff > patch` — the worker's entire output is a reviewable diff. Run record (result.json, stderr.txt) is the receipt. 5. **Review**: conductor reads the diff line by line. Bad output → refine the prompt, re-dispatch (same session: "your patch had these problems…"). 6. **Integrate**: conductor applies the patch to the real repo, runs the full suites, commits and pushes. Suites failing → revert apply, back to step 5. 7. **Record**: update CURRENT.md, BUILD-LOG, close the Gitea issue. ## Guardrails - Workers never receive credentials; they never run git; they never leave the workspace (container is the boundary; tools allowlist is the gate). - Every worker diff is reviewed by the conductor before integration. No auto-apply. (Auto-apply would be a capability-policy decision for later.) - Verification is mechanical: suites + `node --check` / `bash -n` gates. - Recursive decomposition = "fail → smaller task", never "hope." ## Landing approved work A stack coder pushes `work/vikunja-

-` to the working repository, the reviewer approves a commit on it, and the PM raises a `git.merge.protected` decision for the human. After the human resolves it with the merge option, the conductor runs: ```bash scripts/land-work.sh --dry-run scripts/land-work.sh ``` The tool binds the commit to what was reviewed and decided. It reads the decision, its raise and the latest verdict from the bus database read-only, requires the work ref to be at the approved commit, squashes the reviewed diff onto `refactor` in a detached worktree, checks the patch-id, runs the full gate and commits once, locally. It refuses work that adds a file at the repository root, in a new top-level directory, or under `src/` or `v1/`. Each refusal names its reason (`docs/TOOLS.md`). Don't work around one; fix the cause or go back to the PM. The conductor then reviews the commit, pushes it as a separate act and sends the PM the line the tool printed. Only `refactor` lands this way. Merges to `next` or `main`, re-pins and restarts keep their own authority, and no stack role runs this tool. ## Worker task template ```json { "taskVersion": 1, "id": "t-worker-", "prompt": "", "workspace": "stack-repo", "capabilities": { "tools": ["read", "write", "edit", "bash"] }, "session": "worker-1", "timeoutSeconds": 600 } ```