| Layer | Directory | Runtime |
|---|---|---|
| UI | ui/ | React + Vite (Bun) |
| API | api/ | Elysia (Bun) — routes requests to workforce |
| Workforce | workforce/<name>/ | Python agents/workflows (timbal.server.http) |
timbal.yaml manifest. The API and UI discover workforce services through env vars (TIMBAL_START_WORKFORCE, etc.) that timbal start wires up automatically.
Local development
For day-to-day work, usetimbal start. It:
- Detects
ui/,api/, and everyworkforce/<name>/with a validtimbal.yaml - Installs dependencies (
bun install,uv sync) - Picks free ports (defaults: UI
3737, API3000, workforce from4455) - Starts all services and multiplexes logs to one terminal
- Exposes interactive commands (
oopen UI,sstatus,rrestart,f/mlog focus/mute,qquit)
Environment variables
timbal start composes a separate environment for each service before spawning it. You do not need --env-file for the standard project layout — these files are auto-loaded when present:
| File | Scope |
|---|---|
<project>/.env | All services (UI, API, every workforce member) |
workforce/<name>/.env | That workforce member only |
--env and --env-file accept an optional scope prefix: ui:, api:, or a workforce member name. Unscoped entries apply globally.
Precedence (low → high)
Later layers win over earlier ones:- Timbal built-ins (
TIMBAL_LOG_FORMAT,TIMBAL_API_KEY, etc. from your CLI profile) - Inherited shell environment (
PORTfrom your shell is ignored so it does not leak into services) - Auto-loaded
<project>/.env, then auto-loadedworkforce/<name>/.env(members only) --env-file(in flag order; scoped files apply only to that service)--env(in flag order; scoped entries apply only to that service)- Runtime wiring that always wins (
PORT,TIMBAL_START_*,TIMBAL_WORKFORCE)
r in the timbal start terminal, or quit and re-run) after changing .env files — changes are read at startup, not hot-reloaded.
.env parsing is intentionally minimal: KEY=VALUE lines, optional export prefix, optional quotes, # comments. No variable expansion, line continuations, or shell escapes. For complex values, set the variable in your shell or use --env.Production
For production you have two paths:Timbal Platform
Managed hosting — connect your git repo, deploy a branch, platform runs UI, API, and workforce for you
Self-hosted
Run UI, API, and workforce on your own infra — you own process lifecycle, ports, env wiring, and logging