Skip to content

Service configuration reference

This page is the field-by-field reference for the VectorStep service’s config.yaml — every top-level key and sub-key, what it does, its valid values, and its default. For the operational how-to (where the file lives, what you need to set to get a working deployment running end to end), see Deployment.

The installer writes ~/.vectorstep/config/vectorstep.yaml, bind-mounted read-only into the container at /etc/vectorstep/config.yaml. pipeline_config_dir, step_library_dir, artifacts.dir, logging.dir, and the SQLite path all resolve inside the container’s /data volume, not a path relative to the process’s own working directory:

server:
host: 0.0.0.0
port: 8000
pipeline_config_dir: /data/pipelines
step_library_dir: /data/steps # reusable step definitions; omit to disable library
database:
url: sqlite+aiosqlite:////data/db/runs.db # four slashes = absolute path
# url: postgresql+asyncpg://vectorstep:vectorstep@postgres:5432/vectorstep # production
notifications:
telegram:
bot_token: ${TELEGRAM_BOT_TOKEN}
chat_id: ${TELEGRAM_CHAT_ID}
executors:
openclaw:
url: ws://127.0.0.1:18789/rpc # OpenClaw Gateway WebSocket URL
gateway:
url: ws://gateway:18780/rpc # VectorStep Gateway WebSocket URL — the compose service name
token: ${VECTORSTEP_GATEWAY_TOKEN} # Bearer token; empty string for local dev
rest_url: http://gateway:18780 # VectorStep Gateway REST base URL (used by Agents UI)
logging:
level: INFO
dir: /data/logs # omit to disable file logging (stdout only)
# creates service.log and access.log (rotating, 10 MB × 5)
artifacts:
dir: /data/artifacts # omit this block entirely to disable artifact storage
retention_days: 7 # artifact directories older than this are removed daily at 02:00
dedup:
enabled: true # omit this block (or set false) to disable dedup entirely
window_seconds: 300 # overridable per-pipeline via trigger.dedup
concurrency:
max_runs: 10 # maximum simultaneous pipeline executions (default: 10).
# POST /webhook returns 429 when at capacity.
# GET /health exposes active_runs / max_concurrent_runs.
auth:
tokens: # named tokens, each carrying a role — see /docs/operations/security/
- name: platform-admin
token: ${VS_TOKEN_PLATFORM_ADMIN}
role: admin
- name: payments-webhook
token: ${VS_TOKEN_PAYMENTS}
role: webhook # POST /webhook only
team: payments # webhook-role only — resolves `team` attribution on every
# run it authenticates. Alertmanager sends its token via
# http_config.authorization.credentials — route different
# teams' alerts to different receivers with different tokens.
# allow_unauthenticated: true # refuses to start with no tokens configured unless this is
# set — only appropriate on a trusted local machine.
security:
allow_shell_checks: false # default: false — a pipeline author gets a shell on this
# host if true (type: shell deterministic checks run
# unsandboxed). See the section below before enabling.
template_sandbox: true # default: true — Jinja2 rendering of pipeline-authored
# content is sandboxed against arbitrary code execution.
observability:
otel:
enabled: false # omit this block (or set false) to disable tracing entirely
exporter: otlp # otlp | console
endpoint: http://localhost:4318/v1/traces
service_name: vectorstep-service
calibration: # omit this block entirely for the defaults shown below
n_min: 20 # marked outcomes required before a bucket is "validated"
bin_width: 0.1 # must evenly divide 1.0
cache_ttl_seconds: 300 # how long the in-process bucket cache is reused before refetching
pricing: # omit this whole block to run fully unpriced
currency: USD # display label only — no FX conversion anywhere
models:
- match: {provider: anthropic, model: "claude-sonnet-4-6"}
input_per_mtok: 3.00 # currency units per 1,000,000 input tokens
output_per_mtok: 15.00
team_budgets:
payments: 500 # currency units per calendar month, UTC — advisory only
live_pricing:
enabled: false # optional — persisted, real cost from OpenRouter's public catalog
refresh_interval_seconds: 3600
allow_cross_provider: false # opt-in — see the pricing section below

${ENV_VAR} placeholders are resolved at startup. Unresolved placeholders become "".

Key Values Default
host bind address 0.0.0.0
port bind port 8000
  • pipeline_config_dir — directory pipeline YAMLs are loaded from.
  • step_library_dir — directory reusable step definitions are loaded from. Omit to disable the step library. See Steps.

A pipeline’s own name: and a library step’s name: become filenames under these directories, so both are restricted to [a-zA-Z0-9][a-zA-Z0-9_-]{0,63} — see Pipeline schema.

  • url — a SQLAlchemy async database URL.
    • SQLite default: sqlite+aiosqlite:////data/db/runs.db (four slashes = an absolute path inside the container’s /data volume) — zero infrastructure.
    • Production: postgresql+asyncpg://user:password@postgres:5432/vectorstep — same code path, dialect swap via config only. See Deployment for the operational detail on making this switch.
  • auto_migrate — run pending Alembic migrations automatically on boot. Default true. Set false to hand migrations to a DBA — startup then fails fast, naming the pending revisions, instead of applying them. See Deployment for the full adoption mechanism.

