@intellectronica/ruler 0.3.25 → 0.3.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -54,38 +54,38 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
54
54
 
55
55
  ## Supported AI Agents
56
56
 
57
- | Agent | Rules File(s) | MCP Configuration / Notes |
58
- | ---------------- | ------------------------------------------------ | ------------------------------------------------ |
59
- | AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) |
60
- | GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` |
61
- | Claude Code | `CLAUDE.md` | `.mcp.json` |
62
- | OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` |
63
- | Pi Coding Agent | `AGENTS.md` | - |
64
- | Jules | `AGENTS.md` | - |
65
- | Cursor | `AGENTS.md` | `.cursor/mcp.json` |
66
- | Windsurf | `AGENTS.md` | `.windsurf/mcp_config.json` |
67
- | Cline | `.clinerules` | - |
68
- | Crush | `CRUSH.md` | `.crush.json` |
69
- | Amp | `AGENTS.md` | - |
70
- | Antigravity | `.agent/rules/ruler.md` | - |
71
- | Amazon Q CLI | `.amazonq/rules/ruler_q_rules.md` | `.amazonq/mcp.json` |
72
- | Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` |
73
- | Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` |
74
- | Open Hands | `.openhands/microagents/repo.md` | `config.toml` |
75
- | Gemini CLI | `AGENTS.md` | `.gemini/settings.json` |
76
- | Junie | `.junie/guidelines.md` | - |
77
- | AugmentCode | `.augment/rules/ruler_augment_instructions.md` | - |
78
- | Kilo Code | `.kilocode/rules/ruler_kilocode_instructions.md` | `.kilocode/mcp.json` |
79
- | OpenCode | `AGENTS.md` | `opencode.json` |
80
- | Goose | `.goosehints` | - |
81
- | Qwen Code | `AGENTS.md` | `.qwen/settings.json` |
82
- | RooCode | `AGENTS.md` | `.roo/mcp.json` |
83
- | Zed | `AGENTS.md` | `.zed/settings.json` (project root, never $HOME) |
84
- | Trae AI | `.trae/rules/project_rules.md` | - |
85
- | Warp | `WARP.md` | - |
86
- | Kiro | `.kiro/steering/ruler_kiro_instructions.md` | `.kiro/settings/mcp.json` |
87
- | Firebender | `firebender.json` | `firebender.json` (rules and MCP in same file) |
88
- | Mistral Vibe | `AGENTS.md` | `.vibe/config.toml` |
57
+ | Agent | Rules File(s) | MCP Configuration / Notes | Skills Support / Location |
58
+ | ---------------- | ------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------- |
59
+ | AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) | - |
60
+ | GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` | `.claude/skills/` |
61
+ | Claude Code | `CLAUDE.md` | `.mcp.json` | `.claude/skills/` |
62
+ | OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` | `.codex/skills/` |
63
+ | Pi Coding Agent | `AGENTS.md` | - | `.pi/skills/` |
64
+ | Jules | `AGENTS.md` | - | - |
65
+ | Cursor | `AGENTS.md` | `.cursor/mcp.json` | `.cursor/skills/` |
66
+ | Windsurf | `AGENTS.md` | `.windsurf/mcp_config.json` | - |
67
+ | Cline | `.clinerules` | - | - |
68
+ | Crush | `CRUSH.md` | `.crush.json` | - |
69
+ | Amp | `AGENTS.md` | - | `.agents/skills/` |
70
+ | Antigravity | `.agent/rules/ruler.md` | - | `.agent/skills/` |
71
+ | Amazon Q CLI | `.amazonq/rules/ruler_q_rules.md` | `.amazonq/mcp.json` | - |
72
+ | Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` | - |
73
+ | Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` | - |
74
+ | Open Hands | `.openhands/microagents/repo.md` | `config.toml` | - |
75
+ | Gemini CLI | `AGENTS.md` | `.gemini/settings.json` | `.gemini/skills/` |
76
+ | Junie | `.junie/guidelines.md` | - | - |
77
+ | AugmentCode | `.augment/rules/ruler_augment_instructions.md` | - | - |
78
+ | Kilo Code | `.kilocode/rules/ruler_kilocode_instructions.md` | `.kilocode/mcp.json` | `.claude/skills/` |
79
+ | OpenCode | `AGENTS.md` | `opencode.json` | `.opencode/skill/` |
80
+ | Goose | `.goosehints` | - | `.agents/skills/` |
81
+ | Qwen Code | `AGENTS.md` | `.qwen/settings.json` | - |
82
+ | RooCode | `AGENTS.md` | `.roo/mcp.json` | `.roo/skills/` |
83
+ | Zed | `AGENTS.md` | `.zed/settings.json` (project root, never $HOME) | - |
84
+ | Trae AI | `.trae/rules/project_rules.md` | - | - |
85
+ | Warp | `WARP.md` | - | - |
86
+ | Kiro | `.kiro/steering/ruler_kiro_instructions.md` | `.kiro/settings/mcp.json` | - |
87
+ | Firebender | `firebender.json` | `firebender.json` (rules and MCP in same file) | - |
88
+ | Mistral Vibe | `AGENTS.md` | `.vibe/config.toml` | `.vibe/skills/` |
89
89
 
