Team attribution
To show LLM token spend broken down by owning team/department, every run is
tagged with a team — used for the vectorstep_pipeline_tokens_total metric (see
Observability) and the GET /runs?team= filter.
Team comes from the Bearer token that authenticated the webhook, not from a
field in the payload. A self-reported team in a JSON body is spoofable and
easy to get wrong; tying team to the auth credential makes attribution
authoritative, and “onboarding a team” becomes synonymous with “issuing them a
token” — a natural gate.
Configuration
Section titled “Configuration”team is a field on a webhook-role token under auth.tokens — see
Security for the full token/role model:
auth: tokens: - name: payments-webhook token: ${VECTORSTEP_WEBHOOK_TOKEN_PAYMENTS} role: webhook team: payments - name: platform-webhook token: ${VECTORSTEP_WEBHOOK_TOKEN_PLATFORM} role: webhook team: platformteam is only valid on a webhook-role token — VectorStep refuses to start if
it’s set on admin/operator/viewer. A webhook token with no team stays
valid and attributes its runs to None (unattributed), the same as the legacy
single-token form below.
Generate each team’s token with openssl rand -hex 24 (or any other source of
cryptographically random bytes) — a 48-character hex string. There’s no token
issuance endpoint; this is a plain shared secret, handled the same way as
executors.gateway.token and the Telegram bot_token elsewhere in
config.yaml: either resolved from an environment variable via ${ENV_VAR}
as shown above, or written directly into config.yaml if you’re not using
env vars for secrets. Regenerate it
yourself locally rather than reusing a value that’s appeared anywhere else (a
chat transcript, an issue tracker, etc.), since a real secret should only ever
exist in the one place it’s actually used.
- If
auth.tokensis set, eachwebhook-role entry’s token is checked onPOST /webhook; a recognized token resolves the run’steamfrom that entry’steamfield, an unrecognized or missing token 401s. auth.teamsandauth.tokenare deprecated — VectorStep still parses them (logging a warning naming the replacement) ifauth.tokensisn’t set, mapping eachauth.teamsentry to awebhook-role token with that name as itsteam, andauth.tokento a single unattributedwebhook-role token. If bothauth.tokensand a legacy form are present,auth.tokenswins.- VectorStep will not start with no tokens configured at all unless
auth.allow_unauthenticated: trueis set explicitly — see Security.
Non-webhook runs
Section titled “Non-webhook runs”Non-webhook runs don’t have a caller/token to resolve team from:
- Scheduled (cron) runs declare
team:directly on the pipeline’sschedule:block — trusted because it’s git-controlled config, not external input. - Sub-pipeline calls (
executor: pipeline) inherit the parent run’steamautomatically, the same way they inheritlabels/metadata, and it can be overridden per-call viacontext: {team: "..."}like any other field. - Run now (the pipeline detail page’s manual trigger) is always
unattributed (
team: None), regardless of which token/role is logged in — there’s no per-run team concept in a UI session, unlike a webhook’s Bearer-token attribution. - Rerun (
POST /runs/{run_id}/rerun) is also always unattributed, even when the original run had a real team — rerun reconstructs its context from the original run’s persisted data, but team is not one of the fields it carries forward. This is easy to miss if you’re relying on rerun to reproduce a run faithfully for cost-attribution purposes: the new run’s spend lands in “Unattributed,” not the original team’s bucket.
Team budgets
Section titled “Team budgets”Converting tokens to a dollar figure, and setting an advisory monthly budget
per team, is covered in Cost accounting.
The openclaw executor’s lack of token reporting still applies there too — a
team running mostly openclaw steps will undercount regardless, which is why
every cost aggregate carries an “unpriced steps” annotation rather than
silently showing a possibly-partial total as if it were complete.
Running several teams off one instance
Section titled “Running several teams off one instance”If one platform team runs VectorStep for several other teams, see
Multi-team config ownership for a
GitOps repo layout — per-team CODEOWNERS on pipelines/steps, credential
minting kept centralized to the platform team.