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

PrerequisiteWhy
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 runningomnislash start runs the whole stack in containers
gitthe scaffold is committed as your first commit
An OpenAI API keyAPI-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:

  1. writes the brain-author-owned tree (config, constitution/, skills/, toolchain, gitignore);
  2. writes .env and a committed .env.example, both generated from the live engine env schema — so they cannot drift from what the engine validates;
  3. git init;
  4. pnpm install — this is what puts the pinned engine into node_modules;
  5. 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;
  6. 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:

  1. Click New chat.

  2. Leave Role on general and leave Model blank — blank means inherit from the role, so you do not need to know a model reference string to start.

  3. 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 --telegram for a new brain, or add a bots entry to omnislash.config.ts and put TELEGRAM_BOT_TOKEN, TELEGRAM_ALLOWED_IDS and TELEGRAM_STATUS_CHAT_ID in .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

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.

Screens from Sixty Seconds Studio, a fictional demo studio, running on the real dashboard.