AGENTS.md · git:20260819.0832039 · 2026-08-19 · sha256 f519eda9f334e13a
AGENTS.md git:20260819.0832039B
Immutable. This exact content is served forever at /api/v1/blob/f519eda9f334e13a.
# Operating Shelly as a coding agent This file is for coding agents (Claude Code, Cursor, and similar). It covers installing Shelly without a tty, checking that it is healthy, and the sharp edges that are not obvious from the code. Naming: **Shelly** is the agent framework — identities, thinkers, the mind log, bridges, the dash. **shellm** is one tool inside it: the CLI implementation of Recursive Language Models in bash (`bin/shellm`), plus its run machinery (`shellm-docker`, `shellm-explore`). Use "Shelly" for the system and "shellm" only for that tool. Framework commands are `shelly-*` (`shelly-init`, `shelly-web`, ...; the old `shellm-*` names remain as symlinks) and framework env vars are `SHELLY_*` (legacy `SHELLM_*` spellings still honored). The state home defaults to `~/.shelly`, falling back to `~/.shellm` when only that exists (so pre-rename installs keep their state); explicit `SHELLY_HOME` or `SHELLM_HOME` overrides both. Systemd units are `shelly-*`; a box provisioned before the rename is migrated once with `deploy/migrate-units.sh` (see deploy/DEPLOY.md). What deliberately keeps the `shellm` name: the `/opt/shellm` deploy path, the `shellm` and `shellm-telegram` UNIX users, `~shellm/.shellm`, the per-identity `.shellm/` subdirectory, and the `*.shellm.net` domains. If you take one of those on, or any other structural change to a live box, read `deploy/MIGRATIONS.md` first — it lists the couplings that fail *silently*. Shelly creates a persistent identity whose mind is a loop of LLM calls run by a dispatcher. The identity has a name (default `ada`), and that name becomes a shell command. A local web dashboard shows the mind's trajectory. ## Install without a tty With no tty the installer asks nothing; every answer comes from an environment variable or a default. A key must be in the environment: ```bash export OPENROUTER_API_KEY=sk-or-... # or ANTHROPIC_/OPENAI_/GEMINI_API_KEY curl -fsSL https://raw.githubusercontent.com/laude-institute/shelly/main/install.sh | bash ``` Optional variables: `SHELLY_IDENTITY_NAME`, `SHELLY_IDENTITY_VIBE`, `SHELLY_IDENTITY_FOCUS`, `SHELLY_IDENTITY_USER` (the interview answers), `SHELLM_MODEL` (otherwise picked per provider; a tool var, so no SHELLY_ spelling), `SHELLY_NO_DASH=1`, `SHELLY_NO_THINKERS=1`. The installer never uses sudo. In a container as root it apt-installs its own dependencies. Warning: the installer symlinks tools into `~/.local/bin`. If those names already link into a development checkout, the one-liner repoints them to `<state-home>/app`. Do not run it against a HOME you did not create for it. ## Check the outcome The installer writes `status.json` in the state home (`~/.shelly`, or `~/.shellm` on pre-rename installs) at the end of every run: ```bash jq -r '.identity, .mind.status, .dash.status, .dash.url' ~/.shelly/status.json ``` `mind.status` and `dash.status` are `ok`, `failed`, or `skipped`. The file is a snapshot of that run; the live source of truth is the pid files it names (`.mind.pid_file`, `.dash.pid_file`). `<name> status` prints the same picture for humans. `dash.url` works from wherever Shelly is installed. When `container` is true, the URL is container-internal: from the host, use localhost with whatever host port was published (`docker run -p <host>:8080`). The container cannot know that number. ## Talk to the identity ```bash ada hello # bare words are a message; waits for the reply ada say "longer message" # same, explicit ada status # mind and dash state ada stop / ada start # pause and resume the mind ada dash # print or open the dashboard URL ada shell # a shell inside the identity's environment ``` If the name collides with an existing command, the installer refuses to stomp it and everything is reachable as `persona <name> ...` instead. Replies take 15 to 45 seconds while the monolith thinker wakes. ## Where things live - `~/.shelly/` — state root (`SHELLY_HOME`, legacy `SHELLM_HOME`; pre-rename installs use `~/.shellm`): `.env` (key + model), `status.json`, `logs/` (`init.log`, `web.log`), `run/web.pid`, `app_dir` (path to the checkout). - `~/.shelly/app/` — the checkout, when installed by the one-liner. - `<app>/.identities/<name>/` — the identity: persona, memories, trajectory, `run/dispatcher.pid`, and its `activate` script. ## Sharp edges - Any script that sources an identity's `activate` must first load `<app>/.env` and then the state home's `.env` (see `_load_env` in `bin/persona`). Sourcing `activate` bare makes the think model fall back to an expensive default with no key. - `chat send` dies without a sender name. It comes from the identity's own chatrc (`<identity>/chat/.chatrc`, seeded by the installer), not from a `.chatrc` in the current directory. - The installer is idempotent: re-running keeps the key and identity, skips the interview, restarts the mind and dashboard, and never blocks on a prompt once a key has worked, so unattended re-runs (a restarted container) are safe. - The dashboard binds localhost by default and `0.0.0.0` in a container. A failed dashboard does not fail the install; check `dash.status` in `status.json` and `<state-home>/logs/web.log`.