Files
ClaudeMailbox/plugin/commands/mailbox-doctor.md
Mika Kuns ac626f678b
All checks were successful
CI (Node) / build-test (push) Successful in 9s
fix(cli,plugin): CLAUDE_MAILBOX_URL env override + port-conflict-aware doctor
The plugin's UserPromptSubmit and SessionStart hooks call `claude-mailbox`
with no --url flag, so they previously always hit the hardcoded
http://127.0.0.1:47822/mcp default. If port 47822 was held by another
local service (e.g. ClaudeDo), the daemon couldn't bind there and every
hook was talking to the wrong process.

CLI default for --url now resolves to $CLAUDE_MAILBOX_URL when set,
falling back to http://127.0.0.1:47822. Doctor gained a Step 2 that
probes /health on 47822, identifies foreign occupants, picks a free
port, writes both ~/.claude-mailbox/mailbox.json and the
CLAUDE_MAILBOX_URL entry in .claude/settings.json env so the hooks
follow along automatically.

Also adds a fallback hint when Windows schtasks /Create fails with
Access is denied (Group Policy restricts non-admin task creation): run
install-autostart from an elevated shell, or accept an ephemeral serve
for the current session.
2026-05-19 13:30:51 +02:00

5.5 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 47822. Probe whether anything is already on it:

curl -sf http://127.0.0.1:47822/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 47822.
  • 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 47822 | Select-Object OwningProcess, then Get-Process -Id <pid>; macOS/Linux: lsof -i :47822).
  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.

If install-autostart fails with "Access is denied" on Windows: Group Policy may block non-admin schtasks /Create. Two fallbacks:

  1. Tell the user to run claude-mailbox install-autostart from an elevated PowerShell themselves (one-time).
  2. For this session, run claude-mailbox serve as a background process so the rest of the doctor's checks can pass — the daemon won't survive logoff, but that's fine for verification.

If status doesn't reach Running after the fallback, stop and report.

Step 4 — health probe

Hit http://127.0.0.1:<port>/health (use the configured port, not necessarily 47822). 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 47822 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: ."