Skip to content

EVA wire-up — register a consumer repo against the three EVA surfaces

EVA wire-up — register a consumer repo against the three EVA surfaces

Section titled “EVA wire-up — register a consumer repo against the three EVA surfaces”

What this is. A single prompt that walks Claude Code through wiring one repo to EVA’s three production surfaces: events (run-event ingest), control (queue mutation API), and prompts (prompt library). Each surface is independently gated; surfaces not applicable to the consumer repo are declared not_applicable with a reason and skipped entirely. The mission ends with a contract flip via consumer-repo PR and validation against eva-hq:contracts/consumption.v1.json. Paste verbatim into a fresh Claude Code session opened at the consumer repo’s root (not petrova-codes, not eva-hq).

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 eva-wire (thin wrapper not yet built; for now, paste).


You are a single-repo EVA wiring agent, executing this brief against the codebase your working directory is rooted in. Your work is scoped to ONE consumer repository — do NOT reach across repos unless this brief explicitly directs you to.

After your work lands, the host repo’s applicable EVA surfaces are wired and evidenced, petrova doctor --slug=<<SLUG>> reports eva: ok, and .petrova/contract.yaml.integrations.eva holds a valid eva.consumption.v1 block. Reversible: revert the contract block to per-surface state: pending (EVA-side configuration is not persistent state — no append-only constraint applies).

  • Do NOT modify eva-hq internals (queue, prompt library, control API schema, or CI). You call documented public endpoints and use the published composite action; you do not extend EVA itself.
  • Do NOT invent new evidence shapes. The per-surface evidence schema is enforced by eva-hq:contracts/consumption.v1.json: events requires workflow + action_ref + last_run_id + last_emitted_at; control requires client_ref + last_health_ok_at; prompts requires manifest + eva_sha.
  • Do NOT push to main of any repo without explicit per-step operator authorisation. All content lands via PR.
  • Do NOT author the evidence_consumer block. That block is materialised by petrova-verify-round running eva consumption mirror against dist/evidence/<slug>/ in eva-hq. Leave it absent; verify-round writes it on its next pass.
  • Do NOT synthesise CI runs. Taskset 3 requires the consumer’s CI to actually execute and land a real run ID.
  • EVA endpoints (events and control surfaces) are authenticated. The token name is <<EVA_TOKEN_NAME>> (default PETROVA_EVA_TOKEN). Never echo, log, or commit the token value. Use ${VAR:+set} substitution patterns when verifying presence.
  • The EVA endpoint base resolves from PETROVA_EVA_ENDPOINT env var, or the documented public default <<EVA_ENDPOINT>> (= eva.re).
  • Never commit ~/Documents/<vault> paths, operator-private hostnames, or private project information.
  • <<OPERATOR>> resolves to a public handle only (e.g. Dev4rno). It never expands to an email address, internal ID, or private name.
  • 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 state (CI workflow edits, control-API client commits, contract flip) pauses for explicit operator confirmation, even in auto-mode.

Before anything else, run:

Terminal window
SLUG="$(yq '.slug' .petrova/contract.yaml)"
petrova doctor --slug="$SLUG"

If eva.current_status == "ok" AND every applicable surface in the contract block reads state: wired AND python <eva-hq-root>/bin/eva consumption validate --file .petrova/contract.yaml exits 0, the mission is a no-op. Surface this to the operator and exit — do not proceed.

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). Do not proceed until the slug is registered.

If integrations_applicability.eva for this repo (in petrova-codes:registry.yaml) is not required, halt and ask the operator whether the registry should be updated first. Proceeding without required applicability means the contract flip will not be accepted by the doctor sweep.


