feat(cli): add mureo install-desktop for Claude Desktop onboarding#75
Merged
feat(cli): add mureo install-desktop for Claude Desktop onboarding#75
mureo install-desktop for Claude Desktop onboarding#75Conversation
…boarding
Phase 2-1 of the non-engineer onboarding roadmap. Wires mureo into
Claude Desktop's MCP config in a single command so users no longer
need to:
1. find ~/Library/Application Support/Claude/claude_desktop_config.json
2. edit JSON by hand
3. work around Claude Desktop ignoring the `cwd` field
4. write a shell wrapper
The command takes care of all four:
- creates the workspace (default ~/mureo)
- generates ~/.local/bin/mureo-mcp-wrapper.sh that `cd`s into the
workspace before exec'ing python -m mureo.mcp (with shlex-quoted
paths so HOMEs with spaces or metacharacters do not break)
- merges a `mureo` entry into the Desktop config without clobbering
other MCP servers (filesystem, github, ...) or top-level prefs
- writes the config atomically (tempfile + os.replace + fsync) so a
disk-full or power loss mid-write cannot leave Claude Desktop
without an mcpServers section
- timestamped backup before any mutation
Flags: --workspace, --with-demo, --force, --dry-run.
Refuses cleanly on:
- non-macOS (Phase 1 scope, Linux/Windows tracked as follow-up)
- existing `mureo` entry without --force
- corrupt JSON / non-object top-level / non-object mcpServers
- symlinked config (Dropbox/iCloud sync setups -- surfaces the
constraint instead of silently writing through the link)
- unknown --with-demo scenario (validated before any mutation, so
a typo cannot leave a half-populated workspace)
22 unit tests cover fresh install, config preservation, force
overwrite + backup, dry-run, idempotence (including key-count check),
all corrupt-config flavours, symlinked config, and shell quoting of
spaces in workspace paths.
Phase 2-1.5 of the non-engineer onboarding roadmap. Lets each Claude
Desktop workspace have its own BYOD directory so demo and real-data
setups can coexist without manual cleanup of ~/.mureo/byod/ between
them.
Changes:
- byod_data_dir() now consults MUREO_BYOD_DIR env var first; legacy
~/.mureo/byod/ remains the default when the var is unset or empty
(existing CLI / Claude Code users see no change).
- mureo install-desktop wrapper now exports
MUREO_BYOD_DIR=<workspace>/byod so the MCP runtime spawned by
Claude Desktop reads/writes BYOD inside the workspace.
- During --with-demo seeding the install process itself temporarily
sets the same env var so materialize writes the demo bundle into
the workspace, then restores the prior value (or unsets it if it
was unset) to keep install_desktop clean when called as a library.
User-visible effect:
mureo install-desktop --workspace ~/mureo-demo --with-demo seasonality-trap
mureo install-desktop --workspace ~/mureo-real --force
Both workspaces now have independent byod/ directories.
Tests:
- 5 new tests in test_byod_runtime_env.py covering precedence
(env > home), expanduser, empty-string fallback, and
composability through manifest_path.
- 3 new tests in test_desktop_installer.py for the wrapper export
line, env var being set during demo seed, and proper restoration
after seed (preserving prior value, leaving unset when initially
unset).
The 4 production callers of byod_data_dir() (_client_factory,
byod/installer, byod/bundle, cli/byod_cmd) and 25 test sites all
call it dynamically so they pick up the override transparently.
…olve, e2e tests) - runtime.py: reject whitespace-only MUREO_BYOD_DIR (was only rejecting empty) - desktop_installer.py: drop redundant .resolve() (workspace is already resolved); add not-thread-safe note - runtime.py docstring: mention install_desktop() also sets the env var - test_byod_runtime_env.py: add whitespace-only fallback test, skip expanduser test on win32 - test_desktop_installer.py: align byod_target assertion with new unresolved path - test_desktop_installer.py: add 2 integration tests covering real materialize and two-workspace isolation (the headline guarantee of the env-var feature)
hyoshi
added a commit
that referenced
this pull request
May 1, 2026
…e EVERY commit (#76) Codifies the rule reinforced after PR #20 (OAuth helper, 2 HIGH issues found post-hoc) and PR #75 fixup (review-response commit pushed without re-review). Fixup, lint, and review-response commits all require their own review pass — a previous review on the same branch does NOT exempt follow-up commits. Exceptions (visual review only): docs/README/CHANGELOG, version bumps, Dependabot Actions bumps, typo fixes in comments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2-1 of the non-engineer onboarding roadmap. Adds
mureo install-desktopto wire mureo into Claude Desktop chat in a single command.Why
Today, getting mureo running in Claude Desktop chat requires four manual steps that each have their own footgun:
~/Library/Application Support/Claude/claude_desktop_config.jsoncwdon save)cwdfield anyway and the MCP process inheritscwd=/, which is read-only on macOScds into the workspace before exec'ing the MCP serverA non-engineer cannot reasonably be expected to do any of those. This command does all four at once.
What it does
mkdir -p ~/mureo(or--workspace PATH)~/.local/bin/mureo-mcp-wrapper.shwithchmod 0o755, pathsshlex.quote-d so spaces/metacharacters cannot break the scriptclaude_desktop_config.jsonto<name>.bak.<UTC-microsecond-timestamp>before any mutationmureoMCP entry without clobbering other servers (filesystem, github, ...) or top-level keys (preferences, ...)os.fsync+os.replaceso a disk-full or power loss mid-write cannot leave Claude Desktop withoutmcpServers--with-demo seasonality-trapseeds the workspace with a demo scenario; validated up-front so a typo cannot leave a half-populated stateRefusal cases
mureoentry without--forcemcpServers(refuses rather than silently overwriting hand-edited config)--with-demoscenario — raised before any mutationFlags
Test plan
tests/test_desktop_installer.pycover:mureoentry exists without--force--dry-runmutates nothing--with-demoinvokes demo materialise with correct argsmureokey not duplicated on re-runmcpServers{"mcpServers": null}ruff check,black --check,mypy --strictclean on all 4 modified filesmureo install-desktop --helpand--dry-run --forceworkshlex.quote, non-atomic config write via tempfile +os.replace+ symlink refusal) and all HIGH findingsOut of scope
mureo uninstall-desktop— Phase 2 follow-up PRmureo doctor desktop— Phase 2 follow-up PR/daily-checkworks in Desktop — Phase 3