@capsulesecurity/pi-capsule
v1.0.1
Published
Capsule extension for Pi — forwards hook events to the Capsule agentsecurity service for centralized policy enforcement and audit.
Readme
@capsulesecurity/pi-capsule
Capsule extension for Pi. Forwards Pi hook events to your Capsule agentsecurity tenant and applies
the tool_call block verdict returned by Capsule policy.
Install
Register the package in your Pi settings.json (~/.pi/agent/settings.json, or .pi/settings.json for a single
project):
{
"packages": ["npm:@capsulesecurity/pi-capsule"],
}Configure
Pi has no per-extension config block in settings.json, so the extension reads .pi/capsule.json - the project copy
first, then ~/.pi/capsule.json:
{
"endpoint": "https://agents.capsule.security",
"token": "<jwt-signed-with-tenant-PI_SECRET>",
"blockOnRisk": true,
"failOpen": true,
"timeoutMs": 5000,
"allowConversationAccess": false
}endpoint and token are always read from the same source, never combined across sources. The first of the
environment, the project .pi/capsule.json, then ~/.pi/capsule.json that supplies both wins, and the rest of its
settings come with it. A project file carrying only an endpoint is ignored with a warning, so an untrusted
repository cannot redirect your token to its own server. The remaining options can still be overridden by an
environment variable, which repository content cannot set.
| Option | Env var | Default | Description |
| ------------------------- | ----------------------------------- | --------------------------------- | -------------------------------------------------------------- |
| endpoint | CAPSULE_ENDPOINT | - | Capsule agentsecurity base URL. |
| token | CAPSULE_TOKEN | - | JWT with tid (tenant) and eid (env external ID) claims. |
| blockOnRisk | CAPSULE_BLOCK_ON_RISK | true | Apply server block verdicts. Set to false for shadow mode. |
| failOpen | CAPSULE_FAIL_OPEN | true | Allow the tool to run when Capsule is unreachable. |
| timeoutMs | CAPSULE_TIMEOUT_MS | 5000 | Per-request timeout in ms. |
| allowConversationAccess | CAPSULE_ALLOW_CONVERSATION_ACCESS | false | Forward the model context transcript on every LLM call. |
| user | CAPSULE_USER | process.env.USER or "unknown" | User identifier sent on every event. |
Without endpoint and token the extension logs a warning and stays inactive - it never breaks the agent loop.
Hooks
- Blocking:
tool_call. Awaited, bounded bytimeoutMs, and the only hook whose verdict is applied. - Observation (fire-and-forget):
tool_result,tool_execution_start,tool_execution_end,session_start,session_shutdown,agent_start,agent_end,before_agent_start,turn_start,turn_end,user_bash. - Conversation (fire-and-forget, only when
allowConversationAccessis on):context.
user_bash fires for ! and !! commands, which run outside the tool loop. Pi does not accept a block verdict there,
so those commands are audited but not enforced.
Server contract
The extension POSTs to POST {endpoint}/v1/pi/hooks/events with:
{
"hook": {
"hook_event_name": "tool_call",
"context": {
"session_id": "...",
"workspace_dir": "/home/dev/repo",
"mode": "tui",
"model": "claude-opus-5"
},
"timestamp": "2026-09-22T10:00:00.000Z",
"toolName": "bash",
"toolCallId": "...",
"input": {}
},
"user": "[email protected]",
"plugin_version": "1.0.1"
}A tool_call response of { "block": true, "reason": "...", "terminate": true } is returned to Pi unchanged, which
stops the tool from running and shows the reason in the terminal. Any other response allows the call.
License
Proprietary. Copyright Capsule Security. All rights reserved.
