attach() or guard() records carries a project id; querying costs, logs, or exports by project is how you split a shared deployment’s bill.
Defining projects
Projects live underprojects: in voicegw.yaml. The key is the project id used everywhere (CLI, API, dashboard, and the project= argument to attach()/guard()).
Projects also accept
routing, branding, replay, and metrics blocks; those aren’t cost-tracking concerns and are covered in the voicegw.yaml reference.
Unknown keys under a project fail config validation (typos are caught at startup, not silently ignored).
Budgets
daily_budget is a dollar cap; budget_action (warn / throttle / block) records what you want to happen once spend crosses it.
To actually stop or reroute a call once a cap is hit, wrap the provider with guard() and pass its own budget="$X/day" argument. That check is a separate mechanism scoped to the guard() call itself; it does not read a project’s daily_budget/budget_action.
Budget tracking (the spend that powers the status badge) requires the storage backend to be on. For attach()/guard(), that means VOICEGW_DB_PATH (local SQLite) or VOICEGW_COLLECTOR_URL + VOICEGW_API_KEY (fleet collector) set as environment variables: attach() does not read cost_tracking.enabled from voicegw.yaml. For the Gateway behind voicegw serve, cost_tracking.enabled: true in voicegw.yaml (or VOICEGW_DB_PATH / VOICEGW_DB_URL) turns storage on instead. Without storage, spend always reads as $0.
Which project a call lands under
Passproject="<id>" to attach() or guard() to tag every record from that session. Omit it and records land under the default project (auto-created on first run, $0 budget). See attach() for the exact resolution order between the argument and the VOICEGW_PROJECT environment variable.
Reading project data
CLI
voicegw projects prints a table: ID, Name, Tags, Budget/day (- if unlimited), Default Stack (- if none). With no projects configured it warns and exits 0.
voicegw project <id> prints a panel with the name, description, tags, default stack, and daily budget, plus a Today: $X.XXXX (N requests) line when the storage backend is enabled. Exits 1 if the id isn’t found.
Both accept --config/-c to point at a non-default voicegw.yaml.
HTTP API and dashboard
voicegw dashboard) shows a per-project spend bar against daily_budget and the budget_action value as a label. Projects can also be created at runtime from the dashboard, the MCP server (voicegw mcp), or POST /v1/projects; runtime-created projects persist in SQLite and merge with YAML on startup (YAML wins on id conflicts).
Tags
Tags are arbitrary strings for filtering. The dashboard picks an accent color from the first tag (substring match, case-insensitive): containsprod → green, contains stag → yellow, contains dev or test → blue, anything else → pink.
See Models for the
provider/model id format and the default_stack bundles.
See Tenant attribution for per-end-user attribution within a project.
See voicegw.yaml reference for the full config file shape.