docs(v0.21): .dockerignore + USB brain step-by-step guide

.dockerignore — trim Docker build context (was trying to pack
2.6 GB target/ + 6 GB .claude/worktrees/ + 212 MB node_modules/
on 2026-04-22, causing daemon I/O error). Excludes Rust target,
TS node_modules/dist/.turbo, agent worktrees, .git, IDE files,
logs. Essential before any tests/battle/* docker build.

docs/USB-BRAIN-GUIDE.md — 11-step recipe for the physical-USB
exobrain workflow:
  1-4. Prepare + download 5 platform binaries + verify sha256
  5-6. keisei attach --scope=user → verify in Claude Code
  7.   keisei mount for multi-client fan-out
  8.   --scope=project for per-repo brains
  9-10. status + detach cleanup
  11.  safe eject
Plus Troubleshooting section (7 common errors with fixes),
plus What-this-tests-end-to-end checklist (6 v0.21 features
exercised).

Target audience: first-time user of v0.21 exobrain feature on
macOS (Linux adaptation notes inline).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Parfii-bot 2026-04-22 18:47:12 +08:00
parent 340de0e2f6
commit 2b3ba50ccb
2 changed files with 352 additions and 0 deletions

46
.dockerignore Normal file
View file

@ -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/

306
docs/USB-BRAIN-GUIDE.md Normal file
View file

@ -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/<NAME>` (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 <path> 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-<os-renamed>-<arch-renamed>` 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 <binary>` 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).