Droid CLI Reference
Complete reference for the Droid CLI, including commands and flags
Installation
Install Droid CLI
The Droid CLI operates in two modes:
- Interactive (
droid) - Chat-first REPL with slash commands - Non-interactive (
droid exec) - Single-shot execution for automation and scripting
Installing a specific version
Pin a version when upgrades must be reviewed and applied intentionally, such as in CI runners, provisioned development environments, or other reproducible systems.
npm
Specify an exact package version:
npm install -g droid@0.174.0The binaries published through npm have auto-updates disabled at build time, so the installed version remains pinned. To upgrade, install the new version explicitly with npm.
Built-in updater
After installing Droid through the standalone installer, select a version with:
droid update --version 0.174.0This command can also roll back to an older version. Use droid update --check to check for an
available update without installing it.
Standalone installations enable automatic updates by default. After selecting a version, follow the auto-update guidance to keep it pinned.
Direct binary download
Release binaries and their SHA256 checksums use the following paths:
https://downloads.factory.ai/factory-cli/releases/<version>/<platform>/<arch>/<binary>
https://downloads.factory.ai/factory-cli/releases/<version>/<platform>/<arch>/<binary>.sha256<platform>:linux,darwin, orwindows<arch>:x64,arm64, orx64-baseline<binary>:droidon Linux and macOS, ordroid.exeon Windows
For example, download and verify the Linux x64 binary:
VERSION=0.174.0
BASE_URL="https://downloads.factory.ai/factory-cli/releases/${VERSION}/linux/x64"
curl -fsSLO "${BASE_URL}/droid"
curl -fsSLO "${BASE_URL}/droid.sha256"
echo "$(awk '{print $1}' droid.sha256) droid" | sha256sum --check
chmod +x droidMove the verified binary to a directory on PATH. The download URL layout is an implementation
detail, so always pin a version and verify its checksum.
Droid CLI commands
| Command | Description | Example |
|---|---|---|
droid | Start interactive REPL | droid |
droid "query" | Start REPL with initial prompt | droid "explain this project" |
droid --resume [sessionId] | Resume a session (defaults to last modified). Alias: -r | droid --resume |
droid --fork <sessionId> | Fork and resume a session in a new copy | droid --fork session-abc123 |
droid exec "query" | Execute task without interactive mode | droid exec "summarize src/auth" |
droid exec -f prompt.md | Load prompt from file | droid exec -f .factory/prompts/review.md |
cat file | droid exec | Process piped content | git diff | droid exec "draft release notes" |
droid exec -s <id> "query" | Resume existing session in exec mode | droid exec -s session-123 "continue" |
droid exec --list-tools | List available tools, then exit | droid exec --list-tools |
droid search "query" | Search across local sessions (messages, documents, tool results). Alias: droid find | droid search "auth bug" |
droid rules check | Validate permission rules and optionally preview command policy | droid rules check --command 'git push origin main' |
droid mcp add <name> <url> | Add an MCP server | droid mcp add api https://api.example.com/mcp --type http |
droid mcp remove <name> | Remove an MCP server | droid mcp remove linear |
droid automations <command> | Create, list, read, edit, delete, or run automations, and list their templates (details) | droid automations list --execution-location remote |
droid plugin install <plugin> | Install a plugin. Alias: droid plugin i | droid plugin install droid-control@factory-plugins |
droid plugin uninstall <plugin> | Uninstall a plugin. Alias: droid plugin remove | droid plugin uninstall droid-control@factory-plugins |
droid plugin update <plugin> | Update a plugin to the latest version | droid plugin update droid-control@factory-plugins |
droid plugin list | List installed plugins | droid plugin list |
droid plugin marketplace | Manage plugin marketplaces | droid plugin marketplace |
droid computer register [name] | Register this computer for Remote Control | droid computer register laptop |
droid computer remove | Remove this computer's Remote Control registration | droid computer remove |
droid computer list | List computers and Factory Environments as JSON; use --human for readable tables | droid computer list --human |
droid computer service-accounts list | List service accounts (Manager role or higher) | droid computer service-accounts list |
droid computer ssh <name> | SSH into a registered computer | droid computer ssh laptop |
droid computer port-forward <name> <mappings...> | Forward local ports to a computer over the relay | droid computer port-forward laptop 8080:80 |
droid daemon | Run the Factory daemon server | droid daemon |
droid daemon --remote-control | Connect this computer through Remote Control. Alias: --remote-access | droid daemon --remote-control |
droid update | Manually update the CLI to latest version | droid update |
List computers and environments
droid computer list lists your computers and the Factory Environments visible to your
identity, including whether each Environment can launch. It is read-only and prints JSON
by default. Use --human for readable tables.
droid computer list
droid computer list --humanTo list another identity's inventory, first list the organization's service accounts, then select an active account by its ID or name. Both account discovery and account selection require the Manager role or higher. Replace the example values with an account returned by the first command:
droid computer service-accounts list
droid computer list --service-account-id sa_example
droid computer list --service-account-name "deploy-bot"| Flag | Behavior |
|---|---|
--service-account-id <id> | List the selected service account's computers and Factory Environments instead of your own. |
--service-account-name <name> | Select the same inventory by account name. Supply either the ID or the name, not both. |
--human | Print readable output instead of JSON; nonempty lists appear as a computer table followed by a Factory Environments table. |
The service-account list returns {"ok": true, "data": {"serviceAccounts": [...]}}.
Each account has id, name, and status. Deleted accounts are omitted; inactive
accounts remain visible, but only active accounts can be selected with the flags above
or run automations.
Read the human output
In English, --human prints a computer table with COMPUTER, STATUS, PROVIDER, and ID columns and
marks this machine with (this machine) when Droid can identify it. When there are no
computers, it prints a message instead: how to register this machine for your own
inventory, or No computers registered for service account "<name>". for a selected
account.
When Environments are returned, a Factory Environments: section follows after a blank
line. The table has ENVIRONMENT, STATUS, SCOPE, LAUNCHABLE, and ID columns, and
LAUNCHABLE is yes or no. For example, with illustrative names and IDs:
COMPUTER STATUS PROVIDER ID
laptop (this machine) active byom 3f2a9c1e-5b7d-4e8a-9c0f-1d2e3f4a5b6c
dev-box active e2b 8b1c2d3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e
Factory Environments:
ENVIRONMENT STATUS SCOPE LAUNCHABLE ID
team-default ready organization yes 0c56098a-c40d-4a56-bdd2-8f58120dc456
my-sandbox building user no 6de596d4-1a67-4ebc-be46-61265c198698With --service-account-id or --service-account-name, the heading is
Factory Environments service account "<name>" can launch:.
If the Environment lookup fails, one line replaces the Environments section, and the computers still list. The HTTP status appears when one is available:
Factory Environments could not be listed (HTTP <status>: <error>).Without an HTTP status, the line is Factory Environments could not be listed (<error>).
When the lookup succeeds with no Environments, the section is omitted.
Read the JSON result
A successful computer list returns {"ok": true, "data": {...}} with these fields:
| Field | Meaning |
|---|---|
data.serviceAccount | The selected account (id, name, status), or null for your own inventory. |
data.computers | Computer rows with id, name, providerType, thisMachine, and status when known. An unknown status appears as unknown in the human table. |
data.environments | A successful Environment lookup (ok: true, items) or a failed lookup (ok: false, error, and an HTTP status when available). |
Each Environment item has id, name, status, scope, and launchable. Use an
Environment with launchable: true when choosing an automation's environmentName.
Account selection applies to both the computers and Environments in the result.
An Environment lookup can fail while the computer list succeeds. Check
data.environments.ok before reading items: ok: false means the lookup failed,
not that no Environments exist. The top-level ok can still be true, and the
command can exit successfully with the computer inventory intact.
Migrate existing scripts and prompts
droid computer list defaults to JSON. If a script expects the computer table, add
--human and account for the Factory Environments section, or update the script to read
data.computers and handle data.environments separately.
Update tool names in prompts and automation instructions:
| Previous tool | Current tool |
|---|---|
ListComputers | computer_list (Script: tools.computer.list) |
ListServiceAccounts | computer_service_accounts_list (Script: tools.computer.service_accounts_list) |
PickSlackChannels | Removed. |
Check permission rules
Use droid rules check to validate permission rules,
run their embedded matching examples, and preview a decision without executing a command.
droid rules check
droid rules check --command 'git push origin main'
droid rules check --file rules.json --command 'npm publish' --json| Option | Behavior |
|---|---|
--file <path> | Check a standalone {version, rules} object or bare rule array. Does not load built-ins or other settings. A full settings.json wrapper is not accepted. |
--command <shell-command> | Preview the policy decision for a non-empty command. Quote it so your shell passes it as one argument. |
--json | Print the report as one JSON object, including rule diagnostics and, when requested, decision and match details. |
Without --file, the checker validates resolved settings. A command preview follows the
active policy engine; validating rules does not enable enforcement on a client still
using legacy policy.
Exit code 0 means the check succeeded, even if the preview says block. Invalid rules
or failed examples produce exit code 1. Preview covers command policy only, not
hooks, sandbox permissions, autonomy, or session approvals.
The commandAllowlist, commandDenylist, and commandBlocklist settings are deprecated
but remain respected for backward compatibility. Use permissionRules for new policy;
see migration guidance.
Droid CLI flags
Customize droid's behavior with command-line flags:
| Flag | Description | Example |
|---|---|---|
-f, --file <path> | Read prompt from a file | droid exec -f plan.md |
-m, --model <id> | Select a specific model ID | droid exec -m claude-opus-5-5 |
-s, --session-id <id> | Continue an existing session | droid exec -s session-abc123 |
--auto <level> | Set autonomy level (low, medium, high) | droid exec --auto medium "run tests" |
--only-tools <ids> | Use only these tools: names such as Read, or MCP:<server>[/<tool>] (comma or space separated) | droid exec --only-tools Read,Grep,Glob,LS |
--add-tools <ids> | Add tools to the default set (same selectors as --only-tools) | droid exec --add-tools MCP:linear |
--remove-tools <ids> | Remove tools from the allowed set (same selectors as --only-tools) | droid exec --auto low --remove-tools Execute |
--disable-builtin-skills | Disable Factory-provided builtin skills in interactive or exec sessions while preserving other skill sources | droid --disable-builtin-skills |
--list-tools | Print available tools and exit | droid exec --list-tools |
-o, --output-format <format> | Output format (text, json, stream-json, stream-jsonrpc) | droid exec -o json "document API" |
--input-format <format> | Input format for multi-turn sessions. Use stream-jsonrpc; the older stream-json mode is deprecated. Must match --output-format. | droid exec --input-format stream-jsonrpc -o stream-jsonrpc |
-r, --resume [sessionId] | Resume a previous session. In interactive mode, -r is --resume; in droid exec, -r is --reasoning-effort. | droid -r |
-r, --reasoning-effort <level> | Override reasoning effort; valid levels are model-dependent (see /models). In droid exec, -r maps to this flag. | droid exec -r high "debug flaky test" |
--spec-model <id> | Use a different model ID for specification planning | droid exec --spec-model claude-opus-5-5 |
--spec-reasoning-effort <level> | Override reasoning effort for spec mode | droid exec --use-spec --spec-reasoning-effort high |
--use-spec | Start in specification mode (plan before executing) | droid exec --use-spec "add user profiles" |
--skip-permissions-unsafe | Skip all permission prompts; command blocks still apply (unsafe) | droid exec --skip-permissions-unsafe |
--cwd <path> | Execute from a specific working directory (use an absolute path) | droid exec --cwd "$PWD/service" --auto medium "run tests" |
-w, --worktree [name] | Run the session in an isolated git worktree | droid --worktree fix-bug |
--tag <spec> | Session tag (name or JSON, repeatable) | droid exec --tag code-review |
--log-group-id <id> | Log group ID for filtering logs | droid exec --log-group-id grp-123 |
--fork <id> | Fork and resume an existing session into a new copy | droid exec --fork session-abc123 |
--mission | Run droid exec in Mission Mode (multi-agent orchestration). Requires --auto high or --skip-permissions-unsafe. | droid exec --mission --auto high -f mission.md |
--worker-model <id> | Model used for mission worker agents | droid exec --mission --worker-model claude-opus-5-5 |
--worker-reasoning-effort <level> | Reasoning effort for mission worker agents (model-dependent; see /models) | droid exec --mission --worker-reasoning-effort medium |
--validator-model <id> | Model used for mission validator agents | droid exec --mission --validator-model gpt-6.1-sol |
--validator-reasoning-effort <level> | Reasoning effort for mission validator agents | droid exec --mission --validator-reasoning-effort high |
--append-system-prompt <text> | Append custom text to the end of the system prompt | droid --append-system-prompt "Always run tests." |
--append-system-prompt-file <path> | Append the contents of a file to the end of the system prompt | droid --append-system-prompt-file .factory/system.md |
--settings <path> | Apply a settings file merged on top of the normal settings hierarchy, for this process only | droid exec --settings ./runtime-settings.json |
-v, --version | Display CLI version | droid -v |
-h, --help | Show help information | droid --help |
Use --output-format json for scripting and automation, so you can parse droid's responses
programmatically.
--output-format controls how droid exec serializes results. Your saved
output style controls how Droid writes the responses inside them.
Manage automations
droid automations creates and manages automations from your
terminal. Each command is the command form of a tool Droid calls in a session, and both
take the same inputs. Each field of the tool is a flag in kebab case, such as
--execution-location for executionLocation, except automationId: read, edit,
delete, and run take it as their first argument.
| Command | What it does |
|---|---|
droid automations templates list | List the prompt presets that create --template-id applies. Add --trigger schedule, webhook, or slack to filter them. |
droid automations list | List the scheduled automations on this machine, or your scheduled, webhook, Slack, and chained automations in the cloud. |
droid automations read <automation-id> | Show one automation, with the full prompt its runs use. |
droid automations create | Create an automation. --trigger is schedule (the default), webhook, slack, or automation for a chained automation. |
droid automations edit <automation-id> | Change an automation. A new --prompt replaces the whole prompt. |
droid automations delete <automation-id> | Delete an automation. Deleting a webhook automation also retires its URL. |
droid automations run [automation-id] | Start a run now, without waiting for it to finish. Pass --automation-name <name> instead of an ID to match an exact name, ignoring case. |
Every command except templates list and run requires --execution-location: local
for automations on this machine, or remote for automations in the cloud. Webhook, Slack,
and chained automations are always remote. A local schedule runs only while the desktop
app or a standalone droid daemon is running on this machine; a terminal session alone
does not run it. Factory-managed Droid Computers never run local schedules, so create a
remote automation there.
droid automations templates list --trigger slack
droid automations list --execution-location remote
droid automations read 3f2a9c1e-5b7d-4e8a-9c0f-1d2e3f4a5b6c --execution-location remotecreate needs --name and --prompt, unless --template-id incident-response supplies
them for a Slack automation. That preset also sets --message-source bots and
--session-privacy team; explicit flags override its defaults. A scheduled automation
needs --schedule: a five-field cron expression for local, or a cron expression or
natural-language cadence for remote. New automations default to --status active.
A remote automation needs exactly one run target: --computer-name or --computer-id for
a computer, or --environment-name or --environment-id to start each run on a fresh
computer built from a Factory Environment. To deliver runs into an existing session
instead, pass --deliver-to-session-id and no run target; runs happen wherever that
session lives. Slack automations cannot deliver into a session.
For session delivery, --execution-location is still required, but the session determines
the actual location. A session on another unregistered local machine cannot be targeted
from this machine. In a tool call, deliverToSessionId: "current" names the calling
session; a terminal command must use an explicit session ID. Runs keep that session's
autonomy, model, and tools, so --model and --reasoning-effort are ignored and runs can
wait for permission. A session-delivery automation cannot start a chain. For a remote
automation already configured this way, edit --deliver-to-session-id can move delivery
to another session of the same machine kind, but cannot turn session delivery off.
If --computer-id or --computer-name identifies a temporary computer created from an
Environment, Factory targets that Environment instead, so each run gets a fresh computer.
Creating a remote scheduled automation also starts its first run right away, unless you
pass --status paused or it delivers into a session. If that run cannot start, the
automation is still created, and data.notes says why.
droid automations create \
--execution-location remote \
--name "Weekday PR summary" \
--schedule "0 9 * * 1-5" \
--prompt "Summarize the pull requests merged yesterday." \
--computer-name dev-boxFlags follow the tool's field types:
- A boolean field takes
--<flag>for true and--no-<flag>for false, as in--rotate-webhook-secret. - A list field takes several values or a repeated flag, and each value is added to the
list. A value that starts with
[is read as a JSON array and replaces the list, so--triggered-by-automation-ids '[]'clears it. --visualization_instructionand--memory_instructionkeep their underscores. On create, they append visualization and memory guidance to the run prompt.
Run droid automations <command> --help to list every flag.
Useful options beyond the run target:
| Flags | Applies to | Behavior |
|---|---|---|
--model, --reasoning-effort | create, edit | Pin the run's model and reasoning level. A model can be an ID, a display name, or cheapest for the available built-in model with the lowest credit multiplier. Omit them on create to use defaults. On edit, --model "" clears the pin; --reasoning-effort "" clears the reasoning override. Reasoning edits are remote-only. |
--description | Remote create, edit | Set a summary of up to 1,024 characters. |
--run-as-service-account-name, --run-as-service-account-id | Remote create | Choose one service account by name or ID. Requires Manager or Owner. Any remote trigger can run this way, on that account's computer or on an Environment. |
--privacy-level, --session-privacy | Remote create | Automation visibility is private or organization; run-session privacy is private or team. Defaults are private, except that service-account automations default to organization/team, organization visibility defaults sessions to team, and the Incident Response preset defaults sessions to team. |
--computer-id | Remote edit | Move an automation to another computer. A Slack automation running as a service account must stay on a computer owned by that account. Session-delivery automations use --deliver-to-session-id instead. |
--payload-regex | Webhook create, edit | Filter the raw delivery body with an unflagged JavaScript regex supported by RE2. Patterns cannot look ahead or behind, use backreferences, or set inline modifiers. On edit, --payload-regex "" clears it. |
--max-runs-per-hour | Webhook create, edit | Limit runs started by webhook deliveries per clock hour. Takes an integer from 1 to 60; the default is 10. |
--triggered-by-automation-ids | Remote create, edit | Set the automations whose completed or failed runs start this one. On edit, replaces the entire list; read triggeredBy first to preserve sources you still want. |
--pass-upstream-context, --no-pass-upstream-context | Remote create, edit | Include or omit the source run's outcome and final message in a chained run's prompt, marked as untrusted data. Enabled by default on create; omitted on edit, keeps the current value. |
--message-source | Slack create, edit | Match messages from anyone, humans, or bots. Defaults to anyone on create unless a preset supplies it; omitted on edit, keeps the current value. |
--keywords, --excluded-keywords, --excluded-authors | Slack create | Require a matching phrase, exclude matching phrases, or exclude senders. Exclusions take priority. On edit, use the corresponding --add-* and --remove-* flags. |
--add-slack-channel-patterns, --remove-slack-channel-patterns | Slack edit | Add or remove wildcard channel-name rules without replacing the other patterns. |
--tags | Remote create | Store tags for grouping the automation. |
A chain can be at most five automations deep, counting the first. Each automation can have
up to five sources and start up to five others; loops are rejected. Sources must have
the same owner and be scheduled, webhook, or chained automations, not Slack or CI.
--trigger automation waits only for its sources; another trigger keeps working alongside
the sources you add.
Each command prints JSON; there is no human-readable mode. A success prints
{"ok": true, "data": {...}} to stdout and exits 0. A failure prints
{"ok": false, "code": "...", "error": "..."} to stderr, sometimes with details, and
exits 1.
A success can still carry a partial result, so read data before you move on. When
create or edit saves the change but cannot read the automation back, data.readError
says why. When edit --rotate-webhook-secret saves the other changes but cannot rotate the
secret, the old secret keeps working and data.rotationError says why. data.notes
explains the rest of the result, such as where the automation runs.
| Where | Behavior |
|---|---|
| A terminal outside any session | The command runs. create, edit, delete, and run ask you to confirm first, and cancelling exits 130. When stdin or stdout is not a terminal, they cannot ask, and they exit 1 with confirmation_required. |
| A Droid session | Droid calls the tool directly. If the session's shell runs a droid automations command, it exits 1 with in_process_command, and details.tool and details.scriptPath name the tool to call instead. |
In droid exec at the default autonomy, Droid can list templates, list automations, and
read one, because those tools are read-only. Creating, editing, or running an automation is
medium risk. Deleting one, or creating one that runs as a service account, is high risk.
See autonomy levels. The automation tools are not available in an
airgapped deployment.
| Code | Meaning |
|---|---|
invalid_input | A flag failed the command's checks, or a required flag such as --execution-location is missing. When the flags fail the input schema, details lists each field's path and message. |
not_found | read found no automation you can read with that ID. Automations the command does not support, such as CI automations, return this code too. |
confirmation_required | The command needs your confirmation, and stdin or stdout is not a terminal. |
input_required | Someone has to choose Slack channels, and nobody can pick them where the command ran. See Choose Slack channels. |
in_process_command | A session's shell ran the command. |
request_failed | A request to Factory failed. status, when present, is the HTTP status. run reports start failures in details.reason instead. |
unexpected_error | Something else went wrong. error says what. |
Choose Slack channels
To have someone pick a Slack automation's channels, leave --slack-channels and
--slack-channel-patterns out of create, or pass --choose-slack-channels to edit.
--name-filter <text> narrows the channels offered to names that contain the text, in any
case.
In an interactive terminal, or on a direct tool call in a CLI session that can ask you
questions, a channel picker opens. On edit, it starts from the automation's current
channels. The selection replaces the channel set, as --slack-channels would. Press
Ctrl+R to reload the channel list, or Esc or Ctrl+C to cancel. A command in your terminal
exits 130; in a Droid session, cancelling ends Droid's turn.
Calls inside Script never open the picker, even in a CLI session. They return
input_required, as do tool calls in the desktop app, the web app, or droid exec when
they need a channel selection. details.rows lists up to 100 channels, details.total
counts every channel that matches --name-filter, and details.preselectedIds marks the
channels already configured. Confirm the set, then run the command again with
--slack-channels, or have Droid call the tool again with slackChannels.
On edit, --slack-channels and --choose-slack-channels replace the whole set, so they
cannot be combined with --add-slack-channels or --remove-slack-channels. A replacement
keeps the configured channels that the Factory Slack app can no longer see; the result
lists them in slackChannels.unavailable, next to the channels added and removed.
Read automation results
read returns the automation and its full prompt, or prompt: null when a local
automation's prompt could not be read. For a cloud automation, it also returns
triggeredBy, the automations whose runs start this one. For a webhook
automation, it returns deliveries, up to five recent deliveries with the newest first,
which show why a delivery did not start a run. Each is a separate lookup that can fail on
its own, so each is either {"ok": true, "items": [...]} or
{"ok": false, "error": "..."}, with a status when the lookup got an HTTP error.
triggeredBy always fails for an automation someone else owns, because only the owner's
list shows what starts it.
Cloud automation records also expose nextAutomationIds for downstream automations and
targetSessionId when runs deliver into an existing session.
list omits prompts. Each listed automation can include modelAvailable; read,
create, and edit can return it alongside the automation. false means its pinned
model does not resolve in the catalog and runs fall back to the default. An absent field
means the pin was not checked, including remote custom models.
A webhook's secret appears only once: with its URL in the result of create, or in the
result of edit --rotate-webhook-secret, which replaces it.
run returns started: true, automationId, name, sessionId, isPaused,
isWebhook, and nextAutomationIds. sessionId is nullable; a local shared-session run
returns its target session's ID. nextAutomationIds lists downstream automations.
When Factory refuses to start the run, run still exits 0 and returns
started: false with a reason and a detail:
| Reason | Meaning |
|---|---|
not_found | No automation you can run has that ID or name, or this machine's daemon no longer hosts it. |
ambiguous_name | More than one automation has that name. Run again with its ID. |
already_running | Factory answered with a conflict (HTTP 409). Usually a run is already in progress. Factory also answers this way when it pauses the automation instead of running it, for example because its computer was deleted, or when the session its runs deliver into has moved. Read detail before you retry. |
computer_offline | Its self-hosted computer is offline or hibernating. |
daemon_incompatible | The droid on its computer is too old to start runs on demand. |
not_runnable | Factory does not start this kind of automation on demand, such as a CI automation. |
local_only | The automation exists only as files on the machine that owns it, and this session cannot hand the run to that machine's daemon. |
api_disabled | Factory refused the run (HTTP 403), for example because your organization turned off the automations API or you cannot use the automation's computer. detail names the cause. |
In a Droid session that the desktop app or a standalone droid daemon runs, run also
starts a local automation that daemon hosts, by its slug or ID.
A run started this way gets no delivery payload or message from the caller. Its downstream
automations still run when it ends. A paused automation still runs. If the start request
fails, run fails with request_failed,
and details.reason is network, backend_error, or dispatch_failed. A call that names
no automation, or both an ID and a name, fails with invalid_input.
Renamed automation tools
The automation tools share these commands' names. A Script calls each one at its script path:
| Previous name | Tool | Script path | Command |
|---|---|---|---|
ListAutomationTemplates | automations_templates_list | tools.automations.templates_list | droid automations templates list |
ListAutomations | automations_list | tools.automations.list | droid automations list |
ReadAutomation | automations_read | tools.automations.read | droid automations read |
CreateAutomation | automations_create | tools.automations.create | droid automations create |
EditAutomation | automations_edit | tools.automations.edit | droid automations edit |
DeleteAutomation | automations_delete | tools.automations.delete | droid automations delete |
RunAutomation | automations_run | tools.automations.run | droid automations run |
A saved denial or --remove-tools entry that names a previous tool name also denies the
renamed tool. automations_create does not take chooseSlackChannels; leave the
channels out to have someone pick them. automations_edit applies chooseSlackChannels
in the same call as any other update.
Autonomy levels
droid exec uses tiered autonomy to control what operations the agent can perform. Only raise access when the environment is safe.
| Level | Intended for | Notable allowances |
|---|---|---|
| (default) | Read-only reconnaissance | File reads, git diffs, environment inspection |
--auto low | Safe edits | Create/edit files, run formatters, non-destructive commands |
--auto medium | Local development | Install dependencies, build/test, local git commits |
--auto high | CI/CD & orchestration | Git push, deploy scripts, long-running operations |
--skip-permissions-unsafe | Isolated sandboxes only | Skips all permission prompts; command blocks still apply |
Examples:
# Default (read-only)
droid exec "Analyze the auth system and create a plan"
# Low autonomy - safe edits
droid exec --auto low "Add JSDoc comments to all functions"
# Medium autonomy - development work
droid exec --auto medium "Install deps, run tests, fix issues"
# High autonomy - deployment
droid exec --auto high "Run tests, commit, and push changes"--skip-permissions-unsafe skips all permission prompts, but command blocks still apply.
Use only in isolated, disposable
environments such as throwaway containers. See Permission rules.
Model IDs
Use any available model ID with -m, --model or --spec-model. For custom models, see Custom Models (BYOK).
droid exec --model and --spec-model also accept provider tier aliases such as openai-latest-balanced, which follow Factory's recommended model for that provider and tier as new models ship.
Legacy models
When a newer version of a model is available to you, /model lists the older one in a collapsed Legacy Models section. Selecting a legacy model asks you to Switch to latest or Keep using legacy. Keeping it adds the model to legacyModelOverrides in your user settings.json, and Droid stops asking about it.
When Droid starts, it moves saved default models (including spec mode, subagent, mission, and compaction models) from a legacy model to its newer version, unless the model is in legacyModelOverrides. A model passed to droid exec --model runs as named.
Interactive mode features
Keyboard shortcuts
The interactive REPL supports a rich set of keyboard shortcuts for navigation, overlays, and input control:
| Shortcut | Action |
|---|---|
| Ctrl+C | Cancel the current operation / interrupt the agent. Press twice quickly to exit |
| Ctrl+Z | Suspend the process (Unix only). Resume with fg |
| Ctrl+O | Toggle the detailed transcript view (full message details) |
| Ctrl+T | Toggle the Mission Control overlay (orchestrator sessions only) |
| Ctrl+N | Cycle through available models (when typing in chat input) |
| Ctrl+L | Cycle through autonomy levels (when typing in chat input) |
| Ctrl+Y | Toggle the /btw scroll view (side-question history) |
| Ctrl+J | Toggle the changelog display (dismiss / restore) |
| Alt+E | Toggle the approval details view (Option+E on macOS) |
| Ctrl+V | Paste an image from the clipboard as an attachment |
| Tab | Cycle through the model's available reasoning-effort levels |
| Shift+Tab | Toggle Normal Mode and Spec Mode |
| @ | File path autocomplete: typing @ triggers fuzzy file search |
| Up / Down | Navigate input history (cycle through previously submitted messages) |
| Double Escape | Second press clears the input draft; a third Escape opens the rewind menu |
| ? | Open the scrollable keyboard shortcuts pane (when the input is empty); close it with Esc |
| Ctrl+/ | Open the keyboard shortcuts pane (works even when the input has content) |
| Ctrl+A | Move the cursor to the start of the line |
| Ctrl+W | Delete the word before the cursor |
| Ctrl+K | Delete from the cursor to the end of the line |
| Ctrl+U | Delete from the cursor to the start of the line |
| Ctrl+D | Clear all attached images, or forward-delete the next character if none attached |
| Ctrl+F | Open the fork tree for the highlighted session (in the /sessions list view) |
| Ctrl+R | Rename the highlighted session (in the /sessions list view) |
| Ctrl+X | Archive the highlighted session (in the /sessions list view); restores it on the Archived tab |
| Alt+Up | Scroll the transcript up (navigate any turn) |
| Alt+Down | Scroll the transcript down (navigate any turn) |
| Alt+PageUp | Scroll the transcript up to the previous user turn |
| Alt+PageDown | Scroll the transcript down to the next user turn |
| Escape | Close the active pane, overlay, or menu |
| Shift+Enter | Insert a newline in the chat input (multiline editing) |
| ! | Toggle bash mode (when the input is empty) |
Run /terminal-setup once to configure your terminal so Shift+Enter reliably produces a newline
in the chat input.
Bash mode
Press ! when the input is empty to toggle bash mode. In bash mode, commands execute directly in your shell without AI interpretation, useful for quick operations like checking git status or running npm test.
- Toggle on: Press ! (when input is empty)
- Execute commands: Type any shell command and press Enter
- Toggle off: Press Esc to return to normal AI chat mode
The prompt changes from > to $ when bash mode is active.
Mermaid diagram rendering
Droid automatically renders Mermaid diagram code blocks as ASCII art directly in the terminal, with no external viewer or browser required. When a response contains a fenced ```mermaid block of a supported diagram type, the diagram is drawn inline in the transcript.
Supported diagram types:
flowchart(andgraph)sequenceDiagramstateDiagramclassDiagramerDiagram
Unsupported diagram types (for example gantt, pie, mindmap, timeline, journey, gitGraph) fall back to displaying the raw Mermaid source and a link to view the diagram externally.
Markdown and math rendering
Droid renders supported inline Markdown styles in responses, including formatting inside table cells. It also converts inline and display TeX into Unicode math for terminal output.
Use \(...\) or $...$ for inline math. Use \[...\] or $$...$$ for display math.
A completed code fence labeled latex, math, or tex also renders as display math:
```latex
\frac{a}{b}
```Slash commands
Available when running droid in interactive mode. Type the command at the prompt:
| Command | Description |
|---|---|
/account | Open Factory account settings in browser |
/archive | Archive the current session (restore it from the /sessions Archived tab) |
/billing | View and manage billing settings |
/btw <question> | Ask a side question without polluting the main transcript |
/bug [title] | Create a bug report with session data and logs |
/clear | Clear conversation context, keep current model & autonomy |
/commands | Manage custom slash commands |
/compress [prompt] | Compress session and move to new one with summary |
/context | Show context window usage breakdown with progress bar |
/copy | Copy prompts, responses, turn ranges, or session ID |
/cost | Show usage statistics |
/create-skill | Create a reusable skill from current session |
/cd <path> | Change session working directory (alias for /cwd) |
/cwd <path> | Change session working directory |
/diagnostics | Show settings configuration errors |
/droids | Manage custom droids |
/missions | Enter Mission Mode |
/fast | Enable fast mode for current model (/fast off to disable) |
/favorite | Mark current session as a favorite |
/fork | Copy current session into a new session; you stay in the original and get a droid --resume <id> command for the fork |
/help | Show available slash commands |
/hooks | Manage lifecycle hooks |
/ide | Configure IDE integrations |
/install-code-review | Set up automated code review |
/install-slack-app | Install/connect Slack integration |
/language <locale> | Switch TUI display language |
/limits | Manage token usage limits and overage preferences |
/login | Sign in to Factory |
/logout | Sign out of Factory |
/mcp | Manage Model Context Protocol servers |
/model | Switch AI model mid-session |
/new | Start a fresh session, reset model & autonomy to defaults |
/plugins | Manage plugins and marketplaces |
/quit | Exit droid (alias: exit, or press Ctrl+C) |
/readiness-fix | Fix failing agent readiness signals from latest report |
/readiness-report | Generate readiness report |
/rename | Rename current session |
/review | Start AI-powered code review workflow |
/rewind-conversation | Undo recent changes in the session |
/sessions | List and resume previous sessions, with forks grouped under their parent (details) |
/settings | Configure application settings |
/setup-incident-response | Set up Slack auto-run for incident-response channel |
/share | Share session with organization |
/skills | Manage and invoke skills |
/stats [period] | Show usage statistics (supports relative periods, date ranges) |
/status | Show current droid status and configuration |
/statusline | Configure custom status line |
/terminal-setup | Configure terminal keybindings for Shift+Enter |
/themes | Choose a color theme |
/tree | Browse, label, and filter the current session's fork tree, and resume or fork from any entry (details) |
/vim [on|off] | Toggle vim-style modal editing (INSERT/NORMAL) in the chat input |
Slash commands stay usable while the agent is running: read-only and settings commands open right away over the live stream, commands that modify the conversation or session (such as /new, /clear, /compress) ask for confirmation before stopping the current run, and /model, /fast, and /archive apply only between turns. /fork also runs immediately: it copies the session in the background and keeps you in the original session, so there is nothing to interrupt.
Archiving hides a session from your session lists without deleting any data. Restore an archived session anytime from the Archived tab in /sessions (where Ctrl+X restores instead of archiving), or send a new message in the archived session to restore it automatically.
For detailed information on slash commands, see the interactive mode documentation.
Session list
/sessions lists your previous sessions and opens with the newest one selected. Press Enter to resume the selected session, or use the /sessions shortcuts to rename it, archive it, or open its fork tree.
Forks appear directly under the session they came from, marked with ↳, so a session and its forks stay together. Each fork family takes its place in the list from its most recently active member. Search keeps the grouping: when a search hides a fork's parent, the fork stays under its nearest ancestor that still matches.
A chain of sessions that each continue the last, such as the new session /compress starts, stays in one column. The indent grows only below a session that has more than one fork.
Session tree
/tree shows the current session's fork family as one tree: the messages of the original session and every fork, joined at the points where the forks branched off. ← current marks where you are, and ● <title> marks the latest entry of each session in the family.
A conversation with no forks renders flat. Rows indent only where the conversation branches: ├─ and └─ connect each branch to the row it branched from, and │ carries a branch past the rows of its siblings.
Select a row and press Enter to act on it:
- On another session's latest entry, resume that session.
- On a user message, fork just before it and prefill the message so you can edit and resend it.
- On an assistant message, fork just after it and continue with an empty prompt.
| Key | Action |
|---|---|
| Up / Down | Move the selection |
| Left | Collapse the selected branch, or jump to the row it branched from |
| Right | Expand a collapsed branch |
| Enter | Resume, edit and resend, or continue from the selected row |
| Shift+L | Add, edit, or clear the selected row's label |
| f | Cycle the filter: no tools, user only, all |
| t | Show user messages, assistant replies, and compaction summaries (the default "no tools" filter) |
| u | Show user messages only |
| a | Show every entry, including tool calls and results |
| l | Show only labeled rows; press again to return to "no tools" |
| Escape | Close the tree |
The footer names the active filter. The filter keys work even when the current filter shows no rows.
Shift+L opens a one-line editor below the tree, prefilled with the row's label. Press Enter to save it as a [label] badge on the row, or Escape to cancel. Saving an empty label removes it. Letters you type in the editor never trigger tree shortcuts. A label holds one line of up to 32 characters; longer text ends in an ellipsis.
Labels last until you exit Droid. They survive closing /tree and switching or forking from it, and because forks share their history, one label marks the same entry in every session of the fork family. Labels are not saved to disk.
Git worktrees
Use -w, --worktree [name] to run a session inside a native git worktree so you can work on multiple branches of the same repository in parallel without file conflicts. This flag is available on both droid (interactive) and droid exec.
By default, Droid creates worktrees under the worktreeDirectory setting, which defaults to ~/.factory/worktrees. Each worktree uses the path <root>/<8-character group>/<repository name>/ and has its own checkout and dedicated branch.
Branch naming:
--worktree(no value): Creates/reuses a worktree on a branch named<current-branch>-wt.--worktree <name>: Uses<name>as the branch. If the branch already exists, it is checked out in the worktree; otherwise it is created fromHEAD.- If the target branch is already checked out in another worktree, the command fails with a clear error.
Examples:
# Interactive: derive branch from current branch (creates <current>-wt)
droid --worktree
# Interactive: explicit branch name
droid -w fix-auth-bug "start debugging the login flow"
# Headless: isolate an automated task on its own branch
droid exec --worktree refactor-tests --auto medium "migrate jest suites to vitest"
# Run two parallel sessions on the same repo, each on its own branch
droid --worktree feature-a &
droid --worktree feature-b &Session lifecycle:
- Interactive mode: The worktree persists after the session ends so you can resume work, inspect changes, or push the branch.
droid execmode: On exit, a clean worktree (no uncommitted changes) is removed automatically; a dirty worktree is preserved and its path is printed so you can review the work.- The underlying git branch is never deleted by Droid; only the worktree directory is removed during cleanup.
When --worktree is active, Droid operates entirely inside the worktree directory. Run follow-up
commands (tests, builds, installs) from that directory rather than the original repo root. Fresh
worktrees may not have dependencies installed yet (for example node_modules); set them up if
builds or tests fail with missing-module errors.
Subcommand flags
In addition to the global flags above, several droid subcommands accept their own flags.
droid update flags
| Flag | Description | Example |
|---|---|---|
-c, --check | Check for updates without installing | droid update --check |
-v, --version <version> | Update to or roll back to a specific version | droid update -v 0.174.0 |
droid search flags
| Flag | Description | Example |
|---|---|---|
--kind <kind> | Filter by entry kind: message_text, document, tool_use, tool_result, or all | droid search "auth" --kind document |
--limit-sessions <n> | Maximum number of sessions to return | droid search "auth" --limit-sessions 5 |
--limit-hits <n> | Maximum number of matches per kind per session | droid search "auth" --limit-hits 3 |
--context-chars <n> | Number of characters of context shown around each match | droid search "auth" --context-chars 200 |
--json | Emit results as JSON | droid search "auth" --json |
--reindex | Drop the search cache and rebuild the local index | droid search "auth" --reindex |
droid mcp add flags
| Flag | Description | Example |
|---|---|---|
--type <type> | Server transport: http (streamable HTTP), sse (legacy HTTP+SSE), or stdio (local) | droid mcp add api https://api.example.com/mcp --type http |
--env <KEY=VALUE> | Set an environment variable for a stdio server (repeatable) | droid mcp add gh "gh-mcp" --type stdio --env GH_TOKEN=$GH_TOKEN |
--header <KEY: VALUE> | Add an HTTP header for a remote server (repeatable) | droid mcp add api https://api.example.com/mcp --type http --header "Authorization: Bearer $TOKEN" |
droid plugin flags
| Flag | Description | Example |
|---|---|---|
-s, --scope <scope> | Installation scope: user (default) or project | droid plugin install droid-control@factory-plugins --scope project |
droid computer register flags
| Flag | Description | Example |
|---|---|---|
-y, --yes | Skip interactive prompts and accept registration defaults | droid computer register laptop -y |
MCP command reference
The /mcp slash command opens an interactive manager UI for browsing and managing MCP servers.
Quick start: Type /mcp and select "Add from Registry" to browse 40+ pre-configured servers (Linear, Sentry, Notion, Stripe, Vercel, and more). Select a server, authenticate if required, and you're ready to go.
CLI commands for scripting and automation:
droid mcp add <name> <url> --type http # Add HTTP (streamable) server
droid mcp add <name> <url> --type sse # Add legacy HTTP+SSE server
droid mcp add <name> "<command>" # Add stdio server
droid mcp remove <name> # Remove a serverSee MCP Configuration for the full registry list, CLI options (--env, --header), configuration files, and how user vs project config layering works.
Authentication
- 1Generate an API key in the Factory API keys settings
- 2Set the environment variable:
export FACTORY_API_KEY=fk-...Persist the variable in your shell profile (~/.bashrc, ~/.zshrc, or PowerShell $PROFILE) for long-term use.
Never commit API keys to source control. Use environment variables or secure secret management.
Auto-updates
Standalone Droid installations check for and install CLI updates automatically. Run droid update
to trigger an update on demand.
To keep a standalone installation pinned, disable its in-process updater:
export FACTORY_DROID_AUTO_UPDATE_ENABLED=falseWith this variable set, automatic updates are disabled and droid update does not install another
version. Set it in the environment that launches every Droid process, including droid daemon.
The npm distribution has auto-updates disabled at build time and does not require this variable.
Running droid update from an npm installation reports that auto-update is unavailable. Setting
FACTORY_DROID_AUTO_UPDATE_ENABLED=true explicitly overrides the npm build default.
Enterprise administrators can disable CLI auto-updates for all organization members with the
disableAutoUpdate organization setting. See the release notes and
organization controls.
Pin the CLI and disable auto-updates in reproducible environments. For local developer installations, leave auto-updates enabled to receive fixes and security updates.
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | General runtime error |
2 | Invalid CLI arguments/options |
Common workflows
Code review
Interactive review inside a Droid session:
> /reviewNon-interactive review through droid exec:
# Analysis only
droid exec "Review this PR for security issues"
# With modifications
droid exec --auto low "Review code and add missing type hints"See the Local Code Review documentation for detailed guidance on review types, workflows, and best practices.
Testing and debugging
# Investigation
droid exec "Analyze failing tests and explain root cause"
# Fix and verify
droid exec --auto medium "Fix failing tests and run test suite"Refactoring
# Planning
droid exec "Create refactoring plan for auth module"
# Execution
droid exec --auto low --use-spec "Refactor auth module"Parallel sessions on one repo
# Work on two branches of the same repo at the same time, each in its own worktree
droid --worktree feature-a &
droid --worktree feature-b &
# Fan out headless tasks across branches without clobbering each other's files
droid exec -w migration-step-1 --auto medium "apply codemod A" &
droid exec -w migration-step-2 --auto medium "apply codemod B" &
waitSee Git worktrees for details.
CI/CD integration
# GitHub Actions example
- name: Run Droid Analysis
env:
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
run: |
droid exec --auto medium -f .github/prompts/deploy.md