Interven guard for Anthropic Computer Use — scan every computer/bash/text-editor tool call through policy + risk before it executes locally. Block, route to approval, or allow.
Project description
interven-computer-use
Govern Anthropic Computer Use tool calls through Interven before they run on your host.
Computer Use tools — computer_* (mouse/keyboard/screenshot), bash_* (shell),
text_editor_* (file edits) — execute locally and never touch HTTP. The
only place to govern them is the agent's own loop: after messages.create
returns tool_use blocks and before you execute them. IntervenGuard sits
exactly there. Each tool call is scanned through Interven's policy + risk engine,
and the decision is mapped back into Computer Use's allow/deny model.
Install (30 seconds)
pip install interven-computer-use
export INTERVEN_API_KEY=iv_live_... # from https://app.intervensecurity.com/signup
Use
Wrap the tool-execution step of your loop. The guard scans, then either runs your executor (ALLOW/SANITIZE) or returns a synthetic error block (DENY/REQUIRE_APPROVAL):
import anthropic
from interven_computer_use import IntervenGuard
client = anthropic.Anthropic()
guard = IntervenGuard() # reads INTERVEN_API_KEY from env
def run_tool(block):
# your existing executor: screenshot, run bash, edit a file, ...
return execute_computer_use_tool(block.name, block.input)
messages = [{"role": "user", "content": "Open the terminal and run `whoami`."}]
while True:
response = client.beta.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=[
{"type": "computer_20250124", "name": "computer",
"display_width_px": 1280, "display_height_px": 800},
{"type": "bash_20250124", "name": "bash"},
{"type": "text_editor_20250124", "name": "str_replace_editor"},
],
betas=["computer-use-2025-01-24"],
messages=messages,
)
tool_results = []
for block in response.content:
if block.type == "tool_use":
# One line of governance — scan + execute-or-block:
tool_results.append(guard.guard_tool_use(block, execute=run_tool))
if not tool_results:
break # no tools requested — Claude is done
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
Prefer to make the decision yourself? Call guard.check(block) and inspect the
Verdict (.proceed, .decision, .reason, .approval_url, .trace_id).
Decision mapping
| Interven decision | What the guard does |
|---|---|
| ALLOW | Runs your execute and returns its real tool_result. |
| SANITIZE | Runs the tool (a pure-local action — a mouse click, a keystroke — can't be redacted), logs the event for audit, and writes a warning to stderr. |
| DENY | Skips execution. Returns a tool_result with is_error=True and a reason string Claude sees and reacts to. |
| REQUIRE_APPROVAL | Skips execution. Returns is_error=True with an "approval pending" message + the Console approval URL. After an analyst approves, Claude's retry on the next turn lands inside the approval grace window and auto-allows. |
A blocked call returns a standard Computer Use tool_result block:
{ "type": "tool_result", "tool_use_id": "tu_…", "content": "Interven DENY (…). Trace: …", "is_error": true }
Configuration
| Env var | Default | Purpose |
|---|---|---|
INTERVEN_API_KEY |
required | Your iv_live_* key. Sign up at https://app.intervensecurity.com/signup |
INTERVEN_GATEWAY |
https://api.intervensecurity.com |
Gateway base URL. Override only when self-hosting. |
INTERVEN_TIMEOUT_MS |
5000 |
Per-scan timeout in milliseconds. |
INTERVEN_FAIL_CLOSED |
(unset) | Set to 1 to block when a scan fails. Default is fail-open. |
INTERVEN_CONSOLE_URL |
https://app.intervensecurity.com |
Base URL used to build approval links. |
All of these can also be passed to the constructor:
guard = IntervenGuard(
api_key="iv_live_...",
gateway="https://interven.your-company.internal",
timeout=10.0,
fail_closed=True,
agent_name="ops-desktop-agent",
)
Failure mode
If /v1/scan is unreachable (network down, gateway 5xx, timeout, missing key),
the guard fails open by default: the tool runs and a warning is written to
stderr, so a partial outage doesn't freeze the agent. Set
INTERVEN_FAIL_CLOSED=1 (or fail_closed=True) to block instead — choose this
when enforcement matters more than availability.
What gets scanned
Every tool_use block you pass to guard_tool_use / check is scanned — not
just the three built-in families — so a custom tool your agent calls is governed
too. The guard infers a category (computer / bash / text_editor /
other) from the tool name and includes it in the scan so policies can match on
it. No tool args are executed before the decision returns.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file interven_computer_use-0.1.1.tar.gz.
File metadata
- Download URL: interven_computer_use-0.1.1.tar.gz
- Upload date:
- Size: 11.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cb12ba82683ea8ba093a1b42e4b53b3e12c07f7a7e05c817bee0c6de8cba612c
|
|
| MD5 |
2e0fff11f9b45c1e5e98461709542a2c
|
|
| BLAKE2b-256 |
d6fba87c29ac77e21f79b98d397a531e8e994b7b88f70784bad23027990cb1d5
|
File details
Details for the file interven_computer_use-0.1.1-py3-none-any.whl.
File metadata
- Download URL: interven_computer_use-0.1.1-py3-none-any.whl
- Upload date:
- Size: 10.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65067157b41f2acb20fd91d75c7167ec294b18133e7df7e302136ca324f2bdf2
|
|
| MD5 |
1f63e5be065cc3dd57e6e22958cac33c
|
|
| BLAKE2b-256 |
5bd05894638dac52762f1bfda430b3b472d01376aa6e4b48a2b273eb69916f48
|