Added
- XP-009: Codex Instruction Chain Exceeds project_doc_max_bytes. Codex's 32 KiB
project_doc_max_bytescap is cumulative across the instruction chain, not per-file - it "stops adding files once the combined size reaches the limit". XP-007 checks eachAGENTS.mdin isolation, so a project split across several mid-size files was truncated with no diagnostic at all. The new project-level rule builds the chain the way Codex discovers it (root down, at most one file per directory,AGENTS.override.mdbeforeAGENTS.md), sums root-first, and reports on the file where the running total crosses the limit - that file and everything deeper is what Codex drops. Rule count 442 -> 443 (closes #1289). argson command hooks. The exec-form field - "When present,commandis resolved as an executable and spawned directly withargsas the argument vector, with no shell involved" - was absent from the schema, so it was silently ignored and two rules could not tell exec form from shell form.
Removed
- CC-SK-003 (Context Without Agent). The rule errored when
context: forkhad noagentfield and shipped an unsafe autofix insertingagent: general-purpose. The skills reference states "Theagentfield specifies which subagent configuration to use... If omitted, usesgeneral-purpose", so the rule demanded that users restate a default the tool already applies. Rule count 443 -> 442. - CC-HK-019 (Deprecated Setup Event). The rule warned that the
Setuphook event was deprecated in favor ofSessionStartand shipped an unsafe autofix that rewrote the event key.Setupis not deprecated: it is documented as a current event that fires on--init-onlyand on--init/--maintenancein-pmode, with its own matcher set (init,maintenance), exit-code row, and decision-control entry.SessionStartfires on every session begin/resume, so applying the "fix" silently changed when a hook ran. The rule cited no upstream deprecation notice when it was added. Rule count 444 -> 443. Follows the origin-less-rule removal precedent from PR #979.
Fixed
- COP-005 rejected the documented
excludeAgentvalue and autofixed it wrong. The valid values arecode-reviewandcloud-agent; agnix listedcoding-agent, which was never upstream - so the doc's own value errored, and the unsafe autofix rewrote a correct value into the invalid one.coding-agentis retained as a deprecated alias so configs written against agnix's previous wrong advice keep validating, reported at info level rather than accepted silently, and kept out of the autofix candidate list so the fixer can never write it. Fixed across the validator, all 12 locale files, bothrules.jsoncopies, and the knowledge-base docs. - COP-003 rejected comma-separated
applyTo. "You can specify multiple patterns by separating them with commas", withapplyTo: "**/*.ts,**/*.tsx"as the doc's own example. The whole string went toglob::Pattern, so every such config errored. A correct brace/bracket-aware splitter already existed with 18 passing tests but was marked#[allow(dead_code)] // reserved for future useand never called. - CUR-004 rejected comma-separated
globs. Same class as COP-003, same upstream wording ("Separate multiple patterns with commas"). This one was intermittently wrong, which is why it survived: the doc's literal exampledocs/**/*.md, docs/**/*.mdxhappens to parse as one pattern, whilesrc/**, tests/**does not. - CUR-010 required
versionin.cursor/hooks.json. It is documented with a default of1and several of the doc's own examples omit it. Now optional, and type-checked as a number (not an integer) only when present. - CUR-012 required
commandon prompt hooks. "Prompt hooks use an LLM to evaluate a natural language condition" and carrypromptinstead - the doc's example has onlytype,prompt,timeout. CUR-018 already checkedpromptfor those. - CUR-016 required
installin.cursor/environment.json. The published schema has norequiredarray at all (definitions.common) andrequired: [](definitions.container), and the setup page's own snapshot example omitsinstall. Terminal entries now require onlycommand(name/descriptionare optional per bothoneOfbranches, and the array branch is accepted), andupdate- absent from the schema, which setsunevaluatedProperties: false- is reported as renamed toinstallrather than accepted as valid. - Cursor hook
timeoutsuggestions said milliseconds. The option is "Execution timeout in seconds". - CC-MEM-014 fired on Cursor
.mdcfiles.ClaudeMdValidatoris registered forFileType::CursorRulefor its generic prose checks, so a.cursor/rules/*.mdcfile was reported asCLAUDE.md has N non-empty lines, exceeding the recommended 200 line limit- wrong filename, wrong threshold (Cursor documents 500), wrong tool attribution. Now scoped to Claude memory files. - Stale evidence URLs for 18 rules.
docs.github.com/en/copilot/customizing-copilot301-redirects anddocs.cline.bot/features/cline-rules/overview308-redirects; both are updated inrules.jsonand.github/spec-baselines.json, so those two sentinel sources can match again. AGENTS.override.mdwas not recognized as an instruction file. Codex checks it beforeAGENTS.mdin each directory, butis_instruction_file()did not list it, so it was invisible to every cross-platform rule. This also made theAGENTS.override.mdhandling added to XP-007 in the previous release unreachable in practice.- CC-SK-009 miscounted dynamic injections in both directions. It counted raw
!`occurrences, so inertKEY=!`cmd`forms inflated the count (the doc: a!following another character "is left as literal text and the command does not run"), while```!fenced blocks - where every line is a command - counted as zero. Counting now honors both documented forms and ignores plain fences. - CC-SK-012/CC-SK-016 recognized only
$ARGUMENTS. The substitution table documents four forms; a body using the$Nshorthand or a$namedeclared inargumentswas reported as ignoring its own arguments, and$0escaped CC-SK-016 entirely. Theargumentsfrontmatter field is now parsed so named placeholders can be resolved. The shorthand is matched as a single digit, matching the documented examples, so${CLAUDE_SKILL_DIR},x$3y, and prose amounts like$500are not mistaken for positional arguments. - CC-HK-028 flagged the exec form the doc recommends.
${user_config.*}is rejected only in shell form: "Plugin hooks additionally substitute${user_config.*}values, in exec form only". The rule fired regardless ofargs, so{"command": "${user_config.formatter}", "args": ["--fix"]}errored. - CC-HK-008 skipped scripts named in
args. In exec form the script sits inargswhilecommandnames an interpreter, so exec-form hooks - the form the doc recommends for path placeholders - got no script-existence checking at all. - AS-013 only inspected
references/paths. The spec scopes skill resources to "scripts/,references/, orassets/" and usesscripts/extract.pyin its own example, so deepscripts/andassets/paths were invisible. Git ref paths stay excluded. - AS-017 rejected Claude Code display labels. Claude Code decouples
namefrom the directory ("namesets only the display label... the command still comes from the directory or file name"), and a plugin skill'snamedeliberately replaces the last command segment - the reference's ownname: fancyinskills/review/example errored. Scoped out for Claude Code skills, following the AS-008 precedent; the agentskills.io baseline still requires the match. - CC-PL-002 checked four of eight directories. The doc names
commands/,agents/,skills/,workflows/,output-styles/,themes/,monitors/, andhooks/as forbidden inside.claude-plugin/. - CC-PL-007/CC-PL-008 checked four of ten path fields.
workflows,mcpServers,outputStyles,lspServers,experimental.themes, andexperimental.monitorsaccepted absolute paths,..traversal, and.claude-plugin/targets unchecked. Dottedexperimental.*keys are now traversed, which a plain field lookup could not do. - XP-007 ignored
AGENTS.override.md. Codex reads it first in each directory, so it draws on the sameproject_doc_max_bytesbudget; the code comment claiming Codex "reads this file, not local/override variants" was contradicted by the current guide. The cap is cumulative across the root-to-cwd chain while this check remains per-file - noted in the rule docs as a known gap. - AGM-006's suggestion contradicted upstream. It advised consolidating files, while Codex documents root-down concatenation with nearest-file-wins precedence and recommends splitting across nested directories to stay under the byte cap.
- MCP-008 flagged the current protocol revision.
2026-07-28is now the current MCP revision and the unversioned/specificationURL serves it, but agnix compared against a single pinned default of2025-11-25. With no revision pinned, both are now accepted: the two are behaviorally incompatible rather than sequential (2026-07-28 drops theinitialize/initializedhandshake andMcp-Session-Idsessions), so a config written for either is legitimately current and demanding one would only move the false positive onto the other. Pinning[spec_revisions] mcp_protocolstill enforces exactly one revision and keeps the autofix; the unpinned diagnostic now names every accepted revision instead of claiming a single one is required. A revision outside the current set is still reported. - CC-SK-001's message listed a stale alias set. It advertised only
sonnet, opus, haiku, inherit, or claude-*after the accepted list had been widened. codex-cli-agents-mdsource URL was dead.https://developers.openai.com/codex/guides/agents-md/308-redirects tohttps://learn.chatgpt.com/docs/agent-configuration/agents-md- the doc moved host and site, so the Spec Drift Sentinel baseline for that source could never match again. Updated inspec-baselines.json, in all 20 affectedevidence.source_urlsentries, and across the knowledge-base docs.- Parenthesized tool arguments were shattered by tokenization.
tools: Agent(worker, researcher), Read, Bash(npm run test:*)- the sub-agents reference's own verbatim example - reportedUnknown tool 'researcher)','run', and'test:*)'under CC-AG-009/010, because the string deserializer split on commas and spaces before parentheses were stripped. The skill validator already had a paren-aware tokenizer; it is now shared asvalidation::split_tool_listsoallowed-tools,tools, anddisallowedToolscannot drift apart again. - CC-AG-004 rejected
autoandmanual, and accepted the undocumenteddelegate. The permission-modes reference documents six modes (default,acceptEdits,plan,auto,dontAsk,bypassPermissions) plusmanualas a CLI alias fordefault(v2.1.200+).delegateappears in neither that reference nor sub-agents and was added without a cited source, so it is no longer accepted. - CC-AG-003/CC-SK-001 rejected documented model values.
model"Accepts the same values as the--modelflag", sodefault,best,fable,opusplan,sonnet[1m], andopus[1m]are all valid and were all erroring. The alias list is now shared between the agent and skill validators rather than duplicated. - MCP-020 warned on two valid capability keys.
tasksis in the 2025-11-25 capability-negotiation table - the revision agnix already pins - andextensionswas added in 2026-07-28. Note the spec calls capabilities an open set ("any server can define its own, additional capabilities"), so this rule is advisory. - CC-MEM-001 rejected absolute and home-directory imports. The memory reference states "Both relative and absolute paths are allowed" and prescribes
@~/.claude/my-project-instructions.mdas the way to share personal instructions across git worktrees; Claude Code gates external imports behind a one-time approval dialog rather than rejecting them. Existence is still checked, and the path-shape guard is retained for non-memory files under REF-001, where no spec sanctions escaping the project root. - CC-MEM-003 allowed two more hops than documented. The doc says "a maximum depth of four hops"; the limit was 5 and the check is
depth + 1 > MAX, so the diagnostic first fired at six. .claude/rules/was only validated one level deep. The doc says "All.mdfiles are discovered recursively, so you can organize rules into subdirectories likefrontend/orbackend/", but both the file-type detector and the validator requiredrules/to be the immediate parent. Nested rule files got no validation at all - CC-MEM-011/012 never ran on them.- CC-HK-025 rejected the documented
forkSessionStart matcher.forkcovers--fork-sessionwith--resume/--continue, the/forkbackground copy, and/branch. It was missing from the known-value list, so a valid hook config was flagged. (resumestays valid: before Claude Code v2.1.214 a forked session reportedresume.) - CC-PL-015 flagged additive and merge-semantics plugin fields as shadowing. The rule warned that a default component folder was ignored whenever the matching manifest key was present, but the plugins reference splits those keys three ways:
skillsadds to the default (the defaultskills/directory is always scanned), whilehooks/mcpServers/lspServershave their own merge rules. Neither can shadow, so bothskillsandhooksproduced false warnings on plugins that kept their default folder. The rule now checks only the six documented replace-semantics fields, which also closes a coverage gap:workflows,outputStyles,experimental.themes, andexperimental.monitorswere never checked. Folder names that differ from their manifest key are handled (outputStyles->output-styles/,experimental.*-> root-levelthemes/,monitors/). - Spec Drift Sentinel pointed maintainers at 15 rule IDs that do not exist.
.github/spec-baselines.jsonmappedclaude-code-subagentstoCC-SA-001..007,github-copilottoGH-001..004, andcline-rulestoCLINE-001..003- none of which were ever in this repo; the real rules areCC-AG-*,COP-*/CP-SK-*, andCLN-*/CL-SK-*. It also still listedAS-014, removed in PR #979. Every drift issue rendered these straight into the "rules may need review" list, sending the reader to rules they could not look up. Mappings are now derived from each rule's own evidence URLs, and a newtest_spec_baseline_rule_ids_existparity test fails CI if an unknown ID is ever added.