Embabel Worlds

The embabel command

The appliance as a verb rather than a directory. Everything here was already possible — as cd ~/embabel/worlds && ./worlds.py, ./setup.py --uninstall, docker compose -f docker-compose-worlds.yml ps — which asks you to remember where the product lives and which compose file today’s mode uses.

It is installed onto your PATH by the installer, as a two-line forwarder to the checkout’s own CLI. Updating the checkout updates the command; there is no second copy to drift.

curl -fsSL https://raw.githubusercontent.com/embabel-worlds/appliance/main/install.sh | EMBABEL_MODE=worlds sh

If ~/.local/bin is not on your PATH, the installer says so and gives you the line to add.


Typing embabel on its own prints status and the verbs worth knowing next.

The short version

embabel up            # start it, and finish setup if it has not been set up
embabel status        # what is running, what is still downloading, where to go
embabel doctor        # why it is not working
embabel open          # the console, in your browser
embabel tui           # the terminal client

Reference

embabel up

Start the appliance and complete first-run setup. Safe to run at any time — a running mode is reconciled with the compose file rather than started twice, and a completed setup says so instead of asking again.

Flag
--worldsthe world runtime and its console. The default
--methe personal-assistant door
--freshdelete all data first (asks), then start over

The first run pulls roughly 0.8 GB before handing the terminal back, then continues downloading the rest — the code sandbox, metrics, and structured document conversion — behind you. embabel status says what is still arriving.

embabel status

Splits what is running from what is still on its way, because during the first quarter of an hour “not everything is up” is the normal state and a flat container list cannot tell that apart from broken.

For the Worlds mode it ends with every surface: the console, the API, the MCP endpoint, the graph browser, dashboards.

embabel doctor

Checks the things that have actually gone wrong for somebody, and says what to do about each. It prints the appliance directory first, because that is what it is reporting on.

  • Docker installed, running, and Compose v2 present
  • Docker Model Runner — embeddings run locally and need it
  • whether this directory has been set up
  • whether realm checkouts are linked, and whether that path is one the appliance can actually see (a path outside Docker Desktop’s file sharing mounts empty, with nothing in any log to say why)
  • stray code-sandbox containers left by a JVM that died without its shutdown hook

embabel logs [service]

The appliance’s own log by default; name a compose service for any other.

Flag
-f, --followfollow
--tail Nlines of history, default 200

embabel open [what]

Open a surface in your browser: console (default), graph, dashboards, me.

Point the appliance at the directory your realm checkouts live in — the parent, so adding another realm is a git clone rather than a change to any config.

The path is checked before it is written: one that does not exist, is not readable, is a realm rather than a directory of realms, or is somewhere Docker Desktop does not share, is refused with the reason. What it found is printed.

  Realm checkouts: /Users/you/dev
  4 realms visible: realm-esg, realm-github, realm-legal, realm-stripe

The mount is read-only, by design. You edit on the host — where your editor, your coding agent and your git remote already are — and the appliance only reads. A world then loads one by path instead of by repo:

# config/realms.yml, in the world
- name: esg
  path: /realms/realm-esg

One consequence to know rather than discover: a realm’s declared npm/wasm build runs as part of cloning, so it never fires for a local realm. A declarative realm needs nothing; a realm with a build step must be built on the host first.

embabel realms list

Which realms the appliance can currently see.

embabel upgrade

Pull newer images and recreate the containers. Your data is untouched — this is the opposite of up --fresh.

embabel down

Stop the appliance, keeping everything. embabel up brings it back.

Flag
--wipealso delete all data (asks first)

embabel uninstall

Undo the installation: the appliance’s state, this machine’s configuration — .env, the shared-folder override, the MCP registration whose token died with the volume — and the embabel command itself, taken back off your PATH.

That last one only removes the launcher THIS installation wrote. The TUI ships an embabel too (pip puts it wherever your python is), and install.sh warns when one already comes first on your PATH; uninstall reads the file before deleting it and leaves anything it did not write alone. If another embabel still answers afterwards, it says so — otherwise the next which embabel finds a hit and the uninstall looks like it failed.

