Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
[4.23.1] - 2026-10-03¶
Added¶
- xum stdio MCP
env(#209): Xum'smcp.jsoncloader keeps only the command string of a stdio entry, soenvis written as a POSIX shell assignment prefix (GITHUB_TOKEN=... npx -y pkg, keys sorted, values shell-quoted) instead of being dropped with a warning. Names that are not shell identifiers are skipped with a warning. Resolved secrets in it fall under the existing MCP secret guard (0600, must be git-ignored). - v1 OpenCode plugin warning: OpenCode v2 does not run v1 plugins and only logs the refusal to its server log.
generatenow warns, once per file and without failing, about a v1-shaped authored.ai-rulez/opencode/index.jsand about v1-shaped local files in.opencode/plugin(s)/or in theplugin/pluginsarray ofopencode.json(c)(local paths only), with a link to the migration guide. Seedocs/plugins.md. - OpenCode plugin MCP servers and agent settings: the generated OpenCode plugin now registers the bundle's MCP servers (
${PLUGIN_ROOT}and${VAR}expand at runtime, nothing resolved is written to the package) and maps agent settings with theopencodepreset's rules: provider-qualifiedmodeland variant pass through, bare aliases such assonnetare omitted with one warning, plusmode,hidden,temperatureandtop_p. Both are emitted in.opencode/ai-rulez-bundle.json, and top-level paths an MCP server references through${PLUGIN_ROOT}/<path>(such asscripts/) are added to the generatedpackage.jsonfileslist, with a warning when the path does not exist. A project server withenabled = falseis bundled withdisabled: truefor OpenCode (other runtimes have no such flag, so a disabled server is bundled enabled for them andgeneratewarns), and remoteheadersare still not bundled (warned).docs/plugins.mdnow lists the routes that load the plugin in OpenCode 2.0.20 (copying into.opencode/plugins/, or"plugins": ["<dir>"]with anindex.jsat the directory root;main/exportsof the generatedpackage.jsonare ignored for local directories) and notes that${VAR}in bundled MCP config is expanded from the OpenCode process environment, which a third-party plugin can read.
Changed¶
- MCP servers in shared settings documents are owned one by one.
.claude/settings.json,.gemini/settings.json,.mcp.json,.agents/settings.json,opencode.json(mcp.servers) and.xum/mcp.jsoncused to have their wholemcpServersobject replaced, which deleted servers you wrote by hand.generatenow writes each configured server into the existing object, so a server whose name is not inconfig.tomlsurvivesgenerateandclean; a server dropped from the config is removed on the nextgenerate. A hand-written server with the same name as a configured one is overwritten by the configured value. A document ai-rulez wrote whole behaves as before. - A plugin
namemust match^[a-z0-9][a-z0-9._-]*$and contain no..for every runtime, not onlyagent-plugins: it becomes a directory and file name and, for OpenCode, an identifier in generated source. Scoped (@scope/x), uppercase and slash-containing names are rejected byvalidate.
Fixed¶
- Codex plugin
.mcp.jsonis merged into the file already in the repository (server by server, claims recorded) instead of overwriting it. - OpenCode plugin helper:
$ARGUMENTSin a command is replaced literally ($&,$$and$1in the prompt were interpreted), a command or agent file that cannot be read is skipped with a warning instead of aborting the registration, and skill and command names and descriptions come from.opencode/ai-rulez-bundle.json, so quoted or escaped YAML values are no longer mangled. The plugin id is written as a JavaScript string, and a${PLUGIN_ROOT}\scripts\run.cmdreference publishesscripts/. - v1 OpenCode plugin detection ignores comment markers inside string literals (
"src/**/*.js"), recognizes v2 plugins whoseidis a variable or shorthand and that also export helper functions, and readsfile://plugin paths with URL parsing (drive letters, percent escapes). -
Merged-document housekeeping: manifests are read once per run (a corrupt one is reported once), warnings the baseline and the real render both produce are printed once, an edited document is replaced through a temporary file and a rename, and the
AGENTS.override.mdwarnings read correctly for one preset as for several. -
OpenCode plugin bundles: the skills, commands and agents bundled under
.opencode/were never discovered when the plugin was installed from npm, because OpenCode v2 only scans its own config directories. The generated entrypoint now registers them through the skill, command and agent transforms (.opencode/ai-rulez-content.js), and no longer imports@opencode/pluginat runtime, which failed to resolve for local plugins. - Local content reaches each tool through a file it loads. Several
*.local.mdfiles ai-rulez wrote for machine-local content were never read by their tools. Local context and inline local rules now go to: - Gemini CLI:
GEMINI.local.mdis listed in.gemini/settings.jsoncontext.fileName(["GEMINI.md", "GEMINI.local.md"], or["AGENTS.md", "GEMINI.local.md"]withagents_md). The document is now written without[[mcp_servers]]and whether or not local content exists, so a committed.gemini/settings.jsongains this one entry. Acontext.fileNameyou wrote is kept andGEMINI.local.mdis appended to it (andAGENTS.mdunderagents_md), a single string becoming a list, with no warning; a value that exactly equals one ai-rulez writes is its own with or without a manifest, which also fixes theagents_mdtoggle in a partly hand-written file and on a fresh clone. - OpenCode:
opencode.jsoninstructionslistsAGENTS.local.md(./AGENTS.local.mdcounts as the same entry), merged per entry with your own.opencode.jsonis now written without[[mcp_servers]], and$schemais added only to a file ai-rulez creates, never to one you wrote. - Codex, and Hermes with
agents_md: a git-ignoredAGENTS.override.mdthat repeats theAGENTS.mdbody that run wrote (without its banner, so a[header] timestampdoes not rewrite it) and appends the local sections (both tools load it instead ofAGENTS.md). A hand-writtenAGENTS.override.mdis never overwritten or deleted;generatewarns instead. Local content with noAGENTS.mdto extend is reported. - Junie and Antigravity:
.junie/rules/ai-rulez.local.mdand.agents/rules/ai-rulez.local.md(trigger: always_on). A local rule namedai-rulezis written asai-rulez-<hash>.local<ext>. Junie reads.junie/rules/only on itsAGENTS.mddiscovery path, not with a.junie/AGENTS.mdor the legacy.junie/guidelines.mdlayout. - Amp, and Hermes without
agents_md, have no local file to load: nothing is written andgeneratewarns once per preset. cleanand preset or server removal leave no ai-rulez keys behind in hand-authored settings..claude/settings.json,.gemini/settings.json,opencode.json,.mcp.json,.agents/settings.jsonand.xum/mcp.jsoncthat you share with ai-rulez were never edited byclean, and the entries ai-rulez merged stayed after a preset or MCP server was removed; an overlay server's resolvedAuthorizationheader could outlive the overlay in a hand-written.claude/settings.json. ai-rulez now records what it merged (server entries, array elements, scalars) with a digest of each value (never the value itself): in the local manifest for a document shared with you, in the committed manifest for one it wrote whole.cleanremoves exactly that, only while the value is still the one written; an entry you edited stays and is reported once. It deletes a file nothing else is left in, andgenerateremoves what an earlier run claimed and the current config no longer produces, also after the overlay is deleted. A document without a record gets a fallback oncleanonly (never ongenerate): the servers the config names, when their value equals what the config renders, plus values ai-rulez writes itself. Seedocs/local-overrides.md.- Commented
opencode.jsonand.gemini/settings.jsonno longer stopgenerate. Both tools accept comments; a document with comments or trailing commas is left untouched with a warning when only theinstructionsorcontext.fileNameentry would be written. Writing MCP servers into one still fails with a hint, as before. cleanno longer prints the Geminicontext.fileNameadvice, androot.local_fileof a provider spec rejects backslashes, drive prefixes and the root file itself.AGENTS.local.md(codex or amp only),.hermes.local.md,.junie/guidelines.local.mdand Antigravity'sGEMINI.local.mdare no longer written; the firstgenerateremoves the ones an earlier version left, through the local manifest.
[4.23.0] - 2026-10-03¶
Added¶
config.local.*overlay: a machine-localconfig.local.{toml,yaml,yml,json}beside the main config is merged onto it at load time (scalars local-wins, maps per key,presetsas an ordered union with"!name"drops, named lists such asmcp_serversmerged by name withremove = true). It is gitignored, validated againstschema/ai-rules-local.schema.json, skipped for plugin bundles and never written back by config mutators.validateprints an overlay summary (key paths only).ai-rulez local(init,show,set,unset,path) edits the overlay;--localonprofile,includeandskill(andlocal: trueon the matching MCP tools) writes there instead of the shared config.local showwithholds values outside a small type-checked allowlist unless--revealis given,local set --stdinkeeps secrets out of shell history, and names containing dots are addressed asmcp_servers["foo.bar"].command. Local profiles may use local domains.- Local skills, agents, commands and domains:
.ai-rulez/local/mirrors the shared layout. Local domains follow the active profile,targetsapply, and local items are written to the same per-item paths as shared ones (a name collision with a shared item is an error). Copilot gets.github/instructions/ai-rulez.local.instructions.mdand AntigravityGEMINI.local.mdfor local context.add,removeandlisttake--localfor every content type, and the MCP CRUD tools takelocal: true. - Shared baseline and drift guard: with local configuration present,
generatealso renders the shared view and classifies outputs as local-only, drift or suppressed. Drift on a tracked or unignored shared file stops generation (paths only, also in a non-zero--dry-run) unless--allow-local-driftis passed on the command line; MCP clients cannot bypass it. Local-only paths go to a per-project block in.git/info/exclude, a gitignored.generated-manifest.local.jsontracks them so teammate-view runs never delete them, and shared outputs keep the sharedSource-Hash.--no-localongenerate,validateandtokens(MCPno_local) renders the teammate view and keeps the ignore entries of local files that exist.generaterefuses, listing the paths, when a machine-local or secret-bearing output, the overlay or thelocal/tree would not be git-ignored once the ignore entries are written (for example because a!rule un-ignores it).cleanremoves every file the local manifest lists, even after the overlay was deleted. - xum http/sse MCP servers (#208): remote servers are written as
{transport, url, headers}entries in.xum/mcp.jsonc, and disabled servers setdisabled: true. The secret guard now also covers.xum/mcp.jsonc, which must be gitignored when it holds resolved header secrets. agents_md = true(top-level, defaultfalse) renders the files several tools share once: oneAGENTS.md(nested<scope>/AGENTS.mdfor[[scopes]]) with the always-on rules and context, and one.agents/skillstree, read by thecodex,opencode,amp,xum,claude(through aCLAUDE.mdshim),gemini,antigravity,hermes,cursor,copilot,windsurf,cline,continue-devandjuniepresets. Tools with a rules folder keep their path-scoped, auto and manual rules there; root files that would shadowAGENTS.mdare no longer written. With the flag off, output is unchanged from 4.22.2.
Changed¶
.gitignoremanagement adds only what git does not already ignore:generatechecks each entry withgit check-ignoreagainst all ignore sources (with its own block left out, without touching your files) and skips entries you already ignore or have un-ignored with a!rule; the managed block is removed when empty. Machine-local and secret outputs you un-ignored stay out of the block with a warning. Outside a git repository every entry is still added. A.gitignorethat is a symbolic link is never written through (git does not read it): all entries go to a per-project block in.git/info/excludeinstead, and ignore files are read with a size limit, so a link to a device cannot hanggenerate.- poly hook catalog:
ai-rulez-validate,ai-rulez-generateandai-rulez-recursivepass--no-local, so hooks render the shared view and never fail on, or write, a developer's machine-local configuration. - Config writes keep the file mode of an existing config instead of resetting it to
0644. - MCP
add_includedefaultsmerge_strategytolocal-override(it previously sent a value validation rejected).
Fixed¶
- Gemini agents are written to
.gemini/agents/<id>.md, the only project location Gemini CLI loads subagents from;.agents/agents/was never read. The old files are removed on the nextgenerate(files other tools still write there stay). Every agent now has the requireddescription(a generic one when the source has none), and a bare Claude model alias (sonnet,opus,haiku) is omitted with a warning so the agent inherits the session model;gemini_modelanddefaults.model_by_preset.geminiare written as given. - xum disabled stdio MCP servers are written as
{transport: "stdio", command, disabled: true}instead of an enabled command string, and a server withenvwarns that Xum'smcp.jsonccannot set environment variables (Xum reads only the command string of a stdio entry).
Security¶
- Generated files that contain resolved MCP secrets (
.mcp.json,.claude/settings.json, ...) are written0600, and an existing world-readable file is tightened. Credentials in a server URL (user info,?token=-style query values), in secret-looking flags (names ending intoken,key,secret,password,authorcredential;--max-tokens,--api-key-fileand numeric values are not), inAuthorization: Bearer ...args and in URL-valued args and env values count as secrets too, andgeneraterefuses to write such a config unless it is git-ignored; the error lists every path. - Include and skill sources are logged and returned with URL credentials and query-string values redacted.
[4.22.2] - 2026-10-03¶
Fixed¶
- Generator schema v8 forces a one-time rewrite of existing generated files.
- Cursor agents are written to
.cursor/agents/<id>.md, which Cursor reads;.agents/agents/is not a Cursor agent location. The old files are removed on the nextgenerate.readonlyandis_backgroundare written as YAML booleans; unparsable values are omitted with a warning. - OpenCode agents with a bare model alias (
model: sonnet, the Claude form) are no longer written as is. OpenCode needsprovider/model: it silently dropped the whole agent file, or failed the session withModel not found: sonnet/..generatenow omits an unqualified model with a warning, so the agent inherits the session model; setopencode_modelin the agent frontmatter ordefaults.model_by_preset.opencodeto pin one. Surrounding whitespace in a model value is trimmed for every preset. - OpenCode agent variant is written as a separate
variant:key next to a plainprovider/model, because markdown agents do not accept themodel#variantform (onlyopencode.jsondoes). A#variantin the source model is split off and wins over the configured effort. - OpenCode agent
hidden,temperatureandtop_pare written as a boolean and top-level numbers instead of quoted strings (and no longer underrequest.body), which OpenCode rejected; unparsable values are omitted with a warning.
[4.22.1] - 2026-10-03¶
Fixed¶
- Cursor
globsis written as the bare comma list Cursor's own rule files use (globs: **/*.go,**/*.ts) instead of a quoted YAML string; unusual values keep the quotes. Windsurf, Antigravity and Copilot keep quoted values. Generated files are rewritten once on upgrade (generator schema v7). - Negated globs (
!x) are dropped from the frontmatter of every dialect, not only Copilot, with a warning. A rule whose globs are all negated stays in the root file where the preset has one and is otherwise written as an always-on rule file. - Junie
_Applies to: ..._lines format globs as code spans, so_and*in a glob are no longer read as emphasis. AGENTS.mdis identical acrosscodex,opencode,xumandamp: theamppreset no longer includes contextsummarylines inAGENTS.md, which the other three never emitted, so the shared file renders the same whichever preset writes it.- Scoped
autoandmanualrules are written to the root rules folder without a path restriction, as before;generatenow warns once per scope about it. targetsnaming a root file by its base name (copilot-instructions.md,guidelines.md) now selects that preset's root file and rule files, like a rule file's base name does.validatewarns when a legacy always-on activation (trigger: always_on,alwaysApply: true) comes withpaths, which are ignored.- Claude rule file names keep the case of the source name (changed in 4.22.0, for example
API-Design.md); rename a source if you relied on lowercase names. - Rules no longer vanish when a rule file name is taken: a hand-written file such as
.claude/rules/testing.mdthat collides with a generated rule is left alone and the rule is written totesting.ai-rulez.md(<id>.ai-rulez.instructions.mdfor Copilot) with a warning naming both. The renamed file is recorded in the manifest, gitignored per file, and removed once the collision is gone.generate --dry-runlists the renamed file and no longer lists files the overwrite guard skips. The.ai-rulezname is what the tool sees (for exampletesting.ai-rulezin the rule list), so rename the hand-written file if that matters. - Rule names that map to the same file id no longer abort generation (the previous behaviour):
api_style/api-style,Foo/fooorC++ style/C stylekeep the first source, sorted by path relative to the config dir (includes sort asinclude:<name>/<path>), under the plain name, and the later ones get a-<6 hex of sha1(that path)>suffix, with a warning. The same applies to machine-local rules (<id>-<hash>.local<ext>). The suffix does not depend on the checkout location or the machine, but adding or removing a rule that sorts earlier can move the plain name to a different rule. Generation still fails if the suffixed name is also taken. - Custom provider specs with
outputs.rules.split = trueget the same protections as the built-in rules folders (overwrite guard, hashes in the banner, per-file gitignore), anddiris now required for them and must be a relative path inside the project. - Provider specs without
splitthat write into a rules folder now carry a hash banner, so they are no longer rewritten on every run or mistaken for hand-written files. - Ownership check for rule files only trusts a generated-file banner at the top of the file (first comment after the frontmatter), not a marker quoted anywhere in the first 16 KB. Frontmatter delimiters with CRLF line endings are read the same as LF, and
.mdheader stripping only removes a banner at the start of the file, so a-->in the body (for example fenced HTML) no longer changes the content hash.
[4.22.0] - 2026-10-02¶
Added¶
- Copilot path-specific instructions: path-scoped rules and context are written to
.github/instructions/*.instructions.mdwithapplyTofrontmatter (all rules with[rules] mode = "split"); the rest stay in.github/copilot-instructions.md. [rules] modeandmode_by_preset: config for choosingsplitorinlinerules output, globally or per preset, validated byvalidateand the JSON schema. MCPupdate_configacceptsrules_modeandrules_mode_by_preset, andread_configreturns both. The default issplit, which writes every rule to the tool's native rules folder for presets that have one;inlinekeeps them in the root file.- Rule
activationfrontmatter: rules and context files can setactivationtoalways,glob,autoormanual.validaterejects unknown values,globwithout globs,autowithout a description andalwaystogether with globs, and warns when a legacytriggeroralwaysApplycontradicts it. Comma-separatedpaths/globssuch aspaths: "src/**, docs/**"now split into separate globs (commas inside{},[]or escaped with a backslash are kept). Anactivationkey is no longer passed through as an extra frontmatter field. - Antigravity
.agents/rules: the antigravity preset writes rules as native rule files withtrigger/globsfrontmatter (top level only). The defaultsplitmode moves every rule there;inlinemoves only path-scoped rules. When the gemini preset is also enabled both writeGEMINI.md, so rules stay inline unlessrules.mode_by_preset.antigravityis set. - Junie
.junie/rules: in the defaultsplitmode Junie writes each rule to.junie/rules/<id>.md;inlinekeeps everything in.junie/guidelines.md. - Provider specs:
outputs.rulesacceptssplit,inline_filteranddialectso a custom provider can opt in to split-aware rules output. - Local rules as native rule files: where a built-in preset routes rules to rule files, rules in
.ai-rulez/local/rulesbecome<rulesdir>/<id>.local<ext>(for example.claude/rules/my-rule.local.md) instead of landing inCLAUDE.local.md, so the tool loads them natively. Routing is the one shared rules use: every rule with[rules] mode = "split"(and always for Cursor, Windsurf, Cline and Continue), only path-scoped rules in inline mode for presets that scope rules, and Copilot still keeps auto, manual and negated-only rules inline. The files are gitignored through one<rulesdir>/*.local.*pattern, written only after that ignore entry is in place, and listed in a new gitignored.ai-rulez/.generated-manifest.local.jsoninstead of the committed manifest, so a teammate's run never deletes them (cleanremoves them through it). Names matching*.local.*in a rules folder are reserved for ai-rulez local rules: an existing hand-written file with such a name is skipped with a warning. Local context still goes to the.localroot file, and custom provider presets get no local rule files. Local rules and context a preset has no place for (for example local context with Cursor, or unscoped local rules with Copilot in inline mode) are not written and are reported in one warning per preset. Newconfig.LocalRuleProviderhook.
Changed¶
- BREAKING: rules are split into native rules folders by default: the default
[rules] modeis nowsplit. Claude writes rules to.claude/rules/*.md(CLAUDE.md keeps context), Copilot to.github/instructions/*.instructions.md(auto and manual rules stay inline), Junie to.junie/rules/and Antigravity to.agents/rules/(inline when the gemini preset is also enabled). Set[rules] mode = "inline"(ormode_by_preset) to keep the previous layout. Stale inline content is removed on the nextgenerate. ai-rulez tokensrule-file accounting: path-scoped rule files count as conditional, manual rules as on-demand, and agent-requested rules split into an always-loaded description and an on-demand body, instead of all counting as always-loaded.- Claude rule files: path-scoped rule files in
.claude/rulesnow carry a generated banner, and path-scoped context is written to.claude/rules/context-*.md. With[rules] mode = "split"Claude and Junie write every rule to their rules folder instead of the root file. Claude rule file names keep the rule name's case. Generated files are rewritten once on upgrade (generator schema v6). Rule names that differ only in case or collide after sanitizing (including a context filexagainst a rulecontext-x) now fail generation in every rules-folder preset instead of silently overwriting each other; the customdirectorypreset is not part of this check. Names with no ASCII letters or digits (for example CJK-only) get a stablerule-<hash>file name instead of failing. - Scope shown for rules inlined into root files: rules inlined into root files (
AGENTS.md,GEMINI.md, ...) now state their path scope (_Applies to: ..._) or trigger description (_When relevant: ..._) instead of silently becoming global.manualrules still render as always-on and log one warning listing them. - Rule files are processed like inline rules: bodies in per-rule files (Cursor, Windsurf, Cline, Continue, Copilot, Antigravity, Claude) now have a leading H1 that repeats the rule name removed.
- Legacy Cursor
alwaysApply: falsenow means agent-requested (when a description is set) or manual (without one) instead of always-on. - Rule-file freshness hashes now live in the generated banner instead of the frontmatter, because the tools' frontmatter parsers are not documented to tolerate YAML comments. Rules-folder files written by earlier versions are rewritten once to move the hashes.
- Copilot:
autoandmanualrules stay in.github/copilot-instructions.mdinstead of becoming instructions files withoutapplyTo, which Copilot would not apply automatically. Negated globs (!x) are dropped fromapplyTowith a warning, and a rule whose globs are all negated stays incopilot-instructions.md. - Antigravity: explicitly splitting rules while the gemini preset is enabled warns that they load twice; the quiet default demotion is only logged at info level when it actually costs rule files.
- Scoped rule files go to the root rules folder: for
[[scopes]], rules-folder presets (claude, cursor, copilot, windsurf, cline, continue-dev, antigravity, junie) no longer write<scope>/.claude/rules,<scope>/.cursor/rulesand so on, which tools do not read. Scoped rule files, and scoped context that becomes a file, are written to the root folder as<dir>/<scope-slug>/<id>(Claude, Cursor, Copilot) or<dir>/<scope-slug>--<id>(Windsurf, Cline, Continue, Antigravity, Junie). Their globs are relative to the scope root and get the scope path as prefix; rules without globs, or with only negated globs, apply to<scope>/**;autoandmanualrules keep their mode; a glob containing..(also inside braces) skips that rule for the scope with a warning. With[rules] mode = "inline"only path-scoped items move; the rest stays in the scope's root file. Rule files of the root and all scopes that map to the same path, or two scopes whose paths sanitize to the same slug, fail generation. Previously generated<scope>/.../rulesfiles are removed on the nextgenerate, andcleanremoves the emptied scope subfolders and lists them in--dry-run. - Scopes no longer repeat root domains: a scope renders only the domains of its profile that the root output does not already contain (builtin, include and root-profile domains are skipped), and a scope left empty writes no files. Scope paths are validated: relative, no
.., no glob characters. - Scoped inline remainders for Copilot and Junie: these tools read their root file at the repository root only, so inline rules and context in a scope's copy are never loaded;
generatewarns and names them (seedocs/monorepo.md). - Activation warnings: an unknown legacy
triggeroralwaysApplyvalue is reported byvalidateandgenerateas a warning naming the file;triggeris matched case-insensitively. The downgrade summary now covers every rules-folder preset. - Frontmatter
targetsnow restrict rule outputs: they previously only applied to targeted sections, commands and skills, so a rule targeted atCLAUDE.mdalso landed in.cursor/rules/. A target now selects an output by preset name (case-insensitive), root file, file path or base name, directory prefix (.cursor/rules/), or glob. This applies to every rules-folder file (Claude, Junie, Copilot, Antigravity, Cursor, Windsurf, Cline, Continue) and to the inlined root filesCLAUDE.md,AGENTS.md(codex, opencode, xum, amp),GEMINI.md(gemini, antigravity),.hermes.md,.junie/guidelines.md,.github/copilot-instructions.mdand the*.local.mdvariants. A root file shared by several presets is selected by the name of any of them, so it stays identical whichever writes it. A rule targeted only at skill or agent files (for example.claude/skills/*/SKILL.md) no longer appears in any root file, and one targeted only at a rules folder (.junie/rules/) is written as a file even ininlinemode (Junie and providers withoutinline_filterwrite no files ininlinemode, so it is omitted there). Rules withouttargetsare unaffected, and root files of unrelated presets that previously inlined everything lose the items targeted elsewhere. - Target matching is unified: one matcher now serves rule files, root files, skills/agents sections and provider filters. Paths compare case-insensitively,
\and a leading./or/are accepted,dir/*anddir/**cover the whole directory tree, and a bare*or**matches every output. Malformed glob targets (such as[x) never match;validateandgeneratewarn about them.
Fixed¶
- Include and skill-source git URLs no longer leak credentials (
https://TOKEN@host/...) into--debuglogs, error context or echoed git output; userinfo is shown as<redacted>. - Cline rules (
.clinerules/) now honorpaths/globs: scoped rules and context files getpathsfrontmatter, which was previously dropped. - Continue rules (
.continue/rules/) now carry thenameContinue requires, plusglobs,alwaysApplyordescriptionaccording to the rule's activation. - Windsurf rules honor
paths/globsand emitglobs:instead ofglob:. Untriggered rules are written astrigger: always_on(Windsurf treated them as manual), and context files now get frontmatter. Legacytrigger/glob/descriptionkeep working, and files over Windsurf's 12000-character limit log a warning. - Cursor context rules were manual-only:
context-<name>.mdcfiles had no frontmatter, so Cursor never applied them automatically. They now getalwaysApply: true, orglobswhen path-scoped. Cursor rules and context are rendered by the shared rule-file renderer, so globs with braces such as*.{ts,tsx}are expanded (*.ts,*.tsx), which Cursor needs; rules withactivation: manualget an explicitalwaysApply: false. - Generated rule files are gitignored per file (for example
.claude/rules/x.md) instead of the whole rules folder, so hand-written rules in the same folder are no longer ignored. generateno longer overwrites a hand-written rule file in a native rules folder that collides with a generated rule name. It warns and skips the file; rename one of them.- A legacy
trigger: globwithout globs, andmodel_decision/autowithout a description, are written as manual instead of always-on. Cursorautorules now carry an explicitalwaysApply: false. - Hash detection no longer gives up on frontmatter longer than 60 lines.
[4.21.0] - 2026-10-02¶
Added¶
headerson[[mcp_servers]](#206): remote (http/sse) servers can send HTTP headers, typically for auth, e.g.headers = { Authorization = "Bearer ${TOKEN}" }. Values resolve${VAR}placeholders likeenv, and every preset that renders remote servers (Claude.mcp.jsonand.claude/settings.json, Cursor, Copilot, Gemini, OpenCode, Antigravity) writes them asheaders. A header holding a placeholder or a credential (Authorization,Proxy-Authorization,Cookie, or a sensitive name) is treated as a secret: redacted from the source hash, and generation refuses to write it into an MCP file that is not gitignored.validaterejects headers on stdio servers, invalid or case-duplicate header names, and values containing line breaks. Plugin bundles do not carry headers;generate --pluginwarns per affected server and does not require header placeholders to resolve.[header] hashes: chooses the freshness lines in generated headers."full"(the default, unchanged) writesContent-HashandSource-Hash;"content"keeps only the per-fileContent-Hash;"none"writes neither.Source-Hashhashes the whole source set, so when generated output is committed, editing one skill rewrote a line in every generated skill, agent andCLAUDE.md, and concurrent branches conflicted. With"content"or"none"an edit changes only the outputs it feeds. In these modesgenerateskips a file only when it is byte-identical to what would be written (theGenerated:text is ignored undertimestamp = true), so header-only changes such as[header] stylestill re-render.cleanandverify --pluginare unaffected. Switching modes re-renders every file once. Invalid values are rejected byvalidateand the JSON schema.
Fixed¶
- Secret guard missed
opencode.json: MCP secrets resolved intoopencode.jsonwere written even when the file was not gitignored. It is now protected like.mcp.jsonand the other MCP settings files.
[4.20.1] - 2026-10-02¶
Fixed¶
- CRUD commands with
.config/ai-rulez/(#207):add,remove,list,domain,profile,include,skilland the MCP CRUD tools only looked for.ai-rulez/and failed with.ai-rulez directory not foundin a project using the.config/ai-rulez/layout. They now resolve the config directory the same waygenerateandvalidatedo. The MCPupdate_configtool likewise saved to a new.ai-rulez/instead of the directory it loaded, which then took precedence over.config/ai-rulez/.
[4.20.0] - 2026-10-02¶
Added¶
[mcp] self_server:generatecan now add ai-rulez's own MCP server (npx -y ai-rulez@<version> mcp,"type": "stdio") to the project.mcp.json. The entry is merged into an existing file, so hand-authored servers survive, and.claude/settings.jsonis not touched. The version defaults to the running binary (latestfor a dev build);self_server_versionpins it andself_server_commandreplaces the launch command. Also adds thehas_mcp_json_entriessidecar predicate for provider specs.validate --recursive/-r: validates every discovered config root and exits non-zero if any is invalid.
Fixed¶
generate --recursiveexit status: a root that failed to load, validate, or generate was reported but the process still exited 0 (also with--dry-run). All roots are still processed and all errors printed, but the exit status is now 1 if any failed. Failures are also printed in quiet mode and are attributed to the right config when roots run concurrently.cleandeleting merged settings documents:cleanremoved a merged file such as.mcp.jsonor.claude/settings.jsonwholesale, taking hand-authored servers and settings with it. A merged document that holds content ai-rulez did not write is now left in place.validate --quiet:validateignored--quiet, so discovery progress and per-root success lines were still printed.
[4.19.0] - 2026-10-02¶
Added¶
- Project-level
.config/convention: configuration discovery now also accepts.config/ai-rulez/(the.configproposal) as a fallback to the tool-specific.ai-rulez/. The CLI, recursivegenerate, MCP recursive discovery, generated headers, and the managed.gitignoreblock all resolve the active config directory, and.ai-rulez/still wins when both layouts exist at the same level.ai-rulez init --config-dir .config/ai-rulezscaffolds the new layout.
Changed¶
- Generated headers follow the config directory: banners now name the real source path
(
.config/ai-rulez/config.tomland.config/ai-rulez/rules/…) instead of a hardcoded.ai-rulez/.GeneratorSchemaVersionis bumped soSource-Hashvalues written by 4.18.0 no longer match and every file is re-rendered once.
[4.18.0] - 2026-10-01¶
Added¶
- Custom header text (#203):
[header] textaccepts a multi-line string that replaces the banner generated fromheader.style. Useful when the predefined prose does not match the environment — for example the default banner recommendsnpx, but a project manages tools withmise. The text is written verbatim, wrapped in the output's comment syntax, and still carries theContent-Hash/Source-Hashfreshness lines, so hash-based regeneration keeps working.styleis ignored whiletextis set.
Fixed¶
-
Rules and context render in priority order again (#204): the generated files listed rules and context alphabetically by name instead of by the documented
priorityfrontmatter (critical → high → medium → low → minimal, name breaking ties). The priority sort was dropped in favor of alphabetical output for determinism; ordering is now priority desc with a name tie-break, which is deterministic and matches the docs. Context gains the same ordering as rules. -
Regeneration is forced once after the ordering fix:
GeneratorSchemaVersionis bumped, soSource-Hashvalues written by earlier versions no longer match and every file is re-rendered on the nextai-rulez generate. -
Generated
opencode.jsonstays a managed artifact: theopencodepreset now owns the top-level$schemakey alongsidemcp.servers, and writes it into a freshly generated document. Previously a generatedopencode.jsoncarried no$schema, so an editor that added one (or a user who did) flipped the file to "partially owned", which drops it from the gitignore/manifest set and made everygeneratedisagree with the committed.gitignore. A file that adds real settings (model,mcp.timeout, …) is still treated as the consumer's and preserved.
[4.17.0] - 2026-09-30¶
Added¶
-
Path-scoped rules (#199): a rule may declare
globs/pathsin its frontmatter (two spellings of the same path scope). A path-scoped rule is kept out of the root instructions file and delivered through the target tool's on-demand mechanism:claudeemits.claude/rules/<id>.mdwith apaths:field (a new provideroutputs.rulesoutput plus apath_scopedfilter), andcursoremits a.mdcwithglobs:andalwaysApply: false. Presets without a glob mechanism (for examplecodex) keep the rule inline. This lets one source keepCLAUDE.mdsmall without a hand-maintained Claude-only copy. -
Cursor rule frontmatter (#198):
.cursor/rules/*.mdcnow carry the frontmatter Cursor reads —alwaysApply: truefor unscoped rules, orglobs:withalwaysApply: falsefor path-scoped ones — plus the sourcedescriptionwhen set. Previously a generated rule had no frontmatter and was manual-@-mention-only. -
Profile-scoped MCP servers and installed skills (#202):
[[mcp_servers]]and[[installed_skills]]accept aprofileslist. The server or skill is emitted only when the active profile names it; omittingprofileskeeps today's include-everywhere behavior. -
defaults.omit_agent_fields(#197): suppresses named agent frontmatter fields (model,effort,tools,description) for every preset, so an agent stays loadable in a tool where a field would be invalid — an unconfigured model or provider, or a tool name the tool does not recognize.
Fixed¶
-
Generated agents are spawnable as subagents (#196, #200): the
opencodepreset now defaults an agent tomode: allinstead of OpenCode's implicit primary-only, and thexumpreset emitssubagent: {runnable: true}. Both could be used as a primary only before. -
Scoped outputs no longer repeat the root content (#201): a
[[scopes]]file contained the root rules and context in addition to the scope's own; the target tools load a subdirectoryCLAUDE.md/AGENTS.mdon top of the root file, so this duplicated the always-loaded text. A scope now contains only its profile's domains. -
The
add_includeMCP tool schema and the repo's own poly hook catalog were stale: the tool advertised the removeddefault|override|appendmerge values and anmcpcontent type, and the hook catalog listed the removedenforcecommand. Both corrected. -
Documentation: a second full pass corrected invalid TOML examples, the go-install guidance (the module path has no
/v4suffix, sogo install …@latestresolved to 1.x), marketplace/render paths, and more.
[4.16.0] - 2026-09-30¶
Added¶
${PROJECT_ROOT}for MCP servers: an MCP server'scommandorargsmay use the${PROJECT_ROOT}placeholder, resolved at generation time to the project root (the directory containing.ai-rulez/). It lets a server that requires an absolute path avoid a hardcoded, machine-specific one;envvalues resolve it too unless a realPROJECT_ROOTis supplied via--env, the process environment, or a dotenv file. Because it resolves to a machine-specific path, generated output carrying it must be gitignored or regenerated per machine. The source hash keeps the literal token, so it stays stable across checkout roots. (For Claude Code,${CLAUDE_PROJECT_DIR:-.}inargsremains the portable native alternative and passes through unchanged.)
Fixed¶
-
ai-rulez validatenow checks the schema: the raw config file is validated againstschema/ai-rules.schema.json(TOML is converted to JSON first), so an unknown key or a value outside an enum is reported rather than silently dropped. V3 configs still get the structural checks only. The schema itself gained the consumerplugins/marketplacesarrays (previously rejected underadditionalProperties: false), the correct includes enums (commands,include-override,local_override), the missing builtin names (docker,cicd,observability,polyglot-bindings,vite-plus), the TOMLschema/$commentkeys, and lost the dead deprecatedcompressionproperty. -
include add --merge-strategywrote a value the resolver rejected: the CLI accepteddefault|override|appendand stored the value verbatim, but the include resolver only acceptslocal-override|include-override|error, so an added include was silently skipped at generation. The CLI and CRUD layer now use the resolver's values (local-overrideis the default). -
The
popularpseudo-preset: it was not a registered built-in and had no generator, so MCPinit_projectwithpopular_providerswrote a config that failed validation. It now emits the curated provider set.AllPresetNames/IndividualPresetNamesare derived from the built-in registry, so they includeopencodeandmcpand can no longer drift. -
Documentation audit: corrected ~50 inaccuracies across
README.mdanddocs/— stale preset output paths (amp→AGENTS.md/.agents/,windsurf→.windsurf/,.cursorrules→.cursor/rules/), V3-YAML examples labelledconfig.toml, the fictional custom-preset template-function reference (now describes the implementedtext/templatebehavior and points at provider specs), wrong[[plugins]]/[[marketplaces]]fields, theadd skill --priorityexample, exit codes, and more. The builtin-agent table,go installpath, and builtins list in the shipped skill were also corrected.
[4.15.0] - 2026-09-30¶
Added¶
-
Profile-scoped builtin domains (#195): a profile's domain list may reference a builtin pack as
builtin:<name>(e.g.builtin:docker). The pack is loaded for that profile only, instead of every profile. This works even when the rootbuiltinsfield is absent orfalse— a profile reference is an explicit opt-in — and thebuiltin:prefix keeps the pack from colliding with a local domain of the same name. A pack the rootbuiltinsfield already enables stays globally active rather than being downgraded. Validation andprofile addaccept the prefixed form and reject an unknown pack. -
OpenCode v2 preset output (#194): the
opencodepreset emits a native v2opencode.jsonwith MCP servers undermcp.servers(typeoflocal/remote,disabled,commandas a single array,environmentfor stdio). The file is merged, so every other key in a hand-authoredopencode.json— including a siblingmcp.timeout— is preserved. Agent frontmatter moves to the v2 shape: effort becomes a modelvariantjoined asmodel#variant,temperature/top_pmove underrequest.body, and the non-schemanamekey is dropped because the filename is the agent ID. -
OpenCode v2 plugin adapter (#194): the plugin runtime now emits an OpenCode v2 plugin —
Plugin.define({ id, setup })from@opencode/plugin— instead of the v1 function entrypoint that v2 refuses to run, and bundles the plugin's skills, commands, and agents under.opencode/.
Changed¶
- Merged JSON documents can own a nested key path:
jsonmergenow supportsOwnedKey.Path, letting a generator ownmcp.serverswhile preserving sibling keys under the same ancestor, and the partially-owned check recurses to match.
[4.14.1] - 2026-09-29¶
Fixed¶
- Windows CI for the 4.14.0 test suite: two new tests (
TestRenderAgentPlugins_ManifestSkillsAndMCP,TestGeneratePresets_ProviderBacked) keyed outputs by a slash-normalized path but looked them up with a nativefilepath.Join, so they failed on Windows only. No runtime behavior changed; this patch supersedes the redv4.14.0tag with a green one.
[4.14.0] - 2026-09-29¶
Added¶
-
xumbuilt-in preset (#190): generates project files for the Xum coding agent — a sharedAGENTS.md, skills under.xum/skills/<id>/SKILL.md, agent definitions under.xum/agents/<id>.mdwith Xum's frontmatter shape (ai.model,ai.thinkingLevel,tools.add), and stdio MCP servers in.xum/mcp.jsonc. Effort tiersxhigh/maxmap tohigh, matching Xum'sthinkingLevelvocabulary; remote (http/sse) MCP servers are skipped with a warning because Xum's command-string format is stdio-only. -
Provider-backed custom presets (#191): a
[[presets]]entry may setprovider = "<project-relative spec path>"to reference a declarative provider spec instead of a template. A provider spec carries the full built-in feature set — root instructions file, skills/agents/commands, per-agent frontmatter, effort/model, and MCP sidecars — so custom tools no longer stop atmarkdown/directory/json. The spec is validated atvalidate/generate time, must stay inside the project root, and itsnamemust match the preset's. TOML configs now also accept custom and provider presets as inline tables (presets = ["claude", { name = "my-tool", provider = "..." }]), which they previously could not express at all. -
Agent Plugins 1.0.0 plugin runtime (#193): the opt-in
agent-pluginsruntime packages a plugin in the portable Agent Plugins standard form — a rootplugin.json, a rootskills/directory, and a rootmcp.jsonusing the standard's closed server variants (stdio,streamable-http,sse). It is not in the default runtime set, so existing bundles are unchanged; enable it withruntimes = ["agent-plugins"]. Authored plugin names are validated against the standard's grammar, and${PLUGIN_ROOT}-rooted MCP commands are rewritten to the plugin-relative./form the standard requires.
Fixed¶
- CRUD commands wrote
config.yamlinto TOML-only projects (#192):skill install/remove,profile add/remove/set-default,include add/remove, and the MCPupdate_configtool all rewrote the configuration throughSaveConfig, which only knew aboutconfig.yamlandconfig.jsonand fell back to YAML when neither was present. On a V4 project (config.toml) this created a spuriousconfig.yamlthat the loader then shadowed, so the mutation was silently lost.SaveConfignow writes back in the file's actual format, preferringconfig.toml, thenconfig.yaml/config.yml, thenconfig.json. Consequence: TOML parsing does not round-trip comments, so a hand-commentedconfig.tomlloses those comments when a CRUD command rewrites it; the file keeps a standard header pointing at the documentation.
Changed¶
ai-rulez migrate v4now shares one TOML serializer withSaveConfig. The serializer previously flattened every preset to its name, which would have dropped custom/provider presets; it now emits built-in presets as strings and custom/provider presets as inline tables, and preserves all fields (includingdefaults,scopes,compact,plugin, andmarketplace).
[4.13.0] - 2026-09-27¶
Added¶
-
ai-rulez tokens: reports the prompt-token cost of the generated configuration, split by when an agent actually loads it. Artifacts are measured as rendered strings in memory at the same seamgenerate --dry-runwalks, so nothing is read back off disk and a stale or half-written output tree cannot corrupt the numbers. Output is grouped per runtime and then per bucket —always(the root instructions file, skill and command names, agent names and descriptions),conditional(skill and command descriptions, which some harness modes carry and others do not),on demand(bodies), andunmodeled(cost ai-rulez cannot see, such as the tool schemas an MCP manifest implies). The root file is broken down per section with rules and context listed individually, so an expensive one can be named; skill names, descriptions and bodies are separate lines, because a single per-file total hides which part is being paid for. Flags:--json/-j,--budget/-b(exit 2 when the headline is exceeded, distinct from 1 so a hook can tell over-budget from failure),--compare-profiles(renders several profiles in one process and prints a table),--tokenizer(cl100k_base, embedded, offline, no API key — orestimatefor a byte ratio), plus the usual--profile/-pand--config-dir/-n. The report states its own limits in its output: counts are approximations because Claude's tokenizer is not published (cl100k_basemeasured 8% low against one real 19,230-byte instruction file); runtimes are not additive, since one session loads one root instructions file, so emitting bothCLAUDE.mdandAGENTS.mdcosts one of them and the headline is the largest single runtime rather than the sum; and ai-rulez counts only what it generates, never predicting a session total, because the harness's own system prompt, tool schemas and per-artifact overhead are invisible to it. Two consequences worth knowing: the per-fileContent-HashandSource-Hashlines cost about 76 tokens per artifact, because a blake3 hex digest is incompressible, and the## Agentsroster in the root file duplicates every agent file's name and description. -
Composed profiles: a profile value may name several profiles separated by commas —
--profile base,backend, ordefault = "base,backend"in the config — and resolves to the de-duplicated union of their domains, ordered by first mention. This is what a shared baseline plus role-specific extras needs: onebaseprofile everybody installs and one profile per role, instead of a hand-written profile for every base-and-role pair. A single name behaves exactly as before, including the built-indefaultfallback, which differs depending on whether any profiles are defined at all. An unknown element is an error naming that element rather than echoing the whole value, with the same available-profiles hint. Whitespace and empty elements are ignored (base, backendandbase,backend,select the same two profiles); a value that is nothing but separators selects nothing and is reported as not found. Profile values list domains only — composition is one level deep, so there is no nesting and no cycle to detect — and a profile name may no longer contain a comma, since it could never be selected. Composition applies wherever a profile is named, including a[[scopes]]entry'sprofileandai-rulez tokens.tokens --compare-profilesis now a repeatable flag rather than a comma-splitting list, because a comma composes: pass it once per column (--compare-profiles base --compare-profiles base,backend).
Changed¶
-
The
Generated:header line is now off by default. Generated output is byte-reproducible unless a project asks for a per-run value: the same sources generate the same bytes, output can be verified by content hash, andCLAUDE.mdandAGENTS.md— which the minimal header renders identically, since it carries no per-output field — can no longer disagree. They did before, because every preset calledtime.Now()for itself, so the two renders straddling a second boundary produced files differing in exactly that line; downstream completeness checks had to special-case it to compare them at all.[header] timestamp = trueopts the line back in. Upgrading: the source hash already coveredheader_timestamp, so the firstgenerateafter upgrading rewrites every output once to drop the line, and runs after that are byte-stable; a project that wants the line must now say so. When it is enabled, one run resolves the timestamp once and stamps every file it writes with that value, andSOURCE_DATE_EPOCHpins it (an unparsable value is ignored in favour of the wall clock) so an opted-in project can still be reproducible. -
Builtin rules cut roughly in half, with narrow guidance moved to skills. Everything in a builtin pack's
rules/directory is concatenated into the generated root instruction file, so it is re-read on every request of every session; a skill costs its name until it is invoked.
Two scopes, both measured on the generated CLAUDE.md, and worth not confusing: across the seven auto-included packs — what a project gets without naming anything — 33 rules / 11,596 bytes become 18 rules / 5,351 bytes, a little over 1,500 tokens back per request at the ~3.9 bytes/token rate that generated instruction prose measures at. Across all thirteen universal packs, including the opt-in docker and observability, 40 rules / 14,421 bytes become 23 / 7,209 bytes. Neither figure is the other; the corresponding source rules/ trees go 10,033 → 3,929 bytes and 12,365 → 5,342 bytes.
Seventeen rules stopped being rules. Fifteen were moved into skills, not deleted, because they only matter once you are already in a specific activity — writing a test, writing an error path, writing a Dockerfile — which is exactly what a skill's description is for:
code-quality:readability-first,complexity-limits,dead-code,avoid-duplicationandanti-patterns→ thecode-quality-standardsskill;error-handling→ theerror-handlingskill. The pack now ships skills only.testing:tdd-workflow→ thetdd-workflowskill;meaningful-assertions,test-independence,test-namingandtesting-anti-patterns→ thetesting-conventionsskill.test-alongside-codestays a rule — "tests ship with the change" has to land before the change is written — and now points at both skills.token-efficiency:task-runner→ thetask-runnerskill (it only applies to a repository with aTaskfile.yaml, so it was never universal);incremental-approach→ theincremental-approachskill.docker:container-standards→ a skill of the same name.observability:observability-standards→ a skill of the same name. Neither pack is auto-included, but both were a single technology-scoped rule loaded unconditionally once opted into, and both packs now ship skills only.
verify-before-acting was merged into verification-before-completion, which said the same thing about the other end of the task; the state-checking clause (branch, working directory, running processes) is preserved in the survivor. batch-operations was merged into incremental-approach, losing only its instruction to issue independent tool calls in parallel, which every current agent harness already states in its own tool documentation. branch-hygiene lost "use descriptive branch names", which no project without its own naming convention benefits from and every project with one overrides.
Existing !domain/rule exclusions keep working. The per-item exclusion is keyed by name, not by content type, so !testing/tdd-workflow now suppresses the skill. The five converted rules that collapsed into code-quality-standards and the four that collapsed into testing-conventions no longer have individual keys.
Eight new skill names are now claimed by builtin packs: code-quality-standards, error-handling, tdd-workflow, testing-conventions, task-runner, incremental-approach, container-standards and observability-standards. These are names a project plausibly already uses for a skill of its own. A project skill with the same name as a builtin skill shadows it — that is the documented precedence, root content over builtins — so check for a collision if you enable one of these packs and a skill of yours stops behaving as written. Exclude the builtin with !<domain>/<name> to be explicit about which one you mean.
-
The eighteen surviving builtin rules were tightened: frontmatter-plus-heading wrappers around a single sentence removed, and duplicated guidance cut to one owner —
communication-styleno longer restates commit formatting (git-workflow/commit-messagesowns it, and the contradiction between the two made downstream projects override one of them),atomic-commitsno longer repeats the conventional-commit type list, andoutput-awarenesskeeps only whatcommunication-styledoes not already say. -
The README and
docs/configuration.mddescriptions of what each builtin pack contains now match the packs. Both listed rules that are skills, or had moved, and both claimed thatcode-qualityandtesting"remain inline" whencode-qualityno longer ships a rule at all. The universal-domain table indocs/configuration.mdwas also missingagent-delegation,cicd,dockerandobservability, and marked onlyai-governanceas auto-included when six others are.
Documentation¶
- Documented how to drop the
## Agentsroster from the generated root instructions files:builtins = ["!agent-delegation"]. The roster renders only while the auto-includedagent-delegationbuiltin domain is loaded, so excluding the domain removes the section from every root file —CLAUDE.md,AGENTS.mdand the hand-writtencodex,geminiandopencodeoutputs alike — with no new configuration key. The per-agent files are still generated, so nothing is lost: the roster is a second copy of each agent's name and description in the one file that is read on every request, measured at roughly 1,100 always-loaded tokens on a 32-agent tree.ai-rulez tokensreports it as theagents_delegationline.
Fixed¶
- Skills and commands now honour the documented source precedence (root > on-disk domain > include > builtin) instead of silently inverting it. Rules, context and agents were already deduplicated by name in precedence order; skills and commands never were, so two same-named items both rendered and both were written to the one name-derived output path (
.claude/skills/{id}/SKILL.md) — leaving whichever the writer happened to reach last, which is the lowest-precedence copy. A project.ai-rulez/skills/testing-conventions/was therefore replaced wholesale, description and body, by a builtin pack's skill of that name, and a root skill lost to a domain skill, both with exit code 0 and no diagnostic. The lower-precedence copy is now dropped before rendering rather than overwritten after it, andgenerateandvalidatelogDuplicate skill collapsed/Duplicate command collapsednaming the kept and dropped source paths. Shadowing a builtin with a project skill stays a supported pattern — it warns, it does not fail.getAllDomainSkills/getAllDomainCommandsalso switched from alphabetical domain order to precedence order, so which domain wins no longer depends on its name. - Corrected the domain-collision documentation, which claimed the domain version wins over root for rules and context, and illustrated it with a warning message no code emits (
docs/domains.md,docs/configuration.md). Root wins, and has for as long asallInlineRuleshas been the collector; the domain-wins rule lived only in theinternal/scannerpackage retired in 4.12.1, which nothing imported. generatenow removes the directories its own stale-file pass emptied. Narrowing a profile deleted theSKILL.mdfiles the new profile no longer emits but left every<id>/directory standing — measured: 200 skills down to 62 left 138 empty directories — and an empty directory underskills/reads to a human, and to tooling that lists the directory, as a live skill that has lost its body. Only the ancestors of a file ai-rulez wrote are candidates, so the walk never leaves the generated output roots; it stops below the project root and refuses the.ai-rulez/source tree; and a directory holding any entry survives, so a hand-authored file in a skill'sreferences/,scripts/orassets/keeps both that subdirectory and the skill directory above it. Directories a preset declares as outputs (.codex/agents/,.codex/commands/) are still created empty when there is nothing to put in them — they are current outputs, not leftovers.generate --recursivereports a counted file total instead oflen(presets) * 3. The estimate was wrong in both directions — one preset with three skills generates four files and was reported as three — and nothing measured it.Generator.GenerateFilesandGeneratePluginFilesreturn the number of files written, directories excluded;GenerateandGeneratePluginkeep their signatures and delegate. Plugin generation reported0for the same summary and now reports its own count.- The README no longer claims the auto-included builtin domains "activate automatically, no configuration needed". Builtins load only when the
builtinsfield is present in the config —loadBuiltinsis gated on it — so a project that never sets the field, which is whatai-rulez initwrites, gets no builtin rules, skills or agents at all. Auto-inclusion means "included without being named once builtins are on", not "on by default".docs/configuration.mdstated this correctly in one place and is now explicit about the omitted-field case.
[4.12.1] - 2026-09-25¶
Fixed¶
generateno longer deletes H1-like lines from inside fenced code blocks. The first-heading strip applied to rule and context bodies matched#on any line, so a shell or Python comment opening a line inside a fence vanished fromCLAUDE.mdandAGENTS.md— silently, with a green exit code, and the only workaround was to never start a fenced line with#. Despite its name the pass also stripped every H1 rather than the first, because its guard cleared as soon as a non-blank line followed. It now tracks fenced regions (backtick and tilde, honouring the closing run length), strips a single heading, and leaves indented code blocks alone, since ATX allows at most three leading spaces. Skills were never affected — they pass their body through verbatim. (#188)- A merged settings document is no longer re-indented when its first key opens an object or array on the brace line. The indent was inferred from the first indented line, which in
{"permissions": {/"allow": []is the nested member at four spaces rather than the two the document uses, so every hand-authored member came back at the wrong width — the whole-file diff the merge exists to avoid. Detection now tracks brace depth, ignoring braces inside strings, and reads the first line that opens a key at depth one. - A CRLF settings document keeps its line endings. Untouched members are re-emitted byte for byte, so their CRLFs survived, but the top level and the freshly rendered owned value were written with LF, leaving one document holding both.
Changed¶
- Removed the unused
internal/scannerpackage. Nothing imported it — content is scanned throughconfig.ScanContentTreeand profiles resolve throughConfig.GetContentForProfile— so it was a second, diverging copy of the same walk, and it mishandled the command directory form by dropping both items when a flat and a directory command collided in one source.validatereports that collision, which is why nothing depended on the broken path.
[4.12.0] - 2026-09-25¶
Added¶
- Bundled hook scripts for plugins: Plugin hooks now support a
scriptfield pointing at a project-relative file ai-rulez bundles into the plugin'shooks/directory. The rendered command points at the bundled copy through the installing runtime's plugin-root variable (${CLAUDE_PLUGIN_ROOT}/hooks/<basename>for Claude Code), enabling self-contained bootstrap hooks that work in a fresh clone before any generation has run.Command(for executables already in the consumer's environment) andScript(for bundled files) are mutually exclusive. Hook actions gainedargs,timeout,if, andstatus_messagefields alongside the existingcommand,type, andasync(status_messagerenders as the runtime'sstatusMessage).iftakes a single permission rule such asBash(git *)— not an expression — and Claude Code evaluates it only on the tool-use and permission events, sovalidatenow warns when it appears on an event that ignores it, where the effect is a handler that never runs at all. An event name outside the known list (KnownHookEvents) produces a warning rather than an error, so a config written against a newer Claude Code keeps working on an older ai-rulez. - Directory form for commands: Commands may now be directories containing
COMMAND.mdplus areferences/subdirectory for supporting material, mirroring the existing skill layout. The flatcommands/foo.mdform is unchanged. Command resources are passed through to generated output using the same progressive-disclosure model as skill resources.
Changed¶
- Settings documents are now merged, not overwritten (issue #185):
.claude/settings.json,.mcp.json,.gemini/settings.json,.agents/settings.jsonand.amp/settings.jsonare shared documents where ai-rulez owns specific top-level keys (mcpServers, oramp.anthropic.effort) and the consumer owns the rest. Generation now replaces only the owned keys and preserves every other member byte-for-byte, including the document's original indentation. Consequence: an MCP server a user added by hand inside themcpServersobject does NOT survive — the owned key is replaced wholesale. JSONC not supported: a document containing comments or trailing commas is not valid JSON, and generation now fails loudly with a hint naming the path, rather than silently stripping comments. Gitignore behavior: a document still holding keys ai-rulez does not own is treated as the user's file and is NOT added to the managed.gitignoreblock or deleted as stale. A document holding only ai-rulez's own keys is still gitignored (keeping resolved MCP secret values out of git). Emission gating: thegeminiandantigravitypresets no longer write their settings document on every run purely to self-register the ai-rulez MCP server — it is emitted only when the config declares MCP servers, so a project without[[mcp_servers]]keeps whatever is already at.gemini/settings.json/.agents/settings.jsonuntouched. One consequence of that gating: removing the last[[mcp_servers]]entry leaves the previous run'smcpServersblock on disk, because nothing is rendered to replace it and the file is never deleted. Delete the key by hand if the document should stop advertising those servers. Upgrading: a manifest written by 4.11.5 or earlier lists those two paths, because the presets wrote them unconditionally. The stale-output pass now recognizes every merged document — the ones declared by a provider sidecar spec and the ones rendered by a preset — so upgrading with no[[mcp_servers]]declared no longer deletes a hand-authored.gemini/settings.jsonor.agents/settings.json. ai-rulez init --setup-hooksnow fills in an emptypre-commit:,commands:,repos:orhooks:section rather than refusing the file. A key written with no value is legal YAML and a legal placeholder in both hook configs, but it parses as a null scalar, which the previous kind check rejected outright. A section holding a real value of the wrong type is still an error — and is now reported as one forrepos:andhooks:too, where the value used to be silently overwritten.- Dependency sweep:
dustin/go-humanize1.0.1 → 1.1.0,go.opentelemetry.io/otelandotel/trace1.45.0 → 1.46.0,golang.org/x/net0.58.0 → 0.59.0,golang.org/x/oauth20.36.0 → 0.37.0,golang.org/x/sys0.47.0 → 0.48.0,golang.org/x/term0.45.0 → 0.46.0,golang.org/x/time0.15.0 → 0.16.0. Every direct dependency was already current. The docs toolchain moves with it (zensical0.0.57 → 0.0.65). - CI gained a
govulncheckjob.poly.tomlrecorded that one should exist, but it was never added, leavinggosecthrough golangci-lint as the only security tooling — SAST rather than CVE scanning of the dependency graph. - Corrected the preset and tool counts in the README and docs. There are 13 platform presets, not 20, and the MCP server exposes 36 tools, not "35+"; the README already listed all 13 by name, so "and more" promised presets that do not exist.
Fixed¶
- Skill and command subdirectories outside the canonical set (
references/,scripts/,assets/) now emit a warning naming the item and the offending directory, so authors learn their content is not being included. Previously such directories were silently dropped (issue #183). - The managed
.gitignoreblock now lists subdirectories ai-rulez writes (.claude/skills/,.claude/agents/) rather than whole assistant directories (.claude/). Ignoring the directory root made git silently skip tracked user files inside them, such as.claude/settings.json(issue #184). ai-rulez init --setup-hooksnow preserves comments, key order and the original indentation width in an existinglefthook.ymlor.pre-commit-config.yaml, usingyaml.Nodefor comment-preserving round-trips rather than unmarshaling to a plain map. Previously the whole file was reformatted: comments were dropped outright, and even once they survived,yaml.Marshal's hardcoded four-space indent re-indented every line of a two-space document. Blank lines between entries are still lost, and padding that aligns trailing comments collapses to a single space — yaml.v3 does not model either (issue #186).ai-rulez init --setup-hooksnow emits the fields of thelefthook.ymlcommand it adds in a fixed order. They were built from a Go map, whose iteration order is randomized, so every invocation reorderedglob/run/fail_textand a CI check that regenerates and diffs could never be stable.ai-rulez init --setup-hooksno longer corrupts a.pre-commit-config.yamlwhoserevYAML resolves to a non-string type. An unquotedrev: 24parses as!!int, and yaml.v3 writes a node's parse-time tag out explicitly once it stops matching the value, so updating the revision in place producedrev: !!int v4.11.5— a document pre-commit rejects. The value node is now replaced wholesale, carrying its comments across.ai-rulez validatenow reports when a skill and a command share an output id. Skills and commands both render to.claude/skills/{id}/SKILL.md(differing only in theuser_invocableconstant), so a collision silently overwrites one with the other. The check pools root and every domain because the output layout has no domain segment.ai-rulez validatenow reports two skills, or two commands, in one directory that resolve to the same output id (duplicate output ids). The flat and directory forms of a command resolve identically, socommands/deploy.mdalongsidecommands/deploy/COMMAND.mdwas the easy way to lose one of them silently. Unlike the cross-kind check this one pools nothing: root shadowing a domain is documented resolution, not a collision.- Domain content now shadows root content for a command written in the other form. Collision keys were the file basename for a flat command and the directory name for a directory one, so a root
commands/deploy.mdand a domaincommands/deploy/COMMAND.mdlooked unrelated and were both emitted to.claude/skills/deploy/SKILL.md. Every collision map is now populated through the same key function that reads it. - Skill/agent frontmatter
argument-hintno longer passes through to generated skills, where it was inert. It is relevant only to commands (user_invocable=true). A skill declaring it produces a warning suggesting the author move it tocommands/instead. - A plugin passthrough source that resolves outside the project is refused. The path guards are lexical — they reject
.., absolute paths and drive letters in the declared string — so a symlink defeated them: neitherbootstrap.sh(linked at~/.ssh/id_rsa) norvendor/passwd(wherevendorlinks to/etc) contains a traversal sequence, andos.Stat/os.ReadFilefollow the link. Passthrough bytes are published — they land in a bundle consumers install, and a hook script is executed by the installing runtime — so whoever built the bundle would have copied a local file into it. Symlinks that stay inside the project still work, andvalidatereports the escape before generation. (#187) - A merged settings document belonging to a
[[scopes]]entry is no longer deleted as stale. The registries hold paths relative to a config's own base dir (.mcp.json) while a manifest entry is relative to the root config (packages/api/.mcp.json), and the guard matched exactly — so it protected the root document and deleted every scope's, which is the #185 data loss it exists to prevent. It now matches on the tail, the rule the merged-document registry already applied. (#187)
[4.11.5] - 2026-09-19¶
Fixed¶
- Skill includes pinned to a full commit SHA now resolve deterministically and fail closed, extending the 4.11.4
GitSourcefix (#167) toSkillGitSource. A 40-hex pin is used verbatim and cloned by fetching the exact object instead of being passed throughls-remote(which cannot advertise raw commits) and silently degrading to cached content; the doomed--branchclone on refresh is gone too. A pin the remote cannot serve is an error, never a cache fallback. (#179) - Schema validation compiles with a fresh compiler per call. jsonschema 0.9.10 rejects re-registering a schema resource URI on an existing compiler, which broke the second in-process
ValidateWithSchemacall (e.g. the MCP server). The embedded schema only uses internal$defsrefs; a per-call compiler also removes a shared-state race for concurrent validation. (#181)
Changed¶
- Go toolchain bumped to 1.27 across the module directive, CI
setup-goversions, and the contribution guide, unblocking jsonschema 0.9.10. (#180) - Dependency upgrades:
kaptinlin/jsonschema0.9.8 → 0.9.10 (#168),modelcontextprotocol/go-sdk1.7.0 → 1.8.0 (#171),yuin/goldmark1.8.5 → 1.8.6 (#169),golang.org/x/text0.41.0 → 0.42.0 (#172).
[4.11.4] - 2026-09-18¶
Fixed¶
generatesplices the managed.gitignoreblock back in place instead of re-emitting it after any user entries that followed# END ai-rulez. ABEGIN/ENDregion that was stripped, kept, and re-appended silently reordered the file; the block is now written exactly where the fence stood, leaving the suffix untouched. (#178)ai-rulez validatenow fails (nonzero exit) when a content file's frontmatter fails to parse. Previously the malformed file was loaded with nil metadata and validation passed, hiding bad content until a later failure; the error lists every offending path. (#175)- A skill whose frontmatter fails to parse is no longer dropped from generated output. It loads with nil metadata, which used to leave the generated
SKILL.mdwithout adescription(invisible to the assistant); the documented name-as-description fallback now applies — the skill id is emitted as its description, matching a healthy skill's frontmatter. (#176) - Includes pinned to a full commit SHA now resolve deterministically and fail closed. A 40-hex
refwas passed togit ls-remote, which cannot advertise raw commits, so pinned refs never matched the cache and silently fell back to stale cached content on any transient error. Full SHAs are now recognized, cloned by fetching the exact object, and cached under that SHA; a SHA the remote cannot serve is an error, never a cache fallback. (#167)
Changed¶
- Workflow actions updated:
xberg-io/actionsreusable-validate v1.11.6 → v1 (now pinned to thev1major tag), andastral-sh/setup-uvv10.0.1 → v10.1.0. setup-uv stays pinned to a full semver tag because it stopped publishing major and minor tags at v8 as a supply-chain measure, so@v10does not resolve.
[4.11.3] - 2026-08-24¶
Fixed¶
generateis now reproducible across checkout paths.computeSourceHashfolded the raw absoluteContentFile.Pathinto the source hash, so the same tree generated from two directories produced differentSource-Hashvalues. The bodies were byte-identical, but the mismatch forced a rewrite and stamped a freshGenerated:timestamp, leaving clean-checkout CI drift checks permanently dirty. Paths are now normalized before hashing — relative to the config or base directory when in-tree, collapsed to their last two segments when not. The fallback also removes three cases the report did not cover: git includes cached under the user's home directory (so a laptop and a CI runner disagreed at the same commit), installed skills, and the randomly-named temp symlink used for bare include layouts (non-deterministic run to run on one machine). Normalizing throughfilepath.ToSlashadditionally stops Windows and Linux disagreeing about the same tree.GeneratorSchemaVersionmoves tov3, so every project regenerates once before the skip mechanism re-engages. (#166)ai-rulez mcpno longer uses the deprecatedServerOptions.HasTools; tools are advertised throughCapabilitieswith the same{"listChanged":true}value. SettingCapabilitiessuppresses the SDK's defaultloggingcapability, which is deprecated as of protocol version 2026-07-28 and which this server never emitted. This also unblocks the Lint job, which staticcheck's SA1019 had been failing onmainsince the SDK bump in 4.11.2.
Added¶
[header] timestamp = falseomits theGenerated:line from all three header styles, for projects that commit their generated outputs and want no per-run value in the header at all. Defaults totrue, so existing output is unchanged.
Changed¶
- Dependencies updated:
samber/oops1.23.1,golang.org/x/text0.41.0, with indirect bumps togolang.org/x/net0.58.0,golang.org/x/crypto0.55.0, andgo-json-experiment/json; docs toolchain to zensical 0.0.57.govulncheckreports no known vulnerabilities. - Workflow actions updated:
golangci-lint-actionv7 → v9,xberg-io/actionsreusable-validate v1.8.142 → v1.8.145, andastral-sh/setup-uvv6 → v10.0.1. setup-uv is pinned to a full semver tag because it stopped publishing major and minor tags at v8 as a supply-chain measure, so@v10does not resolve. - The JSON schema's
header.styledefault now readsminimal, matching the code default since 4.9.
[4.11.2] - 2026-08-08¶
Fixed¶
ai-rulez mcpno longer wedges when a host sendsinitializetwice on one stdio session. The MCP SDK treats initialization as a one-shot state machine, so a repeatedinitializefailed withduplicate "initialize" received(and a repeatednotifications/initializedlikewise), permanently breaking any host that retries or reconnects over a long-lived server process — Claude Code's MCP client, or an mcpm/fastmcp bridge shared between consumers. A repeatedinitializeis now answered with the result of the original negotiation and a repeatednotifications/initializedis dropped, leaving the session intact. Because the SDK's version negotiation is internal, a re-initialize receives the protocol version agreed on first connect. (#158)
Changed¶
- Dependencies updated:
kaptinlin/jsonschema0.9.8,oklog/ulid2.1.2, OpenTelemetry 1.45.0,go.yaml.in/yaml3.0.5; docs toolchain to zensical 0.0.53. The unusedtool github.com/evilmartians/lefthookdirective was dropped, removing 27 indirect modules fromgo.mod— the repo moved off lefthook to poly hooks and nothing imported it. task updatenow updates the whole Go module graph plusuv.lock, andtask lintruns the poly checks. Both previously invokedprekagainst a.pre-commit-config.yamlthat no longer exists.
[4.11.1] - 2026-07-31¶
Fixed¶
generateno longer inlines the full rules block into every generated.claude/skills/<name>/SKILL.mdand.claude/agents/<name>.md. A rule targeting theclaudepreset name was matching any output under.claude/, so it was duplicated into every per-item skill/agent file; it now routes toCLAUDE.mdonly. Explicit path, directory, and glob targets are unaffected. (#156)generateno longer emits a second, raw frontmatter block in a skill file when the source frontmatter fails to parse. Malformed YAML frontmatter (e.g. an unquoted value containing": ") was returned unstripped and re-emitted after the generated block; it is now stripped with a warning. The 14 builtin skills whosedescriptioncontained an unquoted": "are quoted so their descriptions parse and populate the generated frontmatter. (#156)
[4.11.0] - 2026-07-22¶
Added¶
ai-rulez cleancommand: removes the files produced bygenerate(the inverse ofgenerate) — the generated assistant outputs (CLAUDE.md,AGENTS.md,GEMINI.md,.claude/,.codex/, generated skills, …), the generated manifest, and the ai-rulez managed.gitignoreblock. The.ai-rulez/source tree is never touched and generated directories are removed only once empty (files you authored inside them are kept). Lists targets and prompts for confirmation by default;--dry-runpreviews,--forceskips the prompt,--keep-gitignore/--keep-manifestpreserve those. Exposed over MCP asclean_outputs.
Fixed¶
- MCP
update_rule/update_context/update_skillno longer fail withfile already existswhen updating existing content. The update path used a create-only write primitive that refused to overwrite; it now uses an overwrite-capable atomic write. (#150)
[4.10.0] - 2026-07-22¶
Added¶
- Local-override content: drop machine-local rules and context under
.ai-rulez/local/rules/and.ai-rulez/local/context/and they are emitted only to per-preset.localroot files (CLAUDE.local.md,AGENTS.local.md,GEMINI.local.md,.junie/guidelines.local.md,.github/copilot-instructions.local.md, …). Local content is kept strictly separate from committed output and both the.localfiles and the.ai-rulez/local/source directory are gitignored unconditionally (even whengitignore = false). New--localflag onai-rulez add ruleandai-rulez add contextwrites there directly. - Bare/flattened include layout: included repositories no longer need to wrap their content in an
.ai-rulez/directory; a flattenedrules/,context/,skills/layout is now supported.
Changed¶
- Built-in language, binding, OWASP, and dependency-awareness conventions now emit as on-demand Agent Skills (
skills/<name>/SKILL.md) instead of always-inlined rules/context, shrinking the generatedCLAUDE.md(and peers) considerably. The agent loads them only when the relevant "Load when…" trigger applies. - Default header style is now
minimal(wasdetailed), trimming ~37 lines of boilerplate from every generated root file while keeping the DO-NOT-EDIT warning plus the Content-Hash / Source-Hash provenance lines.detailedandcompactremain available via[header] style = "…".
[4.9.4] - 2026-07-12¶
Changed¶
- Built-in language and binding convention rules are now tool-agnostic. They describe idiomatic principles and quality bars rather than mandating one third-party stack: opinionated tools (e.g.
mypy,oxlint,oxfmt,structlog,vitest) are now framed as examples, while canonical/official toolchains (gofmt,cargo fmt,dotnet format,tsc,mix format, …) are retained.
Fixed¶
- Python builtin convention no longer references
Unknown(a TypeScript type); it now recommends precise types, generics, ortyping.Protocol. - Fixed typos in the vite+ builtin convention.
[4.9.3] - 2026-07-12¶
Fixed¶
- Reject Windows drive-relative plugin paths such as
C:outsideon every host platform.
Changed¶
- Pin Poly catalog npx and uvx execution paths to the catalog release for reproducible hook runs.
[4.9.2] - 2026-07-12¶
Fixed¶
- Validate plugin paths consistently across operating systems and use portable path assertions for Hermes and OpenCode output tests.
Changed¶
- Split plugin authoring validation into focused checks to keep complexity within project limits.
[4.9.1] - 2026-07-12¶
Fixed¶
- Use the ai-rulez
versionsubcommand in Poly hook installation paths.
[4.9.0] - 2026-07-12¶
Added¶
- Reusable
poly-hooks.tomlcatalog with multiple selectable hooks, guarded npx, uvx, and system execution paths, explicit managed install commands, and parity with the pre-commit hook catalog. - Recursive plugin generation and verification with
--if-configured, including atomic marketplace traversal without duplicate member work. - Plugin generation and verification hooks for both Poly and pre-commit, triggered by root or nested
.ai-rulez/changes.
Changed¶
- Poly consumers declare local or Git sources in
poly.tomland can select non-mutating validation and plugin verification while keeping generation and auto-fix hooks opt-in.
[4.8.0] - 2026-07-12¶
Added¶
- Native Hermes Agent rules generation through the
hermespreset and.hermes.mdproject context. - Hermes Agent project plugins and PyPI entry-point packages, with compatible
hermes,register, and__version__exports. - Plugin-specific content through
plugin.content_root, adapter reuse throughplugin.hermes.source, and configurable Python compatibility throughplugin.hermes.requires_python. - Generated plugin freshness and provenance verification with
ai-rulez verify --plugin, including profile-aware rendering.
Fixed¶
- Preserve authored Markdown whitespace when inserting and verifying generated-file provenance headers.
- Serialize Hermes Python package metadata safely and emit Claude marketplace files only when targeting Claude.
[4.7.0] - 2026-07-11¶
Added¶
- Complete Codex plugin bundles with root MCP configuration, canonical marketplace metadata, recursive skill resources, and validated interface assets.
- OpenCode plugin generation from
.ai-rulez/opencode/index.js, including generated package metadata and a documented no-op scaffold when no adapter is authored. - Deterministic plugin provenance through generated-file headers and
.ai-rulez-generated.jsonsidecars with BLAKE3 content and source hashes.
Fixed¶
- Preserve nested skill resources and Codex interface metadata during plugin generation.
- Emit runtime-safe relative MCP commands and strict JSON manifests without comment headers.
[4.6.0] - 2026-07-08¶
Added¶
- Plugin & marketplace authoring via
ai-rulez generate --plugin: packages the project's skills, commands, agents, and MCP servers into distributable plugin bundles and a marketplace index for Claude, Cursor, Codex, Gemini, Kimi, OpenCode, and Factory. A new[plugin]config block carries the packaging metadata (kept distinct from the consumer[[plugins]]/[[marketplaces]]install arrays), with hooks, a Claude status-line passthrough, a canonical${PLUGIN_ROOT}launch variable rewritten per runtime, and both single-plugin and monorepo ([marketplace].members) marketplaces. - Agent
extendsdirective: an agent whose frontmatter setsextends: <name>inherits the body and frontmatter of a lower-precedence agent (the same name in a lower layer, or the named target) and appends its own body, with set frontmatter fields overriding the base and omitted fields inherited. Chains resolve across multiple layers (local extends include extends builtin); a missing base or anextendscycle degrades to a plain agent with the directive stripped.
Fixed¶
- Agent precedence is now deterministic and matches rules/context: same-named agents collapse to the single highest-precedence definition (local > include > builtin) instead of a non-deterministic last-write-wins that depended on domain name ordering. The generated header agent count also reflects the deduplicated set.
Changed¶
- Built-in agent default models:
docs-writer,devops-engineer, andrelease-engineernow usesonnet(washaiku);polyglot-architectnow usesopus.
[4.5.0] - 2026-07-02¶
Added¶
- Rule and context deduplication by name with source precedence (root > on-disk domain > include > builtin). When the same name is defined by more than one source (for example a builtin
git-workflowrule and an include redefiningcommit-messages), the generated output now includes it only once, and a warning is logged duringgenerateandvalidatenaming the kept and dropped sources. compactconfig option: whentrue, generated inline rule sections omit the per-rule**Priority:**annotations to reduce output size.- Per-rule builtin exclusion via the
!domain/rulesyntax in thebuiltinsarray (e.g.!git-workflow/commit-messages), which drops a single builtin rule while keeping the rest of the domain. - MCP tool annotations for all write tools (create/add/update/set marked additive or idempotent rather than defaulting to destructive), plus server
Titleand initializationInstructionsmetadata.
Fixed¶
- MCP server configuration for remote (
http/sse) transports no longer emits an emptycommandor atransportkey. Each preset now emits its tool-specific remote format: Claudetype(#136, #137), GeminihttpUrl/url, Copilottype, Cursorurl, and AntigravityserverUrl. Stdio servers are unchanged.
Changed¶
- Migrated preset rendering to a declarative DSL provider system (Claude, Amp, Junie, and MCP specs), replacing the hand-written generators for those presets.
- Migrated lint and format tooling from prek to poly.
- Updated Go dependencies (
pelletier/go-toml/v22.4.2,kaptinlin/jsonschema0.9.2,golang.org/x/text0.38,golang.org/x/net0.56) and CI actions (actions/checkoutv7,actions/cachev6).
[4.4.1] - 2026-06-07¶
Fixed¶
.ai-rulez/.generated-manifest.jsonis now included in the managed.gitignorefence when--gitignore(orgitignore: truein config) is enabled. The manifest is rewritten on everygenerate; tracking it produced endless diff noise. Honours customconfig_dirvalues.
Tests¶
- Added end-to-end coverage for per-preset model overrides so the resolver chain (agent
<preset>_model→defaults.model_by_preset→ legacymodel:) is exercised against real generated agent files for both Claude and Copilot.
[4.4.0] - 2026-06-07¶
Added¶
- Per-preset model overrides for agents. Each preset now resolves its agent
modelvalue via<preset>_modelfrontmatter (e.g.claude_model,copilot_model,cursor_model) withdefaults.model_by_presetas a project-wide fallback. The legacy singlemodel:field remains supported as the lowest-priority fallback for backward compatibility.
Fixed¶
- The TOML config loader silently dropped the entire
[defaults]table, soeffort_by_presetfrom TOML configs never reached the generator. The newmodel_by_presetfeature exposed the gap; both tables now load correctly.
Changed¶
- Updated Go dependencies (
agentable/go-intl,go-json-experiment/json,kaptinlin/go-i18n,kaptinlin/jsonpointer,kaptinlin/jsonschema,kaptinlin/messageformat-go) and pre-commit hooks (kreuzberg-dev/pre-commit-hooks1.2.3 → 2.1.8,gh-actions-updater0.1.5 → 0.1.6,Goldziher/ai-rulezself-reference 4.3.1 → 4.3.2). Go toolchain bumped from 1.26.3 to 1.26.4.
[4.3.0] - 2026-05-30¶
Added¶
- Added
generate --gitignorewith-ishorthand; the old--update-gitignoreflag remains as a deprecated compatibility alias. - Added collision-safe short flags across global, generate, CRUD, list, domain, profile, include, init, validate, and skill commands.
- Added MCP environment placeholder resolution from repeated
--env KEY=VALUE, process environment,.env, and explicit--env-filesources.
Changed¶
.gitignoregeneration now writes generated roots and directory patterns instead of per-file assistant output entries, while keeping generated.github/paths scoped to Copilot-owned files and directories.
Fixed¶
- Secret-bearing MCP outputs now fail generation when their generated path is not ignored, including scoped MCP config outputs.
- Resolved MCP secret values are redacted before source hash calculation so generated metadata does not encode secret material.
- Existing outside-fence
.gitignorepatterns are now interpreted semantically when deciding whether managed entries are already covered.
Tests¶
- Added generator and CLI coverage for MCP env substitution,
.envand--env-fileloading, unresolved placeholders, secret safety errors, scoped MCP outputs, deprecated gitignore aliases, and shorthand flags.
[4.2.2] - 2026-05-26¶
Added¶
- Added a
polyglot-bindingsbuiltin with Rust-core, native ABI, FFI ownership, cross-language error conversion, and binding parity guidance.
Changed¶
- Updated the TypeScript builtin to recommend
oxfmtwithoxlint.
Dependencies¶
- Updated shared pre-commit hooks,
gh-actions-updater,github.com/modelcontextprotocol/go-sdk, and related Go module dependencies.
[4.2.1] - 2026-05-21¶
Fixed¶
- Cursor skill frontmatter is now valid YAML: generated
.agents/skills/*/SKILL.mdfiles quote skill descriptions, so descriptions containing colons no longer fail Codex skill loading.
Dependencies¶
- Refreshed pre-commit hook revisions with
prek autoupdate. - Updated Go module dependencies with
go get -u ./...andgo mod tidy.
[4.2.0] - 2026-05-21¶
Added¶
- Manifest-scoped generation cleanup:
ai-rulez generatenow writes.generated-manifest.jsonunder the active config directory and deletes only stale files previously recorded in that manifest. Assistant directories such as.claude/,.codex/,.cursor/,.gemini/,.windsurf/,.cline/,.agents/,.continue/,.opencode/, and.junie/are no longer treated as fully owned. - Real dry-run output:
generate --dry-runand MCPgenerate_outputsdry runs now report plannedcreate-dir,write-file, anddelete-staleentries without mutating the filesystem. - Custom config directory support:
generate --config-dir <name>,validate --config-dir <name>, recursive generation, and MCP generation/validation can use configuration roots other than.ai-rulez/. - Exact config path loading: positional config paths and
--config <path>now load that exact file or config directory. Root-level config files fail with a precise directory-layout error when they would otherwise make the parent directory the output root. - Scoped subfolder outputs: new
[[scopes]]config entries generate subfolder-specificAGENTS.mdandCLAUDE.mdfiles with their own profile and preset selection, keeping root context separate from scoped context.
Fixed¶
- User-owned files no longer get deleted: hand-written settings, hooks, personal skills, and other files in assistant output directories are preserved during regeneration.
- CI Taskfile drift: consolidated on
Taskfile.yml, removed the lowercase duplicate, and added the workflow-referenced tasks:test,test:platform,test:e2e,test:e2e:cli,test:e2e:mcp,test:e2e:integration,test:all, andtest:benchmark. task formatno longer walks local caches: the task now usesgo fmt ./...instead of formatting every file below the repository root.
Changed¶
.gitignoregeneration now lists generated files individually instead of ignoring whole assistant directories.- MCP generation and validation now share the same config-loading semantics as the CLI.
- Documentation, schema, and the bundled
ai-rulezskill now describe custom config directories, scoped outputs, manifest cleanup, and current[[mcp_servers]]configuration.
Dependencies¶
- Merged Dependabot updates for
github.com/pelletier/go-toml/v2,golang.org/x/text,github.com/kaptinlin/jsonschema, andpymdown-extensions.
Tests¶
- Added regression coverage for preserving user-owned assistant files, manifest-owned stale cleanup, exact config file loading,
--config,--config-dir, dry-run behavior, and scoped subfolder outputs.
[4.1.6] - 2026-05-03¶
Changed¶
- Git fetches now use sparse checkout —
ai-rulezno longer downloads entire repository archives to resolve installed skills or remote includes. All git operations now rungit clone --depth 1 --filter=blob:none --sparseand materialise only the required subtree (e.g.skills/<name>/or.ai-rulez/). This fixes the"response body too large"error that occurred when installing skills from large repositories, and dramatically reduces network and disk usage for all remote sources. Requires git ≥ 2.25 (released January 2020). - BLAKE3-based cache invalidation — the time-based TTL (
.fetch_timemarker, 1-hour for includes) is replaced with a content-driven approach. On everyai-rulez generate, a fastgit ls-remotecall checks whether the remote HEAD SHA has changed; cached content is reused when the SHA matches and re-fetched only when it differs. Cached file content is hashed with BLAKE3 and stored in.cache_meta.jsonalongside each cached source. Skills always check the remote (no grace period);--no-fetchbypasses all network calls as before.
Removed¶
- HTTP archive download path (
downloadAndExtract,buildArchiveURL,extractTarGz,extractZip): replaced by sparse git clone. - Duplicate SSH clone helpers (
cloneViaGit,cloneViaGitForSkill): replaced by the sharedsparseCloneprimitive in the newinternal/includes/gitops.go.
[4.1.5] - 2026-05-02¶
Changed¶
- Skill resources are no longer concatenated into
SKILL.md. A skill'sreferences/,scripts/, andassets/subdirectories are now emitted as separate files under the rendered skill directory, matching the canonical Agent Skills layout used by Claude Code and OpenAI Codex.SKILL.mdcarries a## Resourcesindex with relative-path links so the agent can read references on demand (progressive disclosure) instead of paying the full reference cost on every invocation. Reference descriptions are pulled from each file'sdescriptionfrontmatter or the first heading. - Loader:
internal/includes/skill_source.go::ScanInstalledSkillDirno longer inlinesreferences/*.md(the deletedreadReferenceshelper). Local skills under.ai-rulez/skills/<name>/now also pick up bundled resources viainternal/config/loader.go::scanSkills— previously these subdirectories were ignored. - Renderer: shared helpers
RenderSkillResourcesIndex,SkillResourceOutputs,InlineSkillResourcesininternal/generator/presets/skill_resources.go. Applied across every preset that emits a skill directory (Claude, Codex, Cursor, Cline, Amp, Antigravity, Copilot, Gemini, Junie, Opencode, Windsurf). The single-filecontinue.devpreset keeps the inline-concat behaviour since it has no skill directory to read from. - File mode (executable bit on
scripts/*.sh) is preserved through generation.
Added¶
OutputFile.RawContent []byteandOutputFile.Mode os.FileModeininternal/config/presets.go— non-nilRawContentroutes the file through a verbatim-write path that skips the AI-RULEZ banner, content/source-hash injection, and trailing-newline normalisation. Used for skill resource files where any added marker would corrupt the payload (Python scripts, binary assets) or break tooling that hashes the file.- Idempotency on the raw-write path:
internal/generator/generator.go::writeOutputnow compares existing bytes plus mode and skips the write/chmod when both match, so unchanged bundled assets don't dirty the working tree on every regeneration. SkillResourcetype andContentFile.Resourcesininternal/config/types.gocarryKind(references/scripts/assets), forward-slash-normalisedRelPath, rawContentbytes, fileMode, and an optionalDescription.- Stale-file cleanup for resource subdirectories:
SkillResourceOutputsemits each parent directory (including nested ones) as anIsDiroutput socleanManagedDirswalks them on regeneration. Without this, a deletedreferences/old-api.mdwould persist forever in the rendered skill tree. - Resource content is included in the source hash (
writeContentFiles), length-prefixed (|res=<kind>:<relpath>:len=<n>:<bytes>) so a reference body cannot spoof the inter-record delimiter to fake a second resource.
Security¶
- Symlink guard in
internal/config/skill_resources.go: the resource loader usesos.Lstaton each kind directory and checksd.Type()&os.ModeSymlinkon every walked entry. A malicious installed skill cannot exfiltrate host files (e.g.references/evil.md → /etc/passwd) or replace a kind directory with a symlink to an attacker-controlled tree. Symlinks are skipped with aWARNlog. - Defensive walk-up guard in
SkillResourceOutputs: an absoluteRelPath(whichLoadSkillResourcescannot produce, but a future caller might) used to put the parent-directory walk into an infinite loop onfilepath.Dir. Nowfilepath.IsAbsis checked before the walk.
Tests¶
internal/config/skill_resources_test.go—LoadSkillResourcescovering canonical layout, nested paths, frontmatter description extraction, scripts/assets handling, symlink-to-file rejection, symlinked-kind-directory rejection, symlinked subdirectory rejection, dangling symlinks, executable-bit preservation.internal/generator/presets/skill_resources_test.go—RenderSkillResourcesIndex,SkillResourceOutputs,InlineSkillResources,referenceDisplayName, plus the absolute-path infinite-loop guard with a 2 s timeout sentinel.internal/generator/presets/claude_test.go::TestClaudePresetGenerator_PreservesSkillResourcesLayout— end-to-end assertion that references stay separate fromSKILL.md, scripts/assets round-trip via raw bytes, and the resource index is rendered.internal/generator/generator_test.go— raw-write happy path (text, binary, parent-dir creation, mode preservation, mode fallback), raw-write idempotency usingos.Chtimessentinel mtime, mode-only changes still rewrite, content-only changes still rewrite.TestGenerator_CleansStaleSkillResourceverifies a deleted reference is swept on regeneration.TestComputeSourceHash_IncludesSkillResourcesandTestComputeSourceHash_ResistsResourceDelimiterCollisionlock down the source-hash format.- Updated
internal/includes/skill_source_test.goandinternal/includes/skill_resolver_test.goto assert onResourcesrather than the deprecated inline-concat behaviour.
Migration¶
No config or schema change. Existing skills regenerate on next ai-rulez generate. Generated SKILL.md files become smaller (reference bodies move out); new sibling files appear under each skill directory.
[4.1.4] - 2026-05-01¶
Fixed¶
- Flaky MCP e2e test client: the per-test
MCPClientwas a single-line-per-request stdio reader with no JSON-RPC id matching, no notification handling, a fresh reader goroutine per call, and the default 64 KiBbufio.Scannerbuffer. Thetools/listresponse is already ~18 KiB on a single line and grows with the tool surface; any server-emitted notification interleaved with a response would be misparsed as the response and orphan the real one. After bumpingmodelcontextprotocol/go-sdk v1.5.0 → v1.6.0in v4.1.3, this manifested asMCP request timed outflakes on cold runs (tests/e2e/testutil/mcp_client.go).
Changed¶
- MCP e2e test client rewritten for correctness:
- One persistent reader goroutine demuxes stdout into per-request response channels keyed by JSON-RPC id, so notifications cannot be misparsed as responses.
- Notifications (frames without an
id) are silently discarded. - JSON-RPC id key normalized via re-marshal so request and response sides format the same way (encoding/json's float64 round-trip for large nanosecond ids was the latent gotcha).
bufio.Scannerbuffer raised to 1 MiB.- Per-RPC timeout standardized at 30 s with explicit
t.Fatalfshowing the method name and reader error on server-side exit. Close()now waits for the reader to drain so its goroutine doesn't outlive the test.- Reverted v4.1.3's blind 5 s → 30 s timeout bump as the cure: that bump only masked the underlying client fragility. With the rewrite the timeout is no longer the load-bearing fix.
[4.1.3] - 2026-04-30¶
Fixed¶
generate --recursiveperformance and robustness: a recursive run on a polyglot monorepo could take ~2 minutes and abort on a single broken symlink (e.g. a stale Rusttarget/debug/deps/lib*.rlib). Two underlying defects incmd/commands/generate.go:- The walker had no skip list — it descended into
target/,node_modules/,.venv/,vendor/,dist/,.git/, etc. - The walk callback re-returned every
lstaterror fatally, so one bad symlink killed the entire run. - Recursive discovery now ignores v2 flat configs: only
.ai-rulez/config.{toml,yaml,yml,json}is discovered by--recursive. The legacy v2ai-rulez.yamldiscovery path is removed (single-configgenerate <file>is unaffected).
Added¶
- Shared skip helper at
internal/walkutilcovering VCS metadata, build outputs (target,node_modules,vendor,dist,build,out,obj,bin), language toolchain caches (.venv,__pycache__,.tox,.gradle,.mvn, …), editor caches, and any hidden directory other than.ai-rulez/.github. Reused fromcmd/commands/generate.go,internal/mcp/handlers/project.go, andinternal/agents/context.goso the same pruning applies to every recursive walk. - Shared rule library detection: a directory named
ai-rulez/(no leading dot) that itself containsconfig.{toml,yaml,yml,json}at its root is treated as a shared library. Its entire subtree is pruned during recursive discovery, so nested.ai-rulez/module configs that exist only for inclusion by consumers are no longer (re-)generated for. - Parallel multi-config processing:
generate --recursivenow processes discovered configs concurrently with aruntime.NumCPU()-bounded worker pool. Each config has its own working directory and produces independent output. - Concurrency-safe include cache:
internal/includesnow serializes refresh of any one cache directory with a per-cacheDir mutex (double-checked, lock-free fast path) so parallel callers targeting the same shared include never race onRemoveAll/extract. Applies to bothGitSource.FetchandSkillGitSource.Fetch. - Process-level scanned-tree memoization:
ScanContentTreeresults for a given cached.ai-rulez/directory are reused across consumers within the same process. In a monorepo where 18 configs each include the same 5 shared libraries, this cuts 90 redundant tree scans down to 5. Per-consumer include filters still apply viafilterContent, which returns a new tree without mutating the cached one.
Performance¶
kreuzberg-dev(24.ai-rulez/dirs, 18 actual consumer configs, 5 shared library modules):generate --recursive --update-gitignorewent from ~2 minutes (failing on a stale.rlibsymlink) to ~1 second steady-state. Cold full-tree generation completes in ~12 s.
Tests¶
internal/walkutil/skip_test.go— covers the shared skip predicate.cmd/commands/generate_recursive_test.go— fixture-driven test covering pruned dirs, broken-symlink resilience, library-skip, and config-format priority (TOML over YAML over JSON).internal/includes/fetch_concurrency_test.go— fetch-lock identity, concurrent access, scanned-tree cache round-trip / invalidation, race-detector stress.tests/e2e/cli/recursive_test.go— end-to-end suite asserting (a) walker pruning ofnode_modules/target/.venv/vendor/.cache/build, (b) shared rule library subtree is skipped, (c) parallel andGOMAXPROCS=1runs produce byte-identical outputs.
README¶
- New collapsible Installation section covering Homebrew, npx, npm -g, uvx, uv tool, pip/pipx, pre-commit hook, and lefthook setup.
[4.1.2] - 2026-04-30¶
Added¶
- Per-subagent reasoning effort for Codex: Codex subagent TOML files (
.codex/agents/<id>.toml) now emitmodel_reasoning_effortwhen an effort is resolved for that agent. Per-agent metadata wins over.codex/config.toml, which still carries the global default. Tracks the schema documented at https://developers.openai.com/codex/subagents. - Per-subagent reasoning effort for Opencode: Opencode agent files (
.opencode/agents/<id>.md) now emit areasoningEffortfrontmatter field. Resolution: per-agent metadata →defaults.effort_by_preset["opencode"]→defaults.effort.xhighandmaxmap tohigh(Opencode tops athigh);inheritis dropped.
Changed¶
- Updated the per-preset effort support matrix in
docs/configuration.mdto reflect Codex per-agent support and Opencode per-agent support.
[4.1.1] - 2026-04-30¶
Added¶
- Reasoning effort across multiple providers: extends the v4.1.0 Claude-only effort support to Codex, Amp, and Windsurf.
- Codex: emits
.codex/config.tomlwithmodel_reasoning_effortwhen an effort resolves. Global setting (Codex doesn't accept per-agent effort). - Amp: emits
.amp/settings.jsonwithamp.anthropic.effort. Global setting;xhighmaps tohigh(Amp tops athigh/max). - Windsurf: emits
reasoning_effortper-agent in.windsurf/agents/<id>.mdfrontmatter.maxmaps tohigh. - Claude: refactored to share the same resolver path; behavior unchanged.
defaults.effort_by_preset: per-preset overrides that beatdefaults.effort. Per-agent metadata still wins where the preset supports it. YAML/TOML key validated against the registered preset list.- MCP
update_configdefault_effort_by_presetparameter: object-typed argument that lets MCP clients set or clear per-preset overrides.read_configalways returns the field (possibly empty) for stable read-modify-write loops.
Notes¶
- Cursor, Copilot, Gemini, Junie, Opencode, Antigravity, Cline, and Continue.dev expose effort behind UI toggles or in user-managed config files we don't generate. ai-rulez deliberately skips emission for them — guard tests lock that in. Configure effort in those tools' own settings instead.
- See
docs/configuration.mdfor the full per-preset mapping table.
[4.1.0] - 2026-04-29¶
Added¶
- Reasoning effort on Claude Code subagents: agent frontmatter now accepts an
effortfield (low|medium|high|xhigh|max|inherit) that ai-rulez emits into.claude/agents/<name>.md. Maps directly to Claude Code's adaptive thinking spec — available levels depend on the model. defaults.effortinconfig.yaml/config.toml: top-level project default that propagates to every generated subagent which doesn't declare its owneffort. Resolution order: per-agent →defaults.effort→ omit.- MCP
update_configdefault_effortparameter: lets MCP clients set or clear the project-wide default.read_confignow always returnsdefault_effort(possibly empty) so read-modify-write loops have a stable contract. - Validation for the new value set across config load, MCP
update_config, andai-rulez validate— invalid values fail with an actionable message naming the field and the offending value.
Notes¶
- Other presets (Cursor, Windsurf, Copilot, Gemini, Antigravity, etc.) silently skip the
effortfield — they have no native equivalent yet. No-leak tests lock that in. - Claude Code's session-level effort remains a runtime setting (
/effortslash command) — there is no static surface to render it into, so this release covers subagents only.
[4.0.8] - 2026-04-27¶
Fixed¶
- Generation was non-deterministic across runs:
content.Domainsis a Go map, and every preset that flattened domain rules/context/skills/agents/commands iterated it in randomized order. Two consecutivegenerateruns with identical sources produced different rule orderings inCLAUDE.md,.github/copilot-instructions.md, and every other multi-rule output, breaking pre-commit hook idempotency. Domain iteration is now sorted by name (internal/generator/presets/helpers.go). toolsfield corrupted into a Go slice string:Metadata.Extra map[string]stringcould not hold YAML sequences —tools: [Read, Grep, Glob]was stringified viafmt %vto"[Read Grep Glob]"and emitted astools: '[Read Grep Glob]'. Added typedTools,Skills,Keywordsfields onMetadata; YAML now round-trips as proper sequences in agent frontmatter across all presets (claude, amp, antigravity, cline, copilot, gemini, junie, windsurf).mcppreset rejected by validation:internal/generator/presets/mcp.goregistered anmcppreset generator, butinternal/config/types.gobuiltInPresetsdidn't list it — configs that includedmcpin their preset array failed withunknown built-in preset: "mcp". Added to the map.- Skip-on-content-hash never fired for files with both frontmatter and a banner: windsurf rule files have YAML trigger frontmatter prepended to the standard generated-file banner.
stripHeaderonly stripped one layer, so the banner's per-run timestamp leaked into the body hash and caused unnecessary rewrites every run. Now strips both layers.
Added¶
Source-Hashheader line: alongside the existingContent-Hash, every generated file now embeds a blake3 hash covering all profile-relevant inputs (config metadata, content tree, MCP servers, plus a generator schema version constant). The skip decision inwriteOutputrequires both hashes to match the values stored in the existing file — never re-hashes the on-disk body, so it's robust to formatters that may modify generated files post-write.- Hash injection for YAML-frontmatter files: skill and agent files (
.claude/skills/*/SKILL.md,.opencode/agents/*.md, etc.) had no header to inject hashes into and were rewritten every run. Hashes now go in as YAML comment lines (# Content-Hash:/# Source-Hash:) inside the frontmatter, where YAML parsers ignore them.
Changed¶
- Sort everything alphabetically by name: scanner's
sortByPriorityreplaced withsortByName; merged content slices re-sorted incombineContentFiles; typed list metadata (Tools/Skills/Keywords) sorted on load. Priority is preserved as metadata in the rule body and rendered next to the rule name. This is a behavior change — projects with mixed-priority rules will see one round of reordered output. - Output normalized to a single trailing newline at write time, so
end-of-file-fixerand similar formatters don't modify files post-generation.
[4.0.7] - 2026-04-27¶
Fixed¶
.mcp.jsonnot asserted in managed gitignore fence:cursor,copilot, and the auto-mcppreset all emit.mcp.jsonwhen MCP servers are configured, but no regression test confirmed the path actually landed in the# BEGIN ai-rulezblock. Coverage added; behavior verified end-to-end across all preset combinations.- Cross-fence gitignore duplication: when a user already had a pattern (e.g.
.cursor/,CLAUDE.md) listed manually outside the managed block, regenerate added the same line inside the fence too. The writer now skips any pattern already present outside the fence. --debugflag did nothing: registered onRootCmdbut never propagated to the logger singleton. Addedlogger.SetLeveland aPersistentPreRunthat lowers the level toDEBUGwhen--debugis set (and toERRORfor--quiet).--update-gitignoreflag did nothing: declared ongeneratebut never read. Now forcescfg.Gitignore = trueregardless of the config file value, matching the help text.
Changed¶
- Demoted intentional-behavior warnings to debug: scanner's
domain X file overrides root fileandmultiple domains have same filewereWARN-level on every legitimate domain override (documented design, not user error). Generator'sOutput path conflictlikewise fired any timecursor+copilot+auto-mcpshared.mcp.json(also expected). All three are nowDEBUG. - Quieter generation output:
Processing commands for Claude preset, per-commandChecking command/Including command, andScanned commands directoryare nowDEBUG. Run with--debugto see them again.
[4.0.6] - 2026-04-25¶
Fixed¶
- MCP schema rejected V4 configs:
ai-rules-mcp.schema.jsononly allowed version"3.0"— V4 configs failed validation. Now accepts both"3.0"and"4.0". - Generated file headers hardcoded
config.yaml: preset generators always wroteSource: .ai-rulez/config.yamlin output headers, even for TOML or JSON configs. Headers now reflect the actual config filename.
Changed¶
- Removed stale V3 naming across codebase:
ValidateV3()renamed toValidate(),isV3ConfigFile()toisConfigFile(),DetectConfigVersionreturns"dir"instead of"v3", test fixtures and helpers renamed to version-neutral names. - Added
IsV4()method toConfigfor symmetry withIsV3().
[4.0.5] - 2026-04-25¶
Fixed¶
- Config discovery missing TOML:
FindConfigFile(used by MCP handlers) only searched for YAML/YML configs, ignoringconfig.toml(the V4 default) andconfig.json. TOML is now checked first. - Recursive generate missed TOML configs:
isV3ConfigFile(used bygenerate --recursiveand pre-commit hooks) did not matchconfig.tomlorconfig.json, so projects using the V4 default were silently skipped.
[4.0.4] - 2026-04-25¶
Fixed¶
- Pre-commit hooks broken for V3/V4 users: file trigger patterns in
.pre-commit-hooks.yamlonly matched V2-style filenames — hooks never fired when.ai-rulez/directory content changed. Updated to^\.ai-rulez/. - Stale versions across packages: default download version in
run-ai-rulez.shwasv3.0.0,officialPreCommitRevinsetup.gowasv2.4.3, lefthook glob was V2-only. All updated. - Init templates generated old config version: YAML and JSON templates used
version: "3.0"while TOML correctly used"4.0". All formats now default to"4.0". - PyPI wrapper version drift:
release/pypi__version__was stuck at3.14.2, causing binary download mismatches. - Stale
ErrInvalidVersionsentinel: error message only mentioned3.0, now includes4.0.
Added¶
- Taskfile: added
Taskfile.ymlwithsetup,update,upgrade,set-version,build,test,lint,check, andcleantasks.set-versionupdates all 8 version locations in one command. - Hook unit tests: added
internal/hooks/hooks_test.goandsetup_test.gocovering detection, all three hook systems (lefthook, pre-commit, husky), idempotency, legacy pruning, and error paths.
[4.0.3] - 2026-04-24¶
Fixed¶
- Gitignore cleanup: shared directories (e.g.
.github/) now use subdirectory patterns (.github/agents/,.github/skills/) instead of listing every individual file. Nested paths deduplicated automatically. - Stale binary: builtin agents were generated by
GeneratePresetsbut not written to disk when using a stale binary. Confirmed working with fresh build.
[4.0.2] - 2026-04-24¶
Added¶
- Builtin agents: code-reviewer, test-writer, security-auditor, docs-writer, devops-engineer, release-engineer — specialized agents shipped with the tool, ready to use as subagents.
- New rules (adapted from superpowers patterns): verification-before-completion, systematic-debugging, testing-anti-patterns.
- Strengthened TDD rule: iron law enforcement — wrote code before the test? Delete it, start over, no exceptions.
Changed¶
- README redesigned: value-first structure showing builtin capabilities, agents, and full development workflow.
- Package descriptions updated across npm, PyPI, and GitHub to reflect complete workflow capabilities.
[4.0.1] - 2026-04-24¶
Added¶
- New builtins:
cicd(pipeline standards, GitHub workflow),docker(container best practices),observability(logging, metrics, health checks). - New ai-governance rules:
no-ai-signatures(no AI attribution in commits/PRs/code),agent-workflow(subagent delegation with mandatory critical review),communication-style(concise, no fluff/emojis/checklists). - New testing rule:
tdd-workflow(TDD red-green-refactor, test type taxonomy). - New code-quality rule:
anti-patterns(magic numbers, global state, composition over inheritance). - Auto-include expanded:
code-quality,testing,git-workflow,security,token-efficiencyare now auto-included by default alongsideai-governanceandagent-delegation.
Fixed¶
migrate v4preserves MCP servers from legacymcp.yamlfiles — previously lost during migration.
Changed¶
token-efficiency/task-runnerenriched with standard task naming conventions and lock file requirements.
[4.0.0] - 2026-04-23¶
Breaking Changes¶
- TOML is the default config format:
ai-rulez initnow generatesconfig.tomlinstead ofconfig.yaml. Existing YAML configs continue to work. - MCP servers are inline: MCP servers are now configured in your main config file under
[[mcp_servers]]instead of a separatemcp.yaml. Legacymcp.yamlfiles are still loaded with a deprecation warning. - V2 compatibility removed: All V2 config types, migration code, validator, and generators have been removed. V3 YAML configs remain fully supported.
- Deprecated features removed:
CompressionConfig,--skip-mcpflag,--auto-migrateflag,migrate v3command.
Added¶
- Agent generation for all presets: Amp, Windsurf, Cline, and Continue.dev now generate agent files with YAML frontmatter.
- Context rendering for per-file presets: Cursor, Windsurf, and Cline now render context as rule-like files.
- Claude MCP & plugins output:
.claude/settings.json(MCP servers) and.claude/plugins.json(plugin declarations). - Cursor/Copilot MCP output:
.mcp.jsongenerated when MCP servers are configured. - Codex plugins & commands:
.codex/plugins.jsonand.codex/commands/output. - Copilot command generation:
.github/commands/output for Copilot. - Gemini/Antigravity user MCP servers: Settings.json now includes user-configured servers alongside the hardcoded ai-rulez server.
- TOML config support: Config loader tries TOML first, then YAML, then JSON.
- Plugins and marketplaces: New
[[plugins]]and[[marketplaces]]config sections for declaring tool extensions. migrate v4command: Convertsconfig.yamltoconfig.toml, inlines MCP servers, removes old files.- Backward-compatible
mcp.yamlloading: Legacy separate MCP files are loaded with a deprecation warning.
Changed¶
- All V3 types renamed:
ConfigV3→Config,ContentTreeV3→ContentTree,OutputFileV3→OutputFile, etc. - Schema files renamed:
ai-rules-v3.schema.json→ai-rules.schema.json,ai-rules-v3-mcp.schema.json→ai-rules-mcp.schema.json. - Schema updated: Accepts version
"3.0"or"4.0", addspluginsandmarketplacesfields, removes deprecatedcompression. - Documentation migrated to Zensical: Replaces MkDocs with Zensical for documentation site generation.
- All documentation updated for V4: TOML examples, inline MCP, plugins/marketplaces, updated CLI reference.
Removed¶
- V2 config types, loader, migration tool, validator, and generators (~3000 lines).
- V1 and V2 JSON schemas.
- V2 template rendering engine and builtin templates.
CompressionConfig(deprecated no-op).- Separate MCP file loading functions (replaced by inline config).
- MkDocs configuration (
mkdocs.yaml). - Generated documentation site (
site/).
[3.14.2] - 2026-04-20¶
Fixed¶
- Critical: generator deleting non-generated files in
.github/:cleanManagedDirswas treating.github/as a fully managed directory, deleting workflows, CODEOWNERS, issue templates and other user content duringgenerate. Now skips shared directories that contain both generated and non-generated content.
[3.14.1] - 2026-04-20¶
Fixed¶
- CI: missing Taskfile tasks: Added
test:e2e,test:e2e:cli,test:e2e:mcp,test:e2e:integration,test:platform, andtest:alltasks that the CI/E2E workflows referenced but didn't exist. - CI: golangci-lint-action: Pinned to
@v7(resolves@latestlookup failure), useversion: latestfor the binary. - CI: stale test expectations: Fixed
TestInitExistingConfig(unset CI env to test non-interactive mode) andTestValidateFailsWhenSkillDescriptionMissing(updated to match 3.13.1 behavior change where missing description is a warning, not error). - Windows test failures: Fixed path separator issues in
TestAmpPresetGenerator_Generate_WithSkillsandTestClinePresetGenerator_Generate_WithSkillsusingfilepath.ToSlash. - Stale comment: Fixed
git.gocache directory comment (was.ai-rulez/.remote-cache/, actual is~/.cache/ai-rulez/includes/).
[3.14.0] - 2026-04-20¶
Added¶
- Antigravity preset: New
antigravitybuilt-in preset generatingGEMINI.md,.agents/settings.json, and skills/agents to.agents/skills/and.agents/agents/. - Gemini skills and agents: Gemini preset now generates skill files to
.agents/skills/{id}/SKILL.mdand agent files to.agents/agents/{name}.mdwith YAML frontmatter. - Cursor agents: Cursor preset now generates agent files to
.agents/agents/{name}.mdwith YAML frontmatter (name, description, model, readonly, is_background). - Cursor skills moved to
.agents/: Cursor skills output moved from.cursor/skills/to.agents/skills/following the cross-agent standard. - Codex subagents: Codex preset now generates agent files to
.codex/agents/{name}.tomlin TOML format (name, description, developer_instructions). - AMP skills: AMP preset now generates skill files to
.agents/skills/{id}/SKILL.md. - Windsurf skills: Windsurf preset now generates skill files to
.windsurf/skills/{id}/SKILL.md. - Copilot skills and agents: Copilot preset now generates skill files to
.github/skills/{id}/SKILL.mdand agent files to.github/agents/{name}.agent.mdwith YAML frontmatter. - Cline skills: Cline preset now generates skill files to
.cline/skills/{id}/SKILL.md. - Junie skills and agents: Junie preset now generates skill files to
.junie/skills/{id}/SKILL.mdand agent files to.junie/agents/{name}.mdwith YAML frontmatter. - OpenCode skills and agents: OpenCode preset now generates skill files to
.opencode/skills/{id}/SKILL.mdand agent files to.opencode/agents/{name}.mdwith YAML frontmatter. - Output conflict detection: Generator now warns when multiple presets write to the same file path, deduplicates directory entries, and uses last-write-wins for file conflicts.
- Vite+ builtin: New
vite-plusbuiltin for the unified TypeScript toolchain (oxlint, oxfmt, vitest, rolldown/tsdown, task caching). - MCP read tools: New
read_rule,read_context,read_skillMCP tools for reading file content without filesystem fallback. - MCP
working_directoryparameter: All MCP CRUD and project tools now accept an optionalworking_directoryparameter for polyrepo support. - MCP enum constraints:
priorityandmerge_strategyfields now use JSON Schemaenumconstraints for better LLM tool use. - MCP
read_config/update_config: New tools for reading and updatingconfig.yamlfields (name, description, builtins, gitignore) via MCP. - MCP
dry_run/recursive:generate_outputsnow acceptsdry_run(preview mode) andrecursive(walk subdirectories) parameters. - MCP annotations: All tools now have
readOnlyHint/destructiveHintannotations so clients can implement appropriate confirmation UX. builtins showcommand: Newai-rulez builtins show <name>CLI command andshow_builtinMCP tool to inspect builtin domain contents (rules, context, skills with priorities).- Content hash: Generated files include a
Content-Hash: blake3:<hex>in the header. Files are skipped when the hash matches, eliminating timestamp-only diffs. - Include cache TTL: Git-based includes are cached for 1 hour instead of re-fetched every run. New
--no-fetchflag for offline generation.
Changed¶
- Rust builtin: Added Rust API Guidelines (naming conventions, trait implementations, type safety, builder pattern, sealed traits, rustdoc standards) and Rust Design Patterns reference.
- MCP atomic updates:
update_rule,update_context,update_skillnow use atomic overwrite (temp+rename) instead of delete-then-create, preventing data loss on write failure. - MCP
with_agentsparameter:init_projectnow creates.ai-rulez/agents/directory whenwith_agentsis true (previously silently ignored). - MCP
list_contextunified: Mergedlist_contextandlist_contextsinto a single enriched endpoint returning summaries. - MCP list metadata:
list_rules,list_context, andlist_skillsnow populatepriorityandtargetsfields from YAML frontmatter. - CLAUDE.md inlines all content: Local project rules and contexts are now inlined in CLAUDE.md instead of using
@pathreferences, matching all other presets. - Gitignore idempotent updates:
.gitignorenow uses fenced# BEGIN ai-rulez/# END ai-rulezmarkers. Repeatedgenerateruns replace the block instead of appending duplicates. Old-style# AI Rules generated filesheaders are auto-migrated.
[3.13.1] - 2026-04-19¶
Fixed¶
- Frontmatter parsing: Fall back to raw map parsing when direct YAML unmarshal fails (e.g., SKILL.md files with nested
metadata:objects). Nested values are stringified for the Extra map. - Skill description validation: Downgraded missing description from a fatal error to a warning. Uses skill name as fallback description instead of failing generation.
- Cache directory consistency: Unified all cache locations to
~/.cache/ai-rulez/(XDG convention) instead of mixingos.UserCacheDir()(~/Library/Cacheson macOS) with~/.cache/.
Changed¶
- Module structure: Restructured shared modules to use
.ai-rulez/subdirectories, enabling remote includes via GitHub URLs withoutlocal_override. - mdformat exclusion: Excluded
.ai-rulez/directories from mdformat pre-commit hook to prevent YAML frontmatter destruction. - Enriched agents: Improved devops-engineer, docs-writer, polyglot-architect, and code-reviewer agents with more detailed guidance.
[3.13.0] - 2026-04-19¶
Added¶
- Agent delegation builtin: New
agent-delegationauto-included builtin that renders an "## Agents" section in generated outputs (CLAUDE.md, AGENTS.md, GEMINI.md) listing all available subagents with their descriptions and delegation/parallelization instructions. Disable withbuiltins: ["!agent-delegation"]. - New binding builtins:
jni-rs(Rust-Java/JVM),extendr(Rust-R),cgo(Go-C/Rust FFI). - Token-efficiency rules: Three new rules —
batch-operations,incremental-approach,context-preservation— expanding the builtin from 2 to 5 rules.
Deprecated¶
- Compression: The
compressionconfig option is now a no-op and will be removed in a future version. Existing configs withcompressionwill still parse without error but emit a deprecation warning. The compression feature's stopword removal at moderate+ levels stripped meaning-critical words (negations, verbs, prepositions), making generated output ungrammatical and sometimes inverting meaning. Condense content at the source level instead.
Removed¶
- Compression package: Deleted
internal/compression/— all compression logic, stopword lists, semantic scoring, and hypernym replacement.
Changed¶
- Language builtins improved: All 10 language convention files (Rust, Python, TypeScript, Go, Java, Ruby, PHP, Elixir, C#, R) restored to 11-14 bullets each with security scanning tools, benchmarking frameworks, build system guidance, and key language patterns.
- Binding builtins improved: Fixed accuracy issues in PyO3 (
Py<T>deprecation wording), Magnus (build tools), and ext-php-rs (error mapping, GC, async guidance). - Universal builtins improved: Rewrote
output-awarenesswith concrete limits, restoreddependency-awarenessper-language tool list, rewrote OWASP context verb-first, sharpenedread-before-writevsverify-before-actingdistinction, improvedavoid-duplicationwith concrete "three similar lines" guidance.
[3.12.0] - 2026-04-17¶
Added¶
- Installed skills: New
ai-rulez skill install/remove/listcommands for installing named skills from external git repos or local paths. Skills are fetched dynamically at generate time and included in outputs. Config field:installed_skillsin config.yaml. - MCP tools for installed skills:
install_skill,uninstall_skill,list_installed_skillsMCP operations. - Distributable ai-rulez skill:
skills/ai-rulez/folder at repo root with comprehensive SKILL.md and reference docs, installable by other projects. installed_skillsJSON schema: Schema validation for the new config section.- llms.txt: Added LLM-friendly documentation index at
docs/llms.txt.
Fixed¶
- YAML config preservation:
SaveConfigV3now usesyaml.Noderound-tripping to preserve field ordering, comments, and formatting when modifying config (e.g.,skill install,include add). Previously, saving re-marshaled the entire config, losing comments and reordering fields. - Stale cache invalidation: Include and skill caches are now cleared before each fetch, preventing stale data from previous downloads from contaminating results.
- golangci-lint clean: Extracted
sourceTypeGit/sourceTypeLocalconstants, fixedgocriticshadow and named result warnings.
Changed¶
- golangci-lint pinned in CI:
golangci-lint-action@latestwithversion: v2.11.4in CI workflow.
[3.11.5] - 2026-04-15¶
Fixed¶
- Claude preset: no headers in skills/agents/commands: Generated header comments (
<!-- AI-RULEZ ... -->) are no longer emitted in skill, agent, or command files. These files serve as prompts for Claude Code — header comments wasted tokens and injected confusing "DO NOT EDIT" instructions into the agent's system prompt. Headers are now only emitted in CLAUDE.md and equivalent top-level files.
[3.11.4] - 2026-04-15¶
Fixed¶
- Claude preset: frontmatter placement: Skill, agent, and command files now emit YAML frontmatter (
---) as the first line, before the generated header comment. Previously the HTML comment header was placed before frontmatter, preventing Claude Code from parsing it. - Claude preset: skill frontmatter fields: Skills now include
user_invocable(false for domain skills, true for commands) anddescriptionin frontmatter. Removed ai-rulez internal fields (priority,targets) from Claude output. - Include domain profiles (#97):
GetContentForProfilenow addsFromIncludeand builtin domains before profile-specific domains, ensuring included domains are always available regardless of profile configuration.mergeDomainInstallnow correctly setsFromInclude=trueon new domains. - Non-deterministic output:
mergeContentFileswithbaseWins=falsenow iterates the include slice instead of a map, producing deterministic file ordering across regenerations. - Lint: Fixed
rangeValCopywarnings in include CRUD operations andgofmtformatting inIncludeConfigstruct.
Added¶
local_overridefor includes: Newlocal_overridefield on include configs allows using a local directory instead of fetching from git. If the local path exists, it is used; if not, the include falls back to the configured git source. Supports thepathsubdir field. Useful for developing shared rules locally before pushing.- Minimal headers for skills/agents:
StyleOverridefield onTemplateDataallows preset generators to force a specific header style. Claude preset now uses "minimal" headers for skills and agents to reduce token waste.
Changed¶
- Profile domain warnings:
warnMissingDomainReferencesnow emits debug-level (not warn-level) messages when includes are configured and a referenced domain is missing, since the domain may exist in an include that failed to resolve.
[3.11.3] - 2026-03-29¶
Fixed¶
- Includes: fail fast when includes are configured but the includes resolver isn't registered, preventing silent drops of included domains referenced by profiles.
Added¶
- Integration coverage for profiles resolving domains delivered via includes, ensuring included domains stay visible to profile selection.
Changed¶
- GolangCI-Lint now tracks the
latestrelease in CI and pre-commit instead of a pinned version.
[3.11.2] - 2026-03-25¶
Fixed¶
- Gitignore:
.github/directory no longer ignored: The gitignore updater was adding.github/as a directory-level pattern because the copilot preset creates.github/copilot-instructions.md. This caused CI workflows and other.github/content to be ignored. Shared directories like.githubare now excluded from directory-level patterns — only individual generated files inside them are gitignored. - Gitignore: no more individual file paths: Files inside fully-managed directories (e.g.
.claude/skills/foo/SKILL.md) are no longer added individually to.gitignore— the parent directory pattern covers them.
[3.11.1] - 2026-03-25¶
Added¶
- R language builtin: R conventions covering tidyverse style, testthat, roxygen2, CRAN compliance, and extendr/rextendr Rust FFI bindings
[3.11.0] - 2026-03-25¶
Fixed¶
- Include domain duplication (issue #97): Include sources now use
ScanContentTreeinstead ofscanner.ScanProfile, preventing domain content from appearing twice in generated output - Claude preset output bloat: Skill, agent, and command-as-skill files no longer embed all rules and context; only explicitly targeted content is included (reduces
.claude/from ~13MB to ~440KB on large projects) - Stale file cleanup: Generator now removes orphaned files from managed output directories (
.claude/skills/,.claude/agents/) before writing new output
Changed¶
- Rules rendered as
@references: Local project rules in CLAUDE.md now use@pathlazy-loading references instead of full inlining, matching the existing context rendering pattern. Builtin and included rules remain inlined. - Exported
ScanContentTree:config.ScanContentTree()is now public for use by include sources and external consumers - Context and rules rendering consolidated into shared
renderContentRefhelper
[3.10.0] - 2026-03-18¶
Fixed¶
- Included skills validation: Frontmatter parser now captures
descriptionand other extra fields from included skill files via YAML inline tag (issue #96) - Included domains in profiles: Include sources (git and local) now discover and scan domain directories, so consuming projects can reference included domains in profiles (issue #97)
Changed¶
- Include domain discovery skips hidden directories (e.g.
.git) in thedomains/tree
[3.9.0] - 2026-03-11¶
Added¶
- Root
.ai-rulez/commands/documentation files forbuild,fix,lint,review, andtest - Repository-managed
.pre-commit-config.yamlwith commit-message linting andprek-driven checks
Changed¶
- Replaced
lefthook.yamlwith theprek/pre-commit toolchain across local workflows, CI wiring, and helper scripts - Refreshed command-generation, docs-site output, and test fixtures to match the new command docs and hook setup
- Aligned Go/tooling dependencies and CI lint configuration with the current Go
1.26toolchain
Fixed¶
- Codex skill generation now always emits
descriptionin.codex/skills/*/SKILL.md, falling back to the skill ID when needed - V3 validation now rejects source
SKILL.mdfiles that omit a non-emptydescription - Skill import, CRUD creation, and V2 section migration now synthesize valid skill descriptions so generated Codex skills always load
- E2E test binary setup now uses a stable temp path, preventing later suites from inheriting deleted binaries
[3.8.3] - 2026-03-08¶
Fixed¶
- GetContentForProfile: Domain content from includes no longer duplicated into root-level slices; domains are now placed only in the Domains map for proper preset generation
- Includes resolver: Added
FromIncludefield toDomainV3to track domains originating from external includes
[3.8.2] - 2026-03-08¶
Fixed¶
- Claude preset: Domain skills, agents, and commands are now properly collected and generated (previously only root-level content was processed)
- Builtins:
default-commandsbuiltin (/iterate,/parallelize) now generates Claude skill files correctly
Changed¶
- Builtin language conventions: All 9 language builtins expanded with explicit linting toolchain, SAST tools, coverage tools, benchmark tools, and package manager recommendations
- Rust: added
cargo-llvm-cov,cargo deny,cargo-machete,criterion,cargo-flamegraph,Cow/Arc/memchr/SIMD guidance - Python: added
bandit,hypothesis,uvlockfile,hatchling/maturin,pytest-benchmark,py-spy/scalene - TypeScript: added
oxlint,pnpmpreferred,tsup/esbuild,socket.dev/snyksupply chain - Go: added
govulncheck,gosec, specificgolangci-lintlinters,benchstat - Java: added Gradle preference,
google-java-format,Error Prone,Checkstyle,SpotBugs,JaCoCo,JMH - Ruby: added
rubocopplugins,bundler-audit,brakeman,factory_bot,simplecov - PHP: added
PHP-CS-Fixer,Psalm,roave/security-advisories, PSR-4 autoloading - Elixir: added
excoveralls,sobelow,mix_audit,dialyxir,ExDoc - C#: added
StyleCop.Analyzers,Roslynator,coverlet,BenchmarkDotNet,ValueTask - Security builtin:
dependency-awarenessrule expanded with per-language audit tool recommendations - Token efficiency builtin: Description updated from "RTK awareness" to "Output efficiency and task automation"
[3.8.1] - 2026-03-07¶
Changed¶
- Token reduction: Replaced simple compression system with kreuzberg-ported token reduction engine
- 5 reduction levels:
off,light,moderate,aggressive,maximum - Markdown-aware processing preserves headers, lists, tables, and code blocks
- Stopword removal with language support (English)
- Sentence scoring and selection for aggressive/maximum levels
- Semantic token scoring and hypernym compression for maximum level
- Backward-compatible: old level names (
none/minimal/standard) auto-mapped - Compression config: New fields
preserve_markdown,preserve_code,language; removedremove_duplicates,use_abbreviations,preserve_formatting
Fixed¶
- Includes: Flat ai-rulez structure (rules/, context/ directly) now detected at sub-paths, not just at repository root
- Includes:
findAIRulezDir()andfindSourceDir()both support flat structure at sub-paths for git sources
[3.8.0] - 2026-03-07¶
Added¶
- Built-in domains system: 23 embedded content domains shipped with the binary via
//go:embed - 8 universal domains:
ai-governance(auto-included),security,git-workflow,code-quality,testing,token-efficiency,documentation,default-commands - 9 language domains:
rust,python,typescript,go,java,ruby,php,elixir,csharp - 6 binding domains:
pyo3,napi-rs,magnus,ext-php-rs,rustler,wasm builtinsconfig field with flexible syntax:builtins: true— enable all built-in domainsbuiltins: false— disable all (including auto-includes)builtins: [rust, python, security]— enable specific domainsbuiltins: ["!ai-governance"]— exclude auto-included domainsai-rulez builtins listCLI command to show available built-in domains (supports--json)/iterateslash command (viadefault-commandsbuiltin): instructs LLM to work in implementation/review/adjustment cycles/parallelizeslash command (viadefault-commandsbuiltin): instructs LLM to split tasks among subagentsBuiltinsConfigtype with custom YAML/JSON marshaling supporting boolean and array formats- Builtins merge at lowest priority — local content and includes always override builtin content
Changed¶
- Schema updated:
builtinsfield added, preset enum updated withcodex,amp,junie,opencode
[3.7.3] - 2026-02-19¶
Fixed¶
- Publish workflow now resolves Go from
go.modfor GoReleaser (go-version-file: "go.mod"), preventing asset build failures when the module Go version advances
Changed¶
- Contribution guide now requires Go
1.26+and references the correct release workflow file (.github/workflows/publish.yaml)
[3.7.2] - 2026-02-16¶
Fixed¶
- Claude preset skill rendering now respects frontmatter
targetswhen embedding rules/context in.claude/skills/*/SKILL.md, preventing unrelated content leakage - npm installer now supports offline/private-registry bundled binaries (
bin/ai-rulez-{os}-{arch}), using packaged binaries before attempting GitHub release downloads
[3.7.1] - 2026-02-16¶
Fixed¶
- Windsurf trigger frontmatter now safely YAML-quotes
descriptionandglobvalues, preventing malformed output when values include special characters - Windsurf invalid trigger warning now reflects the original unsupported trigger value before fallback
[3.7.0] - 2026-02-16¶
Added¶
Fixed¶
- Includes system now correctly includes agents in merged include content (PR #83)
- Codex skill generation now always writes
descriptionin.codex/skills/*/SKILL.mdfrontmatter
Changed¶
- Bumped Go toolchain target to
1.26and aligned CI workflows - Bumped
golangci-linttov2.9.0across Taskfile, hooks, and CI - Updated Go, Node, and Python/docs dependencies to latest available versions
[3.6.1] - 2026-01-07¶
Fixed¶
- Windows binary packaging - now uses
.zipformat instead of.tar.gzfor Windows releases
[3.6.0] - 2026-01-05¶
Fixed¶
Preset Generator Skills/Commands Inlining Bug¶
- Claude: Removed skills and commands from CLAUDE.md (77% size reduction - 14K lines to 3.2K lines)
- Skills now only generate to
.claude/skills/{skill-id}/SKILL.md - Commands now only generate to
.claude/skills/{command-id}/SKILL.md - Cursor: Added missing skills and commands directory support
- Skills now generate to
.cursor/skills/{skill-id}/SKILL.md - Commands now generate to
.cursor/commands/{command}.md(was.cursor/rules/cmd-*.mdc) - Codex: Removed skills inlining from AGENTS.md
- Skills now generate to
.codex/skills/{skill-id}/SKILL.md - AGENTS.md only contains Rules and Context
- Gemini: Removed skills inlining from GEMINI.md
- Copilot: Removed skills inlining from
.github/copilot-instructions.md - AMP: Removed skills inlining from AGENTS.md
- OpenCode: Removed skills inlining from AGENTS.md
- Junie: Removed skills inlining from
.junie/guidelines.md
Changed¶
- All preset generators now correctly separate skills into dedicated directories
- Main preset files (CLAUDE.md, GEMINI.md, etc.) only contain Rules and Context
- Skills are lazily loaded from separate files, reducing prompt token usage
[3.5.0] - 2026-01-04¶
Added¶
V3-Native Command System¶
- File-based slash commands in
.ai-rulez/commands/directory with YAML frontmatter - Profile-aware commands (root + domain-specific commands)
- Commands generate to preset-specific formats:
- Claude:
.claude/skills/{command-name}/SKILL.md - Cursor:
.cursor/rules/cmd-{name}.mdc - Continue.dev: Entries in
.continue/prompts/ai_rulez_prompts.yaml - Support for all 18 presets
- Command metadata: name, aliases, description, usage, shortcut, priority, category, targets
- V2 command migration support via
ai-rulez migrate v3
Prompt Compression¶
- Configurable compression levels: none, minimal, standard, aggressive
- Simple optimizations without external dependencies:
- Whitespace removal (trailing spaces, excessive blank lines)
- Priority label compaction
- Abbreviations (aggressive mode)
- Context optimization: summaries with @ links instead of full content (34% size reduction)
- Compression stats logging during generation
Context File Optimization¶
- Required
summaryfield in context frontmatter for concise descriptions - Context rendered as summaries with @ links to full files
- MCP
list_contextstool added to list context files with names and summaries - Enables agents to fetch full context only when needed
Changed¶
- Remote includes cache moved from
.remote-cache/to system cache directory - macOS:
~/Library/Caches/ai-rulez/includes/ - Linux:
~/.cache/ai-rulez/includes/ - Windows:
%LocalAppData%/ai-rulez/includes/ - Context files now require
summaryfield in frontmatter - CLAUDE.md and other presets significantly smaller (9.5K vs 14K, 34% reduction)
Fixed¶
- Include system now properly merges commands from remote sources
- Scanner properly scans commands in root and domain directories
- Default profile now includes commands in content tree
3.4.1 - 2026-01-03¶
Added¶
- SSH git clone support for private repositories - automatically uses
git clonefor SSH URLs (git@...,ssh://...) - Support for self-hosted GitLab instances and other GitLab-compatible git servers
- Support for repositories where root IS the ai-rulez structure (no nested
.ai-rulez/directory) - Automatic detection of repository structure (standard vs root-level)
Changed¶
- Git includes now use native SSH cloning when SSH URLs are detected, leveraging existing SSH key configuration
- Improved git include fetching to skip
.gitdirectory when copying repository content
Documentation¶
- Added comprehensive SSH cloning documentation in docs/includes.md
- Added repository structure support documentation
- Added self-hosted GitLab examples and requirements
3.4.0 - 2026-01-03¶
Added¶
- Configurable header styles for generated files (detailed, compact, minimal)
- CLAUDE.md generation to claude preset
- Enhanced headers with AI-RULEZ explanation, folder structure, and MCP server usage instructions
- Markdown formatting support using goldmark and goldmark-markdown
- Markdown processor utilities to normalize embedded content (strip duplicate H1 headings, normalize blank lines)
- Markdownlint configuration for generated files
- Comprehensive documentation for header configuration in docs/configuration.md
Changed¶
- All 11 presets now include enhanced headers with AI agent instructions
- Generated markdown files now pass markdownlint validation
- Headers now explain what ai-rulez is, the .ai-rulez folder structure, and how to use the MCP server
- Embedded content processing removes duplicate headings and normalizes formatting
Dependencies¶
- Added github.com/yuin/goldmark v1.7.13
- Added github.com/teekennedy/goldmark-markdown v0.5.1
3.3.2 - 2026-01-02¶
Fixed¶
- SSH git URL conversion in includes system - now properly converts SSH URLs to HTTPS for archive downloads
- Added support for multiple SSH URL formats:
git@host:owner/repo.git,ssh://git@host/owner/repo.git - Updated validation to accept SSH URLs alongside HTTP/HTTPS URLs
Documentation¶
- Added comprehensive examples for Git includes with SSH and HTTPS URLs in README
- Updated includes documentation with supported Git URL formats and include options
3.3.1 - 2025-12-31¶
Fixed¶
- SSH git URL detection in includes system - now properly detects
git@host:pathformat URLs - Previously only HTTP/HTTPS URLs were recognized, causing SSH git URLs to be treated as local paths
3.3.0 - 2025-12-31¶
Fixed¶
- Complete agents support in includes system
- Add agents scanning support to includes and scanner
Changed¶
- Bump actions/cache from 4 to 5
- Bump actions/upload-artifact from 4 to 6
3.2.2 - 2025-12-28¶
Added¶
- Init now creates root and domain agent directories by default
- Generated MCP config now includes the ai-rulez MCP server
Fixed¶
- MCP tool configs now render with structured MCP output for supported tools
Changed¶
- Bumped golangci-lint to v2.7.2 in Taskfile and CI
3.2.1 - 2025-12-28¶
Fixed¶
- Gitignore updates now use relative paths instead of absolute machine-specific paths
- .ai-rulez directory is no longer added to .gitignore (source of truth should be tracked)
- Added tests to verify gitignore path handling
3.2.0 - 2025-12-28¶
Added¶
- Full agent/subagent support in V3 configuration with
.ai-rulez/agents/directory - Auto-migration feature in generate command (detects V2 configs and migrates automatically)
- Interactive prompting for migration in terminal environments
- Silent auto-migration in CI environments
--auto-migrateflag for explicit migration control- Agent metadata support (name, description, model, tools, permission_mode, skills)
- Claude Code subagent format generation to
.claude/agents/
Fixed¶
- Migration mapping corrected: V2 sections → V3 skills, V2 agents → V3 agents
- Agent model field now preserved in YAML frontmatter during migration
- Backup directories automatically deleted on successful migration
- V3→V2 conversion now uses correct agent source
- Default profile now includes agents in generated content
- Code quality improvements (removed unused functions, reduced cyclomatic complexity)
Changed¶
- Dependencies updated to latest minor versions (19 packages upgraded)
- Migration now creates proper directory structure for skills (skills/{id}/SKILL.md)
3.1.0 - 2025-12-27¶
Added¶
- Migrate command for V2 to V3 configuration migration
- Comprehensive test suite for migrate command (27 tests covering command structure, flags, and utility functions)
- Integration test placeholder to prevent test runner errors
Fixed¶
- Windows path separator issues in tests (content_test.go, validation_test.go, local_test.go)
- Windows absolute path generation for cross-platform test compatibility
- Test coverage for migrate command utilities (CopyDir, CreateBackup, detectV2Config)
3.0.0 - 2025-12-27¶
Added¶
- Directory-based configuration system (
.ai-rulez/directory structure) - CRUD operations via CLI commands (domain, add, remove, list, include, profile)
- 22 MCP tools for AI assistant integration
- Domain separation for organizing rules by team/area
- Profile system for generating different configs for different teams
- Includes system for composing from local packages or Git repositories
Changed¶
- BREAKING: Configuration format changed from single YAML to directory structure
- BREAKING: Init command no longer uses AI agents for dynamic initialization
- Documentation simplified and focused on V3 only
Removed¶
- BREAKING: Enforce command removed
- BREAKING: V2 dynamic init with AI agents removed
- V2 single-file YAML configuration support
2.4.0 - 2025-10-22¶
Fixed¶
- CLI MCP interference with template-generated files
- Output type values in AI-generated configurations
2.3.0 - 2025-10-05¶
Added¶
- AI-powered rule enforcement system
- Automatic gitignore management
- Junie preset with lefthook configuration
2.2.0 - 2025-09-20¶
Added¶
- MCP file-based configuration system for Claude and other tools
2.1.0 - 2025-08-20¶
Added¶
- CLI MCP integration for Claude
- Improved init phase system
Fixed¶
- Cross-platform binary extensions for Windows support
- Homebrew formula structure
2.0.0 - 2025-07-30¶
Added¶
- Schema v2 with priority enum system
- Named target resolution for filter functions
Changed¶
- BREAKING: Updated schema to v2 with priority enum system
- Unified section field naming to use 'name' instead of 'title'
1.6.0 - 2025-07-10¶
Added¶
- Target filtering and named targets support
1.5.0 - 2025-06-25¶
Added¶
- Initial release with core configuration generation
- Rule definition system
- Template-based generator