api: port: 5300 webhook_prefix: 'http://127.0.0.1:5300' extra_webhook_prefix: '' # Canonical browser origin when WebUI and API use different origins in # development (for example http://localhost:3000). Production bundled UI # may leave this empty when webhook_prefix already has the browser origin. # OAuth redirects trust only these server-side values, never request Host # or Origin headers. webui_url: '' # Global API key for the HTTP service API and the MCP server. When set to a # non-empty string, this key is accepted anywhere a web-UI-created API key is # accepted (X-API-Key header or "Authorization: Bearer "), WITHOUT any # login session and without a database record. Leave empty to disable. # Keep this value secret; only enable it on trusted/internal deployments. global_api_key: '' workspace: invitations: # Public WebUI origin used to build invitation links. Leave empty to # use api.webui_url, then api.webhook_prefix. Set via # WORKSPACE__INVITATIONS__PUBLIC_WEB_URL in container deployments. public_web_url: '' email: # Optional invitation email delivery. Empty provider keeps # invitations link-only. Supported: resend, smtp. provider: '' from: '' timeout_seconds: 10 resend: api_url: 'https://api.resend.com/emails' # Secret. Set via WORKSPACE__INVITATIONS__EMAIL__RESEND__API_KEY. api_key: '' smtp: host: '' port: 587 username: '' # Secret. Set via WORKSPACE__INVITATIONS__EMAIL__SMTP__PASSWORD. password: '' starttls: true ssl: false command: enable: true prefix: - '!' - ! privilege: {} concurrency: pipeline: 20 session: 1 # Hard admission limits for queued + running pipeline queries. pending_queries: 1000 pending_queries_per_workspace: 100 webhooks: # Bound database materialization and per-message outbound fan-out. # Existing rows above this limit remain deletable through the management # API, but only this many enabled destinations are dispatched. # Supports WEBHOOKS__MAX_PER_WORKSPACE (hard cap: 64). max_per_workspace: 16 # Instance-wide request admission. Delivery fails open when every slot is # occupied instead of retaining an unbounded queue of webhook tasks. # Supports WEBHOOKS__MAX_INFLIGHT_REQUESTS (hard cap: 128). max_inflight_requests: 16 cloud: # Operational safety ceilings for the one logical Cloud instance. These # are not subscription entitlements. An authoritative directory update # that would exceed them is rejected atomically rather than truncated. directory: # Tune downward from the measured production capacity curve. Core has # an absolute safety ceiling of 5,000 active Workspaces. max_active_workspaces: 1000 # Full snapshots contain current Workspaces only. Archived tombstones # are delivered through bounded per-Workspace deltas. max_snapshot_workspaces: 1000 # Aggregate memberships accepted in one signed snapshot or delta. max_snapshot_memberships: 20000 # Signed control-plane envelope buffered by the closed adapter before # JSON/JWS verification (32 MiB; absolute maximum 64 MiB). max_response_bytes: 33554432 proxy: http: '' https: '' system: instance_id: '' edition: community recovery_key: '' allow_modify_login_info: true disabled_adapters: [] blocking_executor: # All asyncio.to_thread work shares this process-wide bounded pool. # Both running threads and queued calls are capped to prevent tenant # bursts from creating an unbounded queue of retained request objects. max_workers: 8 max_pending: 128 # One trusted Workspace can occupy at most this many running + queued # slots. This must not exceed half of max_workers. max_inflight_per_scope: 4 # Public outbound IP addresses of this LangBot deployment. Some platforms # (e.g. WeCom, WeChat Official Account, QQ Official API) require the # caller's IPs to be added to their trusted-IP / IP-whitelist settings. # When set, the web UI shows these IPs on the bot config form of such # adapters. Also settable via the SYSTEM__OUTBOUND_IPS env var # (comma-separated). Empty list = hidden in the web UI. outbound_ips: [] limitation: max_bots: -1 max_pipelines: -1 max_extensions: -1 max_knowledge_bases: -1 # When set to a non-empty string, every pipeline is forced to use this # Box sandbox-scope template regardless of its own configuration, and # the per-pipeline "Sandbox Scope" selector is locked in the web UI. # Used by SaaS deployments to confine a tenant to a single shared # sandbox (set to '{global}'). Empty string = no restriction. force_box_session_id_template: '' task_retention: # Keep at most this many completed async task records in memory completed_limit: 200 # Bound progress output retained by one task, including running tasks. max_log_chars: 200000 # Protect the shared process from user-triggered operation storms. max_active_user_tasks: 256 max_active_user_tasks_per_workspace: 8 session_retention: # Process-local conversation sessions are a cache, not durable history. max_entries: 2000 max_entries_per_workspace: 200 idle_ttl_seconds: 86400 max_conversations_per_session: 20 max_messages_per_conversation: 100 websocket_retention: # Bound live browser sockets and per-Workspace fan-out in the shared process. max_connections: 1024 max_connections_per_workspace: 32 # Idle proxy runtimes are evicted when this process-local cache fills. max_workspace_proxies: 1024 max_conversations_per_workspace: 200 max_messages_per_conversation: 100 conversation_idle_ttl_seconds: 86400 send_queue_size: 100 response_limits: # Defense in depth for tenant-configured upstream providers. max_generated_chars: 1048576 max_stream_chunks: 100000 jwt: expire: 604800 secret: '' database: use: sqlite sqlite: path: 'data/langbot.db' postgresql: # Optional SQLAlchemy URL (postgresql[+asyncpg]://...). When set, it # overrides the structured fields and preserves TLS/query options. url: '' host: '127.0.0.1' port: 5432 user: 'postgres' password: 'postgres' database: 'postgres' # One bounded pool is shared by business data and Cloud pgvector. pool_size: 10 max_overflow: 10 pool_timeout_seconds: 30 pool_recycle_seconds: 1800 # Applied only to Cloud runtime connections. The one-shot release # migration uses its operator connection without these short limits. statement_timeout_ms: 60000 lock_timeout_ms: 5000 idle_in_transaction_session_timeout_ms: 60000 cloud_migration: # `langbot migrate --cloud` reads an operator-only PostgreSQL DSN from # this environment variable. The operator role must differ from the # runtime role above; never put its password in this file or CLI args. operator_dsn_env: 'LANGBOT_CLOUD_MIGRATION_DSN' vdb: use: chroma # Bound process-local collection/index handles across all Workspaces. runtime_cache_limit: 1024 qdrant: url: '' host: localhost port: 6333 api_key: '' seekdb: mode: embedded # 'embedded' or 'server' # Embedded mode options: path: './data/seekdb' database: 'langbot' # Server mode options (used when mode='server'): host: 'localhost' port: 2881 user: 'root' password: '' tenant: '' # Optional, for OceanBase server milvus: uri: 'http://127.0.0.1:19530' token: '' db_name: '' pgvector: # SaaS/shared-schema deployments reuse database.postgresql. OSS can # keep this false when deliberately using an external pgvector DB. use_business_database: false # Release migrations create one partial ANN index per enabled value. allowed_dimensions: [384, 512, 768, 1024, 1536] host: '127.0.0.1' port: 5433 database: 'langbot' user: 'postgres' password: 'postgres' valkey_search: host: 'localhost' port: 6379 # integration tests use 6380 -> valkey/valkey-bundle:9.1.0 db: 0 password: '' # optional (toB auth) username: '' # optional (ACL user, toB) tls: false # optional (toB/SaaS) index_algorithm: 'HNSW' # HNSW | FLAT distance_metric: 'COSINE' # COSINE | L2 | IP request_timeout: 5000 # per-request timeout in ms (glide default 250ms is too low for KNN) storage: use: local # Bound every object materialized into Core memory. Built-in Local/S3 # providers enforce this while reading (hard cap: 64 MiB). max_object_read_bytes: 10485760 cleanup: # Enable periodic cleanup of local/S3 uploaded files and old log files enabled: true # Cleanup check interval in hours check_interval_hours: 1 # Root-level uploaded files older than this will be deleted uploaded_file_retention_days: 7 # LangBot log files older than this many days will be deleted log_retention_days: 3 # Bound per-Workspace file cleanup and diagnostic candidate lists. # Supports STORAGE__CLEANUP__MAX_FILES_PER_RUN (hard cap: 10000). max_files_per_run: 1000 s3: endpoint_url: '' access_key_id: '' secret_access_key: '' region: 'us-east-1' bucket: 'langbot-storage' # boto3 is synchronous; bound the number of operations delegated to # worker threads so an S3 slowdown cannot saturate the process. max_concurrency: 16 plugin: enable: true runtime_ws_url: 'ws://langbot_plugin_runtime:5400/control/ws' enable_marketplace: true display_plugin_debug_url: 'ws://localhost:5401/plugin/debug/ws' worker: # Instance-wide maximum for every plugin installation. Plugin # manifests cannot raise or override these limits. max_cpus: 1.0 max_memory_mb: 512 max_pids: 128 max_open_files: 256 max_file_size_mb: 512 # Instance-wide admission budgets. The effective worker count is the # lowest of max_workers, max_total_cpus/max_cpus and # max_total_memory_mb/max_memory_mb. max_workers: 16 max_total_cpus: 8.0 max_total_memory_mb: 8192 # Includes disabled and historical installation fences retained to # reject stale desired-state replay. max_installations: 10000 # Restart storms are globally serialized by default. Repeated # unexpected exits within the configured window open a Runtime-wide # circuit; one half-open probe must remain stable before other # installations may restart. max_concurrent_restarts: 1 restart_failure_threshold: 8 restart_failure_window_seconds: 30.0 restart_circuit_open_seconds: 60.0 # Cloud shared Runtime sets this to true and fails closed unless # delegated cgroup v2 controllers are available. require_hard_limits: false binary_storage: # Max bytes for a single plugin binary storage value max_value_bytes: 10485760 mcp: # Bound instance-wide MCP startup and shutdown bursts. Supports # MCP__LIFECYCLE_CONCURRENCY and is clamped to a maximum of 128. lifecycle_concurrency: 16 stdio: # Independent gate for local stdio MCP transports. Cloud v2 sets # MCP__STDIO__ENABLED=false even when Box Runtime is available. enabled: true monitoring: query_limits: # Maximum records materialized by one paginated monitoring request. # Supports MONITORING__QUERY_LIMITS__PAGE_ROWS (hard cap: 5000). page_rows: 1000 # CSV exports are currently assembled in memory. Keep this lower than # the historical 100000-row default (hard cap: 50000). export_rows: 10000 # Maximum related records returned by one session/message detail view # (hard cap: 10000). Aggregate statistics remain database-computed. detail_rows: 2000 # Token charts are grouped in SQL and return only the newest buckets # (hard cap: 10000). Supports an environment variable override. timeseries_buckets: 1000 # Bound high-offset scans that can otherwise monopolize PostgreSQL CPU # (hard cap: 10000000). max_offset: 1000000 auto_cleanup: # Enable automatic cleanup of expired monitoring records enabled: true # Retention period in days, records older than this will be deleted retention_days: 30 # Cleanup check interval in hours check_interval_hours: 1 # Number of expired rows to delete per table batch delete_batch_size: 1000 # Prevent one large Workspace backlog from monopolizing PostgreSQL. # Supports MONITORING__AUTO_CLEANUP__MAX_BATCHES_PER_TABLE_PER_RUN. max_batches_per_table_per_run: 4 box: # Master switch for the Box sandbox runtime. When false, LangBot does NOT # attempt to connect to a remote Box runtime nor start a local stdio Box # subprocess. Disabling Box also disables every feature that depends on it: # the native sandbox tools (exec/read/write/edit/glob/grep), the activate # skill tool, skill add/edit, and stdio-mode MCP servers. Skills can still # be listed read-only and http/sse MCP servers continue to work. enabled: true backend: 'local' # 'local' (Docker/nsjail), 'docker', 'nsjail', or 'e2b'. Can be written via BOX__BACKEND. runtime: # External WebSocket runtimes also require LANGBOT_BOX_CONTROL_TOKEN in # both LangBot and Box. Keep the shared secret out of this config file. endpoint: '' # External Box Runtime base URL, e.g. 'ws://127.0.0.1:5410'. Leave empty for local auto-managed runtime. limits: max_sessions: 64 max_managed_processes: 64 max_completed_processes: 256 # Core scans a Workspace before and after quota-enforced executions. # Fail closed instead of repeatedly walking an inode bomb. # Supports BOX__LIMITS__MAX_WORKSPACE_ENTRIES (hard cap: 1000000). max_workspace_entries: 100000 # Retained admission fences prevent replay after entitlement expiry or # revocation. Fail closed before that monotonic state can grow without # bound; Cloud may override this with BOX__LIMITS__MAX_ADMISSION_RECORDS. max_admission_records: 100000 max_rpc_file_bytes: 20971520 # Cloud v2 overrides these values through the instance config/environment. # OSS keeps admission disabled and preserves the existing multi-session # local behavior. These limits are Runtime-owned and cannot be relaxed by # a pipeline, Workspace entitlement, or tool call. admission: required: false logical_session_id: 'global' required_backend: 'nsjail' max_sessions: 1 max_managed_processes: 0 max_grant_ttl_sec: 300 max_timeout_sec: 120 cpus: 1.0 memory_mb: 512 pids_limit: 128 read_only_rootfs: true # OSS admission-disabled mode uses 0 for unlimited compatibility. # Cloud bootstrap requires a positive hard quota. workspace_quota_mb: 0 readiness_cache_sec: 15 local: profile: 'default' image: '' # Custom local sandbox image. Leave empty to use the profile default. host_root: './data/box' # Base host directory for local workspace mounts. Docker deployments should override this with an absolute host path. default_workspace: '' # Defaults to '/default'. Relative paths are resolved under host_root. skills_root: 'skills' # Box-owned skill package directory. Relative paths are resolved under host_root. allowed_mount_roots: # Defaults to [''] when left empty. - './data/box' - '/tmp' workspace_quota_mb: null # Optional disk quota override (>= 0). null = profile default. # Default nsjail cgroup memory limit for each MCP stdio server process, in MB. # Node.js MCP servers (npx/bunx) need more memory than Python ones because V8 # and WebAssembly modules (e.g. undici llhttp) reserve large virtual address # space at startup. Setting this too low causes processes to be killed with # return_code=137 (OOM kill); the symptom is "Box managed process exited # unexpectedly" in the logs. Raise on machines with ample RAM; lower only if # you run exclusively Python (uvx) MCP servers. # Can also be set via BOX__DEFAULT_MEMORY_MB. Default: 1536. default_memory_mb: 1536 docker: cpu_limit_enabled: true # When false, Docker sandbox containers are started without --cpus. Memory and PID limits still apply. e2b: api_key: '' # Can also be set via E2B_API_KEY env var. api_url: '' # Custom API URL for self-hosted deployments. template: '' # Default template ID (e.g. 'base', 'python-3.11'). space: # Space service URL for OAuth and API url: 'https://space.langbot.app' # Space API URL for model requests (MaaS) models_gateway_api_url: 'https://api.langbot.cloud/v1' # OAuth authorization page URL (user will be redirected here) oauth_authorize_url: 'https://space.langbot.app/auth/authorize' disable_models_service: false disable_telemetry: false