It also offers to remove stray code-sandbox containers. They are created by the app through the Docker socket as siblings of the appliance rather than as compose services, so down never sees them. It asks rather than assumes, because an assistant you are running from an IDE owns containers carrying the same label.

Two things it deliberately keeps:

  • Images and the local embedding model. The embedding artifact alone is over a gigabyte, and re-downloading one that has not changed is waste. There is no flag to remove them.
  • Your realm checkouts. They are your repositories.
  • The installation directory. ~/embabel/worlds (or wherever you put it) stays, so ./worlds.py sets up again from it. Delete the directory yourself when you want it gone — this script does not remove the ground it is standing on.

embabel tui

The terminal client, pointed at this appliance. Runs the container, so it is the version that matches your appliance and needs nothing installed.

The TUI also ships a pip console script called embabel, which pip drops into whichever Python is around. On a machine with both, which one you get is decided by PATH order — two commands with one name, from the same people. This subcommand is the resolution: one embabel, with the TUI as a verb under it.

If another embabel comes first on your PATH, the installer says so and names the binary that wins. It does not reorder your PATH for you.

embabel where

Print the appliance directory.


Working on a realm

The loop the CLI exists to make short:

embabel realms link ~/dev        # once

then, from a coding agent connected over MCP:

install_realm_from_path("realm-esg")   # once — by reference, nothing is cloned
… edit the files in ~/dev/realm-esg with your own tools …
realm_validate_path("realm-esg")       # would it load?
realm_refresh()                        # the world re-reads it
kg_query(…)                            # does it answer?

and git push from the checkout, to your own GitHub. Nothing in that requires the appliance to write to your files, which is why the mount is read-only.

realm_brief over MCP explains the realm format and points at the realm-authoring skill that walks through building one.


Platforms

macOSSupported. Docker Desktop with Model Runner enabled (Settings → AI). embabel lands in ~/.local/bin, which is not on PATH by default — the installer says so and names your shell’s profile.
LinuxSupported. Model Runner needs the docker-model-plugin package rather than a Desktop toggle. ~/.local/bin is usually already on PATH. embabel open uses xdg-open; on a headless box it prints the URL and opens nothing, which is the useful behaviour over ssh.
WindowsWSL2 only — see below.

Windows, specifically

Run the installer and embabel inside a WSL2 distribution — Microsoft’s Linux environment for Windows — with Docker Desktop’s WSL integration enabled for it. Docker Desktop already uses WSL2 as its engine by default, so anyone running Docker on Windows almost certainly has it.

This is not Windows support so much as Linux support that Windows users can reach: the installer is a POSIX shell script and the CLI assumes POSIX paths, so neither runs in PowerShell. A native port would mean a PowerShell installer and a CLI that understands Windows paths — a piece of work, not a flag.

Two things that will bite otherwise:

  • Keep the appliance inside the Linux filesystem~/embabel/worlds, not /mnt/c/.... Crossing the Windows/Linux filesystem boundary is dramatically slower, and it costs most where it hurts most: realm checkouts, which a coding agent reads and rewrites in a tight loop. Clone your realms under your WSL home directory too, and point embabel realms link at that.
  • localhost forwards through to Windows, so http://localhost:4343 opens the console in an ordinary Windows browser. embabel open tries wslview for exactly this.

Two things that are macOS-specific by nature rather than by neglect:

  • Docker Desktop’s file sharing. embabel realms link warns when a path is outside the shared list, because such a mount resolves empty with nothing in any log to explain it. Linux has no equivalent restriction, so the check does not run there.
  • The Me app, the menu-bar sensor, is macOS today. The appliance itself runs anywhere Docker does, including a Linux server.

Environment

The CLI reads the same .env as everything else. The variables it cares about:

Variable
EMBABEL_REALMS_DIRthe parent of your realm checkouts, mounted read-only at /realms
EMBABEL_MODEme or worlds, for the installer
EMBABEL_HOMEwhere the installer puts the appliance, default ~/embabel/worlds
EMBABEL_BIN_DIRwhere the installer puts embabel, default ~/.local/bin

Everything else is in .env.example, which is the reference for ports, provider keys, and tuning.

Published from CLI.md in the appliance repository, which is where it is written and where corrections go.