Per-channel notification config. The example above shows telegram (bot_token, chat_id); see Pipeline notification channels for the full set of supported channels and how pipelines and steps route to them.

  • openclaw.url — OpenClaw Gateway WebSocket URL.
  • gateway.url — VectorStep Gateway WebSocket URL.
  • gateway.token — Bearer token for the Gateway (${VECTORSTEP_GATEWAY_TOKEN}); empty string is fine for local dev.
  • gateway.rest_url — VectorStep Gateway REST base URL, used by the Agents UI.

See Executors for the adapter pattern these keys configure.

  • level — log level, e.g. INFO.
  • dir — directory for log files. Omit to disable file logging (stdout only). When set, creates service.log and access.log (rotating, 10 MB × 5 — uvicorn.access noise is kept out of service.log).
  • dir — directory step artifacts are written to. Omit this block entirely to disable artifact storage.
  • retention_days — artifact directories older than this are removed daily at 02:00. Default: 7.

See Artifact storage for the full artifact model.

  • enabled — true/false. Omit this block (or set false) to disable dedup entirely. Default: true.
  • window_seconds — dedup window in seconds; overridable per-pipeline via trigger.dedup. Default: 300.

See Webhooks for idempotency and deduplication semantics.

  • max_runs — maximum simultaneous pipeline executions. Default: 10. POST /webhook returns 429 when at capacity; GET /health exposes active_runs/max_concurrent_runs.

Full model, route requirements, UI login, and the audit log: Security.

  • tokens — list of {name, token, role, team?} entries. role is one of admin, operator, viewer, webhook. team is valid only on a webhook-role token and resolves the team attribution on every run it authenticates — see Team attribution.
  • allow_unauthenticated — true/false. Default: false. VectorStep refuses to start with no tokens configured unless this is set explicitly. Only appropriate on a trusted local machine.
  • metrics_auth — true/false. Default: false. GET /metrics is unauthenticated by default; set this to require viewer.
  • session_secret — HMAC key for signing UI session cookies. If unset, a random one is generated at startup and every session is invalidated on restart.
  • session_max_age_seconds — UI session lifetime. Default: 28800 (8h).
  • session_max_age_remembered_seconds — UI session lifetime when “Remember me” is checked at login. Default: 2592000 (30d). See Logging in.
  • teams and token are deprecated — still parsed (with a startup warning) if tokens isn’t set. teams maps each {name, token} entry to a webhook-role token with that name as its team; token maps to a single unattributed webhook-role token. If both tokens and a legacy form are present, tokens wins.
  • allow_shell_checks — true/false. Default: false. When false (the default), a pipeline or step-library YAML containing a type: shell deterministic check is rejected at write time (400 on POST/PUT /pipelines, /steps, and their /validate endpoints); a shell check already on disk (e.g. loaded from a file placed directly on the host) logs a startup warning instead of failing to boot, and aborts the run the first time that check would actually execute. Setting this to true restores the pre-containment behaviour exactly — a shell check runs run: through the real shell, inheriting the service process’s full environment and permissions, with no sandboxing. Only enable it if you fully trust everyone who can write pipeline config; prefer a type: webhook check (see Deterministic checks) wherever the thing you’re checking has an HTTP API.
  • template_sandbox — true/false. Default: true. Controls whether Jinja2 rendering of pipeline-authored content (prompt_template, when:, every deterministic check’s expect/url/payload/message, notification templates) runs inside a sandbox that blocks attribute-traversal tricks (e.g. {{ ''.__class__.__mro__[1].__subclasses__() }}) which would otherwise execute arbitrary Python during rendering. Disabling it removes that protection for every template render site in the service — only do so if you understand that this allows arbitrary code execution from pipeline config.
  • otel.enabled — true/false. Omit this block (or set false) to disable tracing entirely. Default: false.
  • otel.exporter — otlp | console.
  • otel.endpoint — OTLP endpoint, e.g. http://localhost:4318/v1/traces.
  • otel.service_name — service name reported to the tracing backend.

See Observability for the full metrics/tracing reference.

Omit this block entirely for the defaults shown below.

  • n_min — marked outcomes required before a bucket is “validated”. Default: 20.
  • bin_width — width of each confidence bucket; must evenly divide 1.0. Default: 0.1.
  • cache_ttl_seconds — how long the in-process calibration bucket cache is reused before refetching. Default: 300.

See Calibration for what these buckets measure and how they’re used.

  • currency — display label only, no FX conversion. Default: USD.
  • models — the rate table: a list of {match: {provider, model}, input_per_mtok, output_per_mtok} entries, resolved by longest-prefix match on the step’s model string, scoped by provider.
  • team_budgets — {team: amount} map, currency units per calendar month (UTC). Advisory only, never blocks a run.
  • live_pricing.enabled — optional, opts a component with no manual match into OpenRouter’s public catalog instead. When the component’s own provider genuinely is openrouter, this is a real, persisted rate for the exact model called — not an approximation. Off by default.
  • live_pricing.allow_cross_provider — a second, separate opt-in: lets a component that ran against a different provider be priced off a similar-sounding OpenRouter listing anyway. This is a genuine estimate (different vendor, possibly different contract terms), which is why it needs its own flag on top of live_pricing.enabled. Off by default.
  • live_pricing.refresh_interval_seconds — how often the OpenRouter catalog is re-fetched. Default: 3600.

Omit this whole block to run fully unpriced (every step’s cost stays NULL, every money surface shows “unpriced”). See Cost accounting for the full pricing model, budget guardrails, and live/approximate pricing semantics.