Status:
accepted · Version 1.0 · Filed 2026-04-18SPEC-017 — prism_clone
One MCP verb that takes a project name and optional github_repo, auto-detects clone-vs-register-vs-bind, and terminates at the Plan #5 core invariant:Runs host-side (not in the backend)
The backend runs in a Docker container in personal mode and cannot write to the host filesystem for cloning a NEW project outside the mounted repo. Therefore:- git clone executes on the host (same process as the MCP server).
- Legacy-project detection probes the host filesystem.
- Prism-side registration (bootstrap_project, register_project_paths, prism_sync_bios) is delegated to existing verbs.
_execute_manifest pattern from bootstrap_project — backend computes, host applies.
Signature
Mode detection
Evaluateproject_dir on the host:
| Dir state | github_repo | Mode | Action |
|---|---|---|---|
| exists + has .git | any | register | bootstrap_project(strategy=“register” if Prism-structured else “bind”) |
| exists + no .git | any | ERROR | refuse — “directory exists but is not a git repo; won’t auto-init” |
| not exists | present | clone | host git clone <repo> <project_dir> → bootstrap_project(strategy=“register” if Prism-structured else “bind”) |
| not exists | absent | ERROR | refuse — “no directory and no repo given; nothing to do” |
PRISM.md OR context/_ACTIVE_CONTEXT.md OR plans/_TODO.md at repo root.
Terminal steps (all modes, unconditional on success)
register_project_paths(project_dir)— idempotent allowlist injection.prism_sync_bios(pid, files="all", dry_run=False, force=False)— best-effort; if PRISM.md pre-flight blocks, surface in response but don’t fail the whole call.- Legacy-project detection — returns
migration_candidate: bool+legacy_signatures: list[str].
Return payload
Legacy-project signature probes (Wave A stub — Wave B does full mapper)
Returnmigration_candidate=True if ANY of these are found at project_dir:
context/_ACTIVE_CONTEXT.mdplans/_TODO.mdplans/_DELTAS.mdAGENTS.mdcontaining the regexr"^# AGENTS\.md\s*$"as a legacy AGENTS.md header signature- A sibling Obsidian vault at
<project_dir>/../<name>Vault/or<project_dir>/.obsidian/
legacy_signatures. Wave A does NOT read the content or produce a migration plan.
Error shaping
DirExistsNotGit: dir present, no.git. Agent should escalate to the user.NothingToClone: dir absent and github_repo absent.GitCloneFailed: propagate git’s stderr in the error message.BackendError: wrap any HTTPError from the backend with the call that failed.
Smoke battery (Wave A exit gate)
fresh_clone— target dir absent, github_repo given, small repo. Expect mode=clone, PID created, paths registered, bios synced, migration_candidate=False.register_existing— target dir is a Prism project already on disk. Expect mode=register, PID resolved (or created via bootstrap register), allowlist updated, bios re-synced.bind_non_prism— target dir is a git repo with no Prism structure. Expect mode=bind, PID minted, scaffold manifest written, bios synced.error_exists_non_git— target dir exists, no.git. ExpectDirExistsNotGit. No side effects.
Exit gate for Wave A
All 4 smoke cases green; verb callable end-to-end from Claude Desktop and Claude Code MCP surfaces; terminal-state invariant verified by post-callprism_start(pid) cold read.
Frank-decisions NOT silently resolved
- FD-1 (Wave B): write path stays behind explicit user prompt, not auto-executed. (Affects Wave B migration integration — not Wave A.)
- FD-2/FD-3: n/a for Wave A.
Dependencies
- Existing:
bootstrap_project,register_project_paths,prism_sync_bios(all shipped). - New: host-side git subprocess, legacy-project detector stub, mode-detection branching.
- Not new: no backend schema change, no new route, no alembic migration for Wave A.

