Skip to main content
Status: active · Version 1 · Filed 2026-04-18

Plan #5 — Cross-machine clone + DFW migration + project symmetry + ambient memory

Status: PENDING — awaiting Frank’s GO

Filed 2026-04-18 from the “cloning gap” discovery session (Lola / Claude.ai project). Author: Donna (external reviewer voice). Gated on Plan #4 Wave A activation so we don’t interleave migrations with the server1 cutover.

Origin story

Frank attempted to clone an existing project (MemRGR) from his Windows machine to a new machine and found there was no Prism-native path for it. The discovery surfaced three adjacent gaps and one orthogonal one:
  1. No prism_clone primitive — cloning a git-hosted project onto a machine, placing it under $PROJECT_ROOT, registering it with Prism, and wiring it into the local filesystem-MCP allowlist is a 4-step manual dance with no single verb.
  2. No DFW→Prism migration path — projects like MemRGR carry legacy history in Obsidian markdown under the deprecated DFW process. That history is not currently accessible via semantic_recall and is not migrated on clone.
  3. Claude Desktop project ↔ Prism project ↔ directory symmetry is not guaranteed — creating a Claude Desktop project does not automatically create its Prism PID or its $PROJECT_ROOT/<name>/ directory. The three identities can drift from birth.
  4. No ambient-memory capture when not in a project — noodling outside any PID scope has no clean landing pad; content evaporates or gets mis-attached to whatever project happens to be open.
Plan #5 addresses all four under one spine because they share a critical invariant: every path to “project exists” must terminate at the same state — filesystem dir + (optionally) git repo + Prism PID + MCP allowlist entry + BIOS synced. Fixing them in isolation would allow the invariant to be half-implemented by each surface.

Core invariant (architectural through-line)

For every project Prism manages, these five facts must be simultaneously true:
dir_exists($PROJECT_ROOT/<name>)      AND
(optional) git_repo($PROJECT_ROOT/<name>)  AND
prism_pid_exists(<name>, project_dir) AND
mcp_allowlist_contains($PROJECT_ROOT/<name>) AND
bios_synced(<pid>)
Any verb, hook, or agent action that creates, clones, or binds a project must end in this terminal state. Any verb that destroys a project must unwind it symmetrically. Waves A, C, and (to a lesser degree) B all re-use this invariant.

Frank’s answers from the shaping session (2026-04-18)

  • Q1 (Wave A): prism_clone supports BOTH modes — auto-detect. If $PROJECT_ROOT/<name> exists, register-mode (bootstrap_project strategy=register/join). If not, clone-mode (agent runs git clone first). Same terminal state either way.
  • Q2 (Wave B): DFW detection automatic when a DFW vault is found in or near the repo. Migration pass triggered as part of the same clone call (still worth dry-run-preview before destructive writes — see Wave B body).
  • Q3 (Wave C): Claude Desktop is the preferred driver for project creation but the mechanism is convention-based, not hook-based: first-session-on-missing-PID triggers bootstrap_project automatically. Any Prism-enabled agent (Claude Code, Cursor, Codex) implements the same convention so Desktop-first and agent-first entry points converge on identical state.

Waves

Wave A — prism_clone primitive (keystone)

Goal: one MCP verb that takes a project name and optional github_repo, auto-detects clone-vs-register, and terminates at the core invariant. A1. SPEC-017 — prism_clone verb contract (see spec filing alongside this plan). A2. Backend implementation — route, service, input validation.
  • Signature: prism_clone(name, github_repo=None, project_dir=None, ptype="application", branch=None)
  • If project_dir omitted, default to $PROJECT_ROOT/<name> (already the registry convention).
  • Check isdir(project_dir):
    • exists + is git repo: register-mode → bootstrap_project(strategy=“register” if has-Prism-structure else “bind”)
    • exists + not git: error (ambiguous — refuse to auto-init)
    • not exists + github_repo given: clone-mode → git clone {github_repo} {project_dir} then bootstrap_project(strategy=“join”)
    • not exists + no github_repo: error A3. Call register_project_paths(project_dir) unconditionally at end of successful clone/bind. A4. Call prism_sync_bios(pid, files="all") at end to ensure CLAUDE/AGENTS/PRISM replicas are current against SOR. A5. Return structured payload: {pid, project_dir, mode: "clone"|"register", git_result, sync_result, migration_candidate: bool}. The migration_candidate flag is Wave B’s entry point — true when DFW vault detected. A6. MCP server exposure — wire prism_clone as a tool in mcp/server.py with the standard error-shaping pattern. A7. Smoke tests — 4 cases: fresh clone, register existing, git-but-no-Prism-structure (bind), failure mode (dir exists non-git). A8. Exit: Verb callable end-to-end from Claude Desktop and Claude Code MCP surfaces. Terminal-state invariant verified by post-call prism_start cold-read.

Wave B — DFW vault detection + migration

