feat: add provider-specific ignore file support#159
Conversation
- Add Ignore variant to Feature enum and IgnoreFeature implementing FeatureTrait - Load patterns from .dotagents/.agentignore (newline-separated globs) - Deploy ignore.hbs templates for 11 providers (auggie, autohand, cline, cursor, gemini, goose, junie, kilocode, opencode, pi, qwen) - Single-phase rendering: no frontmatter content pre-render needed - Track deployed ignore files in gitignore fence for undeploy cleanup - Add agent-ignore to init CLI --features flag and TUI wizard multiselect - Scaffold default .agentignore mock during init - Archive add-deploy-e2e-coverage and add-provider-ignore-files OpenSpec changes - Add strum/sturm_macros for kebab-case Feature enum serialization - Sync main specs: deploy-pipeline, ignore-feature, ignore-init-scaffold, ignore-provider-templates
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 37 minutes and 6 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (31)
📝 WalkthroughWalkthroughThis PR introduces a new ChangesIgnore feature implementation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/templates/remote.rs (1)
89-94:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
agent-ignoredefaults are never resolved in provider-default hydration.
resolve_provider_defaultsomitsFeature::AgentIgnorefromall_features, so ignore template/target defaults are skipped even thoughset_feature_settingssupports them. This can prevent ignore deployment for providers relying on defaults.Suggested fix
let all_features = [ Feature::Command, Feature::Instruction, Feature::Mcp, Feature::Skill, + Feature::AgentIgnore, ];🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/templates/remote.rs` around lines 89 - 94, resolve_provider_defaults currently builds all_features without including Feature::AgentIgnore, so provider-default hydration skips ignore/template defaults even though set_feature_settings supports them; update the all_features array in resolve_provider_defaults to include Feature::AgentIgnore (alongside Feature::Command, Feature::Instruction, Feature::Mcp, Feature::Skill) so that ignore defaults are resolved during provider-default hydration and propagate into set_feature_settings.
🧹 Nitpick comments (3)
src/cli/options.rs (1)
449-496: ⚡ Quick winAdd
AgentIgnorecoverage tohas_featuretests.The new enum variant is introduced, but these tests still only assert Command/Instruction/Mcp/Skill paths. Add one negative case and one positive case for
Feature::AgentIgnoreto lock behavior.✅ Suggested test additions
@@ fn has_feature_returns_false_when_features_absent() { @@ assert!(!opts.has_feature(Feature::Skill)); + assert!(!opts.has_feature(Feature::AgentIgnore)); } @@ fn has_feature_returns_false_for_unlisted_feature() { @@ assert!(!opts.has_feature(Feature::Instruction)); assert!(!opts.has_feature(Feature::Skill)); + assert!(!opts.has_feature(Feature::AgentIgnore)); } @@ fn has_feature_returns_true_for_all_listed() { @@ Feature::Mcp, Feature::Skill, + Feature::AgentIgnore, ]), @@ assert!(opts.has_feature(Feature::Mcp)); assert!(opts.has_feature(Feature::Skill)); + assert!(opts.has_feature(Feature::AgentIgnore)); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli/options.rs` around lines 449 - 496, Update the unit tests for InitOptions::has_feature to cover the newly added Feature::AgentIgnore: in the test has_feature_returns_false_when_features_absent add assert!(!opts.has_feature(Feature::AgentIgnore)); and in has_feature_returns_true_for_all_listed include Feature::AgentIgnore in the features vector and assert!(opts.has_feature(Feature::AgentIgnore)); so both a negative and a positive path for has_feature (the method on InitOptions) are asserted.openspec/specs/ignore-feature/spec.md (1)
50-54: ⚡ Quick winAdd language specifier to fenced code block.
The fenced code block showing
.agentignorecontent should specify a language (or leave it empty for plain text) to satisfy markdown linting requirements.📝 Proposed fix
#### Scenario: Load patterns from .agentignore - **WHEN** `.dotagents/.agentignore` contains: - ``` + ```text node_modules/ *.log .env🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openspec/specs/ignore-feature/spec.md` around lines 50 - 54, Update the fenced code block that displays the .agentignore content so it includes a language specifier (e.g., use ```text or ```plain) instead of bare backticks; locate the fenced block containing "node_modules/", "*.log", ".env" in spec.md and change the opening fence to include the language to satisfy markdown linting rules.src/cli/skills.rs (1)
238-238: ⚡ Quick winUse enum-derived feature key here to avoid future key drift.
Prefer
Feature::Skill.as_ref()instead of hardcoding"skill"so cleanup stays aligned with feature serialization changes.Suggested fix
- if let Err(e) = - super::undeploy::undeploy_item("skill", &opts.name, &mut cache, &workspace_dir) + if let Err(e) = super::undeploy::undeploy_item( + crate::core::features::Feature::Skill.as_ref(), + &opts.name, + &mut cache, + &workspace_dir, + ) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli/skills.rs` at line 238, Replace the hardcoded "skill" feature key with the enum-derived key to prevent drift: call super::undeploy::undeploy_item with Feature::Skill.as_ref() (or Feature::Skill.to_string().as_str() if needed) instead of the literal "skill", updating the invocation at the site that currently calls super::undeploy::undeploy_item("skill", &opts.name, &mut cache, &workspace_dir) so the cleanup uses the canonical Feature::Skill representation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@openspec/changes/archive/2026-05-26-add-provider-ignore-files/tasks.md`:
- Line 3: The task doc has inconsistent Feature variant names (Feature::Ignore
vs Feature::AgentIgnore) and string mappings ("ignore" vs "agent-ignore"); pick
the canonical variant (use Feature::Ignore with string "ignore"), update all
mentions in this document (sections 1.1, 4.1, 4.2 and checklist) to
Feature::Ignore and the mapping to "ignore", and ensure the implementation in
src/core/features/common.rs defines the enum variant Feature::Ignore and its
serialization/deserialization mapping to "ignore" so all specs
(ignore-feature/spec.md and ignore-init-scaffold/spec.md) and the codebase
consistently reference Feature::Ignore/"ignore".
In `@openspec/specs/ignore-provider-templates/spec.md`:
- Around line 65-96: Remove the nine unsupported provider scenarios for claude,
copilot, codex, factory-droid, deepagents, kimi, mistral-vibe, qoder-cli and amp
from the spec (the blocks that start with "Scenario: <provider> provider has
ignore config") and add a short note in the spec explaining that only providers
with documented ignore-file support receive ignore.hbs templates (list the
supported providers: opencode, auggie, autohand, cline, cursor, gemini, goose,
junie, kilocode, pi, qwen) so the spec matches tasks.md and the actual
implementation.
In `@public/v1/templates/auggie/ignore.hbs`:
- Line 1: The rendered ignore patterns are concatenated with no separators;
update the Handlebars template (public/v1/templates/auggie/ignore.hbs) so each
item in ignore.patterns is emitted on its own line by adding a newline delimiter
between rendered items (use the each block over ignore.patterns and
conditionally insert a newline after each {{this}} — e.g., add a newline except
for the last item using the `@last` built-in — so entries become separate lines
and produce valid ignore rules).
In `@public/v1/templates/autohand/ignore.hbs`:
- Line 1: The current Handlebars loop {{`#each` ignore.patterns}}{{this}}{{/each}}
concatenates patterns without separators; update the loop in
public/v1/templates/autohand/ignore.hbs to emit a newline after each pattern so
each entry from ignore.patterns is rendered on its own line (i.e., inside the
{{`#each` ignore.patterns}}...{{/each}} block write the pattern then a newline
separator). Ensure you only modify that each block to add the separator and
avoid introducing extra blank lines.
In `@public/v1/templates/cline/ignore.hbs`:
- Line 1: The template currently concatenates all entries because the each block
outputs patterns back-to-back; update the ignore.hbs each block (the {{`#each`
ignore.patterns}} ... {{/each}} surrounding {{this}}) to emit a newline after
each pattern by placing a literal line break after {{this}} inside the loop so
each pattern is rendered on its own line.
In `@public/v1/templates/cursor/ignore.hbs`:
- Line 1: The Handlebars loop over ignore.patterns is rendering patterns
back-to-back; update the template (public/v1/templates/cursor/ignore.hbs) so
that each iteration appends a newline after the rendered pattern (i.e., ensure
the {{`#each` ignore.patterns}} block writes a line break after {{this}}) so
output is newline-separated entries rather than concatenated text.
In `@public/v1/templates/gemini/ignore.hbs`:
- Line 1: The ignore template currently renders all patterns inline using the
block "{{`#each` ignore.patterns}}{{this}}{{/each}}"; change it so each pattern is
emitted on its own line by outputting a newline separator after each "{{this}}"
within the same "{{`#each` ignore.patterns}}...{{/each}}" block (so generated
ignore files preserve individual rules).
In `@public/v1/templates/goose/ignore.hbs`:
- Line 1: The template public/v1/templates/goose/ignore.hbs currently emits all
ignore.patterns back-to-back via {{`#each` ignore.patterns}}{{this}}{{/each}},
collapsing entries into a single pattern; update the {{`#each` ignore.patterns}}
loop in ignore.hbs to emit one pattern per line by appending a newline or
line-break after each {{this}} (ensure you handle the final element correctly,
e.g., only add the separator when not `@last`) so each ignore rule appears on its
own line for ignore engines to parse.
In `@public/v1/templates/junie/ignore.hbs`:
- Line 1: The template currently concatenates all ignore.patterns into a single
string; update the Handlebars loop in public/v1/templates/junie/ignore.hbs (the
{{`#each` ignore.patterns}} ... {{this}} ... {{/each}} block) so each pattern is
emitted on its own line by appending a newline after each {{this}} output,
producing line-based ignore patterns instead of one combined pattern.
In `@public/v1/templates/kilocode/ignore.hbs`:
- Line 1: The template public/v1/templates/kilocode/ignore.hbs is concatenating
ignore.patterns into one line; change the {{`#each`
ignore.patterns}}{{this}}{{/each}} rendering so each pattern is emitted on its
own line (i.e., output a newline after each {{this}} inside the {{`#each`}} block)
to preserve per-rule semantics when generating the ignore file.
In `@public/v1/templates/opencode/ignore.hbs`:
- Line 1: The template currently renders ignore.patterns with {{`#each`
ignore.patterns}}{{this}}{{/each}} which concatenates entries without
separators; update the loop in the ignore.hbs template to output each pattern
followed by a newline (e.g., render {{this}} then a newline or use Handlebars'
block/whitespace to produce line breaks) so each pattern becomes its own line;
apply the same change to other public/v1/templates/*/ignore.hbs instances that
use ignore.patterns to ensure multi-pattern ignores are emitted as separate
lines.
In `@public/v1/templates/pi/ignore.hbs`:
- Line 1: The template currently concatenates ignore.patterns with no
separators; update the Handlebars template in ignore.hbs so each entry of
ignore.patterns renders on its own line by emitting a newline between items
(e.g., change the {{`#each` ignore.patterns}}...{{/each}} loop to insert a line
break after each pattern, or conditionally between items using `@last` to avoid an
extra blank line), ensuring each pattern renders as a separate line.
In `@public/v1/templates/qwen/ignore.hbs`:
- Line 1: The template public/v1/templates/qwen/ignore.hbs is concatenating
ignore.patterns without delimiters ({{`#each` ignore.patterns}}{{this}}{{/each}}),
which squashes multiple patterns into one line; update the each loop for
ignore.patterns in the ignore.hbs (and mirror the same change across the other
providers' public/v1/templates/*/ignore.hbs) to emit a newline between entries
so patterns become newline-delimited (e.g., ensure each iteration appends a line
break after {{this}} or use a join-with-newline approach).
In `@src/cli/config.rs`:
- Around line 544-545: The pruning logic is dropping providers whose only
override is the new agent-ignore feature because Feature::VARIANTS (assigned to
all_features) and the check in features_has_overrides ignore feats.ignore;
update features_has_overrides (or the code that iterates
Feature::VARIANTS/all_features) to consider feats.ignore as a valid override (or
explicitly check for Feature::AgentIgnore) so providers with only an ignore
override are treated as having overrides and are not pruned; locate uses of
Feature::VARIANTS, the all_features binding, and the features_has_overrides
function and ensure feats.ignore (or Feature::AgentIgnore) is included in the
override detection logic.
In `@src/constants/mocks.rs`:
- Around line 73-74: AGENTIGNORE_MOCK currently only contains ".env.prod";
update the AGENTIGNORE_MOCK constant to seed a richer default .agentignore
scaffold containing common ignore patterns (e.g., *.env and .env.*,
node_modules, dist, build, target, __pycache__, *.log, .git, .venv, .idea) so
new agents get a useful baseline; keep the constant name AGENTIGNORE_MOCK and
replace the string value with a multi-line string containing those entries
separated by newlines.
---
Outside diff comments:
In `@src/templates/remote.rs`:
- Around line 89-94: resolve_provider_defaults currently builds all_features
without including Feature::AgentIgnore, so provider-default hydration skips
ignore/template defaults even though set_feature_settings supports them; update
the all_features array in resolve_provider_defaults to include
Feature::AgentIgnore (alongside Feature::Command, Feature::Instruction,
Feature::Mcp, Feature::Skill) so that ignore defaults are resolved during
provider-default hydration and propagate into set_feature_settings.
---
Nitpick comments:
In `@openspec/specs/ignore-feature/spec.md`:
- Around line 50-54: Update the fenced code block that displays the .agentignore
content so it includes a language specifier (e.g., use ```text or ```plain)
instead of bare backticks; locate the fenced block containing "node_modules/",
"*.log", ".env" in spec.md and change the opening fence to include the language
to satisfy markdown linting rules.
In `@src/cli/options.rs`:
- Around line 449-496: Update the unit tests for InitOptions::has_feature to
cover the newly added Feature::AgentIgnore: in the test
has_feature_returns_false_when_features_absent add
assert!(!opts.has_feature(Feature::AgentIgnore)); and in
has_feature_returns_true_for_all_listed include Feature::AgentIgnore in the
features vector and assert!(opts.has_feature(Feature::AgentIgnore)); so both a
negative and a positive path for has_feature (the method on InitOptions) are
asserted.
In `@src/cli/skills.rs`:
- Line 238: Replace the hardcoded "skill" feature key with the enum-derived key
to prevent drift: call super::undeploy::undeploy_item with
Feature::Skill.as_ref() (or Feature::Skill.to_string().as_str() if needed)
instead of the literal "skill", updating the invocation at the site that
currently calls super::undeploy::undeploy_item("skill", &opts.name, &mut cache,
&workspace_dir) so the cleanup uses the canonical Feature::Skill representation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 44eb2759-d4c4-4858-9897-8f36506874a8
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (75)
Cargo.tomlopenspec/changes/add-provider-ignore-files/tasks.mdopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/.openspec.yamlopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/design.mdopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/proposal.mdopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/specs/deploy-flag-coverage-e2e/spec.mdopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/specs/deploy-tui-prompts-e2e/spec.mdopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/specs/deploy-user-edit-protection-e2e/spec.mdopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/specs/undeploy-edge-cases-e2e/spec.mdopenspec/changes/archive/2026-05-17-add-deploy-e2e-coverage/tasks.mdopenspec/changes/archive/2026-05-26-add-provider-ignore-files/.openspec.yamlopenspec/changes/archive/2026-05-26-add-provider-ignore-files/design.mdopenspec/changes/archive/2026-05-26-add-provider-ignore-files/proposal.mdopenspec/changes/archive/2026-05-26-add-provider-ignore-files/specs/deploy-pipeline/spec.mdopenspec/changes/archive/2026-05-26-add-provider-ignore-files/specs/ignore-feature/spec.mdopenspec/changes/archive/2026-05-26-add-provider-ignore-files/specs/ignore-init-scaffold/spec.mdopenspec/changes/archive/2026-05-26-add-provider-ignore-files/specs/ignore-provider-templates/spec.mdopenspec/changes/archive/2026-05-26-add-provider-ignore-files/tasks.mdopenspec/specs/deploy-pipeline/spec.mdopenspec/specs/ignore-feature/spec.mdopenspec/specs/ignore-init-scaffold/spec.mdopenspec/specs/ignore-provider-templates/spec.mdpublic/v1/templates/auggie/ignore.hbspublic/v1/templates/auggie/provider.tomlpublic/v1/templates/autohand/ignore.hbspublic/v1/templates/autohand/provider.tomlpublic/v1/templates/cline/ignore.hbspublic/v1/templates/cline/provider.tomlpublic/v1/templates/cursor/ignore.hbspublic/v1/templates/cursor/provider.tomlpublic/v1/templates/gemini/ignore.hbspublic/v1/templates/gemini/provider.tomlpublic/v1/templates/goose/ignore.hbspublic/v1/templates/goose/provider.tomlpublic/v1/templates/junie/ignore.hbspublic/v1/templates/junie/provider.tomlpublic/v1/templates/kilocode/ignore.hbspublic/v1/templates/kilocode/provider.tomlpublic/v1/templates/opencode/ignore.hbspublic/v1/templates/opencode/provider.tomlpublic/v1/templates/pi/ignore.hbspublic/v1/templates/pi/provider.tomlpublic/v1/templates/qwen/ignore.hbspublic/v1/templates/qwen/provider.tomlsrc/cli/commands.rssrc/cli/config.rssrc/cli/deploy.rssrc/cli/init.rssrc/cli/options.rssrc/cli/skills.rssrc/cli/ui/deploy.rssrc/cli/ui/init.rssrc/cli/ui/undeploy.rssrc/cli/undeploy.rssrc/constants/file.rssrc/constants/mocks.rssrc/core/config/app.rssrc/core/config/common.rssrc/core/config/global.rssrc/core/config/local.rssrc/core/features.rssrc/core/features/common.rssrc/core/features/ignore.rssrc/templates/remote.rstests/e2e/commands.test.tstests/e2e/config.test.tstests/e2e/errors.test.tstests/e2e/helpers.tstests/e2e/init.test.tstests/e2e/skills.test.tstests/e2e/workflow.test.tstests/integration/config.rstests/integration/dedup.rstests/integration/features.rstests/integration/main.rs
💤 Files with no reviewable changes (2)
- openspec/changes/add-provider-ignore-files/tasks.md
- src/cli/ui/deploy.rs
- Update registry.json checksums - Add init scaffold and mock for mycode agent-ignore template
- Restrict ignore templates to 11 supported providers (opencode, cursor, gemini, etc.) - Wire AgentIgnore feature into CLI config overrides and init options - Use Feature::Skill.as_ref() in undeploy_item instead of hardcoded string - Update ignore-provider-templates spec to document supported providers only
Summary
ignorefeature type to deploy pipeline alongside commands, instructions, MCP, and skillsIgnoreFeatureimplementingFeatureTrait— loads patterns from.dotagents/.agentignore(newline-separated glob patterns, gitignore-like)[providers.<name>.ignore]config withdisabledtoggle andtemplate/targetpathsignore.hbstemplates and updatedprovider.tomlfor 11 providers: opencode, auggie, autohand, cline, cursor, gemini, goose, junie, kilocode, pi, qweninitCLI (--features agent-ignore) and TUI wizard ("Ignore Patterns" pre-selected option).agentignorewith common patterns (node_modules/,.git/,target/,.env).gitignorefence trackingstrum/strum_macrosfor derive macros onFeatureenumTesting
IgnoreFeatureroundtrip, pattern parsing, and edge cases (empty/missing.agentignore)Features::mergewith ignore field)disabledflag)--features agent-ignoreflagmise check(cargo fmt + clippy) passesmise tests(unit + integration + e2e) passesSummary by CodeRabbit
Release Notes
New Features
.agentignore,.cursorignore,.augmentignore, etc.) across 11+ AI providersChores