@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 +7 -0
- package/README.md +17 -6
- package/bin/cli.js +94 -11
- package/bin/mavis-install.js +5 -1
- package/bin/opencode-install.js +5 -1
- package/package.json +1 -1
- package/presets/claude/next/REPO_AGENTS.md +26 -5
- package/presets/cursor/next/REPO_AGENTS.md +18 -5
- package/presets/mavis/next/MAVIS.md +1 -0
- package/presets/mavis/next/REPO_AGENTS.md +25 -47
- package/presets/mavis/next/adapter-map.json +3 -3
- package/presets/opencode/next/REPO_AGENTS.md +25 -48
- package/presets/opencode/next/adapter-map.json +3 -3
- package/scripts/fixtures/cli-golden/claude/next.json +1 -1
- package/scripts/fixtures/cli-golden/cursor/next.json +1 -1
- package/scripts/fixtures/cli-golden/mavis/next.json +2 -2
- package/scripts/fixtures/cli-golden/opencode/next.json +1 -1
- package/scripts/generate-mavis-next.mjs +4 -103
- package/scripts/generate-opencode-next.mjs +3 -104
- package/scripts/test-cli-init-clean.mjs +70 -3
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
|
|
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
|
-
- **
|
|
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/**`.
|
|
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
|
|
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 &&
|
|
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' &&
|
|
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 || !
|
|
787
|
-
console.error(
|
|
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);
|
package/bin/mavis-install.js
CHANGED
|
@@ -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 {
|
package/bin/opencode-install.js
CHANGED
|
@@ -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
|
@@ -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
|
|
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
|
|
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
|
|
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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": "
|
|
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": "
|
|
36
|
+
"disposition": "copy",
|
|
37
37
|
"loadMode": "root-entry",
|
|
38
|
-
"reason": "
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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": "
|
|
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": "
|
|
36
|
+
"disposition": "copy",
|
|
37
37
|
"loadMode": "root-entry",
|
|
38
|
-
"reason": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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,
|
|
234
|
+
writeFile(target, sourceText);
|
|
235
235
|
entries.push(
|
|
236
236
|
entry({
|
|
237
237
|
source,
|
|
238
238
|
target,
|
|
239
239
|
category: 'entry',
|
|
240
|
-
disposition: '
|
|
240
|
+
disposition: 'copy',
|
|
241
241
|
loadMode: 'root-entry',
|
|
242
|
-
reason: '
|
|
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,
|
|
344
|
+
writeFile(target, sourceText);
|
|
345
345
|
entries.push(
|
|
346
346
|
entry({
|
|
347
347
|
source,
|
|
348
348
|
target,
|
|
349
349
|
category: 'entry',
|
|
350
|
-
disposition: '
|
|
350
|
+
disposition: 'copy',
|
|
351
351
|
loadMode: 'root-entry',
|
|
352
|
-
reason: '
|
|
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'), /
|
|
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'), /
|
|
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
|
}
|