Skip to content
GurtOS

Add a secret to the vault

The vault is where the box keeps keys and tokens. Agents never read it. A tool that runs inside the box service reads the keys it declared, makes the call, and hands the task only the result. In this guide you add a key to the vault, on the box's screen, through the box's API, or by editing the file. All three take effect at once except the file.

  • The key's name, as the app that uses it expects. See Vault keys.
  • For the screen: the box's own screen, or a phone paired as the owner.
  • For the API or the file: a shell on the box (on Ubuntu, a terminal on GurtOS Personal, or SSH on a debug build of GurtOS Server), or a phone paired as the owner for the API. See pair a phone as the owner.
  1. Open Settings, then Accounts & Keys. The list shows the model keys, the keys of apps that are on, and any key already in the vault. During first-run setup, the Model key step takes a model key. Other keys are set only in Settings.
  2. Choose Set key (Replace if the key is already set) on the key's row, or Add a key… for a name that is not listed. Paste the key and choose Save.

The screen shows only whether a key is set and when. It never shows a key again; to change one, choose Replace and paste a new key. On GurtOS Personal, open GurtOS Settings from the desktop, then Accounts & Keys. Its buttons are Add or Replace on a key's row, Add a key… for any other name, and Save key in the dialog. The AI models step of GurtOS Setup takes a model key. A phone paired as the owner can set keys too.

An Anthropic key is checked when you save it: the box asks Anthropic for one model with the key. If Anthropic rejects it, the box does not save it and says so. If Anthropic cannot be reached, the key is saved unchecked. A Factory key cannot be checked until its first task.

Only the owner may set keys: a request from the box's own machine, or from a phone paired as the owner. A name starts with a capital letter, then has capital letters, digits and underscores, 2 to 64 characters in all. A value is one line of at most 8,192 characters.

  1. Set the key. This reads the value without echoing it or leaving it in your shell history:

    read -rs -p 'Value: ' v && curl -s -X PUT http://127.0.0.1:7700/api/vault/FACTORY_API_KEY \
    -H 'content-type: application/json' -d "{\"value\": \"$v\"}"; unset v
    {"name":"FACTORY_API_KEY","setAt":"2026-10-24T07:12:00.000Z","check":"unchecked","checked":false,"message":"Saved. GurtOS can't check a Factory key before its first task."}

    For ANTHROPIC_API_KEY the answer has check set to ok or unchecked, and a key Anthropic rejects is refused with a 400 and not saved. Any other name has no check field.

    The box writes the key to /etc/box/vault.env, keeps the file root-only, and uses the key at once. The action log records that FACTORY_API_KEY was set, never the value.

  2. Check the names. No route ever returns a value:

    curl -s http://127.0.0.1:7700/api/vault
    [{"name":"FACTORY_API_KEY","setAt":"2026-10-24T07:12:00.000Z"}]

    setAt is null for a key that was put in the file by hand.

The vault is a plain KEY=value file. Everything after = is the value, with no quotes.

  1. Add one line per key:

    read -rs -p 'Value: ' v && echo "FACTORY_API_KEY=$v" | sudo tee -a /etc/box/vault.env >/dev/null; unset v

    On a debug build of GurtOS Server you are already root, and the image has no sudo and no text editor. Run the same line without sudo.

  2. Keep it readable by root only. The box refuses to start if anyone else can read the file.

    sudo chown root:root /etc/box/vault.env
    sudo chmod 600 /etc/box/vault.env
  3. Restart the box service. The box reads the file at start.

    sudo systemctl restart box.service

    Running tasks resume where they were. See Resume after power loss.

systemctl is-active box.service
curl -s http://127.0.0.1:7700/api/health

The service is active and health answers {"ok":true,...}. If the file's mode is wrong, the service fails and the journal says the vault "must be readable by root only (chmod 600)":

journalctl -u box.service -n 20

A tool whose key is missing fails its call with "the vault has no <NAME>", which shows in the task's log.

Part of the box What it may read
A task (the agent) Nothing. It runs as its own user and the file is root only.
A tool Only the keys in its own secrets list.
A model job Only the keys in its own secrets list.
An app's routes and triggers Only the keys in the app's secrets list.
The box's network proxy The model key, FACTORY_API_KEY or ANTHROPIC_API_KEY, which it swaps in on calls to Factory or Anthropic, so a Droid task holds only a placeholder.
You, through the API Names and when each was set. Never a value.
  • The vault is a plain file on the data disk, protected by file permissions. It is not encrypted at rest.
  • Edits to the file by hand need a restart of the box service. Keys set through the API do not.
  • A tool's result goes into the action log. A tool that returned a key would leak it there, so tools must never return one.