{"id":31183764,"url":"https://github.com/patrickclery/ruly","last_synced_at":"2026-03-11T03:03:44.073Z","repository":{"id":313840022,"uuid":"1052953155","full_name":"patrickclery/ruly","owner":"patrickclery","description":"CLI tool for managing AI assistant rules and configurations","archived":false,"fork":false,"pushed_at":"2026-03-03T21:19:09.000Z","size":963,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-04T00:49:44.399Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/patrickclery.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-08T19:24:58.000Z","updated_at":"2026-03-03T21:19:13.000Z","dependencies_parsed_at":"2026-02-06T20:04:46.290Z","dependency_job_id":"9b0475d5-4a00-4419-9d38-401cab14f9ac","html_url":"https://github.com/patrickclery/ruly","commit_stats":null,"previous_names":["patrickclery/ruly"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/patrickclery/ruly","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickclery%2Fruly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickclery%2Fruly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickclery%2Fruly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickclery%2Fruly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/patrickclery","download_url":"https://codeload.github.com/patrickclery/ruly/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickclery%2Fruly/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30368620,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"online","status_checked_at":"2026-03-11T02:00:07.027Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-19T18:14:46.112Z","updated_at":"2026-03-11T03:03:44.065Z","avatar_url":"https://github.com/patrickclery.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"```\n██████╗░██╗░░░██╗██╗░░░░░██╗░░░██╗\n██╔══██╗██║░░░██║██║░░░░░╚██╗░██╔╝\n██████╔╝██║░░░██║██║░░░░░░╚████╔╝░\n██╔══██╗██║░░░██║██║░░░░░░░╚██╔╝░░\n██║░░██║╚██████╔╝███████╗░░░██║░░░\n╚═╝░░╚═╝░╚═════╝░╚══════╝░░░╚═╝░░░\n```\n\n## 🚀 Quick Install\n\n### One-Line Installation\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/patrickclery/ruly/main/setup.rb -o /tmp/ruly_setup.rb \u0026\u0026 ruby /tmp/ruly_setup.rb\n```\n\nThis will:\n\n- Install Ruly to `~/ruly`\n- Add `ruly` command to your PATH\n- Set up initial configuration at `~/.config/ruly/profiles.yml`\n\n### Manual Installation\n\nIf you prefer to install manually:\n\n```bash\n# Clone the repository\ngit clone https://github.com/patrickclery/ruly.git ~/ruly\ncd ~/ruly\n\n# Install dependencies\nbundle config set --local path 'vendor/bundle'\nbundle install\n\n# Add to PATH (add to your ~/.bashrc or ~/.zshrc)\nexport PATH=\"$HOME/ruly/bin:$PATH\"\n\n# Initialize configuration\nruly init\n```\n\n### Uninstall\n\nTo remove Ruly:\n\n```bash\nrm -rf ~/ruly\n# Remove the PATH export from your shell configuration file\n```\n\n### Getting Started\n\nAfter installation, you can immediately start using Ruly:\n\n```bash\n# Initialize configuration (if not done during install)\n$ ruly init\n\n# List available commands\n$ ruly help\n\n# Combine all rules into one file\n$ ruly squash\n\n# Use a specific profile\n$ ruly squash starter\n\n# Clean up generated files\n$ ruly clean\n\n# List available profiles\n$ ruly list-profiles\n\n# Show version\n$ ruly version\n```\n\n## 🌟 How It Works\n\n### Standalone CLI Tool\n\nRuly is a standalone command-line tool that manages AI assistant rules:\n\n1. **Simple Installation**: One-line install with curl\n2. **Self-Contained**: Everything runs from `~/ruly`\n3. **Profile System**: Use pre-configured profiles or create your own\n4. **Smart Caching**: Cache compiled profiles for performance\n5. **Multiple Formats**: Support for different AI assistants (Claude, Cursor, etc.)\n\n**Benefits:**\n\n- ✅ **Standalone**: No gem installation required\n- ✅ **Easy updates**: Just pull the latest changes\n- ✅ **No system dependencies**: Self-contained in your home directory\n- ✅ **Flexible rules system**: Define your own rules repository or use remote sources\n- ✅ **Cross-platform**: Works anywhere Ruby is installed\n\n### What Ruly Does\n\n**The `ruly` command provides:**\n\n- ✅ Combine multiple rule files into one document\n- ✅ Use profile collections for different contexts\n- ✅ Fetch and include remote GitHub files\n- ✅ Cache compiled profiles for performance\n- ✅ Support for Claude, Cursor, and other AI assistants\n- ✅ Clean up all agent-related files automatically\n\n**Generated Files:**\n\n```\nyour-project/\n├── CLAUDE.local.md      # Generated by ruly squash (default)\n├── .ruly/\n│   └── bin/             # Executable scripts (from scripts: key)\n└── .claude/\n    ├── commands/        # Command files for Claude agent\n    │   ├── bug/         # Bug-related commands\n    │   ├── pr/          # PR management commands\n    │   └── workflow/    # Workflow commands\n    └── skills/          # Skill files for Claude agent\n        ├── debugging/\n        │   └── SKILL.md\n        └── pr-review-loop/\n            └── SKILL.md\n```\n\nFor other agents:\n\n- **Cursor**: Uses `.cursor/` directory with `.mdc` files\n- **Custom**: Specify with `--agent` and `--output-file` options\n\n---\n\n## About Ruly\n\nRuly is a powerful CLI tool that manages AI assistant rules and configurations for software development projects. It provides a framework for organizing and combining rule files from various sources - your own private repositories, public GitHub repos, or local files - into a single document for AI assistants like Claude or Cursor.\n\n### ⚠️ Important: Rules Not Included\n\nThis repository **does not include rule files**. You need to:\n\n1. Create your own rules repository (private or public)\n2. Configure profiles to point to your rule sources\n3. Use the `ruly init` command to get started with a template\n\n## 🎯 Setting Up Your Rules\n\n### Option 1: Create Your Own Rules Repository\n\n1. **Create a new repository for your rules:**\n\n   ```bash\n   # Create a private repository\n   gh repo create yourusername/rules --private --description \"My AI assistant rules\"\n\n   # Clone it locally\n   git clone git@github.com:yourusername/rules.git\n   cd rules\n   ```\n\n2. **Organize your rules:**\n\n   ```\n   rules/\n   ├── ruby/\n   │   ├── common.md\n   │   ├── rspec.md\n   │   └── best-practices.md\n   ├── testing/\n   │   └── patterns.md\n   ├── commands/\n   │   ├── bug/\n   │   │   └── diagnose.md\n   │   └── pr/\n   │       └── create.md\n   ├── comms/\n   │   ├── jira/\n   │   │   ├── common.md           # Shared Jira patterns\n   │   │   └── bin/                # Shell scripts for Jira operations\n   │   │       └── fetch-jira-details.sh\n   │   └── ms-teams/\n   │       ├── common.md           # Shared Teams patterns\n   │       ├── commands/\n   │       │   └── dm.md           # User-facing command\n   │       └── agents/\n   │           └── ms-teams-dm.md  # Subagent instructions\n   ├── github/\n   │   ├── pr/\n   │   │   └── bin/                # Shell scripts for PR operations\n   │   │       └── fetch-pr-details.sh\n   │   └── bin/                    # General GitHub scripts\n   │       └── git_prettycommit.rb\n   └── core/\n       └── debugging.md\n   ```\n\n   **Directory conventions:**\n   - `commands/` - User-invocable slash commands (e.g., `/ms-teams:dm`). Must be listed under the `commands:` profile key to be output as `.claude/commands/` files.\n   - `skills/` - Skill files that become `SKILL.md` in `.claude/skills/`. Must be listed under the `skills:` profile key.\n   - `agents/` - Subagent instruction files (dispatched by orchestrator, not user-invocable)\n   - `bin/` - Shell scripts and executables. Must be listed under the `scripts:` profile key to be copied to `.claude/scripts/`.\n   - Root files - Common patterns and shared configuration\n\n### Option 2: Use Multiple Rule Sources\n\nCreate `~/.config/ruly/profiles.yml` to combine rules from different repositories:\n\n```yaml\nprofiles:\n  my-complete-rules:\n    description: \"Combines personal and company rules\"\n    sources:\n      # Your personal rules repository\n      - github: yourusername/rules\n        branch: main\n        rules:\n          - ruby\n          - testing\n          - commands\n\n      # Company rules (e.g., \"FakeCorp\")\n      - github: fakecorp/development-standards\n        branch: main\n        rules:\n          - guidelines/code-review.md\n          - guidelines/security.md\n\n      # Individual files from public repos\n      - https://github.com/thoughtbot/guides/blob/main/ruby/README.md\n```\n\n### Option 3: Quick Start with Init\n\nAfter installing Ruly, you can quickly get started with a basic configuration:\n\n```bash\n# Initialize Ruly with a starter configuration\nruly init\n\n# This creates ~/.config/ruly/profiles.yml with example profiles\n# Edit this file to add your own rule sources\n```\n\n### Option 4: Use Remote Sources Only\n\nIf you don't want to maintain your own rules repository, you can use rules directly from GitHub:\n\n```yaml\nprofiles:\n  remote-only:\n    description: \"Rules from various GitHub sources\"\n    sources:\n      # Individual files\n      - https://github.com/rubocop/ruby-style-guide/blob/master/README.md\n      - https://github.com/testdouble/standard/blob/main/docs/README.md\n\n      # Entire directories (expands to all .md files)\n      - https://github.com/fakecorp/standards/tree/main/ruby\n      - https://github.com/fakecorp/standards/tree/main/testing\n```\n\n### Example: Setting Up Like patrickclery/rules\n\nHere's how the maintainer set up their private rules repository:\n\n1. **Created a private repository:**\n\n   ```bash\n   gh repo create patrickclery/rules --private --description \"Private rules for Ruly gem\"\n   ```\n\n2. **Created your rules content and pushed to GitHub**\n\n3. **Updated your Ruly configuration:**\n\n   ```yaml\n   # ~/.config/ruly/profiles.yml\n   profiles:\n     complete:\n       description: \"Personal + FakeCorp rules\"\n       sources:\n         - github: patrickclery/rules\n           branch: main\n           rules:\n             - ruby\n             - testing\n             - commands\n\n         - github: fakecorp/cursor-rules\n           branch: main\n           rules:\n             - workflow\n             - jira\n   ```\n\n## 📝 Using Ruly Commands\n\nRuly provides a powerful CLI for managing and compiling your AI assistant rules.\n\n### Basic Commands\n\n**Combine all rules into one file:**\n\n```bash\nruly squash\n```\n\n**Use a specific profile:**\n\n```bash\n# Profile name as positional parameter\nruly squash rails\nruly squash api\n```\n\n**Custom output file:**\n\n```bash\n# Squash mode with custom output\nruly squash --output-file=combined-rules.md\n# or using short option\nruly squash -o docs/my-rules.md\n\n# Combine with profile\nruly squash rails -o RAILS.md\n```\n\n**Analyze token usage:**\n\n```bash\n# Analyze a specific profile\nruly analyze rails\nruly analyze api\n\n# Analyze all profiles\nruly analyze --all\nruly analyze -a\n```\n\n**Clean up generated files:**\n\n```bash\n# Clean all agent-related files for current agent\nruly clean\n\n# Clean files from specific profile\nruly clean rails\n\n# Clean files for specific agent\nruly clean --agent cursor\n\n# Dry run to see what would be deleted\nruly clean --dry-run\nruly clean -d\n\n# Clean before squashing (remove old files first)\nruly squash --clean\nruly squash rails --clean\nruly squash -c  # Short form\n\n# Deep clean before squashing (remove ALL Claude artifacts)\nruly squash --deepclean\nruly squash rails --deepclean\n```\n\n**Generate MCP server configuration:**\n\n```bash\n# Create .mcp.json with specific servers (must exist in ~/.config/ruly/mcp.json)\nruly mcp atlassian teams playwright\n\n# Use MCP servers from a profile\nruly mcp -r workaxle-spike\nruly mcp --profile workaxle-bug\n\n# Append to existing .mcp.json instead of overwriting\nruly mcp playwright -a\nruly mcp --append task-master-ai\n\n# Combine profile servers with additional servers\nruly mcp -r workaxle-bug playwright\n\n# Append profile servers to existing config\nruly mcp -r workaxle-spike -a\n```\n\n### Subagents\n\nSubagents allow you to generate specialized agent files that Claude can dispatch to for specific tasks. Each subagent is a self-contained agent with its own rules, commands, and MCP server access.\n\n#### Defining Subagents in Profiles\n\nAdd a `subagents` array to any profile. Each subagent references another profile:\n\n```yaml\nprofiles:\n  # Main profile that spawns subagents\n  full:\n    description: \"Complete development environment\"\n    files:\n      - /path/to/rules/core.md\n    subagents:\n      - name: bug_investigator\n        profile: bug\n      - name: test_runner\n        profile: testing\n      - name: pr_manager\n        profile: pr\n\n  # Profiles used by subagents\n  bug:\n    description: \"Bug investigation and debugging\"\n    files:\n      - /path/to/rules/bug/\n      - /path/to/rules/debugging.md\n    mcp_servers:\n      - task-master-ai\n\n  testing:\n    description: \"Testing and QA workflows\"\n    files:\n      - /path/to/rules/testing/\n    mcp_servers:\n      - playwright\n\n  pr:\n    description: \"PR management\"\n    files:\n      - /path/to/rules/github/pr/\n```\n\n#### How It Works\n\nWhen you run `ruly squash -r full`:\n\n1. **MCP servers collected**: Recursively collects `mcp_servers` from all subagent profiles\n2. **`.mcp.json` written**: Parent's `.mcp.json` includes all collected servers (deduplicated)\n3. **Main rules generated**: `CLAUDE.local.md` with the main profile content\n4. **Agent files created**: `.claude/agents/{name}.md` for each subagent\n5. **Commands organized**: `.claude/commands/{agent_name}/` for agent-specific commands\n\n```\nyour-project/\n├── CLAUDE.local.md              # Main rules (from 'full' profile)\n├── .mcp.json                    # MCP servers (parent + all subagent servers)\n├── .ruly/\n│   └── bin/                     # Bin files (from scripts: key)\n└── .claude/\n    ├── agents/\n    │   ├── bug_investigator.md  # Squashed 'bug' profile\n    │   ├── test_runner.md       # Squashed 'testing' profile\n    │   └── pr_manager.md        # Squashed 'pr' profile\n    ├── commands/\n    │   ├── bug_investigator/    # Commands for bug agent\n    │   ├── test_runner/         # Commands for testing agent\n    │   └── pr_manager/          # Commands for PR agent\n    └── skills/                  # Skills (from skills: key)\n        └── debugging/\n            └── SKILL.md\n```\n\n#### MCP Server Propagation\n\nClaude Code subagents inherit the parent session's MCP configuration — they cannot have independent MCP servers. Ruly handles this automatically: during `ruly squash`, MCP servers from all subagent profiles (recursively, including nested subagents) are collected and merged into the parent's `.mcp.json`.\n\nFor example, given this profile configuration:\n\n```yaml\nprofiles:\n  core:\n    description: \"Main orchestrator\"\n    files:\n      - /path/to/rules/core.md\n    # Note: no mcp_servers defined here\n    subagents:\n      - name: comms\n        profile: comms\n      - name: feature\n        profile: feature\n\n  comms:\n    description: \"Communication agent\"\n    files:\n      - /path/to/rules/comms/\n    mcp_servers:\n      - teams\n      - mattermost\n\n  feature:\n    description: \"Feature development\"\n    files:\n      - /path/to/rules/feature/\n    mcp_servers:\n      - Ref\n```\n\nRunning `ruly squash core` produces a `.mcp.json` containing `teams`, `mattermost`, and `Ref` — all propagated from the subagent profiles — even though `core` itself defines no MCP servers. The console output shows which servers were propagated:\n\n```\n🔌 Propagated MCP servers from subagents: teams, mattermost, Ref\n🔌 Updated .mcp.json with MCP servers\n```\n\nThis propagation is recursive: if `comms` itself has subagents with additional MCP servers, those are collected too. Circular references are handled safely.\n\n#### Agent File Format\n\nGenerated agent files have YAML frontmatter that Claude understands:\n\n```yaml\n---\nname: bug_investigator\ndescription: Bug investigation and debugging\ntools: inherit\nmodel: haiku                # Set via subagent or profile config (default: inherit)\n# Auto-generated from profile: bug\n# Do not edit manually - regenerate using 'ruly squash full'\n---\n\n# Bug Investigator\n\nBug investigation and debugging\n\n## Profile Content\n\n[squashed content from bug profile]\n\n## MCP Servers\n\nThis subagent has access to the following MCP servers:\n- task-master-ai\n\n---\n*Last generated: 2026-02-04 12:30:00*\n*Source profile: bug*\n```\n\n#### Model Specification\n\nControl which Claude model each subagent uses. Route lightweight tasks (context fetching, DMs) to faster/cheaper models while keeping complex tasks on the most capable model.\n\n##### Subagent-Level Model\n\nSpecify `model` directly on a subagent entry:\n\n```yaml\nsubagents:\n  - name: context_grabber\n    profile: context-grabber\n    model: haiku          # Fast, cheap — just fetching data\n  - name: core_engineer\n    profile: core-engineer\n    model: opus           # Most capable — complex implementation\n  - name: comms\n    profile: comms         # No model — inherits from profile or defaults to 'inherit'\n```\n\n##### Profile-Level Default Model\n\nSet a default model for all subagents in a profile:\n\n```yaml\nprofiles:\n  core:\n    description: \"Main orchestrator\"\n    model: sonnet         # Default for all subagents\n    files:\n      - /path/to/rules/core.md\n    subagents:\n      - name: fast_agent\n        profile: fast-tasks\n        model: haiku      # Overrides profile default\n      - name: smart_agent\n        profile: complex-tasks\n                           # Uses profile default (sonnet)\n```\n\n##### Inheritance Chain\n\nModel is resolved in this order:\n\n1. **Subagent `model`** — if specified on the subagent entry\n2. **Parent profile `model`** — if set on the profile containing the subagents\n3. **`inherit`** — the default (inherits from the calling session)\n\nValid values: `haiku`, `sonnet`, `opus`, or `inherit`.\n\n\u003e **Note:** Skills can also specify `model` in their frontmatter — this is already supported and preserved during squash.\n\n#### Directory Structure for Subagents\n\nSubagent instruction files should be organized in `agents/` directories:\n\n```\nrules/\n└── comms/\n    ├── ms-teams/\n    │   ├── common.md                     # Shared patterns (loaded by both)\n    │   ├── commands/\n    │   │   └── dm.md                     # User command: /ms-teams:dm\n    │   └── agents/\n    │       └── ms-teams-dm.md            # Subagent: dispatched on \"send it\"\n    └── mattermost/\n        ├── common.md                     # Shared patterns (loaded by both)\n        ├── commands/\n        │   └── dm.md                     # User command: /mattermost:dm\n        └── agents/\n            └── mattermost-dm.md          # Subagent: dispatched on \"send it\"\n```\n\n**Key distinction:**\n- `commands/` - User-invocable via `/command-name`\n- `agents/` - Dispatched programmatically by the orchestrator\n\n#### When to Use Subagents\n\n| Use Case | Benefit |\n|----------|---------|\n| **Specialized tasks** | Each agent has focused rules for its domain |\n| **Parallel work** | Dispatch multiple agents for independent tasks |\n| **Context isolation** | Agents only load rules they need |\n| **MCP server propagation** | Subagent MCP servers are automatically propagated to parent |\n\n#### Example: Development Workflow\n\n```yaml\nprofiles:\n  workaxle:\n    description: \"Main WorkAxle development\"\n    files:\n      - /path/to/rules/core.md\n    subagents:\n      - name: comms\n        profile: comms        # Jira, Teams, GitHub communications\n      - name: merger\n        profile: merger       # PR merging operations\n      - name: dashboard\n        profile: dashboard    # PR status dashboard\n\n  comms:\n    description: \"Communication via Jira, Teams, GitHub\"\n    files:\n      - /path/to/rules/comms/\n    mcp_servers:\n      - teams\n      - atlassian\n\n  merger:\n    description: \"PR merging commands\"\n    files:\n      - /path/to/rules/github/pr/\n    mcp_servers: []\n\n  dashboard:\n    description: \"Open PRs dashboard\"\n    files:\n      - /path/to/rules/dashboard.md\n    mcp_servers: []\n```\n\nThen Claude can dispatch to these agents:\n\n```\nUser: \"Update all my PRs with latest main\"\nClaude: [Dispatches to merger agent which has PR merge rules]\n\nUser: \"Send a Teams message about WA-1234\"\nClaude: [Dispatches to comms agent which has Teams MCP access]\n\nUser: \"Show me my open PRs\"\nClaude: [Dispatches to dashboard agent]\n```\n\n### Profile System\n\nProfiles allow you to define collections of rules to combine, rather than always including all files.\n\n**List available profiles:**\n\n```bash\nruly list-profiles\n```\n\n**Use a specific profile:**\n\n```bash\n# Use the 'core' profile\nruly squash --profile core\n\n# Use 'testing' profile with custom output\nruly squash --profile testing -o testing-rules.md\n\n# Short form\nruly squash -r minimal\n```\n\n#### Available Profiles\n\nProfiles depend on having access to rule files. If you cloned with the default rules submodule, you'll have access to the profiles defined in `profiles.yml`. Otherwise, create your own profiles in `~/.config/ruly/profiles.yml` pointing to your rule sources.\n\n- **qa** — WorkAxle QA acceptance testing. Write and run Playwright specs in the automation-test-qa repo against dev.workaxle.com. Includes skills for running acceptance tests and syncing the QA repo.\n\n#### Custom Profiles\n\nCreate a `~/.config/ruly/profiles.yml` file to define your own profiles or override existing ones:\n\n```yaml\n# ~/.config/ruly/profiles.yml\n---\ntier: claude_max\nprofiles:\n  # Complete development environment combining multiple sources\n  my_company_core:\n    description: Complete development environment with Ruby, testing, and workflow rules\n    tier: claude_max\n    sources:\n      # John's private rules repository\n      - github: john/private-rules\n        branch: main\n        rules:\n          - rules/commands/bug\n          - rules/commands/pr\n          - rules/bug\n          - rules/commands.md\n          - rules/core\n          - rules/core/debugging\n          - rules/pr\n          - rules/ruby\n          - rules/testing\n          - rules/commands/testing\n          - rules/commands/workflow\n\n      # Company's shared rules repository\n      - github: my_company/development-standards\n        branch: main\n        rules:\n          - rules/commands/jira/details.md\n          - rules/workflow\n          - rules/jira\n\n  # Local files from various projects\n  development_local:\n    description: Auto-generated from local sources\n    files:\n      - /Users/john/Projects/my_app/rules/ruby/common.md\n      - /Users/john/Projects/my_app/rules/ruby/monads.md\n      - /Users/john/Projects/my_app/rules/ruby/rspec.md\n      - /Users/john/Projects/my_app/rules/ruby/sequel.md\n      - /Users/john/Projects/my_app/rules/testing/common.md\n      - /Users/john/Projects/my_app/rules/commands.md\n      - /Users/john/Projects/my_app/rules/commands/bug/diagnose.md\n      - /Users/john/Projects/my_app/rules/commands/bug/fix.md\n      - /Users/john/Projects/my_app/rules/commands/pr/create.md\n    tier: claude_max\n\n  # Simple profile for specific context\n  testing_only:\n    description: Testing and QA rules\n    tier: claude_max\n    files:\n      - /Users/john/Projects/my_app/rules/testing/*.md\n      - /Users/john/Projects/my_app/rules/commands/testing/*.md\n```\n\n#### Profile Keys: Skills, Commands, and Bins\n\nProfiles support explicit keys for files that need special treatment. Files listed under `files:` are always squashed into the main output (`CLAUDE.local.md`) regardless of their path. To output files as skills, commands, or bins, use the dedicated keys:\n\n```yaml\nprofiles:\n  my-profile:\n    description: \"Example with explicit keys\"\n    files:\n      # Regular rule files — squashed into CLAUDE.local.md\n      - /path/to/rules/core.md\n      - /path/to/rules/frameworks/ruby.md\n    skills:\n      # Output as .claude/skills/{name}/SKILL.md\n      - /path/to/rules/skills/debugging.md\n      - /path/to/rules/github/pr/skills/pr-review-loop.md\n    commands:\n      # Output as .claude/commands/{path}.md\n      - /path/to/rules/github/pr/commands/create.md\n      - /path/to/rules/comms/jira/commands/comment.md\n    scripts:\n      # Copied to .claude/scripts/ as executables\n      - /path/to/rules/bin/deploy.sh\n```\n\n**Key behavior:**\n\n| Profile key | Output location | What it does |\n|------------|----------------|--------------|\n| `files:` | `CLAUDE.local.md` | Squashed into main output (always, regardless of path) |\n| `skills:` | `.claude/skills/{name}/SKILL.md` | Creates individual skill files |\n| `commands:` | `.claude/commands/{path}.md` | Creates slash command files |\n| `scripts:` | `.claude/scripts/` | Copies scripts as executables |\n\nAll four keys support both individual file paths and directory paths. Directories are expanded:\n- `skills:` and `commands:` directories expand to all `*.md` files\n- `scripts:` directories expand to all `*.sh` files\n\n**Frontmatter `skills:` references** in individual rule files still work independently. If a rule file declares `skills:` in its frontmatter, those referenced files are automatically resolved and output as SKILL.md files during squash, regardless of which profile key they appear under.\n\n**Remote Sources:**\n\n- Supports pulling rules directly from GitHub repositories\n- Automatically converts GitHub blob URLs to raw URLs\n- Non-Claude agents include all files in the main output\n\n**GitHub URL Formats:**\n\n- **Individual files**: Use `/blob/` URLs for specific files\n  - Example: `https://github.com/owner/repo/blob/branch/path/to/file.md`\n- **Directories**: Use `/tree/` URLs to include all `.md` files in a directory\n  - Example: `https://github.com/owner/repo/tree/branch/path/to/directory`\n  - Automatically expands to include all markdown files in that directory\n- **Important**: Files with extensions (like `.md`) in `/tree/` URLs are treated as individual files, not directories\n\n**Command File Handling:**\n\n- When `--agent claude` (default), files listed under the `commands:` profile key are saved to `.claude/commands/`\n- For other agents, command files are included in the main output file\n- Files in `/commands/` paths under `files:` are treated as regular content (squashed into main output)\n\n**Caching:**\n\n- Use `--cache` flag to enable caching for any profile\n- Cached files are stored in `cache/\u003cagent\u003e/` directory\n- Remote files are cached separately in `cache/remote/` (7-day expiration)\n- Cache is disabled by default\n- Use `ruly clean` to remove cache files\n\nUser profiles:\n\n- Are automatically loaded from `~/.config/ruly/profiles.yml`\n- Override base profiles with the same name\n- Are stored in your home directory configuration\n- Allow user-specific or team-specific customizations\n\n#### Profile Inheritance (`extends:`)\n\nProfiles can extend other profiles using the `extends:` key. The child profile inherits all keys from the parent, with:\n\n- **Array keys** (`files`, `skills`, `commands`, `scripts`, `sources`, `mcp_servers`, `omit_command_prefix`): Merged via union — parent entries first, then child entries, deduplicated\n- **Scalar keys** (`description`, `model`, `tier`): Child wins — parent value only used if child doesn't define it\n- **Subagents**: Merged by `name` — child entry overrides parent entry with same name\n\n```yaml\nprofiles:\n  base:\n    description: \"Base development profile\"\n    files:\n      - rules/core.md\n      - rules/common.md\n    mcp_servers:\n      - task-master-ai\n\n  extended:\n    extends: base\n    description: \"Extended profile with extra tools\"\n    files:\n      - rules/extra.md\n    mcp_servers:\n      - playwright\n```\n\nAfter resolution, `extended` will have:\n- `files`: `[rules/core.md, rules/common.md, rules/extra.md]`\n- `mcp_servers`: `[task-master-ai, playwright]`\n- `description`: `\"Extended profile with extra tools\"`\n\nMulti-level inheritance is supported (A extends B extends C). Circular references are detected and produce an error.\n\n### Commands\n\n- **Squash** (`squash [RECIPE]`): Combines all rule content into a single large file. Profile is\n  optional positional parameter. Supports fetching remote GitHub files and caching for performance.\n  Use `--toc` or `-t` to generate a table of contents with unique anchors for all headers, ensuring proper navigation even when multiple files have identical header names. Also includes a list of available slash commands.\n  Use `--deepclean` to remove all Claude artifacts before squashing (overrides `--clean`).\n  Use `--verbose` or `-v` to show detailed per-file processing output (file paths, token counts, requires discovery). Default output shows only profile, subagents, errors, and summary.\n\n- **Analyze** (`analyze [RECIPE]`): Analyzes token usage for profiles without generating files. Shows\n  detailed file breakdown and total token count. Use `--all` to analyze all profiles at once.\n\n- **Clean** (`clean [RECIPE]`): Deletes output files created by the squash command. Profile is\n  optional. Removes main output file and command files directory.\n  Use `--deepclean` to remove all Claude artifacts (.claude/ directory, CLAUDE.local.md, CLAUDE.md) regardless of profile.\n\n- **Introspect** (`introspect [FILE_PATH]`): Analyzes a markdown file to extract its frontmatter\n  metadata and identify any `requires:` dependencies. Shows the YAML frontmatter, lists required\n  files, and displays their resolved paths. Useful for understanding file dependencies and debugging\n  the requires system. If no file path is provided, it will look for a file in the current directory.\n\n- **List Profiles** (`list-profiles`): Shows all available profiles with file counts and cache\n  indicators.\n\n- **Version** (`version`): Shows the current Ruly version.\n\n### Slash Commands\n\nSlash commands are special commands that can be defined in your rule files to provide quick actions for AI assistants. When you include command files in your rules (typically in a `commands/` directory), they become available as slash commands in the generated output.\n\nFor example, if you have a file `commands/bug/diagnose.md` in your rules, it would become available as `/bug:diagnose` when using the generated rules with Claude or other AI assistants.\n\nThe `--toc` option will automatically generate:\n\n1. A table of contents with links to all headers in the combined document\n2. Unique anchors for headers (prefixed with the source file path) to handle duplicate header names across files\n3. A list of all available slash commands in your squashed output\n\nThis ensures proper navigation even when multiple rule files contain headers with identical names (e.g., multiple files with \"# Introduction\" sections).\n\n#### Available Ruly Commands\n\n- `/ruly:compress` - Analyze markdown rules to find redundancies and make them more DRY\n- `/ruly:decompose` - Decompose a markdown file into a directory using git mv (preserves history)\n- `/run-acceptance-test` - Takes acceptance criteria (direct text, Jira ticket `WA-XXXX`, or PR number `PR:NNNN`), reads page objects from automation-test-qa, writes a Playwright spec, runs it, and reports results.\n- `/sync-qa-repo` - Pulls latest from automation-test-qa, reports new/changed page objects, specs, and API helpers.\n\n### Examples\n\n```bash\n# Generate CLAUDE.local.md with all rules\nruly squash\n\n# Dry run - see what would be created without creating it\nruly squash --dry-run\nruly squash -d\n\n# Generate core rules only\nruly squash --profile core\nruly squash -r core\n\n# Generate squashed testing rules to a custom file\nruly squash -r testing -o test/testing-rules.md\n\n# Generate rules for a different agent (e.g., cursor)\nruly squash -r rails --agent cursor -o CURSOR.md\nruly squash -r rails -a cursor -o CURSOR.md\n\n# Generate with remote sources (command files go to .claude/commands/)\nruly squash -r example_mixed\n\n# Use cached version (if profile has cache: true)\nruly squash rails\n\n# Bypass cache for one run\nruly squash rails --no-cache\n\n# Clean up generated files\nruly clean\n\n# Dry run - see what would be deleted\nruly clean --dry-run\nruly clean -d\n\n# Deep clean - remove all Claude artifacts\nruly clean --deepclean\n\n# Clean specific output file\nruly clean -o test/testing-rules.md\n\n# Introspect a markdown file to see its frontmatter and requires\nruly introspect rules/ruby/ruby-practices.md\n\n# Introspect a file in the current directory\nruly introspect README.md\n\n# List what profiles are available\nruly list-profiles\n\n# Show version\nruly version\n\n# View help\nruly help\nruly help squash\nruly help clean\nruly help introspect\n```\n\nRuly will automatically:\n\n- Load profiles from both `profiles.yml` and `~/.config/ruly/profiles.yml`\n- Support glob patterns in profile definitions\n- Create parent directories if using custom output paths\n- Display file count and output size\n- Show which profile was used in the output\n\n## Example Recipes\n\n### Multi-Repo Orchestrator\n\nAn orchestrator that manages multiple repositories, each with their own `CLAUDE.md` and hooks. Subagents dispatched into each repo automatically pick up the repo's configuration.\n\n#### Directory Layout\n\n```\n~/agents/orchestrator/\n├── CLAUDE.local.md              # Generated orchestrator rules\n├── .mcp.json                    # MCP servers (collected from all subagents)\n├── .claude/\n│   ├── agents/\n│   │   ├── backend_engineer.md  # Has acme-api's CLAUDE.md + hooks baked in\n│   │   ├── frontend_engineer.md # Has acme-web's CLAUDE.md + rules + hooks baked in\n│   │   └── comms.md             # Pure ruly profile (no repo append)\n│   ├── scripts/\n│   │   └── worktree-create.sh   # Propagated to all submodule dirs\n│   └── settings.local.json      # Parent hooks (WorktreeCreate)\n├── acme-api/                    # Backend repo (git submodule)\n│   ├── CLAUDE.md                # 1800-line repo-specific guidance\n│   └── .claude/\n│       └── settings.json        # No custom hooks\n├── acme-web/                    # Frontend repo (git submodule)\n│   ├── CLAUDE.md                # 500-line repo-specific guidance\n│   └── .claude/\n│       ├── rules/\n│       │   └── command-timeouts.md  # Repo-specific rules\n│       ├── hooks/\n│       │   └── eslint-fix.sh        # Repo-specific hook script\n│       └── settings.json            # PostToolUse hook for ESLint\n```\n\n#### Profile Configuration\n\n```yaml\nprofiles:\n  orchestrator:\n    description: \"Multi-repo dispatcher\"\n    hooks:\n      WorktreeCreate:\n        - hooks:\n            - type: command\n              command: \".claude/scripts/worktree-create.sh\"\n              timeout: 120\n    files:\n      - /path/to/rules/orchestrator/dispatch.md\n    scripts:\n      - /path/to/rules/orchestrator/bin/worktree-create.sh\n    subagents:\n      # Backend — reads acme-api's CLAUDE.md and hooks\n      - name: backend_engineer\n        profile: backend-engineer\n        cwd: acme-api\n        append: true\n      # Frontend — reads acme-web's CLAUDE.md, rules, and hooks\n      - name: frontend_engineer\n        profile: frontend-engineer\n        cwd: acme-web\n        append: true\n      # Comms — pure ruly profile, no repo to append\n      - name: comms\n        profile: comms\n```\n\n#### What `append: true` Does\n\nWhen a subagent has both `cwd:` and `append: true`, ruly reads from the repo directory during squash:\n\n| Source | What's read | Where it goes |\n|--------|------------|---------------|\n| `{cwd}/CLAUDE.md` | Repo's main guidance doc | Appended to agent body as `## Repository Context` |\n| `{cwd}/.claude/rules/*.md` | Repo-specific rules | Appended to agent body as `## Repository Rules` |\n| `{cwd}/.claude/settings.json` | Repo's hooks | Merged into agent frontmatter `hooks:` |\n\nEach subagent gets only its own repo's hooks — no cross-contamination between subagents.\n\n#### Generated Agent Frontmatter\n\nThe `frontend_engineer` subagent gets the parent's `WorktreeCreate` hook merged with the repo's `PostToolUse` hook:\n\n```yaml\n---\nname: frontend_engineer\ndescription: Frontend feature development - React/TypeScript with TDD\ntools: Bash, Read, Write, Edit, Glob, Grep\nmodel: inherit\nmcpServers: \"[playwright, Ref]\"\npermissionMode: bypassPermissions\nhooks:\n  WorktreeCreate:\n  - hooks:\n    - type: command\n      command: \".claude/scripts/worktree-create.sh\"\n      timeout: 120\n  PostToolUse:\n  - matcher: Edit|Write\n    hooks:\n    - type: command\n      command: \".claude/hooks/eslint-fix.sh\"\n# Auto-generated from profile: frontend-engineer\n# Do not edit manually - regenerate using 'ruly squash orchestrator'\n---\n```\n\nThe `backend_engineer` subagent only gets the parent's hook (since acme-api has no custom hooks):\n\n```yaml\n---\nname: backend_engineer\ndescription: Backend feature development - Ruby/Sequel with TDD\ntools: Bash, Read, Write, Edit, Glob, Grep\nmodel: inherit\nhooks:\n  WorktreeCreate:\n  - hooks:\n    - type: command\n      command: \".claude/scripts/worktree-create.sh\"\n      timeout: 120\n# Auto-generated from profile: backend-engineer\n# Do not edit manually - regenerate using 'ruly squash orchestrator'\n---\n```\n\n#### Generated Agent Body (append sections)\n\nAfter the profile's squashed content, each subagent with `append: true` gets additional sections:\n\n```markdown\n## Profile Content\n\n[squashed content from frontend-engineer profile]\n\n---\n\n## Repository Context\n\n# CLAUDE.md\n\nThis file provides guidance for the acme-web frontend application...\n\n## Development\n\n- Use `yarn dev` for development server\n- Use `yarn typecheck` for type checking\n- Use `yarn lint --fix` for linting\n\n---\n\n## Repository Rules\n\n## Command Timeouts\n\n### Rule\nAlways use a **5-minute timeout** (300000ms) for:\n- `yarn typecheck`\n- `yarn lint`\n\n---\n*Last generated: 2026-03-06 10:43:25*\n*Source profile: frontend-engineer*\n```\n\n#### With vs Without `append`\n\n| Feature | `append: true` | No `append` |\n|---------|----------------|-------------|\n| Profile content | Included | Included |\n| Repo CLAUDE.md | Baked into agent body | Not visible to subagent |\n| Repo .claude/rules/ | Baked into agent body | Not visible to subagent |\n| Repo hooks (settings.json) | Merged into frontmatter | Not applied |\n| Parent hooks | Always included | Always included |\n| MCP servers | From profile (propagated to parent) | From profile (propagated to parent) |\n\n\u003e **Note:** Claude Code subagents do **not** automatically discover `CLAUDE.md`, `.claude/rules/`, or `.claude/settings.json` from their CWD. The `append` feature exists specifically to bridge this gap by baking repo configuration into the agent file at squash time.\n\n---\n\n## 🔧 Troubleshooting\n\n### Common Issues\n\n**Permission denied:**\n\n- Ensure you have write access to your project directory\n- Check that Ruby gems can be installed globally\n\n**Profile not found:**\n\n- Run `ruly list-profiles` to see available profiles\n- Check `~/.config/ruly/profiles.yml` for user-defined profiles\n- Ensure profile names match exactly (case-sensitive)\n\n**Files not being cleaned:**\n\n- Use `ruly clean --dry-run` to preview what will be deleted\n- Specify agent with `--agent` option if not using Claude\n- Ensure you're using the correct profile name if specified\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatrickclery%2Fruly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpatrickclery%2Fruly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatrickclery%2Fruly/lists"}