Skip to content
GurtOS

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 relay The relay machine, only when remote access is on. A hosted relay is not running during the preview, so this is a relay you run. It carries encrypted tunnel bytes and push messages. Untrusted with content. It sees names, addresses, connect times and byte counts, never what is inside HTTPS or a push.
The GurtOS app app.gurtos.com, an installable web app served from the public repository Trusted as much as its host. It holds each box's device token in the browser's storage. It reaches a box only at an https address, which today means one that a relay gives it.
The box's own screen The portal on the box's display, and anything else that calls the API from the box itself with the box's own Host and Origin 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. At most 64 KB per step, question or cost, and 20 MB in all. 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, never reaches link-local addresses (the cloud metadata service), and refuses the box's own ports. A name that resolves to the box or to a private network needs an exact host:port. At most 256 connections per task. 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 or api.anthropic.com, and puts the vault's key in the authorization or x-api-key header only. With a Factory key, only the paths Droid calls; a model call may not ask the service to fetch for the task. Token counts and cost as cost. Refusals as net.blocked.
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, a Host of 127.0.0.1 or localhost, and no Origin but the box's own address 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. It lets the device read, start tasks and answer like the box's screen, but never use the owner's controls (vault, settings, apps, folders, Keep). 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.
A paired device, through the relay The HTTP API at https://<name>.<relay domain> The same as a paired device on the home network TLS ends on the box. The request carries X-Forwarded-For, so a device token is required. The same as on the home network
The box (remote access on) The relay One outbound tunnel, and encrypted push messages The tunnel is verified against the relay's pinned certificate authority and logs in with the box's secret. The relay allows each name to route only its own address. Remote access state in Settings
Anyone else The HTTP API Only the health check, redeeming a pairing code, the portal's pages, Business work-account sign-in and the open routes of apps Every other request gets 401. At most 5 wrong pairing codes a minute per address, and 1 MB per request body. 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) and the owner has not refused strangers for that app. 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, and its guest and policy routes only queue a request for the owner to approve. What the app writes, such as approval.answered by jira:<name>
An app's page in a browser The HTTP API Its own app's routes; reads of tasks and approvals; answers to its own app's requests The page runs sandboxed (no same origin) with a window token from POST /api/apps/<id>/window. Anything else is 403. What the app writes, and approval.answered
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, an optional app) The HTTP API Reads, new tasks and answers, as a helper It runs on the box as nobody and calls the API on 127.0.0.1. The API counts it as a helper on the box, not the box's own screen, so it never gets the owner's controls. 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.