Get started
From nothing to your first todo in a few minutes
Telos runs as one container plus Postgres. Nothing to clone and nothing to build: save a compose file, make two secrets, start it. After step 4 you have the whole todo app. Steps 5 and 6 are extras you can skip.
Save the compose file
Make an empty directory and save this in it as docker-compose.yml:
name: telos
services:
telos:
image: vantreeseba/telos:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:?generate one with `openssl rand -hex 32`}
DATABASE_URL: postgres://telos:${POSTGRES_PASSWORD:?set a database password}@postgres:5432/telos
# The address you actually reach Telos at. Sign-in links are built from it.
APP_URL: ${APP_URL:-http://localhost:3001}
# How sign-in links are emailed. See "Sign in" below.
SMTP_URL: ${SMTP_URL:-}
SECURE_LOCAL_NET: ${SECURE_LOCAL_NET:-false}
NODE_ENV: production
ports:
- "${PORT:-3001}:3001"
postgres:
image: postgres:17-alpine
restart: unless-stopped
environment:
POSTGRES_USER: telos
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set a database password}
POSTGRES_DB: telos
volumes:
- telos_pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U telos -d telos"]
interval: 5s
timeout: 5s
retries: 10
volumes:
telos_pgdata:
Make the secrets and start it
It refuses to start without both, so generate them into .env beside the compose file:
printf 'BETTER_AUTH_SECRET=%s\nPOSTGRES_PASSWORD=%s\n' \
"$(openssl rand -hex 32)" "$(openssl rand -hex 24)" > .env
docker compose up -d
Migrations run at boot, so there is no setup step. Keep that
.env: BETTER_AUTH_SECRET signs sessions and
POSTGRES_PASSWORD is the database's own.
docker compose pull && docker compose up -d.
Your data lives in the telos_pgdata volume, which survives
docker compose down.
Sign in
Telos has no passwords. Give it one way to sign people in, in
.env, then docker compose up -d again:
- Email:
SMTP_URL=smtp://user:pass@mail.example.com:587, and links are emailed. - An OpenID Connect provider such as heautou: nothing to set. The login page of a new instance has a Set up sign-in tab to paste its setup URL into.
- Just this machine:
SECURE_LOCAL_NET=true, and typing an address signs you in. Never on a reachable instance.
Open http://localhost:3001 and sign in. The first account to sign in is the admin.
Make a project and add todos
New project in the sidebar, then type a todo in a sentence and press Enter. Tick it off when it is done. From there:
- Set what a todo waits on, and it shows as blocked, with its blockers named, until they are done.
- Give todos labels and due dates. A late one is flagged, and the project can sort by due date.
- Press
nto add,/to filter, andCtrl Kto search every project.
The board optional
The same todos as lanes you name yourself, one of which means done. Switch to Board on the project. Dragging a card into the done lane ticks it off, and ticking it moves the card.
Put an agent on a lane optional
AI is off at every level until you turn it on.
Switch it on
- Instance: as the admin, Settings → AI → "AI on this instance".
- Account: Settings → AI. Settings gains the Agents and MCP servers tabs.
- Project: its AI switch, and under it auto-run if you want agents to start on todos by themselves.
Make an agent
Settings → Agents → Start from one of the three starters: a Planner that splits work into todos, a Worker that does it and a Reviewer that rules PASS or FAIL. Type the endpoint's base URL (any OpenAI-compatible one, a local Ollama included) and pick a model from the list it returns.
Give it a lane
On the board, open the lane's menu → Agent…, and set where a passing run and a failing run send the todo. With auto-run off, press Run now on a card to work it once.
Connect your own client optional
With AI on, make an API key in Settings and point any MCP client, Claude
Code for one, at /mcp on your instance. Each key has a switch
per tool, all on until you turn one off.
# Claude Code, for example
claude mcp add --transport http telos http://localhost:3001/mcp \
--header "x-api-key: <your API key>"
Before you put it on a domain
Registration is open: any address that completes a sign-in gets an account. Put Telos behind a reverse proxy with TLS, and read Before you expose it first.
Everything else is in the docs and the README. The image is vantreeseba/telos on Docker Hub.