EmptyOS / docs Sign in

Things

Put a Thing on your computer, clone it, and publish a change.

Things are artifacts that your agent makes for you: files, webpages, or apps. Each page or app gets its own address, like itinerary.yourname.emptyos.com, and starts private. If you have made artifacts in a chat assistant, a Thing is an artifact that you own, on your own computer, and can be edited by any other agent or exported wherever you'd like.

A static Thing serves a file or a site. A service Thing runs an app, which can save to a Database. Every Thing keeps its history in Git, so you can undo its latest change.

$ empty put ./notes.html --as finance
Installed private static Thing finance from 1 file (61 bytes) at /home/exedev/things/finance
On yourname.emptyos.com
View it (owner sign-in): https://finance.yourname.emptyos.com/
Only you can open it until you share it
Share it: `empty share finance --with <email>`
Make it public: `empty expose finance`
See all Things: `empty things`

$ empty clone finance && cd finance
Cloning into 'finance'...
Bound /Users/you/finance to yourname:thing://finance

# edit, then
$ ./verify && git commit -am 'Add monthly view'

$ empty put . --json

When you put a Thing, put installs it as a Git repository at ~/things/<id> on the computer to track changes. clone copies that repository to your machine. You commit in the clone. put . from the clone publishes that commit.

Put (uploading)

put accepts a file, an HTML page, a static directory, or a repository with a Thing manifest. A service needs the manifest. Every file under the selected directory is served. Use a build output such as dist/ rather than a source root. EmptyOS does not scan for secrets.

Choose a descriptive ID when creating a Thing because it becomes the site's or service's permanent hostname. For a Japan trip, use japan-itinerary rather than itinerary or a build directory name:

empty put ./dist --as japan-itinerary --name "Japan Trip Itinerary"

Use --description "Reservations, transport, and daily plans" to add optional text under the Thing's name in Home. Use a few words that add context beyond the name; omit it when it would only repeat the name. Whitespace becomes spaces, the limit is 200 characters, and empty text means no description. For a manifested repository, commit description: in thing.yaml first; the flag checks that value and does not rewrite it. Creation metadata flags do not apply to put . from a bound clone. To change an existing description, use empty thing set-description <id> <text...>.

An agent should honor an ID or URL you specify, otherwise choose a short name that reflects the request and show the resulting link. It need not ask another naming question when the context is clear. Direct imports without --as retain the filename/directory-name default, lowercased. Invalid names or conflicts are reported; an explicit ID is never silently renamed or used to overwrite a Thing.

Clone (local editing)

clone copies the Thing's Git repository to a local checkout bound to one computer and one Thing. Do not copy that checkout elsewhere. Do not edit its emptyos.* Git config keys.

Publish

put . from a clone publishes the commit you made. It requires a clean tree and exactly one commit on top of the live head. The command runs ./verify in the clone before sending the commit. The computer validates the candidate, activates it, and checks the route. On failure, the computer reverts the change and reports the failure.

A private static Thing can become a private service through the same put . workflow. Keep its ID and route, add the service code and manifest fields, and commit the change in the clone. Both the current Thing and candidate must be private with no restricted shares. Publication registers and starts the service, checks its route, and preserves Git history and Databases.

On a cloud-connected computer, sites and services use <thing-id>.<owner-host> over HTTPS. For example, https://yourname.emptyos.com/tracker/scores?q=1 redirects to https://tracker.yourname.emptyos.com/scores?q=1. The Thing runs at / on its own hostname, without the /tracker prefix. Its URL stays the same when shared, made public or private, or converted from a private site to a service. Renaming the display title does not change that address.

While private, the owner needs a live cloud-login session with verified email to enter. A break-glass session permits owner management but requires cloud reauthentication for Thing entry. Standalone computers retain private owner-path hosting. Cloud computers do not fall back to owner-path hosting during an outage. A prepared service can be exposed with empty expose <id> or shared with empty share <id> --with <email>; see Sharing. Import services privately first.

Publishing an existing service requires it to be registered and active. Forward service-to-static publication is unsupported. Undo of a conversion restores static serving at the same hostname; Redo registers and starts the service there again. The usual latest-change and clean-Thing checks apply, and neither action reverts Databases.

empty things and empty thing describe <id> show app admission separately from the service process. A running process does not mean its public or private app is admitted; closed or unavailable admission is shown explicitly.

Both commands print each Thing's URL (url in JSON). Sites and services keep their per-Thing hostname across private, shared and public access. Files keep their owner, shared and public path URLs. Share the link as printed. No URL is shown when the computer's hostnames are unknown.

Deleting a site or service permanently reserves its hostname. A different Thing needs a new ID, such as japan-itinerary-2; Git Undo does not release that reservation. This prevents a new Thing from inheriting the old Thing's browser storage.

Prepare and verify

When you put a file, an HTML page, or a static directory, put adds thing.yaml and an executable ./verify to the new repository. That ./verify checks that thing.yaml and the expected served file exist. It also rejects a served file that is a symlink.

A repository with a Thing manifest needs a clean Git tree and a tracked executable ./verify. When the Thing needs to install declared dependencies, add a tracked executable ./prepare. put does not create ./prepare. Use a repository with a Thing manifest when you need this script.

On put and publish, the computer runs ./prepare first if it exists. ./prepare may install declared dependencies and use the network. Then the computer runs ./verify offline. ./verify exits 0 only when every check passes.

Service limits

Service apps have no outbound network access, so they cannot call external APIs. They also cannot receive external webhooks or use WebSockets. Build applications that work with the files and Databases on your computer. Dependency installation during ./prepare can use the network; the running service cannot.

Thing manifests

A repository becomes a Thing when it has thing.yaml at its root. For a static site, use a manifest like this:

id: finance
name: Finance
type: static
directory: dist

For a service, use a manifest like this:

id: tracker
name: Tracker
type: service
command: npm start
port: 4310
data:
  - ledger

The manifest fields have these requirements:

When you put a repository with a manifest, --as, --name, --project, and --public must match the manifest.

Home icon

Home draws icon.svg, the file next to thing.yaml, on the Thing's tile in place of the neutral app, site, or file glyph. It is an ordinary file, not a manifest field, so adding or redrawing one is a normal committed change that needs no restart. Draw a simple line picture on a 0 0 24 24 viewBox, with strokes in currentColor and no text, images, or scripts. Home keeps only the shape and draws it in its own ink color. A symbolic link or a file over 64 KiB is not drawn; empty things --json reports icon and an iconError that says why. When you share a Thing, its shared-link page shows the same icon if the file is under about 10 KiB, and the kind glyph otherwise. The icon reaches that page the next time the Thing is shared, added, activated, or restarted.