90
90
  ## Getting Started
91
91
 
@@ -318,15 +318,15 @@ ruler revert [options]
318
318
 
319
319
  ### Options
320
320
 
321
- | Option | Description |
322
- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
323
- | `--project-root <path>` | Path to your project's root (default: current directory) |
321
+ | Option | Description |
322
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
323
+ | `--project-root <path>` | Path to your project's root (default: current directory) |
324
324
  | `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (agentsmd, aider, amazonqcli, amp, antigravity, augmentcode, claude, cline, codex, copilot, crush, cursor, firebase, firebender, gemini-cli, goose, jules, junie, kilocode, kiro, mistral, opencode, openhands, pi, qwen, roo, trae, warp, windsurf, zed) |
325
- | `--config <path>` | Path to a custom `ruler.toml` configuration file |
326
- | `--keep-backups` | Keep backup files (.bak) after restoration (default: false) |
327
- | `--dry-run` | Preview changes without actually reverting files |
328
- | `--verbose` / `-v` | Display detailed output during execution |
329
- | `--local-only` | Only search for local .ruler directories, ignore global config |
325
+ | `--config <path>` | Path to a custom `ruler.toml` configuration file |
326
+ | `--keep-backups` | Keep backup files (.bak) after restoration (default: false) |
327
+ | `--dry-run` | Preview changes without actually reverting files |
328
+ | `--verbose` / `-v` | Display detailed output during execution |
329
+ | `--local-only` | Only search for local .ruler directories, ignore global config |
330
330
 
331
331
  ### Common Examples
332
332
 
@@ -559,7 +559,7 @@ export CODEX_HOME="$(pwd)/.codex"
559
559
 
560
560
  ## Skills Support (Experimental)
561
561
 
562
- **⚠️ Experimental Feature**: Skills support is currently experimental and requires `uv` (the Python package manager) to be installed on your system for MCP-based agent integration (agents without native skills support).
562
+ **⚠️ Experimental Feature**: Skills support is currently experimental. Skills are only propagated to agents with native skills support; other agents are skipped with a warning.
563
563
 
564
564
  Ruler can manage and propagate skills to supported AI agents. Skills are stored in `.ruler/skills/` and are automatically distributed to compatible agents when you run `ruler apply`.
565
565
 
@@ -576,11 +576,11 @@ Skills are specialized knowledge packages that extend AI agent capabilities with
576
576
  - **Pi Coding Agent**: `.pi/skills/`
577
577
  - **Goose**: `.agents/skills/`
578
578
  - **Amp**: `.agents/skills/` (shared with Goose)
579
+ - **Antigravity**: `.agent/skills/`
579
580
  - **Mistral Vibe**: `.vibe/skills/`
580
581
  - **Roo Code**: `.roo/skills/`
581
582
  - **Gemini CLI**: `.gemini/skills/`
582
583
  - **Cursor**: `.cursor/skills/`
583
- - **Other MCP-compatible agents**: Skills are copied to `.skillz/` and a Skillz MCP server is automatically configured via `uvx`
584
584
 
585
585
  ### Skills Directory Structure
586
586
 
@@ -627,23 +627,9 @@ ruler apply --no-skills
627
627
  enabled = true # or false to disable
628
628
  ```
629
629
 
630
- ### Skillz MCP Server
630
+ ### Non-native Agents
631
631
 
