← Ledger


title: Rocky — System Redesign status: Draft for review date: 2026-05-02 author: Alex (devarno) + Claude supersedes: docs/specs/2026-05-02-rocky-design.md (in scope, not in deletion — that doc remains the SS-07 RALPH spec)

Rocky — System Redesign

Purpose

Pivot rocky-hq from a single-feature Python prompt-queue tool into a superproject that delivers per-workspace operations & modelling. The existing Python tool becomes one subsystem (SS-07 RALPH) inside a multi-subsystem product whose canonical surface is the existing Next.js console previously developed at devarno-cloud/rocky (@rocky/ops).

Rocky's long-term role: every PETROVA-onboarded project gets exactly one Rocky instance, alongside one GRACE and one TRACEO instance. Rocky owns operations, modelling, prompt automation, and per-workspace knowledge-stack provisioning (1×CAIRNET + 1×LORE per workspace, tiered).

Goals

  1. Lift the existing Next.js @rocky/ops console (7 shipped subsystems, all VTM Pass) into the new structure without rewrites.
  2. Wrap the current Python rocky-hq CLI as a console subsystem (SS-07 RALPH) while keeping the standalone CLI usable.
  3. Add SS-08 HEARTH — a tiered per-workspace CAIRNET+LORE provisioner.
  4. Keep the system Airlock-tenanted: every action resolves to an authenticated Airlock session and a HATCH audit event.
  5. Ship as OSS by default, with cloud-only Polar.sh entitlement gates layered on top — never leaking commercial paths into self-host installs.
  6. Match devarno-cloud's superproject pattern so PETROVA already knows how to govern Rocky.

Non-goals (this redesign)

Big design decisions

Decision Choice Why
Repo shape Superproject + submodules (mirror of devarno-cloud) Reuses PETROVA governance, AGENTS.xml conventions, and push-down policy 0004 from devarno-cloud
Console source Lift devarno-cloud/rockyrocky-hq/console submodule, no rewrite 7 subsystems already shipped & VTM Pass; rewriting throws away working code
RALPH integration Keep Python; add ralph serve HTTP/worker mode; console wraps it claude-agent-sdk Python is the mature client; standalone CLI use case stays
Polyglot TS in console, Python in RALPH, Go in HEARTH One language per subsystem, never mixed inside one repo. Go chosen for HEARTH because k8s/Docker/kustomize ecosystem is Go-native and a single static binary is the right OSS distribution shape (rationale below).
Auth Keep Airlock BetterAuth on .devarno.cloud cross-subdomain cookies Already working in console/src/lib/auth.ts; tenancy invariant is non-negotiable
Audit Every state change → HATCH event via SS-05 RELAY "I want evidence of every Rocky use" (operator constraint)
Licensing OSS (MIT or Apache-2 — TBD per submodule) "Always design for open-source"
Monetisation Polar.sh entitlements gating cloud-hosted HEARTH tiers above solo "Always Polar.sh"; OSS solo tier always free
HEARTH tier model Config-driven ProvisioningProfiles, three drivers (LocalDocker / Kustomize / DevarnoCloud) Tier ≠ code path; drivers ≠ tiers; OSS parity requires LocalDocker
Failure handling for provisioning No auto-retry; loud failures; admin re-run Provisioning errors usually mean credential or capacity drift — silent retry hides the real problem

Architecture

Repository layout

rocky-hq/                                # this repo, the superproject
  console/         → submodule → @rocky/console      (Next.js 16 + React 19, lifted from devarno-cloud/rocky)
  ralph/           → submodule → @rocky/ralph        (Python 3, current rocky-hq codebase moved here)
  hearth/           → submodule → @rocky/hearth        (NEW; Go — see "Why Go for HEARTH")
  algo/            → submodule → @rocky/algo         (project-specific modelling packages, plugged via SS-03 PLUGINS)
  contracts/       → submodule → @rocky/contracts    (zod + JSON schema + proto for cross-submodule interfaces)
  docs/                                              (in-tree)
  registry.yaml                                      (in-tree; lists deployed workspaces + tiers)
  AGENTS.xml                                         (in-tree; PETROVA-compatible verb declarations)
  CLAUDE.md                                          (in-tree; MR-12 projection only)
  pyproject.toml + package.json minimal scaffolds for superproject-level scripts

Per devarno-cloud decision 0004 (push-down policy): the parent CLAUDE.md is projection-only. Build/test/runtime instructions live in each submodule's own CLAUDE.md.

Subsystem map

ID Name Lives in State today
SS-01 WORKBENCH console/src/lib/workbench/ Existing, VTM Pass
SS-02 DASHBOARDS console/src/lib/dashboards/ Existing, VTM Pass
SS-03 PLUGINS console/src/lib/plugins/ Existing, VTM Pass; becomes seam for ALGO packages
SS-04 WORKSPACE console/src/lib/workspace/ Existing, VTM Pass
SS-05 RELAY console/src/lib/relay/ Existing, VTM Pass; gains /api/relay/ralph and /api/relay/polar
SS-06 VAULT console/src/lib/vault/ Existing, VTM Pass; stores per-workspace HEARTH credentials
SS-07 RALPH ralph/ + console/src/lib/ralph/ Tool exists in rocky-hq today; console wrapper is NEW
SS-08 HEARTH hearth/ + console/src/lib/hearth/ NEW
ALGO algo/ (per-project Python packages) Plugged through SS-03 PLUGINS; not a subsystem

