Skip to content

onboard repo

The end-to-end flow for admitting a new repo to the petrova control plane. After a successful run, the repo is reachable via every verb, visible in petrova status / petrova dashboard, and (if the operator chose) governed by agent fleets.

  • Repo is reachable on GitHub (public or private with petrova auth).
  • Operator has push access to petrova-codes/petrova (the registry lives here).
  • PETROVA_GITHUB_TOKEN (or the GitHub App env triple) configured for the --apply step.
  • Repo is locally cloned at $PETROVA_WORKSPACE/<slug> (default: parent dir of petrova-codes). If not, clone it first — the readiness report needs filesystem access.
  • After the playbook PR merges, set a one-time PETROVA_DISPATCH_TOKEN secret on the consumer repo so .github/workflows/petrova-notify-state.yml can fire repository_dispatch at petrova-codes on phase verb merges. See PETROVA_DISPATCH_TOKEN setup at the end of this runbook. Optional — without it the workflow no-ops and the 30-min state-sweep cron is the safety net.
Terminal window
cd ~/code/workspace/petrova-codes
claude code

The prompt lives at core/playbook/prompts/05-petrova-onboard.md. Copy it verbatim into the Claude Code session. The prompt is interactive — it will:

  1. Ask which repo you’re onboarding.
  2. Read the consumer repo (read-only) and produce a readiness report covering petrova-shape state, branch protection, recommended role and profile.
  3. Confirm fleets_allowed (default: empty).
  4. Compose the registry-update PR payload as a JSON file.
  5. Run dry-run, show you the diff.
  6. After your go-ahead, run --apply, return the PR URL.

The registry PR appears in petrova-codes/petrova. CODEOWNERS for registry.yaml (or any human approver) reviews it.

Things to check:

  • The new entry’s url matches the consumer’s actual git remote get-url origin.
  • profile is conservative — strict for production, standard for most, permissive only when intentional.
  • fleets_allowed is empty unless the operator named specific fleets (and they exist).

Merge.

Terminal window
git -C ~/code/workspace/petrova-codes pull
petrova status # new slug appears
petrova diagnose <slug> # returns structured context
petrova validate <slug> # MR / convention compliance

If petrova status doesn’t show the new slug, the local registry is stale — git pull and retry.

If the readiness report flagged the consumer as missing control-loop docs (CLAUDE.md, AGENTS.xml, MILESTONES.md):

Terminal window
cd ~/code/workspace/<slug>
claude code
# Paste core/playbook/prompts/00-bootstrap.md

Bootstrap is its own session — it needs the consumer’s spec docs in context, not the petrova-codes root.

6. (Optional) Add petrova-act capability declaration

Section titled “6. (Optional) Add petrova-act capability declaration”

If the consumer has an AGENTS.xml but no <capability id="petrova-act"> block, add it via petrova request_review:

Terminal window
# Read the new template's capability block from
# core/templates/AGENTS.xml.tmpl, splice it into the consumer's
# AGENTS.xml just before </agents>, then:
petrova request_review <slug> \
--input /tmp/capability-add.json \
--triggered-by-kind human_request \
--triggered-by-ref "post-onboarding capability declaration"

This is purely informational for the consumer’s orchestrator — verbs work without it (gating happens in registry.yaml’s fleets_allowed, not in the consumer’s XML).

ProblemFix
Slug already in registryThis is an update, not an onboard. Re-target as a request_review modifying the existing entry.
git remote get-url origin doesn’t match registry urlOperator typo or registry drift. Open a one-line request_review PR fixing the url.
Consumer not locally clonedgit clone it first; the prompt won’t proceed without filesystem access.
PETROVA_GITHUB_TOKEN unsetSet it. Onboarding cannot complete in dry-run only.
Concurrent registry editPull latest, recompose JSON with current registry contents, retry.
Branch protection on petrova-codes blocks the PR’s auto-mergeExpected. Petrova-hq is strict-profile; the registry PR needs human approval.
  • Does not push to the consumer repo’s main branch (everything is PR-based per the control-plane decision).
  • Does not auto-grant agent-fleet access. Empty fleets_allowed is the safe default; fleets are added in subsequent registry PRs as their identity gets defined.
  • Does not auto-bootstrap. The bootstrap session is run separately with the consumer’s spec docs in context.

The petrova_install_playbook verb deposits .github/workflows/petrova-notify-state.yml into the consumer repo. That workflow fires a repository_dispatch at petrova-codes/petrova whenever a phase verb PR merges, so the fleet-wide phases grid refreshes in <60s rather than waiting for the 30-min state-sweep cron.

The workflow needs a token with permission to call the dispatches endpoint on petrova-codes/petrova. Without the secret it no-ops (logged warning, no failure); the 30-min cron is the safety net.

The token is reused across all consumer repos; you only mint it once.

  1. https://github.com/settings/personal-access-tokens/new
  2. Token name: petrova-state-dispatch
  3. Resource owner: petrova-codes
  4. Repository access → Only select repositories → petrova-codes/petrova
  5. Permissions → Repository permissions → set both:
    • Actions: Read and write (for the dashboard’s ▶ trigger sweep button, which calls POST /actions/workflows/.../dispatches).
    • Contents: Read and write (for the consumer-side petrova-notify-state.yml workflow, which calls POST /dispatches — a separate, contents-scoped endpoint).
  6. Generate, copy the github_pat_… string.

Install per consumer (after the playbook PR merges)

Section titled “Install per consumer (after the playbook PR merges)”
Terminal window
gh secret set PETROVA_DISPATCH_TOKEN -R <owner>/<consumer-repo>
# paste token at the prompt

Verify by closing a phase in the consumer; the petrova-notify-state workflow run should show Dispatched petrova-state-stale for slug=<consumer-repo> and the petrova-codes state-sweep should fire within ~60s.