Skip to content

feat(agent): add primary allowed_tools/denied_tools filtering#2663

Merged
theonlyhennygod merged 2 commits intomainfrom
issue-2651-agent-allowed-denied-tools
Mar 3, 2026
Merged

feat(agent): add primary allowed_tools/denied_tools filtering#2663
theonlyhennygod merged 2 commits intomainfrom
issue-2651-agent-allowed-denied-tools

Conversation

@theonlyhennygod
Copy link
Copy Markdown
Collaborator

@theonlyhennygod theonlyhennygod commented Mar 3, 2026

Summary

  • add [agent].allowed_tools and [agent].denied_tools to AgentConfig
  • validate agent tool filters with the same character policy used by security.roles[].allowed_tools/denied_tools
  • add startup-time primary-agent tool filtering helper (tools::filter_primary_agent_tools)
  • apply filtering in both:
    • Agent::from_config
    • runtime loop entry points (agent::loop_::run and process_message_with_session)
  • ensure filtered-out tools are removed from both executable registry and system prompt tool descriptions
  • emit debug log entries for unmatched allowed_tools entries
  • fail fast when allowed_tools + denied_tools remove all matched allowlisted tools
  • document new keys in docs/config-reference.md
  • i18n follow-through in docs/i18n/{zh-CN,ja,ru,fr,vi,el}/config-reference.md
  • add deterministic tests for filtering behavior, validation, and primary-agent config integration
  • add a shared test lock module to serialize plugin-runtime-global tests and prevent flaky cross-test interference

Validation

  • cargo fmt --all
  • cargo test --lib filter_primary_agent_tools_ -- --nocapture
  • cargo test --lib from_config_ -- --nocapture
  • cargo test --lib agent_validation_rejects_ -- --nocapture

Closes #2651

Summary by CodeRabbit

  • New Features

    • Added agent-level tool filtering via allowed_tools and denied_tools (applied at startup); unknown allowed entries are ignored (debug logged); configuration fails fast if filtering removes all executable tools.
  • Documentation

    • Updated config reference (English + translations) with behavior, validation rules, examples, and startup semantics for the new agent tool filters.

@theonlyhennygod theonlyhennygod requested a review from chumyin as a code owner March 3, 2026 21:30
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 3, 2026

PR intake checks found warnings (non-blocking)

Fast safe checks found advisory issues. CI lint/test/build gates still enforce merge quality.

  • Missing required PR template sections: ## Validation Evidence (required), ## Security Impact (required), ## Privacy and Data Hygiene (required), ## Rollback Plan (required)
  • Incomplete required PR template fields: summary problem, summary why it matters, summary what changed, validation commands, security risk/mitigation, privacy status, rollback plan
  • Missing Linear issue key reference (RMN-<id>, CDV-<id>, or COM-<id>) in PR title/body (recommended for traceability, non-blocking).

Action items:

  1. Complete required PR template sections/fields.
  2. (Recommended) Link this PR to one active Linear issue key (RMN-xxx/CDV-xxx/COM-xxx) for traceability.
  3. Remove tabs, trailing whitespace, and merge conflict markers from added lines.
  4. Re-run local checks before pushing:
    • ./scripts/ci/rust_quality_gate.sh
    • ./scripts/ci/rust_strict_delta_gate.sh
    • ./scripts/ci/docs_quality_gate.sh

Detected Linear keys: none

Run logs: https://github.com/zeroclaw-labs/zeroclaw/actions/runs/22646588999

Detected blocking line issues (sample):

  • none

Detected advisory line issues (sample):

  • none

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 3, 2026

Thanks for contributing to ZeroClaw.

For faster review, please ensure:

  • PR template sections are fully completed
  • cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, and cargo test are included
  • If automation/agents were used heavily, add brief workflow notes
  • Scope is focused (prefer one concern per PR)

