Configuration
Bellwether uses a config-first approach where all settings are defined in bellwether.yaml.
Getting Started
Create a configuration file with bellwether init:
bellwether init # Default check mode (free, fast)
bellwether init --preset ci # CI-oriented defaults (failOnDrift enabled)
bellwether init --preset security # Enables check.security + uses anthropic provider
bellwether init --preset thorough # Currently same generated preset values as security
bellwether init --preset local # Explore mode with local Ollama
The generated file includes all options with helpful comments.
Configuration File Location
Bellwether looks for configuration in this order:
--configflag (explicit path)./bellwether.yaml(project root)./bellwether.yml./.bellwether.yaml./.bellwether.yml
Most commands require a config file. auth, discover, and registry can run without one, and validate-config can validate an explicit path via --config; init is the easiest way to bootstrap a full project config.
Configuration Overview
The generated bellwether.yaml includes all available options with comments. Below is a concise, up-to-date overview of the main sections. For the full reference, run bellwether init and edit the generated file.
server:
command: "npx @mcp/your-server"
args: []
transport: stdio
# url: "https://example.com/mcp"
# sessionId: "session-id"
# headers:
# Authorization: "Bearer ${MCP_SERVER_TOKEN}"
timeout: 30000
# env:
# API_KEY: "${API_KEY}"
scenarios:
# path: "./bellwether-tests.yaml"
only: false
output:
dir: ".bellwether"
docsDir: "."
format: both # docs, json, or both (legacy: agents.md)
examples:
full: true
maxLength: 5000
maxPerTool: 5
files:
checkReport: "bellwether-check.json"
exploreReport: "bellwether-explore.json"
contractDoc: "CONTRACT.md"
agentsDoc: "AGENTS.md"
baseline:
path: "bellwether-baseline.json" # baseline subcommands resolve this under output.dir
# savePath: "./bellwether-baseline.json" # check auto-save path (resolved under output.dir)
# comparePath: "./bellwether-baseline.json" # check drift comparison (output.dir first, cwd fallback)
failOnDrift: false
outputFormat: text
severity:
minimumSeverity: none
failOnSeverity: breaking
suppressWarnings: false
# aspectOverrides:
# description: none
check:
incremental: false
incrementalCacheHours: 168
parallel: true
parallelWorkers: 4
performanceThreshold: 10
diffFormat: text
warmupRuns: 0
smartTestValues: true
statefulTesting:
enabled: true
maxChainLength: 5
shareOutputsBetweenTools: true
externalServices:
mode: skip # skip | mock | fail
services: {}
assertions:
enabled: true
strict: false
infer: true
rateLimit:
enabled: false
requestsPerSecond: 10
burstLimit: 20
backoffStrategy: exponential
maxRetries: 3
security:
enabled: false
categories:
- sql_injection
- xss
- path_traversal
- command_injection
- ssrf
- error_disclosure
sampling:
minSamples: 10
targetConfidence: low
failOnLowConfidence: false
metrics:
countValidationAsSuccess: true
separateValidationMetrics: true
llm:
provider: ollama
model: ""
ollama:
baseUrl: "http://localhost:11434"
# openaiApiKeyEnvVar: OPENAI_API_KEY
# anthropicApiKeyEnvVar: ANTHROPIC_API_KEY
explore:
personas: [technical_writer]
maxQuestionsPerTool: 3
parallelPersonas: false
personaConcurrency: 3
skipErrorTests: false
workflows:
# path: "./bellwether-workflows.yaml"
discover: false # LLM discovery (explore only)
trackState: false
autoGenerate: false # Check-mode generation
requireSuccessfulDependencies: true
stepTimeout: 5000
timeouts:
toolCall: 5000
stateSnapshot: 10000
probeTool: 5000
llmAnalysis: 30000
llmSummary: 60000
watch:
path: "."
interval: 5000
extensions: [".ts", ".js", ".json", ".py", ".go"]
# onDrift: "npm test"
cache:
enabled: true
dir: ".bellwether/cache"
# Cache is persisted on disk. Remove the directory to fully clear cached entries.
logging:
level: info
verbose: false
discovery:
json: false
timeout: 30000
transport: stdio
# url: "https://example.com/mcp"
# sessionId: "session-id"
# headers:
# X-API-Key: "${MCP_API_KEY}"
registry:
limit: 10
json: false
golden:
defaultArgs: "{}"
mode: structural # exact | structural | semantic
compareFormat: text
listFormat: text
normalizeTimestamps: true
normalizeUuids: true
contract:
# path: "./contract.bellwether.yaml"
mode: strict # strict | lenient | report
format: text
timeout: 30000
failOnViolation: false
If you have output.format: agents.md in an existing config, it still works.
Bellwether now normalizes that to docs. Update your config to docs when convenient.
Environment Variable Interpolation
Bellwether supports environment variable interpolation in your configuration file, allowing you to reference secrets without committing them to version control.
Syntax
server:
env:
# Basic interpolation - pulls from shell or .env file
API_KEY: "${API_KEY}"
SERVICE_URL: "${SERVICE_URL}"
# With default values - uses fallback if var is not set
LOG_LEVEL: "${LOG_LEVEL:-info}"
DEBUG: "${DEBUG:-false}"
TIMEOUT: "${TIMEOUT:-30000}"
How It Works
- At runtime, Bellwether replaces
${VAR}with the value of the environment variableVAR - Default values can be specified with
${VAR:-default}syntax - Unset variables without defaults are left as-is (useful for catching missing config)
Example Workflow
# Set environment variables
export PLEX_URL="http://192.168.1.100:32400"
export PLEX_TOKEN="your-token-here"
# Or use a .env file with dotenv
# PLEX_URL=http://192.168.1.100:32400
# PLEX_TOKEN=your-token-here
# Run bellwether - it will interpolate the values
bellwether check
This pattern allows you to commit bellwether.yaml to version control while keeping secrets in environment variables or .env files (which should be gitignored).
Common Patterns
API Keys and Tokens:
server:
env:
API_KEY: "${API_KEY}"
AUTH_TOKEN: "${AUTH_TOKEN}"
Remote Server Authorization Headers:
server:
transport: sse
url: "https://api.example.com/mcp"
headers:
Authorization: "Bearer ${MCP_SERVER_TOKEN}"
discovery:
transport: streamable-http
url: "https://api.example.com/mcp"
headers:
X-API-Key: "${MCP_API_KEY}"
Header precedence:
server.headersapplies to remote commands by default.discovery.headersoverridesserver.headersforbellwether discover.- CLI
-H/--headeroverrides both for a single run.
URLs with Defaults:
server:
env:
BASE_URL: "${BASE_URL:-http://localhost:3000}"
API_ENDPOINT: "${API_ENDPOINT:-/api/v1}"
Feature Flags:
server:
env:
DEBUG: "${DEBUG:-false}"
LOG_LEVEL: "${LOG_LEVEL:-info}"
Multiple Configurations
Manage different configs for different environments:
# Development config
bellwether init --preset local
mv bellwether.yaml configs/dev.yaml
# CI config
bellwether init --preset ci
mv bellwether.yaml configs/ci.yaml
# Use specific config
bellwether check --config configs/ci.yaml npx your-server
Configuration Validation
Bellwether validates your config on startup and shows helpful errors:
Invalid configuration:
- llm.provider: Must be one of: ollama, openai, anthropic
- explore.maxQuestionsPerTool: Must be between 1 and 10
Best Practices
- Version control your config - Commit
bellwether.yamlto your repo - Use
bellwether checkfor CI - Deterministic, free, fast - Never commit API keys - Use environment variables or
bellwether auth - Use presets as starting points - Customize from there
- Keep JSON reports accessible - Set
output.formatto includejsonif you rely onbellwether-check.jsonorbellwether-explore.json
See Also
- init - Generate configuration
- check - Run tests using configuration
- baseline - Manage baselines
- Custom Scenarios - YAML-defined test cases
- CI/CD Integration - Pipeline configurations