Run SAT locally
Start the API, database, web app and CLI on your machine, with an optional demo company.
Run the whole control plane on your machine for development or evaluation: PostgreSQL, the FastAPI API on port 8080, the React web app on port 4200, and the sat CLI from source. The demo seed gives you a populated company, NoteFlow, to explore.
Prerequisites
| Tool | Version | Notes |
|---|---|---|
| Python | 3.12 or later | For the API |
| uv | Any recent | Creates the API virtual environment |
| Bun | 1.4 or later | Monorepo tooling, web app and CLI |
| PostgreSQL | 15 or 16, via Docker or a local install | Required; migrations do not run on SQLite. Staging and prod run 16; docker-compose.db.yml runs postgres:15-alpine |
| Docker | Any recent | Only if you use docker-compose.db.yml |
npm account with access to @yarlisai/ui | — | The web app's component library is a restricted package. Run npm login once before bun install |
| Claude Code or Codex | — | Only to execute agent runs with sat runner |
Steps
Clone and install JavaScript dependencies
git clone https://github.com/YarlisAISolutions/smart-agent-teams.git
cd smart-agent-teams
npm login # once; needed for @yarlisai/ui
bun installIf bun install fails with a 404 or 403 for @yarlisai/ui, your npm login is missing or lacks access to the package.
Create the API environment
cd apps/api
uv venv -p 3.12 .venv
uv pip install -p .venv/bin/python -r requirements-production.txt
cd ../..Start PostgreSQL
With Docker:
docker compose -f docker-compose.db.yml up -d postgres redisThis creates database sat_main on localhost:5432 with user sat_admin; the password is in docker-compose.db.yml. Redis is not required to run the API locally: live events use it only when EVENTS_BACKEND=redis, and without it the health snapshot reports Redis as degraded.
With a local PostgreSQL install, create an empty database and note its connection URL. If port 5432 is taken by another project, run PostgreSQL on another port and use that port in DATABASE_URL.
Start the API on port 8080
The simplest way is the local starter at the repository root. Its defaults match docker-compose.db.yml (database, Redis URL, DEBUG=true so /docs is served, and CORS for port 4200), and any variable you set yourself wins:
apps/api/.venv/bin/python start_api_local.pyOr run uvicorn directly with your own database URL:
cd apps/api
export DATABASE_URL='postgresql://<user>:<password>@localhost:5432/sat_main'
.venv/bin/uvicorn main:app --reload --port 8080bun run dev:api
bun run dev:api runs uvicorn main:app --reload --port 8080 in apps/api with whatever uvicorn is on your PATH, and without DATABASE_URL the API falls back to postgresql://sat_user:sat_password@localhost:5432/sat_db, which does not match docker-compose.db.yml. Activate apps/api/.venv and export DATABASE_URL first if you use it.
On startup the API runs the Alembic migrations (alembic upgrade head), so the schema is always current. Check that it is up:
curl -s http://localhost:8080/healthAPI docs are at http://localhost:8080/docs when DEBUG=true. Without JWT_SECRET_KEY, the API signs tokens with a development-only secret; that is fine locally and refused in staging and production.
Seed the demo company (optional)
export DATABASE_URL='postgresql://<user>:<password>@localhost:5432/sat_main'
apps/api/.venv/bin/python apps/api/scripts/seed_demo.pyThe seed signs in as (or registers) demo@example.com with password DemoPassword123! and creates NoteFlow (prefix NF, budget $1,500 a month):
- Agents Ada (CEO), Linus (CTO), Maya (CMO), Grace (Senior Engineer), Ken (Engineer), Margaret (QA Lead) and Toni (Content Writer), plus Iris (Product Designer) waiting in Approvals as a hire request.
- Three goals, two projects ("Web app" and "Marketing site"), 20 tasks, two routines, and two weeks of finished runs with costs.
- Three runs left
running(for Grace, Ken and Maya) so the dashboard has live activity.
Use --email, --password, --name and --company to change the defaults. Each time you run the seed it creates another company, so run it once.
Demo data quirks
The "Web app" project points at https://github.com/acme/noteflow-web, which does not exist, so a runner fails to clone it. The three seeded running runs have no runner; the first runner claim after five minutes marks them failed ("stopped reporting (lease expired)") and sets those agents to error. Both are expected.
Start the web app on port 4200
In another terminal, from the repository root:
bun run devVite serves the app on http://localhost:4200 and proxies /api and /health to http://localhost:8080. To proxy elsewhere, run SAT_API_URL=http://host:port bun run --cwd apps/web dev instead. Sign in as demo@example.com / DemoPassword123!, or select Sign up to start empty.
Use the CLI from source
The local profile points at http://localhost:8080 and is the default.
bun run sat -- login --email demo@example.com # prompts for the password
bun run sat -- company use NoteFlow
bun run sat -- dashboard
bun run sat -- doctorsat doctor checks the profile, API health, your sign-in, the default company, the live event stream, the agent CLIs (claude, codex) and git, and exits with code 1 if any check fails. To get a sat binary instead of bun run sat --, run bun run --cwd apps/cli build and put apps/cli/dist on your PATH.
One command instead
scripts/02-local-dev/bootstrap.sh does the steps above except seeding: it installs dependencies, starts PostgreSQL and Redis from docker-compose.db.yml, starts the API with start_api_local.py, and starts the web app.
scripts/02-local-dev/bootstrap.sh # --skip-deps, --skip-db, --only api|web|db
scripts/02-local-dev/stop.shIt needs Node 20+, npm, Python 3.12+ and a running Docker daemon. Logs go to .local-run/{api,web,db}.log. Ports come from API_PORT, WEB_PORT, POSTGRES_PORT and REDIS_PORT.
bootstrap.sh kills any process already listening on the API and web ports before it starts its own.
Troubleshooting
Check that PostgreSQL is running and that DATABASE_URL points at it. docker compose -f docker-compose.db.yml ps shows the container state. If another PostgreSQL already uses port 5432, run yours on another port and change DATABASE_URL.
The Vite proxy cannot reach the API. Check curl http://localhost:8080/health. If the API runs elsewhere, start the web app with SAT_API_URL=http://host:port bun run --cwd apps/web dev. (The root bun run dev goes through Turborepo, which does not pass SAT_API_URL through.)
Live events come from GET /api/companies/{company_id}/events. Locally they work without Redis. The runner still works without the stream: it polls every 30 seconds.