Skip to main content
Every action an agent takes — reading a file, running a command, querying a database — is a tool call. The gateway is the single chokepoint through which all of them flow. This page walks through exactly what happens.

Two Kinds of Tool Calls

There are two distinct paths depending on which tool is called: Core tools (read, write, patch, exec) execute directly via docker exec. Plugin tools go through an extra hop: a launcher script on $PATH inside the sandbox forwards the call back out through a Unix socket to the gateway, where the plugin handler runs.

Core Tool Call

When the LLM calls exec curl https://api.example.com:
  1. The LLM emits an exec tool call via the pi SDK
  2. The gateway writes an audit log entry (type: "core_tool", tool: "exec")
  3. The gateway runs docker exec <container> curl https://api.example.com
  4. The process runs inside the sandbox; stdout and exit code are captured
  5. The result is returned to the LLM
The sandbox has no special awareness of the gateway here — it simply runs a process.

Plugin Tool Call (Launcher + Socket)

Plugin tools like git, git, or any toolkit tool take a different path. Since /tools/bin is on $PATH, the agent calls them naturally. When the LLM calls exec git status: Step by step:
  1. The LLM calls exec git status
  2. Gateway writes audit log entry #1 (type: "core_tool", tool: "exec")
  3. Gateway runs the command in the sandbox — the shell finds git on $PATH at /tools/bin/git
  4. /tools/bin/git is a launcher script generated by the gateway at startup — it’s a thin shell wrapper that invokes tool-client
  5. tool-client serialises the tool name and args as JSON and connects to /beige/gateway.sock — a Unix socket mounted read-write into the container
  6. The socket server receives the connection; the agent’s identity comes from which socket file was connected to, not from the payload
  7. The policy engine checks whether this agent is permitted to invoke git
  8. If allowed, the plugin handler runs on the gateway host (outside the sandbox), executes the git logic, and returns the result
  9. The result travels back through the socket → tool-client → launcher → docker exec → gateway
  10. Gateway writes audit log entry #2 (type: "tool", tool: "git")
  11. The LLM receives the result
Two audit log entries are always produced for a plugin tool call: one for the exec that triggered it, one for the tool invocation itself.

Why the Extra Hop?

Plugin tool handlers run on the gateway host, not inside the sandbox. This is intentional:
  • Access to secrets — a git tool needs SSH keys, which never enter the sandbox
  • Access to host resources — a git tool writes to ~/.beige/data/, which the sandbox cannot reach directly
  • Consistent identity enforcement — the gateway always knows which agent is calling, regardless of what runs inside the container
The sandbox is an isolated execution environment. The gateway is the only entity that can reach the outside world on the agent’s behalf.

Policy Enforcement

The policy engine runs on every plugin tool call, before the handler executes:
  • If the agent’s config lists tools: ["git", "git"], only those tools are permitted
  • All other tool calls are rejected and the rejection is written to the audit log
  • Core tools (read, write, patch, exec) are always available — they are controlled by the Docker sandbox itself

Audit Log

Every tool call produces at least one audit log entry at ~/.beige/logs/gateway.log:
decision is either "allow" or "deny". Denied calls include an error field explaining why.