Outcall

Egress control · agent containers

Decide what your containers can reach.
Then prove it.

By default, an LLM agent in a container can reach the public internet, your internal network, and the host's localhost services. Outcall says no in the kernel: nftables, DNS, and an HTTP proxy your container can't bypass — and every allow you write becomes an nft list table counter you can read.

/etc/outcall/rules.d/agent.yaml
# /etc/outcall/rules.d/agent.yaml
# Default-block is implicit. Write only what the agent may do.
# HTTPS is matched by hostname (SNI). Method/path are visible
# only for plaintext HTTP — no TLS interception.
version: "1"
rules:
  - id: allow-openai
    description: "agent may call the OpenAI API over HTTPS"
    condition: 'http.host == "api.openai.com"'
    action: allow
    egress:
      mode: proxy

  - id: allow-github-clone
    condition: |
      dns.query == "github.com" ||
      http.host == "github.com"
    action: allow

What's in the box

One daemon. Six surfaces. Same source of truth.

Outcall ships the network plumbing, the policy plane, and the operator UX as a single binary. You don't stand up six tools to enforce egress — you stand up one.

Default-deny in the kernel

Each agent host gets one Linux bridge with `policy drop` on FORWARD. Allow rules you write compile to nftables verdicts and hit-counters. Verify any rule is live with `nft list table inet outcall`.

Block agents at the DNS layer

The bridge gateway answers only for hosts in your rule set. Unlisted lookups return NXDOMAIN — agents fail immediately at name resolution, not after a 30-second TCP timeout that taints retries.

See exactly what HTTPS calls were made

A forward proxy on the bridge matches plaintext HTTP on host + method + path, and HTTPS on CONNECT host + TLS SNI — no decryption, by design. A per-rule intercept mode is specified (S011) but intentionally not implemented in v0.1; HTTPS method/path/body is not visible inside the encrypted tunnel.

Agents ask before they reach

A Unix socket inside each container lets the agent ask the daemon via `outcall fetch <url>` (or `outcall exec`, `outcall file`, etc.) before acting, and submit new rule requests for operator approval. The agent never touches host policy directly; rule changes are auditable.

Reload policy without restarting agents

Drop YAML into `/etc/outcall/rules.d` and `outcall rules reload`. Networks and containers outlive the daemon — you can ship a rule change in seconds without rolling a single agent.

One source of truth across CLI, API, and dashboard

The `outcall` CLI, the JSON API on `/run/outcall/host.sock`, and the web dashboard all read the same daemon state. What you see in the UI is what `outcall rules list` prints — no separate inventory to drift.

How it fits together

One bridge. One source of truth.

The daemon is the only thing on the host that can change policy. Operators talk to the host socket. Containers talk to the agent socket. Neither side reaches the other.

Operatoroutcall CLI · UIAgent containeroutcall-agent shimhost.sockagent.sockoutcalldrule enginebridgenftablesDNS filterHTTP proxyagent APIdocker manageroutcall0 bridgeInternet (filtered)

Stop trusting agents.
Start enforcing them.

Outcall is open source. Spec-first, default-deny, and Linux-native. If you run agents that touch the network, you owe yourself a look.