EmptyOS / docs Sign in

CLI reference

Every empty command, from the same table as empty --help. Client 0.1.25, protocol 3.

You invoke every command from the workstation. The client runs each command locally, on the computer over the tunnel, or through a Git workflow across both.

Agents: run empty --skill and read the complete bundled skill before working on a computer. Have delegated workers read it too. Command help does not replace this guidance.

# computers
connect <computer-url> [--as <alias>] [--label <label>] [--no-browser] Connect this client to an EmptyOS computer.
Options: --as <alias> Local shorthand used to select this computer; defaults to the first part of its URL. --label <label> Names this client as the owner sees it: on the approval page, the approved-client list, and every action it runs on the computer. Lead with the agent product, then the machine it runs on, such as codex-mbp or muse-wump-vm; defaults to this machine's hostname. --no-browser Print the approval page URL without opening it in your default browser. Approval requests expire after 15 minutes. Retry the same URL and alias to resume a valid request or finish installing a valid approval saved locally, even after request expiry. The owner compares the full code and SSH-key fingerprint before approving. Approval does not prove local installation or an active session; verify access with `empty --computer <alias> status --json`. After an expired or unknown request following approval, inspect Client access for an unused grant before requesting another approval. For a replacement at the same hostname, inspect `empty computers --json`, remove the intended old profile, and connect again with the same alias for a new approval. Old credentials and pinned trust are preserved; do not delete key directories.
empty connect yourname.emptyos.com empty connect maya-chen.emptyos.com --as maya empty connect jordan.emptyos.com --label jordan-macbook
computers [--json] List configured computers.
computer add <alias> --host <host> [--release-catalog <https-url>] [--json] Add a computer by SSH host.
empty computer add personal --host owner@personal.example
computer use <alias> [--json] Select the default computer.
computer show [--json] Show the selected computer.
computer update [--check | --resume <stage-name>] [--release <signed-release.json> | --catalog <https-url>] [--json] Update Home, Gateway, CLI, Recovery, and system services as one signed EmptyOS release.
empty computer update --check empty computer update empty computer update --resume stage.A1b2C3 empty --computer https://yourname.emptyos.com computer update empty --computer work computer update --release ./emptyos-release.json
computer remove <alias> [--revoke] [--json] Remove a local computer profile.
Options: --revoke First revoke this client on the computer with its own credential, so its SSH key and tunnel token stop working there; then remove the profile. Only this client is affected. The profile is kept when the computer cannot be reached. Without --revoke, removal preserves credential files and pinned trust and does not revoke access on the computer; use --revoke, or the Client access page, when this client should stop having access. For an authorized replacement, reconnect to the same hostname and alias with a new owner approval. The new pairing uses a separate credential directory without overwriting old files.
empty computer remove personal empty computer remove personal --revoke
# things
things [--json] List Things on the selected computer.
empty things empty --computer work things --json
put <path> [--as <id>] [--name <name>] [--description <text>] [--project <project-id>] [--public] [--json] Put local content on the selected computer.

A directory is the deployment boundary: every selected file becomes owner-served content and may become anonymous with --public. Prefer a ready build-output directory over a source repository root.

A manifested repository may run its tracked ./prepare as trusted owner code on the computer before offline verification.

--description <text> adds optional Home text to a generated Thing in its first commit. Use a few words that add context beyond the name; omit it when redundant. Whitespace becomes spaces; the limit is 200 characters. Empty text means no description.

For a manifested repository, --description must match the committed description; it does not rewrite thing.yaml. Metadata flags are only valid for an initial put. To change an existing description, use `thing set-description`.

empty put ./portfolio --as portfolio empty put ./olive.jpg --as olive --public empty put .
clone <id> [directory] [--json] Clone a Thing for local work.
thing describe <id> [--json] Inspect a Thing.
thing logs <id> [--lines <count>] [--json] Read recent service logs.
thing fetch <id> [<path>] [--head] [--range <bytes=start-end>] [--json] Request a Thing path as its owner.

Gateway on the computer answers as it answers your browser after sign-in, so the status, headers, and bytes show what a site, file, or service serves. The result does not show the security headers Recovery adds for browsers.

A private service sees a placeholder owner (emptyos-fetch), not your account, and a GET runs its code. Redirects are not followed.

A text body prints its first 64 KiB. Every complete body reports its size and SHA-256. Use --range to read a later part or to check byte-range support.

empty thing fetch portfolio empty thing fetch portfolio /intro.mp4 --range bytes=0-1023 --json
thing assign <thing-id> <project-id> [--json] Assign a Thing to a Project.

On a Git-backed Thing, a real change commits only `thing.yaml` as one Change; the manifest path must be clean and unrelated edits are preserved but can temporarily block Undo.

A no-op creates no commit. Detached HEADs and interrupted Git operations are refused.

thing unassign <thing-id> [--json] Remove a Thing from its Project.

On a Git-backed Thing, a real change commits only `thing.yaml` as one Change; the manifest path must be clean and unrelated edits are preserved but can temporarily block Undo.

A no-op creates no commit. Detached HEADs and interrupted Git operations are refused.

thing set-description <thing-id> <text...> [--json] Set or remove a Thing's description.

The description is one line of at most 200 characters that Home shows under the Thing's name. Pass "" to remove it.

On a Git-backed Thing, a real change commits only `thing.yaml` as one Change and keeps a running Thing reachable; the manifest path must be clean. A no-op creates no commit.

