@bonesofspring/ai-rules 0.2.24 → 0.2.25

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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Quad-install Next: shared root `AGENTS.md`
6
+
7
+ - Cursor, Claude, Mavis, and OpenCode **next** presets now ship the **same** `REPO_AGENTS.md` (presence-based load + per-tool pipeline caveat + local overlay). Last `init` still overwrites the file; content no longer depends on which tool ran last.
8
+ - `clean <tool>` leaves root `AGENTS.md` when another tool install is still present.
9
+ - `init multi --preset next` installs all four platforms in one command (Mavis/OpenCode skipped on stacks they have not released).
10
+ - Consumers: `npx @bonesofspring/ai-rules init multi --preset next` on Next repos.
11
+
5
12
  ### OpenCode platform (experimental Next-only)
6
13
 
7
14
  - New platform **`opencode`**: `npx @bonesofspring/ai-rules init opencode --preset next` installs **`.opencode/**`** plus root `AGENTS.md` and merges MCP into **`opencode.json`**. `clean opencode` is manifest/hash-safe. The CLI never writes `~/.config/opencode/**`.
package/README.md CHANGED
@@ -6,10 +6,7 @@ Node 18+.
6
6
 
7
7
  ```bash
8
8
  # from the project root
9
- npx @bonesofspring/ai-rules init cursor --preset next
10
- npx @bonesofspring/ai-rules init claude --preset next
11
- npx @bonesofspring/ai-rules init mavis --preset next
12
- npx @bonesofspring/ai-rules init opencode --preset next
9
+ npx @bonesofspring/ai-rules init multi --preset next
13
10
  npx @bonesofspring/ai-rules clean cursor
14
11
  npx @bonesofspring/ai-rules clean mavis
15
12
  npx @bonesofspring/ai-rules clean opencode
@@ -38,7 +35,7 @@ If `.cursor` does not appear, check the command output for errors and confirm yo
38
35
  - optional dirs when present: `agents/`, `hooks/`, `skills/`, `team/`
39
36
  - Cursor root files: `hooks.json`, `BUGBOT.md`, `AGENTS.md`, `MCP.md`, `mcp.json`
40
37
  - Claude: `CLAUDE.md`, `MCP.md` under `.claude/`; project `.mcp.json` at repo root
41
- - **Both tools:** repo-root `AGENTS.md` (from preset `REPO_AGENTS.md`)
38
+ - **Shared root `AGENTS.md`:** removed only when no other tool install remains (Cursor, Claude, Mavis, or OpenCode markers still on disk)
42
39
 
43
40
  Any other files you added under `.cursor/` or `.claude/` (notes, local overrides, IDE state) are **left intact**. Older releases that deleted the whole tool directory are no longer the behavior.
44
41
 
@@ -60,7 +57,21 @@ Where things go on `init`:
60
57
 
61
58
  **Mavis (MiniMax Code, experimental Next-only):** `ai-rules init mavis --preset next` writes ai-rules-owned **`.mavis/**`** plus root `AGENTS.md`. MCP merges into **`.mavis/mcp.json`** only — the CLI never writes `~/.minimax/**`. `clean mavis` is manifest-owned: unchanged hashes are removed; modified files stay. See [`docs/MAVIS.md`](docs/MAVIS.md), [`presets/mavis/README.md`](presets/mavis/README.md), and [`docs/MAVIS-COMPATIBILITY.md`](docs/MAVIS-COMPATIBILITY.md).
62
59
 
63
- **OpenCode (experimental Next-only):** `ai-rules init opencode --preset next` writes native **`.opencode/**`** plus root `AGENTS.md` and merges MCP into **`opencode.json`**. `clean opencode` is manifest-owned. The CLI never writes `~/.config/opencode/**`. Last `init` wins on root `AGENTS.md` if several tools are installed. See [`docs/OPENCODE.md`](docs/OPENCODE.md), [`presets/opencode/README.md`](presets/opencode/README.md), and [`docs/OPENCODE-COMPATIBILITY.md`](docs/OPENCODE-COMPATIBILITY.md).
60
+ **OpenCode (experimental Next-only):** `ai-rules init opencode --preset next` writes native **`.opencode/**`** plus root `AGENTS.md` and merges MCP into **`opencode.json`**. `clean opencode` is manifest-owned. The CLI never writes `~/.config/opencode/**`. All four next platforms ship the **same** root `AGENTS.md` (last `init` still overwrites, content does not change). See [`docs/OPENCODE.md`](docs/OPENCODE.md), [`presets/opencode/README.md`](presets/opencode/README.md), and [`docs/OPENCODE-COMPATIBILITY.md`](docs/OPENCODE-COMPATIBILITY.md).
61
+
62
+ ### Multi-tool on one branch (Next)
63
+
64
+ Install all four from the app root (`init multi` is the one-shot), then commit the four trees plus root `AGENTS.md`. Living exceptions belong in **`.ai.local/`** (init never touches it).
65
+
66
+ ```bash
67
+ npx @bonesofspring/ai-rules init multi --preset next
68
+ ```
69
+
70
+ Per-tool: `init cursor|claude|mavis|opencode --preset next`. On stacks other than `next`, `init multi` still installs Cursor and Claude and **skips** Mavis/OpenCode until those platforms list the stack in `releasedStacks`.
71
+
72
+ **Shared:** stack rules (packaged per tool), root `AGENTS.md`, `.ai.local/` overlay.
73
+
74
+ **Not shared:** `/task` pipelines. Each tool writes `.tool/team/tasks/<slug>/` (`status.json` is not cross-tool). Cursor auto-chains via `hooks.json` / `subagentStop`. Claude ships `chain-team-phases.sh` without `hooks.json`. Mavis and OpenCode are semi-auto: `printf '{"status":"completed"}' | bash .tool/hooks/chain-team-phases.sh`. Mavis/OpenCode remain Next-only.
64
75
 
65
76
  Skills of note: `write-adr` (all stacks); `spec-authoring` (Generate/Bootstrap `docs/specs`); `mockup-review` (**next** / **nuxt** / **svelte** / **ios-swift** / **android-kotlin** — Figma mockup reviewer via agent `mockup-reviewer`); `ux-design` (**next** / **nuxt** / **svelte** / **ios-swift** / **android-kotlin** — behavioral UX via `task-analyst`, no agent); `react-performance` (**next only**); `vue-performance` (**nuxt only**); `svelte-performance` (**svelte only**). Optional command `/spec-start`. Living gotchas: `team/conventions.md`. Opt-in rule samples eval: `yarn check:rule-eval` (workflow `rule-eval.yml`; not part of `check:preset-structure`). Optional consumer specs check: `yarn check:product-specs` (WARN default; `--strict` FAIL).
66
77
 
package/bin/cli.js CHANGED
@@ -11,6 +11,9 @@ const { cmdInitOpencode, cmdCleanOpencode } = require('./opencode-install');
11
11
  const PRESET_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
12
12
  const DEFAULT_PRESET = 'next';
13
13
  const TOOLS = new Set(['cursor', 'claude', 'mavis', 'opencode']);
14
+ /** Meta-target: `init multi` runs every platform that has released the preset. */
15
+ const INIT_TARGETS = new Set([...TOOLS, 'multi']);
16
+ const MULTI_INSTALL_ORDER = ['cursor', 'claude', 'mavis', 'opencode'];
14
17
 
