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 callsexec curl https://api.example.com:
- The LLM emits an
exectool call via the pi SDK - The gateway writes an audit log entry (
type: "core_tool",tool: "exec") - The gateway runs
docker exec <container> curl https://api.example.com - The process runs inside the sandbox; stdout and exit code are captured
- The result is returned to the LLM
Plugin Tool Call (Launcher + Socket)
Plugin tools likegit, 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:
- The LLM calls
exec git status - Gateway writes audit log entry #1 (
type: "core_tool",tool: "exec") - Gateway runs the command in the sandbox — the shell finds
giton$PATHat/tools/bin/git /tools/bin/gitis a launcher script generated by the gateway at startup — it’s a thin shell wrapper that invokestool-clienttool-clientserialises the tool name and args as JSON and connects to/beige/gateway.sock— a Unix socket mounted read-write into the container- The socket server receives the connection; the agent’s identity comes from which socket file was connected to, not from the payload
- The policy engine checks whether this agent is permitted to invoke
git - If allowed, the plugin handler runs on the gateway host (outside the sandbox), executes the git logic, and returns the result
- The result travels back through the socket →
tool-client→ launcher →docker exec→ gateway - Gateway writes audit log entry #2 (
type: "tool",tool: "git") - The LLM receives the result
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
gittool needs SSH keys, which never enter the sandbox - Access to host resources — a
gittool 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
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.