feat(cli): install Claude orchestration rules globally (closes #25)#26
Merged
feat(cli): install Claude orchestration rules globally (closes #25)#26
Conversation
Adds `adloop install-rules`, `update-rules`, and `uninstall-rules`
subcommands that manage AdLoop's orchestration rules + slash commands at
the user level (~/.claude/), so Claude Code sessions outside this repo
inherit the same safety patterns, GAQL reference, and 43-tool guidance
that Cursor users get for free via workspace rules.
The init wizard now detects Claude installations and offers to install
the rules at the end of setup.
Two install modes:
- inline (default): full rules embedded in ~/.claude/CLAUDE.md between
sentinel comments. Reliable; ~10K tokens loaded every Claude Code
session.
- lazy (--lazy): small directive in CLAUDE.md pointing at
~/.claude/rules/adloop.md. Cheaper baseline cost; the LLM reads the
full rules only when AdLoop tools are in scope.
Idempotency is handled by sentinel comments
`<!-- adloop:rules:start vX.Y.Z --> ... <!-- adloop:rules:end -->`
that include the AdLoop version, so update-rules can detect drift
across versions and replace stale blocks cleanly. uninstall-rules only
touches the managed block and adloop-* prefixed slash commands —
user-authored content is never modified.
Claude Desktop has no programmatic rules location, so it returns
manual paste-into-claude.ai instructions instead.
Architecture:
- src/adloop/rules/{adloop.md, commands/*.md} — bundled with the wheel
via uv_build's default file inclusion (verified by building locally).
- scripts/sync-rules.py now writes three targets: in-repo Cursor format
source -> .claude/rules/adloop.md (in-repo Claude Code) +
src/adloop/rules/adloop.md (bundled) + .claude/commands/ ->
src/adloop/rules/commands/. Single source of truth maintained.
- src/adloop/rules_install.py — pure module with detect_clients,
install_rules, update_rules, uninstall_rules. Frontmatter is stripped
for inline mode (CLAUDE.md is itself a rules file) but preserved for
the lazy-mode sibling file.
Tests: 26 new in tests/test_rules_install.py covering detection,
inline/lazy install, idempotency, frontmatter handling, mode preservation
on update, version-mismatched block replacement, namespaced-command
isolation during uninstall, and CLI entry-point smoke tests. Full suite:
184 passed.
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
Closes #25. Adds
adloop install-rules,update-rules, anduninstall-rulessubcommands that manage AdLoop's orchestration rules + slash commands at the user level (~/.claude/), so Claude Code sessions outside this repo inherit the same safety patterns, GAQL reference, and 43-tool guidance that Cursor users get for free via workspace rules.The
adloop initwizard now also detects Claude installations and offers a one-shot install at the end of setup.Why
Currently, the orchestration rules and slash commands only work when:
.cursor/rules/).CLAUDE.md+.claude/).Users running AdLoop in Claude Code from any other project or in Claude Desktop / claude.ai get raw tool access but none of the orchestration intelligence — no safety rules, no GAQL reference, no orchestration patterns. This was surfaced by @sg-modlab in #23 and the underlying context-bloat trade-off was raised by @luison in #18.
What's new
Subcommands
adloop install-rules~/.claude/CLAUDE.md, copy slash commands to~/.claude/commands/(prefixedadloop-*).adloop install-rules --lazyadloop install-rules --no-commandsadloop update-rules--inline/--lazyis passed.adloop uninstall-rulesadloop-*commands. User content is never touched.Two install modes
~/.claude/CLAUDE.md. Reliable; ~10K tokens loaded every Claude Code session.--lazy) — short directive inCLAUDE.mdpointing at~/.claude/rules/adloop.md. The LLM reads the full file only when AdLoop tools are in scope. Cheaper baseline cost.Idempotency
A sentinel-bracketed block is the canonical write surface:
Re-running
install-rulesreplaces the block in place (no duplication). The version is part of the start sentinel soupdate-rulescan detect drift across upgrades and overwrite stale blocks. Uninstall surgically strips the block and removes theadloop-*slash commands — anything outside the sentinels (the user's own CLAUDE.md content, their own slash commands) is preserved exactly.Claude Desktop / claude.ai
Has no programmatic rules location. The installer detects it and prints copy-paste instructions (with the full rules content stripped of frontmatter, scoped between BEGIN/END markers) for the user to paste into Project settings → Custom instructions on claude.ai. Re-paste after every
update-rules.Architecture
src/adloop/rules/{adloop.md, commands/*.md}— bundled with the wheel. uv_build picks them up automatically (verified by building locally and unzipping the resulting wheel).scripts/sync-rules.pynow writes three targets from the canonical.cursor/rules/adloop.mdc:.claude/rules/adloop.md(in-repo Claude Code)src/adloop/rules/adloop.md(bundled with the wheel)src/adloop/rules/commands/*.md(mirrored from.claude/commands/)Single source of truth is preserved.
src/adloop/rules_install.py— pure module withdetect_clients,install_rules,update_rules,uninstall_rules. Frontmatter is stripped for inline mode (CLAUDE.md is itself a rules file and shouldn't contain nested frontmatter) but preserved for the lazy-mode sibling file at~/.claude/rules/adloop.md.CLI is wired through
src/adloop/__init__.py:mainandsrc/adloop/cli.py:run_rules_command. Theinitwizard prompts at the end if any Claude client is detected.Tests
26 new in
tests/test_rules_install.py:adloop-*commands (user commands untouched), removes empty CLAUDE.md (but preserves it if user content remains), safe no-op when nothing installed._read_bundled_rulesand_list_bundled_commandswork viaimportlib.resources.run_rules_commandinstall/uninstall happy paths + unknown-subcommand error.Full suite: 184 passed (158 baseline + 26 new).
End-to-end smoke verification (locally, against $TMPHOME)
Verified manually before pushing:
--lazyinstall writes 5-line directive in CLAUDE.md + 580-line rules file at~/.claude/rules/adloop.mdupdate-ruleswithout flags preserves lazy modeupdate-rules --inlineswitches to full inline content (block grew from 5 to 585 lines)Test plan
uv run pytest— 184 passsrc/adloop/rules/andsrc/adloop/rules/commands/adloop install-rulesagainst your real~/.claude/doesn't surprise you (useadloop uninstall-rulesto clean up if needed — guaranteed safe by the sentinel design)Out of scope (good follow-ups)
adloop-*namespace is collision-free with current command names but doesn't prevent users from later authoring anadloop-foo.mdof their own. Could add a check in install if it becomes an issue.Acceptance criteria (from #25)
adloop initdetects Claude installations and offers global rules installadloop install-rules,update-rules,uninstall-rulessubcommands (note: as standalone subcommands rather thaninit --update-rulesflags — matches the rest of the CLI surface better)sync-rules.py