---
name: emptyos-computer
description: Work with a personal EmptyOS computer through the external `empty` CLI. Use when an agent needs to connect to or inspect a computer; work with Things, Projects, Data, changes, sharing, or hooks; publish verified software; or enter the computer for resident-only work.
---

# EmptyOS Computer

If the local `empty` command is missing, install the official workstation
package `@emptyos/client`. The prerequisites and installation steps are at
https://emptyos.com/docs/start.md; complete that installation before running
the commands below. Connecting to an existing EmptyOS hostname does not
require claiming another computer, changing DNS, or installing a server on
the agent's machine.

Run every `empty` command from the local terminal. The client decides whether
the operation is local, transported over SSH, or a local/remote Git workflow.
Use the live help as the command reference:

```sh
empty --help
empty thing --help
empty <command> --help
```

Use `--json` for stable results and error codes rather than parsing human text.

This skill ships inside the `@emptyos/client` npm package; `empty skill
install [--dir <path>]` copies it into a skills directory. For anything beyond
this bootstrap, read https://emptyos.com/docs/.
Read the installed `SKILL.md` during the current session; installation does
not imply that the running agent has reloaded its skill catalog.

## Start and select a computer

Inspect the selected profile and available profiles first:

```sh
empty computer show --json
empty computers --json
```

If no computer profile exists and the user supplies an EmptyOS computer URL,
connect through EmptyOS rather than asking for an exe.dev account or provider
SSH access:

```sh
empty connect https://<computer-host>
```

Show the user the printed short code, SSH-key fingerprint, and approval URL.
Use `--no-browser` when the agent's machine has no browser, and leave the
command running while the user opens that URL on their own machine.
Wait for them to authenticate with EmptyOS, compare both values, and approve
the request. `connect` derives the local alias from the hostname; `--as
<alias>` chooses the local shorthand used with `--computer`. `--label <label>`
sets this connecting client's persistent display label on the approval and
approved-agent screens and defaults to this machine's hostname. The command
selects the first profile automatically but preserves an existing default, so
use `empty computer use <alias>` when the newly connected computer should
replace that default.

Use `empty --computer <alias> ...` to target a non-default profile. Use
`empty computer add` only when the user intentionally supplies an existing SSH
target; use `empty connect` for an EmptyOS computer URL. Profile removal is
local client state; inspect `empty computer remove --help` before using it.

### Network access in an agent sandbox

Fetching documentation, downloading the client from npm, and commands that
contact the computer need network access, including read-only discovery such
as `empty status --json` and `empty things --json`. Local help,
`empty computer show --json`, and `empty computers --json` do not. When the
agent runtime restricts networking, request the narrowest network access needed
for the command and host through its approval mechanism; reuse an existing
permission when it applies. Task authorization alone does not remove sandbox
restrictions.

If a documentation fetch, download, or connection fails with a DNS or network error, such as
`ENOTFOUND`, `EAI_AGAIN`, or SSH's `Could not resolve hostname`, check the
runtime's network permissions before trying other destinations or profiles.
Request scoped permission or sandbox escalation through that runtime. Once
approved, retry the same documentation URL or package-metadata request, or a
read-only check on an already configured computer, such as
`empty --computer <alias> status --json`. A successful check supports a sandbox
restriction as the cause; continue the authorized task with the permitted
network access. If the check still fails, investigate the hostname and
connection without assuming the sandbox is the cause. If permission is
unavailable or denied, report the blocked action and the stated reason, and
continue any independent work. A denial or cancellation is not approval;
do not substitute another package or repository after a failed official fetch.

A DNS failure does not prove that a computer was retired, that its profile
should be removed, or that its content must be recovered from local files.
Keep the selected computer and its profile unless the task calls for a change.

## Discover the computer

Start broad, then inspect the relevant object:

```sh
empty --json
empty status --json
empty things --json
empty projects --json
empty data --json
empty changes --json
empty commands --json
empty hooks --json
empty shared --json
```

`empty --json` is the compact whole-computer overview. `empty status --json`
reports health. For focused inspection, use `empty thing describe <id> --json`,
`empty thing logs <id> --json`, and `empty data describe <id> --json`.
`empty commands --json` merges built-in commands with owner-authored commands
installed on the selected computer.

## Work with Things

### Put a new Thing

Put workstation content on the selected computer:

```sh
empty put <local-path> [--as <id>] [--name <display-name>] [--project <project-id>]
```