See CONTRIBUTING.md and docs/pr-workflow.md for full collaboration rules.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 3, 2026

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'tools', 'path_filters', 'review_instructions'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 696a0c5 and 0947a92.

📒 Files selected for processing (1)
  • src/main.rs
✅ Files skipped from review due to trivial changes (1)
  • src/main.rs

📝 Walkthrough

Walkthrough

Adds agent-level tool visibility controls via agent.allowed_tools and agent.denied_tools: schema fields with validation, registry filtering applied at agent startup (before prompt construction), synchronization of tool descriptions with the filtered registry, tests, a test mutex for plugin runtime, and documentation updates across locales.

Changes

Cohort / File(s) Summary
Configuration Schema & Validation
src/config/schema.rs
Add AgentConfig.allowed_tools and AgentConfig.denied_tools (Vec) with Default init and validation enforcing non-empty trimmed entries and allowed chars (alphanumeric, _, -, *). Update unit tests for defaults and validation errors.
Tool Filtering Logic
src/tools/mod.rs
Add filter_primary_agent_tools() and PrimaryAgentToolFilterReport to apply allowlist then denylist, with wildcard and case-insensitive matching, return unmatched allowed entries and match count. Include tests for wildcard, unmatched entries, and denylist interactions.
Agent Integration & Prompt Sync
src/agent/agent.rs, src/agent/loop_.rs
Apply filtering during agent construction via filter_primary_agent_tools_or_fail(), error if filtering results in zero executable tools when both lists configured, and prune tool description blocks via retain_visible_tool_descriptions() so prompts match visible tools. Add tests covering filtering behavior and fail-fast case.
Test Serialization Guard
src/lib.rs, src/test_locks.rs, src/plugins/runtime.rs
Introduce crate-private PLUGIN_RUNTIME_LOCK (parking_lot::Mutex) in src/test_locks.rs and expose test-only module. Acquire the lock in plugin runtime init tests to serialize global plugin runtime mutations.
Documentation & i18n
docs/config-reference.md, docs/i18n/{el,fr,ja,ru,vi,zh-CN}/config-reference.md
Document allowed_tools and denied_tools under [agent], startup semantics (applied before prompt construction), logging for unknown allowed entries (debug), fail-fast behavior when filtering yields no tools, and provide a TOML example. Translations updated accordingly.
Misc — Main/Test modules
src/main.rs, Cargo.toml
Add test-only test_locks module declarations; Cargo metadata updated alongside new test module files.

Sequence Diagram(s)

sequenceDiagram
    participant Config as Configuration (schema.rs)
    participant Startup as Agent Startup (agent.rs)
    participant Tools as Tool Registry (tools/mod.rs)
    participant Filter as Filter Logic (loop_.rs)
    participant Agent as Primary Agent (Agent)

    Config->>Config: Validate `agent.allowed_tools` & `agent.denied_tools`
    Config-->>Startup: Validated config
    Startup->>Tools: Build full tool registry
    Tools-->>Startup: Registry (all tools)
    Startup->>Filter: filter_primary_agent_tools_or_fail(registry, allowed, denied)
    Filter->>Filter: Apply allowed_tools (if non-empty)
    Filter->>Filter: Record unmatched allowed entries
    Filter->>Filter: Apply denied_tools
    Filter->>Filter: If both lists present && no executable tools -> return error
    alt Tools remain
        Filter-->>Startup: Filtered registry + report
    else No tools remain
        Filter-->>Startup: Fail-fast error
    end
    Startup->>Filter: retain_visible_tool_descriptions(tool_descriptions, filtered_registry)
    Filter-->>Startup: Pruned descriptions
    Startup->>Agent: Construct Agent with filtered tools and descriptions
    Agent-->>Startup: Agent ready (system prompt built from filtered tools)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

size: L, risk: medium, tool, tests