632
- For agents that support MCP but don't have native skills support, Ruler automatically:
633
-
634
- 1. Copies skills to `.skillz/` directory
635
- 2. Configures a Skillz MCP server in the agent's configuration
636
- 3. Uses `uvx` to launch the server with the project-relative path to `.skillz`
637
-
638
- Agents using native skills support (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Mistral Vibe, Roo Code, Gemini CLI, and Cursor) **do not** use the Skillz MCP server and instead use their own native skills directories.
639
-
640
- Example auto-generated MCP server configuration:
641
-
642
- ```toml
643
- [mcp_servers.skillz]
644
- command = "uvx"
645
- args = ["skillz@latest", ".skillz"]
646
- ```
632
+ If you run Ruler for agents that do not support native skills, Ruler logs a warning and skips skills propagation for those agents.
647
633
 
648
634
  ### `.gitignore` Integration
649
635
 
@@ -654,22 +640,17 @@ When skills support is enabled and gitignore integration is active, Ruler automa
654
640
  - `.opencode/skill/` (for OpenCode)
655
641
  - `.pi/skills/` (for Pi Coding Agent)
656
642
  - `.agents/skills/` (for Goose and Amp)
643
+ - `.agent/skills/` (for Antigravity)
657
644
  - `.vibe/skills/` (for Mistral Vibe)
658
645
  - `.roo/skills/` (for Roo Code)
659
646
  - `.gemini/skills/` (for Gemini CLI)
660
647
  - `.cursor/skills/` (for Cursor)
661
- - `.skillz/` (for other MCP-based agents)
662
648
 
663
649
  to your `.gitignore` file within the managed Ruler block.
664
650
 
665
651
  ### Requirements
666
652
 
667
- - **For agents with native skills support** (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Mistral Vibe, Roo Code, Gemini CLI, Cursor): No additional requirements
668
- - **For other MCP agents**: `uv` must be installed and available in your PATH
669
- ```bash
670
- # Install uv if needed
671
- curl -LsSf https://astral.sh/uv/install.sh | sh
672
- ```
653
+ - **For agents with native skills support** (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Antigravity, Mistral Vibe, Roo Code, Gemini CLI, Cursor): No additional requirements.
673
654
 
674
655
  ### Validation
675
656
 
@@ -688,7 +669,7 @@ Test skills propagation without making changes:
688
669
  ruler apply --dry-run
689
670
  ```
690
671
 
691
- This shows which skills would be copied and which MCP servers would be configured.
672
+ This shows which skills would be copied.
692
673
 
693
674
  ### Example Workflow
694
675
 
@@ -717,11 +698,11 @@ ruler apply
717
698
  # - OpenCode: .opencode/skill/my-skill/
718
699
  # - Pi Coding Agent: .pi/skills/my-skill/
719
700
  # - Goose & Amp: .agents/skills/my-skill/
701
+ # - Antigravity: .agent/skills/my-skill/
720
702
  # - Mistral Vibe: .vibe/skills/my-skill/
721
703
  # - Roo Code: .roo/skills/my-skill/
722
704
  # - Gemini CLI: .gemini/skills/my-skill/
723
705
  # - Cursor: .cursor/skills/my-skill/
724
- # - Other MCP agents: .skillz/my-skill/ + Skillz MCP server configured
725
706
  ```
726
707
 
727
708
  ## `.gitignore` Integration
@@ -49,5 +49,8 @@ class AntigravityAgent extends AbstractAgent_1.AbstractAgent {
49
49
  getDefaultOutputPath(projectRoot) {
50
50
  return path.join(projectRoot, '.agent', 'rules', 'ruler.md');
51
51
  }
52
+ supportsNativeSkills() {
53
+ return true;
54
+ }
52
55
  }
53
56
  exports.AntigravityAgent = AntigravityAgent;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SKILLZ_MCP_SERVER_NAME = exports.SKILL_MD_FILENAME = exports.SKILLZ_DIR = exports.CURSOR_SKILLS_PATH = exports.GEMINI_SKILLS_PATH = exports.ROO_SKILLS_PATH = exports.VIBE_SKILLS_PATH = exports.GOOSE_SKILLS_PATH = exports.PI_SKILLS_PATH = exports.OPENCODE_SKILLS_PATH = exports.CODEX_SKILLS_PATH = exports.CLAUDE_SKILLS_PATH = exports.RULER_SKILLS_PATH = exports.SKILLS_DIR = exports.DEFAULT_RULES_FILENAME = exports.ERROR_PREFIX = void 0;
