On this page
- Conventions
- Commands
- sf ls
- sf create
- sf start
- sf restart
- sf recreate
- sf stop
- sf rm
- sf set
- sf info
- sf logs
- sf gpu
- sf image
- sf tasks
- sf top
- sf open
- sf shell
- sf screenshot
- sf apps
- sf app
- sf push
- sf pull
- sf gallery
- sf input
- sf window
- sf vpn
- sf gateway
- sf camera
- sf listen
- sf auto
- sf backup
- sf mcp
- sf approvals
- sf ask
- sf ai
- sf doctor
- sf host
- sf config
- sf token
- sf serve
- sf service
- sf version
- sf completion
- Next
Command reference
For anyone who runs the farm from a terminal or a script. Every command of sf, with its usage,
options and an example. sf <command> --help prints the same text for one command.
Conventions#
sf has two kinds of commands. Local commands (doctor, host, config, token, serve,
service, version, completion) work on the machine and need no daemon. All others talk to
the daemon over HTTP, so the daemon must be running (sf serve or sf service start).
A selector picks Androids. It is one of all, running, stopped, tag:NAME, a number such
as 5, or a range such as 1-10. Join selectors with commas and exclude with !, for example
1-10,tag:eu,!tag:spare.
Exit codes: 0 success, 1 the operation failed, 2 wrong usage, 130 interrupted with Ctrl-C. sf doctor exits 1 when a check fails, and sf service status exits 3 when the service is not active.
The global options below are accepted before and after the command name (sf --json ls and
sf ls --json are the same).
| Option | Description |
|---|---|
--home DIR | farm home to work on (default: $SUPERFARM_HOME or ~/.local/share/superfarm) |
--json | print the result as JSON (for scripts) |
--wait, --no-wait | follow a started task to its end and show per-device results (default: yes on a terminal, no in a script) |
-q, --quiet | no progress line and no hints, only the result |
Commands#
| Command | What it does |
|---|---|
sf ls (list) | list the Androids and their state |
sf create | add Androids (they are created stopped) |
sf start | start Androids |
sf restart | restart Androids |
sf recreate | rebuild the containers of Androids (data is kept) |
sf stop | stop Androids |
sf rm (delete) | delete Androids (asks first) |
sf set | change settings of Androids (applied at their next restart) |
sf info | show one Android in detail |
sf logs | show the container logs of one Android |
sf gpu | GPUs and the rendering mode of Androids |
sf image | Android images, one per Android version |
sf tasks | list background tasks, or show, follow and cancel one |
sf top | live load of the host, the GPUs and every running Android |
sf open | print the panel's address and how to log in |
sf shell | run a command inside Androids |
sf screenshot | save a screenshot of one Android |
sf apps | the app library: APK / XAPK / APKS / APKM files kept by the farm |
sf app | apps on the Androids: install, launch, stop, clear, compare versions |
sf push | copy a local file onto Androids |
sf pull | copy a file from one Android to this machine |
sf gallery | add a picture or video to the gallery of Androids |
sf input | send the same touch or key to many Androids at once |
sf window | native device windows (scrcpy) on the desktop the daemon runs on |
sf vpn | VPN profiles, logins and tunnel status |
sf gateway | shared VPN gateways: one tunnel for many Androids |
sf camera | feed a video or live stream into the camera and microphone of Androids |
sf listen | hear one Android on the speakers of the machine the daemon runs on |
sf auto | automation: train recordings into programs and run programs or flows |
sf backup | back up and restore Androids and the farm's settings |
sf mcp | let MCP-enabled AI assistants see and operate the farm |
sf approvals | answer AI assistants that ask to change the farm |
sf ask | ask the built-in Assistant to look at or operate the farm |
sf ai | the in-farm AI: model profiles, the Assistant, the Pilot |
sf doctor | check that this machine can run Androids, with the fix for each problem |
sf host | prepare and inspect this machine (kernel modules, limits, GPUs) |
sf config | read and change the farm's settings (config.yaml) |
sf token | print the API token the panel and scripts log in with |
sf serve | run the daemon (panel + API) in the foreground |
sf service | run the daemon as a systemd user service |
sf version | print the version |
sf completion | print a shell completion script |
sf ls#
Alias: sf list.
List the Androids and their state.
sf ls [-w] [--interval SECONDS]| Option | Default | Description |
|---|---|---|
-w, --watch | keep the list on screen and refresh it | |
--interval SECONDS | 2.0 | refresh interval for -w (default: 2) |
Example:
sf ls
sf ls -wsf create#
Add one or more Androids. Anything not given follows the farm's settings (sf config show) and keeps following them when they change.
sf create [-n COUNT] [--name NAME] [--android VERSION]
[--gpu {auto,software,igpu,dgpu,intel,amd,nvidia}]
[--net {direct,vpn,gateway,proxy,none}] [--vpn PROFILE] [--gateway NAME] [--cpus CPUS]
[--memory MIB] [--width WIDTH] [--height HEIGHT] [--dpi DPI] [--fps FPS] [--tag TAG]
[--data-volume VOLUME] [--image IMAGE]| Option | Default | Description |
|---|---|---|
-n, --count COUNT | 1 | how many (default: 1) |
--name NAME | display name (numbered when several are created) | |
--android VERSION | Android version, e.g. 13 (default: android.default_version) | |
--gpu {auto,software,igpu,dgpu,intel,amd,nvidia} | rendering: CPU only (software), integrated or discrete GPU, a vendor, or auto | |
--net {direct,vpn,gateway,proxy,none} | network mode | |
--vpn PROFILE | pin this VPN profile (implies --net vpn) | |
--gateway NAME | shared VPN gateway to use (implies --net gateway) | |
--cpus CPUS | CPU cores each may use | |
--memory MIB | RAM limit each, in MiB | |
--width WIDTH | screen width in pixels | |
--height HEIGHT | screen height in pixels | |
--dpi DPI | screen density | |
--fps FPS | frames per second | |
--tag TAG | tag for selectors (repeatable) | |
--data-volume VOLUME | adopt an existing Docker volume as /data (one Android only) | |
--image IMAGE | run this exact image instead of the one for the Android version |
Example:
sf create -n 5 --android 13 --gpu igpu --tag eu
sf create --name shop --net vpn --vpn nl-ams.ovpnsf start#
Start Androids.
sf start [--force] selector| Argument | Description |
|---|---|
selector | which Androids |
| Option | Default | Description |
|---|---|---|
--force | start even when the farm is over its capacity estimate |
Example:
sf start 1-10sf restart#
Restart Androids.
sf restart [--force] selector| Argument | Description |
|---|---|
selector | which Androids |
| Option | Default | Description |
|---|---|---|
--force | start even when the farm is over its capacity estimate |
Example:
sf restart tag:eusf recreate#
Rebuild the containers of Androids (data is kept).
sf recreate [--force] selector| Argument | Description |
|---|---|
selector | which Androids |
| Option | Default | Description |
|---|---|---|
--force | start even when the farm is over its capacity estimate |
Example:
sf recreate 3sf stop#
Stop Androids.
sf stop selector| Argument | Description |
|---|---|
selector | which Androids |
Example:
sf stop allsf rm#
Alias: sf delete.
Delete Androids and, unless --keep-data, their data. With backup.auto_before_risky (the default) a backup is taken first.
sf rm [--keep-data] [--force] [-y] selector| Argument | Description |
|---|---|
selector | which Androids |
| Option | Default | Description |
|---|---|---|
--keep-data | keep the /data volume (it can be adopted again later) | |
--force | delete even if the safety backup cannot be taken | |
-y, --yes | do not ask for confirmation |
Example:
sf rm 7
sf rm tag:test --keep-data --yessf set#
Change per-Android settings. Keys are InstanceSpec fields, nested ones with a dot (network.mode, resources.cpus, device.locale). Lists are comma separated. default puts an optional setting back to following the farm's value.
sf set [--force] selector key=value [key=value ...]| Argument | Description |
|---|---|
selector | which Androids |
key=value | one or more settings |
| Option | Default | Description |
|---|---|---|
--force | allow a change that can lose data (another Android version on existing data) |
Example:
sf set 1-5 fps=30 network.mode=vpn tags=eu,shop
sf set 3 gpu_mode=defaultsf info#
Show one Android in detail.
sf info [--device] id| Argument | Description |
|---|---|
id | Android id |
| Option | Default | Description |
|---|---|---|
--device | also ask the running Android about itself (model, build, battery) |
Example:
sf info 3sf logs#
Show the container logs of one Android.
sf logs [-n LINES] [--logcat] id| Argument | Description |
|---|---|
id | Android id |
| Option | Default | Description |
|---|---|---|
-n, --lines LINES | 200 | lines to show (default: 200) |
--logcat | Android's own log (logcat) instead of the containers' output |
Example:
sf logs 3 -n 50
sf logs 3 --logcatsf gpu#
GPUs and the rendering mode of Androids.
| Command | What it does |
|---|---|
sf gpu ls | list GPUs and the rendering choices on this machine |
sf gpu set | choose how Androids draw (applied at their next restart) |
sf gpu ls#
List GPUs and the rendering choices on this machine.
sf gpu lsExample:
sf gpu lssf gpu set#
Choose how Androids draw (applied at their next restart).
sf gpu set [--node DEVICE] selector {auto,software,igpu,dgpu,intel,amd,nvidia,default}| Argument | Description |
|---|---|
selector | which Androids |
{auto,software,igpu,dgpu,intel,amd,nvidia,default} | default follows the farm's gpu.mode again |
| Option | Default | Description |
|---|---|---|
--node DEVICE | pin one card, e.g. /dev/dri/renderD129 (empty string: unpin) |
Example:
sf gpu set 1-8 igpu
sf gpu set 9 nvidia --node /dev/dri/renderD129sf image#
Android images, one per Android version.
| Command | What it does |
|---|---|
sf image ls | list the image of every configured Android version |
sf image pull | download and prepare the image of one Android version |
sf image build | rebuild an image with its overlays (camera, GPU runtime) |
sf image ls#
List the image of every configured Android version.
sf image lsExample:
sf image lssf image pull#
Download and prepare the image of one Android version.
sf image pull version| Argument | Description |
|---|---|
version | Android version, e.g. 13 |
Example:
sf image pull 13sf image build#
Rebuild an image with its overlays (camera, GPU runtime).
sf image build version| Argument | Description |
|---|---|
version | Android version, e.g. 13 |
Example:
sf image build 13sf tasks#
List background tasks, or show, follow and cancel one.
sf tasks [--active] [--cancel] [id]| Argument | Description |
|---|---|
id | task id, e.g. t12 |
| Option | Default | Description |
|---|---|---|
--active | only tasks still running | |
--cancel | ask the task to stop |
Example:
sf tasks
sf tasks t12 --wait
sf tasks t12 --cancelsf top#
Live load of the host, the GPUs and every running Android.
sf top [--interval SECONDS] [--once]| Option | Default | Description |
|---|---|---|
--interval SECONDS | 3.0 | refresh interval (default: 3) |
--once | print one snapshot and exit |
Example:
sf topsf open#
Print the panel's address and how to log in.
sf openExample:
sf opensf shell#
Run one command on every selected Android and show each one's output. The words after -- are the command, passed as separate arguments (no shell on this machine ever sees them). Obviously destructive commands are refused unless --force.
sf shell [--root] [--timeout SECONDS] [--force] selector| Argument | Description |
|---|---|
selector | which Androids |
| Option | Default | Description |
|---|---|---|
--root | run as root inside the Android | |
--timeout SECONDS | time limit per Android (default: control.shell_timeout) | |
--force | run a command the safety denylist would refuse |
Example:
sf shell all -- getprop ro.build.version.release
sf shell 3 --root -- ls /data/appsf screenshot#
Save a screenshot of one Android.
sf screenshot [-o FILE] id| Argument | Description |
|---|---|
id | Android id |
| Option | Default | Description |
|---|---|---|
-o, --output FILE | where to save (default: android-<id>.png) |
Example:
sf screenshot 3 -o shot.pngsf apps#
The app library: APK / XAPK / APKS / APKM files kept by the farm.
| Command | What it does |
|---|---|
sf apps ls | list the apps in the library |
sf apps add | upload an app file into the library |
sf apps rm | remove an app from the library |
sf apps ls#
List the apps in the library.
sf apps lsExample:
sf apps lssf apps add#
Upload an app file into the library.
sf apps add FILE [FILE ...]| Argument | Description |
|---|---|
FILE | APK, XAPK, APKS or APKM file |
Example:
sf apps add ~/Downloads/shop-4.2.apksf apps rm#
Remove an app from the library.
sf apps rm app_id| Argument | Description |
|---|---|
app_id | app id as shown by sf apps ls |
Example:
sf apps rm com.example.shop-42sf app#
Apps on the Androids: install, launch, stop, clear, compare versions.
| Command | What it does |
|---|---|
sf app install | install an app from the library |
sf app ensure | install an app only where it is missing or older |
sf app uninstall | remove an app |
sf app launch | open an app |
sf app stop | force-stop an app |
sf app clear | erase an app's data (as after a fresh install) |
sf app matrix | which version of which app is installed where |
sf app install#
Install an app from the library.
sf app install [--no-grant] [--downgrade] selector app| Argument | Description |
|---|---|
selector | which Androids |
app | app id from sf apps ls, or a package name (its newest version is used) |
| Option | Default | Description |
|---|---|---|
--no-grant | do not grant the app's runtime permissions | |
--downgrade | allow replacing a newer installed version |
Example:
sf app install 1-10 com.example.shopsf app ensure#
Install an app only where it is missing or older.
sf app ensure [--no-grant] selector app| Argument | Description |
|---|---|
selector | which Androids |
app | app id from sf apps ls, or a package name (its newest version is used) |
| Option | Default | Description |
|---|---|---|
--no-grant | do not grant the app's runtime permissions |
Example:
sf app ensure all com.example.shopsf app uninstall#
Remove an app.
sf app uninstall [--keep-data] selector package| Argument | Description |
|---|---|
selector | which Androids |
package | package name, e.g. com.example.shop |
| Option | Default | Description |
|---|---|---|
--keep-data | keep the app's data and cache |
Example:
sf app uninstall tag:test com.example.shopsf app launch#
Open an app.
sf app launch selector package| Argument | Description |
|---|---|
selector | which Androids |
package | package name, e.g. com.example.shop |
Example:
sf app launch all com.example.shopsf app stop#
Force-stop an app.
sf app stop selector package| Argument | Description |
|---|---|
selector | which Androids |
package | package name, e.g. com.example.shop |
Example:
sf app stop all com.example.shopsf app clear#
Erase an app's data (as after a fresh install).
sf app clear selector package| Argument | Description |
|---|---|
selector | which Androids |
package | package name, e.g. com.example.shop |
Example:
sf app clear 3 com.example.shopsf app matrix#
Which version of which app is installed where.
sf app matrix [selector]| Argument | Description |
|---|---|
selector | which Androids (default: all) |
Example:
sf app matrix runningsf push#
Copy a local file onto Androids.
sf push selector local [remote]| Argument | Description |
|---|---|
selector | which Androids |
local | file on this machine |
remote | folder (ending in /) or full path on the Android (default: /sdcard/Download/) |
Example:
sf push all notes.txt /sdcard/Download/sf pull#
Copy a file from one Android to this machine.
sf pull [-o PATH] id remote| Argument | Description |
|---|---|
id | Android id |
remote | file path on the Android |
| Option | Default | Description |
|---|---|---|
-o, --output PATH | local file or folder (default: the file's name, here) |
Example:
sf pull 3 /sdcard/Download/report.pdfsf gallery#
Add a picture or video to the gallery of Androids.
sf gallery selector local| Argument | Description |
|---|---|
selector | which Androids |
local | picture or video on this machine |
Example:
sf gallery 1-5 photo.jpgsf input#
Send the same touch or key to many Androids at once.
| Command | What it does |
|---|---|
sf input tap | tap a point of the screen |
sf input text | type text into the focused field |
sf input key | press a key |
sf input tap#
Tap one point on every selected Android. Coordinates are fractions of the screen (0.5 0.9 = centre, near the bottom), so one command fits every resolution.
sf input tap [--pixels] selector x y| Argument | Description |
|---|---|
selector | which Androids |
x | 0 (left) to 1 (right) |
y | 0 (top) to 1 (bottom) |
| Option | Default | Description |
|---|---|---|
--pixels | x and y are pixels, not fractions |
Example:
sf input tap 1-10 0.5 0.9sf input text#
Type text into the focused field.
sf input text selector text| Argument | Description |
|---|---|
selector | which Androids |
text | text to type (it appears in this machine's process list; never type secrets this way) |
Example:
sf input text 3 'hello world'sf input key#
Press a key.
sf input key selector key| Argument | Description |
|---|---|
selector | which Androids |
key | key name (HOME, BACK, ENTER, APP_SWITCH, ...) or an Android key code |
Example:
sf input key all HOMEsf window#
Native device windows (scrcpy) on the desktop the daemon runs on.
| Command | What it does |
|---|---|
sf window open | open a window for each selected Android |
sf window grid | open windows tiled to fill the screen |
sf window close | close device windows |
sf window open#
Open a window for each selected Android.
sf window open selector| Argument | Description |
|---|---|
selector | which Androids |
Example:
sf window open 3sf window grid#
Open windows tiled to fill the screen.
sf window grid selector| Argument | Description |
|---|---|
selector | which Androids |
Example:
sf window grid 1-12sf window close#
Close device windows.
sf window close selector| Argument | Description |
|---|---|
selector | which Androids (all closes every window, also of deleted Androids) |
Example:
sf window close allsf vpn#
VPN profiles, logins and tunnel status.
| Command | What it does |
|---|---|
sf vpn profiles | list the imported VPN profiles |
sf vpn import | import OpenVPN (.ovpn) or WireGuard (.conf) profiles |
sf vpn rm | remove a VPN profile |
sf vpn credentials | store the username and password a VPN profile logs in with |
sf vpn status | tunnel state, public address and kill switch of Androids |
sf vpn profiles#
List the imported VPN profiles.
sf vpn profilesExample:
sf vpn profilessf vpn import#
Import OpenVPN (.ovpn) or WireGuard (.conf) profiles.
sf vpn import FILE [FILE ...]| Argument | Description |
|---|---|
FILE |
Example:
sf vpn import ~/vpn/nl-ams.ovpn ~/vpn/de-fra.ovpnsf vpn rm#
Remove a VPN profile.
sf vpn rm name| Argument | Description |
|---|---|
name | profile name as shown by sf vpn profiles |
Example:
sf vpn rm nl-ams.ovpnsf vpn credentials#
Store a VPN login under a name (network.vpn.credentials says which name profiles use; default unless changed). The password is asked for without echo, or read from stdin with --password-stdin; it is never taken from the command line. Stored logins cannot be read back, only replaced or deleted. Without a name: list the names that exist.
sf vpn credentials [--username USERNAME] [--password-stdin] [--delete] [name]| Argument | Description |
|---|---|
name | credentials name, e.g. default |
| Option | Default | Description |
|---|---|---|
--username USERNAME | VPN account name (asked for when omitted) | |
--password-stdin | read the password from stdin (one line) | |
--delete | delete the stored login |
Example:
sf vpn credentials default
printf '%s' "$VPN_PASSWORD" | sf vpn credentials default --username myaccount --password-stdinsf vpn status#
Tunnel state, public address and kill switch of Androids.
sf vpn status [--refresh] [selector]| Argument | Description |
|---|---|
selector | which Androids (default: running) |
| Option | Default | Description |
|---|---|---|
--refresh | ask the public address again from inside each Android's network (a few seconds each) |
Example:
sf vpn status running
sf vpn status 3 --refreshsf gateway#
Shared VPN gateways: one tunnel for many Androids.
| Command | What it does |
|---|---|
sf gateway ls | list gateways and their state |
sf gateway add | define a gateway (or change an existing one) |
sf gateway rm | remove a gateway (asks first) |
sf gateway up | start a gateway and wait for its tunnel |
sf gateway down | stop a gateway |
sf gateway ls#
List gateways and their state.
sf gateway lsExample:
sf gateway lssf gateway add#
Define a gateway (or change an existing one).
sf gateway add --profile PROFILE [--provider {openvpn,wireguard}] [--credentials CREDENTIALS]
[--subnet SUBNET]
name| Argument | Description |
|---|---|
name | gateway name, e.g. eu |
| Option | Default | Description |
|---|---|---|
--profile PROFILE | VPN profile the gateway connects with | |
--provider {openvpn,wireguard} | openvpn | |
--credentials CREDENTIALS | default | credentials name (default: default) |
--subnet SUBNET | private /24 for its Androids (default: next free one from docker.subnet_pool) |
Example:
sf gateway add eu --profile nl-ams.ovpnsf gateway rm#
Remove a gateway (asks first).
sf gateway rm [--force] [-y] name| Argument | Description |
|---|---|
name |
| Option | Default | Description |
|---|---|---|
--force | remove it even while Androids are attached | |
-y, --yes | do not ask for confirmation |
Example:
sf gateway rm eusf gateway up#
Start a gateway and wait for its tunnel.
sf gateway up name| Argument | Description |
|---|---|
name |
Example:
sf gateway up eusf gateway down#
Stop a gateway.
sf gateway down [--force] name| Argument | Description |
|---|---|
name |
| Option | Default | Description |
|---|---|---|
--force | stop it even while Androids are attached |
Example:
sf gateway down eusf camera#
Feed a video or live stream into the camera and microphone of Androids.
| Command | What it does |
|---|---|
sf camera status | show whether the virtual camera is ready, what plays where, and the sources |
sf camera play | play a media file (or the live RTMP ingest) as the camera of Androids |
sf camera stop | stop the camera feed |
sf camera mic | mute, unmute or solo the microphone of Androids |
sf camera status#
Show whether the virtual camera is ready, what plays where, and the sources.
sf camera statusExample:
sf camera statussf camera play#
Play a media file (or the live RTMP ingest) as the camera of Androids.
sf camera play [--sound SOUND] selector source| Argument | Description |
|---|---|
selector | which Androids |
source | a file from the media library (see sf camera status), or rtmp for the live ingest |
| Option | Default | Description |
|---|---|---|
--sound SOUND | source | microphone sound: source (the video's own, default), none, or another library file |
Example:
sf camera play 1-5 intro.mp4
sf camera play 3 rtmp --sound nonesf camera stop#
Stop the camera feed.
sf camera stop [selector]| Argument | Description |
|---|---|
selector | which Androids (default: every Android) |
Example:
sf camera stop 1-5sf camera mic#
Mute, unmute or solo the microphone of Androids.
sf camera mic selector {mute,unmute,solo}| Argument | Description |
|---|---|
selector | which Androids |
{mute,unmute,solo} | solo: unmute these and mute every other |
Example:
sf camera mic 3 solosf listen#
Hear one Android on the speakers of the machine the daemon runs on.
sf listen [ID|off]| Argument | Description |
|---|---|
| `ID | off` |
Example:
sf listen 3
sf listen offsf auto#
Automation. Record a task a few times in the panel, train the recordings into a program (sf auto train), then run it on any selection of Androids (sf auto run). Flows are hand-written YAML scripts run the same way.
| Command | What it does |
|---|---|
sf auto datasets | list datasets (groups of recordings of one task) |
sf auto train | turn a dataset's recordings into one program |
sf auto programs | list trained programs |
sf auto flows | hand-written YAML flows (bare: list them) |
sf auto run | run a program or a flow on Androids |
sf auto runs | list runs, or show one run device by device |
sf auto resolve | let a device that waits for attention continue, skip the step or stop |
sf auto values | values that runs type in: shared, per Android, and pools (bare: list them) |
sf auto schedule | recurring runs (bare: list them) |
sf auto datasets#
List datasets (groups of recordings of one task).
sf auto datasetsExample:
sf auto datasetssf auto train#
Turn a dataset's recordings into one program.
sf auto train dataset| Argument | Description |
|---|---|
dataset | dataset id as shown by sf auto datasets |
Example:
sf auto train open-settingssf auto programs#
List trained programs.
sf auto programsExample:
sf auto programssf auto flows#
Hand-written YAML flows (bare: list them).
| Command | What it does |
|---|---|
sf auto flows ls | list flows, including the shipped examples |
sf auto flows show | print a flow's YAML |
sf auto flows validate | check a YAML file without saving it |
sf auto flows save | save a YAML file as a flow (validated first) |
sf auto flows rm | delete a flow |
sf auto flows ls#
List flows, including the shipped examples.
sf auto flows lsExample:
sf auto flows lssf auto flows show#
Print a flow's YAML.
sf auto flows show name| Argument | Description |
|---|---|
name |
Example:
sf auto flows show examples/open-appsf auto flows validate#
Check a YAML file without saving it.
sf auto flows validate file| Argument | Description |
|---|---|
file | YAML file, or - for stdin |
Example:
sf auto flows validate login.yamlsf auto flows save#
Save a YAML file as a flow (validated first).
sf auto flows save name file| Argument | Description |
|---|---|
name | flow name |
file | YAML file, or - for stdin |
Example:
sf auto flows save login login.yamlsf auto flows rm#
Delete a flow.
sf auto flows rm name| Argument | Description |
|---|---|
name |
Example:
sf auto flows rm loginsf auto run#
Run a trained program or a flow on every selected Android, each on its own. A device that meets a screen no rule covers stops and waits (see sf auto runs <task> and sf auto resolve); the others carry on.
sf auto run [--var NAME=VALUE] [--secret NAME] [--dry-run] {program,flow} name selector| Argument | Description |
|---|---|
{program,flow} | |
name | program or flow name |
selector | which Androids |
| Option | Default | Description |
|---|---|---|
--var NAME=VALUE | a value for this run (repeatable) | |
--secret NAME | a value for this run that is asked for without echo, or read from stdin (repeatable) | |
--dry-run | find every element but do not tap or type |
Example:
sf auto run flow examples/open-app 1-10 --var package=com.android.settings
sf auto run program sign-in tag:eu --var user=demo --secret passwordsf auto runs#
List runs, or show one run device by device.
sf auto runs [--active] [task]| Argument | Description |
|---|---|
task | task id of a run |
| Option | Default | Description |
|---|---|---|
--active | only runs still going |
Example:
sf auto runs
sf auto runs t12sf auto resolve#
Let a device that waits for attention continue, skip the step or stop.
sf auto resolve task id [{resume,skip,abort}]| Argument | Description |
|---|---|
task | task id of the run |
id | Android id |
{resume,skip,abort} | resume: you fixed the screen, carry on (default). skip: skip this step. abort: stop this device |
Example:
sf auto resolve t12 4 resumesf auto values#
Values that runs type in: shared, per Android, and pools (bare: list them).
| Command | What it does |
|---|---|
sf auto values ls | list stored values and pools |
sf auto values set | store a value |
sf auto values rm | remove a value |
sf auto values pool-add | add lines to a pool (each line is handed out once) |
sf auto values pool-rm | delete a pool |
sf auto values ls#
List stored values and pools.
sf auto values ls [--instance ID]| Option | Default | Description |
|---|---|---|
--instance ID | the values of one Android instead of the shared ones |
Example:
sf auto values ls
sf auto values ls --instance 3sf auto values set#
Store a value under a name; flows and programs use it as {name}. Leave the value out to be asked for it without echo (or to pipe it in), so it never appears in the process list or in shell history. Names that look like secrets (password, pin, otp, ...) are refused by the farm: pass those per run with sf auto run --secret.
sf auto values set [--instance ID] name [value]| Argument | Description |
|---|---|
name | |
value | the value; omit to type it hidden or read it from stdin |
| Option | Default | Description |
|---|---|---|
--instance ID | store it for one Android only |
Example:
sf auto values set city Berlin
sf auto values set invite-code (asked for, not shown)sf auto values rm#
Remove a value.
sf auto values rm [--instance ID] name| Argument | Description |
|---|---|
name |
| Option | Default | Description |
|---|---|---|
--instance ID | remove the value of one Android |
Example:
sf auto values rm citysf auto values pool-add#
Add lines to a pool (each line is handed out once).
sf auto values pool-add name file| Argument | Description |
|---|---|
name | pool name |
file | text file with one value per line, or - for stdin |
Example:
sf auto values pool-add codes codes.txtsf auto values pool-rm#
Delete a pool.
sf auto values pool-rm name| Argument | Description |
|---|---|
name |
Example:
sf auto values pool-rm codessf auto schedule#
Recurring runs (bare: list them).
| Command | What it does |
|---|---|
sf auto schedule ls | list schedules |
sf auto schedule add | run a program or flow on a timetable |
sf auto schedule rm | delete a schedule |
sf auto schedule enable | switch a schedule on |
sf auto schedule disable | switch a schedule off without deleting it |
sf auto schedule ls#
List schedules.
sf auto schedule lsExample:
sf auto schedule lssf auto schedule add#
Run a program or flow on a timetable.
sf auto schedule add [--every SECONDS] [--cron LINE] [--var NAME=VALUE] [--dry-run]
name {program,flow} target selector| Argument | Description |
|---|---|
name | a name for the schedule |
{program,flow} | |
target | program or flow name |
selector | which Androids |
| Option | Default | Description |
|---|---|---|
--every SECONDS | run every so many seconds | |
--cron LINE | cron line: minute hour day-of-month month day-of-week | |
--var NAME=VALUE | a value for this run (repeatable) | |
--dry-run | find every element but do not tap or type |
Example:
sf auto schedule add nightly flow examples/open-app all --cron '0 3 * * *' --var package=com.android.settingssf auto schedule rm#
Delete a schedule.
sf auto schedule rm id| Argument | Description |
|---|---|
id |
Example:
sf auto schedule rm s3sf auto schedule enable#
Switch a schedule on.
sf auto schedule enable id| Argument | Description |
|---|---|
id |
Example:
sf auto schedule enable s3sf auto schedule disable#
Switch a schedule off without deleting it.
sf auto schedule disable id| Argument | Description |
|---|---|
id |
Example:
sf auto schedule disable s3sf backup#
Back up and restore Androids and the farm's settings.
| Command | What it does |
|---|---|
sf backup create | back up the data of Androids |
sf backup list | list the backups |
sf backup verify | check a backup against its recorded checksums |
sf backup restore | restore a backup as a new Android, or over an existing one |
sf backup prune | delete old backups, keeping the newest backup.keep of each Android |
sf backup farm | back up the farm itself: settings, Android definitions, automation |
sf backup create#
Back up /data of every selected Android (tar + manifest with checksums). A running Android is stopped for the copy and started again when backup.stop_for_backup is on.
sf backup create selector| Argument | Description |
|---|---|
selector | which Androids |
Example:
sf backup create 1-5sf backup list#
Alias: sf backup ls.
List the backups.
sf backup list [--kind {android,farm,all}]| Option | Default | Description |
|---|---|---|
--kind {android,farm,all} | all | which backups (default: all) |
Example:
sf backup listsf backup verify#
Check a backup against its recorded checksums.
sf backup verify [--deep] archive| Argument | Description |
|---|---|
archive | backup name as shown by sf backup list |
| Option | Default | Description |
|---|---|---|
--deep | also read the whole archive to check it can be unpacked |
Example:
sf backup verify android-3/20250101-040000sf backup restore#
Without --over the backup becomes a NEW Android and nothing existing is touched. With --over ID that Android's data is replaced: it must be stopped, and you are asked first. A farm backup (farm/<time>) merges settings into this farm and never overwrites what exists. One this farm made itself is restored in full; from any other, only what cannot decide what runs on this machine is taken unless you say so with the flags below.
sf backup restore [--over ID] [--keep-network] [-y] [--trust] [--restore-config]
[--restore-secrets]
archive| Argument | Description |
|---|---|
archive | backup name as shown by sf backup list |
| Option | Default | Description |
|---|---|---|
--over ID | replace the data of this existing Android (asks first) | |
--keep-network | restoring as new: keep the network on even though the original Android still exists | |
-y, --yes | do not ask for confirmation | |
--trust | farm backup from elsewhere: keep the Androids exactly as saved (custom image, data volume, boot arguments, autostart) and the schedules. Only for a backup you made yourself: it decides what runs on this machine with full privileges | |
--restore-config | farm backup from elsewhere: also take its config.yaml (never implied by --trust) | |
--restore-secrets | farm backup from elsewhere: also take its VPN profiles, logins and tokens |
Example:
sf backup restore android-3/20250101-040000
sf backup restore android-3/20250101-040000 --over 3
sf backup restore farm/20250101-050000sf backup prune#
Delete old backups, keeping the newest backup.keep of each Android.
sf backup pruneExample:
sf backup prunesf backup farm#
Back up the farm itself: settings, Android definitions, automation.
sf backup farm [--include-secrets]| Option | Default | Description |
|---|---|---|
--include-secrets | also store VPN logins and tokens (the archive is then owner-only; keep it private) |
Example:
sf backup farmsf mcp#
Run the farm's MCP server. Alone, sf mcp speaks MCP over stdin/stdout: this is what a desktop assistant or IDE agent launches (see sf mcp config). With --http it serves Streamable HTTP on this machine only. Actions that change the farm follow ai.policy and wait for your Yes or No (sf approvals). Details: docs/MCP.md.
| Command | What it does |
|---|---|
sf mcp config | print the configuration snippet for an MCP client |
sf mcp tools | list the tools an assistant gets, with their class and what the policy does |
sf mcp config#
Print the mcpServers entry an MCP client needs to start this farm's server, with the absolute paths of this install. It never contains the API token.
sf mcp config [--http] [--port PORT]| Option | Default | Description |
|---|---|---|
--http | the snippet for the HTTP endpoint instead of stdio | |
--port PORT | port of the HTTP endpoint (default: ai.mcp.http_port) |
Example:
sf mcp config
sf mcp config --httpsf mcp tools#
List the tools an assistant gets, with their class and what the policy does.
sf mcp tools [--markdown]| Option | Default | Description |
|---|---|---|
--markdown | print the tool reference as Markdown (docs/MCP.md is built from it) |
Example:
sf mcp tools
sf mcp tools --markdownsf approvals#
An AI assistant that wants to change the farm waits for your Yes or No. Alone, sf approvals lists the requests.
| Command | What it does |
|---|---|
sf approvals ls | list approval requests, newest first |
sf approvals approve | say yes to a request: the action runs |
sf approvals deny | say no to a request: nothing runs and the assistant is told |
sf approvals watch | answer requests in the terminal as they arrive |
sf approvals ls#
List approval requests, newest first.
sf approvals ls [--state {pending,approved,denied,expired}] [-n LIMIT]| Option | Default | Description |
|---|---|---|
--state {pending,approved,denied,expired} | only requests in this state | |
-n, --limit LIMIT | 30 | how many (default: 30) |
Example:
sf approvals ls
sf approvals ls --state pendingsf approvals approve#
Say yes to a request: the action runs.
sf approvals approve [--remember] id| Argument | Description |
|---|---|
id | request id as shown by sf approvals ls |
| Option | Default | Description |
|---|---|---|
--remember | also approve the same tool on the same Androids for the rest of that assistant session (not for destructive actions) |
Example:
sf approvals approve 3f9a1c2esf approvals deny#
Say no to a request: nothing runs and the assistant is told.
sf approvals deny [--reason REASON] id| Argument | Description |
|---|---|
id | request id as shown by sf approvals ls |
| Option | Default | Description |
|---|---|---|
--reason REASON | `` | shown to the assistant |
Example:
sf approvals deny 3f9a1c2e --reason 'not during business hours'sf approvals watch#
Wait for approval requests and ask yes or no for each, until Ctrl-C.
sf approvals watchExample:
sf approvals watchsf ask#
Send one request to the farm's built-in Assistant and print its steps and its answer. Actions that change the farm follow ai.policy: under ask each one is shown and waits for y or n here (or in the panel). The last line is the farm's own record of what ran.
sf ask [--model MODEL] [--keep] request [request ...]| Argument | Description |
|---|---|
request | what you want, in plain words (quote it) |
| Option | Default | Description |
|---|---|---|
--model MODEL | model profile to use (default: ai.default_model) | |
--keep | keep the conversation afterwards (see: sf ai conversations) |
Example:
sf ask "how many Androids are running, and how many can this machine run?"
sf ask --model local "start every Android tagged eu"sf ai#
Model profiles (which model, where), the built-in Assistant, and the AI Pilot, which turns a model operating an app into a program that replays without one. See docs/AI.md.
| Command | What it does |
|---|---|
sf ai chat | talk with the built-in Assistant |
sf ai conversations | list the Assistant's conversations |
sf ai models | model profiles: where a model lives and what it can do |
sf ai pilot | teach the farm a task: a model operates the app, the runs become a program |
sf ai chat#
Talk with the built-in Assistant.
sf ai chat [--model MODEL]| Option | Default | Description |
|---|---|---|
--model MODEL | model profile to use (default: ai.default_model) |
Example:
sf ai chat
sf ai chat --model localsf ai conversations#
List the Assistant's conversations.
sf ai conversationsExample:
sf ai conversationssf ai models#
Model profiles: where a model lives and what it can do.
| Command | What it does |
|---|---|
sf ai models ls | list the configured profiles |
sf ai models test | really test a profile: server, model, a reply, a tool call |
sf ai models add | add or replace a profile |
sf ai models key | store a profile's API key (typed here, kept in secrets, never shown) |
sf ai models rm | remove a profile |
sf ai models ls#
List the configured profiles.
sf ai models lsExample:
sf ai models lssf ai models test#
Really test a profile: server, model, a reply, a tool call.
sf ai models test name| Argument | Description |
|---|---|
name | profile name |
Example:
sf ai models test localsf ai models add#
Add or replace a profile.
sf ai models add --provider {ollama,openai} [--base-url BASE_URL] [--model MODEL]
[--key-name KEY_NAME] [--vision] [--no-tools] [--timeout TIMEOUT] [--default]
name| Argument | Description |
|---|---|
name | profile name: lower-case letters, digits, - and _ |
| Option | Default | Description |
|---|---|---|
--provider {ollama,openai} | wire format: an Ollama server, or any OpenAI-compatible chat-completions API | |
--base-url BASE_URL | server address (default: http://127.0.0.1:11434) | |
--model MODEL | model name on that server (default: the first it lists) | |
--key-name KEY_NAME | NAME of the secret that will hold the API key (then: sf ai models key) | |
--vision | the model reads pictures | |
--no-tools | the model cannot call tools | |
--timeout TIMEOUT | seconds to wait for one answer (default: 120) | |
--default | make this the default profile |
Example:
sf ai models add local --provider ollama --model <name> --default
sf ai models add hosted --provider openai --base-url https://api.example.com --model <name> --key-name hosted-keysf ai models key#
Store a profile's API key (typed here, kept in secrets, never shown).
sf ai models key name| Argument | Description |
|---|---|
name | profile name |
Example:
sf ai models key hostedsf ai models rm#
Remove a profile.
sf ai models rm name| Argument | Description |
|---|---|
name | profile name |
Example:
sf ai models rm hostedsf ai pilot#
With a goal: start a Pilot session on the selected Androids. A model operates the app one action at a time and every action is recorded; a run counts only when the success check really holds. Train the recordings (--train, or sf ai pilot train) into a program that replays with no model: sf auto run program <dataset> <selector>.
With a word: sessions | show <session> | cancel <session> | resolve <session> <android> resume|skip|abort | confirm <session> <android> | train <dataset>.
sf ai pilot [--app PACKAGE] [--success CHECK] [--runs RUNS] [--model MODEL]
[--max-steps MAX_STEPS] [--dataset DATASET] [--value NAME=VALUE] [--ask-value NAME]
[--train] [--steps]
GOAL SELECTOR | WORD ... [GOAL SELECTOR | WORD ... ...]| Argument | Description |
|---|---|
| `GOAL SELECTOR | WORD ...` |
| Option | Default | Description |
|---|---|---|
--app PACKAGE | the app to operate, e.g. com.android.settings | |
--success CHECK | what must be on screen when the goal is reached: text:..., id:..., desc:..., package:... or activity:... (without it a run can only be checked by the model's own evidence) | |
--runs RUNS | 1 | runs per Android (default: 1; three or more give a real consensus) |
--model MODEL | model profile to use (default: ai.default_model) | |
--max-steps MAX_STEPS | actions per run (default: ai.pilot.max_steps) | |
--dataset DATASET | dataset to record into (default: named after the goal) | |
--value NAME=VALUE | a value the Pilot may type by name (kept in memory for this session only) | |
--ask-value NAME | like --value, but the value is asked for here without being shown (use it for secrets) | |
--train | train the dataset when the session ends with verified runs | |
--steps | with show: list every action and the model's reason for it |
Example:
sf ai pilot "open the date and time settings" 1 --app com.android.settings --success "text:Set time automatically" --runs 3 --train
sf ai pilot sessions
sf ai pilot show t12 --steps
sf ai pilot resolve t12 3 resume
sf ai pilot confirm t12 3
sf ai pilot train open-the-date-and-time-settingssf doctor#
Check that this machine can run Androids, with the fix for each problem.
sf doctorExample:
sf doctorsf host#
Prepare and inspect this machine (kernel modules, limits, GPUs).
| Command | What it does |
|---|---|
sf host plan | show every command host setup would run, changing nothing |
sf host apply | carry out host setup (re-runs itself under sudo) |
sf host capacity | estimate how many Androids this machine can run at once |
sf host gpus | list the GPUs found and the rendering modes they allow |
sf host sign-module | sign a self-built kernel module for Secure Boot (virtual camera) |
sf host plan#
Show every command host setup would run, changing nothing.
sf host plan [--boot]| Option | Default | Description |
|---|---|---|
--boot | only what must be redone after every reboot |
Example:
sf host plansf host apply#
Install packages, load kernel modules, raise kernel limits, create runtime folders and install the systemd units. Needs root: started as a normal user it continues under sudo, keeping your farm home. Safe to repeat.
sf host apply [--dry-run] [--boot]| Option | Default | Description |
|---|---|---|
--dry-run | print every command and file, change nothing | |
--boot | only what must be redone after every reboot |
Example:
sf host apply
sf host apply --dry-runsf host capacity#
Estimate how many Androids this machine can run at once.
sf host capacity [--workload {video,light}]| Option | Default | Description |
|---|---|---|
--workload {video,light} | video | video: apps playing video, the heaviest case measured (default). light: mostly idle screens |
Example:
sf host capacitysf host gpus#
List the GPUs found and the rendering modes they allow.
sf host gpusExample:
sf host gpussf host sign-module#
Run scripts/host/sign-module.sh. Without arguments it reports the Secure Boot state and the signing key in use. Arguments after -- go to the script (see its --help); anything but a status report runs under sudo.
sf host sign-moduleExample:
sf host sign-module (status report)
sf host sign-module -- --create-key --enroll v4l2loopbacksf config#
Read and change the farm's settings (config.yaml).
| Command | What it does |
|---|---|
sf config get | print one setting |
sf config set | change one setting (validated before it is saved) |
sf config unset | put one setting back to its default |
sf config show | print all settings in effect |
sf config path | print where config.yaml is |
sf config docs | render the settings reference (docs/CONFIGURATION.md) |
sf config get#
Print one setting.
sf config get key| Argument | Description |
|---|---|
key | dotted key, e.g. network.vpn.selection |
Example:
sf config get android.fpssf config set#
Change one setting (validated before it is saved).
sf config set key value| Argument | Description |
|---|---|
key | dotted key, e.g. android.fps |
value | new value; lists are comma separated |
Example:
sf config set android.fps 25
sf config set network.dns 1.1.1.1,9.9.9.9sf config unset#
Put one setting back to its default.
sf config unset key| Argument | Description |
|---|---|
key | dotted key |
Example:
sf config unset android.fpssf config show#
Print all settings in effect.
sf config show [--changed]| Option | Default | Description |
|---|---|---|
--changed | only what differs from the defaults (the file's content) |
Example:
sf config show --changedsf config path#
Print where config.yaml is.
sf config pathExample:
sf config pathsf config docs#
Render the settings reference (docs/CONFIGURATION.md).
sf config docs [-o FILE] [--check FILE]| Option | Default | Description |
|---|---|---|
-o, --output FILE | write to FILE instead of printing | |
--check FILE | exit 1 when FILE differs from what would be generated (for CI) |
Example:
sf config docs -o docs/CONFIGURATION.md
sf config docs --check docs/CONFIGURATION.mdsf token#
Print the API token the panel and scripts log in with.
sf token [--rotate]| Option | Default | Description |
|---|---|---|
--rotate | replace the token; the old one stops working at once |
Example:
sf token
sf token --rotatesf serve#
Run the daemon in the foreground until Ctrl-C. Androids keep running when it stops.
sf serve [--host HOST] [--port PORT]| Option | Default | Description |
|---|---|---|
--host HOST | listen address (default: server.host, 127.0.0.1) | |
--port PORT | listen port (default: server.port, 7700) |
Example:
sf serve
sf serve --port 7701sf service#
Run the daemon as a systemd user service.
| Command | What it does |
|---|---|
sf service install | write and enable the user service |
sf service start | start the daemon in the background |
sf service stop | stop the daemon (Androids keep running) |
sf service status | show whether the daemon runs |
sf service logs | show the daemon's log |
sf service install#
Write and enable the user service.
sf service installExample:
sf service installsf service start#
Start the daemon in the background.
sf service startExample:
sf service startsf service stop#
Stop the daemon (Androids keep running).
sf service stopExample:
sf service stopsf service status#
Show whether the daemon runs.
sf service statusExample:
sf service statussf service logs#
Show the daemon's log.
sf service logs [-n LINES] [-f]| Option | Default | Description |
|---|---|---|
-n, --lines LINES | 100 | lines to show (default: 100) |
-f, --follow | keep printing new lines |
Example:
sf service logs -fsf version#
Print the version.
sf versionExample:
sf versionsf completion#
Print a shell completion script.
sf completion {bash,zsh}| Argument | Description |
|---|---|
{bash,zsh} |
Example:
sf completion bash > ~/.local/share/bash-completion/completions/sf
sf completion zsh > ~/.zfunc/_sfNext#
- Quickstart shows the common commands in order.
- API reference lists the routes behind the client commands.
- Configuration reference lists every setting that
sf configandsf setaccept. - Troubleshooting covers what to do when a command fails.
This page is docs/CLI.md in the repository.