Atomic Chat's terminal workspace: local conversations, model and engine installation, and an OpenAI-compatible server console. Keyboard shortcuts and mouse controls share the same interface, with an animated turquoise eye and layouts that adapt to the terminal window.
Choose Personal terminal for chat or Server console for API controls and credentials. First run installs
an engine and model before opening the workspace. The executable is still named atc.
This repository continues the terminal work built on
atomic-chat-cli. Build from source with Bun and Node 22:
git clone https://github.com/AtomicBot-ai/eye-cli.git
cd eye-cli
bun install --frozen-lockfile
npm run build:ui
npm run embed:ui
npm run build
node dist/bin.jsUse npm run build:bin to create a standalone executable for the current platform in dist/bin/.
The terminal needs at least 54 columns and 24 rows. Ctrl+Q closes the interface; accepted downloads
and the background server continue. Ctrl+K shows shortcuts.
Atomic Server keeps models on a machine — Linux, Windows or macOS, usually a headless server — and
serves them over an OpenAI-compatible API on http://127.0.0.1:1337/v1. Its command is atc. It
embeds atomic-chat-core as a library and ships as
one binary per platform, with no engine inside: engines are installed on demand, and the core picks the
build for the hardware. The same server has a web admin on 127.0.0.1:1338 and a terminal UI (bare atc)
for people who would rather not type commands. Atomic Server and the Atomic Chat desktop app are separate
products for different audiences: they share the core (and the core's per-user managed-runtime root) and
nothing else. The words used everywhere — server, engine, engine build, model, run, unload — are defined
in docs/concepts.md.
Status. The server, its lifecycle and supervision, the terminal UI (chat, server console, model and engine setup), the API with its keyring, the web admin's dashboard, installers, updates and the release pipeline work. Commands marked stub below parse their flags and print their help, but exit with code 3 (
ATC_NOT_IMPLEMENTED) and name the iteration that brings them; the terminal UI already does what most of them will.docs/commands.mdis generated from the command specs and is the authoritative list.
curl -fsSL https://github.com/AtomicBot-ai/eye-cli/releases/latest/download/install.sh | shOn Windows, in PowerShell: irm https://github.com/AtomicBot-ai/eye-cli/releases/latest/download/install.ps1 | iex.
The installer downloads the release's SHA256SUMS, picks the binary for this machine — the CPU, musl on
Alpine, a baseline build for x64 CPUs without AVX2, arm64 under Rosetta — verifies it (and refuses when it
cannot), puts it in ~/.local/bin/atc (%LOCALAPPDATA%\atc\atc.exe on Windows) and adds that directory to
PATH. ATC_INSTALL_DIR, ATC_VERSION (a tag, e.g. v0.1.0), ATC_NO_PATH=1 and ATC_REPO override the
defaults. The macOS and Windows binaries are signed (Developer ID with notarisation, Authenticode), and every
binary carries a build provenance attestation (gh attestation verify atc-… -R AtomicBot-ai/eye-cli).
On Debian, Ubuntu, Fedora, RHEL-compatible systems and Arch, atc also comes as a package, and the package
manager then updates it with the rest of the system. A package carries the same binary as the release (on
x86-64 the baseline build, so it runs on any x86-64 CPU) and the shell completions. The repository and the
rpm packages are signed with the Atomic Chat packages key in
packaging/atomic-chat.asc, fingerprint
1047 F119 58C6 442D D472 E497 E4C3 D361 FB7F F123.
Debian, Ubuntu (x86-64, arm64):
curl -fsSL https://atc-packages.fsn1.your-objectstorage.com/atomic-chat.gpg | sudo tee /usr/share/keyrings/atomic-chat.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/atomic-chat.gpg] https://atc-packages.fsn1.your-objectstorage.com/deb stable main" \
| sudo tee /etc/apt/sources.list.d/atomic-chat.list
sudo apt update && sudo apt install atcFedora, RHEL, Rocky, Alma (x86-64, aarch64):
sudo curl -fsSL -o /etc/yum.repos.d/atomic-chat.repo https://atc-packages.fsn1.your-objectstorage.com/rpm/atc.repo
sudo dnf install atcArch Linux: yay -S atc-bin, or any other AUR helper.
Updates come with sudo apt upgrade, sudo dnf upgrade or yay -Syu; atc update refuses on a packaged
install and names the command to use. After an upgrade, atc restart (or atc service restart) moves a
running server onto the new binary. sudo apt remove atc, sudo dnf remove atc or sudo pacman -R atc-bin
removes it and leaves the data folder. The repository keeps the last ten releases; older ones are on the
releases page as .deb and .rpm files.
atc # on a terminal: the terminal UI — choose a workspace, install an engine and a model
atc service install # keep the server running: systemd, launchd or a scheduled task; back after a crash
atc status # pid, versions, API endpoint, running models, admin URL (--json for one document)
atc api start # the OpenAI-compatible API; every client needs a key from atc/client-keys.json
atc admin # prints http://127.0.0.1:1338/#token=… and opens a browser
atc update # the next release, checked against SHA256SUMS and the signature (packages: apt/dnf/yay)
atc doctor # versions, data folder, config, ports 1337/1338, PATH, GPU driveratc start / atc stop run the server in the background without a service; atc start --foreground
runs it in place (containers). atc logs [-f] shows the server's own log, rotated by size.
| Group | Command | What it does | Status |
|---|---|---|---|
| Server | atc start / stop / restart |
The server: core, API and web admin in the background; start --foreground runs it in place |
works |
| Server | atc status |
The server, the API endpoint, running models, the admin URL | works (--watch is a stub) |
| Server | atc logs |
Tail of the server log; -f follows it |
works |
| Models & engines | atc run <model> / atc unload <model> |
Start a downloaded model on the active engine; stop it | stub (iteration 2) |
| Models & engines | atc models search|pull|list|rm|info |
The catalog and the model files | stub (pull: iteration 2; the rest: 3) |
| Models & engines | atc engines list|install|status|rm |
Engines (llama.cpp, MLX, TensorRT-LLM) and their builds; installing one prepares what it needs | stub (install: iteration 2; the rest: 4) |
| Models & engines | atc hardware show|refresh |
What the core sees of the GPU and CPU | stub (iteration 4) |
| Access | atc api start|stop|status |
The OpenAI-compatible API on the running server; clients need a key from the keyring | works |
| Access | atc chat |
Send a message to an OpenAI-compatible model | works |
| Access | atc api key show|set|rotate|clear |
The keyring from the command line (the terminal UI manages it today; --api-key adds one) |
stub (iteration 3) |
| Access | atc admin [open|status|token] |
Sign-in link, where the admin listens, token rotation | works |
| Access | atc tui |
The terminal UI, explicitly (what bare atc opens on a terminal) |
works |
| System | atc config get|set|unset|list|path |
atc settings |
works (engine.* keys are a stub) |
| System | atc doctor |
Diagnostic table with hints | works (GPU: NVIDIA only; Docker check skipped) |
| System | atc service install|uninstall|status|start|stop|restart |
The server as an OS service (systemd, launchd, Task Scheduler) | works |
| System | atc update |
Self-update from GitHub Releases: checksum and signature checked, the server restarted onto it; a deb, rpm or AUR install is left to its package manager | works |
| System | atc version, atc completion <shell> |
Versions; bash/zsh/fish/powershell completion | works |
Hidden: atc daemon (the server process itself, which start spawns) and atc host-step exec <request.json> (the privileged helper for managed runtimes).
Bare atc opens the terminal UI only on an interactive terminal; in a pipe, a script, a service unit or
with --json it prints this help and exits 2, as before. Leaving the UI (Ctrl+Q) never stops the server.
Global flags go anywhere on the line: --json, -v/--verbose, -q/--quiet, -y/--yes,
--data-folder <path>, --no-color, -h/--help, --version. With --json a command prints exactly one
JSON document on stdout; an error is {"error":{"code","message","details?","hint?"}} on stderr.
Exit codes: 0 success, 1 runtime error, 2 usage (also bare atc and bare groups such as atc models),
3 not implemented in this build, 130 interrupted.
<data> = <system data>/atomic-chat-cli/data --data-folder or ATC_DATA_FOLDER override it
<data>/atomic-core/ the core: instance.lock, control-token (0600), settings.json, processes.json, logs/
<data>/llamacpp/models/ GGUF models, one folder with model.yml each (both llama.cpp providers)
<data>/<provider>/backends/ engine builds the core installs
<data>/atc/ what only atc owns (owner-only ACL on Windows)
config.json settings (0644, written atomically; unknown keys are kept)
client-keys.json 0600: the API keyring, created when the server starts
setup.json, chats/ 0600: the terminal UI's setup and conversations
run/daemon.json pid, instance_id, state (starting|ready), atc/core versions, control_url, admin_url, started_at
run/admin-token 0600: the admin login token
run/host-steps/ 0700: <step_id>.request.json (0600), <step_id>.result.json, journal.json
logs/daemon.log the server's own log, rotated by size (log.maxSizeMb, log.maxFiles)
logs/daemon.out.log the server process's output from its last start (crashes before the logger)
cache/ catalog and recommendation caches
<system data> is $XDG_DATA_HOME or ~/.local/share on Linux, ~/Library/Application Support on macOS
and %APPDATA% on Windows — the core's own rule, so the core and atc always agree. The desktop app's data
folder is refused: the two products never share models, settings or a lock.
Precedence: command flags > ATC_<SECTION>_<KEY> environment variables > <data>/atc/config.json >
defaults. atc config list shows every key with its value and where it came from.
atc config set api.port 1337 # written to config.json
ATC_API_HOST=0.0.0.0 atc status # api.host from the environment for this run
atc config set models.autoLoad qwen3-8b,gemma-4b
atc config pathKeys are api.*, admin.*, engines.* (engines.default is the engine atc run falls back on),
models.*, managed.*, proxy.*, update.*, telemetry.*, log.* (the table is src/config/schema.ts). Engine parameters
(engine.<provider>.<key>) belong to the core's settings; forwarding them through atc config is a stub.
A config file written by a newer atc is refused with a hint rather than half-read; an older one is
migrated (version 2 dropped the serve.* keys along with the serve command; version 4 dropped
api.requireKey, since every API client needs a key from the keyring).
The server sends anonymous crash and error reports to Atomic Chat's error tracker: the error, the
versions and the platform — never prompts, replies, file paths, keys or personal data (the core scrubs
them before anything leaves). Reports are on by default, and the first atc start or terminal UI says
so once. Turn them off with any of:
atc config set telemetry.enabled false # applies to the running server at onceexport DO_NOT_TRACK=1 # or ATC_TELEMETRY_ENABLED=false, for services and containersatc admin # http://127.0.0.1:1338/#token=<admin token>, opened in a browser
atc admin status # where it listens
atc admin token --rotate # new token; old login links stop workingThe admin listens on loopback only. The token in the URL fragment is exchanged once for an HttpOnly
cookie, so it never reaches a query string or a log. The core's control token never leaves the server: the
page talks to /api/* and the server proxies an allowlist of control routes. From another machine, forward
the port instead of exposing it:
ssh -L 1338:127.0.0.1:1338 user@server--host 0.0.0.0 is refused until the password login lands (iteration 5).
Prerequisites: Bun 1.3.10 (the package manager — bun.lock is committed — and the compiler of the binary)
and Node 22 (the development and test runtime; scripts run as npm run …, like in the core). The core is the
npm package @atomic-chat/core, pinned to an exact version (docs/release.md, "The core pin").
bun install # the pinned core and the admin-ui workspace
npm test # unit + contract projects on Node
npm run build:bin # embeds the admin SPA (or the placeholder) and compiles dist/bin/atc-<triple>
npm run verify # lint, typecheck, format, tests, build, UI, binary, e2e, runtime-compatTo develop against a local core checkout, build it there (npm run build), run bun link in it and
bun link @atomic-chat/core here; package.json and bun.lock stay untouched and bun install --force puts
the pinned version back. node dist/bin.js … runs the CLI from source after npm run build; npm run dev in
packages/admin-ui runs the SPA against a server started with atc admin --no-open.
Note: the core's own CLI defaults its public API to port 6767; atc uses 1337, like the desktop app.
docs/concepts.md— the product's words: server, engine, engine build, model, run, unloadAGENTS.md— working in this repository: map, rules, checklistsdocs/architecture.md— processes, ports and tokens, the data folder, host stepsdocs/roadmap.md— the iterations behind the stubs, and the terminal UI designdocs/commands.md— every command with its help text (generated)docs/testing.md— test layers, helpers, CIdocs/release.md— releasing, installers, self-update, the core pindocs/admin-ui.md— the web admin SPAdocs/decisions/INDEX.md— engineering decisions
Apache-2.0 (LICENSE). The web admin includes files from
Atomic Chat, also Apache-2.0; the attribution is in
NOTICE. The binary bundles third-party packages, listed with their licenses in
THIRD_PARTY_NOTICES.md (npm run notices regenerates it; CI checks it is
current and that every license is on the policy in scripts/licenses.mjs).