3
+ exports.SKILL_MD_FILENAME = exports.ANTIGRAVITY_SKILLS_PATH = exports.CURSOR_SKILLS_PATH = exports.GEMINI_SKILLS_PATH = exports.ROO_SKILLS_PATH = exports.VIBE_SKILLS_PATH = exports.GOOSE_SKILLS_PATH = exports.PI_SKILLS_PATH = exports.OPENCODE_SKILLS_PATH = exports.CODEX_SKILLS_PATH = exports.CLAUDE_SKILLS_PATH = exports.RULER_SKILLS_PATH = exports.SKILLS_DIR = exports.DEFAULT_RULES_FILENAME = exports.ERROR_PREFIX = void 0;
4
4
  exports.actionPrefix = actionPrefix;
5
5
  exports.createRulerError = createRulerError;
6
6
  exports.logVerbose = logVerbose;
@@ -61,6 +61,5 @@ exports.VIBE_SKILLS_PATH = '.vibe/skills';
61
61
  exports.ROO_SKILLS_PATH = '.roo/skills';
62
62
  exports.GEMINI_SKILLS_PATH = '.gemini/skills';
63
63
  exports.CURSOR_SKILLS_PATH = '.cursor/skills';
64
- exports.SKILLZ_DIR = '.skillz';
64
+ exports.ANTIGRAVITY_SKILLS_PATH = '.agent/skills';
65
65
  exports.SKILL_MD_FILENAME = 'SKILL.md';
66
- exports.SKILLZ_MCP_SERVER_NAME = 'skillz';
@@ -45,8 +45,7 @@ exports.propagateSkillsForVibe = propagateSkillsForVibe;
45
45
  exports.propagateSkillsForRoo = propagateSkillsForRoo;
46
46
  exports.propagateSkillsForGemini = propagateSkillsForGemini;
47
47
  exports.propagateSkillsForCursor = propagateSkillsForCursor;
48
- exports.propagateSkillsForSkillz = propagateSkillsForSkillz;
49
- exports.buildSkillzMcpConfig = buildSkillzMcpConfig;
48
+ exports.propagateSkillsForAntigravity = propagateSkillsForAntigravity;
50
49
  const path = __importStar(require("path"));
51
50
  const fs = __importStar(require("fs/promises"));
52
51
  const constants_1 = require("../constants");
@@ -82,7 +81,7 @@ async function getSkillsGitignorePaths(projectRoot) {
82
81
  return [];
83
82
  }
84
83
  // Import here to avoid circular dependency
85
- const { CLAUDE_SKILLS_PATH, CODEX_SKILLS_PATH, OPENCODE_SKILLS_PATH, PI_SKILLS_PATH, GOOSE_SKILLS_PATH, VIBE_SKILLS_PATH, ROO_SKILLS_PATH, GEMINI_SKILLS_PATH, CURSOR_SKILLS_PATH, SKILLZ_DIR, } = await Promise.resolve().then(() => __importStar(require('../constants')));
84
+ const { CLAUDE_SKILLS_PATH, CODEX_SKILLS_PATH, OPENCODE_SKILLS_PATH, PI_SKILLS_PATH, GOOSE_SKILLS_PATH, VIBE_SKILLS_PATH, ROO_SKILLS_PATH, GEMINI_SKILLS_PATH, CURSOR_SKILLS_PATH, ANTIGRAVITY_SKILLS_PATH, } = await Promise.resolve().then(() => __importStar(require('../constants')));
86
85
  return [
87
86
  path.join(projectRoot, CLAUDE_SKILLS_PATH),
88
87
  path.join(projectRoot, CODEX_SKILLS_PATH),
@@ -93,7 +92,7 @@ async function getSkillsGitignorePaths(projectRoot) {
93
92
  path.join(projectRoot, ROO_SKILLS_PATH),
94
93
  path.join(projectRoot, GEMINI_SKILLS_PATH),
95
94
  path.join(projectRoot, CURSOR_SKILLS_PATH),
96
- path.join(projectRoot, SKILLZ_DIR),
95
+ path.join(projectRoot, ANTIGRAVITY_SKILLS_PATH),
97
96
  ];
98
97
  }
99
98
  /**
@@ -104,16 +103,15 @@ async function getSkillsGitignorePaths(projectRoot) {
104
103
  */
105
104
  let hasWarnedExperimental = false;
106
105
  /**
107
- * Warns once per process about experimental skills features and uv requirement.
106
+ * Warns once per process about experimental skills support.
108
107
  * Uses module-level state to prevent duplicate warnings within the same process.
109
108
  */
