Quickstart
One command to a running, durable, dashboard-observed agent.
Requirements
- Node 24+
- Docker, running (for Postgres and the agent sandbox)
- An
OPENAI_API_KEYor anANTHROPIC_API_KEY— or skip straight to Ollama for $0 total
Create the project
npx evestack create my-agentnpx create-evestack my-agent does the same thing. They are two published names for one
implementation — evestack is the single command (create, status, tour, open,
verify, attach, doctor — see the CLI reference), and create-evestack is
the name npm's create-* convention leads people to. Same code, same prompts, same flags.
It asks four questions, all of them before any work starts, so the install and the image pull are a wait you can walk away from:
- Where — the project directory.
- Model — OpenAI, Anthropic or Ollama, and a key if you have one.
- Tools — Composio's one-click tool sign-in, on by default.
- Bring it up — whether it should start Postgres, create the schema and pull the dashboard for you.
Pass --yes to skip all four and fill in .env.local yourself afterward — the scaffolder
never hangs waiting on input it isn't going to get.
Question 4 decides how much of this page you have to type. Answer yes and the
scaffolder does Bring up the database and See it in the dashboard for you, then offers to
run Run it as well — so there is nothing left to paste, and you can read those sections as a
description of what already happened. Answer no — or run under --yes, or with Docker
not running — and it prints those same four commands when it finishes, which are the ones
below.
Whichever you pick, .env.local gets EVESTACK_PROVIDER and that provider's own key
variable. Both matter: EVESTACK_PROVIDER is what agent/agent.ts branches on, and setting a
model name without it leaves you on the previous provider. See
the provider table if you're switching later by hand.
The provider you pick decides whether long-term memory works. remember and recall need
an embeddings model, and the three providers differ: OpenAI has one on the same key; Ollama has
one but it is a second pull (ollama pull nomic-embed-text); Anthropic has no embeddings
endpoint at all, so on that path memory needs either an OPENAI_API_KEY as well or
EVESTACK_EMBED_PROVIDER=ollama to run embeddings locally. Nothing else is affected — the
agent, its sandbox, durable sessions and the dashboard all work either way, and the first
remember call names the variable that fixes it. Full detail in
long-term memory.
This generates a unique EVESTACK_AUTH_PASSWORD per project. eve fails closed by default, so
there's no shipped default password sitting between a stranger and your agent.
Bring up the database
cd my-agent
docker compose up -d postgres
npm run db:bootstrapNothing creates the workflow schema for you: @workflow/world-postgres runs its migrations
only from its own CLI, and eve never invokes it. Skip this and npm run dev starts against
a database with no tables.
Run it through the script, not as npx --package=@workflow/world-postgres bootstrap. That
CLI loads .env through dotenv and never looks at .env.local — which is the only env file
create-evestack writes — so it silently falls back to
postgres://world:world@localhost:5432/world and dies on ECONNREFUSED. The db:bootstrap
script passes --env-file-if-exists=.env.local explicitly.
Pin @workflow/world-postgres to an exact version. npm's latest is the 4.x line and
eve rejects it outright, but the beta dist-tag is not the fix — upstream moves the World
spec version inside 5.0.0-beta.* with no semver signal, so beta resolving one release
forward is enough to kill a boot. The scaffolded package.json pins 5.0.0-beta.32; leave it
exact if you ever touch that dependency by hand.
Run it
npm run devThe agent boots on the port the scaffolder wrote into .env.local as EVESTACK_AGENT_PORT —
2000 unless that was already taken when you scaffolded. npm run dev passes it to eve dev as
--port, which means there is no auto-increment: eve only scans for a free port when no
port is given at all, so if something else has grabbed that port since, the boot fails with a
plain EADDRINUSE rather than moving. Free the port, or change EVESTACK_AGENT_PORT in
.env.local — and if you do, change the EVESTACK_AGENT_URL default in docker-compose.yml
to match, because the scaffolder wrote that number in at generation time.
Verify it's durable
The whole point is that restarting doesn't lose anything. Prove it to yourself:
curl -X POST http://127.0.0.1:2000/eve/v1/session \
-H 'content-type: application/json' \
-d '{"message":"Remember this exact phrase: quokka-orbit-9."}'Kill the dev server (Ctrl-C), restart it (npm run dev), then send a follow-up using the
continuationToken from the first response. The agent recalls it — durable state survives the
process, because it never lived in the process to begin with.
See it in the dashboard
One command, in the project you just scaffolded:
docker compose --profile dashboard up -dThat is a pull. The generated docker-compose.yml points at
ghcr.io/sammytourani/evestack-dashboard, pinned to the version tested with this template, and
the service is already wired to this project's database and to the .env.local your agent
reads — so there is no repository to clone, no image to build, and no credential to copy across.
That pull resolves a multi-arch manifest — linux/amd64 and linux/arm64, ~230 MB
compressed each — so the same command works on an Apple Silicon laptop and on an x86 server
without you choosing a platform. It unpacks to about 1 GB on disk.
To run an image of your own — a fork, a private registry, a local build under a different name
— set EVESTACK_DASHBOARD_IMAGE in a .env beside the compose file, or export it in your
shell. Nothing else in the generated compose file needs to change.
Open the dashboard — usually http://localhost:4000, but check what the scaffolder printed.
It calls freePort(4000) and takes the first port at or above 4000 that is actually free, so a
second project on the same machine, or anything already holding 4000, moves it. The same is true
of the agent's 2000 and Postgres's 5433. The generated docker-compose.yml and .env.local both
carry the numbers this project actually got.
Sign in with the EVESTACK_AUTH_USER and
EVESTACK_AUTH_PASSWORD generated into .env.local — the scaffolder prints them when it
finishes. Every route is behind that credential: the dashboard starts agent runs, approves
gated shell commands and deletes memories, so it fails closed rather than serving a viewer to
anyone who reaches the port. Scripts can use HTTP Basic instead:
curl -u "$EVESTACK_AUTH_USER:$EVESTACK_AUTH_PASSWORD" localhost:4000/api/fleetEvery session you just created is already there, read straight out of the same Postgres — no ingest step required for the session list itself.
If the container comes up, docker ps shows it unhealthy, and every page answers 503 except
/signin — which renders an error and no sign-in form — the credential did not reach it. The
compose service reads .env.local, so that is the file to check — both halves are required,
and a blank password counts as unset.
To hack on the dashboard rather than run it, install and build from the repository root — not
from packages/dashboard, where workspace:* cannot resolve and @evestack/schedules has no
dist/ for Turbopack to find:
cd evestack
pnpm install
pnpm -r --if-present --filter '@evestack/dashboard^...' run build
EVESTACK_AUTH_USER=evestack EVESTACK_AUTH_PASSWORD=dev \
WORKFLOW_POSTGRES_URL=postgres://evestack:evestack@localhost:5433/evestack \
pnpm --filter @evestack/dashboard dev