AI and network restrictions at a glance
These diagrams show how ForgeKairos restricts AI and outbound network traffic. For the detailed rules, see Outbound network control and AI.
Is a request let through?
An HTTP request started by an AI feature is checked in this order.
flowchart TD
R["Outbound request"] --> O{"Marked as the editor's own traffic?<br/>(language servers, extensions, updates, Git, ...)"}
O -- "Yes" --> FREE["Not restricted"]
O -- "No (treated as AI traffic)" --> L{"Loopback?<br/>127.0.0.0/8, ::1, localhost"}
L -- "Yes" --> ALLOW["Allowed"]
L -- "No" --> B{"Built-in allowance?<br/>(marketplace, ACP registry,<br/>ForgeKairos update check; fixed paths only)"}
B -- "Yes" --> ALLOW
B -- "No" --> A{"Host matches the allowlist?<br/>network_allowlist.json"}
A -- "Yes" --> ALLOW
A -- "No" --> DENY["Denied"]
ALLOW --> RD{"Redirect?"}
RD -- "No" --> DONE["Sent"]
RD -- "Yes: check the next hop the same way<br/>(credential headers dropped on a host change)" --> L
- Loopback is let through even with an empty allowlist, so local LLMs (Ollama, LM Studio, llama.cpp) work without any setup.
- Allowing a host allows every port on it.
Who is restricted, and through which path
flowchart LR
subgraph APP["ForgeKairos"]
AI["AI features<br/>providers, edit predictions,<br/>fetch and web search, MCP (HTTP)"]
TOOLS["Editor tools<br/>language servers, extensions,<br/>updates, Git, remote server"]
GATE["Allowlist check<br/>(loopback + built-in allowances + allowed_hosts)"]
PROXY["Loopback proxy<br/>(loopback + allowed_hosts only;<br/>no built-in allowances)"]
end
subgraph CHILD["Child processes"]
ACP["ACP agents"]
MCP["MCP servers (stdio)"]
NPM["npm installing agents"]
end
SB["Agent sandbox<br/>(WSL / bubblewrap / Seatbelt)"]
BR["Built-in browser"]
NET(("Internet"))
AI --> GATE --> NET
TOOLS -- "not restricted" --> NET
ACP & MCP & NPM -- "HTTP_PROXY / HTTPS_PROXY" --> PROXY --> NET
SB -- "sandbox's own allowances ∩ allowlist" --> NET
BR -- "not restricted by default;<br/>browser.use_egress_proxy routes it through the allowlist" --> NET
- The child-process proxy relies on the program reading the proxy environment variables. A program that
ignores them cannot be restricted. Turn it off with
proxy_child_processes: false. - The sandbox can narrow the allowlist but never widen it.
Before a cloud AI provider is used
By default no AI runs, and nothing is sent to an external provider.
sequenceDiagram
actor U as User
participant FK as ForgeKairos
participant AL as Allowlist
participant P as Cloud provider
Note over FK: agent.enabled = false (default). All AI is off
U->>FK: Settings → AI → Enable the agent
Note over FK: Local LLMs (loopback) work from here
U->>FK: Choose an external provider
FK-->>U: Warning (input and conversations are sent) and required hosts
U->>FK: Tick the acknowledgement
Note over FK: Recorded in acknowledged_external_ai_providers
U->>AL: Add to allowlist
FK->>P: Requests get through only now
Note over U,AL: Revoking asks whether to remove hosts<br/>that no other provider uses
Acknowledging without adding the hosts leaves traffic to that provider denied.
When the agent runs a command or tool
flowchart TD
T["Agent tool call"] --> AC{"Always confirmed in every mode?<br/>safety rules, always_confirm,<br/>outside the sandbox, permission escalation,<br/>writes to .zed or settings, outside the project"}
AC -- "Yes" --> ASK["Ask the user"]
AC -- "No" --> M{"agent.tool_permissions.default"}
M -- "confirm (default)" --> ASK
M -- "deny" --> NO["Not run"]
M -- "allow" --> RUN
M -- "auto" --> J{"Ask the judge model<br/>(10-second limit)"}
J -- "SAFE" --> RUN
J -- "anything else" --> ASK
ASK -- "Approved" --> RUN["Run inside the sandbox"]
RUN --> NETSB["Network limited by the allowlist<br/>credentials (~/.ssh, .npmrc, ...) unreadable"]
RUN --> PAUSE["After a write to the project,<br/>that folder's own code (formatters,<br/>language server build scripts, ...)<br/>is paused until resumed"]
autosends the command and paths to the judge model's provider, so a local model is recommended.- The only way to turn the sandbox off is
agent.sandbox_permissions.allow_unsandboxed, and while it is off every command is confirmed.
SSH remotes
flowchart LR
subgraph LOCAL["Local machine"]
AL["Allowlist<br/>(the local one only)"]
CL["ForgeKairos"]
end
subgraph REMOTE["Remote host"]
RS["Remote server"]
RP["Remote loopback proxy<br/>(not on Windows remotes)"]
RA["ACP agents / MCP servers"]
end
NET(("Internet"))
AL --> CL
CL -- "sent on connect and on every change" --> RS
RS --> RP
RA -- "HTTP_PROXY" --> RP --> NET
RS -- "downloads<br/>(relay_http_through_client, on by default)" --> CL --> NET
A remote with no internet access can still fetch language servers through the local machine.