Operator Handbook
This handbook is the day-to-day manual for ASF50 operators. It assumes you have read Getting Started and Concepts → Goals.
Starting a new goal
- Decide whether the work belongs to a Program Goal or a standalone goal.
- Program layer: roadmap
PHASE-XXwork, dispatch via the Program Controller. - Standalone: a bounded outcome that doesn't fit the IMP chain — docs, repairs, audits.
- Program layer: roadmap
- Copy a goal template (
goals/ASF50_IMP_11_IMPLEMENTATION_001/GOAL_RECORD.yamlfor an IMP-shaped goal;goals/ASF50_DOCS_PORTAL_001/GOAL_RECORD.yamlfor a docs-shaped goal). - Replace every required field. Validate against
goal_registry.REQUIRED_FIELDSandPROGRAM_REQUIRED_FIELDS(if Program). - Write the
CONTEXT.yamlandPROMPT.md. - Commit the goal on a bounded branch.
- Run
.\scripts\goal-runner\goal-run.ps1 -GoalId <GOAL_ID> -RuntimeRoot … -DryRunto materialize and inspect. - If the dry-run succeeds, remove
-DryRunand let the orchestrator dispatch.
Giving a master goal
ASF50 accepts a single bounded master-goal prompt and treats it as the dispatch record. The recommended template:
GOAL: <one-sentence bounded outcome>
SUCCESS_CRITERIA:
- <measurable item 1>
- <measurable item 2>
BOUNDARIES:
- <what may be modified>
- <what may not be modified>
HUMAN_GATES:
- <scope 1>
- <scope 2>
AUTOPILOT_EXPECTATION:
- <single-agent sequential, no intermediate prompts>
TERMINAL_CONDITION: <single-line terminal assertion>
Place the prompt in goals/<GOAL_ID>/PROMPT.md. The orchestrator reads it as the dispatch record.
How autopilot works
The autopilot is single-agent sequential by default. The orchestrator dispatches one role at a time, waits for the role's adapter to return, writes a receipt, and advances the state. There is no parallel Builder, no parallel Auditor, no parallel Repairer.
The autopilot stops when:
- A gate requires an external owner decision (PR review, signed ticket).
- A real architecture/governance decision cannot be resolved from current conventions.
- The goal reaches a terminal state.
When owner input is required
| Trigger | Owner action |
|---|---|
MERGE_APPROVAL gate at exact head | Approve in GitHub UI. |
TAG_APPROVAL gate at exact head | Approve in GitHub UI or via signed ticket. |
RELEASE_APPROVAL gate | Approve via GitHub review or signed ticket. |
PRODUCTION_PROMOTION gate | Sign the production ticket offline; submit to the orchestrator. |
PAID_MODEL_DISPATCH_APPROVAL | Approve via goal-gate.ps1 -Action approve -Source owner-cli …. |
PHASE_00_RESUME_APPROVAL | Approve via GitHub review or signed ticket. |
| Architectural ambiguity | Owner supplies the decision; orchestrator records it. |
| External credential decision | Owner supplies the credential via a non-ASF50 channel. |
What the owner should NOT do
- Do not direct-edit
goal-state.sqlite3. - Do not push to
maindirectly. - Do not click Merge in the chat.
- Do not embed a private key anywhere in the canonical repository, runtime, evidence, chat, or docs.
- Do not bypass the deterministic backend with ad-hoc shell pipelines.
- Do not allow Builder/Auditor/Repairer roles to share context across dispatch boundaries.
- Do not authorize retroactively.
Responding to GitHub review gates
When the orchestrator stops at a MERGE_APPROVAL gate:
- Open the PR in GitHub.
- Read the diff carefully.
- Submit an approving review (
gh pr review --approveor the GitHub UI button). - The orchestrator ingests the review via
ingest-github-review.ps1and materializes the gate. - The autopilot resumes automatically.
If you reject the PR, the orchestrator routes back to PLANNER with next_action_policy.on_repair.
Inspecting current status
| Need | Command |
|---|---|
| Program-level snapshot | program-status.ps1 |
| Per-goal status | goal-status.ps1 -GoalId … |
| Open gates | goal-gate.ps1 -Action list -RuntimeRoot … |
| Gate detail | goal-gate.ps1 -Action inspect -GateId … |
| Doctor / split-brain check | goal-doctor.ps1 -RuntimeRoot … |
| Receipts | inspect <worktree>/.goal-runner/receipts/ |
Resuming a stopped goal
# Resume a paused goal
.\scripts\goal-runner\goal-resume.ps1 -GoalId <GOAL_ID> -RuntimeRoot …
# Cancel a goal
.\scripts\goal-runner\goal-cancel.ps1 -GoalId <GOAL_ID> -RuntimeRoot …
The orchestrator re-reads the next_actions record and dispatches the next task. Resuming a goal that has not been paused (no PAUSE state) is rejected.
Detecting stale runtime/path mistakes
Run:
.\scripts\goal-runner\goal-doctor.ps1 -RuntimeRoot …
If the runtime root is split-brain, the doctor fails closed and reports the exact identity mismatch.
Recognizing real blockers vs agent over-stop
The agent stops for one of:
- A real human gate (listed above).
- A canonical architecture/governance decision it cannot resolve.
- A genuine external action it cannot perform.
The agent must not stop for:
- A "should I commit?" prompt — commits are part of the bounded scope.
- A "what should the sidebar order be?" prompt — make the decision.
- A "what colour should the diagram be?" prompt — pick reasonable defaults.
- A "should I open the PR?" prompt — opening the PR is part of the bounded scope.
If the agent stops for one of the latter, that is an over-stop and must be reported.
Recovering after CI failure
- Inspect the CI run:
.github/workflows/history. - Determine whether the failure is deterministic or flaky.
- If deterministic: fix in the same bounded branch; push; the orchestrator re-runs.
- If flaky: re-run via
gh run rerestart <run-id>; the orchestrator resumes. - If the failure is a CI governance policy violation, open a repair goal.
Recovering after agent failure
- Read the task receipt in
<worktree>/.goal-runner/receipts/. - Determine whether the failure is an adapter failure (timeout, network) or a logic failure.
- Re-dispatch via
goal-run.ps1 -GoalId …; the orchestrator will re-issue the same task. - If the task fails three times, the orchestrator transitions the goal to
REPAIR_REQUIREDand routes to a repair goal.
Handling subject drift
If the audit worktree's HEAD no longer matches audit_subject_sha:
- Stop all dispatches.
- Report the identity discrepancy.
- Request explicit owner authorization to re-home.
- Do not silently re-home.
Handling a stale gate
A gate is stale when:
- Its
subject_shano longer matches the runtime HEAD. - Its
max_dispatchesis exhausted. - Its
ticket_idhas already been consumed.
The orchestrator refuses to consume stale gates. Re-issue the gate with a fresh subject_sha after the owner re-bases the work.
Handling a deviation
- Acknowledge the deviation in the current goal's evidence.
- Open a bounded repair goal to address the root cause.
- Increment
current_cycle_deviation_countvia the orchestrator. - Do not retroactively authorize.
Terminating or abandoning a goal safely
.\scripts\goal-runner\goal-cancel.ps1 -GoalId <GOAL_ID> -RuntimeRoot …
The goal transitions to CANCELED. All open gates are released. The contract remains in goals/ for audit; it is not deleted.
Determining that a goal is truly terminal
A goal is terminal when its state matches one of required_terminal_states AND every evidence requirement is satisfied AND every acceptance gate is closed. The orchestrator refuses to re-dispatch a terminal goal; revision requires a bounded repair.