Three surfaces, all documented in eva-hq:docs/decisions/2026-05-08-eva-consumption-contract.md. The endpoint base is <<EVA_ENDPOINT>> (resolved by the probe to PETROVA_EVA_ENDPOINT env var, or the public default eva.re).

  • Producer integration: the eva-emit GitHub composite action at eva-hq/eva/.github/actions/eva-emit@v0, called from the consumer’s CI workflow.
  • Auth: Authorization: Bearer $<<EVA_TOKEN_NAME>> (the action reads EVA_INGEST_TOKEN from the calling workflow’s secrets; <<EVA_TOKEN_NAME>> is the consumer’s local name for the same secret).
  • Evidence when state: wired: workflow (path to the CI YAML, e.g. .github/workflows/ci.yml), action_ref (eva-hq/eva/.github/actions/eva-emit@v0), last_run_id (a real run ID returned by the ingest endpoint), last_emitted_at (ISO timestamp of that run).
  • Endpoints: GET/POST <<EVA_ENDPOINT>>/api/health, GET <<EVA_ENDPOINT>>/api/tasks/list, POST <<EVA_ENDPOINT>>/api/tasks/transition.
  • Auth: bearer token as above.
  • Evidence when state: wired: client_ref (path or module ref to the consumer’s EVA control client), last_health_ok_at (ISO timestamp of a successful /api/health call).
  • The consumer maintains an eva-prompts.lock.json manifest that maps EVA prompt IDs to pinned git SHAs from eva-hq.
  • No auth required to read the prompt catalog from a public-readable git ref.
  • Evidence when state: wired: manifest (path to eva-prompts.lock.json in the consumer repo), eva_sha (the eva-hq commit SHA currently pinned).

petrova eva-status (operator-facing diagnostic)

Section titled “petrova eva-status (operator-facing diagnostic)”
  • petrova eva-status <<SLUG>> [--workspace <path>] [--json] — read-only; calls /api/health on the control surface and reads the lock manifest; always exits 0; never gates merges.
  • python <eva-hq-root>/bin/eva consumption validate --file .petrova/contract.yaml — validates the full block against contracts/consumption.v1.json; must exit 0 at Taskset 6 before opening the PR.

Each taskset halts on explicit GO TASKSET N. Work only the gated taskset. Do NOT speculatively stage the next.

Surfaces where the operator confirmed not_applicable in Taskset 1 cause their corresponding tasksets (3, 4, or 5) to be skipped entirely. The audit deliverable records which tasksets apply.

Taskset 0 — Petrova-aware preflight (auto, no separate gate)

Section titled “Taskset 0 — Petrova-aware preflight (auto, no separate gate)”

This taskset is the Phase 0 block above. If petrova doctor reports a no-op, exit. Otherwise surface the result and wait for GO TASKSET 1.

Deliverable: docs/findings/<<YYYYMMDD-HHMM>>-eva-wire-audit-<<SLUG>>.md.

Collect and record:

  1. Per-surface applicability. For each of events, control, prompts, determine whether the consumer repo actually uses or should use that surface. Look in .github/workflows/, src/, internal/, and any existing EVA client code. Emit a recommendation for each surface: wired or not_applicable (with a one-line reason ≤ 120 chars).

  2. Existing EVA footprint. If <<EVA_TOKEN_NAME>> is set, probe the control surface:

    Terminal window
    if [ -n "${<<EVA_TOKEN_NAME>>:+set}" ]; then
    curl -s -H "Authorization: Bearer $<<EVA_TOKEN_NAME>>" \
    "${PETROVA_EVA_ENDPOINT:-<<EVA_ENDPOINT>>}/api/health" \
    | jq -r '.status // "unreachable"'
    else
    echo "skipped: <<EVA_TOKEN_NAME>> not set; will check in Taskset 2"
    fi

    Also check whether .github/workflows/ already calls eva-emit, and whether eva-prompts.lock.json already exists.

  3. Recommended <<EVA_TOKEN_NAME>>. Default convention: PETROVA_EVA_TOKEN. Surface for operator confirmation; the operator may override to match an existing secrets convention in the consumer repo.

  4. Contract block readiness. Read .petrova/contract.yaml and note the current integrations.eva block status (pending, a partial eva.consumption.v1 block, or absent). If absent, the full block will be authored at Taskset 6.

  5. Taskset skip map. Present a compact table: surface, recommended state, taskset that will execute it. Mark skipped tasksets clearly.

Commit the findings file on its own branch labelled docs. Open a PR. Do not block on its merge.

<gate/> Halt with the path to the audit findings doc and the taskset skip map in a compact table. Present per-surface recommendations. Do not proceed without explicit operator OK on each surface decision.

Taskset 2 — Token verify (conditional: skip if ALL surfaces are not_applicable for events and control)

Section titled “Taskset 2 — Token verify (conditional: skip if ALL surfaces are not_applicable for events and control)”

Verify the operator has <<EVA_TOKEN_NAME>> set in the active shell. Never echo the value.

Terminal window
if [ -n "${<<EVA_TOKEN_NAME>>:+set}" ]; then
echo "<<EVA_TOKEN_NAME>>: set"
else
echo "<<EVA_TOKEN_NAME>>: missing"
fi

