Skip to content

2026-05-14-prompt-service-architecture


title: Prompt service architecture — eva-hq authors, petrova.host serves, consumers fetch via MCP date: 2026-05-14 status: ratified mr_compliance: [MR-7, MR-12] supersedes:

  • parts of 2026-05-13-petrova-onboarding-flow-v2.md (the “core/prompts/00-bootstrap.md (canonical in eva-hq)” sourcing claim) superseded_by: none — current

Operators onboarding new consumer repos kept hitting the same friction: the bootstrap agent inside a freshly-installed consumer (e.g. asgard) would try to “emit a chosen_prompt”, fail to find a local prompts/ directory, and halt with a ground-truth-style refusal. The CLAUDE.md in petrova-codes told a story where eva-hq was canonical for prompts, but the bodies themselves lived in the core/prompts/ submodule (downstream of petrova-codes/prompts.git), and a re-vendored copy of META-RULES.md + 00-bootstrap.md lived in-tree at core/playbook/ for installer convenience. Three surfaces, manual sync, inconsistent authoring story. The dashboard’s /console/prompts page additionally looked like a fourth duplicate even though it was a live view.

Trigger: operator screenshot (“seeing prompts in three places, pick a strategy and lock it in”), 2026-05-14.

eva-hq authors. petrova.host serves. consumers carry only the boot kit and fetch the rest via Fleet MCP.

Concretely:

  1. eva-hq/prompts/{slug}/ is the sole authoring surface. Each prompt directory holds meta.yml, prompt.xml (eva wrapper), body.md (canonical markdown body, new this ADR — 11 bodies migrated from the retired prompts.git mirror), and optional guard.sh / verify.sh.
  2. petrova.host/console/prompts and eva.re/catalog are views, not copies. Both read eva-hq live via petrova.prompts.list / petrova.prompts.get (EvaSource in host/src/sources/eva.ts). The dashboard page header is relabelled “catalog · N prompts · live from eva-hq” to make this visible.
  3. Consumer .petrova/playbook/ is the runtime boot kit only: META-RULES.md, 00-bootstrap.md, partials, schemas. Six files. It is not the catalog. Consumer agents fetch every other prompt on demand via Fleet MCP (petrova.prompts.list/get). The asgard-style “no prompts/ directory exists” error is the symptom of an agent that hasn’t internalised this split, and the bootstrap text now carries an explicit consumer-contract callout to prevent it.
  4. petrova-codes/core/playbook/prompts/ is an in-tree mirror of the 11 paste-prompts, refreshed every 6 hours from eva-hq by .github/workflows/sync-playbook-from-eva.yml. This exists so petrova_install_playbook and the docs pipeline can read prompts without a network round-trip; it is machinery, not a parallel authoring surface.
  5. core/prompts/ submodule is retired, along with the petrova-codes/prompts.git repo it pointed at.
  • Consolidate everything into petrova-codes (move 58 prompts from eva-hq → petrova-codes/prompts-catalog/) — reverses the current ownership model, requires eva-hq to become a downstream consumer, bigger refactor, no clear win since eva-hq’s wrapper/verb tooling is more mature for prompts than petrova-codes’s.
  • Keep the three-surface status quo, just document it harder — doesn’t address the operator confusion or the synthetic-duplication appearance on /console/prompts, and leaves the manual core/playbook/ sync drift footgun in place.

For code:

  • eva-hq/prompts/{slug}/body.md added for 11 prompts (commit a3e0cc8 in eva-hq).
  • petrova-codes/core/prompts/ submodule removed (9501345).
  • petrova-codes/core/playbook/prompts/ populated; installer + scripts/sync-docs.mjs + codes/scripts/pull-content.ts repointed.
  • New CI workflow .github/workflows/sync-playbook-from-eva.yml mirrors every 6h; repository_dispatch event eva-playbook-changed available for on-demand triggers.
  • New CI workflow .github/workflows/petrova-notify-state.yml deposited by petrova_install_playbook into consumer .github/workflows/, fires repository_dispatch petrova-state-stale at petrova-codes on phase verb merges.
  • state-sweep.yml cron tightened from 6h to 30m, accepts repository_dispatch petrova-state-stale, runs forced on Node 24.
  • New RPC petrova.sweeps.trigger (rate-limited 60s) + browser-facing proxy at /api/sweeps/trigger; ▶ trigger sweep button on /console/sweeps. Companion petrova.sweeps.last_run surfaces workflow-level health distinct from per-repo data freshness.
  • Bot commits authored as petrova-bot <ops@devarno.cloud> to unblock Vercel auto-deploys (previously rejected on synthetic noreply email).

For docs:

  • CLAUDE.md “Where the playbook lives” section rewritten as a three-row surface table.
  • New /concepts/prompt-service/ page on petrova.blog (docs/site/concepts/prompt-service.md) is the canonical reader-facing explanation; /concepts/control-plane-vs-source-of-truth/ links it.
  • core/playbook/README.md relabelled “boot kit — not the catalog”.
  • Both root-level and installed 00-bootstrap.md copies carry the consumer-contract callout (MCP fetch, do not look local).
  • docs/runbooks/onboard-repo.md documents the PETROVA_DISPATCH_TOKEN setup (fine-grained PAT, Actions: read & write + Contents: read & write on petrova-codes/petrova).

For in-flight phases:

  • No phase impact in petrova-codes (control-plane self-entry is pre-phase by design). Consumer-side: existing repos with .petrova/playbook/ already installed need a re-run of petrova_install_playbook with overwrite: true to receive the notify workflow (separate ADR-tracked task).

For invariants:

  • No MR changes. This decision operates within MR-12 (control plane vs source-of-truth split) — extended to prompts as a separate surface type.

Deferred / known-stale references:

  • Append-only ADRs and historical specs/plans under docs/decisions/, docs/superpowers/specs/, docs/superpowers/plans/ retain literal core/prompts/ strings as historical fact (MR-7). Not swept.
  • META-RULES.md is not in eva-hq today — it still flows through the core/templates/ submodule pointer bump. Tracked separately; ADR updates CLAUDE.md to acknowledge this rather than overclaiming eva-hq’s canonical scope.
  • petrova-codes commits: 97e5a26, 9501345, 6a5c877, 47e7806, 0eefcdf, 52638f2, cd61f32, ad655cb, a9e8840, 5542931, d118aee, d1ecd1f.
  • eva-hq commit: a3e0cc8.
  • Related: docs/decisions/2026-05-13-petrova-onboarding-flow-v2.md — the bootstrap step in that flow now reads from core/playbook/prompts/00-bootstrap.md (in-tree mirror) instead of core/prompts/00-bootstrap.md (retired submodule).
  • Concept page: /concepts/prompt-service/.