Tenancy invariant (applies to every subsystem)

No Rocky route, worker call, or driver action executes without:

  1. A valid Airlock session (admin / operator / observer / denied)
  2. A corresponding HATCH audit event written before the action takes effect
  3. (Cloud build only) A Polar.sh entitlement check on provisioning, upgrade, and decommission of any tier > solo. Per-request runtime checks are not required — the tier is enforced through the DeploymentRef row plus the tier_downgrade_active_data policy below.

Self-host (ROCKY_BILLING=disabled, typically with ROCKY_AUTH=local) skips (3) and resolves (1) via the LocalAuth adapter; (2) is non-negotiable in all builds (HATCH defaults to a local JSONL sink in self-host mode).

SS-07 RALPH — wrapping the Python tool

Inside ralph/ (the submodule)

The current rocky-hq Python code moves verbatim: cli.py, runner.py, agent.py, judge.py, merge_driver.py, journal.py, workspace.py, loader.py, plus tests and the existing design spec at docs/specs/2026-05-02-rocky-design.md.

One additive change: a new ralph serve mode.

The standalone rocky run CLI continues to work unchanged for self-hosters who don't want the console.

Inside console/src/lib/ralph/ (NEW)

// console/src/lib/ralph/client.ts
submitRun(workspace_slug: string, prompts_yaml: string, config: RunConfig): Promise<{ run_id: string }>
streamEvents(run_id: string): AsyncIterable<JournalEvent>
cancelRun(run_id: string): Promise<void>   // admin-only

UI surface

SS-08 HEARTH — per-workspace CAIRNET+LORE provisioning

Tiers

Tier Audience CAIRNET shape LORE shape Polar.sh gate
solo OSS self-host, single dev SQLite + local FAISS, 100MB cap Single-user, 30-day retention none — always free
team Small team, hosted Postgres + pgvector, 5GB cap, 5 seats Multi-user, 90-day retention, RBAC rocky-team subscription
studio Larger orgs, hosted Postgres + pgvector, 100GB cap, unlimited seats Multi-user, 1y retention, audit export rocky-studio subscription
bespoke Per-deal Driver-defined Driver-defined Out-of-band invoice via Polar.sh

A tier is a YAML row resolving to a ProvisioningProfile (resource caps + driver flags). Adding a tier never adds code paths.

Inside hearth/ (NEW submodule, Go)

// hearth/internal/driver/driver.go
type Driver interface {
    Provision(ctx context.Context, slug string, profile ProvisioningProfile) (DeploymentRef, error)
    Status(ctx context.Context, ref DeploymentRef) (Status, error)
    Upgrade(ctx context.Context, ref DeploymentRef, profile ProvisioningProfile) (DeploymentRef, error)
    Teardown(ctx context.Context, ref DeploymentRef) error
}

Cross-language types come from contracts/ via codegen — ProvisioningProfile, DeploymentRef, Status are defined once (zod or proto, TBD in the contracts spec) and emitted to both Go (via quicktype or buf if proto) and TypeScript.

Why Go for HEARTH

HEARTH is a coordinator: it calls Docker, k8s, and cloud APIs and writes a Postgres row. The decision is dominated by ecosystem fit and distribution shape, not by language semantics.

Rejected alternatives:

Drivers shipped:

State store: DeploymentRef rows in the console's existing Postgres — {workspace_slug, tier, driver, endpoint, secrets_vault_path, created, last_status}. Rocky never stores CAIRNET/LORE contents — only deployment metadata. Driver-issued credentials land in SS-06 VAULT keyed by workspace_slug.

Inside console/src/lib/hearth/ (NEW)

provisionWorkspace(slug: string, tier: Tier): Promise<DeploymentRef>     // admin-only
getWorkspaceDeployment(slug: string): Promise<DeploymentRef | null>      // any role with workspace access
decommissionWorkspace(slug: string): Promise<void>                       // admin-only

getWorkspaceDeployment is the discovery seam every other subsystem uses to resolve a workspace's CAIRNET/LORE endpoints.

Polar.sh integration

UI surface

End-to-end data flow (workspace onboarding → first RALPH run)

1. Human edits petrova-hq/registry.yaml — adds entry with rocky_tier=team
2. PETROVA verb provision_rocky(slug, tier) → console.hearth.provisionWorkspace(slug, "team")
3. SS-08 HEARTH:
   a. Airlock check: caller has admin role on workspace
   b. Polar.sh check: workspace has active "rocky-team" entitlement (cloud build)
   c. Driver=DevarnoCloud → deploys 1×CAIRNET + 1×LORE
   d. Credentials → SS-06 VAULT
   e. DeploymentRef row → console DB
   f. SS-05 RELAY → HATCH "hearth.provisioned"
