Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.getbindu.com/llms.txt

Use this file to discover all available pages before exploring further.

The 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.
config = {
    "author": "you@example.com",
    "name": "research_agent",
    "deployment": {
        "url": "http://localhost:3773",
        "expose": False,   # required (no default); declares intent only — real tunnel is launch=True
    },
}
KeyWhat it does
authorGoes 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.
nameThe human-readable slug. Also sanitized into the DID.
deployment.urlWhere the agent listens. Must be a valid http(s) URL — validated via urlparse.
deployment.exposeRequired (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.
Miss 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 from ConfigValidator.DEFAULTS). You override when you care.
config = {
    # ...required keys above...
    "description": "Research assistant with web search.",
    "version": "1.0.0",
    "deployment": {
        "url": "http://localhost:3773",
        "expose": True,                              # required; declares public-facing intent (tunnel comes from launch=True)
        "cors_origins": ["http://localhost:5173"],   # for the inbox UI or your frontend
    },
    "skills": ["skills/question-answering"],         # see /bindu/skills/introduction/overview
    "capabilities": {"push_notifications": True},    # webhook on task state change
    "telemetry": True,                               # on by default; set False to opt out
}
KeyDefaultWhat it does
description"A Bindu agent"Shown on the agent card. Other agents see this when they discover you.
versionbindu package version (__version__)Your agent’s version, not Bindu’s. Bump it like you would any service.
deployment.cors_originsNoneAllowed 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_notificationsabsent (= False)Lets callers register webhooks so they can stop polling.
capabilities.streamingabsent (= False)Server-Sent Events on message/stream.
telemetryTrueOpenTelemetry traces on. Set False to opt out, or override with TELEMETRY_ENABLED=false env var.
agent_trustNoneTrust-level config; see DIDs.
execution_costNonePer-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 when storage / scheduler aren’t already in the config dict.
# Storage — pick one
STORAGE_TYPE=memory                              # default; lost on restart
STORAGE_TYPE=postgres
DATABASE_URL=postgres://user:pass@host:5432/db   # required when STORAGE_TYPE=postgres

# Scheduler — pick one
SCHEDULER_TYPE=memory                            # default; single-process
SCHEDULER_TYPE=redis
REDIS_URL=redis://localhost:6379/0               # required when SCHEDULER_TYPE=redis
Bindu refuses to start if 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.
FeatureHow you turn it onDocs
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 paymentsAdd "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
OpenTelemetryOn 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
SentryEnv: SENTRY_ENABLED=true, SENTRY_DSN=...Observability
Private skills"private_skills": [...], "allowed_dids": [...](Skills page covers it)
Agent trust"agent_trust": {...}DIDs
The pattern is consistent: feature lives in 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:
config = {
    "author": "team@yourco.io",
    "name": "research_agent",
    "description": "Research assistant with web search and PDF Q&A.",
    "version": "1.2.0",
    "deployment": {
        "url": "https://research.yourco.io",
        "expose": False,                             # local-only intent — real DNS in prod, no FRP tunnel
        "cors_origins": ["https://app.yourco.io"],
    },
    "capabilities": {
        "push_notifications": True,
        "streaming": True,
    },
    "skills": [
        "skills/question-answering",
        "skills/pdf-processing",
    ],
    "auth": {
        "enabled": True,
        "provider": "hydra",
    },
    # telemetry is True by default; OTel endpoint comes from env (OLTP_ENDPOINT).
}
Everything else — storage, scheduler, Hydra URLs, OLTP endpoint, x402 facilitator — comes from env vars at deploy time. The dict stays small and your secrets stay out of git. You did not write the validator; the validator wrote you a useful error message instead.

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 messages arg
  • share data between handler invocations → use Storage, not module-level globals
  • override behavior at runtime → you probably want a skill, not a config key
If you find yourself wanting a config key that isn’t here, open an issue — half the time it’s already in 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.