How to stop a coding agent deleting production
A coding agent asked to clean up test data can reach for a DELETE on production if that is the request it finds. Nobody has to be malicious: one token within reach and one call without a person is enough.
Porticol Guard puts every agent call through one policy. A delete on production is denied or held for a person, the key stays out of the agent, and the call is recorded.
1. Install
macOS or Linux:
curl -fsSL https://porticol.app/install.sh | sh
Windows, in PowerShell:
irm https://porticol.app/install.ps1 | iex
Open Porticol. Local use needs no account and no sign-in. An account is asked for only when you invite someone, sync, share or use a team gateway.
2. Connect your agents
On the start screen, choose Connect my coding agent. Porticol finds Claude Code, Cursor and Codex, shows the exact lines it will add to each one's settings, and writes nothing until you click Add Porticol. Remove restores the file.
By hand, the entries are:
claude mcp add --scope user porticol -- porticol-cli mcp
Cursor, in ~/.cursor/mcp.json:
{ "mcpServers": { "porticol": { "type": "stdio", "command": "porticol-cli", "args": ["mcp"] } } }
Codex, in ~/.codex/config.toml:
[mcp_servers.porticol]
command = "porticol-cli"
args = ["mcp"]
The setup follows the agent: for level 2 on macOS and Linux, let Porticol add the Claude Code sandbox and proxy settings. Cursor gets fail-closed shell and MCP hooks, which can ask and deny but are not a forced network path. Codex gets an experimental upstream proxy and a deny-only command hook.
3. Write the policy
Start in shadow mode so you can see what would have been blocked before anything is. When the rules look right, change mode to enforce. The example below is already in enforce, because the walkthrough holds a DELETE.
version: 1
mode: enforce
hosts:
api.example.com: { env: production, key: "{{api_key}}" }
rules:
- match: { method: [GET, HEAD] }
action: allow
- match: { env: production, method: [POST, PUT, PATCH] }
action: ask
agents:
claude-code: { up_to: production }
cursor: { up_to: production }
codex: { up_to: production }
"*": { up_to: staging }
{{api_key}} names a secret variable of the production environment. Its value stays in the keychain, and Porticol adds it to the request.
The first matching rule wins. A call above the agent's ceiling is denied before any rule. A deny is final; an ask waits for a person, and a call no rule matches asks on a protected environment. The Policy page validates the file as you type, shows each rule's allow, ask and deny counts and what shadow mode would have done over the last seven days, and has three templates: read-only production, ask before writes to production, and block deletes everywhere.
4. The held DELETE
When an agent sends DELETE /users/42 to production and the default asks, the agent receives:
{
"status": "pending",
"approval_id": "8f0c…",
"reason": "DELETE to production needs a person.",
"message": "A person must approve this call in Porticol. Call send again with the same request and approval_id once they have. Do not loop and do not ask for a secret."
}
The approval card shows the agent's name, the production badge, the exact request with the key masked, and the agent's reason in its own words. Choose Deny and the call stops. Choose Allow once and only that request goes; choose Allow for today and, when a rule asked, that rule's calls are allowed until local midnight. A system notification fires while the app is in the background, and porticol-cli approve <id> or deny <id> works from a terminal with the four-letter code shown on the card.
The approval is bound to a SHA-256 of the request the policy decided: the method, URL, environment, headers, auth, protocol, settings and body. It is single use and expires after 10 minutes. A retry with a different request does not match.
5. Read the log
Agent activity lists every call with its agent, method, URL, environment, decision and rule, and filters by each. A row opens what the agent saw beside what was sent, with keys revealed only on request. The log is hash-chained: porticol-cli guard log verify checks it, and export gives JSON or CSV with who, which agent, what call, what decision, who approved and when. Free keeps 30 days locally; Team keeps 90; Business keeps 180 with export.
The honest limit
Level 1 stops mistakes, not an agent that finds a key and runs curl itself. Level 2 closes that for Claude Code on macOS and Linux: its sandbox sends shell traffic through the local proxy, and a person can still turn the sandbox off. Codex gets the proxy settings and a hook that can only deny; Cursor gets hooks only, with no forced network path. The agent's name in the log is what the client reports, not a verified identity. Windows runs levels 1 and 3 only. For production that must be protected from every laptop, use level 3: the team gateway holds the production key, and production trusts only the gateway.
Questions
Will Guard stop every delete? No. At level 1 it stops the deletes that go through Porticol's MCP server. At level 2 Claude Code's sandbox covers shell commands, unless someone turns it off, while Codex and Cursor cover only what their proxy and hooks see. At level 3 the production key is only on the gateway, and production accepts calls from the gateway alone.
What about a key that is already on the laptop? porticol-cli guard scan finds .env files and known credential files in a project. Porticol offers to move each value into the keychain, showing every change before it writes. Until that key is gone, level 1 cannot stop an agent that finds it.
Does this need an account? No. Free runs levels 1 and 2 on your own computer with no account. A team needs an account to share a policy, route an approval to a teammate, or run the team gateway.