Goal: when prism_clone succeeds and DFW signatures are detected, offer migration; execute in dry-run-first, write-on-confirm mode. B1. DFW signature detector — probes for: AGENTS.md with legacy DFW constitution header, context/_ACTIVE_CONTEXT.md, plans/_TODO.md, plans/_DELTAS.md, co-located Obsidian vault with projects/<name>/_index.md. Returns structured detection payload listing what was found and where. B2. DFW artifact mappers — per artifact type, define the mapping:
  • plans/_TODO.md → Prism todos (status-aware; done items migrated as done)
  • plans/_DELTAS.md entries → Prism session_deltas
  • context/_DECISIONS_LOG.md → Prism decisions (ADRs, status=accepted where clear, proposed otherwise)
  • Obsidian retro notes → Prism retrospectives
  • Obsidian plan notes → Prism plans
  • Misc notes → Prism notes with source-path tag B3. Provenance discipline — every migrated row gets:
  • migration_source = "dfw_vault" tag
  • source_file = original path
  • source_created_at = original file mtime or frontmatter date (if parseable)
  • created_at = migration timestamp (honest about when the row landed in Prism)
  • Legacy PID preserved in a legacy_pid field or tag — never silently renamed B4. prism_migrate_dfw(pid, vault_path, dry_run=True) verb — default dry-run, prints the full migration plan (N plans, M retros, K decisions, L todos, P deltas) with per-item diff summary. No writes until dry_run=False. B5. Migration integrates with Wave A — when prism_clone returns migration_candidate=True, agent offers: “DFW vault detected at <path>. Migrate now? (dry-run first)” — never automatic write. B6. Backend schema — ensure legacy_pid, source_file, source_created_at, migration_source are either first-class columns or queryable tags across the affected tables (todos, session_deltas, decisions, retrospectives, plans, notes). May need a small Alembic migration. B7. Smoke test — use a copy of MemRGR’s DFW vault as the test fixture. Migrate, then semantic_recall("MemRGR ingestion architecture") against the new PID and confirm historical context surfaces with clear provenance. B8. Exit: migrated project’s history is readable via semantic_recall with source_file tags intact; no fabricated timestamps; legacy_pid preserved and queryable.

Wave C — Claude Desktop project ↔ Prism symmetry (convention-based)

Goal: creating a project in Claude Desktop (or starting work in one that lacks a PID) automatically produces the three-way binding. No platform hooks required — agent convention. C1. Authoring update to templates/prism-base.md and AGENTS.md — document the “first-session-on-missing-PID” convention. When prism_start(pid="") returns no resolution AND the current dir looks like a project root (heuristic: has .git/ or an AGENTS.md or a CLAUDE.md), the agent MUST prompt the user: “No Prism PID for this directory. Bootstrap now? (name=<dir basename>)” C2. prism_start payload enhancement — when pid resolution fails, include suggested_bootstrap: {name, project_dir, reason} so the agent has a structured prompt target. C3. Agent-side enforcement — AGENTS.md rule addition: “Never write to Prism without a resolved PID. If none resolves, bootstrap or ask.” C4. New verb or strategy extension — bootstrap_project already covers this; the gap is the agent-convention layer above it. Verify that calling bootstrap_project from within a Claude Desktop project session produces the same terminal state as calling it from Claude Code or Cursor. C5. Document the convention in AGENTS.md §X “Project entry protocol” with explicit examples for each editor surface. C6. Smoke test — create a fresh Claude Desktop project named TestSymmetry, open a session, verify the agent detects no-PID and offers bootstrap, accept, verify terminal state (dir exists at $PROJECT_ROOT/TestSymmetry, PID resolves, MCP allowlist contains the path, BIOS synced). C7. Repeat C6 from Claude Code and Cursor entry points — same terminal state, same convention, different surface. C8. Exit: three different agent surfaces produce identical terminal state when entering an unbootstrapped project.

Wave D — Ambient memory capture (noodling)

Goal: first-class write target for un-scoped content plus a triage verb for promoting inbox → PID or global. D1. prism_remember(scope="personal", text, tags=[]) — extend the existing remember verb to accept a scope parameter. scope="personal" writes to namespace global:personal with no PID. Semantic_recall already supports the namespace filter per ADR #4. D2. prism_capture(text, session_context={}, tags=[]) — new verb. Writes to namespace inbox:personal with session context (timestamp, originating agent, originating chat/project context if any). No PID required. This is the “I don’t know where this goes yet but I don’t want to lose it” bucket. D3. prism_triage(action, inbox_id, target_pid=None, target_scope=None) — new verb. action ∈ . Promotes an inbox item to a PID namespace or global:personal, or discards it. Never automatic. Matches the global_fact_candidates pattern from ADR-019. D4. Backend schema — inbox_items table with id, tenant_id, text, session_context jsonb, tags, status (open/triaged/discarded), created_at, triaged_at, triaged_to_pid, triaged_to_scope. Alembic migration. D5. prism_inbox(action="list", status_filter="open") — list verb for reviewing untriaged items. Mirrors the prism_todo list pattern. D6. Recall integration — semantic_recall already supports namespace filtering; verify inbox:personal and global:personal are queryable with no PID required. D7. AGENTS.md rule addition — when user says “remember this” outside a PID scope, agent should offer: “Capture to personal notes, or to inbox for later triage?” Never silently pick. D8. Smoke test — capture 3 items ambiently, list them, triage 1 to a PID, 1 to personal, discard 1. Verify all three flows end at correct terminal state and are recallable via semantic_recall with appropriate namespace. D9. Exit: ambient capture + triage loop works end-to-end; no content lost when working outside project scope.

