LORE + CAIRNET wire-up — register a consumer repo with Pebble's knowledge collection and agent emission stream
LORE + CAIRNET wire-up — register a consumer repo with Pebble’s knowledge collection and agent emission stream
Section titled “LORE + CAIRNET wire-up — register a consumer repo with Pebble’s knowledge collection and agent emission stream”What this is. A single prompt that walks Claude Code through wiring one repo to LORE (Pebble’s knowledge-collection registry) and CAIRNET (Pebble’s agent-emission stream). Two operator-driven Pebble HTTP POSTs (one to register the LORE collection, one to register the CAIRNET agent), a cross-repo wait for the first emission to land, and finally a contract flip via consumer-repo PR. Paste verbatim into a fresh Claude Code session opened at the consumer repo’s root (not petrova-codes, not Pebble).
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 rocky-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 LORE + CAIRNET 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 LORE collection is registered in Pebble under <<LORE_COLLECTION_SLUG>>, the CAIRNET agent is registered as <<CAIRNET_AGENT_ID>>, the agent has emitted its first stone, and petrova doctor --slug=<<SLUG>> reports lore_cairnet: ok. Reversible: revert the contract block to status: pending (Pebble registrations are append-only by convention).
Non-goals
Section titled “Non-goals”- Do NOT modify Pebble internals (storage, query, build pipeline, or schema). You make two HTTP POSTs against documented public endpoints and read back the responses; you do not extend Pebble itself.
- Do NOT invent new evidence shapes. The contract’s
lore_cairnetevidence shape is enforced bypetrova-codes:contracts/contract.schema.json(lore_collection_slug+cairnet_agent_idrequired;cairnet_stones_endpoint,emission_rate_30d,emission_budget_30d,decay_policyoptional). - Do NOT push to
mainof any repo without explicit per-step operator authorisation. All content lands via PR. - Do NOT emit stones from this prompt. Agent emission is the consumer repo’s runtime concern, not a wire-up step. Taskset 5 waits for the first natural emission; do not synthesise one.
Airlock constraints
Section titled “Airlock constraints”- Pebble is an authenticated HTTP service. The token name is
<<PEBBLE_TOKEN_NAME>>(defaultPETROVA_PEBBLE_TOKEN). Never echo, log, or commit the token value. Use${VAR:+set}substitution patterns when verifying presence. - Pebble registrations are append-only by convention. Never DELETE a registered collection or agent. If the wiring needs to be undone, the operator opens a separate decision doc; the registration is left in place.
- 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 (Pebble registrations, flipping the contract block) pauses for explicit operator confirmation, even in auto-mode.
Phase 0 — Petrova-aware preflight
Section titled “Phase 0 — Petrova-aware preflight”Before anything else, run:
SLUG="$(yq '.slug' .petrova/contract.yaml)"petrova doctor --slug="$SLUG"If lore_cairnet.current_status == "ok" AND the contract block reads status: wired, 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.lore_cairnet 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.
Contract with Pebble
Section titled “Contract with Pebble”Two surfaces, both reached via <<PEBBLE_ENDPOINT>> (default resolved by the probe to PETROVA_PEBBLE_ENDPOINT env var, or the documented public default).
LORE — knowledge-collection registry (write-side, this prompt)
Section titled “LORE — knowledge-collection registry (write-side, this prompt)”POST <<PEBBLE_ENDPOINT>>/api/knowledge/repos— register a collection. Body:{"slug": "<<LORE_COLLECTION_SLUG>>", "owner_repo": "<<SLUG>>", ...}. Auth:Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>.GET <<PEBBLE_ENDPOINT>>/api/knowledge/repos/<<LORE_COLLECTION_SLUG>>— verify registration. Read-side, used by the probe.
CAIRNET — agent emission stream (write-side, this prompt)
Section titled “CAIRNET — agent emission stream (write-side, this prompt)”POST <<PEBBLE_ENDPOINT>>/api/cairn/agents— register an agent. Body:{"agent_id": "<<CAIRNET_AGENT_ID>>", "owner_repo": "<<SLUG>>", ...}. Auth: as above.GET <<PEBBLE_ENDPOINT>>/api/cairn/stones?agent_id=<<CAIRNET_AGENT_ID>>&since=<iso-30d-ago>— list stones in the 30-day window. Read-side, used by the probe + thepetrova lore-cairnet-statusverb.
petrova lore-cairnet-status (operator-facing diagnostic)
Section titled “petrova lore-cairnet-status (operator-facing diagnostic)”petrova lore-cairnet-status <<SLUG>> [--workspace <path>] [--json]— read-only; same 2 GETs as the probe; prints LORE registration status, CAIRNET emission rate vsemission_budget_30d, top-5 latest stones. Always exits 0; never gates merges.- The probe (
loreCairnetProbein petrova-codes:cli/src/probes/lore_cairnet.ts) checks two conditions in order: (1) the LORE collection responds 2xx, (2) the CAIRNET stone count over 30d is in band —0 → failing(silent agent),> budget → failing(over budget),> 80% of budget → degraded,else → ok.
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 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.
Taskset 1 — Audit (read-only)
Section titled “Taskset 1 — Audit (read-only)”Deliverable: docs/findings/<<YYYYMMDD-HHMM>>-lore-cairnet-wire-audit-<<SLUG>>.md.
Collect and record:
-
Existing agent + emission patterns in this repo. Identify any code paths that already emit logs, events, or audit records. Look in
agent/,councils/,src/,internal/, and any*.log.*files. Note the natural points where CAIRNET stones could be authored (decisions, observations, questions, escalations). -
Existing LORE/CAIRNET footprint. If
<<PEBBLE_TOKEN_NAME>>is set, query Pebble:Terminal window if [ -n "${<<PEBBLE_TOKEN_NAME>>:+set}" ]; thencurl -s -H "Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>" \"${PETROVA_PEBBLE_ENDPOINT:-<<PEBBLE_ENDPOINT>>}/api/knowledge/repos/<<LORE_COLLECTION_SLUG>>" \| jq -r '.slug // "not_registered"'elseecho "skipped: <<PEBBLE_TOKEN_NAME>> not set; will check in Taskset 2"fi -
Recommended
<<LORE_COLLECTION_SLUG>>and<<CAIRNET_AGENT_ID>>. Default convention:<<LORE_COLLECTION_SLUG>>=<<SLUG>>(the consumer’s registry slug).<<CAIRNET_AGENT_ID>>=<<SLUG>>-<role>-001where<role>isfleet,coordinator, or another short noun describing the agent’s purpose (e.g.grace-fleet-001,kahn-coordinator-001). Surface both for operator confirmation; the operator may override.
-
Recommended
<<EMISSION_BUDGET_30D>>. Default suggestion:50stones in 30 days. Calibrate after observing wave-1’s actual emission rate. Document the chosen value in the audit findings. -
Recommended
<<DECAY_POLICY>>. Default:90d. This is operator-tunable; it documents how long stones are queryable before archival. -
Contract block readiness. Read
.petrova/contract.yamland note the currentintegrations.lore_cairnetblock status (pending,wired, or absent). If absent, it will be added at Taskset 6.
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. Present the recommended <<LORE_COLLECTION_SLUG>>, <<CAIRNET_AGENT_ID>>, <<EMISSION_BUDGET_30D>>, and <<DECAY_POLICY>> in a compact table. Do not proceed without explicit operator OK on each.
Taskset 2 — Token verify (read-only)
Section titled “Taskset 2 — Token verify (read-only)”Verify the operator has <<PEBBLE_TOKEN_NAME>> set in the active shell. Never echo the value.
if [ -n "${<<PEBBLE_TOKEN_NAME>>:+set}" ]; then echo "<<PEBBLE_TOKEN_NAME>>: set"else echo "<<PEBBLE_TOKEN_NAME>>: missing"fiIf missing, halt. The operator must export the token before continuing:
# Operator action — do not commit this:export <<PEBBLE_TOKEN_NAME>>="<paste-from-1password>"Tokens are issued by the Pebble admin (out of scope for this prompt). The operator is responsible for token rotation and storage in their secret manager.
<gate/> Token gate — proceed only if <<PEBBLE_TOKEN_NAME>> is confirmed set. Do not store, log, or transmit the token value.
Taskset 3 — Register LORE collection (Pebble-side POST)
Section titled “Taskset 3 — Register LORE collection (Pebble-side POST)”One HTTP POST against Pebble. No PR. The token is piped from the env; the response body is captured into a local variable and surfaced to the operator (do not commit it).
LORE_RESPONSE="$(curl -sS -X POST \ -H "Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>" \ -H "Content-Type: application/json" \ -d "{\"slug\":\"<<LORE_COLLECTION_SLUG>>\",\"owner_repo\":\"<<SLUG>>\"}" \ "${PETROVA_PEBBLE_ENDPOINT:-<<PEBBLE_ENDPOINT>>}/api/knowledge/repos")"echo "$LORE_RESPONSE" | jq '.'Expected: 201 Created with the collection echoed back. If the response is 409 Conflict, the collection already exists — capture the existing record and proceed.
If the response is 401/403, the token is invalid or lacks scope. Halt; the operator rotates the token.
<gate/> Halt with the LORE response payload (slug, registered_at). Operator confirms the registration is correct before proceeding.
Taskset 4 — Register CAIRNET agent (Pebble-side POST)
Section titled “Taskset 4 — Register CAIRNET agent (Pebble-side POST)”Same pattern, second endpoint:
AGENT_RESPONSE="$(curl -sS -X POST \ -H "Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>" \ -H "Content-Type: application/json" \ -d "{\"agent_id\":\"<<CAIRNET_AGENT_ID>>\",\"owner_repo\":\"<<SLUG>>\"}" \ "${PETROVA_PEBBLE_ENDPOINT:-<<PEBBLE_ENDPOINT>>}/api/cairn/agents")"echo "$AGENT_RESPONSE" | jq '.'Expected: 201 Created. 409 Conflict means the agent_id already exists — capture and proceed.
<gate/> Halt with the CAIRNET response payload (agent_id, registered_at). Operator confirms.
Taskset 5 — Cross-repo gate (wait for first emission)
Section titled “Taskset 5 — Cross-repo gate (wait for first emission)”The agent is registered but has not yet emitted its first stone. The operator triggers the first emission via the consumer repo’s normal flow (running the agent, completing a decision, etc.) — this prompt does NOT synthesise an emission.
Periodically poll:
petrova lore-cairnet-status <<SLUG>>Once the output shows cairnet: <N>/<<EMISSION_BUDGET_30D>> stones with N >= 1, capture the timestamp of the first stone:
FIRST_EMISSION="$(curl -sS \ -H "Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>" \ "${PETROVA_PEBBLE_ENDPOINT:-<<PEBBLE_ENDPOINT>>}/api/cairn/stones?agent_id=<<CAIRNET_AGENT_ID>>&limit=1&order=asc" \ | jq -r '.stones[0].emitted_at')"echo "first emission at: $FIRST_EMISSION"<gate/> Halt at this gate. Report the first-emission timestamp and petrova lore-cairnet-status output to the operator. Operator explicitly confirms the agent is emitting before proceeding to Taskset 6. If the agent does not emit within an operator-defined window (default 7 days), the operator may flip the slug to not_applicable instead — this prompt does not silently extend the wait.
Taskset 6 — Contract flip
Section titled “Taskset 6 — Contract flip”Scope: host (consumer) repo. One PR containing the contract edit and the decision doc.
- Populate the evidence block in
.petrova/contract.yaml:
lore_cairnet: status: wired declared_at: <<ISO_DATE>> evidence: lore_collection_slug: <<LORE_COLLECTION_SLUG>> cairnet_agent_id: <<CAIRNET_AGENT_ID>> emission_budget_30d: <<EMISSION_BUDGET_30D>> decay_policy: <<DECAY_POLICY>>Fill in:
<<ISO_DATE>>— today’s date inYYYY-MM-DDformat.<<LORE_COLLECTION_SLUG>>,<<CAIRNET_AGENT_ID>>— from Tasksets 3 + 4.<<EMISSION_BUDGET_30D>>,<<DECAY_POLICY>>— from Taskset 1 (operator-confirmed).
-
Author the decision doc at
docs/decisions/<<ISO_DATE>>-wire-lore-cairnet-<<SLUG>>.md. Use the petrova-codes decision-doc template. Cover:- Context: applicability from
petrova-codes:registry.yaml, sourced fromdocs/decisions/2026-05-01-lore-cairnet-wire-adoption.md. - Decision: authorise the wiring per
core/prompts/09-lore-cairnet-wire.mdtaskset ladder. LORE collection slug<<LORE_COLLECTION_SLUG>>, CAIRNET agent id<<CAIRNET_AGENT_ID>>, initialemission_budget_30d<<EMISSION_BUDGET_30D>>, decay policy<<DECAY_POLICY>>. - Consequences:
petrova doctor --slug=<<SLUG>>reportslore_cairnet: ok; first emission landed at$FIRST_EMISSION; contract block flips towiredin this PR. - Rollback: revert the contract block to
status: pending. Pebble registrations remain (append-only by convention).
- Context: applicability from
-
Open the consumer-repo PR:
Terminal window gh pr create \--title "feat(lore_cairnet): wire <<SLUG>> to LORE + CAIRNET" \--body "..."PR body cites
docs/decisions/<<ISO_DATE>>-wire-lore-cairnet-<<SLUG>>.mdand includes the LORE + CAIRNET registration response payloads (slug, agent_id, registered_at).
<gate/> Halt with the consumer-repo PR URL. Do not merge without explicit operator authorisation.
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”<<PEBBLE_TOKEN_NAME>>is a bearer token. Pipe it via the env (-H "Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>"); never print, log, or commit the value. Use${VAR:+set}substitution patterns when verifying presence.- If a curl 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.
Cross-fleet compatibility
Section titled “Cross-fleet compatibility”- All taskset numbers are global. Prefix PR titles
feat(lore_cairnet): [LC-WIRE/<n>] <summary>. - Resources you create carry discoverable tags:
- LORE collection slug:
<<LORE_COLLECTION_SLUG>>(typically equal to the consumer’s registry slug). - CAIRNET agent id:
<<CAIRNET_AGENT_ID>>(typically<slug>-<role>-NNN). - Consumer decision doc:
docs/decisions/<<ISO_DATE>>-wire-lore-cairnet-<<SLUG>>.md. These tags are the rollback handle.
- LORE collection slug:
- Pebble registrations are independent across slugs — concurrent wirings from multiple consumer repos do not interact. Each repo’s agent runs its own POSTs against Pebble.
- If the LORE collection or CAIRNET agent is already registered when the agent reaches Taskset 3 or 4 (e.g. operator pre-registered manually), the 409 Conflict response is the success signal — capture the existing record and proceed.
- Pipelining rule: consumer-repo PRs (decision doc + contract flip) may overlap across slugs. Pebble-side registrations are HTTP POSTs, not PRs — no review serialisation.
Halt rules summary
Section titled “Halt rules summary”- After Phase 0: auto-proceed only if
lore_cairnetis not yetokAND applicability isrequired. Halt and surface if no-op detected OR if applicability is notrequired. - After Taskset 1 (audit):
<gate/>— operator OKs<<LORE_COLLECTION_SLUG>>,<<CAIRNET_AGENT_ID>>,<<EMISSION_BUDGET_30D>>,<<DECAY_POLICY>>. - At Taskset 2 (token verify):
<gate/>— halt if<<PEBBLE_TOKEN_NAME>>is unset; do not proceed until operator confirms it is set. - At Taskset 3 (LORE registration):
<gate/>— operator confirms the response payload before proceeding. - At Taskset 4 (CAIRNET registration):
<gate/>— operator confirms the response payload before proceeding. - At Taskset 5 (cross-repo gate):
<gate/>— wait for first emission; operator confirmspetrova lore-cairnet-statusshowstotal >= 1. - At Taskset 6 with the consumer-repo PR URL:
<gate/>— operator merges.
Success criteria
Section titled “Success criteria”| ID | Verifiable claim |
|---|---|
| sc-1 | curl -H "Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>" "<<PEBBLE_ENDPOINT>>/api/knowledge/repos/<<LORE_COLLECTION_SLUG>>" returns 200 |
| sc-2 | curl -H "Authorization: Bearer $<<PEBBLE_TOKEN_NAME>>" "<<PEBBLE_ENDPOINT>>/api/cairn/stones?agent_id=<<CAIRNET_AGENT_ID>>&since=<30d-ago>" returns total >= 1 |
| sc-3 | petrova lore-cairnet-status <<SLUG>> prints cairnet: <N>/<<EMISSION_BUDGET_30D>> stones with N within budget |
| sc-4 | docs/decisions/<<ISO_DATE>>-wire-lore-cairnet-<<SLUG>>.md exists, is dated, and references the registration response payloads |
| sc-5 | No secret, vault path, private hostname, or private project data appears in any committed file |
| sc-6 | .petrova/contract.yaml.integrations.lore_cairnet.status == "wired" and petrova doctor --slug=<<SLUG>> reports lore_cairnet: ok |
Secret hygiene
Section titled “Secret hygiene”Pebble is auth-gated. The token (<<PEBBLE_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.
- 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 (<<PEBBLE_ENDPOINT>>) or the env varPETROVA_PEBBLE_ENDPOINT. <<OPERATOR>>resolves to a public handle only.
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: LORE + CAIRNET registration and contract flip per this prompt. - Run Phase 0 (
petrova doctor --slug=<self>). If already-wired no-op detected, exit. - Run a quick readiness probe: check
yq .slug .petrova/contract.yaml,yq '.integrations.lore_cairnet' .petrova/contract.yaml, and[ -n "${<<PEBBLE_TOKEN_NAME>>:+set}" ] && echo "token: set" || echo "token: missing". Emit results in a compact table. - Present the taskset ladder as a numbered plan tailored to the host repo (note any skips — e.g. if the LORE collection or CAIRNET agent is already registered, Tasksets 3/4 capture the existing record and proceed; if
<<PEBBLE_TOKEN_NAME>>is unset, surface that immediately and pause Taskset 2 until the operator exports it). - End with
Awaiting GO TASKSET 1 to begin the audit.Do nothing else.