Files
ClaudeMailbox/plugin/commands/mailbox-doctor.md
Mika Kuns ee0b72f43b
All checks were successful
CI (Node) / build-test (push) Successful in 10s
CI (.NET) / build (push) Successful in 11s
feat: change default port from 47822 to 37849 (v1.2.0)
47822 collided with ClaudeDo.Worker.exe on at least one user's machine.
37849 is high, registered to nobody, and avoids the prior conflict.
Both the Node port and the .NET port move together (still
wire-compatible). Defaults change only — if a user has a custom port
in mailbox.json, that stays.
2026-05-19 14:07:56 +02:00

5.7 KiB

description, allowed-tools
description allowed-tools
Diagnose and auto-fix the Claude-Mailbox setup (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, 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 — 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 2 — 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 4.
  • 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 3.

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 3 — 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 4 — 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 5 — mailbox identity (base prefix)

No prompt by default. Each Claude Code session gets a unique mailbox name auto-derived from its session_id (e.g., claude-a8b3c1d2).

Read .claude/settings.json and look for env.CLAUDE_MAILBOX_NAME.

  • If set → ✓ "Mailbox prefix is <X>." (real name will be <X>-<short_session_id>).
  • If unset → ✓ "Mailbox name will be auto-derived (claude-<short_session_id>)."

Ask once: "Want to flavor your mailbox names with a memorable prefix (e.g., backend, frontend)? (yes / no / <name>)"

On yes/explicit name: merge env.CLAUDE_MAILBOX_NAME = <name> into .claude/settings.json, preserving other keys. Mark restart_needed = true.

Step 6 — 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 2, 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 7 — summary

Claude-Mailbox doctor
  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: ."