Wave E — Dogfood: clone MemRGR end-to-end

Goal: the falsification test. The whole plan earns green only if Wave E produces a working Prism-native MemRGR with its DFW history migrated and recallable. E1. On new machine: user says “Claude, clone MemRGR from <git URL>” in a Claude Desktop session (not yet bound to any Prism PID). E2. Agent calls prism_clone(name="MemRGR", github_repo="{url}"). E3. Clone-mode triggers, git clone completes, bootstrap_project(strategy="join") runs, PID-MRGxx is created, paths registered, BIOS synced. E4. Return payload flags migration_candidate=True because DFW vault detected. E5. Agent offers DFW migration, user approves, dry-run runs, preview shown, user confirms, write executes. E6. Post-migration: prism_start PID-MRGxx returns structured context showing migrated TODOs, retros, decisions, plans with provenance tags. E7. semantic_recall("Learn Loop Phase 2 rationale", pid="PID-MRGxx") returns migrated content with source_file references. E8. Retro on Plan #5 captures what felt natural vs forced. Candidate G-scope lessons — especially around provenance, dry-run-first discipline, and the agent-convention symmetry layer. E9. Exit: MemRGR lives in Prism as a first-class project with history intact and honestly provenanced. If this fails, the plan hasn’t shipped — no matter what Waves A–D did in isolation.

Dependencies

  • Plan #4 Wave A must be GREEN before Plan #5 starts. Server1 cutover and this migration work should not interleave. Frank has not yet signed off on Plan #4 Wave A activation — this plan sits behind that gate.
  • TODO #48 (ORG.md override semantics) is not a blocker but its resolution shapes how per-user “personal scope” content interacts with org-wide overrides. Worth surfacing again when Wave D lands.
  • TODO #61 (retrieval-quality deep-dive) is parallel but independent — Plan #5 writes more data, retrieval-quality work improves how the data is queried. No ordering constraint.

Frank-decisions embedded (do not let agents silently resolve)

  • FD-1: confirm auto-migration trigger in Wave B is “detect then PROMPT for dry-run,” not “detect then automatically run dry-run + execute.” The word “automatic” in Frank’s answer to Q2 covers detection; the write path should still be confirmed. Surface on Wave B kickoff.
  • FD-2: Wave D’s global:personal namespace — single-user (Frank) or multi-user (each driver gets their own)? Today Prism is single-tenant single-user; this plan inherits that. Flag for revisit if ever multi-user.
  • FD-3: legacy PID handling — store as tag (legacy-pid-MRG001) or first-class column (legacy_pid) on migrated rows? Tag is zero-schema-change; column is queryable without recall. Surface on Wave B kickoff.

Out of scope for this plan

  • Multi-user ambient memory (Wave D is single-user).
  • Auto-detecting when a Claude Desktop project is renamed and keeping the Prism side in sync (one-way trigger only; rename is out of scope).
  • Migrating from sources other than DFW Obsidian vaults (Notion, plain-file projects, etc.) — explicit extension work if ever needed.
  • prism_destroy — the symmetric unwind verb. Probably wanted eventually but not this plan.
  • Connecting MemRGR’s graph RAG capability to Prism as a retrieval leg (that’s TODO #61 territory — separate thread).

Exit criteria for Plan #5 as a whole

  • Wave A: prism_clone callable from 3 agent surfaces, both modes work, terminal-state invariant holds.
  • Wave B: MemRGR-shaped DFW vault migrates into a Prism project with provenance tags intact and no fabricated timestamps; dry-run-first discipline enforced.
  • Wave C: creating a project from Claude Desktop OR Claude Code OR Cursor produces identical terminal state via agent convention.
  • Wave D: ambient capture + triage loop closes the “noodling” gap; nothing is lost when working outside PID scope.
  • Wave E: clone MemRGR end-to-end on a real machine, migrate history, retro captures lessons. This is the falsification test — plan ships only when Wave E is green.

Artifacts to produce

  • SPEC-017 — prism_clone verb contract (filed alongside this plan)
  • Alembic migration(s) for inbox_items, provenance columns on migrated tables
  • AGENTS.md §X “Project entry protocol” — the agent-convention layer from Wave C
  • Updates to templates/prism-base.md reflecting the entry-protocol rules
  • Retro document after Wave E
— Filed 2026-04-18 from the cloning-gap shaping session.
Last modified on April 20, 2026