Skip to main content
Status: draft · Version 0.1 · Filed 2026-04-29

version: 0.1 status: draft

Title: SPEC-055 v0.1 — Generic Operator Lifecycle: Target-Registry-Driven LAN install/upgrade/clone-db/backup, No Hardcoded Host Identifiers

Version

0.1

Status

draft

Origin

The current operator lifecycle (prism_deploy, prism_clone_from, prism_backup MCP verbs + their shell wrappers bin/prism-deploy-server1.sh, scripts/clone-server1-to-local.sh) is hardcoded to one specific deployment: donna@server1.home.lan, /home/frank/Prism, prism-server-postgres, neo4j password prism_server, etc. SPEC-051 Phase 1 v0.1 explicitly punted on multi-target (“only target='server1' supported”). The Python server1_config() function is a literal: anyone else running Prism on their own server has to set ~10 env vars or fork the source. Frank’s correction during the SPEC-054 tier 1C-redux design discussion: this is a commercial product. The operator-side lifecycle must be commercial-grade — generic enough that any user, on any server, can use it without forking. Names describe the operation, not the host. Per-deployment data lives in config/env/db, not source. This spec defines the multi-target replacement and retires the server1-shaped verbs.

§1 — Goals

  1. Zero machine-specific identifiers in source. No literal server1, donna@, /home/frank, prism-server-postgres as defaults in any TS or Python file under cli/, mcp-node/, or anywhere a user pulling the repo would inherit them.
  2. Operation-based naming. Verbs and CLI subcommands describe what they do (install-lan, upgrade-lan, clone-db, backup), not which deployment they target.
  3. Config-driven targets. A per-operator target registry (~/.prism/targets.json) lists all named LAN/cloud destinations the user has configured. Verbs and CLI subcommands take a --target <name> arg that names a key in the registry. Empty registry → operator runs prism configure-lan (or edits the file) before any install/upgrade verb works.
  4. Intent-first verbs. prism_install_local, prism_install_lan, prism_upgrade_lan, prism_clone_db, prism_backup — separate verbs per intent, not one multiplexed prism_deploy(target=...). Aligns with feedback memory feedback_intent_is_first_class.md.
  5. CLI is the primary surface. The operator interface is prism install-lan, prism upgrade-lan, etc. — the same CLI that owns prism install --mode local today. MCP verb wrappers exist for AI-FIRST coverage but delegate to the CLI implementation; both share the target-registry lookup.
  6. Frank’s existing setup keeps working. Migration: a one-time prism configure-lan --import-legacy pulls his current donna@server1.home.lan config out of env-var defaults and writes it into ~/.prism/targets.json as a named target (default name home-lan or operator-chosen).

Non-goals (v0.1)

  • Cloud / SaaS targets. Mode cloud stays deferred per ADR-021 — same v0.1 cutoff.
  • Backend changes. Same as SPEC-054: backend Docker stack untouched.
  • Multi-tenant target visibility. v0.1: targets are per-operator, in the operator’s home dir. Tenant-shared target registry is future work.
  • Auto-discovery. Operator declares targets explicitly via prism configure-lan; nothing auto-detects LAN servers.

§2 — Target Registry

Location

~/.prism/targets.json (overridable via PRISM_TARGETS_FILE env). Same dir as credentials.personal.json.

Schema

Container names default-derive from the target key (e.g., target homeprism-home-postgres). Operator can override per-target.

CLI — prism configure-lan

Interactive add/edit. Prompts for ssh target, key, repo dir, backend URL, container-name pattern. Validates ssh connectivity (try a ssh user@host echo ok with BatchMode=yes) before persisting. Writes the new target into targets.json; offers to set as default_target if it’s the first. Non-interactive form: prism configure-lan --name=<n> --ssh-target=<...> --ssh-key=<...> --repo-dir=<...> --backend-url=<...> for scripted setup.

CLI — prism configure-lan --import-legacy

One-shot migration. Reads PRISM_DEPLOY_* env vars + credentials.personal.json and writes them as a named target in targets.json. Default name home-lan; --name overrides. Idempotent. After this lands and Frank runs it once, his existing setup works unchanged through the new verb names.

§3 — Verb Surface

Retired verbs

  • prism_deploy(target='server1', mode='full')retired. Replaced by prism_upgrade_lan(target=<name>, mode='full').
  • prism_clone_from(target='server1')retired. Replaced by prism_clone_db(from_target=<name>).
When the Node shim sees a call to a retired verb name, it returns:
For one release. After that, the verb name is freed.

New verbs

Bootstrap-skip

All seven verbs are bootstrap-skipped (operator-side, not project-session-scoped). Same posture as prism_persona_create and prism_set_force_credentials today.

§4 — CLI Surface

The legacy prism install --mode local|lan form stays for one release as an alias. After that, the dashed forms (install-local, install-lan) are canonical. prism install-lan requires the target to already exist in the registry. Error message points at prism configure-lan.

§5 — Implementation Layout

The CLI workspace is the canonical home for operation logic; MCP verbs become thin wrappers. This split mirrors how prism install --mode local already works (CLI implements; no MCP verb today).

§6 — Cutover Plan