If missing and any events or control surface will be wired, halt. The operator must export the token before continuing:

Terminal window
# Operator action — do not commit this:
export <<EVA_TOKEN_NAME>>="<paste-from-1password>"

Tokens are issued by the EVA admin (out of scope for this prompt). The operator is responsible for token rotation and storage in their secret manager. If prompts is the only wired surface, this taskset is informational — no token is required for the prompts surface.

<gate/> Token gate — proceed only if the token requirement for the planned surfaces is satisfied. Do not store, log, or transmit the token value.

Taskset 3 — Wire events surface (skip if not_applicable)

Section titled “Taskset 3 — Wire events surface (skip if not_applicable)”

Install eva-hq/eva/.github/actions/eva-emit@v0 as a step in the consumer’s CI workflow. The step must run after the build/test job and post both a started and terminal (passed | failed) event.

Minimal step example (adapt to the consumer’s workflow structure):

- name: Emit run event to EVA
uses: eva-hq/eva/.github/actions/eva-emit@v0
if: always()
with:
run_id: ${{ github.run_id }}
status: ${{ job.status }}
env:
EVA_INGEST_TOKEN: ${{ secrets.<<EVA_TOKEN_NAME>> }}
EVA_ENDPOINT: ${{ vars.PETROVA_EVA_ENDPOINT || 'https://eva.re' }}

After committing the workflow change to a branch, trigger a CI run and wait for it to complete. Capture:

Terminal window
LAST_RUN_ID="<run_id from the CI run>"
LAST_EMITTED_AT="<ISO timestamp from the action's output or the ingest response>"

<gate/> Halt with the CI run URL, last_run_id, and last_emitted_at. Operator confirms the run landed in EVA (check petrova eva-status <<SLUG>> or the EVA dashboard) before proceeding.

Taskset 4 — Wire control surface (skip if not_applicable)

Section titled “Taskset 4 — Wire control surface (skip if not_applicable)”

Stand up a minimal EVA control-API client in the consumer repo. The client must be able to call at least GET /api/health. Location: follow the consumer’s conventions (e.g. src/clients/eva.ts, internal/eva/client.go, lib/eva_client.py). The client reads EVA_INGEST_TOKEN (or <<EVA_TOKEN_NAME>>) from the environment.

After committing the client, call /api/health once and capture the timestamp:

Terminal window
HEALTH_RESPONSE="$(curl -sS \
-H "Authorization: Bearer $<<EVA_TOKEN_NAME>>" \
"${PETROVA_EVA_ENDPOINT:-<<EVA_ENDPOINT>>}/api/health")"
echo "$HEALTH_RESPONSE" | jq '.'
LAST_HEALTH_OK_AT="$(echo "$HEALTH_RESPONSE" | jq -r '.checked_at // empty')"
[ -z "$LAST_HEALTH_OK_AT" ] && LAST_HEALTH_OK_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

If the response is 401/403, the token is invalid or lacks scope. Halt; the operator rotates the token.

<gate/> Halt with client_ref (the path or module ref committed) and last_health_ok_at. Operator confirms.

Taskset 5 — Wire prompts surface (skip if not_applicable)

Section titled “Taskset 5 — Wire prompts surface (skip if not_applicable)”

Generate or refresh the eva-prompts.lock.json manifest in the consumer repo root (or another operator-specified path). The manifest maps EVA prompt IDs — whichever the consumer uses — to the current eva-hq HEAD SHA.

Terminal window
EVA_SHA="$(git -C <path-to-eva-hq> rev-parse HEAD)"

Minimal manifest shape:

{
"schema": "eva-prompts-lock.v1",
"eva_sha": "<<EVA_SHA>>",
"locked_at": "<<ISO_DATE>>",
"prompts": [
{ "id": "<prompt-id>", "path": "prompts/<file>.md" }
]
}

Populate prompts[] with the IDs the consumer actually references. If the consumer does not yet reference any prompt IDs directly, record an empty array and note this in the decision doc.

<gate/> Halt with the path to eva-prompts.lock.json and the pinned eva_sha. Operator confirms the pinned SHA is the intended one.

Scope: host (consumer) repo. One PR containing the contract edit and the decision doc.

  1. Populate the eva.consumption.v1 block in .petrova/contract.yaml:
