14 KiB
Phase 10B: Packaged Claude Command Distribution
Goal
Make the packaged OpenPets desktop app capable of configuring Claude Code without relying on unpublished npx @open-pets/* packages.
Phase 10B should add a packaged/bundled command mode that points Claude MCP and Claude hooks at JavaScript entry points shipped inside the packaged app resources.
Non-goals
- No npm publishing.
- No public signed/notarized release.
- No auto-update.
- No changing the public MCP tool set.
- No new agent integrations beyond Claude.
- No model-generated speech.
- No removing the existing published
npxcommand mode for future published packages. - No weakening Claude configuration confirmation/backups.
User-visible/manual outcome
In the packaged app, Agent Setup no longer asks users to configure private/unpublished npx packages by default.
Instead, packaged Agent Setup previews and installs commands like:
node <packaged-app-resource>/app/node_modules/@open-pets/mcp/dist/index.js
node <packaged-app-resource>/app/node_modules/@open-pets/claude/dist/cli.js hook --openpets-managed
The exact path is platform-specific, but it must be inside the packaged app output/resources and must be a regular file.
In dev/unpackaged mode, the existing behavior remains:
- published mode:
npx -y @open-pets/... - local dev mode: built checkout
distpaths
Acceptance criteria
@open-pets/desktoppackages the runtime packages required for bundled Claude commands:@open-pets/mcp,@open-pets/claude,@open-pets/client,- required third-party runtime dependencies.
- Agent Setup chooses command mode by environment:
- packaged app: bundled packaged mode,
- dev app: published/local dev toggle remains available.
- The Agent Setup renderer/preload accepts and renders bundled command mode snapshots without treating them as invalid.
- Packaged Agent Setup checks Node availability for Claude-launched commands, or clearly disables configure/install with a warning if Node is unavailable/too old.
- Packaged mode command previews use
node <packaged resource path>and nevernpx -y @open-pets/...unless the user is explicitly in published mode in dev. - Packaged MCP command points at a regular file shipped inside package resources.
- Packaged hook command points at a regular file shipped inside package resources.
- Packaged command paths are not source-checkout paths and do not use
app.getAppPath()assumptions that fail after packaging. - Packaged commands are validated before install/doctor/configure actions:
- path exists,
- path is a regular file,
- real path is inside packaged app resources/app directory,
- symlink escapes are rejected,
.asarpaths are rejected unless the file is explicitly unpacked/readable as a regular file,- command contains no newline/null/unsupported shell characters.
- Missing bundled resources produce an actionable Agent Setup status/error, not an unhandled IPC failure.
- Claude MCP configure/replace/remove still uses
claude mcp ...and still requires explicit user button actions. - Claude hook install/update/uninstall still writes only OpenPets-managed hooks and still creates backups.
- Doctor/preview text clearly labels packaged bundled mode and explains commands point into the installed OpenPets app.
- If packaged bundled command resources are missing, Agent Setup shows an actionable error and disables configure/install actions rather than falling back silently to unpublished
npxpackages. - Existing contract checks cover packaged bundled command files in package output.
- Existing Claude code/hooks contract checks cover bundled command preview/matching behavior.
pnpm testpasses.pnpm checkpasses.pnpm package:desktop:dirpasses.
Proposed files/directories
packages/claude/src/claude-code.ts- Add command mode support for packaged bundled MCP command paths.
packages/claude/src/hook-settings.ts- Add command mode support for packaged bundled hook CLI command paths.
packages/claude/src/check-claude-code.ts- Add bundled command preview/status checks.
packages/claude/src/check-claude-hooks.ts- Add bundled hook settings checks.
apps/desktop/src/agent-setup.ts- Select bundled mode in
app.isPackaged. - Validate packaged resource paths and surface errors.
- Check/warn for Node availability for packaged bundled commands.
- Keep dev local toggle unavailable in packaged app.
- Select bundled mode in
apps/desktop/preload.cjs- Accept/render
commandMode: "bundled"snapshots and label bundled mode clearly.
- Accept/render
apps/desktop/package.json- Add
@open-pets/mcpas a desktop runtime dependency so packaged output includes it.
- Add
apps/desktop/src/check-packaging-contract.ts- Require packaged MCP/Claude/client entry files and MCP runtime deps.
docs/mvp-validation.md- Update Phase 10B status and manual Claude packaged validation steps.
docs/phases/phase-10b-packaged-claude-command-distribution.md
Technical approach
Command mode model
Extend OpenPetsCommandMode from:
"published" | "local"
to:
"published" | "local" | "bundled"
Semantics:
published: npm/npx package names.local: checkout-relative builtdistfiles for development.bundled: package-relative files shipped in the packaged app'snode_modules/@open-pets/*/distdirectories.
For current unpacked Phase 10A packaging (asar: false), bundled paths can be resolved from @open-pets/claude's own import.meta.url in packaged node_modules:
.../Resources/app/node_modules/@open-pets/claude/dist
.../Resources/app/node_modules/@open-pets/mcp/dist/index.js
This mirrors the current local sibling-package resolution, but should be named bundled so the UI does not imply a fragile source checkout path.
Desktop mode selection
In desktop Agent Setup:
app.isPackagedshould forcebundled.- Dev mode keeps current published/local toggle.
- UI should show the dev checkbox disabled in packaged app, with text indicating packaged bundled commands are used.
Hook settings
Bundled hook settings should still use the OpenPets marker:
node "<path>/@open-pets/claude/dist/cli.js" hook --openpets-managed
Uninstall must continue to remove any OpenPets-managed hooks by marker, including old published/local commands.
Install/update should replace old OpenPets-managed published/local commands with bundled commands when running from packaged app.
MCP settings
Bundled MCP settings should configure Claude with:
{
"type": "stdio",
"command": "node",
"args": ["<path>/@open-pets/mcp/dist/index.js"]
}
If a pet is selected:
"args": ["<path>/@open-pets/mcp/dist/index.js", "--pet", "pet-id"]
Packaging contract
Package output checks should assert:
node_modules/@open-pets/mcp/dist/index.jsexists.node_modules/@open-pets/claude/dist/cli.jsexists.node_modules/@open-pets/client/dist/index.jsexists.- required MCP third-party dependencies exist (
@modelcontextprotocol/sdk,zod, etc.) if included by builder. - no symlink escapes package output.
Security/safety
Path validation should reject:
- missing files,
- directories/symlinks when a regular file is expected,
- paths whose
realpathis outside the packaged app resource/app root in bundled mode, .asarpaths unless the target is explicitly unpacked/readable as a regular file,- command strings containing newline/null.
Do not silently fall back to npx in packaged app if bundled resources are missing; that would reintroduce the Phase 10A blocker.
Risks and tradeoffs
- Installed app path moves. Claude settings will contain absolute paths into the installed app; if the user moves/deletes OpenPets, Agent Setup doctor should report needs update/error and the user should reinstall/update config.
- ASAR disabled in Phase 10A. Bundled commands rely on regular files. If ASAR is enabled later, MCP/Claude command files must move to
asarUnpackorextraResources. - Node availability. Commands use
node, so users still need Node available for Claude to launch MCP/hooks. This matches the project's Node/npm/npx direction and avoids bundling a separate runtime in this phase. - Cross-platform paths. Windows paths with spaces must be handled through Claude MCP arg arrays and shell-quoted hook command strings.
Security/privacy notes
- No silent Claude configuration changes.
- Backups remain required before Claude settings hook writes.
- Bundled commands are local files shipped with OpenPets, not remote downloads.
- No TCP/HTTP control plane is introduced.
- Speech/privacy rules from earlier phases remain unchanged.
- Uninstall removes only OpenPets-managed hooks by marker.
Test/check plan
Run:
pnpm test
pnpm check
pnpm package:desktop:dir
Automated coverage:
- bundled MCP preview command shape,
- bundled hook command shape,
- parse/classify expected bundled Claude MCP entries,
- bundled paths with spaces/backslashes in MCP arg arrays and hook shell quoting,
- bundled command path validation for existing and missing files,
- renderer/preload snapshot validation accepts
commandMode: "bundled", - package output includes MCP/Claude/client runtime entries and MCP runtime deps.
Manual verification guide
- Run:
pnpm test
pnpm check
pnpm package:desktop:dir
- Launch the packaged app.
- Open Agent Setup.
- Confirm command preview uses
node <packaged .../node_modules/@open-pets/mcp/dist/index.js>, notnpx -y @open-pets/mcp. - Confirm hook preview uses
node <packaged .../node_modules/@open-pets/claude/dist/cli.js> hook --openpets-managed. - Configure Claude MCP only if you are ready to update your user Claude settings; verify backup/config behavior as in earlier phases.
- Install/update hooks only if you are ready to update your user Claude settings; verify backup/config behavior as in earlier phases.
- Run Claude Code and confirm MCP/hook behavior if desired.
- Use Agent Setup to remove MCP/hooks after testing if you do not want packaged paths left in Claude settings.
Oracle plan review
Reviewed by Oracle.
Blocker:
- The original plan omitted renderer/preload bundled-mode support. Current
apps/desktop/preload.cjsvalidates command mode as onlypublishedorlocal, so a bundled snapshot would be rejected. The spec must include preload/renderer handling.
Should-fix feedback:
- Add explicit Node prerequisite handling because packaged bundled commands require
nodeon Claude's PATH. - Validate bundled paths with
realpathagainst the packaged app root, not simple string prefix. Reject missing files, directories, symlinks,.asarpaths unless unpacked, newline/NUL/quote/shell-dangerous chars. - Ensure missing bundled resources produce actionable Agent Setup status/error instead of unhandled IPC failure.
- Add cross-platform tests for paths with spaces/backslashes, MCP args arrays, hook shell quoting, and bundled
claude mcp getparsing. - Extend package contract checks to require
@open-pets/mcp/dist/index.jsplus runtime deps like@modelcontextprotocol/sdkandzod. - Update docs to state Claude settings contain absolute OpenPets app paths; moving/deleting/updating the app may require Agent Setup replace/update/remove.
Nice-to-have feedback:
- Centralize command-mode/path resolution helpers.
- Show shortened paths in UI while writing full absolute paths to Claude settings.
- Add future ASAR note for
asarUnpackorextraResources.
Verdict: architecture is sound, but not implementation-ready until preload bundled-mode support and path/quoting/test clarifications are added.
Oracle feedback disposition
Fixed:
- Added
apps/desktop/preload.cjsto proposed files and acceptance criteria for bundled-mode renderer support. - Added Node prerequisite warning/disable requirement.
- Strengthened realpath/path validation requirements.
- Added missing-resource error-state requirement.
- Added cross-platform path/quoting tests to test plan.
- Added MCP runtime deps to package contract requirements.
- Added absolute packaged path docs requirement.
Accepted:
- Centralize command/path helpers where practical during implementation.
- Show shortened paths in UI while writing full paths if cheap.
Deferred:
- ASAR support remains future release hardening; Phase 10B should note that ASAR requires
asarUnpack/extraResourcesfor externally executed JS files.
Oracle implementation review
Reviewed by Oracle after implementation.
Blockers: none.
Should-fix feedback:
- Prevent broken writes when
nodeis unavailable.detectClaudeCodeStatus()reports “Node required”, but action handlers must also guard configure/replace/install-hooks in bundled mode. - Keep cleanup available on bundled-resource errors.
removeanduninstall-hooksshould not be blocked by missing bundled MCP/hook resources. - Add stronger Windows/path tests for hook command quoting, MCP args arrays, and text parsing of bundled paths with spaces.
- Reject symlink command files or document reliance on package checks.
- Manual packaged Agent Setup verification remains required.
Nice-to-have feedback:
- Make bundled tests explicitly depend on built
@open-pets/mcpor avoid relying on stale siblingdiststate. - Clarify Node PATH check is best-effort because Claude's runtime environment may differ.
- Keep ASAR/
extraResourcesdeferred as documented.
Verdict: architecture is sound and package contract is substantially adequate; fix node/action guard and cleanup-path issues before final acceptance.
Oracle implementation feedback disposition
Fixed:
- Added action-level bundled Node guard before configure/replace/install-hooks.
- Moved cleanup actions so
removeanduninstall-hooksremain available even if bundled command resources are missing. - Added quoted-path parsing and Windows-style path display checks for Claude MCP command handling.
- Runtime bundled command validation now rejects symlink entry files in addition to using
realpathcontainment checks.
Accepted:
- Manual packaged Agent Setup verification remains a phase gate.
Deferred:
- ASAR/
extraResourcesrelease hardening remains deferred.
Final Oracle re-check:
- Blockers: none.
- Remaining should-fix: none from the prior Oracle review.
- Manual packaged Agent Setup UI verification remains as the phase gate before closing.
- Verdict: proceed to user manual packaged verification for bundled MCP preview/configure, hook preview/install, real Claude behavior if desired, and cleanup/remove.