Suggested reviewers

  • chumyin
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description covers Summary, Validation, and references the linked issue #2651, but is missing required template sections including Label Snapshot, Change Metadata, Linked Issue details, Security Impact, Privacy/Data Hygiene, Compatibility/Migration, i18n Follow-Through, Human Verification, Side Effects, Rollback Plan, and Risks. Complete the PR description by filling in all required template sections: Label Snapshot (risk, size, scope labels), Change Metadata (type, primary scope), full Linked Issue section with Linear keys, Security/Privacy Impact assessments, Compatibility details, detailed i18n checklist completion, Human Verification scenarios, Side Effects analysis, and Rollback Plan.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(agent): add primary allowed_tools/denied_tools filtering' directly and accurately describes the main change: adding allowed_tools/denied_tools filtering to the primary agent configuration.
Linked Issues check ✅ Passed The PR implements all core requirements from #2651: allowed_tools/denied_tools in AgentConfig, startup-time filtering with debug logging for unmatched entries, fail-fast when combined filters remove all tools, comprehensive documentation, i18n updates for all locales, and tests covering filtering/validation/integration scenarios.
Out of Scope Changes check ✅ Passed All changes directly address #2651 requirements: configuration schema, tool filtering logic, documentation/i18n, tests, and a shared test-lock module for serializing plugin-runtime tests. No unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 87.80% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-2651-agent-allowed-denied-tools

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added docs Auto scope: docs/markdown/template files changed. core Auto scope: root src/*.rs files changed. agent Auto scope: src/agent/** changed. config Auto scope: src/config/** changed. tool Auto scope: src/tools/** changed. size: M Auto size: 251-500 non-doc changed lines. risk: high Auto risk: security/runtime/gateway/tools/workflows. distinguished contributor Contributor with 50+ merged PRs. config: core Auto module: config core files changed. tool: core Auto module: tool core files changed. and removed config Auto scope: src/config/** changed. tool Auto scope: src/tools/** changed. labels Mar 3, 2026
@theonlyhennygod theonlyhennygod self-assigned this Mar 3, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/config/schema.rs (1)

1047-1054: Document default and rollback semantics inline for the new public config keys.

The new [agent] keys are user-facing contract fields; add explicit default + compatibility/rollback notes in these rustdoc comments for consistency with other config keys.

Suggested doc patch
     /// Optional allowlist for primary-agent tool visibility.
     /// When non-empty, only listed tools are exposed to the primary agent.
+    /// Default: `[]` (all registered tools remain visible).
+    /// Compatibility/rollback: omit/remove this key to keep legacy behavior.
     #[serde(default)]
     pub allowed_tools: Vec<String>,
     /// Optional denylist for primary-agent tool visibility.
     /// Applied after `allowed_tools`.
+    /// Default: `[]` (no explicit denies).
+    /// Compatibility/rollback: omit/remove this key to disable deny overrides.
     #[serde(default)]
     pub denied_tools: Vec<String>,

As per coding guidelines src/config/**/*.rs: "Treat config keys as public contract: document defaults, compatibility impact, and migration/rollback path".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config/schema.rs` around lines 1047 - 1054, Update the rustdoc for the
public struct fields allowed_tools and denied_tools to clearly state their
default values (both default to empty lists via #[serde(default]) and therefore
impose no restrictions when empty), describe the semantics/order (allowed_tools
is applied first to restrict to only listed tools, then denied_tools removes
specific tools from that result), and add a brief compatibility/rollback note
telling operators that adding these keys is safe (old configs behave the same
because empty defaults are used), and how to roll back (remove or set keys to
empty to restore prior behavior); place these notes inline as comments above the
allowed_tools and denied_tools fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/i18n/fr/config-reference.md`:
- Around line 25-26: Update the French bullet for `allowed_tools` to improve
phrasing and typography: change "non vide: seuls les outils listés sont
exposés." to use proper French spacing and a smoother wording such as "non
vide : seuls les outils listés sont exposés." and ensure the following
`denied_tools` line remains "retrait supplémentaire appliqué après
`allowed_tools`." so both bullets read fluently and consistently
(`allowed_tools` and `denied_tools`).

