config dict you hand to bindufy() is the whole settings surface. Four keys are required (three at the top level plus deployment.expose). The rest have defaults that work for localhost, and env-var overrides for when you ship.
The required keys
The top-level validator checks three fields. A fourth,deployment.expose, is required by the deployment builder (bindufy.py:332) once deployment is present.
| Key | What it does |
|---|---|
author | Goes into your agent’s DID. Sanitized (@ → _at_, . → _) so the DID stays URL-safe. Use the email you’d be okay seeing in another team’s logs. |
name | The human-readable slug. Also sanitized into the DID. |
deployment.url | Where the agent listens. Must be a valid http(s) URL — validated via urlparse. |
deployment.expose | Required (no default). Declares intent — True means the agent is meant to be publicly reachable, False means local-only. Note: the FRP public tunnel is actually opened by passing launch=True to bindufy(config, handler, launch=True), not by this flag. expose is currently a placeholder for future trust-level signaling. |
author, name, or deployment.url and the config validator raises ConfigError: '<field>' is a required field in the agent configuration. with an example config attached. Miss deployment.expose (when a deployment block is present) and the deployment builder raises ValueError: Missing required config field(s): deployment.expose — different error class, different message format.
The keys you’ll actually touch
Everything below has a sensible default (taken fromConfigValidator.DEFAULTS).
You override when you care.
| Key | Default | What it does |
|---|---|---|
description | "A Bindu agent" | Shown on the agent card. Other agents see this when they discover you. |
version | bindu package version (__version__) | Your agent’s version, not Bindu’s. Bump it like you would any service. |
deployment.cors_origins | None | Allowed origins for the HTTP server. Add your frontend here. |
skills | [] | Folder paths to skill manifests. See Skills. |
private_skills | [] | Private skill manifests — served from /agent/private.json behind Hydra auth, visible only to DIDs in allowed_dids. |
allowed_dids | [] | DIDs allowed to see private_skills / call your agent under Hydra admission control. |
capabilities.push_notifications | absent (= False) | Lets callers register webhooks so they can stop polling. |
capabilities.streaming | absent (= False) | Server-Sent Events on message/stream. |
telemetry | True | OpenTelemetry traces on. Set False to opt out, or override with TELEMETRY_ENABLED=false env var. |
agent_trust | None | Trust-level config; see DIDs. |
execution_cost | None | Per-call price (a dict or list of dicts). Setting this activates the x402 payment middleware — see Payment. |
Storage and scheduler — set these via env
Putting database credentials in a Python dict is how secrets end up in git. The env-enricher fills these in for you whenstorage / scheduler aren’t already in the config dict.
STORAGE_TYPE=postgres but DATABASE_URL is unset (same for SCHEDULER_TYPE=redis / REDIS_URL) — no silent fallback to memory.
Local dev: leave both unset, you get in-memory. Production: set both, you get persistence and distributed task queues. Same bindufy(config, handler) either way.
Deeper guides: Storage, Scheduler.
Auth, payments, and the rest
These are off by default. Turn them on when you need them — each one has its own page that goes deeper than this reference should.| Feature | How you turn it on | Docs |
|---|---|---|
| OAuth2 (Hydra) | Either path works: (1) put it in your config — "auth": {"enabled": True, "provider": "hydra", "admin_url": "...", "public_url": "..."} is applied to app_settings.auth and app_settings.hydra via prepare_auth_settings; (2) or use env vars AUTH__ENABLED=true, HYDRA__ADMIN_URL=..., HYDRA__PUBLIC_URL=... (HydraSettings). | Authentication |
| x402 payments | Add "execution_cost": {...} to the config dict — the middleware activates when execution_cost is present and produces payment requirements (applications.py:686). Env vars X402__FACILITATOR_URL, X402_PAY_TO configure it further. | Payment |
| OpenTelemetry | On by default (telemetry: True). Send traces by setting env vars OLTP_ENDPOINT=..., optionally OLTP_SERVICE_NAME, OLTP_HEADERS='{"Authorization":"..."}'. Turn off with TELEMETRY_ENABLED=false. | Observability |
| Sentry | Env: SENTRY_ENABLED=true, SENTRY_DSN=... | Observability |
| Private skills | "private_skills": [...], "allowed_dids": [...] | (Skills page covers it) |
| Agent trust | "agent_trust": {...} | DIDs |
config if it’s about agent identity or behavior, in env vars if it’s about infrastructure or secrets.
The “okay show me everything” example
Most production agents look something like this:What you can’t put in here
config is for static settings. If you’re trying to:
- pass dynamic state per request → use the handler’s
messagesarg - share data between handler invocations → use Storage, not module-level globals
- override behavior at runtime → you probably want a skill, not a config key
bindu/penguin/config_validator.py under a name we forgot to document. The other half it’s a real feature gap and we want to know.