# Plan — /soul-join: managed remote souls + catalog + project binding ## Problem Three demarkus surfaces can be configured at once — a hand-wired `.mcp.json` demarkus server ("pure MCP", e.g. `demarkus-soul` → soul.demarkus.io), the demarkus-memory plugin (local managed soul), and the demarkus-knowledge plugin (broker KS). All expose identical `mark_*` tools, so the agent can't tell which to write to. Today a *remote* soul can only be reached by hand-editing `.mcp.json`, which also leaks the auth token in plaintext into both `.mcp.json` and `claude mcp list`. There is no `/soul-join` (the soul index Vocabulary already anticipates one). ## Decision (Fritz, 2026-06-22) Build `/soul-join` into demarkus-memory so there is no manual MCP for souls, mirroring `/knowledge-join`. Token storage = wrapper + 0600 file (no secret in config). Maintain a **catalog** of souls plus a **per-project binding** that routes writes. Detect existing hand-wired demarkus-mcp entries and offer to adopt them. ## Data model - **Catalog** — `~/.demarkus/souls` (tab-separated, one row per remote soul): `\t\t\t`. The local managed soul stays in `plugin-memory.conf` (tier=local); a catalog view unions local + remote + knowledge endpoints. Tiers: `local` (plugin-managed), `remote` (joined). - **Per-project binding** — `~/.demarkus/project-souls`: `\t`. Which catalog soul this repo writes to by default. Set when `/soul-join` runs inside a repo. This is the routing key that ends the "which one?" confusion. - **MCP registration scope** — orthogonal: `project` (repo `.mcp.json`, default when joined in a repo) or `user` (global, no binding). ## Components 1. `lib.sh` — `SOULS_REGISTRY`, `PROJECT_SOULS` paths; helpers `register_remote_soul`, `remote_soul_fields`, `list_remote_souls`, `is_registered_remote_soul`, `bind_project_soul`, `project_soul_binding`. Extend `publish_gate_scope` so the tag-gate also fires on registered remote souls (today only `demarkus-memory`). 2. `scripts/soul-join.sh [--token T] [--insecure]` — normalize host (`mark://` scheme, `:6309` default port), derive + sanitize slug from first DNS label, write token to `~/.demarkus/soul-.token` (mode 600), `register_remote_soul`, emit `key=value`. Reachability = best-effort (demarkus is QUIC, no HTTP metadata; first tool call is the real check). 3. `scripts/soul-remote-wrapper.sh ` — registry-driven; exports `DEMARKUS_AUTH` from the token file and execs `demarkus-mcp -host [-insecure]`. Same pattern as the local `mcp-wrapper.sh`. 4. `scripts/detect-manual-souls.sh` — scan project + user `.mcp.json` for unmanaged `demarkus-mcp` entries; feed the adopt flow. 5. `commands/soul-join.md` — mirrors `knowledge-join.md`; includes the detect-and-adopt step. 6. `context/session-guidance.md` — describe catalog + binding + roles. 7. `tests/soul-join_test.sh`; bump `plugin.json` version. ## Constraints (project conventions) - Pure awk/bash, no runtime deps (jq/python/node forbidden). - Bash 3.2 (macOS stock). Branch + PR; Fritz commits. Never ship broken. ## Open / phase 2 - A **destination gate** (PreToolUse on `mark_publish`) enforcing the project→soul binding so a misrouted write is denied, not just guided. - `/soul-join` reachability hardening (one-shot stdio MCP probe).