Skip to main content
A Timbal project is three layers: Each workforce member has its own 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, use timbal start. It:
  • Detects ui/, api/, and every workforce/<name>/ with a valid timbal.yaml
  • Installs dependencies (bun install, uv sync)
  • Picks free ports (defaults: UI 3737, API 3000, workforce from 4455)
  • Starts all services and multiplexes logs to one terminal
  • Exposes interactive commands (o open UI, s status, r restart, f/m log focus/mute, q quit)
Override ports or env vars when needed:

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: Missing files are skipped silently. Override or add variables at the CLI:
--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:
  1. Timbal built-ins (TIMBAL_LOG_FORMAT, TIMBAL_API_KEY, etc. from your CLI profile)
  2. Inherited shell environment (PORT from your shell is ignored so it does not leak into services)
  3. Auto-loaded <project>/.env, then auto-loaded workforce/<name>/.env (members only)
  4. --env-file (in flag order; scoped files apply only to that service)
  5. --env (in flag order; scoped entries apply only to that service)
  6. Runtime wiring that always wins (PORT, TIMBAL_START_*, TIMBAL_WORKFORCE)
Restart services (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.
Vite and Bun may also read ui/.env and api/.env from those directories at dev time. Project-root .env is still the usual place for secrets shared across the stack (model API keys, integration tokens).

Syncing with the platform: timbal env pull / push

For projects connected to the Timbal Platform, timbal env keeps the local files above in sync with the project’s variables for one environment (the env tracking your current branch, --rev <branch>, or --default). The CLI detects your current Git branch automatically. Variable types and secret recovery use the environment tracking that branch, including variables shared across all environments. Use --rev or --default only when you want to override the current branch.
What lands where: Secrets vs plain: a # type: secret (or # secret) comment directly above a var marks it as a secret, # type: plain (or # plain) as plain. A var without a comment keeps its current type on the platform; a brand-new var is inferred from its name and value (*_KEY, *_TOKEN, *_PASSWORD, sk-..., user:pass@ URLs → secret). --secret NAME / --plain NAME override everything. The platform fixes a var’s type when it is created — pushing an existing var only updates its value — so change types in the platform UI. Push refuses a file that marks a platform secret as plain unless you pass --plain NAME explicitly. The push plan always lists every var with its resolved type and where that decision came from.
Pulled files contain secrets in plaintext — keep .env files gitignored (timbal create does this). PORT, TIMBAL_PROJECT_SECRET, and TIMBAL_APP_ID are never pushed as project vars.
TIMBAL_APP_ID remains active in each member’s local .env. On POSIX systems, new env files are created with owner-only permissions, and atomic updates preserve existing file permissions. Pull attempts to recover secrets whose values were omitted or returned as placeholders; values that remain unavailable stay commented out so a later push cannot erase them.

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
Validate locally with timbal start before deploying. The same project layout is what the platform builds from your repo.