Skip to main content

CLI Firewall

Quick example

curl "$TRINITITE_BASE/v1/cli/evaluate" \
-H "Authorization: Bearer $TRINITITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_platform": "claude_code",
"command": "rm -rf /var/lib/postgres",
"cwd": "/repo"
}'

See Cookbook → Sandbox a coding agent's CLI for an end-to-end recipe.


The CLI Firewall is the platform's agentic command firewall — a governed proxy that AI agents call instead of executing shell commands directly. Every command goes through:

  1. Parse the raw command into executable + arguments.
  2. Evaluate against the active governance policy and any matching firewall rules.
  3. Render a verdict: pass, correct (modified command), or block.
  4. Optionally execute the (corrected) command in a sandbox.
  5. Append an immutable audit-log entry.

This mirrors the Pass / Correct / Block vocabulary used by Guardian Mode and the MCP Gateway, but operates at the CLI level — targeting the "Inner Loop" of agent-driven development. Combined with the Skill Vault, it forms an Agentic SBOM around what an agent loads (skills) and what it executes (commands).

Authentication: Authorization: Bearer <session_token | api_key> with the relevant cli:* permission.


Endpoints

Evaluation & execution

MethodPathPermission
POST/v1/cli/evaluatecli:read
POST/v1/cli/executecli:create

Governance policies

MethodPathPermission
GET/v1/cli/governance/policiescli:read
POST/v1/cli/governance/policiescli:create
GET/v1/cli/governance/policies/activecli:read
GET/v1/cli/governance/policies/{id}cli:read
POST/v1/cli/governance/policies/{id}/versioncli:update
POST/v1/cli/governance/policies/{id}/activatecli:update
DELETE/v1/cli/governance/policies/activecli:delete
DELETE/v1/cli/governance/policies/{id}cli:delete

Firewall rules

MethodPathPermission
GET/v1/cli/governance/firewall-rulescli:read
POST/v1/cli/governance/firewall-rulescli:create
GET/v1/cli/governance/firewall-rules/{id}cli:read
PATCH/v1/cli/governance/firewall-rules/{id}cli:update
DELETE/v1/cli/governance/firewall-rules/{id}cli:delete

Audit logs

MethodPathPermission
GET/v1/cli/governance/logscli:read
GET/v1/cli/governance/logs/session/{sessionId}cli:read

Verdict & risk vocabulary

VerdictMeaningBehaviour
passCommand is safe to execute as-isForwarded to execution if requested
correctCommand modified to remove riskThe corrected_command is executed instead of the original
blockCommand rejectedReturns 403 forbidden with details.block_reason

Risk categories: read, write, delete, execute, exfiltrate, install, network, privilege_escalation. Severities: low, medium, high, critical.


POST /v1/cli/evaluate

Evaluate a command without executing it.

{
"raw_command": "rm -rf /var/log/*",
"working_directory": "/home/agent",
"shell_type": "bash",
"agent_platform": "cursor",
"agent_version": "0.42.0",
"session_id": "clisess_01JF8RCSE1A2B3C4D5E6F7G8H9I",
"nhi_id": "nhi_01JF8RNHI1A2B3C4D5E6F7G8H9"
}
FieldTypeRequiredDescription
raw_commandstringYesThe full command line as the agent would run it
working_directorystringNoThe agent's cwd
shell_typeenumNobash, zsh, sh, fish, pwsh
agent_platformstringNoE.g. cursor, codex, claude_code
agent_versionstringNo
session_idstringNoReuse an existing session ID
nhi_idstringNoNHI principal making the call

Pass / Correct response — 200 OK

{
"session_id": "clisess_01JF8RCSE1A2B3C4D5E6F7G8H9I",
"verdict": "correct",
"corrected_command": "rm -rf /var/log/agent-tmp/*",
"action": "Scoped destructive path to /var/log/agent-tmp.",
"block_reason": null,
"violations": [
{ "rule": "pattern_block:rm-broad-glob", "severity": "high", "detail": "rm against a system log path." }
],
"risk_score": 38.5,
"risk_category": "delete",
"sandbox_route": {
"provider_id": "sbprov_01JF8RSBP1A2B3C4D5E6F7G8H9I",
"provider_name": "E2B",
"route_action": "sandbox",
"timeout_ms": 30000
}
}

Block response — 403 Forbidden

{
"error": {
"code": "forbidden",
"message": "Command blocked by governance policy.",
"details": {
"block_reason": "rm is blocked",
"violations": [
{ "rule": "blocklist:rm", "severity": "high", "detail": "rm is blocked" }
],
"risk_score": 85.0
},
"request_id": "req_01J..."
}
}