4. Operator opens /ralph/runs/new:
   a. Selects workspace (HEARTH resolves CAIRNET/LORE endpoints)
   b. Uploads prompts.yaml
   c. submitRun() POSTs to ralph worker with HMAC + workspace context
5. RALPH worker (existing pipeline):
   plan → judge → execute → audit → merge per prompt
   Events stream SSE → console → browser; mirrored to HATCH
   Artifacts → SS-04 object store
6. Run finishes: ralph.runs panel updates; deviation reports linkable from /ralph/runs/[id]

Error handling

Class Where Behaviour
auth_denied Airlock check fails anywhere 403, HATCH audit, no further side effects
entitlement_missing Polar.sh check fails (cloud only) 402-equivalent, surface upgrade CTA, HATCH audit
driver_failure HEARTH driver errors mid-provision Roll back partial state, mark DeploymentRef failed, retain logs, no auto-retry
worker_unreachable Console can't reach RALPH worker "worker offline" banner, queue submission 60s, then fail
pipeline_deviation RALPH judge marks major Existing on-failure policy (stop|skip|realign) — unchanged
tier_downgrade_active_data Polar cancels, workspace exceeds new caps Read-only mode 7 days, then HATCH alert + admin decommission flow — never silent data loss

Every error class produces a HATCH event. Provisioning never auto-retries — failures are loud, admin re-runs explicitly.

Testing strategy

Three tiers (mirrors RALPH's existing pattern)

1. Unit (per submodule, fast, no network)

2. Integration (per submodule, real local services)

3. Smoke (manual, gated, real cloud)

CI shape

Mirrors devarno-cloud:

OSS test parity invariant

The solo tier + LocalDocker driver + LocalAuth adapter path must pass the full e2e test with no Polar.sh network calls and no devarno-cloud-tenant credentials. If a self-hoster's CI breaks on the e2e test, we broke OSS.

Licensing

PETROVA hookup (out of scope for this spec, sketched only)

petrova-hq/registry.yaml schema gains:

integrations_applicability:
  ...existing...
  rocky: required | optional | not_applicable
rocky_tier: solo | team | studio | bespoke    # only when rocky != not_applicable

PETROVA gains a provision_rocky verb that calls console.hearth.provisionWorkspace with the registry's declared tier. Verb design lives in a separate PETROVA spec.

KAHN integration (operator-facing observability)

KAHN (kahn-hq) is the operator's existing fleet-observability product (PRODUCT.md: "agent-fleet observability tool"). It already ships a vendored producer→consumer contract at kahn-hq/contracts/: transitions.schema.json, graph.schema.json, and a stdlib-only kahn_emit.py (additive-compatible; sister repos vendor it directly per contracts/README.md). Rocky does not duplicate this surface.

Phasing (rough order, fully detailed in the implementation plan)

  1. Stand up the superproject scaffold: empty submodule pointers, AGENTS.xml, CLAUDE.md projection, registry.yaml.
  2. Lift devarno-cloud/rockyrocky-hq/console (new repo, fresh history or filtered subtree — TBD; see open question).
  3. Move current rocky-hq Python code → rocky-hq/ralph. Add ralph serve. Wire console SS-07. Adopt KAHN's transitions.schema.json + vendor kahn_emit.py as the RALPH on-disk event format.
  4. Stand up rocky-hq/contracts with the cross-submodule schemas needed by SS-07.
  5. Build rocky-hq/hearth with LocalDocker driver only. Wire console SS-08. Ship the e2e test.
  6. Add Kustomize and DevarnoCloud drivers.
  7. Wire Polar.sh entitlements + /api/relay/polar.
  8. (PETROVA, separate spec) Extend registry schema and add provision_rocky verb.

Resolved decisions (formerly open questions)

  1. Submodule history → git subtree split. Preserves commit history and the VTM Pass lineage. Slightly slower lift, materially more credible provenance for the 7 already-shipped subsystems.
  2. HEARTH implementation language → Go. Rationale in "Why Go for HEARTH" above.
  3. contracts/ license → Apache-2.0. All other submodules are MIT. contracts/ is the only repo whose artifacts (zod schemas, proto, generated clients) get redistributed downstream by consumers, where the explicit patent grant in Apache-2 is the standard-of-care choice for schema/IDL libraries.
  4. algo/ shape → one repo with namespaced packages. @rocky/algo-devarno-finance, @rocky/algo-foo, etc. PETROVA governs one slug, package boundary is the per-project unit. Re-evaluate at ≥3 consumers — split if individual project teams need independent release cadence.
  5. OSS solo identity → LocalAuth adapter. Self-host with ROCKY_AUTH=local resolves the Airlock session to a local single-user identity (file-backed). Tenancy invariant still holds; the HATCH event sink defaults to a local JSONL file in this mode. Cloud build (ROCKY_AUTH=airlock) is unchanged.