claude bfb10b9ab2 feat: token-authenticated approval API + structured webhook payload
Adds POST /api/actions/:id/approve and /reject so a notifier (desktop
popup, chat bot, phone) can resolve an action without driving the web UI
or holding a login session.

Auth is the per-action approve_token already minted at submit time: a
UUIDv4 scoped to exactly one action and delivered only in the approval
notification. The agent API key is deliberately NOT accepted on these
routes -- the agent submits actions, so letting it approve them would
defeat the human-in-the-loop guarantee. The token may be supplied in the
JSON body or as ?token=, matching the existing approve link.

Both endpoints return 401 for an unknown id/token and 409 (with the
current status) if the action is no longer pending, so a notifier can
tell "someone else already handled this" from "this failed".

The notification webhook gains a structured "action" object alongside the
existing "text" field, which is unchanged so current consumers keep
working. Previously the id, command and approve URL were only available
by regexing the human-readable blob.

Also collapses three copies of the actions SELECT and its row mapping
onto ACTION_COLUMNS/row_to_action, and extracts the execute and
reject-chain logic into helpers now shared by the web and API handlers.
Those helpers no longer .unwrap() DB errors while holding the connection
mutex, which would poison it for the life of the process.
2026-08-13 03:03:19 -07:00
2026-03-08 23:33:41 -07:00
2026-03-08 23:33:41 -07:00
2026-03-08 23:33:41 -07:00

Action Gateway

Human-in-the-loop approval service for agent actions. The agent submits actions; you approve or reject them via a web UI.

Setup

1. Config (optional)

Create /home/node/.openclaw/workspace/config/action-gateway.toml:

database_path = "/home/node/.openclaw/workspace/config/action-gateway.db"
bind = "0.0.0.0:7878"
base_url = "https://yourdomain.com:7878"
notification_webhook = ""  # optional Matrix/webhook URL

2. Add a user

./gateway-cli add-user admin yourpassword

3. Generate an API key for the agent

./gateway-cli gen-api-key agent
# Copy the key — store it in pass: pass insert gateway/api-key

4. Run the server

./action-gateway
# 🚀 Action Gateway running at http://0.0.0.0:7878

Agent usage (from inside the container)

# Submit an action
curl -s -X POST http://host:7878/api/actions \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{"description":"List files in /tmp","command":"ls /tmp"}'

# Poll for result
curl -s http://host:7878/api/actions/<id>/result \
  -H "Authorization: Bearer <api-key>"

CLI commands

gateway-cli add-user <username> <password>
gateway-cli list-users
gateway-cli remove-user <username>
gateway-cli gen-api-key [label]
gateway-cli list-keys

Binaries

After cargo build --release:

  • target/release/action-gateway — the web server
  • target/release/gateway-cli — admin CLI
S
Description
Rust-based action gateway with human approval workflow
Readme
115 KiB
Languages
Rust 100%