POST /v1/cli/execute

Evaluate and execute. Same request shape as /evaluate. If the verdict is block, returns 403. Otherwise the (possibly corrected) command runs and the result is returned.

{
"session_id": "clisess_01JF8RCSE1A2B3C4D5E6F7G8H9I",
"verdict": "pass",
"corrected_command": null,
"action": "Passed CLI governance.",
"risk_score": 5.0,
"sandbox_route": null,
"execution": {
"exit_code": 0,
"stdout": "file1.txt\nfile2.txt",
"stderr": "",
"duration_ms": 42,
"truncated": false
}
}

stdout / stderr are size-limited; commands producing very large output have their streams truncated and truncated: true is set.


Governance policies

Policies follow an immutable versioning model: edits to an active policy create a new version. Exactly one version is active at a time per organisation.

Create a policy

POST /v1/cli/governance/policies

{
"name": "Production v1",
"description": "Production agent fleet — destructive commands corrected, not blocked.",
"rules": ["fwr_01JF8RFR1...", "fwr_01JF8RFR2..."],
"auto_pass_risk_threshold": 25.0,
"auto_block_risk_threshold": 80.0,
"default_action": "evaluate",
"metadata": { "team": "platform", "owner": "agent-platform@acme.com" }
}
FieldTypeDescription
namestringDisplay name
rulesstring[]Firewall rule IDs (fwr_*) referenced by this policy
auto_pass_risk_thresholdnumberVerdict gates to pass below this score, regardless of individual rule matches
auto_block_risk_thresholdnumberVerdict gates to block above this score
default_actionstringevaluate, pass, or block (catch-all when no rule matches)

Activate a version

POST /v1/cli/governance/policies/{id}/activate — atomically swaps the active policy. The previous version is preserved.

Get the active policy

GET /v1/cli/governance/policies/active — convenience endpoint for the current effective policy.

Suspend governance

DELETE /v1/cli/governance/policies/active — temporarily deactivates all CLI governance for the org. Subsequent /evaluate calls return verdict: "pass" until a new policy is activated. Useful for incident response when you need to fail-open knowingly. The suspension is logged.


Firewall rules

Reusable rules referenced by policies.

Rule typeWhat it matches
executable_blockBlocks specific binaries (rm, dd, nc)
pattern_blockRegex/glob over the full command
arg_constraintConstrain specific argument values
semantic_intentGuardian-evaluated semantic intent

Create a rule

{
"rule_type": "pattern_block",
"name": "rm-broad-glob",
"patterns": ["^rm\\s+-rf?\\s+/(var|etc|usr|bin|sbin|home|root)\\b"],
"severity": "critical",
"category": "delete",
"action": "block",
"enabled": true
}

System rules ship with the platform and are immutable.


Audit logs

GET /v1/cli/governance/logs

QueryTypeDescription
session_idstringFilter to one session
verdictstringpass, correct, block
from / toRFC 3339Time window
limit / cursorCursor pagination
{
"data": [
{
"log_id": "clilog_01JF8RCLG1A2B3C4D5E6F7G8H9I",
"session_id": "clisess_01JF8RCSE1A2B3C4D5E6F7G8H9I",
"timestamp": "2026-05-01T22:41:00Z",
"agent_platform": "cursor",
"nhi_id": "nhi_01JF8RNHI1A2B3C4D5E6F7G8H9",
"verdict": "block",
"command_hash": "sha256:e3b0c44...",
"block_reason": "rm is blocked",
"risk_score": 85.0,
"risk_category": "delete",
"policy_id": "fwp_01JF8RFWP1A2B3C4D5E6F7G8H9I",
"policy_version": 3
}
],
"page": { "next_cursor": null, "has_more": false }
}

Raw commands are redacted by default; the command_hash lets you correlate without exposing content. To see raw commands, the calling principal must additionally hold cli:admin (and the org must enable raw-command storage).

GET /v1/cli/governance/logs/session/{sessionId}

Convenience: the full timeline for one session, ordered chronologically.


Errors

HTTPerror.codeCause
400validation_errorBody or query failed schema validation
401unauthenticatedMissing or invalid credential
403forbiddenCaller lacks the required cli:* permission, or governance verdict is block
404not_foundPolicy, rule, session, or log not found
409conflictDuplicate policy name, attempt to delete an active policy
422unprocessable_entitySandbox provider unavailable
429rate_limitedPer-organization rate limit exceeded

Next steps

  • Govern what the agent loads in addition to what it runs → Skill Vault
  • Bind a Guardian to evaluate semantic intent of high-risk commands → Identities
  • Inspect every command in the Glass Box Ledger → Logs API