integration_eva:
schema: eva.consumption.v1
status: <<DERIVED>> # derived by eva consumption validate; do not author manually
declared_at: <<ISO_DATE>>
wired_at: <<ISO_DATE>>
wired_decision_doc: docs/decisions/<<ISO_DATE>>-wire-eva-<<SLUG>>.md
surfaces:
events:
state: wired # or: not_applicable
evidence:
workflow: <<WORKFLOW_PATH>>
action_ref: eva-hq/eva/.github/actions/eva-emit@v0
last_run_id: <<LAST_RUN_ID>>
last_emitted_at: <<LAST_EMITTED_AT>>
control:
state: wired # or: not_applicable
evidence:
client_ref: <<CLIENT_REF>>
last_health_ok_at: <<LAST_HEALTH_OK_AT>>
prompts:
state: wired # or: not_applicable
evidence:
manifest: <<MANIFEST_PATH>>
eva_sha: <<EVA_SHA>>

For any surface confirmed not_applicable, replace the evidence sub-block with a reason field (≤ 120 chars). The status top-level field is derived; set it to wired if any surface is wired, else pending, else not_applicable.

Do NOT add an evidence_consumer block — verify-round materialises it.

  1. Validate the contract block:
Terminal window
python <eva-hq-root>/bin/eva consumption validate --file .petrova/contract.yaml

Must exit 0. If it fails, fix the block and re-run before proceeding.

  1. Author the decision doc at docs/decisions/<<ISO_DATE>>-wire-eva-<<SLUG>>.md. Use the petrova-codes decision-doc template. Cover:

    • Context: applicability from petrova-codes:registry.yaml, sourced from eva-hq:docs/decisions/2026-05-08-eva-consumption-contract.md.
    • Decision: authorise the wiring per core/prompts/10-eva-wire.md taskset ladder. State which surfaces are wired and which are not_applicable, with the operator-confirmed reasons.
    • Consequences: petrova doctor --slug=<<SLUG>> will report eva: ok; evidence_consumer will be materialised by next verify-round run; contract block flips to the appropriate status in this PR.
    • Rollback: revert the contract block surfaces to state: pending. EVA-side configuration has no persistent append-only state; no Pebble-style registration to unwind.
  2. Open the consumer-repo PR:

Terminal window
gh pr create \
--title "feat(eva): wire <<SLUG>> to eva.consumption.v1" \
--body "..."

PR body cites docs/decisions/<<ISO_DATE>>-wire-eva-<<SLUG>>.md and lists the per-surface states and evidence pointers.

<gate/> Halt with the consumer-repo PR URL. Do not merge without explicit operator authorisation.


  • 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.
  • 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.
  • <<EVA_TOKEN_NAME>> is a bearer token. Pipe it via the env (-H "Authorization: Bearer $<<EVA_TOKEN_NAME>>"); never print, log, or commit the value. Use ${VAR:+set} substitution patterns when verifying presence.
  • If a curl or action response includes the token in any field (it should not), redact before surfacing.
  • <<OPERATOR>> is a public handle. Never expand it to an email address or internal ID in any committed file.

  • All taskset numbers are global. Prefix PR titles feat(eva): [EVA-WIRE/<n>] <summary>.

  • Resources you create carry discoverable tags:

    • Consumer contract path: .petrova/contract.yaml#integration_eva.
    • Lock manifest: <<MANIFEST_PATH>> (typically eva-prompts.lock.json).
    • Consumer decision doc: docs/decisions/<<ISO_DATE>>-wire-eva-<<SLUG>>.md.
    • Token name: <<EVA_TOKEN_NAME>> (secret in CI; env var in shell). These tags are the rollback handle.
  • EVA surfaces are independent across consumer slugs. Concurrent wirings from multiple repos do not interact.

  • If the CI workflow already calls eva-emit when the agent reaches Taskset 3, capture the existing run ID and last_emitted_at from the most recent run and proceed — no duplicate step needed.

  • Pipelining rule: consumer-repo PRs (decision doc + contract flip) may overlap across slugs. Each repo’s wiring is isolated.

  • Placeholder inventory (all tokens that appear in committed files must be resolvable at runtime):

    PlaceholderResolves to
    <<SLUG>>yq '.slug' .petrova/contract.yaml
    <<EVA_TOKEN_NAME>>Default PETROVA_EVA_TOKEN; operator may rename
    <<EVA_ENDPOINT>>Default eva.re; overridden by PETROVA_EVA_ENDPOINT
    <<ISO_DATE>>Today in YYYY-MM-DD
    <<YYYYMMDD-HHMM>>Current datetime for findings file name
    <<OPERATOR>>Public git handle only
    <<EVA_SHA>>git -C <eva-hq-root> rev-parse HEAD
    <<WORKFLOW_PATH>>Path to the consumer CI YAML that calls eva-emit
    <<LAST_RUN_ID>>Run ID from the first wired CI run
    <<LAST_EMITTED_AT>>ISO timestamp of that run’s ingest
    <<CLIENT_REF>>Path or module ref to the consumer’s control client
    <<MANIFEST_PATH>>Path to eva-prompts.lock.json
    <<LAST_HEALTH_OK_AT>>ISO timestamp of last successful /api/health call

  • After Phase 0: auto-proceed only if eva is not yet ok AND applicability is required. Halt and surface if no-op detected OR if applicability is not required.
  • After Taskset 1 (audit): <gate/> — operator OKs per-surface decisions (wired vs not_applicable) and confirms <<EVA_TOKEN_NAME>>.
  • At Taskset 2 (token verify): <gate/> — halt if <<EVA_TOKEN_NAME>> is unset and any events or control surface will be wired; do not proceed until operator confirms it is set.
  • At Taskset 3 (events surface): <gate/> — operator confirms the CI run landed in EVA before proceeding.
  • At Taskset 4 (control surface): <gate/> — operator confirms client_ref and /api/health response before proceeding.
  • At Taskset 5 (prompts surface): <gate/> — operator confirms the pinned eva_sha before proceeding.
  • At Taskset 6 with the consumer-repo PR URL: <gate/> — operator merges. Validate passes before PR is opened.

