Smart Agent Teams

Development setup

The repository layout, the toolchain, and how to install, run and change each part of SAT locally.

SAT is a monorepo: a Python API, a React web app, a TypeScript CLI and runner, and this docs site, with Bun workspaces and Turborepo for the JavaScript side. This page gets you from a fresh clone to every part running, and covers the conventions for branches, commits and generated code. For the shortest path to a running app, see Run SAT locally.

Repository layout

package.json
turbo.json
biome.json
rollout.yaml
firebase.json
firebase-docs.json
start_api_local.py
PathWhat it is
apps/apiFastAPI backend. main.py is the entry point (main:app); api/main_api.py builds the app. The company domain is in company/, models in database/, auth and email in services/, migrations in alembic/. scripts/seed_demo.py creates the demo company; scripts/export_openapi.py writes the OpenAPI schema.
apps/webReact 19 control plane (Vite 8, Tailwind 4, SWR, zustand). Workspace package @sat/web.
apps/cliThe sat CLI, runner and scheduler (Bun, commander). Workspace package @sat/cli.
apps/docsThis site (Next.js, Fumadocs, static export). Workspace package @sat/docs.
libs/api-client@sat/api-client: the typed client, generated types (src/schema.d.ts) from openapi.json, the SSE subscriber, and the shared status vocabulary. Used by the web app, the CLI and the docs.
libs/shared@sat/shared: older shared constants and types. Neither the web app nor the CLI imports it.
scripts/02-local-devbootstrap.sh (bring up everything) and stop.sh.
scripts/03-testingcli-smoke.sh, the end-to-end CLI and runner test against PostgreSQL.
scripts/04-deploymentOne-time infrastructure setup for the hosted Yarlis environments.
tests/e2ePlaywright suite for the web app.
rollout.yamlThe release manifest for the hosted Yarlis environments.

Other folders (apps/sat_console_flutter, apps/api/archived, apps/api/src, most of scripts/01-setup and docs/) are from earlier versions of SAT and are not built, tested or deployed.

Toolchain

ToolVersionUsed for
Bun1.4.0 (packageManager in package.json)JavaScript installs, scripts, the CLI runtime and its tests
Node.js22 or later (engines)Vite, Next.js, Playwright
Python3.12 (.python-version: 3.12.7)The API
uvany recentOptional; creates the API venv faster
PostgreSQL16The API's database. SQLite does not work; see Database.
Dockerany recentOptional; runs PostgreSQL and Redis from docker-compose.db.yml
Turborepo2.10.12Runs build, typecheck and test across workspaces
Biome2.5.11Lint and format for TypeScript, JSON and CSS
TypeScript6.0.3Type checking

Optional, for running real agents: claude (Claude Code) or codex on your PATH, and git.

Install

Authenticate to npm for @yarlisai/ui

The web app depends on @yarlisai/ui, a restricted package. Run npm login with an account that can read the @yarlisai scope, or put a read-only token in ~/.npmrc:

echo "//registry.npmjs.org/:_authToken=<token>" > ~/.npmrc

Install JavaScript dependencies

bun install

Create the API virtual environment

cd apps/api
uv venv -p 3.12 .venv
uv pip install -p .venv/bin/python -r requirements-production.txt
uv pip install -p .venv/bin/python pytest pytest-asyncio   # for the test suite
cd ../..

Without uv: python3.12 -m venv apps/api/.venv && apps/api/.venv/bin/pip install -r apps/api/requirements-production.txt. If .venv/bin/python is a dangling symlink, see Troubleshooting.

Start PostgreSQL

Either a local cluster on a free port:

initdb -D ~/.sat-pg -U sat -A trust
pg_ctl -D ~/.sat-pg -o "-p 5433" -l ~/.sat-pg.log start
createdb -h 127.0.0.1 -p 5433 -U sat sat_main
export DATABASE_URL=postgresql://sat@127.0.0.1:5433/sat_main

Or a throwaway container matching production:

docker run -d --name sat-pg -p 5433:5432 \
  -e POSTGRES_USER=sat -e POSTGRES_PASSWORD=sat -e POSTGRES_DB=sat_main postgres:16
export DATABASE_URL=postgresql://sat:sat@127.0.0.1:5433/sat_main

About docker-compose.db.yml