15
18
  const PRESETS = {
16
19
  cursor: {
@@ -53,8 +56,8 @@ function printHelp() {
53
56
  console.log(`@bonesofspring/ai-rules
54
57
 
55
58
  Usage:
56
- ai-rules init <cursor|claude|mavis|opencode> [--preset <name>]
57
- ai-rules init <cursor|claude|mavis|opencode> <preset-name>
59
+ ai-rules init <cursor|claude|mavis|opencode|multi> [--preset <name>]
60
+ ai-rules init <cursor|claude|mavis|opencode|multi> <preset-name>
58
61
  ai-rules clean <cursor|claude|mavis|opencode> [--cwd <dir>]
59
62
 
60
63
  Options:
@@ -70,9 +73,10 @@ Notes:
70
73
  Claude init copies rules, commands, skills, agents, hooks, team, CLAUDE.md, MCP.md, and mcp.json → .mcp.json (project root).
71
74
  Mavis init copies into .mavis/ (ai-rules-owned) plus REPO_AGENTS.md → <cwd>/AGENTS.md; MCP merges into .mavis/mcp.json only (never ~/.minimax/**).
72
75
  OpenCode init copies into .opencode/ plus REPO_AGENTS.md → <cwd>/AGENTS.md; MCP merges into <cwd>/opencode.json (never ~/.config/opencode/**).
73
- All init targets also copy REPO_AGENTS.md → <cwd>/AGENTS.md (repo-root cross-tool agents file; overwrite).
76
+ All init targets also copy REPO_AGENTS.md → <cwd>/AGENTS.md (repo-root cross-tool agents file; overwrite; all next platforms ship the same file).
77
+ init multi installs every platform that has released the preset (cursor, claude, plus mavis/opencode when listed in releasedStacks). Not a clean target.
74
78
  When <cwd>/docs/specs/ is absent, init also seeds INDEX.md stub + _templates/* from package assets (never overwrites an existing INDEX).
75
- clean removes tool dirs/files and <cwd>/AGENTS.md (shared across tools — re-init the other tool to restore).
79
+ clean removes tool dirs/files. Shared <cwd>/AGENTS.md is removed only when no other tool install remains.
76
80
  Command forms: "init cursor --preset next", "init cursor next", "--preset next init cursor", "cursor init --preset next".
77
81
 
78
82
  Examples:
@@ -99,6 +103,7 @@ Examples:
99
103
  npx @bonesofspring/ai-rules init claude --preset php-laravel
100
104
  npx @bonesofspring/ai-rules init mavis --preset next
101
105
  npx @bonesofspring/ai-rules init opencode --preset next
106
+ npx @bonesofspring/ai-rules init multi --preset next
102
107
  npx @bonesofspring/ai-rules clean mavis
103
108
  npx @bonesofspring/ai-rules clean opencode
104
109
  npx @bonesofspring/ai-rules clean cursor
@@ -158,7 +163,7 @@ function parseArgs(argv) {
158
163
  }
159
164
 
160
165
  /**
161
- * Supports: init cursor, cursor init, init cursor next (positional preset).
166
+ * Supports: init cursor, cursor init, init cursor next (positional preset), init multi.
162
167
  */
163
168
  function normalizeInitClean(parsed) {
164
169
  const positional = [...parsed._];
@@ -166,11 +171,11 @@ function normalizeInitClean(parsed) {
166
171
  let tool;
167
172
  let presetFromPositional;
168
173
 
169
- if (positional.length >= 2 && TOOLS.has(positional[0]) && positional[1] === 'init') {
174
+ if (positional.length >= 2 && INIT_TARGETS.has(positional[0]) && positional[1] === 'init') {
170
175
  command = 'init';
171
176
  tool = positional[0];
172
177
  presetFromPositional = positional[2];
173
- } else if (positional.length >= 2 && positional[0] === 'init' && TOOLS.has(positional[1])) {
178
+ } else if (positional.length >= 2 && positional[0] === 'init' && INIT_TARGETS.has(positional[1])) {
174
179
  command = 'init';
175
180
  tool = positional[1];
176
181
  presetFromPositional = positional[2];
@@ -391,6 +396,23 @@ function removeFileIfExists(filePath) {
391
396
  }
392
397
  }
393
398
 
399
+ /** Markers that mean a tool install is still present (directory leftovers do not count). */
400
+ const TOOL_INSTALL_MARKERS = {
401
+ '.cursor': ['.cursor/AGENTS.md', '.cursor/hooks.json', '.cursor/rules'],
402
+ '.claude': ['.claude/CLAUDE.md', '.claude/rules'],
403
+ '.mavis': ['.mavis/.ai-rules-install.json', '.mavis/AGENTS.md'],
404
+ '.opencode': ['.opencode/.ai-rules-install.json', '.opencode/AGENTS.md'],
405
+ };
406
+
407
+ function otherToolInstallPresent(cwd, exceptRoot) {
408
+ return Object.entries(TOOL_INSTALL_MARKERS).some(([root, markers]) => {
409
+ if (root === exceptRoot) {
410
+ return false;
411
+ }
412
+ return markers.some((rel) => fs.existsSync(path.join(cwd, rel)));
413
+ });
414
+ }
415
+
394
416
  function listPresetNames(presetsRoot) {
395
417
  if (!fs.existsSync(presetsRoot)) {
396
418
  return [];
@@ -491,6 +513,53 @@ function resolvePresetName(tool, preset, packageRoot) {
491
513
  return { name, base, presetsRoot };
492
514
  }
493
515
 
516
+ function loadReleasedStacks(platform) {
517
+ if (platform === 'cursor' || platform === 'claude') {
518
+ return null;
519
+ }
520
+ const contractPath = path.join(getPackageRoot(), 'presets', platform, 'platform-contract.json');
521
+ if (!fs.existsSync(contractPath)) {
522
+ return [];
523
+ }
524
+ try {
525
+ const contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
526
+ return Array.isArray(contract.releasedStacks) ? contract.releasedStacks : [];
527
+ } catch {
528
+ return [];
529
+ }
530
+ }
531
+
532
+ function cmdInitMulti(preset, cwdOption) {
533
+ const presetName = preset === undefined || preset === '' ? DEFAULT_PRESET : preset;
534
+ const invalid = validatePresetName(presetName);
535
+ if (invalid) {
536
+ console.error(invalid);
537
+ process.exit(1);
538
+ }
539
+
540
+ const installed = [];
541
+ const skipped = [];
542
+ for (const tool of MULTI_INSTALL_ORDER) {
543
+ const released = loadReleasedStacks(tool);
544
+ if (released && released.length > 0 && !released.includes(presetName)) {
545
+ skipped.push(tool);
546
+ console.log(
547
+ `Skipping ${tool}: preset "${presetName}" is not released yet (released: ${released.join(', ')})`,
548
+ );
549
+ continue;
550
+ }
551
+ console.log(`\n=== init ${tool} --preset ${presetName} ===`);
552
+ cmdInit(tool, presetName, cwdOption);
553
+ installed.push(tool);
554
+ }
555
+ if (installed.length === 0) {
556
+ console.error(`multi: no platforms installed for preset "${presetName}".`);
557
+ process.exit(1);
558
+ }
559
+ const skipNote = skipped.length > 0 ? `; skipped ${skipped.join(', ')}` : '';
560
+ console.log(`\nDone. multi installed ${installed.join(', ')}${skipNote}`);
561
+ }
562
+
494
563
  function cmdInit(tool, preset, cwdOption) {
495
564
  if (tool === 'mavis') {
496
565
  cmdInitMavis({
@@ -701,14 +770,14 @@ function cmdClean(tool, cwdOption) {
701
770
  if (tool === 'mavis') {
702
771
  cmdCleanMavis({
703
772
  cwdOption,
704
- helpers: { resolveTargetCwd },
773
+ helpers: { resolveTargetCwd, otherToolInstallPresent },
705
774
  });
706
775
  return;
707
776
  }
708
777
  if (tool === 'opencode') {
709
778
  cmdCleanOpencode({
710
779
  cwdOption,
711
- helpers: { resolveTargetCwd },
780
+ helpers: { resolveTargetCwd, otherToolInstallPresent },
712
781
  });
713
782
  return;
714
783
  }
@@ -751,6 +820,10 @@ function cmdClean(tool, cwdOption) {
751
820
  }
752
821
 
753
822
  for (const destRel of Object.values(cfg.repoRootFiles || {})) {
823
+ if (destRel === 'AGENTS.md' && otherToolInstallPresent(cwd, toolRoot)) {
824
+ console.log('Kept shared AGENTS.md (another tool install is still present)');
825
+ continue;
826
+ }
754
827
  removeFileIfExists(path.join(cwd, destRel));
755
828
  removedParts.push(destRel);
756
829
  }
@@ -783,14 +856,24 @@ function main() {
783
856
  const { command, tool, preset } = normalizeInitClean(parsed);
784
857
 
785
858
  if (command === 'init') {
786
- if (!tool || !TOOLS.has(tool)) {
787
- console.error('Missing or invalid tool. Use: init cursor|claude|mavis|opencode [--preset next]');
859
+ if (!tool || !INIT_TARGETS.has(tool)) {
860
+ console.error(
861
+ 'Missing or invalid tool. Use: init cursor|claude|mavis|opencode|multi [--preset next]',
862
+ );
788
863
  process.exit(1);
789
864
  }
865
+ if (tool === 'multi') {
866
+ cmdInitMulti(preset, parsed.cwd);
867
+ return;
868
+ }
790
869
  cmdInit(tool, preset, parsed.cwd);
791
870
  return;
792
871
  }
793
872
  if (command === 'clean') {
873
+ if (tool === 'multi') {
874
+ console.error('clean multi is not supported. Clean each tool: cursor, claude, mavis, opencode.');
875
+ process.exit(1);
876
+ }
794
877
  if (!tool || !TOOLS.has(tool)) {
795
878
  console.error('Missing or invalid tool. Use: clean cursor|claude|mavis|opencode');
796
879
  process.exit(1);
@@ -374,7 +374,7 @@ function removeEmptyDirs(dir) {
374
374
  }
375
375
 
376
376
  function cmdCleanMavis({ cwdOption, helpers }) {
377
- const { resolveTargetCwd } = helpers;
377
+ const { resolveTargetCwd, otherToolInstallPresent } = helpers;
378
378
  const cwd = resolveTargetCwd(cwdOption);
379
379
  const manifestPath = path.join(cwd, MANIFEST_REL);
380
380
  if (!fs.existsSync(manifestPath)) {
@@ -409,6 +409,10 @@ function cmdCleanMavis({ cwdOption, helpers }) {
409
409
  continue;
410
410
  }
411
411
  const current = sha256File(abs);
412
+ if (rel === 'AGENTS.md' && otherToolInstallPresent && otherToolInstallPresent(cwd, '.mavis')) {
413
+ console.log('Kept shared AGENTS.md (another tool install is still present)');
414
+ continue;
415
+ }
412
416
  if (current === installedHash) {
413
417
  fs.unlinkSync(abs);
414
418
  } else {
@@ -461,7 +461,7 @@ function removeEmptyDirs(dir) {
461
461
  }
462
462
 
463
463
  function cmdCleanOpencode({ cwdOption, helpers }) {
464
- const { resolveTargetCwd } = helpers;
464
+ const { resolveTargetCwd, otherToolInstallPresent } = helpers;
465
465
  const cwd = resolveTargetCwd(cwdOption);
466
466
  const manifestPath = path.join(cwd, MANIFEST_REL);
467
467
  if (!fs.existsSync(manifestPath)) {
@@ -496,6 +496,10 @@ function cmdCleanOpencode({ cwdOption, helpers }) {
496
496
  continue;
497
497
  }
498
498
  const current = sha256File(abs);
499
+ if (rel === 'AGENTS.md' && otherToolInstallPresent && otherToolInstallPresent(cwd, '.opencode')) {
500
+ console.log('Kept shared AGENTS.md (another tool install is still present)');
501
+ continue;
502
+ }
499
503
  if (current === installedHash) {
500
504
  fs.unlinkSync(abs);
501
505
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bonesofspring/ai-rules",
3
- "version": "0.2.24",
3
+ "version": "0.2.25",
4
4
  "description": "Presets of Cursor, Claude, Mavis, and OpenCode rules/commands for Revy Ross personal use",
5
5
  "license": "MIT",
6
6
  "author": "Revy Ross",
@@ -5,17 +5,30 @@ Cross-tool repo-root guide. Tool-specific maps stay under `.cursor/AGENTS.md`, `
5
5
  ## Cross-tool setup
6
6
 
7
7
  - Treat this file as the **shared** entry for any agent (Cursor, Claude Code, Mavis, OpenCode, or other).
8
+ - All four platforms ship **the same** root file. `init` overwrites it; content does not depend on which tool ran last.
8
9
  - Tool maps (agent-team tables, slash commands) live in `.cursor/AGENTS.md` / `.claude/CLAUDE.md` / `.mavis/AGENTS.md` / `.opencode/AGENTS.md` — use them when that tool is installed.
9
10
  - Install:
10
11
 
11
12
  ```bash
12
- npx @bonesofspring/ai-rules init cursor --preset next
13
- npx @bonesofspring/ai-rules init claude --preset next
14
- npx @bonesofspring/ai-rules init mavis --preset next
15
- npx @bonesofspring/ai-rules init opencode --preset next
13
+ npx @bonesofspring/ai-rules init multi --preset next
16
14
  ```
17
15
 
18
- `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`). Living gotchas belong in `team/conventions.md`, not here.
16
+ Per-tool: `init cursor|claude|mavis|opencode --preset next`. `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`). `clean` of one tool leaves this file if another tool install remains. Living gotchas belong in `team/conventions.md` and `.ai.local/conventions.md`, not here.
17
+
18
+ ## Presence-based load
19
+
20
+ When the tree exists, read the tool map, then the essential rules. Do not preload the full catalog.
21
+
22
+ - If `.cursor/` exists: read `.cursor/AGENTS.md`.
23
+ - If `.claude/` exists: read `.claude/CLAUDE.md`.
24
+ - If `.mavis/` exists: read `.mavis/AGENTS.md`, then `.mavis/rules/next-app-core.md`, `.mavis/rules/package-manager.md`, `.mavis/rules/code-quality-and-refactoring.md`, `.mavis/rules/ai-local-overlay.md`.
25
+ - If `.opencode/` exists: read `.opencode/AGENTS.md`, then `.opencode/rules/next-app-core.md`, `.opencode/rules/package-manager.md`, `.opencode/rules/code-quality-and-refactoring.md`, `.opencode/rules/ai-local-overlay.md`.
26
+
27
+ Mavis has no native rule discovery without those root paths. OpenCode has no `alwaysApply` engine — the four `.opencode/rules/*.md` files above are the always-on set.
28
+
29
+ ## Pipelines are per-tool
30
+
31
+ `/task` slug, `status.json`, and `metrics.json` live under `.tool/team/tasks/<slug>/`. They are **not** shared across Cursor, Claude, Mavis, and OpenCode.
19
32
 
20
33
  ## Commands (test / lint / build)
21
34
 
@@ -51,3 +64,11 @@ Skills: `.cursor/skills/`, `.claude/skills/`, `.mavis/skills/`, or `.opencode/sk
51
64
  ## Living conventions
52
65
 
53
66
  Gotchas, local patterns, and team decisions: **`.cursor/team/conventions.md`**, **`.claude/team/conventions.md`**, **`.mavis/team/conventions.md`**, and/or **`.opencode/team/conventions.md`** (fill after init; not overwritten on every dogfood sync when already present).
67
+
68
+ ## Local overlay (`.ai.local/`) — MANDATORY
69
+
70
+ A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in monorepos. **All agents MUST read and apply it on every turn.** Rules there override preset rules; in conflicts, the local rule wins. `override: kill <preset-rule-name>` drops the named preset rule from the agent's context entirely.
71
+
72
+ Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`.
73
+
74
+ Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule (always-on for Cursor, on-demand for Claude) is the mechanism; this `MANDATORY` section is the reinforcement.
@@ -5,17 +5,30 @@ Cross-tool repo-root guide. Tool-specific maps stay under `.cursor/AGENTS.md`, `
5
5
  ## Cross-tool setup
6
6
 
7
7
  - Treat this file as the **shared** entry for any agent (Cursor, Claude Code, Mavis, OpenCode, or other).
8
+ - All four platforms ship **the same** root file. `init` overwrites it; content does not depend on which tool ran last.
8
9
  - Tool maps (agent-team tables, slash commands) live in `.cursor/AGENTS.md` / `.claude/CLAUDE.md` / `.mavis/AGENTS.md` / `.opencode/AGENTS.md` — use them when that tool is installed.
9
10
  - Install:
10
11
 
11
12
  ```bash
12
- npx @bonesofspring/ai-rules init cursor --preset next
13
- npx @bonesofspring/ai-rules init claude --preset next
14
- npx @bonesofspring/ai-rules init mavis --preset next
15
- npx @bonesofspring/ai-rules init opencode --preset next
13
+ npx @bonesofspring/ai-rules init multi --preset next
16
14
  ```
17
15
 
18
- `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`). Living gotchas belong in `team/conventions.md`, not here.
16
+ Per-tool: `init cursor|claude|mavis|opencode --preset next`. `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`). `clean` of one tool leaves this file if another tool install remains. Living gotchas belong in `team/conventions.md` and `.ai.local/conventions.md`, not here.
17
+
18
+ ## Presence-based load
19
+
20
+ When the tree exists, read the tool map, then the essential rules. Do not preload the full catalog.
21
+
22
+ - If `.cursor/` exists: read `.cursor/AGENTS.md`.
23
+ - If `.claude/` exists: read `.claude/CLAUDE.md`.
24
+ - If `.mavis/` exists: read `.mavis/AGENTS.md`, then `.mavis/rules/next-app-core.md`, `.mavis/rules/package-manager.md`, `.mavis/rules/code-quality-and-refactoring.md`, `.mavis/rules/ai-local-overlay.md`.
25
+ - If `.opencode/` exists: read `.opencode/AGENTS.md`, then `.opencode/rules/next-app-core.md`, `.opencode/rules/package-manager.md`, `.opencode/rules/code-quality-and-refactoring.md`, `.opencode/rules/ai-local-overlay.md`.
26
+
27
+ Mavis has no native rule discovery without those root paths. OpenCode has no `alwaysApply` engine — the four `.opencode/rules/*.md` files above are the always-on set.
28
+
29
+ ## Pipelines are per-tool
30
+
31
+ `/task` slug, `status.json`, and `metrics.json` live under `.tool/team/tasks/<slug>/`. They are **not** shared across Cursor, Claude, Mavis, and OpenCode.
19
32
 
20
33
  ## Commands (test / lint / build)
21
34
 
@@ -5,6 +5,7 @@ under `.mavis/skills/**`. This file is ai-rules-owned (`.mavis/AGENTS.md`),
5
5
  not a MiniMax-reserved filename.
6
6
 
7
7
  Root `AGENTS.md` is the compatibility floor. Read it first, then this file.
8
+ Do not write `~/.minimax/**`.
8
9
 
9
10
  ## How to load
10
11
 
@@ -1,47 +1,38 @@
1
1
  # Next.js — agent instructions
2
2
 
3
- Cross-tool repo-root guide. Tool-specific maps stay under `.cursor/AGENTS.md`,
4
- `.claude/CLAUDE.md`, `.mavis/AGENTS.md`, and `.opencode/AGENTS.md`.
5
-
6
- **.mavis/** is an ai-rules-owned namespace, not a MiniMax-native discovery path.
7
- When this Mavis preset is installed, read `.mavis/AGENTS.md` on every turn.
8
- Do not write `~/.minimax/**`. Do not mutate
9
- `.mavis/team/tasks/<slug>/status.json` or `metrics.json` — the chain runner
10
- owns those files.
3
+ Cross-tool repo-root guide. Tool-specific maps stay under `.cursor/AGENTS.md`, `.claude/CLAUDE.md`, `.mavis/AGENTS.md`, and `.opencode/AGENTS.md`.
11
4
 
12
5
  ## Cross-tool setup
13
6
 
14
- - Treat this file as the **shared** entry for any agent (Cursor, Claude Code,
15
- Mavis / MiniMax Code, OpenCode, or other).
7
+ - Treat this file as the **shared** entry for any agent (Cursor, Claude Code, Mavis, OpenCode, or other).
8
+ - All four platforms ship **the same** root file. `init` overwrites it; content does not depend on which tool ran last.
9
+ - Tool maps (agent-team tables, slash commands) live in `.cursor/AGENTS.md` / `.claude/CLAUDE.md` / `.mavis/AGENTS.md` / `.opencode/AGENTS.md` — use them when that tool is installed.
16
10
  - Install:
17
11
 
18
12
  ```bash
19
- npx @bonesofspring/ai-rules init cursor --preset next
20
- npx @bonesofspring/ai-rules init claude --preset next
21
- npx @bonesofspring/ai-rules init mavis --preset next
22
- npx @bonesofspring/ai-rules init opencode --preset next
13
+ npx @bonesofspring/ai-rules init multi --preset next
23
14
  ```
24
15
 
25
- `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`).
26
- Living gotchas belong in `team/conventions.md`, not here.
16
+ Per-tool: `init cursor|claude|mavis|opencode --preset next`. `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`). `clean` of one tool leaves this file if another tool install remains. Living gotchas belong in `team/conventions.md` and `.ai.local/conventions.md`, not here.
17
+
18
+ ## Presence-based load
19
+
20
+ When the tree exists, read the tool map, then the essential rules. Do not preload the full catalog.
27
21
 
28
- ## Mavis compatibility entry
22
+ - If `.cursor/` exists: read `.cursor/AGENTS.md`.
23
+ - If `.claude/` exists: read `.claude/CLAUDE.md`.
24
+ - If `.mavis/` exists: read `.mavis/AGENTS.md`, then `.mavis/rules/next-app-core.md`, `.mavis/rules/package-manager.md`, `.mavis/rules/code-quality-and-refactoring.md`, `.mavis/rules/ai-local-overlay.md`.
25
+ - If `.opencode/` exists: read `.opencode/AGENTS.md`, then `.opencode/rules/next-app-core.md`, `.opencode/rules/package-manager.md`, `.opencode/rules/code-quality-and-refactoring.md`, `.opencode/rules/ai-local-overlay.md`.
29
26
 
30
- After install, also read:
27
+ Mavis has no native rule discovery without those root paths. OpenCode has no `alwaysApply` engine — the four `.opencode/rules/*.md` files above are the always-on set.
31
28
 
32
- - `.mavis/AGENTS.md` — Mavis load map, roles, and procedures
33
- - `.mavis/rules/next-app-core.md`
34
- - `.mavis/rules/package-manager.md`
35
- - `.mavis/rules/code-quality-and-refactoring.md`
36
- - `.mavis/rules/ai-local-overlay.md`
29
+ ## Pipelines are per-tool
37
30
 
38
- Launch roles with `mcode exec --file .mavis/agents/<role>.md`. Start work with
39
- the task procedure in `.mavis/commands/task.md`.
31
+ `/task` slug, `status.json`, and `metrics.json` live under `.tool/team/tasks/<slug>/`. They are **not** shared across Cursor, Claude, Mavis, and OpenCode.
40
32
 
41
33
  ## Commands (test / lint / build)
42
34
 
43
- Working directory for app scripts: **`app/`**. Detect the package manager from
44
- lockfile / `packageManager` (`package-manager` rule).
35
+ Working directory for app scripts: **`app/`**. Detect the package manager from lockfile / `packageManager` (`package-manager` rule).
45
36
 
46
37
  | Gate | Typical command |
47
38
  |------|-----------------|
@@ -50,14 +41,12 @@ lockfile / `packageManager` (`package-manager` rule).
50
41
  | Unit tests | project unit script under `app/` |
51
42
  | Build | project `build` under `app/` |
52
43
 
53
- After code edits: invoke **`post-change-lint`** (requestable). Full gate: agent
54
- `build-verifier`.
44
+ After code edits: invoke **`post-change-lint`** (requestable). Full gate: agent `build-verifier`.
55
45
 
56
46
  ## Security basics
57
47
 
58
48
  - Do not commit secrets (`.env`, tokens, credentials).
59
- - Review destructive git (`reset --hard`, force-push) before running; respect
60
- shell hooks.
49
+ - Review destructive git (`reset --hard`, force-push) before running; respect shell hooks.
61
50
  - Do not weaken CI or skip hooks unless the user explicitly asks.
62
51
 
63
52
  ## Tool entry points
@@ -65,7 +54,7 @@ After code edits: invoke **`post-change-lint`** (requestable). Full gate: agent
65
54
  | Tool | Map |
66
55
  |------|-----|
67
56
  | Cursor | `.cursor/AGENTS.md` (optional if Cursor not installed) |
68
- | Claude Code | `.claude/CLAUDE.md` (optional if Claude Code not installed) |
57
+ | Claude Code | `.claude/CLAUDE.md` (optional if Claude not installed) |
69
58
  | Mavis | `.mavis/AGENTS.md` (optional if Mavis not installed) |
70
59
  | OpenCode | `.opencode/AGENTS.md` (optional if OpenCode not installed) |
71
60
 
@@ -74,23 +63,12 @@ Skills: `.cursor/skills/`, `.claude/skills/`, `.mavis/skills/`, or `.opencode/sk
74
63
 
75
64
  ## Living conventions
76
65
 
77
- Gotchas, local patterns, and team decisions:
78
- **`.cursor/team/conventions.md`**, **`.claude/team/conventions.md`**,
79
- **`.mavis/team/conventions.md`**, and/or **`.opencode/team/conventions.md`**
80
- (fill after init; not overwritten on every dogfood sync when already present).
66
+ Gotchas, local patterns, and team decisions: **`.cursor/team/conventions.md`**, **`.claude/team/conventions.md`**, **`.mavis/team/conventions.md`**, and/or **`.opencode/team/conventions.md`** (fill after init; not overwritten on every dogfood sync when already present).
81
67
 
82
68
  ## Local overlay (`.ai.local/`) — MANDATORY
83
69
 
84
- A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in
85
- monorepos. **All agents MUST read and apply it on every turn.** Rules there
86
- override preset rules; in conflicts, the local rule wins.
87
- `override: kill <preset-rule-name>` drops the named preset rule from the
88
- agent's context entirely.
70
+ A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in monorepos. **All agents MUST read and apply it on every turn.** Rules there override preset rules; in conflicts, the local rule wins. `override: kill <preset-rule-name>` drops the named preset rule from the agent's context entirely.
89
71
 
90
- Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with
91
- higher priority than preset rules. Living gotchas live in
92
- `.ai.local/conventions.md`.
72
+ Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`.
93
73
 
94
- Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules`
95
- package. The `ai-local-overlay` rule is the mechanism; this `MANDATORY`
96
- section is the reinforcement.
74
+ Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule (always-on for Cursor, on-demand for Claude) is the mechanism; this `MANDATORY` section is the reinforcement.
@@ -3,7 +3,7 @@
3
3
  "platform": "mavis",
4
4
  "stack": "next",
5
5
  "semanticSource": "cursor/next",
6
- "sourceRevision": "be606e26d6d0e3f27c2a753e4025925670bc42f6e41d53ec9efc47cdb3a7be7f",
6
+ "sourceRevision": "8d8f6a3ac169783aef7a31559b7c2e286fe15a9424c6957b54a3396fc347ac47",
7
7
  "entries": [
8
8
  {
9
9
  "source": "AGENTS.md",
@@ -33,9 +33,9 @@
33
33
  "source": "REPO_AGENTS.md",
34
34
  "target": "REPO_AGENTS.md",
35
35
  "category": "entry",
36
- "disposition": "transform",
36
+ "disposition": "copy",
37
37
  "loadMode": "root-entry",
38
- "reason": "Root AGENTS.md compatibility floor plus explicit .mavis/AGENTS.md pointer"
38
+ "reason": "Canonical cross-tool root AGENTS.md; identical for all platforms"
39
39
  },
40
40
  {
41
41
  "source": "agents/accessibility-reviewer.md",
@@ -1,48 +1,38 @@
1
1
  # Next.js — agent instructions
2
2
 
3
- Cross-tool repo-root guide. Tool-specific maps stay under `.cursor/AGENTS.md`,
4
- `.claude/CLAUDE.md`, `.mavis/AGENTS.md`, and `.opencode/AGENTS.md`.
5
-
6
- When this OpenCode preset is installed, read `.opencode/AGENTS.md` on every
7
- turn. Do not write `~/.config/opencode/**`. Do not mutate
8
- `.opencode/team/tasks/<slug>/status.json` or `metrics.json` — the chain
9
- runner owns those files.
3
+ Cross-tool repo-root guide. Tool-specific maps stay under `.cursor/AGENTS.md`, `.claude/CLAUDE.md`, `.mavis/AGENTS.md`, and `.opencode/AGENTS.md`.
10
4
 
11
5
  ## Cross-tool setup
12
6
 
13
- - Treat this file as the **shared** entry for any agent (Cursor, Claude Code,
14
- Mavis, OpenCode, or other).
7
+ - Treat this file as the **shared** entry for any agent (Cursor, Claude Code, Mavis, OpenCode, or other).
8
+ - All four platforms ship **the same** root file. `init` overwrites it; content does not depend on which tool ran last.
9
+ - Tool maps (agent-team tables, slash commands) live in `.cursor/AGENTS.md` / `.claude/CLAUDE.md` / `.mavis/AGENTS.md` / `.opencode/AGENTS.md` — use them when that tool is installed.
15
10
  - Install:
16
11
 
17
12
  ```bash
18
- npx @bonesofspring/ai-rules init cursor --preset next
19
- npx @bonesofspring/ai-rules init claude --preset next
20
- npx @bonesofspring/ai-rules init mavis --preset next
21
- npx @bonesofspring/ai-rules init opencode --preset next
13
+ npx @bonesofspring/ai-rules init multi --preset next
22
14
  ```
23
15
 
24
- `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`).
25
- Living gotchas belong in `team/conventions.md`, not here.
16
+ Per-tool: `init cursor|claude|mavis|opencode --preset next`. `init` overwrites this file from the preset (`REPO_AGENTS.md` → `AGENTS.md`). `clean` of one tool leaves this file if another tool install remains. Living gotchas belong in `team/conventions.md` and `.ai.local/conventions.md`, not here.
17
+
18
+ ## Presence-based load
19
+
20
+ When the tree exists, read the tool map, then the essential rules. Do not preload the full catalog.
26
21
 
27
- ## OpenCode load map
22
+ - If `.cursor/` exists: read `.cursor/AGENTS.md`.
23
+ - If `.claude/` exists: read `.claude/CLAUDE.md`.
24
+ - If `.mavis/` exists: read `.mavis/AGENTS.md`, then `.mavis/rules/next-app-core.md`, `.mavis/rules/package-manager.md`, `.mavis/rules/code-quality-and-refactoring.md`, `.mavis/rules/ai-local-overlay.md`.
25
+ - If `.opencode/` exists: read `.opencode/AGENTS.md`, then `.opencode/rules/next-app-core.md`, `.opencode/rules/package-manager.md`, `.opencode/rules/code-quality-and-refactoring.md`, `.opencode/rules/ai-local-overlay.md`.
28
26
 
29
- After install, also read:
27
+ Mavis has no native rule discovery without those root paths. OpenCode has no `alwaysApply` engine — the four `.opencode/rules/*.md` files above are the always-on set.
30
28
 
31
- - `.opencode/AGENTS.md` — OpenCode load map, roles, and procedures
32
- - `.opencode/rules/next-app-core.md`
33
- - `.opencode/rules/package-manager.md`
34
- - `.opencode/rules/code-quality-and-refactoring.md`
35
- - `.opencode/rules/ai-local-overlay.md`
29
+ ## Pipelines are per-tool
36
30
 
37
- Do **not** preload the full `.opencode/rules/` catalog. Native agents live in
38
- `.opencode/agents/`; skills in `.opencode/skills/`; slash commands in
39
- `.opencode/commands/` (`/task`). After a producer receipt run
40
- `bash .opencode/hooks/chain-team-phases.sh`.
31
+ `/task` slug, `status.json`, and `metrics.json` live under `.tool/team/tasks/<slug>/`. They are **not** shared across Cursor, Claude, Mavis, and OpenCode.
41
32
 
42
33
  ## Commands (test / lint / build)
43
34
 
44
- Working directory for app scripts: **`app/`**. Detect the package manager from
45
- lockfile / `packageManager` (`package-manager` rule).
35
+ Working directory for app scripts: **`app/`**. Detect the package manager from lockfile / `packageManager` (`package-manager` rule).
46
36
 
47
37
  | Gate | Typical command |
48
38
  |------|-----------------|
@@ -51,14 +41,12 @@ lockfile / `packageManager` (`package-manager` rule).
51
41
  | Unit tests | project unit script under `app/` |
52
42
  | Build | project `build` under `app/` |
53
43
 
54
- After code edits: invoke **`post-change-lint`** (requestable). Full gate: agent
55
- `build-verifier`.
44
+ After code edits: invoke **`post-change-lint`** (requestable). Full gate: agent `build-verifier`.
56
45
 
57
46
  ## Security basics
58
47
 
59
48
  - Do not commit secrets (`.env`, tokens, credentials).
60
- - Review destructive git (`reset --hard`, force-push) before running; respect
61
- shell hooks.
49
+ - Review destructive git (`reset --hard`, force-push) before running; respect shell hooks.
62
50
  - Do not weaken CI or skip hooks unless the user explicitly asks.
63
51
 
64
52
  ## Tool entry points
@@ -66,7 +54,7 @@ After code edits: invoke **`post-change-lint`** (requestable). Full gate: agent
66
54
  | Tool | Map |
67
55
  |------|-----|
68
56
  | Cursor | `.cursor/AGENTS.md` (optional if Cursor not installed) |
69
- | Claude Code | `.claude/CLAUDE.md` (optional if Claude Code not installed) |
57
+ | Claude Code | `.claude/CLAUDE.md` (optional if Claude not installed) |
70
58
  | Mavis | `.mavis/AGENTS.md` (optional if Mavis not installed) |
71
59
  | OpenCode | `.opencode/AGENTS.md` (optional if OpenCode not installed) |
72
60
 
@@ -75,23 +63,12 @@ Skills: `.cursor/skills/`, `.claude/skills/`, `.mavis/skills/`, or `.opencode/sk
75
63
 
76
64
  ## Living conventions
77
65
 
78
- Gotchas, local patterns, and team decisions:
79
- **`.cursor/team/conventions.md`**, **`.claude/team/conventions.md`**,
80
- **`.mavis/team/conventions.md`**, and/or **`.opencode/team/conventions.md`**
81
- (fill after init; not overwritten on every dogfood sync when already present).
66
+ Gotchas, local patterns, and team decisions: **`.cursor/team/conventions.md`**, **`.claude/team/conventions.md`**, **`.mavis/team/conventions.md`**, and/or **`.opencode/team/conventions.md`** (fill after init; not overwritten on every dogfood sync when already present).
82
67
 
83
68
  ## Local overlay (`.ai.local/`) — MANDATORY
84
69
 
85
- A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in
86
- monorepos. **All agents MUST read and apply it on every turn.** Rules there
87
- override preset rules; in conflicts, the local rule wins.
88
- `override: kill <preset-rule-name>` drops the named preset rule from the
89
- agent's context entirely.
70
+ A `.ai.local/` directory MAY exist at the repo root or at any nesting depth in monorepos. **All agents MUST read and apply it on every turn.** Rules there override preset rules; in conflicts, the local rule wins. `override: kill <preset-rule-name>` drops the named preset rule from the agent's context entirely.
90
71
 
91
- Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with
92
- higher priority than preset rules. Living gotchas live in
93
- `.ai.local/conventions.md`.
72
+ Plain markdown rules under `.ai.local/rules/*.md` are read by the agent with higher priority than preset rules. Living gotchas live in `.ai.local/conventions.md`.
94
73
 
95
- Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules`
96
- package. The `ai-local-overlay` rule is the mechanism; this `MANDATORY`
97
- section is the reinforcement.
74
+ Authoring guide: `docs/LOCAL-OVERLAY.md` in the `@bonesofspring/ai-rules` package. The `ai-local-overlay` rule (always-on for Cursor, on-demand for Claude) is the mechanism; this `MANDATORY` section is the reinforcement.
@@ -3,7 +3,7 @@
3
3
  "platform": "opencode",
4
4
  "stack": "next",
5
5
  "semanticSource": "cursor/next",
6
- "sourceRevision": "be606e26d6d0e3f27c2a753e4025925670bc42f6e41d53ec9efc47cdb3a7be7f",
6
+ "sourceRevision": "8d8f6a3ac169783aef7a31559b7c2e286fe15a9424c6957b54a3396fc347ac47",
7
7
  "entries": [
8
8
  {
9
9
  "source": "AGENTS.md",
@@ -33,9 +33,9 @@
33
33
  "source": "REPO_AGENTS.md",
34
34
  "target": "REPO_AGENTS.md",
35
35
  "category": "entry",
36
- "disposition": "transform",
36
+ "disposition": "copy",
37
37
  "loadMode": "root-entry",
38
- "reason": "Root AGENTS.md is OpenCode native always-on plus cross-tool pointers"
38
+ "reason": "Canonical cross-tool root AGENTS.md; identical for all platforms"
39
39
  },
40
40
  {
41
41
  "source": "agents/accessibility-reviewer.md",
@@ -122,7 +122,7 @@
122
122
  ".claude/team/fixtures/ux-design-standalone.json": "528aeb9db4c310d1b5e3eacae0ad39a4fd1dd49c04154b064e7027981488a07a",
123
123
  ".claude/team/tasks/.gitkeep": "aca85ed348a49b11d68188be6ab245b521e5a706bbe0fbca1a28abfdc7155893",
124
124
  ".mcp.json": "f68a14db68a491a982975a3e6cc985057072a68eebdcedf33d8ac2a4a3b284ca",
125
- "AGENTS.md": "8c90523299194b7796390550c66e7d3442daa385fe5647761deea05e4cab7dc3",
125
+ "AGENTS.md": "0eaef34cabb183f665f25bc85863cbd528967589f49e808a71196748f882a085",
126
126
  "docs/specs/INDEX.md": "cab59f2093e6aaa376246a56d53e4268cb59070a6b10e87a94895192c35f422d",
127
127
  "docs/specs/_templates/feature.md": "83c47b90334c555fb5144749837e2ddfe1cae5bb89031f885ba98671075d59e7",
128
128
  "docs/specs/_templates/page.md": "a668c584e28edd52afaf3f9f8f898a75e43cb82fa12822c7a016033441e12e54"
@@ -124,7 +124,7 @@
124
124
  ".cursor/team/fixtures/mockup-review-standalone.json": "edda49b1298e94f9a33496317e9f6ccbbb047659e044e05ba35669bfe800eda6",
125
125
  ".cursor/team/fixtures/ux-design-standalone.json": "528aeb9db4c310d1b5e3eacae0ad39a4fd1dd49c04154b064e7027981488a07a",
126
126
  ".cursor/team/tasks/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
127
- "AGENTS.md": "de61cddb2fb50d27150ba5427a9c445373d62fe6be136b9da07b130e6fe12c2e",
127
+ "AGENTS.md": "0eaef34cabb183f665f25bc85863cbd528967589f49e808a71196748f882a085",
128
128
  "docs/specs/INDEX.md": "cab59f2093e6aaa376246a56d53e4268cb59070a6b10e87a94895192c35f422d",
129
129
  "docs/specs/_templates/feature.md": "83c47b90334c555fb5144749837e2ddfe1cae5bb89031f885ba98671075d59e7",
130
130
  "docs/specs/_templates/page.md": "a668c584e28edd52afaf3f9f8f898a75e43cb82fa12822c7a016033441e12e54"
@@ -3,7 +3,7 @@
3
3
  "tool": "mavis",
4
4
  "preset": "next",
5
5
  "files": {
6
- ".mavis/AGENTS.md": "66e2d2528ee0e35118fbcd7e9542c2aeab9b47408803dd6bbd9b1ace1c7af57f",
6
+ ".mavis/AGENTS.md": "a7e41d4012a72d183e07f48f7d811b1f6e1373ceedac7a46bfe4066bae931294",
7
7
  ".mavis/MCP.md": "e224fc1d22001949a240a66004da1524939a2b81431425d60ed17167c01a9fdf",
8
8
  ".mavis/agents/README.md": "62aa541b25f260a4a0f932ee844752bf92c7279c2c72b6db1d1e2c84bc0fff16",
9
9
  ".mavis/agents/accessibility-reviewer.md": "1781f56dd6384c2b47f6148ae244f2ddf527f4e48ebf8fd8aae36d22db82903f",
@@ -117,7 +117,7 @@
117
117
  ".mavis/team/fixtures/mockup-review-standalone.json": "edda49b1298e94f9a33496317e9f6ccbbb047659e044e05ba35669bfe800eda6",
118
118
  ".mavis/team/fixtures/ux-design-standalone.json": "528aeb9db4c310d1b5e3eacae0ad39a4fd1dd49c04154b064e7027981488a07a",
119
119
  ".mavis/team/tasks/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
120
- "AGENTS.md": "98fb17139dd1e665cddc7e3d8ae75971b10e88ae36fbcf181897820b4ec5c426",
120
+ "AGENTS.md": "0eaef34cabb183f665f25bc85863cbd528967589f49e808a71196748f882a085",
121
121
  "docs/specs/INDEX.md": "cab59f2093e6aaa376246a56d53e4268cb59070a6b10e87a94895192c35f422d",
122
122
  "docs/specs/_templates/feature.md": "83c47b90334c555fb5144749837e2ddfe1cae5bb89031f885ba98671075d59e7",
123
123
  "docs/specs/_templates/page.md": "a668c584e28edd52afaf3f9f8f898a75e43cb82fa12822c7a016033441e12e54"
@@ -116,7 +116,7 @@
116
116
  ".opencode/team/fixtures/mockup-review-standalone.json": "edda49b1298e94f9a33496317e9f6ccbbb047659e044e05ba35669bfe800eda6",
117
117
  ".opencode/team/fixtures/ux-design-standalone.json": "528aeb9db4c310d1b5e3eacae0ad39a4fd1dd49c04154b064e7027981488a07a",
118
118
  ".opencode/team/tasks/.gitkeep": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
119
- "AGENTS.md": "2a301d7bb2565b2935d816a91dffe0fb837aeb1511857cde0eef4400394bcc48",
119
+ "AGENTS.md": "0eaef34cabb183f665f25bc85863cbd528967589f49e808a71196748f882a085",
120
120
  "docs/specs/INDEX.md": "cab59f2093e6aaa376246a56d53e4268cb59070a6b10e87a94895192c35f422d",
121
121
  "docs/specs/_templates/feature.md": "83c47b90334c555fb5144749837e2ddfe1cae5bb89031f885ba98671075d59e7",
122
122
  "docs/specs/_templates/page.md": "a668c584e28edd52afaf3f9f8f898a75e43cb82fa12822c7a016033441e12e54",
@@ -231,15 +231,15 @@ function main() {
231
231
 
232
232
  if (source === 'REPO_AGENTS.md') {
233
233
  const target = 'REPO_AGENTS.md';
234
- writeFile(target, buildRepoAgents(sourceText));
234
+ writeFile(target, sourceText);
235
235
  entries.push(
236
236
  entry({
237
237
  source,
238
238
  target,
239
239
  category: 'entry',
240
- disposition: 'transform',
240
+ disposition: 'copy',
241
241
  loadMode: 'root-entry',
242
- reason: 'Root AGENTS.md compatibility floor plus explicit .mavis/AGENTS.md pointer',
242
+ reason: 'Canonical cross-tool root AGENTS.md; identical for all platforms',
243
243
  sourceText,
244
244
  }),
245
245
  );
@@ -407,106 +407,6 @@ function dropLeadingHeading(text) {
407
407
  .replace(/^Short Cursor entry point\.[^\n]*\n+/, '');
408
408
  }
409
409
 
410
- function buildRepoAgents(_sourceText) {
411
- return `# Next.js — agent instructions
412
-
413
- Cross-tool repo-root guide. Tool-specific maps stay under \`.cursor/AGENTS.md\`,
414
- \`.claude/CLAUDE.md\`, \`.mavis/AGENTS.md\`, and \`.opencode/AGENTS.md\`.
415
-
416
- **.mavis/** is an ai-rules-owned namespace, not a MiniMax-native discovery path.
417
- When this Mavis preset is installed, read \`.mavis/AGENTS.md\` on every turn.
418
- Do not write \`~/.minimax/**\`. Do not mutate
419
- \`.mavis/team/tasks/<slug>/status.json\` or \`metrics.json\` — the chain runner
420
- owns those files.
421
-
422
- ## Cross-tool setup
423
-
424
- - Treat this file as the **shared** entry for any agent (Cursor, Claude Code,
425
- Mavis / MiniMax Code, OpenCode, or other).
426
- - Install:
427
-
428
- \`\`\`bash
429
- npx @bonesofspring/ai-rules init cursor --preset next
430
- npx @bonesofspring/ai-rules init claude --preset next
431
- npx @bonesofspring/ai-rules init mavis --preset next
432
- npx @bonesofspring/ai-rules init opencode --preset next
433
- \`\`\`
434
-
435
- \`init\` overwrites this file from the preset (\`REPO_AGENTS.md\` → \`AGENTS.md\`).
436
- Living gotchas belong in \`team/conventions.md\`, not here.
437
-
438
- ## Mavis compatibility entry
439
-
440
- After install, also read:
441
-
442
- - \`.mavis/AGENTS.md\` — Mavis load map, roles, and procedures
443
- - \`.mavis/rules/next-app-core.md\`
444
- - \`.mavis/rules/package-manager.md\`
445
- - \`.mavis/rules/code-quality-and-refactoring.md\`
446
- - \`.mavis/rules/ai-local-overlay.md\`
447
-
448
- Launch roles with \`mcode exec --file .mavis/agents/<role>.md\`. Start work with
449
- the task procedure in \`.mavis/commands/task.md\`.
450
-
451
- ## Commands (test / lint / build)
452
-
453
- Working directory for app scripts: **\`app/\`**. Detect the package manager from
454
- lockfile / \`packageManager\` (\`package-manager\` rule).
455
-
456
- | Gate | Typical command |
457
- |------|-----------------|
458
- | Lint JS | \`yarn lint:js\` (or project equivalent) from \`app/\` |
459
- | Lint CSS | \`yarn lint:css\` from \`app/\` |
460
- | Unit tests | project unit script under \`app/\` |
461
- | Build | project \`build\` under \`app/\` |
462
-
463
- After code edits: invoke **\`post-change-lint\`** (requestable). Full gate: agent
464
- \`build-verifier\`.
465
-
466
- ## Security basics
467
-
468
- - Do not commit secrets (\`.env\`, tokens, credentials).
469
- - Review destructive git (\`reset --hard\`, force-push) before running; respect
470
- shell hooks.
471
- - Do not weaken CI or skip hooks unless the user explicitly asks.
472
-
473
- ## Tool entry points
474
-
475
- | Tool | Map |
476
- |------|-----|
477
- | Cursor | \`.cursor/AGENTS.md\` (optional if Cursor not installed) |
478
- | Claude Code | \`.claude/CLAUDE.md\` (optional if Claude Code not installed) |
479
- | Mavis | \`.mavis/AGENTS.md\` (optional if Mavis not installed) |
480
- | OpenCode | \`.opencode/AGENTS.md\` (optional if OpenCode not installed) |
481
-
482
- Rules: \`.cursor/rules/\`, \`.claude/rules/\`, \`.mavis/rules/\`, or \`.opencode/rules/\`.
483
- Skills: \`.cursor/skills/\`, \`.claude/skills/\`, \`.mavis/skills/\`, or \`.opencode/skills/\`.
484
-
485
- ## Living conventions
486
-
487
- Gotchas, local patterns, and team decisions:
488
- **\`.cursor/team/conventions.md\`**, **\`.claude/team/conventions.md\`**,
489
- **\`.mavis/team/conventions.md\`**, and/or **\`.opencode/team/conventions.md\`**
490
- (fill after init; not overwritten on every dogfood sync when already present).
491
-
492
- ## Local overlay (\`.ai.local/\`) — MANDATORY
493
-
494
- A \`.ai.local/\` directory MAY exist at the repo root or at any nesting depth in
495
- monorepos. **All agents MUST read and apply it on every turn.** Rules there
496
- override preset rules; in conflicts, the local rule wins.
497
- \`override: kill <preset-rule-name>\` drops the named preset rule from the
498
- agent's context entirely.
499
-
500
- Plain markdown rules under \`.ai.local/rules/*.md\` are read by the agent with
501
- higher priority than preset rules. Living gotchas live in
502
- \`.ai.local/conventions.md\`.
503
-
504
- Authoring guide: \`docs/LOCAL-OVERLAY.md\` in the \`@bonesofspring/ai-rules\`
505
- package. The \`ai-local-overlay\` rule is the mechanism; this \`MANDATORY\`
506
- section is the reinforcement.
507
- `;
508
- }
509
-
510
410
  function stripInstallSection(body) {
511
411
  const index = body.search(/^## Install\r?\n/m);
512
412
  if (index < 0) {
@@ -535,6 +435,7 @@ under \`.mavis/skills/**\`. This file is ai-rules-owned (\`.mavis/AGENTS.md\`),
535
435
  not a MiniMax-reserved filename.
536
436
 
537
437
  Root \`AGENTS.md\` is the compatibility floor. Read it first, then this file.
438
+ Do not write \`~/.minimax/**\`.
538
439
 
539
440
  ## How to load
540
441
 
@@ -341,15 +341,15 @@ function main() {
341
341
 
342
342
  if (source === 'REPO_AGENTS.md') {
343
343
  const target = 'REPO_AGENTS.md';
344
- writeFile(target, buildRepoAgents());
344
+ writeFile(target, sourceText);
345
345
  entries.push(
346
346
  entry({
347
347
  source,
348
348
  target,
349
349
  category: 'entry',
350
- disposition: 'transform',
350
+ disposition: 'copy',
351
351
  loadMode: 'root-entry',
352
- reason: 'Root AGENTS.md is OpenCode native always-on plus cross-tool pointers',
352
+ reason: 'Canonical cross-tool root AGENTS.md; identical for all platforms',
353
353
  sourceText,
354
354
  }),
355
355
  );
@@ -541,107 +541,6 @@ function dropLeadingHeading(text) {
541
541
  .replace(/^Short Cursor entry point\.[^\n]*\n+/, '');
542
542
  }
543
543
 
544
- function buildRepoAgents() {
545
- return `# Next.js — agent instructions
546
-
547
- Cross-tool repo-root guide. Tool-specific maps stay under \`.cursor/AGENTS.md\`,
548
- \`.claude/CLAUDE.md\`, \`.mavis/AGENTS.md\`, and \`.opencode/AGENTS.md\`.
549
-
550
- When this OpenCode preset is installed, read \`.opencode/AGENTS.md\` on every
551
- turn. Do not write \`~/.config/opencode/**\`. Do not mutate
552
- \`.opencode/team/tasks/<slug>/status.json\` or \`metrics.json\` — the chain
553
- runner owns those files.
554
-
555
- ## Cross-tool setup
556
-
557
- - Treat this file as the **shared** entry for any agent (Cursor, Claude Code,
558
- Mavis, OpenCode, or other).
559
- - Install:
560
-
561
- \`\`\`bash
562
- npx @bonesofspring/ai-rules init cursor --preset next
563
- npx @bonesofspring/ai-rules init claude --preset next
564
- npx @bonesofspring/ai-rules init mavis --preset next
565
- npx @bonesofspring/ai-rules init opencode --preset next
566
- \`\`\`
567
-
568
- \`init\` overwrites this file from the preset (\`REPO_AGENTS.md\` → \`AGENTS.md\`).
569
- Living gotchas belong in \`team/conventions.md\`, not here.
570
-
571
- ## OpenCode load map
572
-
573
- After install, also read:
574
-
575
- - \`.opencode/AGENTS.md\` — OpenCode load map, roles, and procedures
576
- - \`.opencode/rules/next-app-core.md\`
577
- - \`.opencode/rules/package-manager.md\`
578
- - \`.opencode/rules/code-quality-and-refactoring.md\`
579
- - \`.opencode/rules/ai-local-overlay.md\`
580
-
581
- Do **not** preload the full \`.opencode/rules/\` catalog. Native agents live in
582
- \`.opencode/agents/\`; skills in \`.opencode/skills/\`; slash commands in
583
- \`.opencode/commands/\` (\`/task\`). After a producer receipt run
584
- \`bash .opencode/hooks/chain-team-phases.sh\`.
585
-
586
- ## Commands (test / lint / build)
587
-
588
- Working directory for app scripts: **\`app/\`**. Detect the package manager from
589
- lockfile / \`packageManager\` (\`package-manager\` rule).
590
-
591
- | Gate | Typical command |
592
- |------|-----------------|
593
- | Lint JS | \`yarn lint:js\` (or project equivalent) from \`app/\` |
594
- | Lint CSS | \`yarn lint:css\` from \`app/\` |
595
- | Unit tests | project unit script under \`app/\` |
596
- | Build | project \`build\` under \`app/\` |
597
-
598
- After code edits: invoke **\`post-change-lint\`** (requestable). Full gate: agent
599
- \`build-verifier\`.
600
-
601
- ## Security basics
602
-
603
- - Do not commit secrets (\`.env\`, tokens, credentials).
604
- - Review destructive git (\`reset --hard\`, force-push) before running; respect
605
- shell hooks.
606
- - Do not weaken CI or skip hooks unless the user explicitly asks.
607
-
608
- ## Tool entry points
609
-
610
- | Tool | Map |
611
- |------|-----|
612
- | Cursor | \`.cursor/AGENTS.md\` (optional if Cursor not installed) |
613
- | Claude Code | \`.claude/CLAUDE.md\` (optional if Claude Code not installed) |
614
- | Mavis | \`.mavis/AGENTS.md\` (optional if Mavis not installed) |
615
- | OpenCode | \`.opencode/AGENTS.md\` (optional if OpenCode not installed) |
616
-
617
- Rules: \`.cursor/rules/\`, \`.claude/rules/\`, \`.mavis/rules/\`, or \`.opencode/rules/\`.
618
- Skills: \`.cursor/skills/\`, \`.claude/skills/\`, \`.mavis/skills/\`, or \`.opencode/skills/\`.
619
-
620
- ## Living conventions
621
-
622
- Gotchas, local patterns, and team decisions:
623
- **\`.cursor/team/conventions.md\`**, **\`.claude/team/conventions.md\`**,
624
- **\`.mavis/team/conventions.md\`**, and/or **\`.opencode/team/conventions.md\`**
625
- (fill after init; not overwritten on every dogfood sync when already present).
626
-
627
- ## Local overlay (\`.ai.local/\`) — MANDATORY
628
-
629
- A \`.ai.local/\` directory MAY exist at the repo root or at any nesting depth in
630
- monorepos. **All agents MUST read and apply it on every turn.** Rules there
631
- override preset rules; in conflicts, the local rule wins.
632
- \`override: kill <preset-rule-name>\` drops the named preset rule from the
633
- agent's context entirely.
634
-
635
- Plain markdown rules under \`.ai.local/rules/*.md\` are read by the agent with
636
- higher priority than preset rules. Living gotchas live in
637
- \`.ai.local/conventions.md\`.
638
-
639
- Authoring guide: \`docs/LOCAL-OVERLAY.md\` in the \`@bonesofspring/ai-rules\`
640
- package. The \`ai-local-overlay\` rule is the mechanism; this \`MANDATORY\`
641
- section is the reinforcement.
642
- `;
643
- }
644
-
645
544
  function stripInstallSection(body) {
646
545
  const index = body.search(/^## Install\r?\n/m);
647
546
  if (index < 0) {
@@ -8,7 +8,7 @@ import fs from 'node:fs';
8
8
  import os from 'node:os';
9
9
  import path from 'node:path';
10
10
  import { fileURLToPath } from 'node:url';
11
- import { runInit, snapshotInstall } from './lib/cli-golden.mjs';
11
+ import { runInit, sha256File, snapshotInstall } from './lib/cli-golden.mjs';
12
12
 
13
13
  const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
14
14
  const packageDirectory = path.resolve(scriptDirectory, '..');
@@ -116,7 +116,7 @@ assert.equal(manifest.docsSeed.seeded, true);
116
116
  const existingAgents = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-mavis-agents-'));
117
117
  fs.writeFileSync(path.join(existingAgents, 'AGENTS.md'), '# consumer agents\n');
118
118
  runInit(cli, existingAgents, 'mavis', 'next');
119
- assert.match(fs.readFileSync(path.join(existingAgents, 'AGENTS.md'), 'utf8'), /Mavis compatibility entry/);
119
+ assert.match(fs.readFileSync(path.join(existingAgents, 'AGENTS.md'), 'utf8'), /Presence-based load/);
120
120
 
121
121
  const specsExist = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-mavis-specs-'));
122
122
  fs.mkdirSync(path.join(specsExist, 'docs', 'specs'), { recursive: true });
@@ -261,7 +261,7 @@ assert.equal(ocManifest.docsSeed.seeded, true);
261
261
  const ocAgents = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-opencode-agents-'));
262
262
  fs.writeFileSync(path.join(ocAgents, 'AGENTS.md'), '# consumer agents\n');
263
263
  runInit(cli, ocAgents, 'opencode', 'next');
264
- assert.match(fs.readFileSync(path.join(ocAgents, 'AGENTS.md'), 'utf8'), /OpenCode load map/);
264
+ assert.match(fs.readFileSync(path.join(ocAgents, 'AGENTS.md'), 'utf8'), /Presence-based load/);
265
265
 
266
266
  const ocSpecs = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-opencode-specs-'));
267
267
  fs.mkdirSync(path.join(ocSpecs, 'docs', 'specs'), { recursive: true });
@@ -341,6 +341,68 @@ if (!fs.existsSync(ocGoldenPath)) {
341
341
  assert.deepEqual(ocFiles, expectedOc.files, 'opencode/next golden drifted');
342
342
  }
343
343
 
344
+ const canonicalRepoAgents = fs.readFileSync(
345
+ path.join(packageDirectory, 'presets', 'cursor', 'next', 'REPO_AGENTS.md'),
346
+ 'utf8',
347
+ );
348
+ for (const platform of ['claude', 'mavis', 'opencode']) {
349
+ const other = fs.readFileSync(
350
+ path.join(packageDirectory, 'presets', platform, 'next', 'REPO_AGENTS.md'),
351
+ 'utf8',
352
+ );
353
+ assert.equal(other, canonicalRepoAgents, `${platform}/next/REPO_AGENTS.md must match cursor SoT`);
354
+ }
355
+
356
+ const lastInitHashes = [];
357
+ const lastInitDirs = [];
358
+ for (const tool of ['cursor', 'claude', 'mavis', 'opencode']) {
359
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), `ai-rules-last-init-${tool}-`));
360
+ lastInitDirs.push(dir);
361
+ runInit(cli, dir, tool, 'next');
362
+ lastInitHashes.push(sha256File(path.join(dir, 'AGENTS.md')));
363
+ assert.match(fs.readFileSync(path.join(dir, 'AGENTS.md'), 'utf8'), /Presence-based load/);
364
+ assert.match(fs.readFileSync(path.join(dir, 'AGENTS.md'), 'utf8'), /Pipelines are per-tool/);
365
+ }
366
+ assert.equal(new Set(lastInitHashes).size, 1, 'root AGENTS.md must be identical after any last init');
367
+
368
+ const mixed = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-quad-clean-'));
369
+ runInit(cli, mixed, 'cursor', 'next');
370
+ runInit(cli, mixed, 'mavis', 'next');
371
+ assert.match(fs.readFileSync(path.join(mixed, 'AGENTS.md'), 'utf8'), /Presence-based load/);
372
+ const keepCursor = runClean(mixed, 'cursor');
373
+ assert.match(keepCursor, /Kept shared AGENTS.md/);
374
+ assert.equal(fs.existsSync(path.join(mixed, 'AGENTS.md')), true);
375
+ runClean(mixed, 'mavis');
376
+ assert.equal(fs.existsSync(path.join(mixed, 'AGENTS.md')), false);
377
+
378
+ const cursorOnly = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-cursor-only-clean-'));
379
+ runInit(cli, cursorOnly, 'cursor', 'next');
380
+ runClean(cursorOnly, 'cursor');
381
+ assert.equal(fs.existsSync(path.join(cursorOnly, 'AGENTS.md')), false);
382
+
383
+ const multiDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-init-multi-'));
384
+ const multiOut = runInit(cli, multiDir, 'multi', 'next');
385
+ assert.match(multiOut, /Done\. multi installed cursor, claude, mavis, opencode/);
386
+ assert.equal(fs.existsSync(path.join(multiDir, '.cursor', 'AGENTS.md')), true);
387
+ assert.equal(fs.existsSync(path.join(multiDir, '.claude', 'CLAUDE.md')), true);
388
+ assert.equal(fs.existsSync(path.join(multiDir, '.mavis', 'AGENTS.md')), true);
389
+ assert.equal(fs.existsSync(path.join(multiDir, '.opencode', 'AGENTS.md')), true);
390
+ assert.match(fs.readFileSync(path.join(multiDir, 'AGENTS.md'), 'utf8'), /init multi --preset next/);
391
+
392
+ const multiNuxt = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-rules-init-multi-nuxt-'));
393
+ const multiNuxtOut = runInit(cli, multiNuxt, 'multi', 'nuxt');
394
+ assert.match(multiNuxtOut, /Skipping mavis/);
395
+ assert.match(multiNuxtOut, /Skipping opencode/);
396
+ assert.match(multiNuxtOut, /Done\. multi installed cursor, claude; skipped mavis, opencode/);
397
+ assert.equal(fs.existsSync(path.join(multiNuxt, '.cursor', 'AGENTS.md')), true);
398
+ assert.equal(fs.existsSync(path.join(multiNuxt, '.claude', 'CLAUDE.md')), true);
399
+ assert.equal(fs.existsSync(path.join(multiNuxt, '.mavis')), false);
400
+ assert.equal(fs.existsSync(path.join(multiNuxt, '.opencode')), false);
401
+
402
+ const multiClean = runCli(multiDir, ['clean', 'multi']);
403
+ assert.equal(multiClean.status, 1);
404
+ assert.match(`${multiClean.stderr}${multiClean.stdout}`, /clean multi is not supported/);
405
+
344
406
  for (const dir of [
345
407
  isolatedHome,
346
408
  fresh,
@@ -360,6 +422,11 @@ for (const dir of [
360
422
  ocMissing,
361
423
  ocRollback,
362
424
  ocGoldenDir,
425
+ mixed,
426
+ cursorOnly,
427
+ multiDir,
428
+ multiNuxt,
429
+ ...lastInitDirs,
363
430
  ]) {
364
431
  fs.rmSync(dir, { recursive: true, force: true });
365
432
  }