empty thing set-description kitchen-closed Family meal planning empty thing set-description kitchen-closed ""
thing start <id> [--json] Start a service Thing.
thing stop <id> [--json] Stop a service Thing.
thing restart <id> [--json] Restart a service Thing.
thing remove <id> [--json] Remove a Thing service registration; retire its app origin after its directory is deleted.
thing recover-import <id> [--json] Recover an interrupted Thing import.
thing recover-activation <id> [--json] Recover an interrupted Thing activation.
share <id> --with <email> [--json] Grant restricted access to an eligible static Thing or prepared service.
empty share spending --with alice@example.com
unshare <id> (--with <email> | --all) [--json] Revoke restricted access to a Thing.
shared [--json] List Things shared with your account.
# projects
projects [--json] List Projects.
project create <id> <name...> [--json] Create a Project.
# data
datasets [--json] List registered Databases.
dataset describe <id> [--json] Inspect a Database.
dataset create <id> [--name <display-name>] [--json] Create an empty SQLite Database.

Creates ~/data/<id>/ with owner-managed dataset.yaml and imports/, plus an empty SQLite payload behind the protected runtime boundary. A service receives only declared payloads as EMPTYOS_DATASET_<ID>; EMPTYOS_DATA_DIR names its restricted /data view.

empty dataset create nutrition --name "Nutrition log"
dataset query <id> <sql> [--timeout <seconds>] [--json] Run read-only SQL against a Database.

A bounded non-owner tool opens only this Database, without networking, in sqlite3 safe and read-only modes. A statement that writes, attaches, or touches files fails. Rows from every statement are returned in order; --json prints { id, rows, rowCount }. The default deadline is 120 seconds; --timeout accepts 1 to 600 seconds.

SQL is one quoted argument of at most 16 KB over the workstation transport. Use Database commands or a running Thing for Database access; do not open the guarded payload from the owner shell or copy SQLite files between machines.

empty dataset query nutrition "SELECT date, calories FROM meals ORDER BY date DESC LIMIT 7" empty dataset query nutrition "SELECT count(*) AS meals FROM meals" --json
dataset exec <id> <sql> [--timeout <seconds>] [--json] Run SQL that changes a Database.

Runs under the computer's mutation lock in the same bounded, non-networked, single-Database tool view. Statements execute in order and stop at the first error; wrap several in BEGIN/COMMIT for atomicity. --json prints { id, changes, lastInsertRowid }. The default deadline is 120 seconds; --timeout accepts 1 to 600 seconds.

Database changes are not Changes: nothing is committed to Git and Undo never touches ~/data. SQL is one quoted argument of at most 16 KB over the workstation transport.

empty dataset exec nutrition "CREATE TABLE IF NOT EXISTS meals (id INTEGER PRIMARY KEY, date TEXT, food TEXT, calories INTEGER)" empty dataset exec nutrition "INSERT INTO meals (date, food, calories) VALUES ('2026-09-11', 'oats', 320)" --json
dataset remove <id> [--confirm <id>] [--json] Delete a Database and its directory.

Without --confirm this only previews: the directory, database size, and the Things that declare the Database. With --confirm <id> repeating the id, it deletes ~/data/<id> entirely.

There is no Undo for Databases. Removal is refused while a registered service still declares the Database; remove its declaration and update its registration first.

empty dataset remove scratch empty dataset remove scratch --confirm scratch
# system
status [--json] Show computer health.
changes [--json] List committed changes.
activity [--json] List recent actions on the computer and who ran them.

Every mediated mutation is one record: the command, its source (a paired client by label, Home with the owner, the resident shell, or the system), the agent process when known, the outcome, and the duration.

Actions are not Changes: use `empty changes --json` for committed Git history and Undo. `--json` returns the newest 50 records.

commands [--json] List built-in and local commands.
hooks [--json] List lifecycle hook events.
hook install <event> <path> [--json] Install a hook from a path on the computer.
undo [<change-id>] [--json] Undo the latest saved Thing change.

Without a change ID, undoes the newest change whose action is "undo" with no actionReason in `empty changes --json`; pass that ID to name it explicitly.

Only a clean Thing can be undone. Older and platform changes are history only; Undo offers one step back followed by Redo.

redo [<change-id>] [--json] Redo the last undone Thing change.

Without a change ID, redoes the newest change whose action is "redo" with no actionReason in `empty changes --json`; after Undo, refresh Changes to see it.

A new saved change replaces the prior Undo/Redo choice.

expose <id> [--json] Publish a Thing to anyone on the internet.
unexpose <id> [--json] Make a Thing private.
ssh [-- <command...>] Enter the computer or run a raw command.

Words after -- are passed through unchanged and the computer's shell joins them with spaces and parses them again, exactly like `ssh host command...`. Quotes the local shell already consumed do not survive, so pass a command containing quotes, parentheses, $, *, pipes, or && as one quoted argument.

Prefer transported `empty` commands, including `dataset query` and `dataset exec`, whose arguments travel as structured data and need no remote quoting.

empty ssh empty ssh -- 'cd ~/things/notes && git log --oneline -5'
skill install [--dir <path>] [--json] Install the bundled agent skill into a skills directory.

Copies the emptyos-computer skill that ships with this client to <dir>/emptyos-computer/, replacing an earlier copy. The default directory is ~/.agents/skills.

The client records each install. When a different client version runs, it refreshes every recorded copy that still exists and says so on stderr.

If another skill update is running, automatic refresh retries on a later command. An explicit install waits briefly, then reports a busy error if the other update is still running.

empty skill install empty skill install --dir ~/.claude/skills
--json Show the complete computer overview as JSON.
--skill Print the bundled agent skill.

Read this skill before working on an EmptyOS computer. Pass its requirements to any worker you delegate to.

Prints the complete Markdown from this client package. No skill installation or computer connection is needed. This command runs offline and leaves client state unchanged.

empty --skill
--version Show the client and protocol version.
help [command...] Show command help.