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/pipelinesstep_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 "".
server
Section titled “server”| Key | Values | Default |
|---|---|---|
host |
bind address | 0.0.0.0 |
port |
bind port | 8000 |
pipeline_config_dir / step_library_dir
Section titled “pipeline_config_dir / step_library_dir”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.
database
Section titled “database”url— a SQLAlchemy async database URL.- SQLite default:
sqlite+aiosqlite:////data/db/runs.db(four slashes = an absolute path inside the container’s/datavolume) — 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.
- SQLite default:
auto_migrate— run pending Alembic migrations automatically on boot. Defaulttrue. Setfalseto hand migrations to a DBA — startup then fails fast, naming the pending revisions, instead of applying them. See Deployment for the full adoption mechanism.
notifications
Section titled “notifications”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.
executors
Section titled “executors”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.
logging
Section titled “logging”level— log level, e.g.INFO.dir— directory for log files. Omit to disable file logging (stdout only). When set, createsservice.logandaccess.log(rotating, 10 MB × 5 —uvicorn.accessnoise is kept out ofservice.log).
artifacts
Section titled “artifacts”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 setfalse) to disable dedup entirely. Default:true.window_seconds— dedup window in seconds; overridable per-pipeline viatrigger.dedup. Default:300.
See Webhooks for idempotency and deduplication semantics.
concurrency
Section titled “concurrency”max_runs— maximum simultaneous pipeline executions. Default:10.POST /webhookreturns 429 when at capacity;GET /healthexposesactive_runs/max_concurrent_runs.
Full model, route requirements, UI login, and the audit log: Security.
tokens— list of{name, token, role, team?}entries.roleis one ofadmin,operator,viewer,webhook.teamis valid only on awebhook-role token and resolves theteamattribution on every run it authenticates — see Team attribution.allow_unauthenticated—true/false. Default:false. VectorStep refuses to start with notokensconfigured unless this is set explicitly. Only appropriate on a trusted local machine.metrics_auth—true/false. Default:false.GET /metricsis unauthenticated by default; set this to requireviewer.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.teamsandtokenare deprecated — still parsed (with a startup warning) iftokensisn’t set.teamsmaps each{name, token}entry to awebhook-role token with that name as itsteam;tokenmaps to a single unattributedwebhook-role token. If bothtokensand a legacy form are present,tokenswins.
security
Section titled “security”allow_shell_checks—true/false. Default:false. Whenfalse(the default), a pipeline or step-library YAML containing atype: shelldeterministic check is rejected at write time (400 onPOST/PUT /pipelines,/steps, and their/validateendpoints); ashellcheck 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 totruerestores the pre-containment behaviour exactly — ashellcheck runsrun: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 atype: webhookcheck (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’sexpect/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.
observability
Section titled “observability”otel.enabled—true/false. Omit this block (or setfalse) 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.
calibration
Section titled “calibration”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.
pricing
Section titled “pricing”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 isopenrouter, 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 oflive_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.