110
- function warnOnceExperimentalAndUv(verbose, dryRun) {
109
+ function warnOnceExperimental(verbose, dryRun) {
111
110
  if (hasWarnedExperimental) {
112
111
  return;
113
112
  }
114
113
  hasWarnedExperimental = true;
115
114
  (0, constants_1.logWarn)('Skills support is experimental and behavior may change in future releases.', dryRun);
116
- (0, constants_1.logWarn)('Skills MCP server (Skillz) requires uv. Install: https://github.com/astral-sh/uv', dryRun);
117
115
  }
118
116
  /**
119
117
  * Cleans up skills directories when skills are disabled.
@@ -129,7 +127,7 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
129
127
  const rooSkillsPath = path.join(projectRoot, constants_1.ROO_SKILLS_PATH);
130
128
  const geminiSkillsPath = path.join(projectRoot, constants_1.GEMINI_SKILLS_PATH);
131
129
  const cursorSkillsPath = path.join(projectRoot, constants_1.CURSOR_SKILLS_PATH);
132
- const skillzPath = path.join(projectRoot, constants_1.SKILLZ_DIR);
130
+ const antigravitySkillsPath = path.join(projectRoot, constants_1.ANTIGRAVITY_SKILLS_PATH);
133
131
  // Clean up .claude/skills
134
132
  try {
135
133
  await fs.access(claudeSkillsPath);
@@ -256,15 +254,15 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
256
254
  catch {
257
255
  // Directory doesn't exist, nothing to clean
258
256
  }
259
- // Clean up .skillz
257
+ // Clean up .agent/skills
260
258
  try {
261
- await fs.access(skillzPath);
259
+ await fs.access(antigravitySkillsPath);
262
260
  if (dryRun) {
263
- (0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.SKILLZ_DIR}`, verbose, dryRun);
261
+ (0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.ANTIGRAVITY_SKILLS_PATH}`, verbose, dryRun);
264
262
  }
265
263
  else {
266
- await fs.rm(skillzPath, { recursive: true, force: true });
267
- (0, constants_1.logVerboseInfo)(`Removed ${constants_1.SKILLZ_DIR} (skills disabled)`, verbose, dryRun);
264
+ await fs.rm(antigravitySkillsPath, { recursive: true, force: true });
265
+ (0, constants_1.logVerboseInfo)(`Removed ${constants_1.ANTIGRAVITY_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
268
266
  }
269
267
  }
270
268
  catch {
@@ -301,17 +299,20 @@ async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryR
301
299
  return;
302
300
  }
303
301
  (0, constants_1.logVerboseInfo)(`Discovered ${skills.length} skill(s)`, verbose, dryRun);
304
- // Check if any agents need skills
305
302
  const hasNativeSkillsAgent = agents.some((a) => a.supportsNativeSkills?.());
306
- const hasMcpAgent = agents.some((a) => a.supportsMcpStdio?.() && !a.supportsNativeSkills?.());
307
- if (!hasNativeSkillsAgent && !hasMcpAgent) {
308
- (0, constants_1.logVerboseInfo)('No agents require skills support', verbose, dryRun);
303
+ const nonNativeAgents = agents.filter((agent) => !agent.supportsNativeSkills?.());
304
+ if (nonNativeAgents.length > 0) {
305
+ const agentList = nonNativeAgents
306
+ .map((agent) => agent.getName())
307
+ .join(', ');
308
+ (0, constants_1.logWarn)(`Skills are configured, but the following agents do not support native skills and will be skipped: ${agentList}`, dryRun);
309
+ }
310
+ if (!hasNativeSkillsAgent) {
311
+ (0, constants_1.logVerboseInfo)('No agents support native skills, skipping skills propagation', verbose, dryRun);
309
312
  return;
310
313
  }
311
314
  // Warn about experimental features
312
- if (hasMcpAgent) {
313
- warnOnceExperimentalAndUv(verbose, dryRun);
314
- }
315
+ warnOnceExperimental(verbose, dryRun);
315
316
  // Copy to Claude skills directory if needed
316
317
  if (hasNativeSkillsAgent) {
317
318
  (0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CLAUDE_SKILLS_PATH} for Claude Code, GitHub Copilot, and Kilo Code`, verbose, dryRun);
@@ -332,12 +333,10 @@ async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryR
332
333
  await propagateSkillsForGemini(projectRoot, { dryRun });
333
334
  (0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CURSOR_SKILLS_PATH} for Cursor`, verbose, dryRun);
334
335
  await propagateSkillsForCursor(projectRoot, { dryRun });
336
+ (0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.ANTIGRAVITY_SKILLS_PATH} for Antigravity`, verbose, dryRun);
337
+ await propagateSkillsForAntigravity(projectRoot, { dryRun });
335
338
  }
336
- // Copy to .skillz directory if needed
337
- if (hasMcpAgent) {
338
- (0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.SKILLZ_DIR} for MCP agents`, verbose, dryRun);
339
- await propagateSkillsForSkillz(projectRoot, { dryRun });
340
- }
339
+ // No MCP-based propagation; only native skills are supported.
341
340
  }
342
341
  /**
343
342
  * Propagates skills for Claude Code by copying .ruler/skills to .claude/skills.
@@ -790,13 +789,14 @@ async function propagateSkillsForCursor(projectRoot, options) {
790
789
  return [];
791
790
  }
792
791
  /**
793
- * Propagates skills for MCP agents by copying .ruler/skills to .skillz.
792
+ * Propagates skills for Antigravity by copying .ruler/skills to .agent/skills.
794
793
  * Uses atomic replace to ensure safe overwriting of existing skills.
795
794
  * Returns dry-run steps if dryRun is true, otherwise returns empty array.
796
795
  */
797
- async function propagateSkillsForSkillz(projectRoot, options) {
796
+ async function propagateSkillsForAntigravity(projectRoot, options) {
798
797
  const skillsDir = path.join(projectRoot, constants_1.RULER_SKILLS_PATH);
799
- const skillzPath = path.join(projectRoot, constants_1.SKILLZ_DIR);
798
+ const antigravitySkillsPath = path.join(projectRoot, constants_1.ANTIGRAVITY_SKILLS_PATH);
799
+ const antigravityDir = path.dirname(antigravitySkillsPath);
800
800
  // Check if source skills directory exists
801
801
  try {
802
802
  await fs.access(skillsDir);
@@ -807,25 +807,26 @@ async function propagateSkillsForSkillz(projectRoot, options) {
807
807
  }
808
808
  if (options.dryRun) {
809
809
  return [
810
- `Copy skills from ${constants_1.RULER_SKILLS_PATH} to ${constants_1.SKILLZ_DIR}`,
811
- `Configure Skillz MCP server with path to ${constants_1.SKILLZ_DIR}`,
810
+ `Copy skills from ${constants_1.RULER_SKILLS_PATH} to ${constants_1.ANTIGRAVITY_SKILLS_PATH}`,
812
811
  ];
813
812
  }
813
+ // Ensure .agent directory exists
814
+ await fs.mkdir(antigravityDir, { recursive: true });
814
815
  // Use atomic replace: copy to temp, then rename
815
- const tempDir = path.join(projectRoot, `${constants_1.SKILLZ_DIR}.tmp-${Date.now()}`);
816
+ const tempDir = path.join(antigravityDir, `skills.tmp-${Date.now()}`);
816
817
  try {
817
818
  // Copy to temp directory
818
819
  await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
819
820
  // Atomically replace the target
820
821
  // First, remove existing target if it exists
821
822
  try {
822
- await fs.rm(skillzPath, { recursive: true, force: true });
823
+ await fs.rm(antigravitySkillsPath, { recursive: true, force: true });
823
824
  }
824
825
  catch {
825
826
  // Target didn't exist, that's fine
826
827
  }
827
828
  // Rename temp to target
828
- await fs.rename(tempDir, skillzPath);
829
+ await fs.rename(tempDir, antigravitySkillsPath);
829
830
  }
830
831
  catch (error) {
831
832
  // Clean up temp directory on error
@@ -839,15 +840,3 @@ async function propagateSkillsForSkillz(projectRoot, options) {
839
840
  }
840
841
  return [];
841
842
  }
842
- /**
843
- * Builds MCP config for Skillz server.
844
- */
845
- function buildSkillzMcpConfig(projectRoot) {
846
- void projectRoot;
847
- return {
848
- [constants_1.SKILLZ_MCP_SERVER_NAME]: {
849
- command: 'uvx',
850
- args: ['skillz@latest', constants_1.SKILLZ_DIR],
851
- },
852
- };
853
- }
@@ -233,12 +233,12 @@ async function loadSingleConfiguration(projectRoot, configPath, localOnly) {
233
233
  * @param cliMcpStrategy MCP strategy from CLI
234
234
  * @returns Promise resolving to array of generated file paths
235
235
  */
236
- async function processHierarchicalConfigurations(agents, configurations, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true, skillsEnabled = true) {
236
+ async function processHierarchicalConfigurations(agents, configurations, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true) {
237
237
  const allGeneratedPaths = [];
238
238
  for (const config of configurations) {
239
239
  (0, constants_1.logVerboseInfo)(`Processing .ruler directory: ${config.rulerDir}`, verbose, dryRun);
240
240
  const rulerRoot = path.dirname(config.rulerDir);
241
- const paths = await applyConfigurationsToAgents(agents, config.concatenatedRules, config.rulerMcpJson, config.config, rulerRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup, skillsEnabled);
241
+ const paths = await applyConfigurationsToAgents(agents, config.concatenatedRules, config.rulerMcpJson, config.config, rulerRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
242
242
  const normalizedPaths = paths.map((p) => path.isAbsolute(p) ? p : path.join(rulerRoot, p));
243
243
  allGeneratedPaths.push(...normalizedPaths);
244
244
  }
@@ -256,42 +256,8 @@ async function processHierarchicalConfigurations(agents, configurations, verbose
256
256
  * @param cliMcpStrategy MCP strategy from CLI
257
257
  * @returns Promise resolving to array of generated file paths
258
258
  */
259
- async function processSingleConfiguration(agents, configuration, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true, skillsEnabled = true) {
260
- return await applyConfigurationsToAgents(agents, configuration.concatenatedRules, configuration.rulerMcpJson, configuration.config, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup, skillsEnabled);
261
- }
262
- /**
263
- * Adds Skillz MCP server to rulerMcpJson if skills exist and this agent needs it.
264
- * Returns augmented MCP config or original if no changes needed.
265
- */
266
- async function addSkillzMcpServerIfNeeded(rulerMcpJson, projectRoot, agent, verbose) {
267
- // Check if this agent supports MCP stdio but not native skills
268
- if (!agent.supportsMcpStdio?.() || agent.supportsNativeSkills?.()) {
269
- return rulerMcpJson;
270
- }
271
- // Check if .skillz directory exists
272
- try {
273
- const { SKILLZ_DIR } = await Promise.resolve().then(() => __importStar(require('../constants')));
274
- const skillzPath = path.join(projectRoot, SKILLZ_DIR);
275
- await fs_1.promises.access(skillzPath);
276
- // Skills exist, add Skillz MCP server
277
- const { buildSkillzMcpConfig } = await Promise.resolve().then(() => __importStar(require('./SkillsProcessor')));
278
- const skillzMcp = buildSkillzMcpConfig(projectRoot);
279
- // Initialize empty config if null
280
- const baseConfig = rulerMcpJson || { mcpServers: {} };
281
- const mcpServers = baseConfig.mcpServers || {};
282
- (0, constants_1.logVerbose)(`Adding Skillz MCP server to configuration for ${agent.getName()}`, verbose);
283
- return {
284
- ...baseConfig,
285
- mcpServers: {
286
- ...mcpServers,
287
- ...skillzMcp,
288
- },
289
- };
290
- }
291
- catch {
292
- // No .skillz directory, return original config
293
- return rulerMcpJson;
294
- }
259
+ async function processSingleConfiguration(agents, configuration, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true) {
260
+ return await applyConfigurationsToAgents(agents, configuration.concatenatedRules, configuration.rulerMcpJson, configuration.config, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
295
261
  }
296
262
  /**
297
263
  * Applies configurations to the selected agents (internal function).
@@ -304,16 +270,14 @@ async function addSkillzMcpServerIfNeeded(rulerMcpJson, projectRoot, agent, verb
304
270
  * @param dryRun Whether to perform a dry run
305
271
  * @returns Promise resolving to array of generated file paths
306
272
  */
307
- async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJson, config, projectRoot, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true, skillsEnabled = true) {
273
+ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJson, config, projectRoot, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true) {
308
274
  const generatedPaths = [];
309
275
  let agentsMdWritten = false;
310
276
  for (const agent of agents) {
311
277
  (0, constants_1.logInfo)(`Applying rules for ${agent.getName()}...`, dryRun);
312
278
  (0, constants_1.logVerbose)(`Processing agent: ${agent.getName()}`, verbose);
313
279
  const agentConfig = config.agentConfigs[agent.getIdentifier()];
314
- const agentRulerMcpJson = skillsEnabled && !dryRun
315
- ? await addSkillzMcpServerIfNeeded(rulerMcpJson, projectRoot, agent, verbose)
316
- : rulerMcpJson;
280
+ const agentRulerMcpJson = rulerMcpJson;
317
281
  // Collect output paths for .gitignore
318
282
  const outputPaths = (0, agent_utils_1.getAgentOutputPaths)(agent, projectRoot, agentConfig);
319
283
  (0, constants_1.logVerbose)(`Agent ${agent.getName()} output paths: ${outputPaths.join(', ')}`, verbose);
@@ -357,11 +321,11 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
357
321
  }
358
322
  }
359
323
  // Handle MCP configuration
360
- await handleMcpConfiguration(agent, agentConfig, config, agentRulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup, skillsEnabled);
324
+ await handleMcpConfiguration(agent, agentConfig, config, agentRulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
361
325
  }
362
326
  return generatedPaths;
363
327
  }
364
- async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true, skillsEnabled = true) {
328
+ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true) {
365
329
  if (!(0, capabilities_1.agentSupportsMcp)(agent)) {
366
330
  (0, constants_1.logVerbose)(`Agent ${agent.getName()} does not support MCP - skipping MCP configuration`, verbose);
367
331
  return;
@@ -371,41 +335,9 @@ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson,
371
335
  if (!dest || !mcpEnabledForAgent) {
372
336
  return;
373
337
  }
374
- let filteredMcpJson = rulerMcpJson
338
+ const filteredMcpJson = rulerMcpJson
375
339
  ? (0, capabilities_1.filterMcpConfigForAgent)(rulerMcpJson, agent)
376
340
  : null;
377
- // Add Skillz MCP server for agents that support stdio but not native skills
378
- // Only add if skills are enabled
379
- if (skillsEnabled &&
380
- agent.supportsMcpStdio?.() &&
381
- !agent.supportsNativeSkills?.()) {
382
- // Check if .skillz directory exists
383
- try {
384
- const { SKILLZ_DIR } = await Promise.resolve().then(() => __importStar(require('../constants')));
385
- const skillzPath = path.join(projectRoot, SKILLZ_DIR);
386
- await fs_1.promises.access(skillzPath);
387
- // Skills exist, add Skillz MCP server
388
- const { buildSkillzMcpConfig } = await Promise.resolve().then(() => __importStar(require('./SkillsProcessor')));
389
- const skillzMcp = buildSkillzMcpConfig(projectRoot);
390
- // Merge Skillz server into MCP config
391
- // Initialize empty config if null
392
- if (!filteredMcpJson) {
393
- filteredMcpJson = { mcpServers: {} };
394
- }
395
- const mcpServers = filteredMcpJson.mcpServers || {};
396
- filteredMcpJson = {
397
- ...filteredMcpJson,
398
- mcpServers: {
399
- ...mcpServers,
400
- ...skillzMcp,
401
- },
402
- };
403
- (0, constants_1.logVerboseInfo)(`Added Skillz MCP server for ${agent.getName()}`, verbose, dryRun);
404
- }
405
- catch {
406
- // No .skillz directory, skip adding Skillz server
407
- }
408
- }
409
341
  if (!filteredMcpJson) {
410
342
  (0, constants_1.logVerbose)(`No compatible MCP servers found for ${agent.getName()} - skipping MCP configuration`, verbose);
411
343
  return;
package/dist/lib.js CHANGED
@@ -100,7 +100,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
100
100
  await propagateSkills(nestedRoot, selectedAgents, skillsEnabledResolved, verbose, dryRun);
101
101
  }
102
102
  }
103
- generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup, skillsEnabledResolved);
103
+ generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
104
104
  }
105
105
  else {
106
106
  const singleConfig = await (0, apply_engine_1.loadSingleConfiguration)(projectRoot, configPath, localOnly);
@@ -117,7 +117,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
117
117
  const { propagateSkills } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
118
118
  await propagateSkills(projectRoot, selectedAgents, skillsEnabledResolved, verbose, dryRun);
119
119
  }
120
- generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup, skillsEnabledResolved);
120
+ generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
121
121
  }
122
122
  // Add skills-generated paths to gitignore if skills are enabled
123
123
  let allGeneratedPaths = generatedPaths;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intellectronica/ruler",
3
- "version": "0.3.25",
3
+ "version": "0.3.26",
4
4
  "description": "Ruler — apply the same rules to all coding agents",
5
5
  "main": "dist/lib.js",
6
6
  "scripts": {