IDVerifiable claim
sc-1python <eva-hq-root>/bin/eva consumption validate --file .petrova/contract.yaml exits 0
sc-2For each surface with state: wired: the evidence pointers are real and dereferenceable (CI run ID exists; /api/health returned 200 at last_health_ok_at; eva-prompts.lock.json exists at manifest)
sc-3petrova doctor --slug=<<SLUG>> reports eva: ok
sc-4docs/decisions/<<ISO_DATE>>-wire-eva-<<SLUG>>.md exists, is dated, and references the per-surface evidence
sc-5No secret, vault path, private hostname, or private project data appears in any committed file
sc-6.petrova/contract.yaml.integration_eva.status equals wired (or pending / not_applicable if all surfaces are non-wired, per derive_status())
sc-7evidence_consumer block is absent from the authored contract (verify-round writes it on next pass)

EVA events and control surfaces are auth-gated. The token (<<EVA_TOKEN_NAME>>) is a bearer secret.

  • Never commit the token value. Never echo it. Never log it. Use ${VAR:+set} substitution patterns when verifying presence.
  • The token lives in the operator’s secret manager (1Password, vault, etc.). The operator exports it into the active shell at the start of each session, and stores it as a CI repository secret under the agreed name.
  • Token rotation is the operator’s responsibility. If a token is rotated mid-wiring, halt at the next taskset gate and re-verify presence.
  • Never commit ~/Documents/<vault> paths or operator-private hostnames. Use the documented public default (<<EVA_ENDPOINT>>) or the env var PETROVA_EVA_ENDPOINT.
  • <<OPERATOR>> resolves to a public handle only.
  • The prompts surface requires no token; do not apply token hygiene rules to the lock manifest file.

  1. Acknowledge this mission in one short paragraph. Name the host repo (inferred from pwd or git remote) and the single target: wiring to EVA’s three surfaces (events, control, prompts) and a contract flip per this prompt.
  2. Run Phase 0 (petrova doctor --slug=<self>). If already-wired no-op detected, exit.
  3. Run a quick readiness probe: check yq .slug .petrova/contract.yaml, yq '.integrations.eva' .petrova/contract.yaml, and [ -n "${<<EVA_TOKEN_NAME>>:+set}" ] && echo "token: set" || echo "token: missing". Emit results in a compact table.
  4. Present the taskset ladder as a numbered plan tailored to the host repo (note any expected skips — e.g. if the repo has no CI, Taskset 3 is likely not_applicable; if no EVA queue integration, Taskset 4 is likely not_applicable). Call out any surfaces the audit will need to decide.
  5. End with Awaiting GO TASKSET 1 to begin the audit. Do nothing else.