Skip to main content

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

  1. Decide whether the work belongs to a Program Goal or a standalone goal.
    • Program layer: roadmap PHASE-XX work, dispatch via the Program Controller.
    • Standalone: a bounded outcome that doesn't fit the IMP chain — docs, repairs, audits.
  2. Copy a goal template (goals/ASF50_IMP_11_IMPLEMENTATION_001/GOAL_RECORD.yaml for an IMP-shaped goal; goals/ASF50_DOCS_PORTAL_001/GOAL_RECORD.yaml for a docs-shaped goal).
  3. Replace every required field. Validate against goal_registry.REQUIRED_FIELDS and PROGRAM_REQUIRED_FIELDS (if Program).
  4. Write the CONTEXT.yaml and PROMPT.md.
  5. Commit the goal on a bounded branch.
  6. Run .\scripts\goal-runner\goal-run.ps1 -GoalId <GOAL_ID> -RuntimeRoot … -DryRun to materialize and inspect.
  7. If the dry-run succeeds, remove -DryRun and 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

TriggerOwner action
MERGE_APPROVAL gate at exact headApprove in GitHub UI.
TAG_APPROVAL gate at exact headApprove in GitHub UI or via signed ticket.
RELEASE_APPROVAL gateApprove via GitHub review or signed ticket.
PRODUCTION_PROMOTION gateSign the production ticket offline; submit to the orchestrator.
PAID_MODEL_DISPATCH_APPROVALApprove via goal-gate.ps1 -Action approve -Source owner-cli ….
PHASE_00_RESUME_APPROVALApprove via GitHub review or signed ticket.
Architectural ambiguityOwner supplies the decision; orchestrator records it.
External credential decisionOwner 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 main directly.
  • 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:

  1. Open the PR in GitHub.
  2. Read the diff carefully.
  3. Submit an approving review (gh pr review --approve or the GitHub UI button).
  4. The orchestrator ingests the review via ingest-github-review.ps1 and materializes the gate.
  5. The autopilot resumes automatically.

If you reject the PR, the orchestrator routes back to PLANNER with next_action_policy.on_repair.

Inspecting current status

NeedCommand
Program-level snapshotprogram-status.ps1
Per-goal statusgoal-status.ps1 -GoalId …
Open gatesgoal-gate.ps1 -Action list -RuntimeRoot …
Gate detailgoal-gate.ps1 -Action inspect -GateId …
Doctor / split-brain checkgoal-doctor.ps1 -RuntimeRoot …
Receiptsinspect <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:

  1. A real human gate (listed above).
  2. A canonical architecture/governance decision it cannot resolve.
  3. 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

  1. Inspect the CI run: .github/workflows/ history.
  2. Determine whether the failure is deterministic or flaky.
  3. If deterministic: fix in the same bounded branch; push; the orchestrator re-runs.
  4. If flaky: re-run via gh run rerestart <run-id>; the orchestrator resumes.
  5. If the failure is a CI governance policy violation, open a repair goal.

Recovering after agent failure

  1. Read the task receipt in <worktree>/.goal-runner/receipts/.
  2. Determine whether the failure is an adapter failure (timeout, network) or a logic failure.
  3. Re-dispatch via goal-run.ps1 -GoalId …; the orchestrator will re-issue the same task.
  4. If the task fails three times, the orchestrator transitions the goal to REPAIR_REQUIRED and routes to a repair goal.

Handling subject drift

If the audit worktree's HEAD no longer matches audit_subject_sha:

  1. Stop all dispatches.
  2. Report the identity discrepancy.
  3. Request explicit owner authorization to re-home.
  4. Do not silently re-home.

Handling a stale gate

A gate is stale when:

  • Its subject_sha no longer matches the runtime HEAD.
  • Its max_dispatches is exhausted.
  • Its ticket_id has 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

  1. Acknowledge the deviation in the current goal's evidence.
  2. Open a bounded repair goal to address the root cause.
  3. Increment current_cycle_deviation_count via the orchestrator.
  4. 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.