17 KiB
Phase 07: Claude Code Detection and MCP Configuration
Goal
Implement the first real Agent Setup experience for Claude Code: detect whether Claude Code appears available, show current OpenPets MCP configuration status, preview the exact MCP configuration command/file shape, and apply/remove a safe MCP configuration only after explicit user confirmation.
This phase makes Claude Code usable with the Phase 06 MCP lease routing path. It does not implement Claude hooks yet.
Non-goals
- No Claude hook install, uninstall, or hook event handling. That belongs in Phase 08.
- No Cursor, VS Code, Windsurf, OpenCode, or Antigravity configuration.
- No automatic silent edits during onboarding or app launch.
- No agent-managed pet installation/removal/default-pet changes.
- No attempt to parse or preserve every undocumented field in Claude's internal
~/.claude.json; prefer official CLI commands for writes. - No auto-launch of Claude Code itself.
User-visible/manual outcome
From the tray menu, Configure Agents... opens a real Claude Code setup window instead of a placeholder. The user can:
- See Claude Code as detected, not detected, configured, needs setup, or error.
- See the OpenPets MCP command that will be configured.
- Choose default-pet routing or an explicit installed pet for the Claude MCP server.
- Run a doctor/check to see actionable status.
- Click Configure only after seeing the planned change.
- Remove the OpenPets MCP entry if it was configured by OpenPets.
Acceptance criteria
- Agent Setup window has a Claude Code card with clear status:
DetectedNot detectedConfiguredNeeds setupError / needs attention
- Detection is best-effort and non-invasive:
- Check for a usable
claudebinary onPATHviaclaude --versionwith a short timeout. - Check MCP status using
claude mcp listwith a short timeout when Claude is available. - If Claude is missing or commands fail, report actionable text without crashing the app.
- Check for a usable
- Configuration target for Phase 07 is Claude Code user scope using the official CLI:
claude mcp add --scope user openpets -- npx -y @open-pets/mcp- With explicit pet:
claude mcp add --scope user openpets -- npx -y @open-pets/mcp --pet <petId>
- Preview shows the exact command and the equivalent intended MCP JSON shape before applying.
- Configure requires an explicit button click in the UI.
- Removal requires an explicit button click in the UI and uses:
claude mcp remove --scope user openpets
- Remove is enabled only when Claude reports an
openpetsMCP entry. If the entry cannot be verified as OpenPets-managed, the UI must warn that it will remove any Claude MCP server namedopenpets. - Config operations are conservative and idempotent where Claude exposes enough detail:
- If Claude reports an
openpetsMCP entry and a detail command/output lets OpenPets verify the command/args match, Configure reports already configured / no change. - If Claude only reports
openpetsas present but does not expose reliable command/arg detail, Configure reportsConfigured / needs manual verificationrather than replacing it. - If an
openpetsMCP entry exists but differs or cannot be verified, OpenPets must not automatically remove it. The UI must show a separate Replace action with a strong warning before remove-then-add. - If Replace removes an entry but add fails, OpenPets shows a clear failure and the action journal contains the previous detected summary and intended restore command; no OAuth/session config restoration is attempted.
- If Claude reports an
- Backups/restore behavior is defined and implemented for the files OpenPets directly edits.
- Because Phase 07 writes via the Claude CLI rather than directly editing
~/.claude.json, OpenPets should not create a misleading full backup of that internal file by default. - OpenPets records a local configuration action journal with timestamp, command preview, selected pet, and previous detected status where available.
- Restore behavior for Phase 07 is removal of the OpenPets MCP server entry through
claude mcp remove --scope user openpets; it does not attempt to restore OAuth/session internals.
- Because Phase 07 writes via the Claude CLI rather than directly editing
- Doctor/check reports:
- Whether
claudeis found. - Whether
claude --versionworks. - Whether
claude mcp listworks. - Whether an
openpetsMCP entry appears present. - What command OpenPets expects.
- That Claude Code may need restart/reload for MCP changes to take effect.
- Whether
- UI is CSP-safe and uses Electron IPC handlers with sender checks.
- Renderer/main IPC is narrow: renderer sends only action names and
{ selectedPetId?: string }; main constructs argv, revalidates selected pet against installed non-broken pets, and enforces sender checks for the Agent Setup window. - Configure/remove/replace operations are serialized so concurrent clicks cannot run overlapping Claude CLI commands.
- Automated checks cover command construction, pet id argument handling, status parsing, and timeout/error classification.
pnpm checkpasses.
Proposed files/directories
packages/claude/src/index.ts- Export Claude Code setup/detection helpers.
packages/claude/src/claude-code.tsdetectClaudeCode,buildClaudeMcpAddCommand,buildClaudeMcpRemoveCommand,parseClaudeMcpList, status types.
packages/claude/src/check-claude-code.ts- Node-based contract checks for command construction/status parsing.
packages/claude/package.json- Include build/check script updates.
apps/desktop/src/agent-setup.ts- Desktop orchestration for running Claude commands, timeouts, and local action journal.
apps/desktop/src/windows.ts- Replace Agent Setup placeholder with real Claude setup UI and preload access.
apps/desktop/preload.cjs- Expose narrow
openpetsAgentSetupmethods to renderer, separate from broader app/window APIs.
- Expose narrow
apps/desktop/src/app-state.tsor adjacent state helper- Persist lightweight agent setup status/action journal if needed.
docs/phases/phase-07-claude-detection-configuration.md
Technical approach
Scope: Claude Code user-scope MCP only
Phase 07 configures the universal MCP path already built in Phase 06:
Claude Code → @open-pets/mcp → @open-pets/client → desktop IPC → pet lease
Use a single MCP server name:
openpets
Use user scope first because OpenPets is a personal companion integration and should not silently create team/project files. Project-scoped .mcp.json and per-project pet choices can be documented later.
Detection
Detection runs from the desktop main process, never from the sandboxed renderer.
Best-effort command sequence:
- Resolve
claudefromPATHby runningclaude --version. - If
claudeis not found, try common platform locations only as non-invasive hints:- macOS GUI apps may have a reduced
PATH; include common Homebrew/npm paths such as/opt/homebrew/bin,/usr/local/bin, and inheritedPATHentries. - Windows may expose
claude.cmd; command resolution should tryclaudeandclaude.cmdwhere appropriate.
- macOS GUI apps may have a reduced
- Run
claude mcp listif version works. - If an official/detail command is available and works (for example
claude mcp get openpetsor a future JSON output), use it to verify command/args. Otherwise treat list output as present/absent only. - Parse output conservatively for an
openpetsentry. - Return a structured result to the UI.
Each child process should:
- Have a short timeout, initially 3 seconds.
- Kill the child process on timeout and classify the result as timeout, not as a generic error.
- Capture bounded stdout/stderr.
- Avoid shell interpolation by using
spawn/execFile-style argv arrays. - Never include secrets in UI text.
Command construction
Centralize command construction in @open-pets/claude so tests can verify it without Electron:
Default pet:
claude mcp add --scope user openpets -- npx -y @open-pets/mcp
Explicit pet:
claude mcp add --scope user openpets -- npx -y @open-pets/mcp --pet snoopy
Removal:
claude mcp remove --scope user openpets
Pet id values come from installed OpenPets pet ids in app state, not free-form UI entry. This avoids quoting/shell-injection complexity and aligns with the product rule that agents do not install/remove pets.
Preview
Before applying, show:
- Human summary.
- Exact argv-style command.
- Equivalent intended MCP JSON shape:
{
"mcpServers": {
"openpets": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@open-pets/mcp"]
}
}
}
With explicit pet:
"args": ["-y", "@open-pets/mcp", "--pet", "snoopy"]
Applying changes
Use Claude Code's official CLI rather than directly editing ~/.claude.json:
- Configure new entry:
claude mcp add --scope user openpets -- ... - Update existing differing or unverifiable entry: only through a separate explicit Replace action with warning text.
- Remove OpenPets entry:
claude mcp remove --scope user openpets.
If configure/remove commands fail before making changes, show the sanitized stderr/stdout summary and leave state unchanged.
Exception: Replace is a two-step remove-then-add flow. If remove succeeds but add fails, Claude config has already changed; the UI must state that the previous openpets entry was removed and show the intended restore/add command from the action journal.
The UI should include a Copy command fallback so users can apply configuration manually if Claude CLI invocation from the Electron app fails because of PATH, permissions, or shell environment differences.
Action journal and restore
Because user-scope MCP config lives inside Claude's internal ~/.claude.json, which may include OAuth/session/private state, Phase 07 should not copy the whole file into OpenPets backups by default.
Instead, persist an OpenPets-local action journal entry for each attempted configuration/removal:
- timestamp
- action: configure/update/replace/remove
- selected pet id or default
- command argv preview
- detected previous OpenPets status, if known
- success/failure and sanitized message
Location:
<OpenPets userData>/agent-setup-actions.json
Journal entries must be bounded and sanitized:
- Keep only the latest 20 entries.
- Store argv arrays and OpenPets status labels.
- Store sanitized output summaries capped at 500 characters.
- Do not store raw Claude config files, OAuth/session data, full stdout/stderr, home-directory paths, tokens, or environment variables.
During implementation, verify current claude mcp CLI syntax against official docs/help output before wiring writes. If a detail/get command or output format is unavailable or unexpected, fail closed: classify the entry as present but unverifiable and require manual review/Replace rather than assuming ownership.
Restore path in Phase 07 is explicit uninstall/remove of the OpenPets MCP entry via Claude CLI.
UI shape
Agent Setup can stay lightweight and inline-data-URL based for now, matching existing Pet Manager/Settings style:
- Header: Configure Agents
- Claude Code card
- Status badge and details
- Pet selection dropdown: Default pet + installed non-broken pets
- Preview box
- Buttons: Refresh / Doctor, Configure, Remove
- If an existing
openpetsMCP entry is present but unverifiable/different, show a separate Replace action with stronger warning copy instead of silently changing it. - Copy command fallback.
- Note: restart Claude Code if MCP changes do not appear immediately.
Risks and tradeoffs
- Claude Code config behavior can change. Mitigation: use official CLI commands where possible and keep parsing conservative.
claude mcp listoutput may not be stable. Mitigation: use it for status hints only; failed parsing reports needs manual check rather than corrupting config.- Existing user config could be lost if OpenPets blindly removes an
openpetsentry. Mitigation: no automatic replacement; require explicit Replace with warning and action journal. - User-scope config is personal and may contain secrets. Mitigation: do not directly edit or back up full
~/.claude.jsonin Phase 07. npx -y @open-pets/mcpmay use a published package in real installs, while local dev uses workspace packages. Mitigation: Phase 07 config preview targets the final product command; manual dev verification can inspect command preview without requiring published package behavior.- Windows may need command resolution differences. Mitigation: command discovery tries platform variants, uses argv arrays, and includes Windows samples in checks.
Security/privacy notes
- No shell string execution for user-controlled values.
- Pet choice is constrained to installed pet ids from app state.
- Renderer gets only narrow IPC methods for agent setup.
- Main process revalidates selected pet id and never trusts renderer-supplied command/argv.
- Sanitize child-process output before showing it in UI; bound max displayed length.
- Do not expose Claude config file contents or OAuth/session material in UI or logs.
- No silent configuration changes; user must click Configure/Remove.
Test/check plan
packages/claudecontract checks:- command argv for default pet.
- command argv for explicit pet.
- remove argv.
- equivalent JSON preview.
- MCP list parsing for present/missing/error-ish samples.
- unverifiable existing entry classification.
- Windows/macOS command discovery/path sample helpers where factored.
- invalid/free-form pet id rejection when using helper directly.
- Desktop checks:
- Agent setup IPC renderer sender restrictions.
- Command result timeout/error classification helper if factored separately.
- Action journal redaction/bounds if factored separately.
- Workspace:
pnpm check
Manual verification guide
After implementation:
- Run
pnpm check. - Start desktop:
pnpm --filter @open-pets/desktop dev. - Open tray → Configure Agents....
- Confirm Claude Code status appears and does not crash whether Claude is installed or not.
- Choose default pet and inspect preview.
- Choose an installed non-default pet and confirm preview adds
--pet <id>. - Use Copy command to verify the manual fallback text is correct.
- Click Configure only if you are comfortable modifying your Claude Code user MCP config.
- Run
claude mcp listseparately and confirmopenpetsappears. - If using an unpublished local package, do not expect a real Claude session to load
npx -y @open-pets/mcpuntil the package is available; treat command/config preview andclaude mcp listas the Phase 07 verification target. - Restart/open Claude Code and confirm OpenPets MCP tools appear only if the package is published or your dev environment routes the package name locally.
- Click Remove and confirm
claude mcp listno longer showsopenpets. - Optional safer test: create a fake
claudeexecutable earlier inPATHthat records argv and returns samplemcp listoutput; launch the desktop app from that terminal so the modifiedPATHis inherited; use it to verify missing Claude, successful add, failed add, existing entry, replace warning, and remove flows without touching real Claude config.
Expected results:
- Detection and doctor statuses are actionable.
- Preview matches the command OpenPets runs.
- Configure/remove are explicit and idempotent.
- OpenPets does not edit Claude config silently.
Oracle plan review
Reviewed. Oracle found the phase boundary and official-CLI direction sound, but flagged two blockers:
- Idempotency/update detection was underspecified because
claude mcp listmay not reliably prove command/args match. - Remove-then-add could lose an existing user
openpetsconfig if add fails.
Oracle also requested clearer remove semantics, platform command discovery, stricter renderer/main IPC rules, action journal schema/location, operation locking/timeouts, safer manual verification, and not promising real MCP tools appear before package publishing/dev override exists.
Oracle feedback disposition
Fixed:
- Weakened idempotency to verified-detail-only and present/absent otherwise.
- Added explicit Replace action for unverifiable/different existing entries; no automatic remove-then-add.
- Defined Remove warning semantics for unverifiable entries.
- Added macOS GUI PATH and Windows
claude.cmddiscovery considerations. - Tightened renderer/main IPC boundary and main-process pet revalidation.
- Added action journal location/schema/redaction/bounds.
- Added
replaceto the action journal action schema and clarified Replace add-failure state. - Added operation serialization and timeout kill behavior.
- Added Copy command fallback and safer fake-CLI/manual verification guidance.
- Clarified that real Claude MCP tools require published package or dev package routing.
Fixed after re-review:
- Clarified that Replace can change Claude config if remove succeeds and add fails, and must show restore/add guidance rather than claiming state is unchanged.
- Required implementation-time verification of current
claude mcpCLI syntax/help and fail-closed behavior for unavailable/unexpected detail output. - Clarified Agent Setup preload should be narrow/separate and fake-CLI testing requires launching desktop from a terminal with modified
PATH.