diff --git a/docs/specs/agent-doc-surfaces.md b/docs/specs/agent-doc-surfaces.md index 0ac865f6c8..a667ad2e50 100644 --- a/docs/specs/agent-doc-surfaces.md +++ b/docs/specs/agent-doc-surfaces.md @@ -55,7 +55,7 @@ guidance <200 lines per CLAUDE.md. | Convention | File(s) | Auto-read | |---|---|---| | AGENTS.md open standard (Linux Foundation-stewarded) | `AGENTS.md` root + nested, nearest wins | Native in Codex, Cursor, Copilot agent, Gemini CLI (config), Windsurf, Zed, Roo, others; and in Claude Code since v2.1.277, where no `CLAUDE.md` displaces it (row 9). Claude Code concatenates the ancestor chain rather than resolving nearest-wins | -| Cursor rules | `.cursor/rules/*.mdc` (+ nested); legacy `.cursorrules` deprecated | Per-rule types: Always / Auto Attached (globs) / Agent Requested / Manual; also reads AGENTS.md + CLAUDE.md | +| Cursor rules | `.cursor/rules/*.mdc` (+ nested); legacy `.cursorrules` deprecated | Per-rule types: Always / Auto Attached (globs) / Agent Requested / Manual; CLI observed to read `AGENTS.md`, `CLAUDE.md` and `CLAUDE.local.md` together, without `@`-import expansion; `.cursor/rules/*.md` is inert and an `.mdc` needs frontmatter (`plugins/instruction-placement/skills/migrate/reference/sources.md`) | | GitHub Copilot | `.github/copilot-instructions.md`; `.github/instructions/**.instructions.md` (`applyTo:` globs); AGENTS.md (agent) | Auto-added to matching requests | | Gemini CLI | `~/.gemini/GEMINI.md`; workspace + ancestors; JIT subdir scan; `@` imports; `context.fileName` configurable | Concatenated into every prompt | | Windsurf | `global_rules.md`; `.windsurf/rules/` (newer docs prefer `.devin/`); legacy `.windsurfrules`; AGENTS.md | Per-rule `trigger:` manual / always_on / model_decision / glob | @@ -78,7 +78,8 @@ corroborate the competitor paths themselves. - Claude-side rows corroborate mostly within the single Anthropic publishing pool. **Accepted**: the effort's claim ladder requires verification against current official docs, not multi-publisher independence, for harness-behavior claims. -- Cursor / Copilot / Windsurf / Cline rows are MEDIUM confidence (vendor doc hosts egress-blocked +- Cursor / Copilot / Windsurf / Cline rows are MEDIUM confidence, except that Cursor's + AGENTS.md and CLAUDE.md loading is observed (see the row). Vendor doc hosts were egress-blocked in the research container; sourced via domain-filtered search + Anthropic's `/init` interop list as path corroborator). **Accepted for their purpose**: ecosystem awareness rows, not harness claims. Optional implementation-time task: re-fetch the four vendor pages from an diff --git a/plugins/instruction-placement/.claude-plugin/plugin.json b/plugins/instruction-placement/.claude-plugin/plugin.json index a594d8460e..74d6af01e2 100644 --- a/plugins/instruction-placement/.claude-plugin/plugin.json +++ b/plugins/instruction-placement/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "instruction-placement", - "version": "0.16.1", + "version": "0.16.2", "description": "Routes agent-instruction content to the surface that loads it at the right moment. The audit skill sweeps a repository's instruction layer and its ordinary markdown for content whose scope is narrower than the surface carrying it, meaning conventions keyed to one file type or one subtree sitting in an always-loaded CLAUDE.md or AGENTS.md, and for normative conventions stranded in documentation Claude never loads at all, then classifies each against a routing rubric and proposes a destination whose `paths:` glob is machine-validated before it is ever offered. Safety-class content (irreversible actions, secrets, data integrity, external publication, compliance, agent authority) is hard-denied from demotion and reported as held back rather than proposed, because demotion trades guaranteed presence for conditional presence: a deferred surface is absent until a read matches it, absent after a compaction until that trigger recurs, and never inherited by a subagent, which re-acquires it only by reading a covered path itself. Every accepted move regenerates an always-loaded index of deferred surfaces, which is what keeps a demoted rule discoverable from any context that has not happened to touch a path it covers. The audit is read-only and emits a diffable findings artifact; realignment is a separate skill gated per item with no blanket-approve path; a deterministic check skill gates that every rule glob still resolves and the index is current; a migrate skill moves a repository to AGENTS.md as the content home and keeps a CLAUDE.md shim while one is needed; and a setup skill verifies the one thing no other gate can see: that nothing in the repository stops Claude Code reading the index target, since a CLAUDE.md in the working directory or above it is read instead of the AGENTS.md beside it.", "author": { "name": "Melodic Software", diff --git a/plugins/instruction-placement/CHANGELOG.md b/plugins/instruction-placement/CHANGELOG.md index 35f2621f82..e05a5870fe 100644 --- a/plugins/instruction-placement/CHANGELOG.md +++ b/plugins/instruction-placement/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to the `instruction-placement` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.16.2] - 2026-09-30 + +### Changed + +- **`migrate` sources record the observed Cursor, Grok Build and Muse Code loader behavior.** The parked-install record is replaced by the results of running the loader recipe against each tool, with the bullets that stay open and their reasons. `verification.md` carries the recipe and expected results, and the record cites the upstream pages that exist + ([#4283](https://github.com/melodic-software/claude-code-plugins/issues/4283)). + ## [0.16.1] - 2026-09-30 ### Fixed diff --git a/plugins/instruction-placement/skills/migrate/reference/sources.md b/plugins/instruction-placement/skills/migrate/reference/sources.md index 2828f77b5e..64158d752f 100644 --- a/plugins/instruction-placement/skills/migrate/reference/sources.md +++ b/plugins/instruction-placement/skills/migrate/reference/sources.md @@ -175,16 +175,61 @@ Each row was re-derived on 2026-09-28 by resolving the tag to its commit and rea `agents-md-cutover-check` in `.github/recurring-schedule.json`, or an in-scope repository becoming unreadable or readable. -## Install-dependent loader tests (#4283) +## Loader behavior of Cursor, Grok Build, and Muse Code -- **Claim**: empirical loader tests for Cursor, Grok Build, and Muse Code have not been run. - Claims about those tools stay at docs or source grade. -- **Basis**: #4283's acceptance criteria are unmet and no run exists on main. The tools were not - installed in the environment that did the migration research, an environment limit and not a - decision. Whether and where to install them is pending an owner decision on #4283. -- **As of**: 2026-09-29. -- **Recheck trigger**: the owner's decision on #4283, or a host that records results for a named - tool into this file. +- **Claim**: Each tool was run headless against one recipe tree, and these results are + observed, not docs or source grade. Cursor CLI loads `AGENTS.md`, `CLAUDE.md` and + `CLAUDE.local.md` together at session start, follows symlinks, applies no size cap through + 262,156 bytes, and does not expand `@path` imports. It reads no other name (`Agents.md`, + `AGENT.md`, `.claude/CLAUDE.md` are absent). `.cursor/rules/*.md` never loads; `.mdc` loads + only with frontmatter. Started at the git root, nested files attach when a file under them is + read; started in the nested directory, the ancestor chain loads (12 levels seen). In the + non-git copy the attach on read did not occur. Grok Build loads all eight names of its + documented list per directory, and the two `.claude/` names are gated by + `GROK_CLAUDE_AGENTS_ENABLED` (set to `false`, they vanish). No switch stops it + reading a plain `CLAUDE.md`. It does not expand `@path` imports, follows symlinks, and shows no + size cap through 262,156 bytes. In a trusted folder outside a git repository it loads the + working directory only, so "nothing outside a git repository loads" is contradicted; with + folder trust off nothing project-level loads. Muse Code loads one file per directory with + `AGENTS.md` first, and `CLAUDE.md` alone loads when no `AGENTS.md` exists. It does not expand + `@path` imports and follows symlinks. It skips an `AGENTS.md` over 256,000 bytes ("over the + 256000 byte load limit"), loads one of 244,676 bytes with only the head reaching the model + (65,536-byte delegation startup limit), and skips project files unless the workspace is + trusted (`--trust-workspace`). In a git repository it loads the chain from root to working + directory (12 levels seen); from the root, a read under a nested directory attaches nothing; + outside git it loads the working directory only. + Still open, each with its reason: + - Cursor Team, Project, User precedence: needs a Team plan and the editor rules UI, not + observable headless. + - Cursor editor against CLI, and the editor's "always applied" wording: the editor was not run. + - Cursor `~/.cursor/rules` as a synced file: the path does not exist on the host, and sync + cannot be observed headless. + - Grok path-only reminder text for out-of-chain files: contents stay unloaded and the model + later read the nested files itself, but the streamed transcript carries no reminder text. + - Grok `MAX_WALK_DEPTH` of 10: a working directory at depth 12 loaded all 12 levels, so the + recipe does not show what the constant bounds. + - Muse "sibling `CLAUDE.md` never opened": Muse names the shadowed file on stderr ("is ignored + this session because AGENTS.md takes precedence in that directory"), but whether the file + is opened needs `strace`, which is not installed on the host. + - Muse user-rules path and its Windows resolution: no Muse-native user-rules file exists on + the host, and the Windows path needs a Windows host. +- **Basis**: headless runs on one Linux host with cursor-agent `2026.09.28-64d2043` + (`cursor-agent -p --mode ask --trust`), grok `1.0.41 (4220f3b224a6)` (`grok -p --tools ""` + with `GROK_FOLDER_TRUST=0`, and `grok inspect --json`), and Muse Code `1.4.1 (1.4.1-R4503.1)` + (`muse exec --trust-workspace --disable-shell --disable-write`). The tree, prompt, + invocations and expected results are in + [`reference/verification.md`](verification.md#the-loader-recipe-for-other-tools); the raw + transcripts are not committed. Each result is one model sample except where repeats agreed. +- **Upstream pointers**: Cursor rules, `https://cursor.com/docs/rules` (fetched 2026-09-30, HTTP + 200, mentions `AGENTS.md`); Grok Build, `https://docs.x.ai/build/overview` (fetched + 2026-09-30, HTTP 200, mentions `AGENTS.md`). Neither page states the loader semantics above, + which is why they are recorded as observed. Muse Code: no public documentation or issue + tracker was found, so its results rest on the recipe alone. +- **As of**: 2026-09-30. +- **Recheck trigger**: a new release of any of the three tools, a host that can run the + editor, a Team plan, a Windows host, or `strace`, which would settle the open bullets, either + upstream page coming to state loader behavior, or any change to the recipe in + [`reference/verification.md`](verification.md#the-loader-recipe-for-other-tools). ## The canary recipe diff --git a/plugins/instruction-placement/skills/migrate/reference/verification.md b/plugins/instruction-placement/skills/migrate/reference/verification.md index 7d50ab5835..f8dcc35f4f 100644 --- a/plugins/instruction-placement/skills/migrate/reference/verification.md +++ b/plugins/instruction-placement/skills/migrate/reference/verification.md @@ -120,6 +120,65 @@ file-specific, which is the common case. The fallback: canary an **existing** pa so the mechanism is still proven on this repository, and report that the migration created none. Never invent a rules file to have something to canary. +## The loader recipe for other tools + +The procedure behind the Cursor, Grok Build and Muse Code records in +[`reference/sources.md`](sources.md). Run it again when a recheck trigger there fires. + +**Tree.** Build it outside every repository, once as a git repository and once as a copy without +`.git`. Give every instruction file its own random canary, named by label and never committed. + +- root `AGENTS.md`; `CLAUDE.md` holding `@AGENTS.md`, `@imported.md` and its own canary; + `imported.md`; `.claude/CLAUDE.md`; `.cursor/rules/` with `x.md` and `x.mdc`, both with + `alwaysApply: true` frontmatter, plus a `.mdc` without frontmatter +- `sub/AGENTS.md`, `sub/CLAUDE.md`, and a non-instruction file `sub/inner/note.txt` as the read + trigger +- `symdir/` with `AGENTS.md` and `CLAUDE.md` as symlinks +- `big32k/`, `big245k/`, `big256k/`, `big1m/`: an `AGENTS.md` of 32,784, 244,676, 262,156 and + 1,048,596 bytes, canaries at head, middle and tail +- `deep/l01/` through `l12/`, one `AGENTS.md` each +- `names/`: `Agents.md`, `Claude.md`, `CLAUDE.md`, `CLAUDE.local.md`, `AGENT.md`, `AGENTS.md`, + `.claude/CLAUDE.md`, `.claude/CLAUDE.local.md` +- two more trees holding only a `CLAUDE.md`, and only an `AGENTS.md` + +**Prompt.** Quote every line containing `CANARY` from the loaded instructions, without reading +files. For the read-trigger probes, allow one read of `sub/inner/note.txt` and nothing else. + +**Invocations**, each from the tree root and from a nested directory, with the workspace trusted: + +```bash +cursor-agent -p --mode ask --trust --output-format text +GROK_FOLDER_TRUST=0 grok -p --tools "" --disable-web-search --max-turns 4 +grok inspect --json +muse exec --no-session-log --disable-web-tools --trust-workspace --disable-shell --disable-write --no-foreign-personal-context +``` + +Without `GROK_FOLDER_TRUST=0` Grok lists only `~/.claude/CLAUDE.md`, and without +`--trust-workspace` Muse skips every project file. `grok inspect --json` is deterministic and +needs no model call. Each model result is one sample; repeat a probe before trusting a `NONE`. + +**Expected results**, as observed on cursor-agent `2026.09.28-64d2043`, grok `1.0.41`, and +Muse Code `1.4.1`: + +| Probe | Cursor | Grok Build | Muse Code | +|---|---|---|---| +| Root `AGENTS.md` and `CLAUDE.md` | both load | both load | `AGENTS.md` only | +| `CLAUDE.md` with no `AGENTS.md` | loads | loads | loads | +| `@path` import in an instruction file | not expanded | not expanded | not expanded | +| Symlinked instruction file | followed | followed | followed | +| `Agents.md`, `AGENT.md`, `.claude/CLAUDE.md` | not read | all eight names read | not read | +| 262,156-byte `AGENTS.md` | loads | loads | skipped, "over the 256000 byte load limit" | +| Nested files, cwd at the git root | attach when a file under them is read | absent | absent, and a read attaches nothing | +| Nested files, cwd in the nested directory | ancestor chain loads, 12 levels | chain loads, 12 levels | chain loads, 12 levels | +| Non-git copy, cwd nested | ancestors load | cwd directory only | cwd directory only | +| Non-git copy, cwd at the root, nested file read | attach does not occur | not tested | not tested | +| `.cursor/rules/x.md` | never loads | loads as a rule | not tested | +| `.cursor/rules/x.mdc` | loads with frontmatter only | not loaded | not tested | + +Grok's two `.claude/` names disappear with `GROK_CLAUDE_AGENTS_ENABLED=false`; the six top-level +names stay. Muse prints "is ignored this session because AGENTS.md takes precedence in that +directory" on stderr for a shadowed sibling. + ## Progressive disclosure, with a caveat Run `/docs-hygiene:audit-progressive-disclosure` via the Skill tool, when it is installed, on the