Files
ClaudeMailbox/plugin/commands/mailbox-doctor.md
Mika Kuns b10ac36ed0 feat(naming)!: auto-derive mailbox name from project + runtime rename
Mailbox names are now built as <project>-<session-short>, where <project>
is the sanitized git-repo basename (or cwd basename) — no more env-var
prefix step. Sessions can re-tag themselves at runtime via the new
mcp__mailbox__rename tool (POST /v1/rename), which transfers all
pending messages to the new name in a single transaction. Peers using
the old name re-discover via list_mailboxes.

BREAKING: \$CLAUDE_MAILBOX_NAME is no longer read. Existing setups that
relied on the env-var prefix should remove it from .claude/settings.json;
the prefix now comes from the working directory automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 13:14:15 +02:00

6.5 KiB

description, allowed-tools
description allowed-tools
Diagnose and auto-fix the Claude-Mailbox setup (Node version, binary install, port-conflict detection, daemon autostart, smoke test, optional base-prefix). Bash, Read, Edit, Write

You are running the Claude-Mailbox doctor. Walk through these checks in order. After each step, print a one-line / with the action you took. End with a summary block.

Use Bash only for claude-mailbox subcommands, npm, node, where/which, and HTTP probes. Use Read/Edit/Write for .claude/settings.json and mailbox.json. Never run sudo automatically — if elevation is needed, stop and ask.

Step 1 — Node.js version

Run: node --version

claude-mailbox uses Node's built-in node:sqlite and therefore requires Node 24 or newer. Parse the major version from the output.

  • Major ≥ 24 → ✓ record the version, continue.
  • Major == 22 or 23 → ✗ Stop. node:sqlite is experimental on these and requires --experimental-sqlite. Print:

    Found Node <X.Y.Z>. claude-mailbox needs Node 24 LTS or newer. Install via nvm install 24 && nvm use 24 (or nvs / winget install OpenJS.NodeJS.LTS on Windows), then re-run the doctor.

  • Major < 22 → ✗ Stop with the same message; this Node is end-of-life.
  • Major ≥ 26 with better-sqlite3 still installed globally from a previous version → just note: "Node <X.Y.Z> is fine for the current claude-mailbox (no native deps); ignore any old better-sqlite3 build warnings from a prior install."

If node --version itself fails (command not found), stop and tell the user to install Node 24+ first.

Step 2 — daemon binary on PATH

Run: claude-mailbox --version

  • Exit 0 → ✓ record the version. Continue.

  • Command not found → binary missing. Install path:

    Platform Command
    Windows npm install -g @kuns/claude-mailbox (no admin)
    macOS / Linux npm install -g @kuns/claude-mailbox (may fail with EACCES — never run sudo automatically; ask the user)

    Prerequisite: npm config get @kuns:registry must point at https://git.kuns.dev/api/packages/releases/npm/. If not:

    npm config set @kuns:registry=https://git.kuns.dev/api/packages/releases/npm/
    

    After install, re-run claude-mailbox --version. If it still fails, stop and report.

Step 3 — port-conflict check (before autostart!)

Default port is 37849. Probe whether anything is already on it:

curl -sf http://127.0.0.1:37849/health
  • Returns a JSON body with "status":"ok" and a version field that matches claude-mailbox --version → it's already our daemon, ✓ skip to Step 5.
  • Returns 200 with "status":"ok" but a different version → it's an older claude-mailbox; treat as running, ✓.
  • Returns non-200, non-JSON, or any other foreign responseport conflict. Some other process owns 37849.
  • Connection refused → port is free, ✓ continue to Step 4.

If port conflict detected:

  1. Tell the user which process holds the port (Windows: Get-NetTCPConnection -LocalPort 37849 | Select-Object OwningProcess, then Get-Process -Id <pid>; macOS/Linux: lsof -i :37849).
  2. Pick a free port. Default suggestion: 47900. Verify it's free: curl -sf http://127.0.0.1:47900/health should fail with connection refused.
  3. Read ~/.claude-mailbox/mailbox.json (create empty {} if missing) and merge {"port": <chosen>}. Write back.
  4. Also write the override into .claude/settings.json env so the plugin's hooks find the right URL:
    "env": { "CLAUDE_MAILBOX_URL": "http://127.0.0.1:<chosen>" }
    
    Merge into existing env, preserving other keys.
  5. Mark restart_needed = true.

Step 4 — daemon autostart and running state

Run: claude-mailbox status

  • Running → ✓ continue.
  • Stoppedclaude-mailbox start, re-check.
  • NotInstalledclaude-mailbox install-autostart, then claude-mailbox start, re-check.

Behavior on install-autostart: The CLI tries a Scheduled Task first (schtasks /RL LIMITED, no admin). If Windows Group Policy returns "Access is denied", it falls back transparently to an HKCU\Software\Microsoft\Windows\CurrentVersion\Run registry entry plus a hidden node serve process — same per-user persistence, no admin needed. The chosen mechanism is recorded in ~/.claude-mailbox/autostart-mode and respected by status/start/stop/uninstall-autostart.

If install-autostart still fails after both attempts (very rare — would mean both schtasks and reg add are blocked), stop and report what status and start printed.

Step 5 — health probe

Hit http://127.0.0.1:<port>/health (use the configured port, not necessarily 37849). Expect a JSON body with "status":"ok" AND a version matching claude-mailbox --version. If unreachable or version mismatch, stop and report.

Step 6 — mailbox identity

No prompt. Each Claude Code session gets a unique mailbox name auto-derived as <project>-<short_session_id>, where <project> is the git-repo basename of the session's cwd (or the cwd basename if not a git repo). Example: claude-mailbox-a8b3c1d2.

✓ "Mailbox name will be auto-derived as <project>-<short_session_id>."

Sessions can also rename themselves at runtime via the mcp__mailbox__rename MCP tool — e.g. to add an area tag like claude-mailbox-frontend-a8b3c1d2. No config involved.

Step 7 — smoke test

Use two ephemeral names — we don't need the real session name here:

claude-mailbox send  --from doctor-probe-a --to doctor-probe-b --body "ping from doctor"
claude-mailbox check --name doctor-probe-b

(If the port was changed in Step 3, pass --url http://127.0.0.1:<port> to both.)

The check output must be a JSON array with one message: from: doctor-probe-a, body matches. ✓ on success, ✗ otherwise.

Step 8 — summary

Claude-Mailbox doctor
  node:          <version>
  binary:        <version>
  daemon:        Running    (port: <port>, what you did if anything)
  health:        ok
  port conflict: none | resolved (moved from 37849 to <port>)
  base prefix:   <name from settings, or "auto-derived (anonymous)">
  smoke test:    passed | failed
  restart hint:  yes if restart_needed, otherwise no

End with one of:

  • All ✓ and no restart needed → "Setup is healthy. Your mailbox name this session will be revealed by the SessionStart hook on next session start."
  • All ✓ and restart needed → "Restart Claude Code (or open a new session) so the SessionStart hook picks up the new env values."
  • Anything ✗ → "Setup incomplete: ."