v0.1.4: emodul install / uninstall — one-command AI client setup#2
Merged
Conversation
After pipx install emodul, users had to:
1. emodul auth login --browser
2. emodul skill install (for Claude Code)
3. manually edit claude_desktop_config.json (for Claude Desktop)
This collapses steps 2-3 into a single command per client:
emodul install claude-code # CLI-flavored skill → ~/.claude/skills/emodul/
emodul install claude-desktop # MCP-flavored skill → ~/.claude/skills/emodul-mcp/
# + mcpServers.emodul into config.json
emodul install --all # fans out to every detected client
emodul install --dry-run # preview
emodul uninstall <target> # reverse
Implementation:
- emodul/_client_paths.py — per-platform config paths + client detection
- emodul/_config_writer.py — atomic JSON merge with timestamped backups,
fcntl flock for serialization, strict JSON parse (fail-loud on comments),
shallow merge that preserves sibling top-level keys (preferences,
other mcpServers entries)
- SKILL_MCP.md — MCP-flavored skill (16 tool inventory, no shell examples)
- emodul/commands/install.py — install + uninstall click commands with
--all / --dry-run / --force, JSON envelope output, conflict detection
that requires --force to overwrite existing emodul entry with different args
The two skills coexist (different folder names → different YAML name slugs),
so Claude Code and Claude Desktop each load the right one based on
description keyword matching.
Backward compat: emodul skill install / uninstall keep working as before.
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
After
pipx install emodul, users had to manually editclaude_desktop_config.jsonto wire up the MCP server, then separately runemodul skill installfor Claude Code. This PR adds a singleemodul install <target>command that handles everything per-client.emodul install claude-code→ drops CLI-flavoredSKILL.mdinto~/.claude/skills/emodul/emodul install claude-desktop→ drops MCP-flavoredSKILL_MCP.md(new file) into~/.claude/skills/emodul-mcp/AND addsmcpServers.emodultoclaude_desktop_config.jsonwith a timestamped backupemodul install --all→ fans out to detected clientsemodul install --dry-run→ preview without writingemodul uninstall <target>→ reverseThe two skill folders coexist (different
name:YAML slugs), so each client picks the right one via description-keyword matching. Backward compat:emodul skill install/emodul skill uninstallkeep working unchanged.Architecture
emodul/_client_paths.py— per-platform config paths (macOS / Win / Linux) + client detection via marker-file probesemodul/_config_writer.py— atomic JSON merge withtempfile + os.replace, timestamped.bak-YYYYMMDDTHHMMSS(keep last 5),fcntl.flockfor serialization, strict JSON parse (fail-loud on comments/non-object roots), shallow merge that preserves sibling top-level keys (preferences, othermcpServersentries)SKILL_MCP.md— MCP-flavored skill: 16-tool inventory,{ok: false}envelope semantics, no shell examples,description:keywords target Claude Desktop / Cursor chat / Continue / Cline / Zedemodul/commands/install.py— Click commands with JSON envelope output, conflict detection (requires--forceto overwrite existingemodulentry with different args), idempotent (re-runs areunchanged)Test plan
_config_writerunit-tested (12 scenarios: missing file, empty, malformed JSON, non-object root, merge add/unchanged/conflict/force, remove + prune, atomic write + backup, UTF-8 roundtrip)emodul install claude-desktop --dry-run→ preview correctemodul install claude-desktop→ drops skill, merges config, creates backup, preserves siblings (vkvm-local-poc,preferences)unchanged(idempotent)--force→ updates entry, creates new backupemodul uninstall --all→ removes both skill files +mcpServers.emodul, leaves siblings intactemodul+emodul-mcpboth shown in available-skills list)ruff check --select=E,F,I,BcleanRelease
After merge: tag
v0.1.4→ OIDC publish to PyPI.