AGENT_SETUP — the delegated installation runbook
AGENT_SETUP — the delegated installation runbook
Audience: an AI agent. If you are a human reading this: don’t install by hand — paste the wizard’s “agent prompt” (or this file’s URL) to your own AI agent (Claude Code, Codex, or any capable CLI agent) and let it run this runbook. You will be needed exactly twice, at the steps marked [HUMAN].
Audience contract (for the agent executing this):
- Execute steps in order, 0 → 9. Every step ends with a Verify block — do not proceed on a failed verify. If the same verify fails twice, stop and report the step number and the failing output to your operator.
- Interrupt your operator only at [HUMAN] steps. Collect any other
questions and ask them in one batch at the next [HUMAN] step (respect
preferences.communication.batch_questions). - Talk to your operator in their language (
preferences.language.primary); keep commands and file contents verbatim. - Never print, log, or commit secret values (App private key, receipt key).
Never commit anything under
config/to a public repo.
If your session dies mid-install — this runbook is resume-safe. On entry or re-entry, do not assume a fresh install. Walk the steps in order and run each step’s Verify block first: skip any step whose Verify already passes, and resume at the first one that fails. The steps are idempotence-checked — a Step 1 that finds the governance repo already created, or a Step 4 that finds the App already registered, is a resume signal, not an error to retry (blindly re-creating either is the one reliable way to make a real mess). No state file is needed: the deployed GitHub state — the repo, its secrets and
MERGE_GATE_MERGE_ENABLEDvariable, the labels, the workflow, and the materialized agent kit — is your checklist.
Inputs you need before step 0 — from the wizard zip, or collected by you in Interview Mode (next section) if the operator prepared nothing:
| Input | Example |
|---|---|
| Operator’s GitHub login | <login> |
| Repo(s) to supervise | <login>/<project> |
| The 6 config files | owner / projects / env / skills / agent_registry / preferences .yml |
| Runner tier decision | actions-free (default) or self-hosted |
Where gh is authenticated |
as the operator’s account |
Interview Mode — conversational install, no wizard required
If your operator arrives with nothing but this runbook (no wizard zip, no config), you conduct the setup interview yourself, then continue to step 0. Rules of the interview:
- Speak the operator’s language. Detect it from how they talk to you; everything below is your script’s content, not its wording.
- One batched round. Ask all questions in a single message, numbered, each with its default in brackets. Accept “전부 기본값으로” / “defaults are fine” as a complete answer. Follow up only on genuinely missing essentials (login, repo).
- Offer defaults, never invent. Unanswered optional fields are omitted from the YAML, not guessed.
- Close the loop. Before writing files, reflect a 5-line summary back (“I will supervise X for account Y, ticking every 30 min on GitHub Free, agents will speak Korean and bring you options-menus, quiet 23:00–08:00 — correct?”) and wait for a yes.
The interview (map answers 1:1 onto the schemas in schemas/
and the shapes in examples/solo-developer/config/):
- GitHub login →
owner.yml github_login(verify it matchesgh auth status). - Which repo(s) should be protected? →
projects.yml supervised_repos; governance repo will be<login>/multiagent-protocol-gov(step 1). - Do those repos have CI (automated checks)?
- yes → ask which check names must pass →
env.yml required_checks - no → offer the choice honestly: add a minimal sanity workflow
(recommended; you will create it in step 5) or set
allow_no_ci: true(gate merges without CI evidence — say that plainly).
- yes → ask which check names must pass →
- Runner [GitHub Actions Free, ticking every 30 min]: fine for almost
everyone starting out; 5-minute reactions need a self-hosted runner
(guide) →
env.yml runner_tier. - Working preferences →
preferences.yml(this is where the installation becomes theirs):- language your agents should use with them [their language]
- written reports [same / english / bilingual]
- report style [conclusion first / detailed]
- decisions as [2–4 labeled options with pros+cons / plain questions]
- collect questions and ask together? [yes]
- autonomy [cautious = confirm outward/irreversible things · standard = follow the quadrants · delegating = proceed and report]
- quiet hours + timezone [none]
- taste ledger seeds: “What do you keep repeating to your AI agents? Give me 1–5 one-liners; every agent will follow them from now on.” [skip]
- vocabulary: “Any nicknames or shorthand I should understand — project names, terms?” [skip]
- Skills [defaults]: keep built-in defaults unless they ask.
Then: write the six files, validate exactly as step 2 does, show the summary, get the yes — and run steps 0–9. At every [HUMAN] step, give click-by-click directions in their language and wait; never rush a human step.
Bootstrap prompt (this is all an operator needs to paste to their agent to start a conversational install — the runbook it fetches is resume-safe, so an interrupted or restarted session just re-reads it and continues from the first step whose Verify fails, never from zero):
You are my AI coding agent. Set up multiagent-protocol for me.
Fetch and follow: https://raw.githubusercontent.com/donggun-jung/multiagent-protocol/main/docs/agent-setup/AGENT_SETUP.md
I have not prepared any config. Start with the runbook's Interview Mode:
interview me in my own language (one batched round, offer defaults), build
the six config files from my answers, confirm the summary back to me, then
execute steps 0-9. Involve me only at the [HUMAN] steps, and when we reach
them, walk me through the clicks step by step.
Terminology: the governance repo is the private copy of this framework
that holds the operator’s config and runs the bot. We name it
<login>/multiagent-protocol-gov throughout.
Step 0 — Preflight
gh auth status # must show the operator's login, with repo+workflow scopes
python3 --version # 3.10+
git --version
Verify: all three commands succeed; gh auth status shows the intended
account. If gh is authenticated as a different account, stop — the gate’s
label/approval checks are tied to the operator’s identity.
Step 1 — Create the private governance repo (mirror, NOT fork)
Why not “Fork”? GitHub cannot make a fork of a public repo private, and the governance repo must be private because it will carry the operator’s identity and repo list. A mirror gives you a private, disconnected copy with full history, plus an
upstreamremote for updates.
gh repo create <login>/multiagent-protocol-gov --private \
--description "multiagent-protocol governance (private config layer)"
# Disable Actions BEFORE the mirror push: the mirror carries upstream's
# tags (v0.2.0, v0.9.9, ...) and pushing them would otherwise fire
# release.yml in YOUR repo (publishing a container image to your GHCR)
# plus a doomed Pages deploy and a test-matrix burst.
gh api -X PUT repos/<login>/multiagent-protocol-gov/actions/permissions \
-F enabled=false
git clone --bare https://github.com/donggun-jung/multiagent-protocol.git /tmp/map-mirror
git -C /tmp/map-mirror push --mirror https://github.com/<login>/multiagent-protocol-gov.git
rm -rf /tmp/map-mirror
git clone https://github.com/<login>/multiagent-protocol-gov.git
cd multiagent-protocol-gov
git remote add upstream https://github.com/donggun-jung/multiagent-protocol.git
# Re-enable Actions now that the burst window is over, then switch off the
# inherited workflows a private deployment does not want (Pages deploy fails
# on a private Free repo; keep tests.yml only if your minutes allow).
gh api -X PUT repos/<login>/multiagent-protocol-gov/actions/permissions \
-F enabled=true -F allowed_actions=all
gh workflow disable docs.yml -R <login>/multiagent-protocol-gov || true
Verify: gh repo view <login>/multiagent-protocol-gov --json visibility
-q .visibility prints PRIVATE; git remote -v shows origin (gov) and
upstream (framework); gh api repos/<login>/multiagent-protocol-gov/branches/main -q .name
prints main (the mirror actually arrived).
Later upgrades (replaces the fork “Sync” button):
git fetch upstream && git merge upstream/main — your config/ and your
deployed workflow are yours; if .github/workflows/bot-cron.yml conflicts,
keep your version (step 3 explains why it differs from upstream’s).
Step 2 — Write and validate the config layer (6 files)
Place the wizard-generated files under config/. If the operator skipped the
wizard, compose the files yourself: start from
examples/solo-developer/config/, follow the
schemas in schemas/, and interview the operator in one
batched question set (login, repos, CI status, runner tier, and the
preference fields of schemas/preferences.schema.json).
git add -f config/ # config/ is git-ignored upstream; -f is required and correct here
python3 -m venv .venv && . .venv/bin/activate # avoids PEP 668 "externally managed" failures
python3 -m pip install -e . --quiet
python3 -m multiagent_protocol check-config
python3 - <<'EOF'
import json, yaml, jsonschema
jsonschema.validate(yaml.safe_load(open("config/preferences.yml")),
json.load(open("schemas/preferences.schema.json")))
print("preferences OK")
EOF
git commit -m "setup: initial config layer" && git push
(Add your own Agent-* trailers to every commit you make in this runbook —
the formats are in templates/adopter/AGENTS.md §2.
Use Task-Ref: none during setup.)
Verify: check-config prints config OK with the operator’s login,
governance repo <login>/multiagent-protocol-gov, and the supervised repos;
the preferences check prints preferences OK.
Step 3 — Deploy the cron workflow
Upstream’s .github/workflows/bot-cron.yml is dispatch-only on purpose
(the public framework repo must not run a merge engine). Your deployment
replaces it with the wired example:
cp deploy/bot-cron.example.yml .github/workflows/bot-cron.yml
Pick the cadence inside the file (CRON: marker) using honest arithmetic —
a tick costs roughly 30–60 s of runner time:
| Cadence | Runner minutes/month | Fits GitHub Free (2,000 min, private)? |
|---|---|---|
*/5 |
~4,300–8,600 | No — self-hosted only |
*/15 |
~1,400–2,900 | Borderline — one repo, nothing else on Actions |
*/30 |
~720–1,440 | Yes (default for actions-free) |
| hourly | ~360–720 | Yes, with slower reaction time |
No edit is needed for the merge switch: the file already defaults to observe
mode via the vars.MERGE_GATE_MERGE_ENABLED || 'false' fallback — do NOT
hardcode 'false' there, or step 8’s variable flip will have no effect.
Commit and push.
GitHub reality check:
scheduletriggers can lag minutes-to-tens-of-minutes at peak, and GitHub disables schedules after ~60 days without repo activity. The workflow file’sworkflow_dispatchtrigger is the manual backstop; if you need reliable 5-minute ticks, readdocs/guide/self-hosted-runner.md.
Verify: gh workflow list -R <login>/multiagent-protocol-gov shows
bot-cron as active, and the pushed file contains your chosen cron line.
Step 4 — GitHub App + secrets [HUMAN]
The bot acts through a GitHub App the operator owns. Registration takes clicks in the GitHub UI — this is one of the two human steps.
- Build the registration URL: open the wizard’s Step “GitHub App” (or run its
logic —
docs/wizard/js/wizard.js,buildManifestUrl) with the operator’s values. Present the URL to the operator. - [HUMAN] Operator: open the URL → “Create GitHub App” → on the App page
Install App → choose Only select repositories → select the
governance repo and every supervised repo → then Generate a private
key (a
.pemdownloads). Tell the agent the App ID (a number) and the.pemfile’s local path. (If the manifest URL flow fails in your browser, register manually at Settings → Developer settings → GitHub Apps with the permission set listed indeploy/bot-cron.example.yml’s header comment.) - Agent — store credentials as Actions secrets, generate the receipt key, then remove the PEM:
gh secret set MERGE_GATE_APP_ID -R <login>/multiagent-protocol-gov --body "<app-id>"
gh secret set MERGE_GATE_PRIVATE_KEY -R <login>/multiagent-protocol-gov < "<path-to-pem>"
openssl rand -hex 32 | gh secret set MERGE_GATE_RECEIPT_KEY -R <login>/multiagent-protocol-gov
rm -P "<path-to-pem>" 2>/dev/null || rm "<path-to-pem>"
MERGE_GATE_RECEIPT_KEY is not optional in spirit: without it, approval
receipts and inbox bodies fall back to author-only integrity, meaning a leaked
App token could forge approvals. Set it now, never print it.
Verify: gh secret list -R <login>/multiagent-protocol-gov shows all
three MERGE_GATE_* secrets. The App’s installation page lists governance +
all supervised repos.
Step 5 — Prepare each supervised repo
For every <login>/<project> in config/projects.yml:
gh label create ready-to-merge -R <login>/<project> \
--description "multiagent-protocol: done and verified — bot may merge" \
--color 0e8a16 || true # exists = fine
gh api repos/<login>/<project> --jq .allow_squash_merge # bot merges via squash
# if false:
gh api -X PATCH repos/<login>/<project> -F allow_squash_merge=true
CI decision (batch this question if it wasn’t answered in the inputs): the gate’s CI condition is fail-closed — a repo with zero checks never auto-merges. Two honest options:
- Recommended: add a minimal sanity workflow to the supervised repo (an 8-line “the tree parses” check beats no gate signal at all), or
- set
allow_no_ci: trueinconfig/env.yml(opt-in vacuous CI condition), and record that the operator chose it.
Verify: label exists, squash allowed, and either at least one workflow
exists in the supervised repo or env.yml carries allow_no_ci: true
(re-run check-config after env changes).
Step 6 — Install the agent kit into each supervised repo
Copy templates/adopter/AGENTS.md and
templates/adopter/CLAUDE.md to the
supervised repo root, filling every {{PLACEHOLDER}}
(table in templates/adopter/README.md):
{{REPO_NAME}},{{AGENT_TOOLS}},{{MACHINE_HANDLE}}— from config{{TICK_MINUTES}}— the cadence you chose in step 3{{PREFERENCES_BLOCK}}— renderconfig/preferences.ymlas a bullet list: language + report style + decision format + autonomy profile + quiet hours, then everytaste_ledgerrule (dated), thenvocabularyas “term — meaning”.
Commit on a branch, open a PR titled setup: install multiagent-protocol
agent kit, and merge it yourself — the gate is still in observe mode, and
this bootstrap PR is the last thing that merges without it. From step 8 on,
everything (including you) goes through the gate.
Re-run this step whenever config/preferences.yml changes — the materialized
block is a copy, and stale copies teach agents last month’s preferences.
Verify: both files exist at the supervised repo root on main with zero
remaining {{ markers.
Step 7 — First tick (observe mode)
gh workflow run bot-cron.yml -R <login>/multiagent-protocol-gov
RUN_ID=$(gh run list -R <login>/multiagent-protocol-gov --workflow bot-cron.yml --limit 1 --json databaseId -q '.[0].databaseId')
gh run watch "$RUN_ID" -R <login>/multiagent-protocol-gov --exit-status
gh run view "$RUN_ID" -R <login>/multiagent-protocol-gov --log | grep -Ei "tick complete|supervised="
Verify (two lines, exactly these shapes): the watch exits 0 (run
success), and the grep shows BOTH a config: … supervised=N … line with
N ≥ 1 AND a tick complete: {...} line (a metrics dict — it does not repeat
the repo count; the supervised= line carries that). Missing secrets or
invalid config fail loudly here by design — if the run is red, read the
log’s first error, fix, and re-run this step. Then run
python -m multiagent_protocol verify-setup — every check must be PASS or an
expected SKIP (secrets can’t be read via the App token; confirm the three
names with gh secret list). Details: VERIFY_SETUP.md.
Step 8 — Go-live [HUMAN]
[HUMAN] Operator: confirm you have seen the observe-mode tick and want the bot to actually merge. This is the moment the gate becomes real.
gh variable set MERGE_GATE_MERGE_ENABLED -R <login>/multiagent-protocol-gov --body true
Verify: gh variable list -R <login>/multiagent-protocol-gov shows
MERGE_GATE_MERGE_ENABLED = true.
Step 9 — End-to-end proof + handover
In one supervised repo, author a trivial change the disciplined way:
branch → commit carrying all five Agent-* trailers → PR → apply
ready-to-merge. Then either wait one cadence interval or dispatch a tick
manually (step 7 command).
Verify (the product moment): the bot merges the PR (squash) — or posts a
diagnostic comment listing exactly what it still wants. A diagnostic comment
is a pass for this test if fixing its items leads to a merge on the next
tick. Finish with
python -m multiagent_protocol verify-setup --e2e --login <login> — under
--e2e a stale or missing tick hard-FAILs; clear every FAIL before treating
the installation as live.
Second half — rehearse the stop (RECOMMENDED, skippable) [HUMAN]
The clean merge above was the product moment #1: good work flowing through.
This is the product moment #2 — feel the stop, the half you are actually
installing the gate for. It is safe to skip on a rushed install, but running it
once is how the operator learns to recognize and answer a real parked decision.
The plan: author one change the bot must route to the owner (Quadrant D —
irreversible + critical), watch the decision:pending-owner issue open, and
reject it — leaving main untouched.
1 — Author an intentionally-critical PR. In the same supervised repo, on a
new branch, add a throwaway workflow file whose only job is to touch the
always-Quadrant-D .github/workflows/ path (the one critical path present in
essentially every repo):
git checkout -b gate-rehearsal-d
mkdir -p .github/workflows
cat > .github/workflows/zzz-gate-rehearsal.yml <<'YML'
# multiagent-protocol go-live rehearsal — throwaway, never merged.
# Exists only to touch the always-Quadrant-D .github/workflows/ path so the bot
# opens a real decision:pending-owner issue. Deleted at the end of this step.
on: workflow_dispatch # manual-only: this file never runs on its own
jobs:
noop:
runs-on: ubuntu-latest
steps:
- run: echo "rehearsal only — this PR is meant to be rejected"
YML
git add .github/workflows/zzz-gate-rehearsal.yml
git commit # carry all five Agent-* trailers, exactly as in the clean-merge run
git push -u origin gate-rehearsal-d
gh pr create --fill # then apply the ready-to-merge label — same discipline as above
Do not rehearse D with a src/ edit: the classifier reads that as Quadrant
B (reversible + critical) and auto-merges it with no pause
(classifier_path_default.py: .github/workflows/ is in ALWAYS_D_PREFIXES
→ D, while src/ is a plain CRITICAL_PREFIXES → B). Pushing a file under
.github/workflows/ requires your gh token to carry the workflow scope —
Step 0 verified this.
2 — Make the bot see it. Dispatch a tick and watch it (Step 7’s commands):
gh workflow run bot-cron.yml -R <login>/multiagent-protocol-gov, then the
gh run watch from Step 7. Don’t wait for the schedule — dispatch manually
between every phase (the default */30 cadence is too slow to rehearse
against).
Verify: a decision:pending-owner issue is now open in the governance
repo (<login>/multiagent-protocol-gov → Issues) — not in the supervised
repo. This is the [HUMAN] hand-off point.
3 — [HUMAN] Answer it — reject. Walk the operator to that issue in the
governance repo’s Issues tab and have them comment /reject (or react 👎)
on it. This is the stop you installed the gate for: nothing merged, and nothing
will, until the owner answers.
4 — Let the verdict apply. Dispatch a second tick (same gh workflow run
command).
Verify: the resolver closed both the PR and the issue — the issue is
labeled decision:rejected and the PR is closed with a /reject comment
(verdict rejected, action closed-pr). main in the supervised repo is
unchanged.
5 — Clean up. Delete the throwaway branch —
git push origin --delete gate-rehearsal-d (and drop the local branch). Because
the PR was rejected and never merged, the workflow file never reached main;
the repo is left exactly as it was before the rehearsal.
Why reject, and not approve? 👍 / /approve A would instead label the PR
decision:approved-A and merge it on the next tick (a 3-tick loop:
open → label → merge). But every Quadrant-D path is critical by construction,
so an approved throwaway would land on your real main — and then removing it
is itself another Quadrant-D change that re-opens the inbox. Rejecting leaves
main pristine in two ticks. That asymmetry — cheap to reject, deliberately
heavy to approve-then-undo — is the design, not an accident (see
docs/concepts/four-quadrants.md § “Why this
design”).
Close by giving the operator a short handover in their language:
- What is now true: every merge to
maininpasses the gate; irreversible/critical changes stop and wait for you. - Your two controls: the
decision:pending-ownerissues (answer 👍 or/approve//reject) — and theready-to-mergelabel discipline your agents follow. - Emergency stop: set
MERGE_GATE_MERGE_ENABLEDtofalse(instant observe mode) or disable thebot-cronworkflow. - Upgrades:
git fetch upstream && git merge upstream/mainin the governance repo (your config and workflow survive; conflicts on the workflow file: keep yours). - Preferences: edit
config/preferences.yml, then re-run step 6 so your repos’ agent kits pick it up. - Session-start ritual: run
python -m multiagent_protocol verify-setupnow and then (your agents do it too, per the kit); ifgate-livenessreports the gate may be asleep,gh workflow enable bot-cron.ymlbrings it back before you rely on it.
Step 10 — Offboarding (optional)
Removing the gate should be as disciplined as installing it. This step is keyed to the install steps in reverse, so it doubles as cleanup for a partial install: if you stopped at step N, start the teardown at the entry for step N and work downward. Read both paths below before you start — the default preserves your audit trail; the full purge destroys it.
First, the reversible stop (not a teardown). The instant way to make the bot safe is the Step 8 switch — no removal required:
gh variable set MERGE_GATE_MERGE_ENABLED -R <login>/multiagent-protocol-gov --body false
The bot drops back to observe mode on the next tick (classifies and audits,
merges nothing). If you only want to pause the gate, stop here — flip the
variable back to true to resume. Everything below actually removes it.
Discover, don’t remember. Enumerate what exists from the live source of
truth, never a saved manifest: gh workflow list, gh secret list,
gh variable list (each -R <login>/multiagent-protocol-gov),
gh label list -R <login>/<project> per supervised repo, and the App’s
installation page. Read config/projects.yml supervised_repos for the repo
list.
Default removal — preserve the audit trail
Undo the install from the top step down; each item has its own Verify.
Stop and remove the tick (undo Step 3). Disable, then optionally delete, the deployed workflow:
gh workflow disable bot-cron.yml -R <login>/multiagent-protocol-gov
# optional — also delete the file from the governance repo:
git rm .github/workflows/bot-cron.yml && git commit -m "offboard: remove bot-cron" && git push
Verify: gh workflow list -R <login>/multiagent-protocol-gov no longer
shows bot-cron as active.
Uninstall the GitHub App (undo Step 4). [HUMAN] Only the operator can do
this. Walk them to GitHub → Settings → Applications → Installed GitHub Apps →
(your app) → Configure → Uninstall (or, to remove the registration entirely,
Settings → Developer settings → GitHub Apps → (your app) → Delete). The App ID
is on screen here — it is also the MERGE_GATE_APP_ID secret.
Verify: the App no longer appears on the installation page of the governance repo or any supervised repo.
Delete the three secrets (undo Step 4).
for s in MERGE_GATE_APP_ID MERGE_GATE_PRIVATE_KEY MERGE_GATE_RECEIPT_KEY; do
gh secret delete "$s" -R <login>/multiagent-protocol-gov || true
done
Verify: gh secret list -R <login>/multiagent-protocol-gov lists no
MERGE_GATE_* secret.
Clean each supervised repo (undo Steps 5–6). For every <login>/<project>
in config/projects.yml supervised_repos, remove the bot’s labels — the
decision:* family plus ready-to-merge and merge-gate-failure — by
discovering the live set rather than hardcoding names:
gh label list -R <login>/<project> --limit 100 --json name -q '.[].name' \
| grep -E '^(ready-to-merge|merge-gate-failure|decision:)' \
| while read -r L; do gh label delete "$L" -R <login>/<project> --yes || true; done
Then, optionally: remove the agent kit (AGENTS.md, CLAUDE.md) if the repo has
no other use for it, and revert allow_squash_merge if you enabled it only
for the bot in Step 5
(gh api -X PATCH repos/<login>/<project> -F allow_squash_merge=false).
Verify: gh label list -R <login>/<project> shows none of the decision:*
or ready-to-merge labels.
Keep the governance repo — deliberately (Steps 1–2 withheld). Do not
delete the private governance repo in the default path. Its Decision-Inbox
issues, the L5 break-glass records, and the bot-state branch are your audit
trail — the receipts for every merge the gate allowed and every decision the
owner made. Discarding them silently would betray the same honesty the gate
exists to protect. Leave them; a dormant private repo costs nothing.
What remains, and why that is good: the governance repo, its issue history,
and the bot-state branch. The gate is off — App uninstalled, no tick, no
secrets — but the record of what it did survives, and the owner can read,
diff, or delete it later on their own terms. That is the intended end-state of a
clean, honest offboard.
Full purge — destroys the audit trail
Only if the operator explicitly asks for everything, including history, to be gone. This is irreversible — get an explicit yes before running it, and say plainly what it destroys (the Decision-Inbox and break-glass records that are the entire audit trail).
Do the Default-removal label/kit cleanup first (labels and the agent kit live in the supervised repos, which survive a governance-repo delete), then delete the governance repo:
gh repo delete <login>/multiagent-protocol-gov --yes
That single delete takes the workflow, all three MERGE_GATE_* secrets, the
MERGE_GATE_MERGE_ENABLED variable, the bot-state branch, and the entire
Decision-Inbox / incident-issue history with it.
Verify: gh repo view <login>/multiagent-protocol-gov returns not found.
When something refuses to work
| Symptom | Likely cause → fix |
|---|---|
| Workflow never runs on schedule | GitHub cron lag (wait), or schedules auto-disabled after ~60 days of inactivity (re-enable in Actions tab), or you are still on upstream’s dispatch-only file (redo step 3). Manual backstop: gh workflow run. |
Bad credentials / PEM errors in the tick log |
Secret must contain the entire PEM including BEGIN/END lines; the key must be the RSA key GitHub generated. Redo step 4.3. |
| PR blocked on C1 (label) | The label must be applied by an allowlisted account (config/owner.yml). Your gh identity applies labels — it must be the operator’s login. |
| PR blocked on C2 (CI) | The supervised repo has zero completed checks (add the sanity workflow) or a required check failed. allow_no_ci: true only if the operator accepted that trade. |
| PR blocked on C5 (trailers) | One of the five trailers is missing or malformed — the diagnostic comment names which. Formats: templates/adopter/AGENTS.md §2. |
| Quadrant D issue opened for a routine change | The classifier read the paths as critical (rules/workflows/data). This is the designed pause — have the operator answer the issue rather than re-labeling. |
Tick green but the log shows supervised=0 |
config/projects.yml not committed to the governance repo (step 2’s git add -f), or the App isn’t installed on the supervised repo (step 4.2). |
| Answered the inbox issue but the next tick does nothing (Step 9 rehearsal) | Either your GitHub login is not in config/owner.yml allowlisted_actors — the resolver silently ignores reactions/comments from non-allowlisted accounts, so it never finds a verdict — or you answered on the issue in the supervised repo instead of the governance repo’s Issues tab (that is where the decision:pending-owner issue lives). |
This runbook is the executable counterpart of
docs/guide/quick-start.md. When they disagree,
this file is current — please open an issue on the discrepancy.