`put` accepts regular files, HTML pages, ready static directories, and clean
manifested Thing repositories. A declared file's browser URL opens a page with
filename, type, size, and explicit Download. Append `?download=1` for an inert
attachment; raw clients without explicit acceptable `text/html`, and range
requests, retain byte responses. For ordinary files and static sites, it
generates the manifest and `./verify`; that check prevents import or later
publication when the expected served file or build output is missing. Every
manifested Thing, static or service, must provide a tracked executable
`./verify` and may provide a tracked executable `./prepare`. Services require a
manifest and are registered stopped. `--project` requires an existing Project
and records membership in the initial commit.

Treat a selected directory as the deployment boundary: inspect every file and
prefer ready build output over a source repository root. EmptyOS does not scan
for secrets. For a manifested import, the computer runs `./prepare` when
present as trusted, unsandboxed owner code that may use the network, then runs
`./verify` offline.

### Clone and publish an existing Thing

```sh
empty clone <id>
cd <id>
# inspect, edit, run ./verify, and commit exactly one change
empty put . --json
```

Treat the clone's Git-local EmptyOS binding as authoritative. Do not copy a
checkout between computers, change its `emptyos.*` Git keys, push directly to
the live branch, or bypass a stale-publish rejection. Fetch and rebase or
squash onto the computer's current head, then publish again. Publication
requires a clean checkout and exactly one verified, non-merge commit above the
current computer head.

### Inspect and control Things

Use `empty thing describe <id> --json` before changing a Thing and
`empty thing logs <id> --json` for bounded service logs. Control services through
`empty thing start|stop|restart <id>` rather than raw process commands. Use
`empty thing assign` and `empty thing unassign` for Project membership. On a
Git-backed Thing, a real membership change commits only `thing.yaml` as one
Change that appears in `empty changes` and can be reverted with `empty undo`
when the Thing is otherwise clean. The manifest path must be clean; unrelated
staged or unstaged edits are preserved but make the Change temporarily
unavailable to Undo. Detached HEADs and interrupted Git operations are
refused, and a no-op creates no commit. Do not edit the membership field by
hand.

If discovery reports an interrupted initial import, run the exact
`empty thing recover-import <id>` remediation. Do not delete its journal,
staging directory, Thing directory, or service unit by hand; recovery
removes only state proved to belong to the recorded import. If discovery
reports an interrupted activation, run the exact
`empty thing recover-activation <id>` remediation. Do not delete its journal,
Thing directory, or service unit by hand; recovery removes only state
proved to belong to the recorded activation.

`empty thing remove <id>` removes a service registration; it does not delete
the Thing directory or associated Data. Do not treat it as content deletion.

### Expose and unexpose Things

Anonymous sharing is static-only. Before `empty expose <id>` or
`empty put ... --public`, inspect every file in the declared document
directory. Static sites and declared single files are eligible only when that
directory is below the repository root; services and repository-root static
Things are refused. Do not bypass a refusal by editing `visibility`.

Use `empty unexpose <id>` as the immediate fail-safe to revoke anonymous
access, including when the Thing has become invalid or otherwise ineligible.

### Share with named accounts

Use `empty share <id> --with <email>` to grant viewer access to an eligible
private static Thing. Give the recipient the printed owner-host link yourself;
EmptyOS sends no mail. When platform signup is open, a recipient without an
account can sign up from that link. The grant creates a viewer identity, not a
computer; any later computer claim follows the ordinary capacity policy.
Services and repository-root static Things are refused. Do not bypass that
boundary by editing `share.yaml`.

Use `empty unshare <id> --with <email>` to revoke one person or
`empty unshare <id> --all` to revoke everyone. Omitting both is an error, and
revocation remains available when the Thing has later become invalid.

When the owner asks to save a link someone shared with them, run
`empty shared add <url>`. `empty shared --json` lists those links and
`empty shared remove <url>` removes one. Saving and removing are committed
changes that appear in Changes and support Undo. The saved link itself grants
nothing; the sharing computer checks access whenever it is opened.

## Work with Projects

Use `empty projects --json` to list Projects and
`empty project create <id> <name...>` to create one. Use
`empty thing assign|unassign` to change a Thing's membership. These commands
create one scoped Git Change for a real edit on a Git-backed Thing; inspect it
with `empty changes` before Undo.
`empty put --project <id>` requires the Project to exist.

Projects organize Things but do not change their routes, visibility, service
identity, lifecycle, or Data associations.

## Work with Data

