# Plan: Claude Code Plugin Make demarkus usable in Claude Code with a single marketplace install. No manual server setup, no token generation, no `.mcp.json` hand editing. ## Goal After `/plugin marketplace add latebit-io/demarkus` and `/plugin install demarkus-memory`, the user has a working memory agent. `mark_fetch`, `mark_publish`, `mark_append`, and the rest of the MCP tool set are available. A local `demarkus-server` backs them. Memory persists across sessions. The TUI and browser can hit the same server on the same machine. ## Non-Goals - Cross-machine sync of the local soul. Users who want that run a networked server and reconfigure the plugin. - Windows native. WSL only, matching the rest of demarkus. - Embedded (in-process) MCP mode. We keep server and client as separate processes; the plugin just automates the spin-up. - Remote marketplace hosting. The plugin lives in the monorepo and is published via a marketplace.json at the repo root. ## User Flow 1. `/plugin marketplace add latebit-io/demarkus` 2. `/plugin install demarkus-memory@demarkus` 3. Postinstall downloads platform-specific binaries to `${CLAUDE_PLUGIN_ROOT}/bin/` 4. On the next session, a SessionStart hook ensures the server is up and the token exists 5. The agent has the full MCP tool set pointed at `mark://localhost:` No config files to touch, no prompts, no decisions forced on the user. ## Architecture ### Process Lifecycle: Lazy Spawn The SessionStart hook: - Checks for an existing server with `pgrep -f "demarkus-server.*\.demarkus/soul"`; if running, noop - Otherwise spawns it detached: `${CLAUDE_PLUGIN_ROOT}/bin/demarkus-server -root ~/.demarkus/soul -port $PORT -log-file ~/.demarkus/soul/.log &` followed by `disown` - Server persists across sessions; the next session reuses it No service manager (launchd, systemd user unit) in v1. If the process model proves fragile later, promote to a user service. ### Content Root `~/.demarkus/soul/` is the default content directory. Created on first run. All versioning, graph data, tokens, and logs live under it. ### Port Handling Default port: 6310. On every SessionStart: 1. Try to connect to `127.0.0.1:6310` 2. If something responds, fetch `/.well-known/demarkus-instance.md` and compare its instance ID against `~/.demarkus/soul/.instance-id` 3. If it is our server, reuse the port 4. If the port is taken by something else, pick the next free port in a small range, write it to `~/.demarkus/soul/.port`, and spawn the server there 5. The MCP client reads the chosen port from `.port` (falls back to 6310 if absent) ### Auth On first run the hook generates a token via `demarkus-token`, scoped `/*` with ops `publish,archive`. The raw token is written to `~/.demarkus/soul/.token` with mode 0600. The hashed form lives in the server's `tokens.toml` under the content root. `demarkus-mcp` gets a new `-token-file ` flag that reads the raw token from disk. This keeps the secret off argv and out of `ps`. ### First-Run Seeding The plugin ships a `seed/index.md` template. The SessionStart hook copies it to `~/.demarkus/soul/index.md` only when the content root is empty. The agent expands from there. Minimal seed: ```md # My Soul Personal memory for Claude Code agents. ## Sections - [Journal](/journal.md) — session notes - [Notes](/notes.md) — anything worth remembering ``` ## Plugin Layout ``` plugins/claude-code/ .claude-plugin/plugin.json hooks/ postinstall.sh # download + verify binaries session-start.sh # ensure server, ensure token, seed index .mcp.json # demarkus-mcp -host mark://localhost: -token-file ... commands/ soul.md # /soul → display /index.md soul-journal.md # /soul-journal → mark_append /journal.md skills/ memory/SKILL.md # triggers on remember/save/note/recall seed/ index.md ``` At the monorepo root: `.claude-plugin/marketplace.json` listing the plugin and pointing at `plugins/claude-code/`. ## Binary Distribution `postinstall.sh`: 1. Detects platform via `uname -sm` (darwin/arm64, darwin/amd64, linux/amd64, linux/arm64) 2. Reads the plugin version from `plugin.json` 3. Downloads the three binaries from `https://github.com/latebit-io/demarkus/releases/download/v/...` 4. Verifies SHA256 checksums against a bundled checksums file 5. Places binaries in `${CLAUDE_PLUGIN_ROOT}/bin/` and `chmod +x` them Binaries required: `demarkus-server`, `demarkus-mcp`, `demarkus-token`. GoReleaser already produces these per platform; the only possible pipeline tweak is ensuring the release assets include a consolidated SHA256SUMS file. ## Required Code Changes Small and surgical: 1. **`demarkus-mcp -token-file `** — read the raw token from a file. Error when the file is missing, empty, or has permissions looser than 0600. 2. **`/.well-known/demarkus-instance.md`** — auto-served on the server, body contains the instance ID generated once on first boot and stored at `/.instance-id`. Lets port probes distinguish our server from a colliding process. 3. **`demarkus-token -out `** (optional, nice to have) — atomically writes the raw token to a file with 0600 perms, avoiding shell piping. Everything else (server, store, MCP client, protocol) is unchanged. ## Commands and Skills ### Slash Commands - `/soul` — `mark_fetch /index.md` and render - `/soul-journal ` — `mark_append /journal.md` with the entry, auto-resolving `expected_version` ### Skill: Memory Triggers on phrases like "remember this", "save to memory", "what do I know about X", "note that", "recall". - Read intents → `mark_fetch`, then `mark_backlinks` or `mark_graph` for exploration - Write intents → `mark_append /notes.md` by default, or `mark_publish` to a topic page when the agent decides the note deserves its own document ## Release Pipeline - Plugin version tags follow the monorepo convention: `claude-code-plugin/v0.1.0` - Releases are cut from main; the marketplace.json is updated in the same commit - Users who already added the marketplace get the update via `/plugin marketplace update` ## Open Questions and Deferred Work - **Service installer**: launchd plist / systemd --user unit. Deferred. Lazy spawn is enough for v1. - **Binary auto-update**: v1 downloads on postinstall only. A later version can verify against latest on SessionStart and prompt. - **Cross-machine access**: document the path for users who want to run a networked server and point the plugin at it, but don't automate the migration. - **Port collision UX**: if the probe can't find a free port in the scanned range, the hook should surface a clear error rather than silently fail. ## Phasing ### Phase 1: Core plugin (ships usable v1) 1. Add `-token-file` flag to `demarkus-mcp` 2. Add `/.well-known/demarkus-instance.md` handler to the server 3. (Optional) Add `-out` flag to `demarkus-token` 4. Write `postinstall.sh` and `session-start.sh` 5. Author `.mcp.json`, `plugin.json`, seed `index.md` 6. Publish `.claude-plugin/marketplace.json` at the monorepo root 7. Manual end-to-end test on darwin/arm64 and linux/amd64 ### Phase 2: Agent surface 8. Slash commands (`/soul`, `/soul-journal`) 9. Memory skill 10. Documentation for migrating to a networked server ### Phase 3: Polish 11. Optional user-level service installer 12. Binary update flow on SessionStart 13. Better port-collision error messaging ## Success Criteria - Fresh Claude Code install + marketplace add + plugin install → a working `mark_fetch /index.md` on first session with zero prompts - Existing demarkus users can disable the plugin-managed server and point MCP at their own server via a documented override - Plugin works offline on subsequent sessions (no network needed once binaries are cached) - Total install time under 10 seconds on typical broadband