All docs
Docs · Reference
Every `txco serve` flag
Each flag can also be set from the environment as TXCO_<FLAG>, upper case with
dashes as underscores (--trace-mode is TXCO_TRACE_MODE). A flag on the command line
wins over the environment, which wins over the default. txco serve --help prints
the same list. What the main ones mean, together: the runtime reference.
| Flag | Default | What it does |
|---|---|---|
--admin-addr | :8081 | The port to listen on for the admin web server (:8081) |
--admin-pass | — | Basic Auth password () |
--admin-user | — | User for basic auth () |
--admin-idle-timeout | 60 | Idle timeout, seconds (60) |
--admin-read-timeout | 15 | Read timeout, seconds (15) |
--admin-root-dir | ./chassis/data/admin/static | What is the root directory for the admin web server? (./chassis/data/admin/static) |
--admin-write-timeout | 15 | Write timeout, seconds (15) |
--admin-cors-origins | — | Comma-separated browser Origin allowlist (scheme+host[:port], e.g. https://admin.example.com) for cookie-authed admin mutations. Empty keeps only the built-in dev/self origins. Set this when serving the admin UI at a public hostname so it is full mutate-capable instead of read-only. |
--auth-mode | both | Admin API authentication mode: {basic, signed, both} (both) |
--admin-allow-open | false | Allow the admin API to run WITHOUT authentication (grants admin:all to any caller) when no —admin-user/—admin-pass are set and —auth-mode is basic/both. Off by default → fail closed. Implied true when —env starts with ‘dev’ (local convenience). NEVER enable in a network-reachable production environment. (false) |
--auth-dev-enroll-secret | — | When set on a non-prod chassis, enables POST /auth/dev/enroll. NEVER set this in production. |
--cloud-oauth-issuer | — | OIDC issuer URL whose id_tokens this chassis trusts for POST /auth/oauth/enroll; its discovery doc resolves the JWKS (oidc-provider /jwks fallback). Empty (default) disables the endpoint — open-core trusts no external issuer until an operator opts in. |
--cloud-oauth-audience | — | When set, the id_token aud must contain this value (the OAuth client_id). Empty skips the aud check. |
--cloud-chassis-url | — | Public admin BASE URL echoed to OAuth-enrolled clients in chassis_url (written to the CLI profile). Empty defaults to the request scheme+host. |
--registry-token-key | — | Path to the PEM ECDSA P-256 private key (PKCS#8 or SEC1) that signs package-registry tokens (POST /v1/tenants/{t}/registry/token). The endpoint is enabled only when the key, the certificate, —registry-token-issuer and —registry-token-service are all set. Empty (default) disables it. |
--registry-token-key-b64 | — | Base64 of the PEM private key for package-registry tokens; takes precedence over —registry-token-key. For a secret store that holds a value, not a file. |
--registry-token-cert | — | Path to the PEM certificate for the registry token key: the SAME certificate the registry trusts as its rootcertbundle. Sent in every token’s x5c header. |
--registry-token-cert-b64 | — | Base64 of the PEM certificate for package-registry tokens; takes precedence over —registry-token-cert. Public. |
--registry-token-issuer | — | The iss claim of package-registry tokens; must equal the registry’s auth.token.issuer. |
--registry-token-service | — | The registry this chassis mints tokens for, as host[:port] (e.g. registry.example.com): the aud claim, equal to the registry’s auth.token.service. A token request naming any other service is refused. |
--registry-token-ttl | 300 | Lifetime of a package-registry token, seconds; clamped to 60–900 (300). |
--registry-token-platform-namespaces | — | Comma-separated namespace=tenant_id pairs (e.g. txco=tnt_abc123) pinning the platform’s own registry namespaces to one tenant by ID. A token for a platform name (txco, txco-*, library, …) is minted only when the tenant asking both holds that slug AND is the tenant pinned here; an unpinned platform name is refused for everyone. A mistyped ID therefore grants the namespace to no one (the boot log prints the pins as read). |
--client-version-latest | — | Latest txco CLI version this server advertises (no leading v, e.g. 0.2.6), surfaced in the admin /healthz JSON for client self-sync. Empty omits it. |
--client-version-minimum | — | Minimum supported txco CLI version (no leading v). Clients older than this are warned (warn-only; never blocked) via the /healthz policy. Empty disables the warning. |
--client-version-critical | false | When true, the advertised client-version update is flagged critical in the /healthz policy so out-of-date CLIs warn more loudly. Still warn-only. |
--secret-master-key | ./chassis/data/secrets/txco-master.key | Path to the host-local master-key file for the per-tenant secret store. Auto-minted on first boot if absent (same convention as the runtime DB). File is 32 bytes with 0600 perms. Set to empty to disable the feature entirely (library / embedder opt-out). |
--secret-master-key-b64 | — | Base64-encoded 32-byte master key for the per-tenant secret store, shared across the WHOLE fleet. When set it takes precedence over the per-node —secret-master-key file, so secrets replicated via fleet-sync decrypt on every node. Put the SAME value in every node’s env (e.g. /data/secrets/txco/.env). Empty (default) keeps the per-node auto-minted file (single-node). |
--demo-mode | false | Register the /v1/demo/* execution-hop endpoints (the txcl learning environment served by ‘txco demo’). Default false: a normal chassis / ‘txco dev’ exposes no demo surface, so the admin UI loads the standard interface. ‘txco demo’ sets TXCO_DEMO_MODE=true. NEVER enable in production. |
--debug-breakpoints | false | Enable breakpoint debugging: inlet stamps _txc.flag_breakpoint=true on every event and reads ?_txc.break=<scope> from HTTP query strings. NEVER enable in production. |
--debug-private | false | Inlet stamps _txc.flag_private=true on every event. When set, the response to the client keeps private (underscore-prefixed) fields like _txc that would otherwise be stripped. Useful for development; leave off in production. |
--trace-mode | off | Request tracing: {off, summary, full} (off). Writes per-request artifacts under —trace-dir. |
--trace-store | file | Trace sink + reader backend: {noop, file}. file folds per-request artifacts under —trace-dir. trace-mode=off forces noop regardless. (file) |
--trace-dir | ./data/trace | Directory for trace artifacts when —trace-mode != off, for the file backend (./data/trace) |
--trace-async | false | Buffer trace writes through an async worker so the request path never blocks on disk I/O. Recommended in production when tracing is on. |
--trace-buffer-size | 1024 | Size of the async trace event queue. When full, additional events are dropped (request path is never blocked). Applies only with —trace-async (1024). |
--trace-body-cap-bytes | 65536 | Maximum bytes kept per body (request payload, step in/out, final response) when —trace-async is on. Larger bodies are truncated; meta.json records the original size (65536, ~64KB). |
--trace-stream-longpoll-ms | 30000 | Maximum ms to hold a /traces/stream long-poll request open server-side before returning 202 so the client can re-poll with the same cursor (30000). Auto-clamped to stay under the web-write-timeout. Only meaningful when the trace store registers a live-stream Armable (e.g. the NATS overlay). |
--trace-stream-ring-size | 1024 | Per-subscription buffer hint for live trace streams. Backends may clamp; oversubscribed buffers drop the oldest events (best-effort live tail, not durable replay) (1024). |
--cron-period | 60 | Seconds between cron ticks, seconds (60) |
--cron-queue | local | Cron dispatch queue backend: {local}. local is an in-process channel + worker pool (single node). (local) |
--cron-max-inflight | 32 | Max concurrent cron dispatches the queue runs at once; bounds the per-tick fan-out (32). Backends that bound concurrency their own way may reuse this value. |
--cron-system-tick | false | Emit a system-wide cron tick (job=default, no tenant) each period, for scheduled work hooked in _sys/boot or routed by a ‘default’ cron-job ingress binding. Off by default. The per-tenant _cron fan-out runs independently. |
--scheduled-period | 20 | Seconds between scheduled-event poll passes (the ‘scheduled’ personality). Each pass reclaims stale claims, claims due rows (schedule_at <= now), and fires them into the tenant’s _scheduled/0 stack (20). Worst-case firing latency past schedule_at is one period. |
--scheduled-max-inflight | 32 | Max concurrent scheduled-event dispatches per poll pass; bounds the fan-out when many events come due at once (32). |
--scheduled-stale-after | 600 | Seconds a claimed scheduled event may sit before the reclaim sweep resets it to pending so another node retries — crash recovery for a node that died mid-fire (600). |
--scheduled-retention | 604800 | Seconds to keep terminal (done/failed) scheduled-event rows before the poller purges them (604800 = 7d). |
--db-runtime-dsn | file:$db-root-dir/runtime-$env.db | DSN for runtime database — ops, stacks, versions, files, tenants (file:./chassis/data/db/runtime-$env.db) |
--db-auth-dsn | file:$db-root-dir/auth-$env.db | DSN for auth database. Two planes share it: the account plane (actors, keys, memberships, invitations, browser sessions), used only when the admin personality is active; and the stack-plane identity tables (users, principal bindings, credentials — txco://user/, txco://credential/), opened on every node. A node without the admin personality that cannot open it keeps serving and those ops answer txco_user_disabled. Default is a local SQLite file (file:./chassis/data/db/auth-$env.db); |
--scheduled-store | sqlite | Backend for the scheduled_events queue (txco://schedule + the ‘scheduled’ personality): {sqlite}. sqlite is the bundled SQLite file at —scheduled-db-path. (sqlite) |
--scheduled-db-path | ./chassis/data/scheduled.db | Path to the bundled scheduled_events SQLite store (used by —scheduled-store=sqlite). Its parent dir is created on boot. (./chassis/data/scheduled.db) |
--state-store | sqlite | Backend for the state store (txco://state/*: durable state records, and the transition outbox the ‘state’ personality presents into each tenant’s _state stack): sqlite (bundled), or a backend an overlay registers (the hosted build: postgres, reading TXCO_DB_STATE_DSN, else TXCO_DB_AUTH_DSN). sqlite is a per-node file at —state-db-path and opens only with the ‘state’ personality; a shared backend opens on every node. (sqlite) |
--state-db-path | ./chassis/data/state.db | Path to the bundled state SQLite file (used by —state-store=sqlite; ignored by other backends). Its parent dir is created on boot. (./chassis/data/state.db) |
--state-period | 5 | Seconds between state-event poll passes (the ‘state’ personality). A node that commits a transition presents it at once; the period is the worst case for an event another node committed. (5) |
--state-max-inflight | 32 | Max concurrent state-event presentations per poll pass. (32) |
--state-accept-timeout | 30 | Seconds the state dispatcher waits for the chassis to accept a presented event (routed into the tenant and admitted) before returning it to the queue with an attempt counted; an event accepted late is presented twice. (30) |
--state-run-timeout | 600 | Seconds a _state run may take once accepted. The dispatcher does not wait for it; this bounds the run itself. (600) |
--state-stale-after | 300 | Seconds a claimed state event may sit before the reclaim sweep returns it to pending so another node presents it — crash recovery for a node that died mid-presentation. Must exceed —state-accept-timeout. (300) |
--state-max-attempts | 5 | Presentations of one state event that may time out or be reclaimed before it is marked dead (the crash-loop guard); admission denials do not count. (5) |
--state-retention | 2592000 | Seconds to keep terminal (done/skipped/dead) state-event rows before the dispatcher purges them; pending rows are never purged. (2592000 = 30d) |
--state-max-data-bytes | 65536 | Byte cap for one state record’s data (txco://state/create and /transition). 0 = unlimited. (65536) |
--source-period | 30 | Seconds between source-watcher poll passes (the ‘source’ personality). Each pass reclaims stale claims, claims due sources (next_poll_at <= now), polls each for new items, fires them into the source’s <stack>/_source/0, then reschedules the source its own interval out (30). |
--source-max-inflight | 8 | Max concurrent source connections a poll pass opens; bounds fan-out (and outbound sockets) when many sources come due at once (8). |
--source-stale-after | 600 | Seconds a claimed source may sit before the reclaim sweep returns it to idle so another node retries — crash recovery for a node that died mid-poll (600). |
--source-batch | 50 | Max items one source yields per poll pass, so a first sync of a large mailbox drains over several passes instead of one huge fetch (50). |
--source-dispatch-timeout | 60 | Seconds to wait for one fetched item’s run to complete before treating it as failed (the item is not acked/advanced and is retried next pass) (60). |
--db-root-dir | ./chassis/data/db | What is the root directory for any local databases? (./chassis/data/db) |
--db-mirror-mode | memory | Where the read mirror (the SQLite snapshot of the runtime store every request path reads from) lives: ‘memory’ (default) keeps it in anonymous RAM; ‘file’ keeps it as a disposable SQLite file under —db-root-dir (mirror-<pid>-<gen>.db, journaling to RAM, no fsync), so its pages are reclaimable page cache and a reload builds the next generation on disk instead of holding two mirrors in RAM. Trades cold-page reads for a much smaller, elastic footprint — meant for a small node such as a dedicated DNS head. Stale files are swept at boot; the superseded generation is removed after the reload grace window. (memory) |
--db-schema-dir | ./db/schema/sqlite | What directory contains the db schema? (./db/schema/sqlite) |
--dial-timeout | 100ms | Default rpc dial timeout (100ms) |
--docker-build | true | Attempt to build Dockerfile on push? (true) |
--docker-remote | localhost:5001 | Remote docker host (localhost.5001) |
--docker-remote-user | admin | Remote docker user (admin) |
--docker-remote-pass | — | Remote docker user () |
--docker-tmp | ./chassis/data/tmp/docker | Temporary space for building docker (./chassis/data/tmp/docker) |
--docker-tmp-clean | true | Cleanup temporary tar after build? (true) |
--docker-api-version | 1.39 | Default Docker API version (1.39) |
--env | dev | Runtime Environment: {dev, stage, prod, myenv} (dev) |
--etcd-endpoint-addrs | localhost:2379 | Etcd endpoint addresses Ex: :2379 (:2379) |
--fqdn | — | Set our fully qualified domain name |
--ingress-config | — | Path to ingress YAML mapping (hostname/listener/job) → (tenant, stack). Empty disables ingress routing; events fall through to boot/%/0. |
--require-hostname-verification | false | When true, the data-plane router filters out unverified tenant_hostnames rows so they don’t route. Default permissive (false): unverified rows still route, the chassis logs a WARN once per row. Set true in production to gate routing on proof-of-ownership. |
--structured-host-suffix | — | When set (e.g. ‘.stacks.example.com’), the chassis auto-mints one tenant_hostnames row per activated stack at ’<stack>-<rand><suffix>’ so a freshly-applied stack is reachable with no manual binding. Empty (default) disables minting — embedders unchanged. txco dev injects ‘.localhost’ for zero-flag local use. |
--structured-dns-self | false | When true (and the ‘admin’ personality is enabled + —structured-host-suffix set), the chassis seeds + serves an authoritative WILDCARD zone for the suffix (its own A/MX/SPF + per-host DKIM/DMARC), instead of relying on upstream DNS. Off by default; turn on at cutover, once the suffix’s NS is delegated to this chassis (e.g. NS stacks.thanks.computer -> ns1/ns2.thanks.computer). (false) |
--verify-allow-private-addresses | false | When true, the HTTP-01 hostname verifier accepts hostnames that resolve to private/loopback/link-local IPs. Default false (production-safe, SSRF defense). txco dev flips it true so localhost-style workflows function. |
--ingress-miss-action | fallthrough | What happens when no tenant_hostnames row matches the incoming request: ‘fallthrough’ (default) dispatches to boot/%/0 so operator-authored boot rules can catch-all; ‘reject’ returns a clean HTTP 404 without invoking the processor. Set ‘reject’ in production deployments that route everything via tenant_hostnames. |
--k8s-namespace | default | Kubernetes Namespace (default) |
--kube-config | $USER/.kube/config | What path to use for Kubernetes Config? ($USER/.kube/config) |
--kube-check-incluster | true | Use to prefer in cluster service account over kube config. Tests if we’re running inside a cluster? (true) |
--kvstore | boltdb | Backend for the op-writable KV (txco://kv/*): {boltdb, redis}. boltdb is an embedded on-disk store; redis is a shared networked store (native TTL + atomic ops). (boltdb) |
--kvstore-addrs | ./chassis/data/kv | KVStore address(es). For redis: a bare host:port (plaintext), or a redis://|rediss:// URL — the rediss scheme selects TLS and the URL’s userinfo carries the username/password (e.g. a managed Redis: rediss://default:<token>@<db>.upstash.io:6379). For boltdb: the on-disk file path. (./chassis/data/kv) |
--kvstore-bucket | txco | KVStore bucket (boltdb only) (txco) |
--kvstore-password | — | Password for the redis KV backend. Empty (default) sends no AUTH — correct for boltdb or an unauthenticated redis on a trusted private network. Set it to match the redis ‘requirepass’ to authenticate the redis KV. A password in a rediss://user:pass@… kvstore-addrs URL takes precedence over this. () |
--kv-max-value-bytes | 65536 | Per-value byte cap for the txco://kv/* ops; a larger value errors. 0 = unlimited. Guards the store + envelope against oversized values (65536, 64KiB). |
--kv-max-ttl | 0 | Ceiling (seconds) on a txco://kv/set or kv/incr TTL; a larger requested ttl is clamped down to it. 0 = unlimited. Per-key TTL is opt-in — the default is a persistent key (no expiry). |
--blob-max-bytes | 33554432 | Decoded byte cap for a txco://blob/put value and a blob/get read into the envelope; larger errors as blob.error too_large. 0 = unlimited. BLOBS/ seed packs stream over the blob plane and are bounded by —dataset-max-file-bytes instead (33554432, 32MiB). |
--logger | env | Set Log display type: {env, production, dev, dev-plain} (env) |
--log-level | — | Set Logging Level: {debug, info, warn, error, dpanic, panic, and fatal} (info) |
--log-ops | disabled | Log operations to {logger,disabled,dir} (disabled) |
--log-ops-dir | ./chassis/data/logs | Directory to log operations to (./chassis/data/logs) |
--op-payload-max | 4194304 | maximum message that operations can send/receive in bytes (4194304) |
--op-metrics-regex | .* | Regex must match opname to include in Prometheus Logs. Default matches all. Empty string matches none. (.*) |
--op-timeout | 5s | Default operation timeout (5s) |
--op-timeout-max | 10m | Hard cap on per-op SYNC call timeout. WITH timeout overrides exceeding this are rejected at dispatch. Does NOT cap async ops. (10m) |
--max-fuel-per-request | 100000 | Per-request fuel ceiling. Each accounted action (scope-enter=10, repeat-transition=50, EXEC=25, secret-materialize=100, nano-op compute=10/ms, workspace wall-clock=10/s) accrues weighted cost; exhaustion halts the request with a structured txco_fuel_exhausted error. Catches expensive non-loop work (wide fan-out, secret floods). Set to 0 to disable enforcement (metering continues). (100000) |
--op-scope-ttl-max | 500 | Per-request stage-hop ceiling. Each Run entry decrements _txc.ttl; exhaustion halts with a structured txcl_scope_ttl_exhausted error. The cheap, loop-shape-specific system guard; catches tight loops and cross-stack ping-pongs faster than fuel can. Set to 0 to disable. (500) |
--op-loop-max | 1000 | Hard cap on LOOP … MAX, the per-op pass ceiling for a LOOP clause. An op asking for more is rejected at dispatch and dropped from the merge for that request. 0 = no cap. (1000) |
--loop-timeout | 60s | Default per-op timeout for a rule with a LOOP clause when WITH timeout is absent; it bounds the whole loop, every pass and pause included. Replaces the chassis-wide op-timeout (default 5s), which is too tight for a poll. Still capped by op-timeout-max. (60s) |
--op-repeat-penalty-ms | 20 | Sleep penalty in milliseconds when a request repeats a (from_stage, to_stage) transition. Throttles CPU consumption inside the TTL window. Set to 0 to disable. (20) |
--ai-chat-env-fallback | true | When an ai://chat backend’s required secret (e.g., OPENROUTER_KEY) is not found in the per-tenant secret store, fall back to a chassis-wide environment-variable lookup of the same name. Default true for developer convenience (‘export OPENROUTER_KEY=…’ just works); set false on shared deployments to enforce per-tenant isolation — tenants must provision their own keys. (true) |
--ai-default-timeout | 60s | Default per-op timeout for ai://* EXEC dispatches when WITH timeout is absent. Replaces the chassis-wide op-timeout (default 5s) which is too tight for LLM round-trips. Still capped by op-timeout-max. (60s) |
--embed-ollama-base-url | http://localhost:11434 | Base URL for the ai://embed ollama backend (local, keyless). nomic-embed-text and other local embedding models are reached at <base>/api/embed. Point this at a reachable Ollama on shared deployments, or use the OpenAI-direct backend instead. (http://localhost:11434) |
--decide-zero-data-retention | true | Ask the ai://decide provider not to retain request data. (true) |
--vector-db-path | ./chassis/data/vector.db | Path to the bundled vector store (SQLite + sqlite-vec) backing the txco://vector/* ops. Its parent dir is created on boot. A separate file from the runtime DB so large, independently-changing vectors never bloat the config-reload dump. (./chassis/data/vector.db) |
--vector-store | sqlite | Backend for the txco://vector/* ops: {sqlite}. sqlite is the bundled SQLite + sqlite-vec file at —vector-db-path. (sqlite) |
--search-store | bleve | Backend for the txco://search/* lexical search ops: {bleve,none}. bleve is the bundled Bleve engine, one index per collection under —search-path. none turns lexical search off, and the ops answer txco_search_disabled. (bleve) |
--search-path | ./chassis/data/search | Root directory of the bundled lexical search store. Created on boot. Each (tenant, collection) is its own index directory beneath it, named by hash. (./chassis/data/search) |
--search-max-open-indexes | 64 | How many collection indexes the bundled lexical search store holds open at once. Beyond it the least recently used idle index is closed and reopens on its next use. (64) |
--dev-auto-verify-local-hostnames | true | When true, hostname claims for dev-local patterns (localhost, .localhost,.local, *.local.thanks.computer) are auto-stamped with verified_at on creation, skipping the DNS-TXT round-trip. Removes a UX speed bump from the every-new-feature smoke loop on a developer machine. Set false on shared deployments so all hostnames go through proof-of-ownership. (true) |
--async-runtime-default | 10m | Default runtime budget for an async op (WITH mode=async) when WITH timeout is omitted; seeds the continuation’s expiry. Not capped by op-timeout-max. (10m) |
--async-ack-timeout | 5s | How long to wait for an async worker’s 202 handoff ack (not the worker’s runtime). (5s) |
--continue-after-default | 5s | Default deadline before a WITH mode=continuable op promotes from sync to continuation. Overridable per-op via WITH continue_after. Must be > 0 and < the op’s effective timeout. (5s) |
--continuable-timeout-default | 10m | Default runtime budget for a WITH mode=continuable op when WITH timeout is omitted. Bounds the upstream work both pre- and post-promotion. Not capped by op-timeout-max. (10m) |
--deferred-join-slack | 60s | Flat pad added to a deferred-join op’s runtime budget when computing the run’s reap deadline, covering downstream synchronous scopes. (60s) |
--compute-max-memory-mb | 32 | Per-invocation memory cap for a sandboxed compute (op://) in MB. (32) |
--compute-max-wall | 250ms | Per-invocation wall-clock cap for a sandboxed compute (op://); the guest is killed if it exceeds this. (250ms) |
--workspace-provider | — | Backend for workspace:// ops: {local, <overlay providers>}. Empty = workspace:// disabled (ops fail loudly). () |
--workspace-allow-local | false | Permit the local workspace provider (commands run as the chassis uid on this host, no isolation). Never implied by —env; must be set explicitly. (false) |
--workspace-local-root | ./chassis/data/workspaces | Root directory for local workspaces: <root>/<tenant>/<stack>/<name>. (./chassis/data/workspaces) |
--workspace-default-timeout | 5m | Default per-op timeout for a workspace:// exec when WITH timeout is absent — the whole dispatch (create/wake/run/capture); the command is killed when it expires. Sized for compiles, test suites and tool runs, not request/response calls. Capped by op-timeout-max. (5m) |
--workspace-max-output-bytes | 1048576 | Cap on captured stdout and stderr (each) per workspace exec; excess is dropped and flagged *_truncated. (1048576 = 1 MiB) |
--workspace-reap | 720h | Idle window after which the workspace reaper (a background service, where enabled) destroys a workspace: its files are gone and the next exec starts fresh. (720h = 30 days) |
--workspace-attach-max-duration | 8h | Ceiling on how long one workspace://<name>/attach binding (an interactive terminal on a WebSocket session) may live; the op’s WITH max_duration defaults to this and cannot exceed it. When it expires the lease ends, the process is killed and the socket is told. (8h) |
--workspace-connect-max-duration | 8h | Ceiling on how long one workspace://<name>/connect binding (a workspace-local service on a WebSocket session) may live; the op’s WITH max_duration defaults to this and cannot exceed it. When it expires the lease ends, the connection is closed and the socket is told. (8h) |
--workspace-services | — | Extra services the connect verb may bind, as name=port entries on the workspace’s own loopback (comma-separated), added to the built-in table (browser=5900). Operator-declared only: a stack names a service, never a port. () |
--run-grant-ttl-default | 600 | Seconds a run grant lasts when txco://delegate/mint gives no ttl. A run grant is what one piece of dispatched work may ask this chassis for; when it expires the work’s next request is refused. (600) |
--run-grant-ttl-max | 3600 | Ceiling, in seconds, on the ttl a stack may give a run grant. Longer work mints again: a grant is never extended. At most 86400. (3600) |
--run-grant-budget-default | 50 | Requests a run grant may make when txco://delegate/mint gives no budget. (50) |
--run-grant-budget-max | 1000 | Ceiling on the budget, in requests, a stack may give a run grant. At most 1000000. (1000) |
--grant-socket | — | Path of the Unix socket the launcher (‘txco sandbox’) reaches this chassis on, for the ‘grant’ personality. At most 100 bytes. Its directory is made this user’s own (0700). Empty puts it in a directory of its own under the system’s temp dir, named for —db-root-dir. () |
--grant-decide-timeout | 5s | How long a tenant’s _grant stack may take to decide one request made with a run grant. Past it the request is refused. (5s) |
--parent-url | — | Base URL of this node’s PARENT chassis, the one that dispatched the run it is working on and answers its capability calls: a rule’s EXEC “cap://<name>” POSTs to <parent-url>/v1/cap/<name> with the run grant the request arrived with. Empty (default) means this chassis has no parent and every cap:// call answers cap.error txco_cap_unconfigured. () |
--grant-refusal-window | 5s | How long a refused request is answered from memory, so a program asking again and again cannot run the tenant’s _grant stack without end. Only refusals are remembered. A change that would now allow the request takes up to this long to be seen. 0 turns it off. (5s) |
--personalities | cron,tcp,web,admin | Head types to start. Comma delimited. {cron,tcp,web,admin,lmtp,dns,mailmap,scheduled,imap,websocket,calendar,contacts,webdav,source,ipp,state,grant} (cron,tcp,web,admin) |
--shutdown-grace | 25s | On SIGTERM/SIGINT, how long in-flight runs get to finish before they are cancelled. The node drains first — new web requests get 503, new LMTP deliveries 451, the scheduled and source pollers claim nothing new — then waits for its requests and detached continuation work. 0 cancels at once. Give the container a stop timeout above this. (25s) |
--repl | false | Run REPL mode |
--prom-namespace | txco | Set the Prometheus namespace (txco) |
--prom-period | 5 | Set the Prometheus reporting period (5) |
--push-action-timeout | 300 | Timeout for push actions, in seconds (300) |
--registry-fixed | — | Set to use a fixed operation name registry. Prefix:Address:Port ex: *:localhost:5858 () |
--repoclone | file://./chassis/data/generator/ | What is the Git URL to use for new services (file://./chassis/data/generator/) |
--repostore | file | Which Repo Store to use? {memory, file} (file) |
--repostore-file-dir | ./chassis/data/repo | What is the root directory for the file repo store? (./chassis/data/repo) |
--continuation-store | file | Continuation/run store backend: {file} (file). s3 is a reserved enterprise seam. |
--continuation-store-file-dir | ./chassis/data/continuations | Root directory for the file continuation store (./chassis/data/continuations) |
--continuation-store-s3-bucket | — | Reserved: S3-compatible continuation store bucket (enterprise seam; unused in open core) |
--continuation-store-s3-prefix | — | Reserved: S3-compatible continuation store key prefix (enterprise seam; unused in open core) |
--continuation-callback-base-url | — | Base URL workers POST continuation results back to. Empty derives from —fqdn / web addr. |
--continuation-sweep-period | 900 | Seconds between continuation store sweeps; 0 disables the sweeper (900) |
--continuation-retention | 604800 | Seconds after a run’s expiry before its docs are purged (604800 = 7d) |
--continuation-stale-resume-after | 600 | Seconds a resume-claim may sit before the run is failed as resumer-stale (600) |
--artifact-store | file | Snapshot/event artifact store backend: {file} (file) |
--artifact-store-file-dir | ./chassis/data/artifacts | Root directory for the file artifact store (./chassis/data/artifacts) |
--filecas-store | file | Tenant FILES/ content-addressed store backend: {file} (file). s3 is the fleet overlay seam. |
--filecas-store-file-dir | ./chassis/data/filecas | Root directory for the file content-addressed store (./chassis/data/filecas) |
--filecas-store-s3-bucket | — | Reserved: S3-compatible filecas bucket (fleet overlay; unused in open core) |
--filecas-store-s3-prefix | — | Reserved: S3-compatible filecas key prefix (fleet overlay; unused in open core) |
--filecas-cache-bytes | 67108864 | In-memory LRU budget (bytes) fronting filecas Get (64MiB). 0 disables the cache. |
--filecas-max-file-bytes | 10485760 | Max size of a single FILES/ asset served from the CAS (10MiB); larger is indexed but 404s on serve. Also the per-entry LRU guard. |
--dataset-cache-dir | ./chassis/data/datasets | Node-local materialise cache for DATASETS/ artifacts (one <hash>.sqlite per content hash) fronting the filecas backend. Fleet nodes point this at persistent disk (e.g. /data/datasets). |
--dataset-cache-bytes | 4294967296 | Disk budget (bytes) for the dataset materialise cache; LRU eviction closes the read handle and removes the cached file (4GiB). 0 = unbounded. |
--dataset-max-file-bytes | 4294967296 | Max size of a single DATASETS/ artifact accepted by the blob upload endpoint and enforced again at activation (4GiB). |
--dataset-max-rows | 200 | Hard cap on rows a txco://dataset query returns; a query’s manifest max_rows and the rule’s WITH limit clamp under it (200). |
--outlet-max-rows | 500 | Row ceiling for one outlet://<name>/query or /exec result on this node; an outlet’s declared max_rows can only tighten it. Crossing it returns txco_outlet_result_too_large with no rows (never a prefix). (500) |
--outlet-max-bytes | 1048576 | Byte ceiling for one outlet result, measured while rows stream; crossing it returns txco_outlet_result_too_large with no rows (1MiB). |
--outlet-pool-max-conns | 4 | Max connections one outlet’s pool holds on this node; the minimum is always 0. A customer database sees roughly nodes × this many connections. (4) |
--outlet-pool-idle | 60s | How long an outlet pool keeps an unused connection open before closing it (60s). |
--outlet-idle-close | 5m | How long an outlet pool that no op has used stays open before the chassis closes it; the next call reopens it (5m). |
--outlet-egress | direct | How an outlet dials when its declaration sets no egress: direct (from this node’s own address) or relay (through —outlet-egress-relays, so connections originate from the relays’ addresses). A declaration’s egress field overrides it. (direct) |
--outlet-egress-relays | — | SOCKS5 relays for outlet egress: relay — ip:port on the fleet’s private network (or on the tunnel, with —outlet-egress-wg-config), tried in order. Empty means relay egress is unavailable on this node: an outlet asking for it fails with txco_outlet_connect_failed. () |
--outlet-pg-exec-mode | describe-exec | pgx execution mode for the postgres outlet driver: describe-exec (default; a describe round trip per statement, never stale, safe behind any pooler) or cache-describe (descriptions cached per connection; one round trip per statement). Both use the extended protocol. (describe-exec) |
--outlet-egress-wg-config | — | Path to a WireGuard configuration (wg-quick INI: [Interface] PrivateKey/Address, [Peer] PublicKey/Endpoint/AllowedIPs) the chassis brings up in-process — no kernel interface, no root — to reach —outlet-egress-relays by their tunnel addresses. Empty: relays are reached over the host network. The file holds a private key; keep it readable by the chassis only. () |
--snapshot-bootstrap-ref | — | If set AND the runtime DB is fresh, fetch this artifact ref and bootstrap-restore it before serving. Empty (default) = no bootstrap. |
--feed-source | nop | Control-event feed source: {nop, file}. nop (default) disables the applier; single-node unchanged. |
--feed-source-file-dir | ./chassis/data/feed | Root directory for the file feed source (./chassis/data/feed) |
--feed-poll-period | 15 | Seconds between control-event feed polls; applies when feed-source != nop (15) |
--feed-sink | nop | Control-event feed sink (producer): {nop, file}. nop (default) means admin mutations stay local; no events emitted. |
--feed-sink-batch-size | 64 | Max outbox rows drained per pump tick when feed-sink != nop (64) |
--room-relay | — | Cross-node room-message relay: empty (default) = in-process only (single node). () |
--egress-policy | private | Outbound op dial policy: {open, private}. private (default) blocks loopback/private/link-local/CGNAT/cloud-metadata and any egress-deny-cidrs — the SSRF-safe default for a chassis that runs tenant-authored ops. open allows any address; set it (e.g. —egress-policy=open, or an egress-allow-cidrs escape hatch) only when your own rules must reach internal/localhost services. ‘txco dev’ and start.sh opt into open for local development. |
--egress-deny-cidrs | — | Extra CIDRs the ‘private’ egress policy also blocks (comma-separated); for deployment-specific internal ranges. () |
--egress-allow-cidrs | — | CIDRs the ‘private’ egress policy allows even if otherwise blocked (comma-separated); explicit escape hatch for a trusted internal op endpoint. () |
--system-opstacks-dir | — | Optional workspace dir containing an OPS/ tree whose _-prefixed stacks (OPS/_sys/…) overlay the embedded system default. Empty uses the embedded default only (txco serve). txco dev points this at the workspace. |
--system-opstacks-watch | false | Watch the system-opstacks dir’s OPS/ tree and hot-recompile on change. Off for serve (static after boot); txco dev enables it. |
--read-file-max-bytes | 1048576 | Per-file byte cap for the txco://read-file op. Files larger than this are truncated (entry marked truncated) unless the op runs with strict=true, which errors instead. Guards the envelope against oversized inlined content (1048576, 1MiB). |
--sid | — | Set the Server Id () |
--lmtp-listen-addrs | :2424 | LMTP listen addresses. Comma list of ‘unix:/path’ or ‘:port’. Default :2424 (mirrors the chassis convention of high-port defaults; the well-known LMTP port is 24 but that needs root). Set to empty to explicitly disable the head even when ‘lmtp’ is in —personalities. (:2424) |
--lmtp-max-msg-bytes | 26214400 | Max accepted DATA message size in bytes. Postfix rejects with 552 on overflow. (26214400 ~= 25 MiB) |
--lmtp-max-recipients | 50 | Max RCPT TO addresses per LMTP transaction. (50) |
--lmtp-read-timeout | 30s | Per-command read timeout for the LMTP listener. (30s) |
--lmtp-data-timeout | 60s | DATA phase read timeout for the LMTP listener. (60s) |
--lmtp-resp-timeout | 30s | Pipeline response timeout (envelope dispatch → rule verdict) for an LMTP delivery. (30s) |
--lmtp-hostname | — | Greeting hostname for the LMTP server. Empty (default) uses os.Hostname(). () |
--lmtp-default-hosts | — | Comma list of hosts the chassis answers Strategy A on (tenant.stack[+mod]@<host> parses to <tenant>/<stack>). Empty (default) disables Strategy A. Multiple hosts allowed for operators running several MX-receiving names. () |
--mailmap-listen-addrs | — | Listen addresses for the mailmap head: a Postfix tcp_table(5) responder that answers the edge MTA’s relay_domains lookup (‘is <domain> an accepted mail domain?’) against tenant_hostnames. Comma list of ‘:port’/‘host:port’/‘unix:/path’. Empty (default) disables the head even when ‘mailmap’ is in —personalities. Bind only where the co-located Postfix reaches it (e.g. the compose network); never a public interface — the responder is unauthenticated. () |
--mailmap-read-timeout | 5s | Per-request read timeout for the mailmap tcp_table responder. (5s) |
--mail-relay-addr | — | SMTP submission address the txco://sendmail op hands outbound mail to (host:port), e.g. the edge txco-mail Postfix on the private net. Empty (default) disables sending — the op returns a clear ‘no relay configured’ error. () |
--mail-relay-tls | none | TLS mode dialing the mail relay: {none, starttls}. Default ‘none’ for a trusted private-net relay (same posture as the LMTP inlet); ‘starttls’ encrypts the hop but doesn’t verify the relay’s certificate (a private relay’s is self-signed). (none) |
--mail-dial-timeout-ms | 5000 | Dial+submit timeout for the mail relay, milliseconds. A down relay fails the send fast rather than hanging the request. (5000) |
--mail-max-recipients | 50 | Max recipients per txco://sendmail call (one personalized message + relay submit each, synchronously). Over the cap the op errors rather than truncating; bulk/async is a later story. (50) |
--mail-rate-limits | — | Per-tenant outbound send caps as comma-separated <count>/<duration> rules, e.g. “100/2m,200/4h”. A send is allowed only if EVERY rule is under its cap; over-limit recipients are skipped (reason rate_limited). In-memory, so PER NODE — fleet total is roughly cap×nodes (a runaway-loop safety valve, not fleet-wide accounting). Empty disables. () |
--mail-spam-thresholds | suspicious=5,spam=10 | Score bands for the inbound-mail spam verdict the LMTP inlet derives from an upstream Rspamd milter’s headers, as “suspicious=<score>,spam=<score>“. Sets _txc.mail.spam.verdict to clean/suspicious/spam from _txc.mail.spam.score (which is also exposed raw so txcl can band it independently). When Rspamd added no headers the score is unavailable and the verdict is “unknown”. (suspicious=5,spam=10) |
--tcp-listen-addrs | :5050 | Listen addresses for the TCP head. Comma list of ‘name=addr’ or bare ‘addr’. A named entry sets _txc.tcp.listener to that name for ingress routing (e.g. ‘webhooks=:5050,iot=:5051’); a bare entry keeps the back-compat name ‘default’. Every envelope also carries _txc.tcp.local.{ip,port} for rules that want to route on the raw bound port. Per-listener options follow the address, ’;‘-separated: ‘;tls’ terminates TLS with the bundled cert manager and makes the SNI hostname the routing fact (.host, matched against verified tenant hostnames); ‘;self-signed’ serves the dev certificate instead (implies tls; never for a public deployment); ‘;proxy=CIDR|CIDR’ makes it an edge-only door behind a TLS-terminating proxy — a PROXY v2 header (AUTHORITY/ALPN/SSL TLVs) is required from those networks and fills the same .host/.tls facts, anyone else is closed; never with tls. e.g. ‘irc=:6697;tls,raw=:5050’ or ‘edge=:16697;proxy=172.16.0.0/12|fdaa::/8’. (:5050) ‘;handler=NAME’ picks the protocol spoken on accepted connections (default ‘line’; ‘echo’ is the built-in example) and with it the inlet a hostname routes into: <stack>/_tcp for line, <stack>/_NAME otherwise. |
--tcp-connect-resp-timeout | 3s | Time that backends must accept a new connection before dropping it. (3s) |
--tcp-max-idle-timeout | 5s | Max idle time between commands. May be set lower at runtime. (5s) |
--tcp-resp-timeout | 10s | Max time for us to respond to command. (10s) |
--tcp-max-conns | 0 | Max open TCP-head connections on this node, all listeners; past the cap a new connection is answered with one ‘503 too many connections’ line and closed. 0 disables the cap. (0) |
--tcp-drain-timeout | 5s | On shutdown every open TCP-head connection is closed; this bounds how long the chassis waits for their handlers to unwind. (5s) |
--tcp-max-conns-per-tenant | 0 | Max open TCP-head connections per tenant on this node, counted once the connect run has routed; past it the connection is answered with one ‘503 too many connections’ line and closed. 0 disables the cap. (0) |
--tcp-conn-fuel | 100 | Fuel charged for accepting one TCP-head connection, pre-stamped on its connect run so it lands on that run’s usage event (the routed tenant’s; _sys for an unrouted connection). Bytes a connection moves outside a run are charged separately at the blob/KV rate (100 per MiB) on its next event. 0 disables the connect charge. (100) |
--tcp-handshake-timeout | 5s | Bound on the TLS handshake for a ‘;tls’ listener in —tcp-listen-addrs (a client that stalls its ClientHello is dropped), and on the PROXY header for a ‘;proxy=’ one. (5s) |
--dns-listen-addrs | :5354 | Authoritative-DNS listen addresses. Comma list; a bare ‘:port’ or ‘host:port’ binds UDP AND TCP on that address; a ‘udp:host:port’ or ‘tcp:host:port’ entry binds that ONE transport (for a front that delivers the two on different addresses — Fly needs ‘udp:fly-global-services:53,tcp:0.0.0.0:53’). DNS requires both transports to reach the head one way or another; a one-transport bind logs a warning. NOTE: the ‘udp:’/‘tcp:’ prefixes used to be ignored (both transports bound); they are now honoured. Default :5354 — deliberately NOT :5353 (that’s mDNS on macOS and clashes); the well-known DNS port 53 needs root/CAP_NET_BIND_SERVICE or a front LB. Set empty to disable the head even when ‘dns’ is in —personalities. (:5354) |
--dns-challenge-store | — | Where the transient _acme-challenge TXT records of an ACME DNS-01 solve are kept while a certificate issues: ” or ‘memory’ (default) = in this process, correct when it is the ONLY authoritative nameserver; ‘kv’ = the shared —kvstore (requires —kvstore=redis; refused otherwise), so a challenge written on any head — by the bundled solver or the RFC2136 receiver — is served by every head, which a CA validating against a multi-nameserver NS set requires. Makes heads SERVE one challenge; it does not coordinate certificate issuance between them (that is —cert-storage-dsn). () |
--dns-rrl-per-sec | 0 | Per-source-IP DNS response-rate-limit (queries/sec); over-limit queries are dropped (anti-amplification). 0 (default) disables. (0) |
--dns-nameservers | — | Authoritative nameserver hostnames advertised in synthesized zone NS records (and printed as delegation instructions on ‘txco dns zone create’). Comma list, e.g. ‘ns1.txco.io,ns2.txco.io’. Empty disables NS synthesis. () |
--dns-edge-ips | — | Edge IPv4/IPv6 addresses synthesized as the A/AAAA target for a delegated zone’s apex and per-stack hosts. Comma list, e.g. ‘203.0.113.10’. Empty disables A/AAAA synthesis. () |
--dns-mx-host | — | Mail exchanger hostname synthesized as the MX target for delegated-zone hosts (the chassis LMTP head’s public name). Empty disables MX synthesis. () |
--dns-mx-priority | 10 | Preference value for synthesized MX records. (10) |
--dns-synth-ttl | 60 | TTL (seconds) applied to synthesized pattern records. (60) |
--dns-spf | — | Override the apex SPF TXT synthesized for delegated mail zones. Empty (default) auto-derives ‘v=spf1 ip4:<edge-ips> mx ~all’ (softfail) so outbound from the relay passes. Only emitted when —dns-mx-host is set. () |
--dns-dmarc | v=DMARC1; p=none | DMARC policy TXT synthesized at _dmarc.<zone> for delegated mail zones. Default p=none (monitor, no rejection) with no rua (no automated report mailbox yet). Empty disables. Only emitted when —dns-mx-host is set. (v=DMARC1; p=none) |
--dns-imaps-port | 0 | Port advertised in synthesized RFC 6186 _imaps._tcp SRV records for delegated zones — at the apex and every per-stack host, target = the name itself; the default-suffix wildcard zone advertises imap.<suffix> (one target under the wildcard certificate) — for mail clients that implement RFC 6186 discovery (Thunderbird does not — it fetches the /.well-known/autoconfig XML a stack can serve; see docs/advanced/protocols/imap.md). 0 (default) emits no SRV. Set 993 only when an IMAPS front door serves every hostname of the zone. (0) |
--dns-caldavs-port | 0 | Port advertised in synthesized RFC 6764 _caldavs._tcp SRV records for delegated zones (at the apex and every per-stack host, target = the name itself, with a TXT “path=/.well-known/caldav” beside it; the default-suffix wildcard zone advertises caldav.<suffix>) — for calendar clients that discover a server from an e-mail address. 0 (default) emits no SRV. Set 443 when the ‘calendar’ personality serves every hostname of the zone. (0) |
--dns-carddavs-port | 0 | Port advertised in synthesized RFC 6764 _carddavs._tcp SRV records for delegated zones (at the apex and every per-stack host, target = the name itself, with a TXT “path=/.well-known/carddav” beside it; never on the default-suffix wildcard) — for contacts apps that discover a server from an e-mail address. 0 (default) emits no SRV. Set 443 when the ‘contacts’ personality serves every hostname of the zone. (0) |
--dns-ipp | false | Synthesize ipp.<zone> A/AAAA (the edge IPs) for every delegated pattern zone — the hostname the ‘ipp’ personality answers on (ipps://ipp.<zone>/p/<printer>). Computed at snapshot build, so zones created before the flag was set get the name on the next reload. false (default) emits nothing. Set true when the ‘ipp’ personality serves the fleet. (false) |
--dns-tenant-zone-management | false | Escape hatch: allow tenants holding the dns:capability to manage their OWN delegated zones + override records (and render). Default false — DNS zone management is operator-only (super-admin), since delegating zone control to tenants is a sharp edge we don’t encourage. The chassis-global synthesis config (—dns- / ‘dns config set’) is always super-admin regardless. |
--dns-require-zone-verification | false | Require a delegated zone’s NS to resolve to —dns-nameservers before it confers ANY authority (DKIM signing, verified-sender, inbound routing, authoritative serving). Default false — a created zone is trusted immediately (dev / single-operator). Set true for multi-tenant self-service: ‘txco dns zone create’ leaves the zone PENDING until ‘txco dns zone verify’ confirms the NS delegation, closing the squatting hole. (false) |
--dns-update-tsig-key-name | — | TSIG key name authorizing RFC2136 dynamic UPDATE of _acme-challenge TXT records (lets an external ACME client, e.g. Caddy’s caddy-dns/rfc2136, inject DNS-01 challenges into this authoritative server). Empty disables the UPDATE path entirely — every UPDATE is refused. Both this and —dns-update-tsig-secret must be set to enable it. () |
--dns-update-tsig-secret | — | Base64-encoded shared secret for the —dns-update-tsig-key-name TSIG key (same value configured in the ACME client). Keep it out of shell history; prefer the env var TXCO_DNS_UPDATE_TSIG_SECRET. () |
--dns-observe-sample | 1 | DNS observe tap: after a query in a delegated zone is answered on the wire, a compact record of it (question, client, reply) is dispatched fire-and-forget into the zone tenant’s _dns stack — the stack’s existence is the subscription, like _cron. 1 (default) taps every answered query; N taps one in N; 0 disables the tap. Queries the head refuses (unserved names), drops (RRL), or receives as RFC2136 UPDATEs are never tapped. Each tapped query is a normal (fuel-metered) run of the tenant’s _dns stack. (1) |
--dns-observe-max-inflight | 8 | Max concurrent observe-tap dispatches into _dns stacks. Tapped queries wait in a bounded in-memory queue; when it is full the tap drops (chassis.dns.observe outcome=dropped) rather than ever delaying a wire reply. (8) |
--dns-stack-deadline-ms | 1500 | Stack-answered zones (txco dns zone set <origin> —answer stack): how long the head waits for the tenant’s _dns stack to EMIT @dns.res before answering with the zone’s fallback (proposal or servfail). The run is not cancelled at the deadline — a late answer still warms the answer cache. Resolvers retry at ~1-2s, so keep this well under that. (1500) |
--dns-stack-dispatch-per-sec | 20 | Per-zone ceiling on _dns stack dispatches per second for stack-answered zones; queries over the limit answer with the zone’s fallback instead of queueing (a random-subdomain flood defeats the answer cache by construction, so this is the real cost ceiling). 0 disables the limiter (dev). (20) |
--imap-listen-addrs | — | Plaintext IMAP listen addresses for the ‘imap’ personality. Comma list of ‘:port’ or ‘host:port’. Empty (default) — no default port: a front proxy (edge Caddy layer4, nginx stream) terminates TLS and forwards here, or use —imap-tls-addrs. The head stays silent when both lists are empty even with ‘imap’ in —personalities. () |
--imap-tls-addrs | — | Implicit-TLS (IMAPS) listen addresses, e.g. ‘:993’. The certificate comes from —imap-tls-cert-file/—imap-tls-key-file when set, else from the bundled cert manager (ACME DNS-01 against the ‘dns’ head; —imap-hostname is added to the managed set). Empty (default) disables IMAPS. () |
--imap-hostname | — | Public hostname of the IMAP head (e.g. imap.example.com). Added to the bundled cert manager’s managed names when —imap-tls-addrs is set without cert files. () |
--imap-tls-cert-file | — | PEM certificate chain for —imap-tls-addrs, obtained by anything else (certbot, a same-host Caddy). With —imap-tls-key-file it bypasses the bundled cert manager. () |
--imap-tls-key-file | — | PEM private key matching —imap-tls-cert-file. () |
--imap-self-signed | false | Serve a self-signed certificate (minted in memory at boot; loopback + the dev-local hostname patterns + —imap-hostname) when no cert files and no bundled cert manager apply — so a desktop mail client, which refuses LOGIN over plaintext, can connect with STARTTLS on —imap-listen-addrs or IMAPS on —imap-tls-addrs and trust the certificate once. txco dev —imap turns this on. Never for a public deployment. (false) |
--imap-wire-debug | false | Log every IMAP command and response line at DEBUG (chassis.imap.wire). Includes credentials in the clear — for diagnosing a mail client on a dev machine only. (false) |
--imap-store | sqlite | Backend for the IMAP mailbox index (accounts, mailboxes, message rows; bytes live in the content store): sqlite (bundled), or a backend an overlay registers (the hosted build: postgres, reading TXCO_DB_AUTH_DSN). sqlite is a per-node file at —imap-db-path, opened only when ‘imap’ is in —personalities — never the runtime DB. Any other backend is SHARED and is opened on every node, so txco://imap/* on any node project into the one index the head serves; if it fails to open on a node without the head, the ops answer txco_imap_disabled there until restart. (sqlite) |
--imap-db-path | ./chassis/data/imap.db | Path to the bundled IMAP index SQLite file (used by —imap-store=sqlite; ignored by other backends). Its parent dir is created on boot. (./chassis/data/imap.db) |
--notebook-store | sqlite | Backend for the notebook store (txco://notebook/*: append-only records per tenant/namespace/name): sqlite (bundled), or a backend an overlay registers (the hosted build: postgres, reading TXCO_DB_NOTEBOOK_DSN, else TXCO_DB_AUTH_DSN). sqlite is a per-node file at —notebook-db-path — never the runtime DB. The store opens on every node; a non-sqlite backend that fails to open answers txco_notebook_disabled until restart. (sqlite) |
--notebook-db-path | ./chassis/data/notebook.db | Path to the bundled notebook SQLite file (used by —notebook-store=sqlite; ignored by other backends). Its parent dir is created on boot. (./chassis/data/notebook.db) |
--notebook-max-entry-bytes | 65536 | Per-entry byte cap for the data of a txco://notebook/append; a larger value errors as txco_notebook_too_large. 0 = unlimited. (65536, 64KiB) |
--notebook-max-read-rows | 1000 | Page ceiling for txco://notebook/read and the admin read endpoint; a WITH limit clamps under it. The default page (no limit given) is 100. (1000) |
--notebook-max-ttl | 0 | Upper bound in seconds for a notebook entry TTL (WITH ttl, or a head default); longer requests are clamped. 0 = unlimited. (0) |
--notebook-max-export-bytes | 8388608 | Byte cap for one txco://notebook/export response body; the export stops on a line boundary, reports truncated, and returns a cursor to resume from. 0 = unlimited. (8388608, 8MiB) |
--notebook-sweep-period | 10m | How often each node deletes expired notebook entries, in batches of —notebook-sweep-batch. Expired entries are already invisible to reads; the sweep reclaims space. 0 disables. (10m) |
--notebook-sweep-batch | 1000 | Rows deleted per notebook sweep statement; a sweep repeats until a batch comes back short. (1000) |
--imap-insecure-auth | false | Accept LOGIN on a plaintext connection. For txco dev (loopback) and behind-a-proxy deployments where TLS terminates upstream; leave false when clients reach the plaintext port directly. (false) |
--imap-max-conns-per-account | 16 | Max simultaneous authenticated IMAP connections per account (desktop clients open 5-10 per wake). 0 disables the cap. (16) |
--imap-login-rate | 10 | Max IMAP LOGIN commands per minute, applied per client IP and per username independently, before any lookup: a flood guard for the command itself; attempts over the limit answer NO [LIMIT]. Password checks are limited separately, across every head, by —login-rate. 0 disables. (10) |
--imap-refuse-bare-usernames | false | Refuse an IMAP LOGIN whose username has no @. By default a bare local part (“paris”) signs in when it names exactly one account on the whole chassis — mail clients send it when the address domain and the server name line up — but that lookup cannot be scoped to a tenant (the IMAP head knows no hostname at login). Each such login is logged with bare=true: read that before turning this on, because every client that relies on it must then be given its full address. A later release turns it on by default. (false) |
--login-rate | 30 | Max password checks per minute, per client IP and per principal, shared by every head that signs in with a credential (imap, calendar, contacts, webdav, ipp): a guess over CalDAV spends the same budget as one over IMAP. Counted only on verified-login-cache misses (a DAV client sends its password with every request; hits cost nothing). Over the limit answers 429 (DAV, IPP) or NO [LIMIT] (IMAP) without touching the password. Behind a front proxy the DAV and IPP heads see the proxy’s address, so every client it fronts shares one per-IP bucket, unless —web-trusted-proxies names the proxy. 0 disables. (30) |
--imap-sync-interval | 15s | How often the IMAP head re-reads the modseq of every SELECTed mailbox from the index and delivers what changed (EXISTS / EXPUNGE / FETCH FLAGS, including to IDLE clients). Writes made in this process are delivered at once; the tick covers writes from other nodes against a shared index (ops elsewhere, a second head). One indexed point read per selected mailbox per tick, a full re-read only when the modseq moved. 0 disables the tick: remote changes then surface on a client’s next command only. (15s) |
--imap-resp-timeout | 30s | Answer lane: how long the IMAP head waits for the tenant’s _imap stack to EMIT @imap.res before answering NO [UNAVAILABLE] for a mailbox whose policy says ‘stack’. The run keeps its own 60s context; a late answer is discarded. (30s) |
--imap-observe-sample | 1 | Observe lane: after a client mutation commits (append, move, copy, expunge, create, delete, rename; flags only where a mailbox opts in), a record of it is dispatched fire-and-forget into the account tenant’s _imap stack — the stack’s existence is the subscription, like _dns. 1 (default) observes every mutation; N one in N; 0 disables the lane. Each observed mutation is a normal (fuel-metered) run. (1) |
--imap-observe-max-inflight | 8 | Max concurrent observe-lane dispatches into _imap stacks; over the bounded queue the observation is dropped (chassis.imap.observe outcome=dropped) rather than ever delaying the client. (8) |
--imap-proxy-protocol | — | CIDRs of front proxies allowed to prefix connections with a PROXY protocol (v1/v2) header — the real client IP then survives a TLS-terminating edge (Caddy layer4, haproxy) for throttles and the envelope’s _txc.client.ip. Connections from other addresses are served as-is (a header from them is not honoured). Empty (default) disables. () |
--web-trusted-proxies | — | CIDRs (or bare IPs) of the HTTP proxies in front of the web head. When a request’s socket peer is one of them, the client address is read from X-Forwarded-For: the first address from the right that is not itself a trusted proxy, so nothing a client types into the header is ever reached. It is what the calendar, contacts, webdav and ipp heads key their per-IP login limits on (and log), what the websocket head records, and the ip in the web access log. From any other peer the header is ignored. Empty (the default) trusts nobody: the client is the socket peer, which behind a proxy is the proxy — every client then shares one per-IP login budget. Several entries may be separated by spaces or commas. The HTTP counterpart of —imap-proxy-protocol. (none) |
--imap-append-max-bytes | 33554432 | Max rendered message size a txco://imap/append may store. Bytes go to the content store and only references ride the envelope, so this matches —blob-max-bytes rather than an envelope cap. (33554432, 32 MiB) |
--calendar-store | sqlite | Backend for the calendar index (accounts, calendars, iCalendar objects — the objects live here, never the blob CAS): sqlite (bundled), or a backend an overlay registers (the hosted build: postgres, reading TXCO_DB_AUTH_DSN). sqlite is a per-node file at —calendar-db-path, opened only when ‘calendar’ is in —personalities — never the runtime DB. Any other backend is SHARED and is opened on every node, so txco://calendar/* on any node project into the one index the head serves; if it fails to open on a node without the head, the ops answer txco_calendar_disabled there until restart. (sqlite) |
--calendar-db-path | ./chassis/data/calendar.db | Path to the bundled calendar index SQLite file (used by —calendar-store=sqlite; ignored by other backends). Its parent dir is created on boot. (./chassis/data/calendar.db) |
--calendar-path-prefix | /dav | URL prefix the ‘calendar’ personality reserves on EVERY hostname the web head serves (plus /.well-known/caldav, which redirects into it): CalDAV under <prefix>/<username>/…, ICS feeds under <prefix>/feed/<token>.ics. Requests here are answered from the calendar index and never run a stack. Move it when a tenant’s own routes need /dav. (/dav) |
--calendar-insecure-auth | false | Accept Basic authentication on a plaintext request. Off (default), a request must arrive over TLS — the chassis’s own —web-tls-addr listener, or X-Forwarded-Proto: https from a front proxy that terminates TLS (the same trust the admin surface extends). For txco dev only. (false) |
--calendar-resp-timeout | 30s | Answer lane: how long the calendar head waits for the tenant’s _calendar stack to EMIT @calendar.res before answering 403 for a calendar whose policy says ‘stack’. The run keeps its own 60s context; a late answer is discarded. (30s) |
--calendar-observe-sample | 1 | Observe lane: after a client mutation commits (put, delete, mkcalendar, remove, proppatch where the calendar’s policy says observe), a record of it is dispatched fire-and-forget into the account tenant’s _calendar stack — the stack’s existence is the subscription, like _imap. 1 (default) observes every mutation; N one in N; 0 disables the lane. Each observed mutation is a normal (fuel-metered) run. (1) |
--calendar-observe-max-inflight | 8 | Max concurrent observe-lane dispatches into _calendar stacks; over the bounded queue the observation is dropped (chassis.calendar.observe outcome=dropped) rather than ever delaying the client. (8) |
--calendar-object-max-bytes | 1048576 | Size cap for one iCalendar object, for txco://calendar/put and a client PUT (413 over it; also advertised as CALDAV:max-resource-size). Objects live in the index, so keep this small. (1048576, 1 MiB) |
--calendar-feed-max-age | 300 | Cache-Control max-age (seconds) on ICS feed responses, so a subscription poller (Google Calendar, Outlook) that respects it re-reads at most this often. The feed carries an ETag either way. (300) |
--contacts-store | sqlite | Backend for the contacts index (accounts, address books, vCard objects — the objects live here, never the blob CAS): sqlite (bundled), or a backend an overlay registers (the hosted build: postgres, reading TXCO_DB_AUTH_DSN). sqlite is a per-node file at —contacts-db-path, opened only when ‘contacts’ is in —personalities — never the runtime DB. Any other backend is SHARED and is opened on every node, so txco://contacts/* on any node project into the one index the head serves; if it fails to open on a node without the head, the ops answer txco_contacts_disabled there until restart. (sqlite) |
--contacts-db-path | ./chassis/data/contacts.db | Path to the bundled contacts index SQLite file (used by —contacts-store=sqlite; ignored by other backends). Its parent dir is created on boot. (./chassis/data/contacts.db) |
--contacts-path-prefix | /carddav | URL prefix the ‘contacts’ personality reserves on EVERY hostname the web head serves (plus /.well-known/carddav, which redirects into it): CardDAV under <prefix>/<username>/addressbooks/…. Requests here are answered from the contacts index and never run a stack. Must differ from —calendar-path-prefix. Move it when a tenant’s own routes need /carddav. (/carddav) |
--contacts-insecure-auth | false | Accept Basic authentication on a plaintext request. Off (default), a request must arrive over TLS — the chassis’s own —web-tls-addr listener, or X-Forwarded-Proto: https from a front proxy that terminates TLS (the same trust the admin surface extends). For txco dev only. (false) |
--contacts-resp-timeout | 30s | Answer lane: how long the contacts head waits for the tenant’s _contacts stack to EMIT @contacts.res before answering 403 for an address book whose policy says ‘stack’. The run keeps its own 60s context; a late answer is discarded. (30s) |
--contacts-observe-sample | 1 | Observe lane: after a client mutation commits (put, delete, mkaddressbook, remove, proppatch where the address book’s policy says observe), a record of it is dispatched fire-and-forget into the account tenant’s _contacts stack — the stack’s existence is the subscription, like _calendar. 1 (default) observes every mutation; N one in N; 0 disables the lane. Each observed mutation is a normal (fuel-metered) run. (1) |
--contacts-observe-max-inflight | 8 | Max concurrent observe-lane dispatches into _contacts stacks; over the bounded queue the observation is dropped (chassis.contacts.observe outcome=dropped) rather than ever delaying the client. (8) |
--contacts-object-max-bytes | 1048576 | Size cap for one vCard object, for txco://contacts/put and a client PUT (413 over it; also advertised as CARDDAV:max-resource-size). A contact photo is a few hundred KB; objects live in the index, so keep this small. (1048576, 1 MiB) |
--drive-store | sqlite | Backend for the drive INDEX (collections, accounts, resource rows — names, versions, hierarchy; the bytes live in —drive-objects): sqlite (bundled), or a backend an overlay registers (the hosted build: postgres, reading TXCO_DB_AUTH_DSN). sqlite is a per-node file at —drive-db-path, opened only when ‘webdav’ is in —personalities — never the runtime DB. Any other backend is SHARED and is opened on every node, so txco://drive/* on any node project into the one index the head serves; if it fails to open on a node without the head, the ops answer txco_drive_disabled there until restart. (sqlite) |
--drive-db-path | ./chassis/data/drive.db | Path to the bundled drive index SQLite file (used by —drive-store=sqlite; ignored by other backends). Its parent dir is created on boot. (./chassis/data/drive.db) |
--drive-objects | file | Object store for drive resource BYTES: file (bundled, a directory at —drive-objects-file-dir), or a backend an overlay registers (the hosted build: s3). Every node that opens the drive index opens this too. (file) |
--drive-objects-file-dir | ./chassis/data/drive | Root directory for the bundled file drive object store (used by —drive-objects=file). One immutable file per stored version under <tenant>/<collection>/<resource>/<version>. (./chassis/data/drive) |
--drive-path-prefix | /drive | URL prefix the ‘webdav’ personality reserves on EVERY hostname the web head serves: the mount URL is https://<host><prefix>/ and the authenticated account’s collection is its root. Requests here are answered from the drive index and never run a stack. Must differ from —calendar-path-prefix and —contacts-path-prefix. Move it when a tenant’s own routes need /drive. (/drive) |
--drive-insecure-auth | false | Accept Basic authentication on a plaintext request. Off (default), a request must arrive over TLS — the chassis’s own —web-tls-addr listener, or X-Forwarded-Proto: https from a front proxy that terminates TLS (the same trust the admin surface extends). For txco dev only. (false) |
--drive-max-file-bytes | 4294967296 | Size cap for one drive file, for a client PUT (413 over it) and txco://drive/put. Bytes stream to the object store, so this bounds storage, not memory. 0 = unlimited. (4294967296, 4 GiB) |
--drive-max-collection-bytes | 0 | Cap on a collection’s total live bytes; a write past it answers 507 (WebDAV) or txco_drive_quota (ops). 0 = unlimited. (0) |
--drive-max-resources | 0 | Cap on a collection’s live files + directories; a create past it answers 507 (WebDAV) or txco_drive_quota (ops). 0 = unlimited. (0) |
--drive-op-max-bytes | 33554432 | Cap on the bytes txco://drive/put accepts from the envelope and txco://drive/get returns into it (both are buffered JSON, unlike the streaming head). A larger file is stored and served by the head but read by an op only up to this cap (txco_drive_too_large). 0 = unlimited. (33554432, 32 MiB) |
--signed-url-base | — | Public origin (scheme://host[:port], no path) that txco://drive/sign mints its URLs on; the web head serves them at /_txc/signed/<token> on every hostname, so any name that reaches it works. Empty derives from —continuation-callback-base-url, then —fqdn / web addr. |
--drive-sweep-period | 900 | Seconds between drive sweeps on a node running the ‘webdav’ head: superseded versions and the objects of failed writes are reclaimed, tombstones past —drive-tombstone-retention hard-deleted. Idempotent, so several heads sweeping is wasteful, not wrong. 0 disables. (900) |
--drive-sweep-grace | 3600 | Seconds an object must be older than before the sweeper may reclaim it — covers a put whose bytes landed before its index row and a reader still streaming a version that was just replaced. (3600) |
--drive-tombstone-retention | 604800 | Seconds a deleted resource’s tombstone row stays, so a txco://drive/list since=<modseq> consumer can learn of the deletion; the sweeper hard-deletes older ones. Bytes are reclaimed after —drive-sweep-grace regardless. (604800 = 7d) |
--websocket-max-conns | 8192 | Max open WebSocket sessions on this node, all tenants; an upgrade past the cap answers 503 with Retry-After. A memory guard, not a throughput limit: an idle session costs ~50 KB and no processor time, and message work is bounded by tenant admission. Keep it under the process’s file-descriptor limit and under any front proxy’s connection cap. 0 disables the cap. Needs ‘websocket’ (with ‘web’) in —personalities. (8192) |
--websocket-max-conns-per-tenant | 2048 | Max open WebSocket sessions per tenant on this node; past it an upgrade answers 503 with Retry-After. Stops one tenant from taking a node’s whole session budget. 0 disables the cap. (2048) |
--websocket-max-message-bytes | 262144 | Max bytes of one complete WebSocket message, inbound (a larger one closes the session with 1009) and outbound (txco://websocket/send answers txco_websocket_message_too_large). Text and binary alike; a stack may lower it per session at accept. (262144, 256 KiB) |
--websocket-inbound-queue | 16 | Complete inbound messages a session may hold while its previous message is still running (runs are strictly serialized per session). When the queue is full the session is closed with 1013 rather than growing memory. (16) |
--websocket-run-timeout | 60s | Deadline for the processor run one inbound WebSocket message makes (<stack>/_websocket/0). A late result is discarded; the session stays open. (60s) |
--websocket-idle-timeout | 5m | Close a session (1000) after this long without an application message in either direction; ping/pong does not count. A stack may set a longer one per session at accept, up to —websocket-max-idle-timeout. (5m) |
--websocket-max-idle-timeout | 1h | Ceiling for a per-session idle_timeout a stack asks for at accept. (1h) |
--websocket-ping-interval | 25s | Chassis-level liveness: a ping frame every interval, and the pong must arrive before the next; a silent peer is closed (1011). Keep it under any proxy’s HTTP idle timeout on the path (fly-proxy: ~60s). (25s) |
--websocket-write-timeout | 10s | Deadline for one outbound write (a txco://websocket/send or reply). A peer that does not read within it has its session closed (1011) — messages are never silently dropped. (10s) |
--websocket-drain-timeout | 5s | On shutdown every session is closed with 1001 (going away); this bounds how long the chassis waits for those close handshakes. (5s) |
--websocket-relay | — | Cross-node delivery for txco://websocket/send, reply and close: empty (default) = a session is reachable only on the node holding its socket. Names a registered relay backend; needs a shared —kvstore (redis), which records the node owning each session. () |
--ipp-store | sqlite | Backend for the ipp personality’s JOB store (one row per print job: receiving → committed → delivered): {sqlite}. sqlite is the bundled SQLite file at —ipp-db-path; a downstream overlay can register a shared backend so a job committed on one node is handed to the bus by another. Documents are never stored here — they stream into the file CAS. (sqlite) |
--ipp-db-path | ./chassis/data/ipp.db | Path to the bundled ipp job store SQLite file (used by —ipp-store=sqlite; ignored by other backends). Its parent dir is created on demand. (./chassis/data/ipp.db) |
--ipp-formats | application/pdf | Document formats every printer advertises (document-format-supported) and accepts, first = the default. A job’s declared format must be listed AND the first bytes of the document must look like it. application/postscript is never accepted whatever is listed. (application/pdf) |
--ipp-max-job-bytes | 268435456 | Size cap for one printed document. Bytes stream into the file CAS, so this bounds a job, not memory. Over it the job is refused with client-error-request-entity-too-large and nothing is stored. (268435456 = 256 MiB) |
--ipp-max-inflight | 4 | Max documents one tenant may be uploading at once; over it a new job gets server-error-busy (print clients retry). 0 = unlimited. (4) |
--ipp-insecure-auth | false | Accept Basic authentication on a plaintext request. Off (default), a request must arrive over TLS — the chassis’s own —web-tls-addr, or a front proxy that sets X-Forwarded-Proto: https. Dev only. (false) |
--ipp-anonymous-attributes | false | Answer Get-Printer-Attributes without credentials. Off (default): NOTHING on an ipp host is answered without the password — a bare request is challenged (401) before its body is read, and the client authenticates and asks again. Turn on only if a print client cannot add the printer otherwise (some query a printer’s capabilities while ADDING it, before they have a password to offer); the anonymous answer carries nothing tenant-specific (the fixed capability set + the printer label from the URL), but it does confirm that a printer exists at that hostname. Every other operation always authenticates. (false) |
--ipp-poll-interval | 1 | Seconds between dispatcher passes that hand committed print jobs to the bus. A freshly committed job also nudges the dispatcher, so this is the retry cadence, not the delivery latency. (1) |
--ipp-dispatch-timeout | 10 | Seconds the dispatcher waits for the bus to ACCEPT one job’s envelope before releasing it for a later pass. It never waits for the stack’s run. (10) |
--ipp-lease-stale-after | 600 | Seconds a dispatcher’s lease on a committed job may sit before another node may take it — crash recovery for a node that died mid-handoff. (600) |
--ipp-max-attempts | 20 | Delivery attempts before a committed job the bus never accepted is marked failed. 0 = retry forever. (20) |
--ipp-receive-timeout | 600 | Seconds a job may sit in ‘receiving’ with no document (a Create-Job never followed by Send-Document, or an upload whose node died) before it is failed. Advertised as multiple-operation-time-out. (600) |
--ipp-retention | 604800 | Seconds to keep terminal (delivered/canceled/failed) job rows before the dispatcher purges them. The documents stay in the CAS. (604800 = 7d) |
--ipp-wire-debug | false | Log every IPP request’s operation and the NAMES of the attributes it carried and requested (never their values: job names and user names are private). For recording what a print client actually sends. (false) |
--web-tls-self-signed | false | Serve —web-tls-addr with a self-signed certificate (minted once under —web-tls-self-signed-cert-dir; loopback + the dev-local hostname patterns + —web-tls-self-signed-hosts) instead of the ACME certificate manager. Dev only: a print client or browser must be told to trust it. (false) |
--web-tls-self-signed-cert-dir | ./chassis/data | Directory holding web-selfsigned.crt/.key for —web-tls-self-signed; kept across restarts so the certificate is trusted once. (./chassis/data) |
--web-tls-self-signed-hosts | — | Extra DNS names for the —web-tls-self-signed certificate, beyond localhost, .localhost and.local.thanks.computer. |
--web-tls-addr | — | HTTPS listen address for the bundled TLS terminator (e.g. ‘:8443’). Empty (default) means the chassis serves plain HTTP on —web-addr and a front proxy terminates TLS. When set, the chassis terminates TLS itself, obtaining + renewing wildcard certificates for delegated zones via ACME DNS-01 against its own authoritative DNS head — requires the ‘dns’ personality and —acme-email. () |
--acme-email | — | ACME account contact email for the bundled cert manager (recommended by CAs for expiry notices). Required when —web-tls-addr is set against a public CA. () |
--acme-ca | — | ACME directory URL. Empty (default) uses Let’s Encrypt production. Point at LE staging while testing, or a local Pebble/step-ca directory (e.g. https://localhost:14000/dir) for an offline smoke test. () |
--acme-ca-root-file | — | Path to a PEM root-CA bundle to trust as the ACME CA’s root, for a CA not in the system trust store (Pebble/step-ca). Empty (default) uses the system roots — correct for Let’s Encrypt. () |
--acme-dns-resolvers | — | DNS resolvers the bundled cert manager uses for zone discovery + DNS-01 propagation checks. Empty (default) queries the zone’s authoritative servers directly (correct in production). Point at this chassis’s own DNS head (e.g. 127.0.0.1:5354) for an offline/localhost solve. () |
--cert-storage-dsn | — | Storage backend for issued certificates + the ACME account. Empty (default) stores them on the local filesystem at —cert-storage-path (single-node). A recognised scheme (e.g. postgres://…) uses a shared backend so any node loads the same certs and issuance is serialised. () |
--cert-storage-path | acme | Filesystem directory for the bundled cert/account store when —cert-storage-dsn is empty. (acme) |
--web-addr | :8080 | The port to listen on for the web server (:8080) |
--web-pass | — | Basic Auth password () |
--web-user | — | User for basic auth () |
--web-idle-timeout | 60 | Idle timeout, seconds (60) |
--web-read-timeout | 15 | Read timeout, seconds (15) |
--web-write-timeout | 15 | Write timeout, seconds (15) |
--web-max-body-bytes | 31457280 | Max web-inlet request-body size in bytes; a larger body is rejected with 413 before it is buffered into the envelope (bounds unauthenticated memory use, since the read happens ahead of admission/rate-limiting). 0 disables the cap (embedder opt-out). (31457280, 30 MiB) |
--llm-upstream-url | https://api.anthropic.com | Base URL the AI-gateway inlet (POST /v1/messages) forwards to after the tenant’s _llm stack runs. Point at a local fake for dev/testing. A stack may override per request via _txc.llm.upstream.url; the chassis egress policy applies to both. (https://api.anthropic.com) |
--llm-context-max-tokens | 2000 | Hard cap on estimated tokens (bytes/4) of _txc.llm.context items the AI-gateway inlet injects as system blocks per request, guard block included; items beyond the budget are dropped and recorded in _txc.llm.context_result. Context injection is enabled only when BOTH this and —llm-context-max-items are positive; 0 disables injection entirely. (2000) |
--llm-context-max-items | 8 | Hard cap on the number of _txc.llm.context items the AI-gateway inlet injects per request. Context injection is enabled only when BOTH this and —llm-context-max-tokens are positive; 0 disables injection entirely. (8) |
--continuation-longpoll-ms | 12000 | Max ms to hold a continuation status poll open server-side before returning 202 (adaptive long-poll). Auto-clamped to stay under web-write-timeout; 0 = legacy single-shot poll. |
--web-debug | — | Debug flags: SHOW_PRIVATE_VARS, HIDE_PRIVATE_VARS |
--web-mock-header | false | Honor the X-Txco-Mocks request header and map it into _txc.mocks (caller-driven mock interception). Dev convenience; leave off in production. |
--usage-enabled | true | Emit one structured ‘usage’ log line per completed request (rid, tenant, sizes, timing, status) for downstream accounting. On by default; set —usage-enabled=false to disable. |
--usage-sink | zap | Usage sink backend: {zap}. zap folds each event into the structured ‘usage’ log line. usage-enabled=false disables usage entirely regardless of this. (zap) |
--telemetry-enabled | true | Tenant telemetry: process _txc.telemetry.metrics intents at request end and export them. A tenant is only live once it sets its TELEMETRY_ENDPOINT secret; without it intents are dropped. (true) |
--telemetry-exporter | otlp | Telemetry exporter backend: {otlp, log}. otlp ships OTLP/HTTP to the tenant-configured endpoint; log writes each metric as a chassis log line (dev). (otlp) |
--background-services | — | Comma-list of long-running background services to run (chassis-owned loops, started/stopped with the controllers). Empty by default. () |