---

Nitpick comments:
In `@src/config/schema.rs`:
- Around line 1047-1054: Update the rustdoc for the public struct fields
allowed_tools and denied_tools to clearly state their default values (both
default to empty lists via #[serde(default]) and therefore impose no
restrictions when empty), describe the semantics/order (allowed_tools is applied
first to restrict to only listed tools, then denied_tools removes specific tools
from that result), and add a brief compatibility/rollback note telling operators
that adding these keys is safe (old configs behave the same because empty
defaults are used), and how to roll back (remove or set keys to empty to restore
prior behavior); place these notes inline as comments above the allowed_tools
and denied_tools fields.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3141e9a and 696a0c5.

📒 Files selected for processing (14)
  • docs/config-reference.md
  • docs/i18n/el/config-reference.md
  • docs/i18n/fr/config-reference.md
  • docs/i18n/ja/config-reference.md
  • docs/i18n/ru/config-reference.md
  • docs/i18n/vi/config-reference.md
  • docs/i18n/zh-CN/config-reference.md
  • src/agent/agent.rs
  • src/agent/loop_.rs
  • src/config/schema.rs
  • src/lib.rs
  • src/plugins/runtime.rs
  • src/test_locks.rs
  • src/tools/mod.rs

Comment on lines +25 to +26
- `allowed_tools` non vide: seuls les outils listés sont exposés.
- `denied_tools`: retrait supplémentaire appliqué après `allowed_tools`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Polish the French phrasing/typography in this bullet.

Line 25 reads slightly awkwardly; a small rewrite improves fluency and apostrophe style.

✍️ Suggested wording tweak
-  - `allowed_tools` non vide: seuls les outils listés sont exposés.
+  - `allowed_tools` n’est pas vide : seuls les outils listés sont exposés.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `allowed_tools` non vide: seuls les outils listés sont exposés.
- `denied_tools`: retrait supplémentaire appliqué après `allowed_tools`.
- `allowed_tools` n'est pas vide : seuls les outils listés sont exposés.
- `denied_tools`: retrait supplémentaire appliqué après `allowed_tools`.
🧰 Tools
🪛 LanguageTool

[typographical] ~26-~26: Caractère d’apostrophe incorrect.
Context: ...: retrait supplémentaire appliqué après allowed_tools. - Les entrées inconnues dans `allowed_...

(APOS_INCORRECT)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/i18n/fr/config-reference.md` around lines 25 - 26, Update the French
bullet for `allowed_tools` to improve phrasing and typography: change "non vide:
seuls les outils listés sont exposés." to use proper French spacing and a
smoother wording such as "non vide : seuls les outils listés sont exposés." and
ensure the following `denied_tools` line remains "retrait supplémentaire
appliqué après `allowed_tools`." so both bullets read fluently and consistently
(`allowed_tools` and `denied_tools`).

@github-actions github-actions Bot added config Auto scope: src/config/** changed. tool Auto scope: src/tools/** changed. and removed config Auto scope: src/config/** changed. tool Auto scope: src/tools/** changed. labels Mar 3, 2026
@theonlyhennygod theonlyhennygod merged commit 403fd2d into main Mar 3, 2026
18 of 24 checks passed
@theonlyhennygod theonlyhennygod deleted the issue-2651-agent-allowed-denied-tools branch March 3, 2026 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Auto scope: src/agent/** changed. config: core Auto module: config core files changed. core Auto scope: root src/*.rs files changed. distinguished contributor Contributor with 50+ merged PRs. docs Auto scope: docs/markdown/template files changed. risk: high Auto risk: security/runtime/gateway/tools/workflows. size: M Auto size: 251-500 non-doc changed lines. tool: core Auto module: tool core files changed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Add allowed_tools / denied_tools to primary agent config for context-engineered multi-agent teams

1 participant