Smart Agent Teams

Runner security

What a runner's credential allows, how agents are isolated, the known gaps, and how to run agents safely in production.

A runner executes model-driven processes that read your code, run commands and call the SAT API. This page explains the trust boundaries as the code implements them today: the credential, what an agent process can reach, and what it can do through the API. It ends with recommendations, which are labelled as such. Read the known gaps before you run agents on a machine that holds anything you care about.

The runner's credential

A runner authenticates with a personal API key. sat runner start refuses a password session.

PropertyBehaviour
Formatsat_live_ followed by 32 URL-safe characters
Storage on the serverOnly the SHA-256 hash, plus the first 13 characters (prefix) for display
ShownOnce, in the create response. It cannot be retrieved later
IdentityAuthenticates as the member who created it, in every company that member belongs to. Keys have no company or permission scope
ExpiryNever, unless created with expires_in_days (1 to 3650)
RevocationDELETE /api/me/api-keys/{key_id} or sat apikey revoke. Takes effect on the next request
Limits20 active keys per member; names unique among active keys. Revoked and expired keys do not count
Session-only actionsCreating and revoking keys (/api/me/api-keys and the legacy /api/users/{username}/api-keys routes) and signing out (POST /api/logout) refuse an API key with 403 SESSION_REQUIRED. Listing keys works with a key
User deactivatedThe key stops working
Password resetEnds every key created before the reset, along with all sessions. Create a new key for the runner afterwards

last_used is updated at most once a minute per key. See API keys.

Why a key and not a session

Agents use the runner's credential through sat. A password session can create and revoke API keys, sign you out everywhere, and its refresh token can mint new access tokens. An API key can do none of these, and it can be revoked on its own without signing you out.

Known gap in key restrictions

Profile. PATCH /api/me and PATCH /api/me/preferences accept an API key, so an agent can change its owner's name, avatar and preferences.

What an agent process can reach

sat runner starts each agent as a child process of the runner, as the same operating-system user. It sets these protections:

  • Empty sat configuration. SAT_CONFIG_DIR points at <workdir>/.sat-agent-config, an empty directory (mode 0700). SAT_CREDENTIAL_STORE=file, SAT_TOKEN and SAT_PROFILE are cleared. The agent's sat therefore sees no profiles and no stored credentials, only SAT_API_KEY.
  • One workspace per run. Project runs get their own git worktree, so concurrent runs never edit the same checkout. See Workspaces.
  • The agent CLI's own sandbox. Claude Code permission modes and Codex sandbox modes apply (below).

These protections do not make an agent a separate security principal:

  • The agent inherits the runner's entire environment: provider keys such as ANTHROPIC_API_KEY, cloud credentials, SSH_AUTH_SOCK and anything else set where the runner started.
  • Outside its CLI sandbox, the agent can read whatever the runner's user can read: the real ~/.config/sat credentials, other agents' workspaces and scratch folders, SSH keys, git credentials.
  • The empty configuration directory stops the agent's sat from using your stored session. It does not stop an agent with shell access from opening files directly.

What an agent can do through the API

Through sat and SAT_API_KEY, an agent has the full member powers of the key's owner. Agent-scoped credentials are not implemented. For example, an agent can:

  • Create, assign, move and edit tasks, goals and projects, delete tasks and goals, and post comments, in any company the owner belongs to (SAT_COMPANY is only a default).
  • Hire, edit, pause, resume, wake and terminate agents, including rewriting another agent's instructions.
  • Cancel runs and trigger routines.
  • Approve approvals, including its own budget_override, which lifts its monthly budget. Any member may decide any approval.
  • Change the company's name, mission and budget, when the key's owner is an owner or admin.
  • Attribute writes to another agent by passing that agent's running run id as run_id. The API checks only that the run is running.

Every write is in the activity log with its actor. Writes that pass run_id show the agent; others show the key's owner.

Members cannot be added yet

The API has no endpoint to add members to a company; the creator is its only member, with role owner. In practice the runner's key belongs to the company owner, with all of the owner's powers.

Permission modes and sandboxing

The agent CLI's permission or sandbox mode is the main control over what the agent does on the machine.

SettingDefaultEffectUse it
--claude-permission-mode acceptEditsYesFile edits are allowed; other tools follow Claude Code's permission rulesDeveloper machines
--claude-permission-mode planThe agent plans and changes nothingReviews, dry runs
--claude-permission-mode bypassPermissionsAny command, without askingOnly in a disposable container or VM
--claude-settingsExtra Claude Code settings, such as sandbox and network rulesAllow the SAT API host, deny everything else you can
--codex-sandbox read-onlyNo writesReviews
--codex-sandbox workspace-writeYesWrites inside the workspaceDeveloper machines
--codex-sandbox danger-full-accessNo sandboxOnly in a disposable container or VM
--max-turnsCaps Claude Code turns per runBound the cost and blast radius of one run

If the agent's sandbox blocks network access, the agent cannot reach the SAT API and its sat commands fail. Allow the API host through --claude-settings rather than switching to an unrestricted mode.

Secrets hygiene

  • Never put secrets in tasks, comments or agent instructions. They are sent to the model provider in the prompt and stored in SAT, visible to every member.
  • Transcripts store tool output. A command that prints a secret puts it in the run transcript, which every member can read. Keep secrets out of files and environment variables the agent is likely to print.
  • Protect the key at rest. Use sat apikey create --store (the macOS Keychain or libsecret when available, otherwise credentials.json with mode 0600), or an environment file with mode 0600. Never pass a key as a command-line argument on a shared machine.
  • Prefer expiring keys (--expires-in-days) and rotate them. Revoke a key as soon as a runner machine is retired or compromised.
  • One key per runner. Name keys after the machine (grace-laptop-runner, ci-runner) so you can revoke one without stopping the others.

Recommendations for production

Recommendations

The items below are recommendations, not behaviour SAT enforces.

  1. Run agents on a separate machine or container. Use a VM, container or CI job with nothing on it except the agent CLI, git and the runner. Treat it as untrusted. This is the only real boundary while agents share the runner's user and environment.
  2. Use a dedicated account. Run the runner as its own OS user with no access to personal files. When the API supports adding members, use a separate SAT member account for runners rather than an owner's key.
  3. Give least privilege outside SAT.
    • Git: read-only deploy keys or tokens if agents should not push; a bot account with branch protection if they should.
    • Model providers: a dedicated provider key with its own spending limit.
    • Cloud: no ambient credentials in the runner's environment.
    • Network: restrict outbound traffic to the SAT API, the model provider and your git host.
  4. Start the environment clean. Launch the runner from a service definition with only the variables it needs (see Run as a service), not from your interactive shell.
  5. Keep sandboxes on. Use acceptEdits or workspace-write. Reserve bypassPermissions and danger-full-access for disposable environments.
  6. Bound spend. Set every agent's monthly_budget_cents and decide budget overrides yourself. Agents can approve their own, so watch the activity log for approvals decided by the runner's key.
  7. Review before merge. Keep --on-success in_review and review the sat/... branches before anything reaches your main branch.
  8. Clean up workspaces that hold copies of your code. See Clean up.

On this page