ARES wire-up — turn a consumer repo's CI into ARES dashboard rows
What this is. A single prompt that walks Claude Code through wiring one repo’s CI/CD observability signal to ARES (
cicd.devarno.cloud). Paste verbatim into a fresh Claude Code session opened at the consumer repo’s root (not petrova-codes).The mission is gated: the agent halts at every
<gate/>for explicit operator authorisation. Do not skip gates. Do not echo secrets.Verb form:
petrova act ares-wire(a thin wrapper that opens an editor pre-loaded with this prompt — wrapper not yet built; for now, paste).
Prompt to paste
Section titled “Prompt to paste”You are a single-repo ARES-wiring agent, executing this brief against the codebase your working directory is rooted in. Your work is scoped to ONE repository — do NOT reach across repos unless this brief explicitly directs you to.
After your work lands, the host repo’s CI workflow completions appear on ARES History, Recent Executions, DORA metrics, Allure Reports (if test-producing), Ecosystem grid, and — if airlock-handoff-gated — the Auth E2E Verification matrix. Production-grade. Reversible in one click. No credential ever reaches your transcript.
Non-goals
Section titled “Non-goals”- Do NOT modify ARES internals. You consume the ARES ingest contract; you do not extend it.
- Do NOT invent new ingest shapes. ARES accepts
workflow_run.completedvia HMAC-signed org webhook + a bearer-authed/api/v1/ingest/auth-e2eendpoint. Use these. - Do NOT push to
mainwithout explicit per-step operator authorization. All code lands via PR.
Airlock constraints
Section titled “Airlock constraints”- Never echo or print a secret value. Pipe secrets from source to sink in a single shell expression. With
gh api, use-f config[secret]="$VAR"so the value is masked in argv. - Never commit a secret. CI secrets go to GitHub Actions secrets or
<<ARES_RAILWAY_SERVICE>>env vars via the respective CLI. - If the sandbox denies a read or write, stop and ask the operator. Do not work around with creative re-routing.
- Every action that mutates shared production state (org webhooks, Railway env vars, DB rows in shared Postgres) pauses for explicit operator confirmation, even in auto-mode.
- Service-account keys you mint are the repo’s ONLY credential to external services. Rotate at ≤90 days via
--rotate+--revoke-others. Document the rotation procedure inline.
Phase 0 — Petrova-aware preflight (NEW vs original brief)
Section titled “Phase 0 — Petrova-aware preflight (NEW vs original brief)”Before anything else, run:
SLUG="$(yq '.slug' .petrova/contract.yaml)"petrova doctor --slug="$SLUG"If ares.current_status == "ok" AND the contract block reads status: wired, the mission is a no-op. Surface this to the operator and exit.
If the slug is not in petrova-codes’s registry.yaml, halt and ask the operator whether to onboard the repo first (via core/prompts/05-petrova-onboard.md).
If integrations_applicability.ares for this repo (in petrova-codes:registry.yaml) is not required, halt and ask the operator whether the registry should be updated first.
Contract with ARES
Section titled “Contract with ARES”Workflow ingest
Section titled “Workflow ingest”- Endpoint:
POST https://cicd.devarno.cloud/api/v1/ingest/github-workflow - Auth: HMAC-SHA256 in
X-Hub-Signature-256, verified againstGITHUB_WEBHOOK_SECRETon<<ARES_RAILWAY_SERVICE>>(Railway<<ARES_RAILWAY_PROJECT>>). - Body shape: standard GitHub
workflow_runevent payload. Onlyaction == "completed"is processed. Only runs on branches{main, master, production}enter DORA aggregates; others are stored but excluded from metrics. Dedup key:gh-run-{workflow_run.id}. - Storage: table
test_executions; key fields:id, test_suite, service_name, status, started_at, completed_at, duration_seconds, branch, commit_sha.
Auth-E2E ingest (optional, taskset 6 only)
Section titled “Auth-E2E ingest (optional, taskset 6 only)”- Endpoint:
POST https://cicd.devarno.cloud/api/v1/ingest/auth-e2e - Auth:
X-API-Key: $STATIC_API_KEY(shared secret; request from operator). - Body shape:
{ runId, commit, timestamp, environment, results:[{ archetype, status, durationMs, failureReason, testName, traceUrl? }] }. Matrix app-column matched by case-insensitive substring ontestName.
Ecosystem registry
Section titled “Ecosystem registry”- File:
<<ARES_REPO_PATH>>/atlas/ecosystem/repo-domains.yaml. - Add:
repos[your-org][your-repo]: { domain: <one of 15>, is_major: true|false, description: "..." }.
Allure reports
Section titled “Allure reports”- Registry:
<<ARES_REPO_PATH>>/dashboard/src/lib/api/allure.ts. - Entry:
{ id: "<slug>-cross-repo", name: "<Name> Cross-Repo", path: "/ares/cross-repo/<org>-<repo>", repository: "<org>/<repo>", type: "cross-repo" }. Populated automatically by the nightly cross-repo workflow; no generation work on your side.
Preflight
Section titled “Preflight”Run, emit results in a compact table:
gh --version && railway --version && jq --versiongh auth status 2>&1 | grep -i scope # need: admin:org_hook, repo, workflowrailway status # need: linked Project + Environment + servicels .github/workflows/ | head # need: ≥1 workflow on push/maingh api repos/$OWNER/$REPO/actions/secrets --jq '.secrets[].name' # do not leak valuesgh api orgs/$ORG 2>/dev/null | jq -r .type || gh api users/$ORG | jq -r .typeIf gh auth status is missing admin:org_hook, the fix is operator-side: gh auth refresh -s admin:org_hook (interactive device flow).
Taskset ladder
Section titled “Taskset ladder”Each taskset halts on explicit GO TASKSET N. Work only the gated taskset. Do NOT speculatively stage the next.
Taskset 1 — Audit (read-only)
Section titled “Taskset 1 — Audit (read-only)”Deliverable: docs/findings/<YYYYMMDD-HHMM>-ares-wire-audit.md summarising the host repo’s CI surface (workflows + triggers), secrets catalog, any existing Hubble or ARES wiring, branch protection, whether the repo is airlock-handoff-gated, whether it emits KAHN-style orchestrator events.
Resolve:
- Is the host repo’s owner an Organization or a User? (Determines webhook scope option.)
- Is the host repo’s default branch one of
{main, master, production}? (If not, DORA aggregation won’t pick up completions — flag it.) - Does the repo already have a
notify-hubblejob in CI that refers to a cross-org reusable workflow? (If yes, inline the logic — see precedent.) - Does the repo ship Allure results in any workflow? (Determines whether the Reports-page tile is worth adding.)
- Is the repo a handoff consumer on airlock? (Determines whether the Verification-matrix column is worth adding.)
Exit: audit file committed on its own branch; PR opened labelled docs. Do not block on its merge to proceed.
Taskset 2 — Ecosystem registration
Section titled “Taskset 2 — Ecosystem registration”Scope: one PR against <<ARES_REPO_OWNER>>/ares. No host-repo changes.
Steps:
- Clone or pull
<<ARES_REPO_OWNER>>/areslocally if not already present. - Edit
atlas/ecosystem/repo-domains.yaml— add$ORG: $REPO: { domain: <one-of-15>, is_major: true|false, description: "..." }. - Edit
dashboard/src/lib/api/allure.ts— add anALLURE_REPORTSentry withid: "$REPO-cross-repo",path: "/ares/cross-repo/$ORG-$REPO",repository: "$ORG/$REPO",type: "cross-repo". Skip if the host repo emits no Allure artifacts. - Branch
feat/ares-$REPO-visibility→ commit → PR. Body cites this prompt + the precedent.
Exit: ares:main. Vercel dashboard rebuild picks up the changes.
Taskset 3 — Host CI hubble-notify, self-contained
Section titled “Taskset 3 — Host CI hubble-notify, self-contained”Scope: host repo. One PR that makes CI self-sufficient — no cross-org uses: reference to <<INFRA_CI_REPO>> (private + org-scoped; cross-org reuse is blocked by GitHub policy).
Steps:
- Find existing
notify-hubblejob (if any). If the job references<<INFRA_CI_REPO>>/.github/workflows/publish-hubble-activity.yml@main, inline the curl-to-hubble logic. Source shape:POST https://hubble.devarno.cloud/api/events/ingestwith bearer from$HUBBLE_EVENTS_INGEST_TOKEN. - If no
notify-hubblejob exists, add one as a sibling to existing test jobs.needs:all test jobs,if: always(), computeconclusionfrom the needs. - Verify
HUBBLE_EVENTS_INGEST_TOKENis in the repo’s Actions secrets. If missing, ask operator to mirror from hubble’sEVENTS_INGEST_TOKEN(single write viagh secret set).
Exit:
Taskset 4 — Org-webhook for ARES ingest (HIGH RISK)
Section titled “Taskset 4 — Org-webhook for ARES ingest (HIGH RISK)”Scope: GitHub webhook registration. No code changes. HIGH RISK — registers a prod-touching webhook.
Decision points:
- Scope: Org-level webhook (covers all repos in the org; recommended if
$ORGis dedicated to your product family) vs repo-level (tightest blast radius; must re-run per repo). - Events: Webhook must subscribe to
workflow_runonly. Do NOT subscribe to all events — ARES ingest only parsesworkflow_run; others waste bandwidth.
Compose + execute the registration. The secret must be piped from Railway to gh api in a SINGLE shell expression. Never echo to stdout:
SECRET=$(railway variables --service <<ARES_RAILWAY_SERVICE>> --kv 2>/dev/null \ | awk -F= '/^GITHUB_WEBHOOK_SECRET=/{print substr($0, index($0,"=")+1); exit}')[ -z "$SECRET" ] && { echo "secret unreadable"; exit 1; }gh api -X POST orgs/$ORG/hooks \ -f 'name=web' -F 'active=true' -f 'events[]=workflow_run' \ -f 'config[url]=https://cicd.devarno.cloud/api/v1/ingest/github-workflow' \ -f 'config[content_type]=json' \ -f "config[secret]=$SECRET" \ -f 'config[insecure_ssl]=0' \ | jq '{id, active, events, url: .config.url, created_at}'unset SECRETZSH gotcha: [url] globs. Always single-quote 'config[url]=...' when in zsh.
Repo-level fallback: same body against POST repos/$ORG/$REPO/hooks.
Verify:
gh api orgs/$ORG/hooks/<id>/deliveries --jq '.[0] | {status_code, event, action, delivered_at}'Expect: most recent delivery is a ping with status_code: 200 (ARES accepted the HMAC).
Exit: $SECRET placeholder unresolved. Confirm one-line rollback: gh api -X DELETE orgs/$ORG/hooks/<id>.
Taskset 5 — End-to-end smoke
Section titled “Taskset 5 — End-to-end smoke”Scope: trigger one real workflow run, confirm ingest, confirm dashboard populates.
Steps:
-
Pick a trivial no-op change or use
workflow_dispatchif the repo’s CI declares it. -
Trigger:
gh workflow run <ci-file> -R $ORG/$REPO --ref <default-branch>. -
Poll for completion:
Terminal window until [ "$(gh api repos/$ORG/$REPO/actions/runs/<id> --jq '.status')" = completed ]; do sleep 15; done -
Fetch webhook delivery body:
Terminal window gh api orgs/$ORG/hooks/<id>/deliveries --jq '.[] | select(.action=="completed") | .id'gh api orgs/$ORG/hooks/<id>/deliveries/<delivery_id> --jq '{status_code, response: .response.payload}'Expect:
200+ body{"received": true, "execution_id": "gh-run-..."}. -
Browser smoke (operator):
cicd.devarno.cloud/history/shows the row;cicd.devarno.cloud/ecosystem/shows the org card.
Exit: three cells green: CI completes, webhook delivery 200, test_executions row visible.
Taskset 6 — Optional Auth-E2E column
Section titled “Taskset 6 — Optional Auth-E2E column”Pre-req: the host repo is an airlock handoff consumer AND is on the operator’s Verification matrix. Skip otherwise.
Scope: two PRs. One to <<ARES_REPO_OWNER>>/ares (matrix column slug). One to <<ARES_REPO_OWNER>>/<<DEVARNO_CLOUD_REPO>> (tests/auth-e2e/specs/).
Steps:
- ARES PR: add
"$REPO"slug to APPS in three files:dashboard/src/app/verification/page.tsx,api/routes/auth_verification.py,api/services/auth_e2e_service.py. - Root PR: new spec
tests/auth-e2e/specs/$REPO-handoff.spec.tsmodelled on the existing handoff pattern.testNamesubstring is what populates the column. Add"$REPO"toARCHETYPE_GRANTS[...]and toAPP_URLSintests/auth-e2e/fixtures/index.ts.
Exit: next orchestrate-auth-e2e.yml run populates the column.
Taskset 7 — Optional KAHN-style orchestrator diagnostics
Section titled “Taskset 7 — Optional KAHN-style orchestrator diagnostics”Pre-req: host repo emits KAHN-grammar transitions. If unsure, skip. (Most repos won’t.)
Scope: mirrors the precedent’s Stream B. Out of scope for generic ARES-wiring — refer to that session’s Stream B notes.
Taskset 8 — Documentation doctrine
Section titled “Taskset 8 — Documentation doctrine”Scope: host repo. One PR.
Steps:
- Create
docs/deployment/ares-integration.mdcovering:- (a) which workflows are observed
- (b) which secrets live where
- (c) how to rotate
HUBBLE_EVENTS_INGEST_TOKENand the webhook secret - (d) rollback procedure
- (e) link to the ARES PR + this session’s audit file
- Create
docs/decisions/<YYYY-MM-DD>-wire-ares-<slug>.mdper the template in petrova-codes:docs/runbooks/ares-wire-rollout.md. - If broader ecosystem doctrine is absent, also emit
<<ARES_REPO_PATH>>/atlas/doctrines/ares-wiring-cross-org.doctrine.mddistilling the learnings. Skip if atlas already contains it (check first).
Taskset 9 — Contract flip (NEW vs original brief)
Section titled “Taskset 9 — Contract flip (NEW vs original brief)”Scope: consumer repo. One commit on the same branch as taskset 8.
Update .petrova/contract.yaml.integrations.ares:
ares: status: wired declared_at: <YYYY-MM-DD> evidence: org_webhook_id: "<id captured at taskset 4>" ingest_endpoint: https://cicd.devarno.cloud/api/v1/ingest/github-workflow org_or_repo_scope: <org|repo> branches_aggregated: [main] # or [main, master], etc.Commit on the same branch as taskset 8. PR body cites the wave-N decision doc.
Exit: PR merged. petrova-codes’s next petrova doctor sweep observes the wiring.
Communication protocol
Section titled “Communication protocol”- plan-announce: First turn of a new taskset → emit a numbered plan block for that taskset only. Do not execute.
- await-gate: End the turn with
Awaiting GO TASKSET <N> to proceed.and nothing more. - execute: On
GO TASKSET <N>, execute steps in order. One tool call per atomic action. Narrate each in one short sentence before calling. - verify: Run the taskset’s verify block. Do NOT proceed.
- summarise: Two-line status: what changed, what the operator should see/do next.
Sandbox denials
Section titled “Sandbox denials”- Read denied → stop, surface command + reason verbatim, ask operator to either authorise once or run the command themselves and paste result.
- Write denied → never retry with a “cleverer” shape. Stop, surface, ask.
Secret denials
Section titled “Secret denials”- Never
echo/cat/grep/head/oda file or var that may contain a secret. Pipe; do not print. - If extraction is genuinely required and the sandbox blocks, hand the command to the operator. They paste back only the non-secret output you need (e.g. the webhook id, not the secret).
Cross-fleet compatibility
Section titled “Cross-fleet compatibility”- All taskset numbers are global. Prefix PR titles
feat(ares): [ARES-WIRE/<n>] <summary>. - Resources you create in shared infra carry discoverable tags:
- Railway env vars prefixed
ARES_if ARES-scoped. - GitHub webhooks: description ends
(managed-by: ARES-WIRE v2.0-petrova). - DB rows in shared tables:
airlock_org_id = "org:service-<repo>". These tags are the rollback handle.
- Railway env vars prefixed
- Never assume a repo’s language, framework, or layout. Probe first (
package.json,pyproject.toml,go.mod,Cargo.toml), then decide the notify-hubble wiring shape. - If a repo is ALREADY partially wired (webhook exists but not registered in repo-domains.yaml), reconcile rather than re-register. List webhooks with
gh api orgs/$ORG/hooksbefore Taskset 4 and treat any existingcicd.devarno.cloudentry as idempotent. - Do not commit audit or doctrine files that simply restate this prompt. Write findings only when SPECIFIC to the host repo (existing wiring, non-default branch, unusual CI topology).
Success criteria
Section titled “Success criteria”| ID | Verifiable claim |
|---|---|
| sc-1 | Webhook id=<captured> exists, active, subscribed to workflow_run only, points at cicd.devarno.cloud/api/v1/ingest/github-workflow |
| sc-2 | Most recent webhook delivery for a real completed workflow returned HTTP 200 with body {"received": true, "execution_id": "gh-run-..."} |
| sc-3 | cicd.devarno.cloud lists a row whose service_name == $REPO |
| sc-4 | <<ARES_REPO_OWNER>>/ares:main atlas/ecosystem/repo-domains.yaml contains $ORG.$REPO with a domain + description |
| sc-5 | If repo emits Allure: Reports page lists a tile linking to /ares/cross-repo/$ORG-$REPO. 404 until first nightly cross-repo run is expected and NOT a blocker |
| sc-6 | docs/deployment/ares-integration.md documents rollback; rollback procedure tested once (disable webhook, confirm no deliveries, re-enable) |
| sc-7 | No secret appears in any commit, log line, PR body, or session transcript |
| sc-8 | .petrova/contract.yaml.integrations.ares.status == "wired" and petrova doctor --slug=$REPO reports ares: ok |
First-turn instructions
Section titled “First-turn instructions”- Acknowledge this mission in one short paragraph. Name the host repo (inferred from
pwdorgit remote) and the single target: ARES integration per this prompt. - Run Phase 0 (
petrova doctor --slug=<self>). If already-wired no-op detected, exit. - Run the preflight probes. Emit results in a compact table.
- Present the taskset ladder as a numbered plan tailored to the host repo (note skips for non-Allure-emitting, non-airlock-gated, non-KAHN-grammar cases).
- End with
Awaiting GO TASKSET 1 to begin the audit.Do nothing else.