diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1b60657 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,46 @@ +# .dockerignore — trim the Docker build context. +# Without this, `docker build` tries to copy the full working tree into the +# daemon, including target/ (2.6 GB after v0.21 aws-sdk-s3), agent worktrees +# (6+ GB), and node_modules. That caused an I/O error on 2026-04-22 when the +# battle-test image tried to pack everything. +# +# Keep this list aligned with tests/battle/Dockerfile.install-test — anything +# the Dockerfile actually needs (scripts/, install/, hooks/, skills/, etc.) +# must NOT be listed here. + +# Rust build artefacts +**/target/ +**/*.rlib +**/*.rmeta + +# TypeScript / node +**/node_modules/ +**/dist/ +**/.turbo/ + +# Agent worktrees (several GB — never relevant inside a container build) +.claude/worktrees/ + +# Git internal (we don't need history inside the image) +.git/ + +# IDE + OS +.DS_Store +.idea/ +.vscode/ +*.swp + +# Editor backups +*~ +*.bak +*.bak-* + +# Secrets (defence in depth — RULE 0.8 + project .gitignore) +**/.env +**/secrets/*.env +*.pem +*.key + +# Logs +*.log +/tmp/ diff --git a/docs/USB-BRAIN-GUIDE.md b/docs/USB-BRAIN-GUIDE.md new file mode 100644 index 0000000..5b96fe9 --- /dev/null +++ b/docs/USB-BRAIN-GUIDE.md @@ -0,0 +1,306 @@ +# USB Exobrain — Step-by-Step Test Recipe + +> Goal: put a KeiSeiKit "brain" on a physical USB drive or flash card, mount it into Claude Code (and Cursor / Continue / Zed if installed), verify MCP tools are live, unplug — verify clean detach. +> +> Target audience: someone trying the v0.21 exobrain feature for the first time on macOS (adapt paths for Linux). + +--- + +## 0. Prerequisites + +On the host (your laptop): + +- KeiSeiKit installed: `./install.sh --profile=full` ran successfully, `cargo test -p keisei` shows 28/28 pass. +- `keisei` CLI on PATH: `ls ~/.claude/agents/_primitives/_rust/target/release/keisei` returns the binary. Optionally `ln -sf ~/.claude/agents/_primitives/_rust/target/release/keisei ~/.local/bin/keisei` so you can just type `keisei`. +- Claude Code installed (or Cursor / Continue / Zed — the CLI auto-detects all four). +- A USB stick or flash card mounted on macOS — expected path `/Volumes/` (e.g. `/Volumes/EXOBRAIN`). + +On the USB drive: + +- Filesystem: exFAT or APFS (not HFS+ if you want cross-platform). FAT32 works but has 4 GB per-file limit — fine for brain dir (< 200 MB total even with 5 platform binaries). +- Free space: ~500 MB recommended (5 mcp-server binaries × ~90 MB each = ~450 MB, plus room for memory/artifacts SQLite). + +--- + +## 1. Create the brain directory + +Replace `EXOBRAIN` with your actual USB volume name. + +```bash +BRAIN=/Volumes/EXOBRAIN/my-brain +mkdir -p "$BRAIN"/{bin,memory,artifacts,manifests} +``` + +Structure after step 1: +``` +/Volumes/EXOBRAIN/my-brain/ +├── bin/ +├── memory/ +├── artifacts/ +└── manifests/ +``` + +--- + +## 2. Download MCP server binaries for every platform + +Grab the 5 single-binary compiles from the latest GitHub release. For v0.21.0: + +```bash +BASE=https://github.com/KeiSei84/KeiSeiKit/releases/download/v0.21.0 +cd "$BRAIN/bin" + +# macOS Apple Silicon +curl -fL -O "$BASE/kei-mcp-server-darwin-arm64" +curl -fL -O "$BASE/kei-mcp-server-darwin-arm64.sha256" + +# macOS Intel +curl -fL -O "$BASE/kei-mcp-server-darwin-x64" +curl -fL -O "$BASE/kei-mcp-server-darwin-x64.sha256" + +# Linux x86_64 +curl -fL -O "$BASE/kei-mcp-server-linux-x64" +curl -fL -O "$BASE/kei-mcp-server-linux-x64.sha256" + +# Linux arm64 (may be unavailable on older releases — continue-on-error in CI) +curl -fL -O "$BASE/kei-mcp-server-linux-arm64" 2>/dev/null || echo "skipped linux-arm64" + +# Windows x86_64 +curl -fL -O "$BASE/kei-mcp-server-windows-x64.exe" +curl -fL -O "$BASE/kei-mcp-server-windows-x64.exe.sha256" + +# Verify every downloaded binary against its .sha256 +for f in kei-mcp-server-*.sha256; do + shasum -a 256 -c "$f" || echo "FAIL: $f" +done + +# Strip macOS Gatekeeper quarantine + chmod +x on Unix binaries +chmod +x kei-mcp-server-darwin-* kei-mcp-server-linux-* 2>/dev/null || true +xattr -d com.apple.quarantine kei-mcp-server-darwin-* 2>/dev/null || true +``` + +Expected: every `shasum -c` prints `OK`. + +--- + +## 3. Write `manifest.toml` (schema v2, per-platform) + +```bash +cat > "$BRAIN/manifest.toml" <<'EOF' +[brain] +schema_version = 2 +name = "my-brain" +created = "2026-04-22T00:00:00Z" + +[paths] +memory = "memory/" +artifacts = "artifacts/" +manifests = "manifests/" + +[paths.mcp_server] +darwin-arm64 = "bin/kei-mcp-server-darwin-arm64" +darwin-x64 = "bin/kei-mcp-server-darwin-x64" +linux-x64 = "bin/kei-mcp-server-linux-x64" +linux-arm64 = "bin/kei-mcp-server-linux-arm64" +windows-x64 = "bin/kei-mcp-server-windows-x64.exe" +EOF +``` + +Validation: `keisei` rejects the brain if `name` contains anything outside `^[a-z][a-z0-9_-]{0,63}$`, if any path is absolute, if any path contains `..`, or if the root is a symlink. + +--- + +## 4. Verify the brain loads before attaching + +```bash +keisei list-adapters +``` + +Expected: 2-column table showing every adapter, `detected: yes` for at least `claude-code` (the others depend on whether Cursor / Continue / Zed are installed on this host). + +If you want a dry-run of the brain itself without touching any client config: +```bash +# Loads manifest, validates path confinement + schema — then errors because +# nothing attached yet. Use the error to confirm load-path is clean. +keisei status +# Expected: "no brain attached" +``` + +--- + +## 5. Attach the brain to Claude Code + +Single-client, user scope (the safe default): + +```bash +keisei attach "$BRAIN" --scope=user +``` + +Expected output (literally): +``` +attached brain 'my-brain' to claude-code (user scope) + brain path: /Volumes/EXOBRAIN/my-brain + mcp server: /Volumes/EXOBRAIN/my-brain/bin/kei-mcp-server-darwin-arm64 + client cfg: /Users/you/.claude/settings.json + marker: /Users/you/.keisei/attached.toml +run /help in Claude Code to verify the MCP server is reachable +``` + +The last line is the client-specific post-attach hint. Each adapter emits its own. + +--- + +## 6. Verify in Claude Code + +Close and reopen Claude Code (or run `/help` → "MCP servers" section). You should see `my-brain` listed with the `/Volumes/EXOBRAIN/my-brain/bin/kei-mcp-server-darwin-arm64` command. + +```bash +# On the host, inspect what just got written: +cat ~/.claude/settings.json | jq '.mcpServers["my-brain"]' +# Expected: +# { +# "command": "/Volumes/EXOBRAIN/my-brain/bin/kei-mcp-server-darwin-arm64", +# "env": { +# "KEISEI_BRAIN_ROOT": "/Volumes/EXOBRAIN/my-brain" +# } +# } +``` + +Run a Claude Code command that uses a tool from kei-mcp-server (any of the 25+ MCP tool endpoints). If Claude Code reports success, the brain is live. + +--- + +## 7. Multi-client mount (all detected clients at once) + +```bash +keisei mount "$BRAIN" +``` + +Fan-out attach to every client detected on this host. For each, writes to user-scope config (`~/.claude/settings.json`, `~/.cursor/mcp.json`, `~/.continue/config.json`, `~/Library/Application Support/Zed/settings.json`). + +Expected summary: +``` +mounted brain 'my-brain' to: + claude-code ✓ + cursor ✓ + continue ✗ (not detected) + zed ✓ +``` + +--- + +## 8. Project-scope attach (Claude Code / Cursor only) + +Useful for per-project brains that stay with the repo: + +```bash +cd ~/path/to/your-repo +keisei attach "$BRAIN" --scope=project +``` + +Writes to `./.claude/settings.json` (inside the repo) instead of `~/.claude/`. Continue and Zed reject this scope with a clear error — they don't have per-project MCP config. + +--- + +## 9. Verify brain health + +```bash +keisei status +``` + +Expected: +``` +attached: my-brain + brain path: /Volumes/EXOBRAIN/my-brain + attached at: 2026-04-22T17:30:00Z + clients: + - claude-code (user scope) ~/.claude/settings.json + - cursor (user scope) ~/.cursor/mcp.json + - zed (user scope) ~/Library/Application Support/Zed/settings.json + health: OK (manifest readable, mcp_server binary exists) +``` + +If you unplug the USB, re-run `keisei status`: +``` + health: WARN — mcp_server binary at is not reachable + (brain was mounted at /Volumes/EXOBRAIN/my-brain, which no longer exists) +``` + +--- + +## 10. Detach — clean up when done + +```bash +keisei detach +``` + +Strips the `mcpServers.my-brain` entry from every client's config (preserving any other MCP servers you have configured), then deletes the marker. + +Expected: +``` +detached 'my-brain' from: + claude-code ✓ + cursor ✓ + zed ✓ +marker removed: ~/.keisei/attached.toml +``` + +Confirm: +```bash +keisei status # → "no brain attached" +jq '.mcpServers' ~/.claude/settings.json # → your own entries only +``` + +--- + +## 11. Eject the USB safely + +```bash +# macOS: +diskutil eject /Volumes/EXOBRAIN + +# Linux: +umount /media/$USER/EXOBRAIN +``` + +Physically unplug. + +--- + +## Troubleshooting + +### "BrainNotFound" on attach +- Check `/Volumes/EXOBRAIN/my-brain/manifest.toml` exists +- Check the path to `keisei attach` is absolute (`/Volumes/...`), not relative + +### "PathEscape" on attach +- Every path under `[paths]` must be relative and resolve inside the brain root. No `../`, no absolute paths. + +### "BrainIsSymlink" on attach +- `/Volumes/EXOBRAIN/my-brain` is a symlink to elsewhere. Pass the real resolved path instead — `keisei` refuses symlink roots to prevent accidental host-dir pivot via crafted USB. + +### "NoPlatformBinary" on Claude Code first-use +- Your platform's binary isn't in `bin/`. Check `std::env::consts::{OS, ARCH}` on your host — the expected filename is `kei-mcp-server--` where macos→darwin, x86_64→x64, aarch64→arm64. + +### Claude Code can't spawn the MCP server +- Ensure `chmod +x` applied to the binary +- On macOS: `xattr -d com.apple.quarantine ` to clear Gatekeeper +- Check the binary actually runs standalone: `/Volumes/EXOBRAIN/my-brain/bin/kei-mcp-server-darwin-arm64 --help` + +### "NameConflict" on attach +- Another MCP server with the same name already exists in the client's config. Either rename your brain (`name` in manifest.toml) or remove the existing entry manually. + +--- + +## What this tests end-to-end + +1. **Portable brain** — works from read-only USB, no installer needed on the brain itself +2. **Per-platform dispatch** — schema v2 picks the right binary based on host OS+arch +3. **Multi-client fan-out** — `keisei mount` attaches to every detected client in one call +4. **Clean detach** — zero residue in host configs, preserves unrelated MCP servers +5. **Safety gates** — path confinement, name regex, symlink rejection, size bound (64 KiB manifest cap) +6. **Schema v1 compat** — drop in an older v1 brain with a single-string mcp_server, still works + +If all 11 steps above pass, the v0.21 exobrain is production-ready for single-user workflows. + +For shared-brain scenarios (team members all mounting the same brain over git / S3) see the `kei-store` backend docs — S3 backend via `keisei attach s3://my-bucket/brain/` (requires `--features s3` at install).