Skip to content

Latest commit

 

History

History
133 lines (101 loc) · 5.89 KB

File metadata and controls

133 lines (101 loc) · 5.89 KB

Claude Code Integration

safe-rm includes a general-purpose hook system for Claude Code that can intercept and require email approval for any tool call -- not just rm commands.

Overview

Claude Code supports hooks -- shell commands that run in response to events like tool calls. By writing a hook script that sends events to the safe-rm approval server, you can gate any Claude Code action behind email approval.

This is useful when you let Claude Code run autonomously on a server and want to be notified (and have veto power) when it tries to execute shell commands, write files, or perform other actions.

How It Works

Claude Code tries to call a tool (e.g., Bash)
        │
        ▼
Hook script intercepts the tool call
        │
        ▼
POST /api/claude-events (HMAC-signed)
        │
        ▼
Server checks auto-approve window
        │
   ┌────┴────┐
   │         │
 Active    No auto-approve
   │         │
   ▼         ▼
 Return    Create event, send webhook to n8n
 immediately        │
   │         ▼
   │     Email with:
   │     [Approve] [Deny] [Respond]
   │     [Auto-approve 5 min] [Auto-approve 15 min]
   │         │
   │         ▼
   │     Hook script polls /api/claude-events/:id/status
   │         │
   │    ┌────┴────────┬──────────┐
   │    │             │          │
   │  Approved      Denied    Responded
   │    │             │          │
   ▼    ▼             ▼          ▼
 exit 0          exit 2     Print response
(proceed)       (block)     text, exit 0

Email Actions

When a hook event is created, the approval email includes five buttons:

Button Action
Approve Approves this single tool call. Claude Code proceeds.
Deny Blocks this single tool call. Claude Code is prevented from executing it.
Respond Opens a form where you can type a custom text response. Claude Code receives this text.
Auto-approve 5 min Approves this call and all subsequent calls from the same session for 5 minutes.
Auto-approve 15 min Same as above, but for 15 minutes.

Auto-Approve

When you click an auto-approve button:

  1. The current event is immediately approved.
  2. A session-level auto-approve entry is stored with an expiry timestamp.
  3. All subsequent POST /api/claude-events requests for the same session_id return 200 with auto_approved: true immediately -- no email is sent, no polling is needed.
  4. After the window expires, new events require email approval again.

The auto-approve window is clamped between 1 and 60 minutes. Expired entries are cleaned up automatically.

Setting Up the Hook

1. Create the hook script

Create a script on your server that your Claude Code hook will execute. This script should:

  1. Read the tool name and input from the hook environment/arguments.
  2. Construct a JSON payload with an event_id, event_type, session_id, tool_name, and tool_input.
  3. Sign the payload with HMAC-SHA256 using the shared secret.
  4. POST to {SAFE_RM_API}/api/claude-events with the X-Claude-Signature header.
  5. Poll {SAFE_RM_API}/api/claude-events/{event_id}/status until resolved.
  6. Exit with code 0 (approved/responded) or code 2 (denied/expired).

2. Configure Claude Code

Add a hook to your Claude Code configuration (.claude/settings.json or project-level settings) that runs your script on tool calls you want to gate. Refer to the Claude Code documentation for the exact hook configuration format.

3. Set the session ID

The session_id field is used to scope auto-approve windows. Pass a unique identifier for the current Claude Code session so that auto-approve applies to the correct session.

You can set the CLAUDE_SESSION environment variable before starting Claude Code, and have your hook script read it:

export CLAUDE_SESSION="session-$(date +%s)-$$"
claude

Your hook script can then use $CLAUDE_SESSION as the session_id in the event payload.

API Endpoints for Hooks

All Claude Code hook endpoints use the same shared secret (SAFE_RM_SECRET) as the delete approval system, but with the X-Claude-Signature header instead of X-SafeRM-Signature.

Endpoint Method Description
/api/claude-events POST Create an event (requires HMAC signature)
/api/claude-events/:id/status GET Poll event status
/api/claude-events/approve/:id/:token GET Approve (email link)
/api/claude-events/deny/:id/:token GET Deny (email link)
/api/claude-events/respond/:id/:token GET/POST Custom text response form/submit
/api/claude-events/auto-approve/:id/:token/:minutes GET Auto-approve for N minutes
/api/claude-events GET List events (admin, supports ?status= and ?session_id= filters)

For full request/response schemas, see ARCHITECTURE.md.

Event Status Values

Status Meaning Hook script action
pending Waiting for user action Continue polling
approved User clicked Approve (or auto-approved) Exit 0 (allow)
denied User clicked Deny Exit 2 (block)
responded User sent a custom text response Read response_text, exit 0
expired Timeout reached with no action Exit 2 (block)

Security Notes

  • The hook system shares the same HMAC secret as the delete approval system. A single SAFE_RM_SECRET authenticates both the rm client and hook scripts.
  • Auto-approve is scoped to a session_id. Different sessions have independent auto-approve windows.
  • Auto-approve entries are cleaned up from the database when they expire.
  • The custom response form is protected by a separate response_token (distinct from the approve/deny tokens).