KeiSeiKit-1.0/docs/USB-BRAIN-GUIDE.md
Parfii-bot f12eb9f83c fix(v0.21.1): wave-audit consolidated — 5 critic HIGH + 2 security HIGH + 3 polish
Closes 10 audit findings from 4-agent wave (critic + security +
architect + validator) on v0.21.0.

CRITIC HIGH (5):
  H1 s3_cloud::commit() was listing with delimiter='/' — nested
     writes silently dropped from manifest hash. Added
     list_recursive() (no delimiter), filter manifest-*.json from
     hash input.
  H2 S3Cfg access_key_env + secret_key_env were advertised in TOML
     but never read. Wired via resolve_explicit_creds() with
     aws-credential-types. Partial-set or empty-resolve → error.
  H3 display::sanitize_display missing in detach.rs + mount.rs
     (regression of v0.19.2 L9 ANSI injection fix). Applied at 8
     print sites. 2 new integration tests.
  H4 adapters/jsonmcp.rs RESTORED (was lost in earlier merge).
     107 LOC shared module: load_json_or_empty / upsert_under_key /
     remove_under_key / persist. claude_code 163→105, cursor 165→106,
     zed 178→114. Unified error handling via ConfigParseError.
  H5 ENV_LOCK shared across kei-store tests. New test_env.rs (24 LOC)
     exposed under cfg(any(test, feature='s3')). github.rs +
     s3_cloud/tests.rs + s3_smoke.rs all use shared mutex. Fixes
     parallel-test race on KEI_STORE_S3_ENDPOINT.

SECURITY HIGH (2):
  SEC-H1 scripts/install-actionlint.sh — added sha256 verify
     (shasum/sha256sum) before extract. ACTIONLINT_SHA256_OVERRIDE
     env var for CI injection. Per-platform constants marked
     [UNVERIFIED: SKIP] pending live checksums.txt fetch (agent had
     no WebFetch this session — user follow-up: paste from
     https://github.com/rhysd/actionlint/releases/download/v1.7.12/checksums.txt).
  SEC-H2 S3 SSRF/IMDS guard. validate_endpoint() rejects:
     loopback (127/8, ::1, localhost), link-local (169.254/16,
     fe80::/10), metadata hostnames (google/azure). Override via
     KEI_STORE_S3_ALLOW_INTERNAL=1. HTTP rejected unless
     KEI_STORE_S3_ALLOW_INSECURE=1. Custom endpoint now REQUIRES
     explicit creds (no IMDS chain leak via third-party endpoint).
     4 reject + 3 accept tests pass.

POLISH (3):
  D1 docs/USB-BRAIN-GUIDE.md — ⚠️ WARNING block under Prerequisites:
     exFAT/FAT32 NOT safe for multi-client attach (SQLite WAL needs
     shared-mem mmap). Use ONE client at a time on those FSes.
     New Troubleshooting entry 'SQLite corruption on mount-attach'.
  D2 '~5 MB release binary growth' now labelled [estimate, E5 —
     not yet measured] in CHANGELOG.md + s3_cloud/mod.rs header.
  D3 scripts/validate-workflow-shas.sh exits 2 (not 0) when
     UNVERIFIED_COUNT > 0 and GITHUB_TOKEN absent. Distinguishes
     'network denied' from 'all good'.

REAL VERIFICATION (pasted by agent):
  cargo check -p keisei -p kei-store: Finished (clean)
  cargo test -p keisei --release: 30 passed 0 failed
  cargo test -p kei-store --release: 10 + 9 passed (default features)
  cargo test -p kei-store --features s3 --release:
    31 + 9 + 6 = 46 passed (with s3)
  bash -n scripts/*.sh: OK
  regen-counts.sh --check: no drift

Constructor Pattern: largest new src 200 LOC (s3_cloud/mod.rs, at
limit). jsonmcp.rs 107 LOC. test_env.rs 24 LOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 20:03:17 +08:00

323 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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).
> ⚠️ **WARNING — exFAT / FAT32 are NOT safe for multi-client attach.**
>
> SQLite WAL mode (used by `kei-memory`, `kei-artifact`, `kei-social-store` inside a brain) requires a filesystem with reliable shared-memory mmap. exFAT and FAT32 do NOT provide this, and `keisei mount` (multi-client fan-out in step 7 below) WILL corrupt the memory DBs if the brain lives on one of those filesystems.
>
> - On exFAT / FAT32, use the brain with **ONE client at a time** (single `keisei attach --scope=user`). Do not run `keisei mount`.
> - For reliable multi-client use, put the brain on **APFS (macOS)**, **ext4 (Linux)**, or **NTFS (Windows)**. exFAT is fine for single-client or read-only cross-platform transport.
> - If you've already mounted a brain from exFAT and suspect corruption, see "SQLite corruption on mount-attach" in Troubleshooting.
---
## 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 macosdarwin, x86_64x64, aarch64arm64.
### 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.
### SQLite corruption on mount-attach
- `kei-memory` / `kei-artifact` / `kei-social-store` databases show "disk image is malformed" or "database is locked" errors after a `keisei mount` on a USB drive.
- Root cause: the brain lives on **exFAT or FAT32**, which do not reliably support SQLite WAL-mode shared-memory mmap. Multi-client attach corrupts the DB.
- Fix:
1. Copy the brain dir to an **APFS** (macOS) / **ext4** (Linux) volume, either internal disk or a reformatted USB.
2. Re-attach via `keisei attach <new-path>` or `keisei mount <new-path>`.
3. For single-client use on the same exFAT drive, restrict to `keisei attach --scope=user` only do NOT use `keisei mount`.
- Prevention: re-read step 0 Prerequisites "⚠ WARNING" above.
---
## 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).