Getting Started
From an empty directory to a streamed answer from your own agent. Everything below runs on your machine; no server, no deploy, no CI.
You need exactly one secret of your own: an OpenAI API key. Every other credential the engine requires is generated for you.
1. Prerequisites
| Prerequisite | Why |
|---|---|
| Node.js 24+ | the engine and its CLI declare engines.node >= 24 |
| pnpm 10+ | the brain is a pnpm project; corepack enable is enough |
| Docker, daemon running | omnislash start runs the whole stack in containers |
| git | the scaffold is committed as your first commit |
| An OpenAI API key | API-mode agents and memory embeddings both use it |
The engine’s npm packages are published to a private registry (GitHub
Packages), so one-time registry access is also a prerequisite. Ask the engine
maintainer for a GitHub token with the read:packages scope and put it in your
own ~/.npmrc — never in a project file:
printf '%s\n%s\n' \
'@omnislash-ai:registry=https://npm.pkg.github.com' \
'//npm.pkg.github.com/:_authToken=YOUR_TOKEN' >> ~/.npmrc
You do not need a GitHub account on the engine repository, and Docker images
(ghcr.io/omnislash-ai/engine) are public — the token is only for npm.
2. Create the brain
Two entry points. They do the same thing — the first one is what the second one runs:
pnpm dlx @omnislash-ai/cli init my-brain
pnpm create omnislash my-brain
Use the first one today. create-omnislash is a bootstrapper that resolves
your installed @omnislash-ai/cli and spawns omnislash init with your
arguments verbatim; it has to live on the public npm registry for
pnpm create to find it by name, and publishing it there is a maintainer action
that has not happened yet. Until it does, pnpm create omnislash resolves to
nothing. Both commands take the same flags, so omnislash init --help
documents either one.
Non-interactive (CI, or when you already know what you want):
pnpm dlx @omnislash-ai/cli init my-brain --yes --template chat-only
The flags: --template chat-only|scheduled-ops|pipeline-heavy, --name (npm
name, defaults to the directory), --version (engine version to pin, defaults
to the CLI’s own), --telegram (this brain talks on Telegram), --no-example
(skip the starter weather skill), --no-install, --no-git, --force
(scaffold into a non-empty directory), --yes (skip every prompt).
Secrets deliberately have no flag: a key on argv lands in your shell
history and in ps. Their flag twin is the environment variable of the same
name, which the wizard reads (see step 3).
3. Answer the wizard
Two preliminaries come first. Target directory — my-brain above already
answered it, so it is not asked again; run init with no directory at all and
it asks. Brain name — always asked, pre-filled with the directory name, so
enter accepts my-brain (--name answers it up front).
Then two kinds of question.
Shape. First: Use recommended defaults? Say yes and you get the
chat-only template, no Telegram, and the starter weather skill — the smallest
brain that runs on the OpenAI key alone. Say no and it asks for the template
and whether this brain talks on Telegram.
Secrets. Then it asks only for what it does not already have. Anything
already exported in your shell is harvested, so a machine with OPENAI_API_KEY
in its environment is never asked to retype it. Every prompt ends in
(press enter to skip) and is skippable — an unanswered variable simply does
not reach the file, and the summary names it. Answers are masked, except the
two Telegram id fields, which you need to see to catch a typo.
For a brain with no Telegram persona there is exactly one question:
Secrets
Primary LLM provider — required for API-mode agents and embeddings
? OPENAI_API_KEY (press enter to skip) ********
Add --telegram and three more join it — TELEGRAM_BOT_TOKEN,
TELEGRAM_ALLOWED_IDS, TELEGRAM_STATUS_CHAT_ID — because declaring a Telegram
persona is what makes them required. That one bot is the chief’s bot, so it also
sends the engine’s own messages (status, approvals, restart notices). TELEGRAM_ALLOWED_IDS is you, the owner:
your numeric Telegram user id (message @userinfobot to read it). A
@username is refused — someone else can register it later. Your id doubles
as your DM with the bot, which is where approval requests land unless you set
TELEGRAM_HITL_CHAT_ID. With nothing else configured, the bot serves only you
— letting other people or a group use it comes later (see Where to go next).
Nothing else. WEBHOOK_SECRET, CONNECTIONS_TOKEN_ENC_KEY and
CONNECTIONS_STATE_HMAC_KEY are equally required and are generated for you:
32 random bytes each, written into .env and stored nowhere else. There is no
openssl step. Back that file up — regenerating those keys orphans every OAuth
token already encrypted under the old one.
Then init does the work, in order, and each step leaves a valid tree behind if
it fails:
- writes the brain-author-owned tree (config,
constitution/,skills/, toolchain, gitignore); - writes
.envand a committed.env.example, both generated from the live engine env schema — so they cannot drift from what the engine validates; git init;pnpm install— this is what puts the pinned engine intonode_modules;- materializes the engine-owned artifacts (
Dockerfile,.dockerignore, the GitHub workflows,docs/engine/, the engine system skills, the capability policy) by spawning your brain’s own copy of the CLI, so a--version-pinned brain is never stamped by whichever CLI you happened to run; - commits everything as
chore: scaffold my-brain brain.
--no-git skips steps 3 and 6 together — it means “make no git changes at
all”, including in a directory you had already made a repository yourself.
--no-install skips 4, and 5 with it (there is no engine on disk to run);
the summary then names pnpm install && omnislash regen as what finishes the
job.
Its last line is one command:
✔ Scaffolded my-brain into /path/to/my-brain — 21 files
cd my-brain && omnislash start
If you skipped a secret, the line above it names what is still missing. Put it
in .env and carry on.
4. Start it
cd my-brain
omnislash start
In order: it checks Docker, loads your config and .env, enforces the brain
runtime contract (peer shape, .npmrc, config) before anything slow runs,
resolves host ports, generates the compose file, builds your brain image on top
of the public engine base image, and waits for every container to report
healthy.
The first run is the slow one — it pulls the base images and builds your image
from scratch; later runs reuse both layers. The health gate is a brain-tunable
value, not a fixed number: the engine default is 180 seconds, and a heavier
image or slower hardware raises it with startup: { waitTimeoutSec } in
omnislash.config.ts.
When it is up, it prints a connection map — every endpoint that actually came up, then one next step:
Brain-dev environment started
PostgreSQL → postgresql://omnislash:omnislash@localhost:5432/omnislash
Redis → redis://localhost:6379
Prometheus → http://localhost:9090
MCP → http://localhost:3100/mcp
Webhooks → http://localhost:3200/hooks
Bull Board → http://localhost:3000
Pipelines → http://localhost:9080
Restate ingress → http://localhost:8180
Restate UI → http://localhost:9070
Chat → http://localhost:3300/agents/sessions
NocoDB → http://localhost:8080
n8n → http://localhost:5678
Playwright MCP → http://localhost:8931/mcp
Services → postgres, redis, prometheus, …
Compose → /path/to/my-brain/.omnislash/docker-compose.start.yml
→ Open the Chat URL above to talk to your agent
Your ports may differ: a busy port is bumped automatically so two brains can run
side by side. A service that is off gets no row — a brain with no Telegram
persona has no bot container and therefore no Bot health line.
Chat is the row that matters. It is the dashboard’s agent chat, and it is
the one surface where a brand-new brain can talk to its own agent with no
Telegram bot and no external account.
5. Say hello
Open the Chat URL. Then:
-
Click New chat.
-
Leave Role on
generaland leave Model blank — blank means inherit from the role, so you do not need to know a model reference string to start. -
Ask it about the weather:
What’s the weather in London?
The answer streams back token by token. Behind that one sentence: the agent
resolved its role from your constitution/, matched the starter weather skill
by its description, ran the curl command that skill documents, and wrote what
it learned to memory.
That is a working brain. Everything from here is your own content.
6. Two optional next steps
- Talk to it on Telegram — get a bot token from
@BotFather, then re-run init with--telegramfor a new brain, or add abotsentry toomnislash.config.tsand putTELEGRAM_BOT_TOKEN,TELEGRAM_ALLOWED_IDSandTELEGRAM_STATUS_CHAT_IDin.env. - Put it on a server —
omnislash init-server <server-ip>provisions a fresh host from this same brain root; the production runbook sequences it with the secrets manager and the repo settings around it.
When something is wrong
omnislash doctor
Roughly 58 checks in four sections — Machine (can this computer run it), Project (is the brain well-formed), Secrets (do you have the credentials), Infrastructure (is everything reachable). Where a failure has a mechanical remedy the doctor prints the command on its own line under the hint; the rest explain themselves in the hint alone. The remedies the doctor can perform itself run under:
omnislash doctor --fix
Only a fail sets a non-zero exit code. A warning means one part of the
brain cannot run while the rest is fine — a missing CLI harness is the standing
example: claude / codex are needed only by the roles that name them, and the
report lists exactly which roles those are. A fresh brain answers on the OpenAI
key alone, so you can leave that warning alone until you want a CLI harness.
Where to go next
- contract.md — what a brain owes the engine: package shape, the G/R/W path classification, feature layout, database ownership.
- brain-dev-guide.md — registry access, engine upgrades, Dockerfile customization, CI/CD.
- upgrading.md — moving the brain to a new engine release: the command, then the agent task it writes.
- production-runbook.md — server, secrets manager, repo configuration, first deploy.
- operations.md — the deploy/ops reference: env vars, runtime persistence, day-2 operations.
- database.md — your own tables and migrations.
- chat-access.md, memory.md, engagement.md, human-input.md, notifications.md, voice.md — the behaviors you will configure next.
- role-prompts.md, state.md, contexts.md — where an agent’s rules and data go: the role body, its every-turn state, or the feature context that reaches only the turns linked to that feature.
- dashboard.md — the dashboard’s pages, the owner’s questions each answers, and how an agent links the owner to one.
- PHILOSOPHY.md — why the brain is a repo and not a config blob.
Definition of Done
The scaffold ships three scripts and wires all three into a lefthook.yml
pre-commit hook, so your brain has the same gate the engine does from day one:
pnpm type-check # tsc --noEmit
pnpm lint # biome check .
pnpm test # vitest run (unit only)
vitest.config.ts sets passWithNoTests: true on purpose — a brand-new brain
has no tests yet, and a Definition of Done that fails out of the box gets
deleted rather than satisfied. It globs features/**/*.test.ts and
tools/**/*.test.ts.
Integration tests that need Docker (Restate, testcontainers, a real Postgres)
belong in a separate vitest.config.integration.ts behind a separate
test:integration script — keep them out of the pre-commit hook, or the hook
gets disabled and then catches nothing.
Your scaffolded root CLAUDE.md already points a coding agent at the engine
docs that were synced into your repo:
@docs/engine/README.md
Those docs are engine-owned and version-matched: every omnislash upgrade
overwrites them. To take ownership, create a docs/engine.override file and the
engine stops syncing there.