feat: add pre_tool_call rewrite support for plugin tool arg transformation#19305
Open
elasticdotventures wants to merge 6 commits into
Open
feat: add pre_tool_call rewrite support for plugin tool arg transformation#19305elasticdotventures wants to merge 6 commits into
elasticdotventures wants to merge 6 commits into
Conversation
…ation Adds get_pre_tool_call_directives() that fires pre_tool_call hook ONCE and returns both block_message and rewritten_args. Existing get_pre_tool_call_block_message() kept as backward-compat alias. New get_pre_tool_call_rewrite() alias added. Updates all 3 call sites (_invoke_tool, concurrent loop, sequential loop) and handle_function_call in model_tools.py to use the combined function.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a richer pre_tool_call plugin hook contract so plugins can rewrite tool arguments before execution, not just block the call. It extends the plugin layer and updates the agent/tool dispatch paths that consume pre-tool directives.
Changes:
- Added
hermes_cli.plugins.get_pre_tool_call_directives()to collect block and rewrite directives from a singlepre_tool_callhook invocation. - Updated
run_agent.pytool execution paths to consume block/rewrite directives before dispatching tools. - Updated
model_tools.pydispatch to honor rewritten args when the pre-tool hook is evaluated there.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
run_agent.py |
Swaps pre-tool block checks over to the new directives helper in _invoke_tool, concurrent execution, and sequential execution. |
model_tools.py |
Uses the new directives helper in handle_function_call so registry-dispatched tools can be blocked or rewritten. |
hermes_cli/plugins.py |
Introduces the single-pass directive helper and keeps compatibility wrappers for legacy block-only callers. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+9452
to
+9455
| except Exception: | ||
| block_message = None | ||
| pass | ||
|
|
||
| if block_message is not None: | ||
| block_result = json.dumps({"error": block_message}, ensure_ascii=False) | ||
| else: | ||
| if block_result is None and _block_msg is None: |
Comment on lines
+9445
to
+9448
| elif _rewritten is not None: | ||
| function_args = _rewritten | ||
| # Re-check guardrails with rewritten args | ||
| guardrail_decision = self._tool_guardrails.before_call(function_name, function_args) |
Comment on lines
+1211
to
+1216
| elif action == "rewrite" and rewritten_args is None: | ||
| new_args = result.get("args") | ||
| if isinstance(new_args, dict): | ||
| rewritten_args = new_args | ||
|
|
||
| return block_message, rewritten_args |
Collaborator
1 similar comment
Collaborator
Routes terminal commands through b00t hive run --dry-run guards. Intercepts pre_tool_call hook to block, warn, or rewrite commands. Handles pip->uv, docker->podman, main-branch protection, and more.
elasticdotventures
added a commit
to elasticdotventures/_b00t_
that referenced
this pull request
May 4, 2026
…ite patch Vendor submodule pointing to PromptExecution/hermes-agent-b00t on feat/pre-tool-rewrite-hook branch. Contains the get_pre_tool_call_directives() patch required for b00t guard interposition via Hermes plugin hooks. Upstream PR: NousResearch/hermes-agent#19305 Internal PR: PromptExecution/hermes-agent-b00t#1
elasticdotventures
added a commit
to elasticdotventures/_b00t_
that referenced
this pull request
May 4, 2026
…ite patch Vendor submodule pointing to PromptExecution/hermes-agent-b00t on feat/pre-tool-rewrite-hook branch. Contains the get_pre_tool_call_directives() patch required for b00t guard interposition via Hermes plugin hooks. Upstream PR: NousResearch/hermes-agent#19305 Internal PR: PromptExecution/hermes-agent-b00t#1
elasticdotventures
added a commit
to elasticdotventures/_b00t_
that referenced
this pull request
May 4, 2026
…tocol (#369) * chore: remove plantuml-server embedded repo from git index * feat: guard escalation, parser stages, b00t-ast CLI, b00t-py bindings, violation persistence - Guard violation counter with JSONL persistence (~/.b00t/guard-violations.jsonl) - 🦨→💩 escalation: Warn→Block when violation_count >= repeat_threshold - check_guards() auto-persists violations on every match - K0mmand3rStage guards: pattern = { stage = "pre_parse" } in hive-guards.hive.toml - parser_stages wired into KmdLine::parse() at 7 phases - b00t-ast CLI binary: b00t-ast dir <path> [--format json|mcp|counts] - b00t-py: guard_check, emoji_lookup, register_stage_guard bindings - KmdLine fields made pub for serde serialization - Schema datums moved to _b00t_/schema/ (uppercase convention) - k0mmand3r crate edition 2024, clean lints - Rust 2024: #![allow]→removed, set_var unsafe wrappers - b00t_env_backend.py promoted from DESIGN to working Python backend - Hermes backend symlinked: just hermes-backend-enable * chore: add hermes-agent-b00t vendor submodule with pre_tool_call rewrite patch Vendor submodule pointing to PromptExecution/hermes-agent-b00t on feat/pre-tool-rewrite-hook branch. Contains the get_pre_tool_call_directives() patch required for b00t guard interposition via Hermes plugin hooks. Upstream PR: NousResearch/hermes-agent#19305 Internal PR: PromptExecution/hermes-agent-b00t#1 * feat: add SCM convention guards — branch naming, main protection, conventional commits New hive guards block or warn before git commands reach the shell: - BLOCK: git checkout main/master — use feature branches - BLOCK: git push origin main — use PRs instead - BLOCK: git merge main — use gh pr merge - WARN: git checkout -b without type/ — use feat/fix/chore/ prefix - WARN: git commit -m without colon — use Conventional Commits format * feat: add regex_match() to Rhai engine + SCM convention guards - Registered regex_match(cmd, pattern) on Rhai engine in hive.rs for future guard pattern matching - Added 5 SCM guards to hive-guards.hive.toml: BLOCK: git checkout main/master, git push origin main, git merge main WARN: branch without type/ prefix, commit without conventional format - All guards use simple cmd.contains() — readable, no escaping hell * feat: add b00t guard interposition Hermes plugin Bumps vendor/hermes-agent-b00t to include the new plugins/b00t/ directory with pre_tool_call hook that routes terminal commands through b00t hive run --dry-run guard evaluation. * crypto-sign: ed25519 signing for peer_facts in IrontologyPeerStore * hive-peers: gossip, mDNS discover, list --health, peer GC * docs: initial review plan Agent-Logs-Url: https://github.com/elasticdotventures/_b00t_/sessions/b13588c4-07c5-4b06-8575-5be55c579fb1 Co-authored-by: elasticdotventures <35611074+elasticdotventures@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
elasticdotventures
added a commit
to elasticdotventures/_b00t_
that referenced
this pull request
May 4, 2026
#373) * feat: guard escalation, parser stages, b00t-ast CLI, b00t-py bindings, violation persistence - Guard violation counter with JSONL persistence (~/.b00t/guard-violations.jsonl) - 🦨→💩 escalation: Warn→Block when violation_count >= repeat_threshold - check_guards() auto-persists violations on every match - K0mmand3rStage guards: pattern = { stage = "pre_parse" } in hive-guards.hive.toml - parser_stages wired into KmdLine::parse() at 7 phases - b00t-ast CLI binary: b00t-ast dir <path> [--format json|mcp|counts] - b00t-py: guard_check, emoji_lookup, register_stage_guard bindings - KmdLine fields made pub for serde serialization - Schema datums moved to _b00t_/schema/ (uppercase convention) - k0mmand3r crate edition 2024, clean lints - Rust 2024: #![allow]→removed, set_var unsafe wrappers - b00t_env_backend.py promoted from DESIGN to working Python backend - Hermes backend symlinked: just hermes-backend-enable * chore: add hermes-agent-b00t vendor submodule with pre_tool_call rewrite patch Vendor submodule pointing to PromptExecution/hermes-agent-b00t on feat/pre-tool-rewrite-hook branch. Contains the get_pre_tool_call_directives() patch required for b00t guard interposition via Hermes plugin hooks. Upstream PR: NousResearch/hermes-agent#19305 Internal PR: PromptExecution/hermes-agent-b00t#1 * feat: add SCM convention guards — branch naming, main protection, conventional commits New hive guards block or warn before git commands reach the shell: - BLOCK: git checkout main/master — use feature branches - BLOCK: git push origin main — use PRs instead - BLOCK: git merge main — use gh pr merge - WARN: git checkout -b without type/ — use feat/fix/chore/ prefix - WARN: git commit -m without colon — use Conventional Commits format * feat: add regex_match() to Rhai engine + SCM convention guards - Registered regex_match(cmd, pattern) on Rhai engine in hive.rs for future guard pattern matching - Added 5 SCM guards to hive-guards.hive.toml: BLOCK: git checkout main/master, git push origin main, git merge main WARN: branch without type/ prefix, commit without conventional format - All guards use simple cmd.contains() — readable, no escaping hell * crypto-sign: ed25519 signing for peer_facts in IrontologyPeerStore * chore: update vendor/l3dg3rr submodule to ledgrrr (rebranded upstream) - Submodule URL: https://github.com/PromptExecution/l3dg3rr → git@github.com:PromptExecution/ledgrrr - Submodule pointer: 1ed3b3d → 2168595 (includes PR #80, dashboard-generated-panels-51-rebased) - Remote changed from HTTPS to SSH for consistent auth
Adds b00t Integration category to COMMAND_REGISTRY: /b00t routes any command to b00t-cli, /hive is an alias for /b00t hive. Adds h3rmes-capability plugin that checks subsystem health (b00t-cli, b00t-mcp, irontology-mcp, codebase-memory, guard-plugin) on session start and auto-remediates critical/high gaps.
19 tasks
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Brian Horakh <35611074+elasticdotventures@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
get_pre_tool_call_directives()— a single-hook function that firespre_tool_callonce and returns both block and rewrite directives. Plugins can now return:{"action": "block", "message": "Reason"} # existing {"action": "rewrite", "args": {...}} # new — transform tool argsMotivation
Guard interposition (command sanitization, path normalization, security middleware) needs the ability to transform tool arguments before execution, not just block them. Rather than forking
terminal_tool.pyto add custom backends, this provides a general plugin extension point.Changes
3 files, +85 / -35 lines:
hermes_cli/plugins.pyget_pre_tool_call_directives()— fires hook once, returns(block_msg, rewritten_args). Backward-compat aliases preserved.run_agent.py_invoke_tool, concurrent, sequential) to use directivesmodel_tools.pyhandle_function_callto use directivesBackward Compatibility
get_pre_tool_call_block_message()kept as an exact alias — zero breakage for existing plugins and tests. All 111 plugin/shell-hook tests pass.Rationale
The hook fires once per tool call instead of N times (once per directive type). This is both more efficient and semantically cleaner — a plugin only needs one callback pass to express its intent.