# Droid (https://tenki.cloud/docs/sandbox/droid)

> For the complete documentation index, see [llms.txt](https://tenki.cloud/llms.txt)

Start from Tenki's pre-built Droid image and run Factory's coding agent headlessly with droid exec.

Tenki's public `tenki/droid:stable` image starts from the standard [`sandbox` base image](https://tenki.cloud/docs/sandbox/base-image.md) and adds Factory's Droid coding agent (the `droid` command) plus the `droid-smoke` command for the API-key path. No credential is baked into the image. Droid authenticates from a `FACTORY_API_KEY` that you pass per session and that it reads straight from the session environment, so a session can start and finish unattended, or from a device-code login with your Factory account. Sandbox usage is programmatic, so you drive droid headlessly with `droid exec`.

## Droid: Factory's coding agent in your sandbox

Droid is Factory's terminal coding agent. Alongside its interactive mode it has `droid exec`, a non-interactive mode built for scripts and automation: it takes a prompt, does the work, and exits. That is the mode a sandbox uses, and it pairs with a disposable, isolated Linux VM you create and terminate per task, so an agent has somewhere to run real commands without touching your own machine.

## Start a session with an API key

Create a [Factory API key](https://app.factory.ai/settings/api-keys) (it has the form `fk-...`), export it locally, then pass it only to the session:

```bash
export FACTORY_API_KEY=<your-factory-api-key>

tenki sandbox create \
  --image tenki/droid:stable \
  --env "FACTORY_API_KEY=$FACTORY_API_KEY" \
  --name droid-demo
```

The shell history contains the environment variable reference, not the key value. Do not add the key to a template, snapshot, source file, or image.

Run the built-in connectivity check:

```bash
tenki sandbox exec --session droid-demo -- droid-smoke
```

`droid-smoke` runs one headless `droid exec` with your `FACTORY_API_KEY`, at the default read-only autonomy, and checks that the model echoes a sentinel token back. A successful result looks like:

```text
TENKI_SANDBOX_OK
```

`droid-smoke` exits `2` when `FACTORY_API_KEY` is unset, and `1` when the headless run fails (including a timeout) or the reply is missing the token.

Terminate the Tenki session when you finish:

```bash
tenki sandbox terminate droid-demo
```

## Start a session with a device-code login

Use this path to sign in with your Factory account instead of passing an API key. Create the session with no key:

```bash
tenki sandbox create --image tenki/droid:stable --name droid-demo
```

Droid has no `login` subcommand; it signs in from its interactive mode, which needs a real terminal. Open one over SSH and start droid:

```bash
tenki sandbox ssh droid-demo
droid
```

With no credentials, droid opens on a **Login** prompt (inside a running droid session, use `/login`). It prints a device URL on `auth.factory.ai` and a code. Open that URL on your own machine, enter the code, and droid is signed in for the life of the session. Exit droid and SSH; `droid exec` then runs with no `FACTORY_API_KEY` set.

If a session has both, `FACTORY_API_KEY` takes precedence over the stored login.

## Run a headless task

Drive droid programmatically with `droid exec`, which runs a single prompt and exits. For anything beyond it, run `droid exec --help` inside the session.

```bash
# One-shot task against the working directory inside the session
tenki sandbox exec --session droid-demo -- droid exec "summarize this repo's build setup"

# Against your own project: clone it into the session first, then run droid inside it
tenki sandbox exec --session droid-demo -- \
  bash -lc "git clone https://github.com/your-org/your-repo /home/tenki/work && cd /home/tenki/work && droid exec 'list the top-level modules and how they build'"
```

Both run at the default read-only autonomy. To let droid edit files or run commands, raise the level as described below.

Droid can also call your own model provider keys (BYOK) through custom models in its settings; see [Factory's BYOK docs](https://docs.factory.ai/cli/byok/overview). BYOK changes which provider droid calls, not how droid authenticates: a Factory login or `FACTORY_API_KEY` is still required.

## Autonomy levels

`droid exec` controls what the agent may do on its own through an autonomy level, and it defaults to read-only. Droid enforces this itself, before anything runs:

* **default (no flag)**: read-only. Droid reads files, inspects state, and runs read-only commands (`ls`, `cat`, `git status`, `git diff`), but makes no changes.
* **`--auto low`**: adds basic file operations in non-system directories (create, move, copy). No package installs and no system changes.
* **`--auto medium`**: adds recoverable development actions, such as installing packages without `sudo`, network requests, local git commits, and builds. No `git push` and no `sudo`.
* **`--auto high`**: adds actions with real side effects, such as running downloaded scripts, `git push`, deployments, and migrations. Droid's own gate still blocks `sudo` and system-wide changes at this level.
* **`--skip-permissions-unsafe`**: removes droid's gate entirely and allows every operation. It cannot be combined with `--auto`.

That gate is droid's own. In a Tenki sandbox the guest VM is the safety boundary, and raising the level only changes what droid may do inside that guest. Commands in a session run as the unprivileged `tenki` user (uid 1000) with passwordless `sudo`, so once the gate is fully removed, droid can do anything in that VM. What it cannot reach is the host, other tenants' sessions, and the Tenki control plane, and the VM is disposable.

## Pin an exact build

`stable` moves to each newly published build. When a workload has to stay on the exact build it was tested against, resolve the tag once and launch the snapshot reference it returns:

```bash
tenki sandbox registry resolve tenki/droid:stable
# image_id    : <image-id>
# snapshot_id : <snapshot-id>

tenki sandbox create --image tenki/droid@<snapshot-id>
```

A snapshot reference never moves, so it keeps launching that build after `stable` advances.