From 669b711c66b417907a6880f5f7fe67363c78adb9 Mon Sep 17 00:00:00 2001 From: Edu Wass Date: Fri, 30 Jan 2026 19:44:04 +0100 Subject: [PATCH 1/2] feat: add project rules mapping --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++-- src/core/mappings.ts | 17 +++++++++++++ tests/linking.test.ts | 20 ++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 863afe7..b12288d 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,59 @@ Global home affects all projects. Project folder only affects the current direct `.agents/skills` → `~/.gemini/skills` -Project scope links only commands/hooks/skills into the project’s client folders (no AGENTS/CLAUDE/GEMINI rules). +Project scope links commands/hooks/skills and `rules/` into the project’s client folders. It does not link instruction files (`AGENTS.md`/`CLAUDE.md`/`GEMINI.md`). + +## Where it links (project scope) + +Commands: + +`.agents/commands` → `.claude/commands` + +`.agents/commands` → `.factory/commands` + +`.agents/commands` → `.codex/prompts` + +`.agents/commands` → `.cursor/commands` + +`.agents/commands` → `.opencode/commands` + +`.agents/commands` → `.gemini/commands` + +Hooks: + +`.agents/hooks` → `.claude/hooks` + +`.agents/hooks` → `.factory/hooks` + +Skills: + +`.agents/skills` → `.claude/skills` + +`.agents/skills` → `.factory/skills` + +`.agents/skills` → `.codex/skills` + +`.agents/skills` → `.cursor/skills` + +`.agents/skills` → `.opencode/skills` + +`.agents/skills` → `.gemini/skills` + +`.agents/skills` → `.github/skills` (GitHub Copilot) + +Rules: + +`.agents/rules` → `.claude/rules` (Claude) + +`.agents/rules` → `.cursor/rules` (Cursor) + +`.agents/rules` → `.github/instructions` (GitHub Copilot) + +Notes / limitations: + +- This is project-scope only (it never touches `~/.claude`, `~/.cursor`, or other global rule locations). +- Cursor rules are typically `.mdc` files; sharing one folder across tools is convenient, but you may want to keep tool-specific formatting in mind. +- GitHub Copilot’s path-scoped instructions expect `*.instructions.md` files with frontmatter like `applyTo`. ## Development @@ -109,7 +161,7 @@ bun run build - Skills require a valid `SKILL.md` with `name` + `description` frontmatter. - Claude prompt precedence: if `.agents/CLAUDE.md` exists, it links to `.claude/CLAUDE.md`. Otherwise `.agents/AGENTS.md` is used. After adding or removing `.agents/CLAUDE.md`, re-run dotagents and apply/repair links to update the symlink. Factory/Codex always link to `.agents/AGENTS.md`. - Gemini context file precedence: if `.agents/GEMINI.md` exists, it links to `.gemini/GEMINI.md`. Otherwise `.agents/AGENTS.md` is used. After adding or removing `.agents/GEMINI.md`, re-run dotagents and apply/repair links to update the symlink. -- Project scope creates `.agents` plus client folders for commands/hooks/skills only. Rule files (`AGENTS.md`/`CLAUDE.md`/`GEMINI.md`) are left to the repo root so you can manage them explicitly. +- Project scope creates `.agents` plus client folders for commands/hooks/skills and `rules/`. Instruction files (`AGENTS.md`/`CLAUDE.md`/`GEMINI.md`) are left to the repo root so you can manage them explicitly. - Backups are stored under `.agents/backup/` and can be restored via “Undo last change.” ## License diff --git a/src/core/mappings.ts b/src/core/mappings.ts index e2d1afa..1ff23a0 100644 --- a/src/core/mappings.ts +++ b/src/core/mappings.ts @@ -59,6 +59,23 @@ export async function getMappings(opts: MappingOptions): Promise { } } + if (opts.scope === 'project') { + const ruleTargets = [ + clients.has('claude') ? path.join(roots.claudeRoot, 'rules') : null, + clients.has('cursor') ? path.join(roots.cursorRoot, 'rules') : null, + clients.has('github') ? path.join(roots.githubRoot, 'instructions') : null, + ].filter(Boolean) as string[]; + + if (ruleTargets.length > 0) { + mappings.push({ + name: 'rules', + source: path.join(canonical, 'rules'), + targets: ruleTargets, + kind: 'dir', + }); + } + } + mappings.push( { name: 'commands', diff --git a/tests/linking.test.ts b/tests/linking.test.ts index 923c655..c8e55e5 100644 --- a/tests/linking.test.ts +++ b/tests/linking.test.ts @@ -169,6 +169,26 @@ test('project scope does not link AGENTS/CLAUDE files', async () => { } }); +test('project scope links .agents/rules to supported tool rule folders', async () => { + const home = await makeTempDir('dotagents-home-'); + const project = await makeTempDir('dotagents-project-'); + + const plan = await buildLinkPlan({ scope: 'project', homeDir: home, projectRoot: project }); + const backup = await createBackupSession({ canonicalRoot: path.join(project, '.agents'), scope: 'project', operation: 'test' }); + const result = await applyLinkPlan(plan, { backup }); + await finalizeBackup(backup); + expect(result.applied).toBeGreaterThan(0); + + const rules = path.join(project, '.agents', 'rules'); + const cursorRules = path.join(project, '.cursor', 'rules'); + const claudeRules = path.join(project, '.claude', 'rules'); + const githubInstructions = path.join(project, '.github', 'instructions'); + + expect(await readLinkTarget(cursorRules)).toBe(rules); + expect(await readLinkTarget(claudeRules)).toBe(rules); + expect(await readLinkTarget(githubInstructions)).toBe(rules); +}); + test('github skills link to .github/skills in project scope', async () => { const home = await makeTempDir('dotagents-home-'); const project = await makeTempDir('dotagents-project-'); From 7130f26e3689d693121ec03228809a77bf9dcc0f Mon Sep 17 00:00:00 2001 From: Edu Wass Date: Fri, 30 Jan 2026 19:55:53 +0100 Subject: [PATCH 2/2] docs: clarify rules formats --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b12288d..7050027 100644 --- a/README.md +++ b/README.md @@ -128,8 +128,11 @@ Rules: Notes / limitations: - This is project-scope only (it never touches `~/.claude`, `~/.cursor`, or other global rule locations). -- Cursor rules are typically `.mdc` files; sharing one folder across tools is convenient, but you may want to keep tool-specific formatting in mind. -- GitHub Copilot’s path-scoped instructions expect `*.instructions.md` files with frontmatter like `applyTo`. +- Tools use different rule formats. Keeping a shared `.agents/rules` folder is convenient, but you may need tool-specific files for path targeting: + - Claude rules are typically Markdown with YAML frontmatter like `paths: src/api/**/*.ts` (you can verify what’s active via `/memory` in Claude Code). + - Cursor rules are typically `.mdc` files with fields like `globs`. + - GitHub Copilot’s `.github/instructions` expects `*.instructions.md` files with frontmatter like `applyTo`. +- A practical approach is to colocate multiple formats side-by-side (e.g. `backend.md`, `backend.mdc`, `backend.instructions.md`) and let each tool ignore what it doesn’t understand. ## Development