Skip to content

Trust boundaries

A box is divided into zones with different trust. Each arrow between zones is a place where something is checked, or where it is not. This page names every crossing so you can see what protects it.

Trust boundaries Your devices reach the box's API on port 7700 with a paired device's token. SpacetimeDB listens on the box's loopback only. Inside the box, the core runs as root and holds the API, SpacetimeDB, the action log, the apps, the vault, the brokers and the proxy. Each task runs as its own user in its own zone. A task reaches the core only through its broker socket and the network only through the proxy, which lets it reach its allowed hosts. Three paths are blocked: a task reading the vault, a task connecting straight to any other host, and a task opening another task's copy of the files. Your devices Portal Phone From outside the box, every request needs a paired device's token. Settings, the vault and folders need the owner. SpacetimeDB is loopback only. :7700 + token The box Root: the core API SpacetimeDB 127.0.0.1 only Action log Apps Vault Broker Proxy Task A's own user Task A own copy, no keys, no sudo Task B's own user Task B own copy, no keys, no sudo socket proxy only vault other tasks' copies Outside APIs tools call with vault keys Allowed hosts and the model service Any other host refused, logged
The zones on one box. Your devices reach the API with a paired token, SpacetimeDB answers only on the box, tasks reach the rest only through their broker and the proxy, and the red paths are blocked.
Zone What is in it Trust
Outside The internet, the model provider, paid APIs, outside services such as Jira Untrusted. Reached on purpose, for specific jobs.
The box's own screen The portal on the box's display, and anything else that calls the API from the box itself Trusted like the owner
Your devices Phones and browsers paired with a one-time code Trusted to read, start tasks, undo and answer approvals. Owner's actions only for a device paired as the owner. Anyone without a token is refused.
The core, as root The box service, the vault, every app's code, the action log, the task proxy, SpacetimeDB on 127.0.0.1 Fully trusted. Holds every key.
Each task One Linux user, its own copy of a workspace, its worker (Droid or a test worker) Untrusted. Assumed to be wrong or hostile.

The core trusts apps completely: an app's tools, routes, triggers and log readers run inside the core as root.

From To What crosses Who checks Logged as
Task Its broker (Unix socket) Steps, tool calls, questions, costs The socket is owned by the task's user, mode 0600. The core checks the tool is in the task's tools, applies the budget and keys the call. task.step, tool.call, tool.result, approval.asked, cost
Task The internet Network connections The firewall sends task users only to the proxy. The proxy checks the task's hosts, resolves the name once, and refuses the box's own addresses and ports. Refusals as net.blocked. Allowed connections are not logged.
Droid task The model provider Model calls with a placeholder key The proxy relays only Droid tasks, only to Factory's hosts, and puts the vault's key on the request Token counts and cost as cost
Task The vault, the log, other tasks' files, the base files Nothing File permissions: all root-only or owned by another user Not logged. The task gets a permission error.
Task The API, SpacetimeDB, other local services Nothing The firewall rejects the packet; the proxy refuses the box's own ports The kernel log counts firewall rejects (prefix box-block). Proxy refusals are net.blocked.
Task Other tasks' processes Nothing ProtectProc=invisible, separate users Not logged
From To What crosses Who checks Logged as
A tool or model job The vault One key at a time The core returns only keys the tool or job lists in secrets Not logged
An app's route or trigger The vault One key at a time The core returns only keys the app lists in secrets Not logged
A tool Outside APIs Whatever the tool sends The tool's own code. Tools are outside the task's network limits. The call and its result as tool.call and tool.result
An app's code Anything on the box Anything Nothing. Apps run as root. Only what the app writes
From To What crosses Who checks Logged as
The box's own screen The HTTP API (port 7700, or the Unix socket) Everything The request comes from the box itself with no proxy header task.created with its source, approval.answered with the by it sends, note for settings, setup, vault and apps
A paired device The HTTP API Reads, new tasks, answers, undo A valid device token, as a header or ?access_token=. Without one, 401. approval.answered with the device's name, whatever the request says
A device paired as the owner The HTTP API Also pairing, settings, setup, the vault, apps, the owner, folders, Keep The token's device was paired as the owner from the box's own screen. Other devices get 403. note events, keep events. A vault key's name, never its value.
Anyone else The HTTP API Only the health check, redeeming a pairing code and the portal's pages Every other request gets 401 Not logged
The box's own screen SpacetimeDB (127.0.0.1:3000) Live tasks and approvals; answers through the answer reducer It listens on loopback, and the firewall never opens port 3000. Only the box writes tasks and approvals, and answer works only from a connection the box vouched for. approval.answered with the vouched name
Outside services App routes /t/<app>/... Whatever the app accepts A paired device's token, unless the app marks the route open (openRoutes). Open routes must check their own secret: the Jira app's routes require a shared secret and check the approval belongs to the task; the Mana app's status route returns only a public summary. What the app writes, such as approval.answered by jira:<name>
Outside callers Webhooks /hook/<app>/<name> A JSON payload that usually starts a task A paired device's token, then the app's handler task.created
The chat agent (ASI:One) The HTTP API The same actions as the box's own screen It runs on the box as nobody and calls the API on 127.0.0.1, so the API treats it as the box's own screen. Only paired chat owners can give it work. task.created with source asi1, answers by asi1
From To What crosses Who checks Logged as
An update file The idle system slot A whole system image box-update verifies the signature against /etc/box-os/update.pub and the hash, then checks the image holds the box /data/update/last and the serial console
The new system The default slot Becoming the default box-confirm.service waits up to 5 minutes for a healthy GET /health /data/update/last
  • Every path from a task to anything else goes through the broker or the proxy. Both run in the core and both write to the log.
  • The core is the one zone with the keys. Protecting the box means protecting root and choosing apps carefully.
  • The API trusts the box itself and paired devices. Everyone else is refused. SpacetimeDB stays on 127.0.0.1. The API speaks plain HTTP, so reach it from other devices over a network you control. See the threat model.

GurtOS is open source under the Apache License 2.0.Source code on GitHub.