Configuration
Bento reads two config layers when the daemon starts:
.bento/daemon.yaml— daemon-wide settings (database, ports, defaults, tunnel).bento/pipelines/*.yaml— one file per pipeline definition
Both files are created by bento init. Runtime state (PID, logs, workspaces) lives under ~/.bento/<name>/ and is never committed.
Environment variables are expanded with ${VAR} syntax in both files.
daemon.yaml
# Daemon identity — used for launchd/systemd service name and log dir
name: bento
logging:
level: info # error | warn | info | debug
database:
url: postgresql://bento:bento@localhost:8421/bento
# Global defaults applied to every pipeline unless overridden
defaults:
limits:
max_concurrent: 2
guardrails:
timeout: 300 # seconds before an agent run is killed
max_tokens: 50000
# The orchestrator decides which agent/model handles a given workload
orchestrator:
runtime: claude
model: claude-opus-4-6
# Named repo shortcuts — used in pipeline prompts via {{repo.*}}
repos:
my-project:
url: acme/my-project # GitHub owner/repo
branch: main
issue_tracker: github
webhooks:
host: 127.0.0.1
port: 7890
secret: ${GITHUB_WEBHOOK_SECRET}
# Optional: expose the webhook port via a public tunnel at startup.
# See Public Access for Cloudflare and Tailscale options.
# tunnel:
# provider: cloudflare
# mode: quick
queue:
concurrency: 2
retry:
attempts: 1
circuit_breaker:
failure_threshold: 3
# Optional: override the sandbox backend (auto-detected by default)
# sandboxes:
# backend: docker
# Knowledge retrieval — inject relevant source context into agent prompts
pipeline:
retrieve:
topK: 20Field reference
| Field | Default | Description |
|---|---|---|
name | bento | Service identifier; sets the launchd/systemd unit name and ~/.bento/<name>/ path |
logging.level | info | Log verbosity: error, warn, info, debug |
database.url | — | PostgreSQL connection string |
defaults.limits.max_concurrent | — | Max simultaneous agent runs across all pipelines |
defaults.guardrails.timeout | — | Seconds before a run is killed (pipeline can override) |
defaults.guardrails.max_tokens | — | Token budget per run |
orchestrator.runtime | claude | Runtime used for orchestration decisions |
orchestrator.model | — | Model override for the orchestrator |
webhooks.host | 127.0.0.1 | Bind address |
webhooks.port | 7890 | Bind port |
webhooks.secret | — | GitHub webhook secret for HMAC verification |
queue.concurrency | — | Parallel jobs the queue worker runs |
queue.retry.attempts | 1 | Retry count on job failure |
queue.circuit_breaker.failure_threshold | — | Failures before the circuit opens |
pipeline.retrieve.topK | — | Number of source chunks injected per prompt (requires qmd) |
Pipeline files
Each file under .bento/pipelines/ defines one pipeline. The filename is cosmetic; the name: field (or the filename stem if omitted) is the pipeline's identity.
Webhook trigger
name: pr-review
trigger:
github:
- pull_request.opened
- pull_request.synchronize
agent: reviewer
prompt: |
Review PR #{{event.pull_request.number}} ("{{event.pull_request.title}}")
on {{event.repository.full_name}}, opened by @{{event.pull_request.user.login}},
for merge readiness.
guardrails:
timeout: 900 # override the daemon default for this pipelineSchedule trigger
trigger:
schedule: "*/5 * * * *" # standard cron expression
agent: heartbeat
prompt: |
Reply with exactly the word "pong" and nothing else.
sandbox:
backend: docker # override sandbox for this pipeline
guardrails:
read_only: true
timeout: 60
options:
stateless: true # skip injecting/accumulating run notes
orchestrator: false # bypass orchestrator for trivial tasksTrigger sources
See Triggers for the full reference — event string formats, filter syntax, cron expressions, and prompt template variables.
Pipeline field reference
| Field | Default | Description |
|---|---|---|
name | filename stem | Pipeline identifier |
trigger | — | One or more trigger sources (required) |
agent | — | Agent persona to use (agents/<name>/SOUL.md) |
prompt | — | Prompt template; {{event.*}} expands from the webhook payload |
guardrails.timeout | daemon default | Seconds before the run is killed |
guardrails.max_tokens | daemon default | Token budget |
guardrails.read_only | false | Restrict agent to read-only file operations |
sandbox.backend | auto-detected | Override sandbox: docker, podman, daytona, just-bash |
options.stateless | false | Skip cross-run note injection/accumulation |
orchestrator | true | Set to false to bypass orchestrator routing |
Auth tokens
Bearer tokens are managed via the CLI and stored in the daemon's database. See Authentication.
# daemon.yaml — static token config (alternative to CLI-issued tokens)
auth:
tokens:
- id: cli-prod
secret: ${BENTO_TOKEN_CLI}
scopes: ["pipelines:*", "agents:*"]
- id: ci-runner
secret: ${BENTO_TOKEN_CI}
scopes: ["pipelines:review"]
