v2.0.0next
Sandboxed workers

Callbacks from a sandbox

How a sandboxed worker reaches Kraft through a network policy's channel, which verbs it has there, and what is refused without one.

A sandboxed worker reaches Kraft through a channel of its own. This page covers the shim it calls, how each harness's permission check travels, and what changes without network:.

The kraft shim

Under a network policy a sandboxed worker reaches Kraft through its session's own channel, the one its proxy runs on. Every such container has Kraft's kraft shim, a sh and curl script, mounted read-only at /opt/kraft/bin and first on its PATH (the image's own PATH after it).

The shim has only the verbs a worker needs, each for the worker's own item only:

  • kraft item progress K
  • kraft item reply THREAD --body ...
  • kraft item retry: an escalation turn may retry its item, and a worker's own retry is answered 403
  • kraft view show|threads
  • kraft view events [--after N] [--type T]
  • kraft admin permission-hook HARNESS

view events answers the item's history as JSON (all of it, or the part --after and --type keep). The history holds what a person wrote in a steer or a gate note, and every permission decision. There is no -f inside.

There is no kraft view diff or compare inside: Kraft reads no git in a worktree while a sandboxed session runs in it, and the worker has git itself.

The shim sends each call to http://kraft through the proxy, which answers it in the Kraft server itself, never forwarded anywhere.

A call acts as the session whose channel it came in on, whatever headers or token the worker sends. It acts only on that session's own work item: its progress, replies on its own item's threads, its own permission asks, and reads of its own item. An escalation turn may also retry that item.

A call to anything else is answered 403 and recorded as a sandbox_egress_refused event, like a refused host. A worker's own retry of its item passes the channel, and the API refuses it with 403 ("a worker session cannot act on its own work item"); no event is recorded for that one. No allow list entry is needed for any of this.

Permission checks under network:

  • Codex. Its hook is the shim's admin permission-hook codex.
    • The hash Codex needs to trust the hook is asked of the image's own codex, in a short container with no network, since Codex silently skips a hook it does not trust and runs the call.
    • When that cannot be done (the image's Codex does not start, or does not trust the hook), the task is refused.
    • When the shim gets no answer from Kraft, it prints Codex's own deny.
  • Claude. Launched with Kraft's MCP server at http://kraft/mcp and no other (--strict-mcp-config), which answers its permission tool for that session alone.
  • Cursor ignores a proxy, so it is refused under a network policy.

Without network:

Kraft sets up no channel to itself: the container has no kraft command and no Kraft MCP server. Kraft does not restrict the container's network either, so do not rely on this configuration to keep a worker away from the host: see Security.

For that reason every launch into a sandbox without network: is refused, whatever the harness, unless the sandbox sets unrestricted_network: true. That key says you accept an unrestricted network and gates that are not enforced; it cannot be set together with network:.

With it, a sandboxed Claude task is still refused before it starts (its permission tool would be missing and the CLI would exit), as is a Codex or Cursor task with a tool policy (allowed_tools, deny_tools or a grant other than git-commit). For a task that does start:

  • Prompts do not tell the worker to run kraft: it tags its commits with the task number instead of reporting progress, and says what it did about each review thread in its result.
  • No reply agent is launched for review threads: a comment review answers reply_agent: false, and the item records a reply_agent_skipped event saying why.
  • An escalation turn cannot resume the chain itself: you retry it.
Copyright © 2026