scripts/02-local-dev/bootstrap.sh starts docker-compose.db.yml, which runs postgres:15-alpine on port 5432 (user sat_admin, database sat_main) plus Redis, Redis Commander and pgAdmin. It also loads scripts/db/*.sql into a new volume. Those SQL files predate Alembic and create tables that do not match the migrations. Prefer an empty PostgreSQL 16 database as above, and let the API create the schema.

Run each part

API (port 8080)

cd apps/api
DATABASE_URL=postgresql://sat@127.0.0.1:5433/sat_main DEBUG=true \
  .venv/bin/uvicorn main:app --reload --port 8080

Or, from the repository root, start_api_local.py applies development defaults (ENVIRONMENT=development, DEBUG=true, ALLOWED_ORIGINS for ports 4200 and 3000, PORT=8080) and leaves any variable you set alone:

DATABASE_URL=postgresql://sat@127.0.0.1:5433/sat_main apps/api/.venv/bin/python start_api_local.py

On first start the API runs every migration. With DEBUG=true, Swagger UI is at http://localhost:8080/docs. Check it with curl localhost:8080/health.

Seed the demo company, NoteFlow (prefix NF), with agents Ada, Linus, Grace, Ken, Maya, Margaret and Toni:

cd apps/api
DATABASE_URL=postgresql://sat@127.0.0.1:5433/sat_main .venv/bin/python scripts/seed_demo.py

The seed script calls the API in-process (it imports the app), so it needs DATABASE_URL but not a running server.

The demo login is demo@example.com / DemoPassword123!. Use it only locally.

The root script bun run dev:api runs uvicorn from your PATH, not from apps/api/.venv. Activate the venv first, or use the commands above.

Web app (port 4200)

bun run dev                     # turbo run dev --filter=@sat/web

Vite proxies /api and /health to SAT_API_URL (default http://localhost:8080). Open http://localhost:4200.

CLI and runner

bun run sat -- --help                          # run from source
bun run sat -- login                           # profile "local" → http://localhost:8080
bun run sat -- company use NoteFlow
bun run sat -- apikey create dev-runner --store
bun run sat -- runner start --simulate         # built-in echo adapter, no model calls
bun run --cwd apps/cli build                   # single binary at apps/cli/dist/sat

--simulate executes runs with the echo adapter, so you can exercise the whole loop without Claude Code or Codex. See sat runner.

Docs site (port 4300)

bun run dev:docs

See Writing docs.

Everything at once

scripts/02-local-dev/bootstrap.sh installs dependencies, starts docker-compose.db.yml, the API (through start_api_local.py) and the web dev server, and writes logs to .local-run/. It kills whatever listens on the API and web ports first. Stop with scripts/02-local-dev/stop.sh. Flags: --skip-deps, --skip-db, --only api|web|db.

Regenerate the API client

The web app, the CLI and the docs are typed against libs/api-client/openapi.json. After any change to an endpoint, a request or response model, or a docstring, regenerate it:

bun run --cwd libs/api-client generate

This runs apps/api/scripts/export_openapi.py with apps/api/.venv/bin/python (so the venv must exist), writes libs/api-client/openapi.json, then runs openapi-typescript to produce libs/api-client/src/schema.d.ts. Commit both files with the API change. Then:

bunx turbo run typecheck        # web, CLI and docs against the new types
bun run --cwd apps/cli docs     # if CLI commands changed: regenerate the CLI reference

The API reference on this site is built from the same openapi.json, so endpoint docs come from FastAPI docstrings and Pydantic models.

Lint and format

bun run lint          # biome check .
bun run lint:fix      # biome check --write .
bunx turbo run typecheck

Biome covers apps/web, apps/cli, apps/docs and libs: 2-space indent, single quotes, semicolons, trailing commas (ES5), 100-column lines. Generated files (schema.d.ts, openapi.json) are excluded. Python code is not linted in CI; follow the style of the surrounding file.

Branches, commits and pull requests

  • Branch from main for every change: feat/<topic>, fix/<topic>, chore/<topic>, docs/<topic>. Do not commit to main directly.
  • Commit messages follow Conventional Commits: type(scope): summary, with types feat, fix, docs, refactor, test, chore, ci, build, and scopes such as api, web, cli, docs, deploy. Examples from history: feat(cli): sat CLI, agent runner and scheduler (apps/cli), fix(api): timezone-safe refresh-token and lockout checks on Postgres.
  • Pull requests run CI and tollgate-conformance. Keep the API client, the CLI reference and the docs in the same pull request as the change that needs them.
  • Merging to main builds the API image. Deploys of the hosted Yarlis environments are separate, through the Yarlis release system. See Architecture.

On this page