Use `empty data --json` to list registered Datasets and
`empty data describe <id> --json` to inspect one. Use the live command
inventory for supported Data operations rather than inventing commands or
manifest fields.

Never copy SQLite files between the workstation and computer. Keep canonical
Data on the computer and change it only through a running Thing or an explicit
supported computer command. Data stays outside Thing Git history, publication,
and Undo.

## Review changes and extend the computer

### Status, history, and Undo

Use `empty status --json` for computer health and `empty changes --json` for
committed change records. Before `empty undo <change-id> --json`, inspect the
exact change and confirm its target worktree is clean. Undo creates a new Git
revert commit for one target and never changes Data.

Supported mutations share the computer's mutation lock. If a command returns
`computer-busy`, retry later instead of bypassing the lock through raw SSH or
filesystem edits.

### Commands and hooks

Treat `empty commands --json` as the authoritative inventory of built-in and
owner-authored commands. Treat `empty hooks --json` as the inventory of
supported lifecycle events and installed hooks.

`empty hook install <event> <path>` installs owner code from a path on the
computer into the tracked platform hook directory and commits it. Inspect the
source first. Use `empty ssh` when preparing that computer-side path; do not
teach `put` or `clone` to install platform extensions implicitly.

## Enter the computer

Prefer transported `empty` commands when they cover the operation. Use
`empty ssh` only for work that genuinely needs the resident environment;
arguments after `--` have ordinary remote-shell semantics. Once there, read
`~/EMPTY.md`. The installed computer contract, not this bootstrap, defines
resident paths and capabilities.

## EmptyOS updates

`empty status --json` includes `software`: the last completed whole-computer
release hash, `displayVersion`, and `state` (`current`, `updating`,
`resident-changed`, or `unknown`). This version describes the vendor baseline;
it does not imply that owner-editable files are unmodified. `empty --version`
identifies the desktop client instead. `empty computer update` updates Home,
Gateway, the CLI, agent guidance, Recovery, and EmptyOS system services as one
signed release. The complete version advances only after all components finish.
It does not upgrade the underlying Linux distribution or kernel.

If a command reports that the selected computer lacks a required capability,
inspect the complete update before retrying:

```sh
empty computer update --check --json
empty computer update
```

The second command uses the selected profile's configured HTTPS release
catalog when present, otherwise the official EmptyOS release catalog. Use
`--catalog` only for an operator-selected catalog override, or `--release` for
an immutable local artifact obtained through a trusted channel. Use
`empty --computer <alias> computer update ...` for a non-default profile.

Apply only when the owner requests or approves the update. Checks may retain a
stage without changing installed software; use the result's `nextCommand` to
apply the exact checked release. A new invocation without `--resume` may select
a newer catalog release. The default catalog is
`https://release.emptyos.com/emptyos/v1/catalog.json`. Publisher signatures are
verified against trust already installed on the computer, never against a key
downloaded alongside the release.

Home's update handoff names an owner hostname. Resolve the client alias for
that exact computer and pass `--computer <alias>` on every command; never assume the
default profile matches the browser. Run `empty --computer <alias> computer update`
to install the latest release from the configured or default catalog, even if
it is newer than the version shown in Home. Copying the instructions does not
start an update. Home's `updating` state means unfinished, not proof that a
process is still running; inspect the existing command before recovery and
use its retained transaction rather than fetching a new target.

If apply returns `needs-reconciliation`, continue the retained transaction
rather than starting another update. Read the complete `retainedStage`, resident
candidate location, conflicts, and `nextCommand` from the JSON result. Enter the
computer with `empty ssh`, read the resident candidate's `RECONCILE.md`, and inspect the baseline, local, and incoming
versions of every listed conflict. Edit only the detached `candidate` paths
named by that contract; preserve the user's intent, do not edit `~/emptyos`,
and do not commit or rebase the candidate. Run its complete test suite, then
execute the exact `empty computer update --resume <stage-name>` command from
the result. Resume rejects stale live state, edits outside the declared
conflicts, changed deterministic paths, and validator failures. If a human
encounters this state outside an agent session, tell them to continue the
retained update from an agent instead of attempting a blind overwrite.

If the connection drops, resume the retained complete-update stage; do not
fetch another release or restart the update from scratch. Older computers may
need one operator update to install their protected update configuration. Do
not infer hostnames or replace release trust to bypass that requirement.

Do not use resident-only tooling to fulfill `empty computer update`. A
resident-only update does not update Recovery or services and does not
advance the complete version.