Phase 1 — Land SPEC-055 implementation in cli/ + mcp-node/ (this spec)

  • New cli/src/targets.ts + cli/src/ops/* modules.
  • New CLI subcommands (install-lan, upgrade-lan, configure-lan, clone-db, backup, list-targets).
  • New MCP verbs in mcp-node/src/verbs/tier1c.ts replacing the shell-out stubs.
  • prism_deploy + prism_clone_from registered as retired (return retirement payload).
  • Legacy mcp/deploy.py + mcp/backup.py + mcp/clone_from.py + bin/prism-deploy-server1.sh + bin/prism-backup.sh + scripts/clone-server1-to-local.sh deleted.

Phase 2 — Frank’s migration

  • Frank runs prism configure-lan --import-legacy --name home-lan once.
  • Verifies prism upgrade-lan --target home-lan works.

Phase 3 — Retire the retirement (next release)

  • Delete mcp-node/src/verbs/retired.ts.
  • Drop prism_deploy + prism_clone_from from mcp-node/src/verbs.ts registry list.

§7 — Verification

  1. git grep -nE 'server1|donna@|/home/frank' -- cli/ mcp-node/ returns zero source references after Phase 1 (matches in docs/, archive/, changelog/retros are fine — those are historical record).
  2. ~/.prism/targets.json after prism configure-lan --import-legacy has Frank’s existing setup as a named target.
  3. prism upgrade-lan --target home-lan --mode full is functionally identical to today’s prism_deploy(target='server1', mode='full') — same rsync/build/restart/health/verify stages, same structured return.
  4. prism upgrade-lan --target <other-target> (e.g., a hypothetical staging target) works without code changes — only registry entry needed.
  5. The MCP verb prism_deploy returns the retirement payload with use_instead: prism_upgrade_lan.
  6. Empty registry: prism upgrade-lan errors with a clear message naming prism configure-lan as the fix.

§8 — Decisions

  • D1 — CLI is primary, MCP verb is wrapper. Same posture as prism install --mode local today (CLI-only, no MCP verb today). MCP wrappers exist for AI-FIRST.
  • D2 — Intent-first verb naming. Per feedback_intent_is_first_class.md. Separate prism_install_lan / prism_upgrade_lan / prism_clone_db rather than multiplexed prism_deploy(action=...).
  • D3 — Per-operator registry, not tenant-shared. v0.1 keeps targets in ~/.prism/. Tenant-shared registry is future work — needs auth + permission model that doesn’t exist yet.
  • D4 — Container names derive from target key by default. Override per-target. Avoids the operator having to specify three identical-shape container names every time.
  • D5 — Retirement payload, not silent rename. prism_deploy returns a structured verb_retired error with use_instead for one release. Hard removal in next release. Gives any external scripts a deterministic upgrade path.
  • D6 — --import-legacy migration. Frank gets a one-shot to convert his existing setup. Avoids “dies on first call after merge.”
  • D7 — Target registry schema is versioned. version: 1 field allows future schema migrations without ambiguity.

§9 — Open Questions

  • Q1 — Default target convention. If --target omitted and registry has exactly one entry: use it (operator convenience). If multiple: error with list. Resolution: confirmed during implementation; this is the behavior unless Frank objects.
  • Q2 — Target validation depth. prism configure-lan validates ssh connectivity. Should it also validate repo_dir exists on remote? Probably yes — costs one extra ssh round trip. Resolution: yes.
  • Q3 — Secrets in registry. targets.json deliberately holds no secrets — only paths and IDs. API keys stay in credentials.personal.json (one set per local install). neo4j_password resolved via env-var name in registry. Resolution: confirmed; secrets stay separated by file.
  • Q4 — prism_install_lan vs prism_upgrade_lan first-time semantics. install-lan should be safe to run on a target that already has Prism installed (idempotent — short-circuits to upgrade). Or strict (errors if already installed). Resolution during implementation: idempotent.

§10 — Performance Consciousness

  • Target registry is small (single JSON file, < 10KB even with many targets). Read-once-per-verb-call cost is negligible.
  • ssh ControlMaster reuse from SPEC-051 carries forward: still one master socket per verb invocation.
  • No new HTTP round-trips vs today’s prism_deploy semantics.
  • CLI subcommand dispatch adds one extra layer for MCP verbs (mcp_node/verbs → cli/ops); offset by the elimination of shell-out subprocess fork cost.

§11 — Authorship

  • Author: Donna (Claude Code, session c1d19f01) 2026-04-29.
  • Trigger: Frank’s correction during SPEC-054 tier 1C-redux design discussion — exact words: “this is a commercial product and we continue to take the easy way out.” The hardcoded server1_config() and bin/prism-deploy-server1.sh smell triggered the redesign.
  • Implementation owner: Lafonda (install lane). Donna authors the spec and hands off via signal.
  • Implementation gate: Frank’s GO. Lafonda’s PR #21 (SPEC-054 Phase 3) ships first; this spec’s implementation is a follow-up.

§12 — Relationship to Other Specs

  • Supersedes SPEC-051 Phase 1 + Phase 2 multi-target hardcoding. SPEC-051 itself stays in history; the verbs it shipped (prism_deploy, prism_clone_from) move to retirement.
  • Aligns with SPEC-053 (consumer-grade install consolidation, ADR-030 — currently open as PR #12). SPEC-053 covers consumer bootstrap one-liners + prism update + statusline wiring; SPEC-055 covers the multi-target server-side install lifecycle. Lafonda noted in her SPEC-054 ack that PR #12 will rebase onto Phase 3 + this spec.
  • Inherits target-registry pattern from credentials handling — same ~/.prism/ location, same per-operator scope.
  • Consistent with feedback_no_hardcoded_machine_values.md and feedback_commercial_grade_naming.md — both say zero machine-specific identifiers in source.
  • Does not modify feedback_intent_is_first_class.md posture — separate verbs per intent, not multiplexed flags.
Last modified on May 3, 2026