Skip to main content
Complete field-by-field reference for ~/.datzi/datzi.json

Configuration Reference

Every field available in ~/.datzi/datzi.json. For a task-oriented overview, see Configuration. Config format is JSON5 (comments + trailing commas allowed). All fields are optional โ€” Datzi uses safe defaults when omitted.

Channels

Each channel starts automatically when its config section exists (unless enabled: false).

DM and group access

All channels support DM policies and group policies:
channels.defaults.groupPolicy sets the default when a providerโ€™s groupPolicy is unset. Pairing codes expire after 1 hour. Pending DM pairing requests are capped at 3 per channel. Slack/Discord have a special fallback: if their provider section is missing entirely, runtime group policy can resolve to open (with a startup warning).

Channel model overrides

Use channels.modelByChannel to pin specific channel IDs to a model. Values accept provider/model or configured model aliases. The channel mapping applies when a session does not already have a model override (for example, set via /model).

WhatsApp

WhatsApp runs through the gatewayโ€™s web channel (Baileys Web). It starts automatically when a linked session exists.
  • Outbound commands default to account default if present; otherwise the first configured account id (sorted).
  • Legacy single-account Baileys auth dir is migrated by datzi doctor into whatsapp/default.
  • Per-account overrides: channels.whatsapp.accounts.<id>.sendReadReceipts, channels.whatsapp.accounts.<id>.dmPolicy, channels.whatsapp.accounts.<id>.allowFrom.

Telegram

  • Bot token: channels.telegram.botToken or channels.telegram.tokenFile, with TELEGRAM_BOT_TOKEN as fallback for the default account.
  • configWrites: false blocks Telegram-initiated config writes (supergroup ID migrations, /config set|unset).
  • Telegram stream previews use sendMessage + editMessageText (works in direct and group chats).
  • Retry policy: see Retry policy.

Discord

  • Token: channels.discord.token, with DISCORD_BOT_TOKEN as fallback for the default account.
  • Use user:<id> (DM) or channel:<id> (guild channel) for delivery targets; bare numeric IDs are rejected.
  • Guild slugs are lowercase with spaces replaced by -; channel keys use the slugged name (no #). Prefer guild IDs.
  • Bot-authored messages are ignored by default. allowBots: true enables them (own messages still filtered).
  • maxLinesPerMessage (default 17) splits tall messages even when under 2000 chars.
  • channels.discord.threadBindings controls Discord thread-bound routing:
    • enabled: Discord override for thread-bound session features (/focus, /unfocus, /agents, /session ttl, and bound delivery/routing)
    • ttlHours: Discord override for auto-unfocus TTL (0 disables)
    • spawnSubagentSessions: opt-in switch for sessions_spawn({ thread: true }) auto thread creation/binding
  • channels.discord.ui.components.accentColor sets the accent color for Discord components v2 containers.
  • channels.discord.voice enables Discord voice channel conversations and optional auto-join + TTS overrides.
  • channels.discord.streaming is the canonical stream mode key. Legacy streamMode and boolean streaming values are auto-migrated.
Reaction notification modes: off (none), own (botโ€™s messages, default), all (all messages), allowlist (from guilds.<id>.users on all messages).

Google Chat

  • Service account JSON: inline (serviceAccount) or file-based (serviceAccountFile).
  • Env fallbacks: GOOGLE_CHAT_SERVICE_ACCOUNT or GOOGLE_CHAT_SERVICE_ACCOUNT_FILE.
  • Use spaces/<spaceId> or users/<userId|email> for delivery targets.

Slack

  • Socket mode requires both botToken and appToken (SLACK_BOT_TOKEN + SLACK_APP_TOKEN for default account env fallback).
  • HTTP mode requires botToken plus signingSecret (at root or per-account).
  • configWrites: false blocks Slack-initiated config writes.
  • channels.slack.streaming is the canonical stream mode key. Legacy streamMode and boolean streaming values are auto-migrated.
  • Use user:<id> (DM) or channel:<id> for delivery targets.
Reaction notification modes: off, own (default), all, allowlist (from reactionAllowlist). Thread session isolation: thread.historyScope is per-thread (default) or shared across channel. thread.inheritParent copies parent channel transcript to new threads.

Mattermost

Mattermost ships as a plugin: datzi plugins install @datzi/mattermost.
Chat modes: oncall (respond on @-mention, default), onmessage (every message), onchar (messages starting with trigger prefix).

Signal

Reaction notification modes: off, own (default), all, allowlist (from reactionAllowlist).

iMessage

Datzi spawns imsg rpc (JSON-RPC over stdio). No daemon or port required.
  • Requires Full Disk Access to the Messages DB.
  • Prefer chat_id:<id> targets. Use imsg chats --limit 20 to list chats.
  • cliPath can point to an SSH wrapper; set remoteHost (host or user@host) for SCP attachment fetching.
  • attachmentRoots and remoteAttachmentRoots restrict inbound attachment paths (default: /Users/*/Library/Messages/Attachments).
  • SCP uses strict host-key checking, so ensure the relay host key already exists in ~/.ssh/known_hosts.
bash #!/usr/bin/env bash exec ssh -T gateway-host imsg "$@"

Multi-account (all channels)

Run multiple accounts per channel (each with its own accountId):
  • default is used when accountId is omitted (CLI + routing).
  • Env tokens only apply to the default account.
  • Base channel settings apply to all accounts unless overridden per account.
  • Use bindings[].match.accountId to route each account to a different agent.

Group chat mention gating

Group messages default to require mention (metadata mention or regex patterns). Applies to WhatsApp, Telegram, Discord, Google Chat, and iMessage group chats. Mention types:
  • Metadata mentions: Native platform @-mentions. Ignored in WhatsApp self-chat mode.
  • Text patterns: Regex patterns in agents.list[].groupChat.mentionPatterns. Always checked.
  • Mention gating is enforced only when detection is possible (native mentions or at least one pattern).
messages.groupChat.historyLimit sets the global default. Channels can override withchannels.<channel>.historyLimit ( or per-account). Set 0 to disable.

DM history limits

Resolution: per-DM override โ†’ provider default โ†’ no limit (all retained). Supported: telegram, whatsapp, discord, slack, signal, imessage, msteams.

Self-chat mode

Include your own number in allowFrom to enable self-chat mode (ignores native @-mentions, only responds to text patterns):

Commands (chat command handling)

  • Text commands must be standalone messages with leading /.
  • native: "auto" turns on native commands for Discord/Telegram, leaves Slack off.
  • Override per channel: channels.discord.commands.native (bool or "auto"). false clears previously registered commands.
  • channels.telegram.customCommands adds extra Telegram bot menu entries.
  • bash: true enables ! <cmd> for host shell. Requires tools.elevated.enabled and sender in tools.elevated.allowFrom.<channel>.
  • config: true enables /config (reads/writes datzi.json).
  • channels.<provider>.configWrites gates config mutations per channel (default: true).
  • allowFrom is per-provider. When set, it is the only authorization source (channel allowlists/pairing and useAccessGroups are ignored).
  • useAccessGroups: false allows commands to bypass access-group policies when allowFrom is not set.

Agent defaults

agents.defaults.workspace

Default: ~/.datzi/workspace.

agents.defaults.repoRoot

Optional repository root shown in the system promptโ€™s Runtime line. If unset, Datzi auto-detects by walking upward from the workspace.

agents.defaults.skipBootstrap

Disables automatic creation of workspace bootstrap files (AGENTS.md, SOUL.md, TOOLS.md, IDENTITY.md, USER.md, HEARTBEAT.md, BOOTSTRAP.md).

agents.defaults.bootstrapMaxChars

Max characters per workspace bootstrap file before truncation. Default: 20000.

agents.defaults.bootstrapTotalMaxChars

Max total characters injected across all workspace bootstrap files. Default: 150000.

agents.defaults.imageMaxDimensionPx

Max pixel size for the longest image side in transcript/tool image blocks before provider calls. Default: 1200. Lower values usually reduce vision-token usage and request payload size for screenshot-heavy runs. Higher values preserve more visual detail.

agents.defaults.userTimezone

Timezone for system prompt context (not message timestamps). Falls back to host timezone.

agents.defaults.timeFormat

Time format in system prompt. Default: auto (OS preference).

agents.defaults.model

  • model.primary: format provider/model (e.g. ollama/qwen3-coder:32b). If you omit the provider, Datzi assumes anthropic (deprecated).
  • models: the configured model catalog and allowlist for /model. Each entry can include alias (shortcut) and params (provider-specific: temperature, maxTokens).
  • imageModel: only used if the primary model lacks image input.
  • maxConcurrent: max parallel agent runs across sessions (each session still serialized). Default: 1.
Built-in alias shorthands (only apply when the model is in agents.defaults.models): Your configured aliases always win over defaults. Z.AI GLM-4.x models automatically enable thinking mode unless you set --thinking off or define agents.defaults.models["zai/<model>"].params.thinking yourself. Z.AI models enable tool_stream by default for tool call streaming. Set agents.defaults.models["zai/<model>"].params.tool_stream to false to disable it.

agents.defaults.cliBackends

Optional CLI backends for text-only fallback runs (no tool calls). Useful as a backup when API providers fail.
  • CLI backends are text-first; tools are always disabled.
  • Sessions supported when sessionArg is set.
  • Image pass-through supported when imageArg accepts file paths.

agents.defaults.heartbeat

Periodic heartbeat runs.
  • every: duration string (ms/s/m/h). Default: 30m.
  • suppressToolErrorWarnings: when true, suppresses tool error warning payloads during heartbeat runs.
  • Per-agent: set agents.list[].heartbeat. When any agent defines heartbeat, only those agents run heartbeats.
  • Heartbeats run full agent turns โ€” shorter intervals burn more tokens.

agents.defaults.compaction

  • mode: default or safeguard (chunked summarization for long histories). See Compaction.
  • memoryFlush: silent agentic turn before auto-compaction to store durable memories. Skipped when workspace is read-only.

agents.defaults.contextPruning

Prunes old tool results from in-memory context before sending to the LLM. Does not modify session history on disk.
  • mode: "cache-ttl" enables pruning passes.
  • ttl controls how often pruning can run again (after the last cache touch).
  • Pruning soft-trims oversized tool results first, then hard-clears older tool results if needed.
Soft-trim keeps beginning + end and inserts ... in the middle.Hard-clear replaces the entire tool result with the placeholder.Notes:
  • Image blocks are never trimmed/cleared.
  • Ratios are character-based (approximate), not exact token counts.
  • If fewer than keepLastAssistants assistant messages exist, pruning is skipped.
See Session Pruning for behavior details.

Block streaming

  • Non-Telegram channels require explicit *.blockStreaming: true to enable block replies.
  • Channel overrides: channels.<channel>.blockStreamingCoalesce (and per-account variants). Signal/Slack/Discord/Google Chat default minChars: 1500.
  • humanDelay: randomized pause between block replies. natural = 800โ€“2500ms. Per-agent override: agents.list[].humanDelay.
See Streaming for behavior + chunking details.

Typing indicators

  • Defaults: instant for direct chats/mentions, message for unmentioned group chats.
  • Per-session overrides: session.typingMode, session.typingIntervalSeconds.
See Typing Indicators.

agents.defaults.sandbox

Optional Docker sandboxing for the embedded agent. See Sandboxing for the full guide.
Workspace access:
  • none: per-scope sandbox workspace under ~/.datzi/sandboxes
  • ro: sandbox workspace at /workspace, agent workspace mounted read-only at /agent
  • rw: agent workspace mounted read/write at /workspace
Scope:
  • session: per-session container + workspace
  • agent: one container + workspace per agent (default)
  • shared: shared container and workspace (no cross-session isolation)
setupCommand runs once after container creation (via sh -lc). Needs network egress, writable root, root user.Containers default to network: "none" โ€” set to "bridge" if the agent needs outbound access.Inbound attachments are staged into media/inbound/* in the active workspace.docker.binds mounts additional host directories; global and per-agent binds are merged.Sandboxed browser (sandbox.browser.enabled): Chromium + CDP in a container. noVNC URL injected into system prompt. Does not require browser.enabled in main config. noVNC observer access uses VNC auth by default and Datzi emits a short-lived token URL (instead of exposing the password in the shared URL).
  • allowHostControl: false (default) blocks sandboxed sessions from targeting the host browser.
  • network defaults to datzi-sandbox-browser (dedicated bridge network). Set to bridge only when you explicitly want global bridge connectivity.
  • cdpSourceRange optionally restricts CDP ingress at the container edge to a CIDR range (for example 172.21.0.1/32).
  • sandbox.browser.binds mounts additional host directories into the sandbox browser container only. When set ( including []), it replaces docker.binds for the browser container.
Build images:

agents.list (per-agent overrides)

  • id: stable agent id (required).
  • default: when multiple are set, first wins (warning logged). If none set, first list entry is default.
  • model: string form overrides primary only; object form { primary, fallbacks } overrides both ([] disables global fallbacks). Cron jobs that only override primary still inherit default fallbacks unless you set fallbacks: [].
  • identity.avatar: workspace-relative path, http(s) URL, or data: URI.
  • identity derives defaults: ackReaction from emoji, mentionPatterns from name/emoji.
  • subagents.allowAgents: allowlist of agent ids for sessions_spawn (["*"] = any; default: same agent only).

Multi-agent routing

Run multiple isolated agents inside one Gateway. See Multi-Agent.

Binding match fields

  • match.channel (required)
  • match.accountId (optional; * = any account; omitted = default account)
  • match.peer (optional; { kind: direct|group|channel, id })
  • match.guildId / match.teamId (optional; channel-specific)
Deterministic match order:
  1. match.peer
  2. match.guildId
  3. match.teamId
  4. match.accountId (exact, no peer/guild/team)
  5. match.accountId: "*" (channel-wide)
  6. Default agent
Within each tier, the first matching bindings entry wins.

Per-agent access profiles

See Multi-Agent Sandbox & Tools for precedence details.

Session

  • dmScope: how DMs are grouped. * main: all DMs share the main session. * per-peer: isolate by sender id across channels. * per-channel-peer: isolate per channel + sender (recommended for multi-user inboxes). * per-account-channel-peer: isolate per account + channel + sender (recommended for multi-account). * identityLinks: map canonical ids to provider-prefixed peers for cross-channel session sharing. * reset: primary reset policy. daily resets at atHour local time; idle resets after idleMinutes. When both configured, whichever expires first wins. * resetByType: per-type overrides (direct, group, thread). Legacy dm accepted as alias for direct. * mainKey: legacy field. Runtime now always uses "main" for the main direct-chat bucket. * sendPolicy: match by channel, chatType (direct|group|channel, with legacy dm alias), keyPrefix, or rawKeyPrefix. First deny wins. * maintenance: warn warns the active session on eviction; enforce applies pruning and rotation. * threadBindings: global defaults for thread-bound session features. * enabled: master default switch (providers can override; Discord uses channels.discord.threadBindings.enabled) * ttlHours: default auto-unfocus TTL in hours (0 disables; providers can override)

Messages

Response prefix

Per-channel/account overrides: channels.<channel>.responsePrefix, channels.<channel>.accounts.<id>.responsePrefix. Resolution (most specific wins): account โ†’ channel โ†’ global. "" disables and stops cascade. "auto" derives [{identity.name}]. Template variables: Variables are case-insensitive. {think} is an alias for {thinkingLevel}.

Ack reaction

  • Defaults to active agentโ€™s identity.emoji, otherwise "๐Ÿ‘€". Set "" to disable.
  • Per-channel overrides: channels.<channel>.ackReaction, channels.<channel>.accounts.<id>.ackReaction.
  • Resolution order: account โ†’ channel โ†’ messages.ackReaction โ†’ identity fallback.
  • Scope: group-mentions (default), group-all, direct, all.
  • removeAckAfterReply: removes ack after reply (Slack/Discord/Telegram/Google Chat only).

Inbound debounce

Batches rapid text-only messages from the same sender into a single agent turn. Media/attachments flush immediately. Control commands bypass debouncing.

TTS (text-to-speech)

Datzi runs on Ollama (qwen3-coder:14b). No external API keys required. TTS requires local alternatives or is disabled in local-only mode.

Talk

Datzi runs on Ollama (qwen3-coder:14b). No external API keys required. Talk mode TTS is not available in local-only mode.

Tools

Tool profiles

tools.profile sets a base allowlist before tools.allow/tools.deny:

Tool groups

tools.allow / tools.deny

Global tool allow/deny policy (deny wins). Case-insensitive, supports * wildcards. Applied even when Docker sandbox is off.

tools.byProvider

Further restrict tools for specific providers or models. Order: base profile โ†’ provider profile โ†’ allow/deny.

tools.elevated

Controls elevated (host) exec access:
  • Per-agent override (agents.list[].tools.elevated) can only further restrict.
  • /elevated on|off|ask|full stores state per session; inline directives apply to single message.
  • Elevated exec runs on the host, bypasses sandboxing.

tools.exec

tools.loopDetection

Tool-loop safety checks are disabled by default. Set enabled: true to activate detection. Settings can be defined globally in tools.loopDetection and overridden per-agent at agents.list[].tools.loopDetection.
  • historySize: max tool-call history retained for loop analysis.
  • warningThreshold: repeating no-progress pattern threshold for warnings.
  • criticalThreshold: higher repeating threshold for blocking critical loops.
  • globalCircuitBreakerThreshold: hard stop threshold for any no-progress run.
  • detectors.genericRepeat: warn on repeated same-tool/same-args calls.
  • detectors.knownPollNoProgress: warn/block on known poll tools (process.poll, command_status, etc.).
  • detectors.pingPong: warn/block on alternating no-progress pair patterns.
  • If warningThreshold >= criticalThreshold or criticalThreshold >= globalCircuitBreakerThreshold, validation fails.

tools.web

tools.media

Configures inbound media understanding (image/audio/video):
Provider entry (type: "provider" or omitted):
  • provider: API provider id (e.g. ollama)
  • model: model id override
  • profile / preferredProfile: auth profile selection
CLI entry (type: "cli"):
  • command: executable to run
  • args: templated args (supports {{MediaPath}}, {{Prompt}}, {{MaxChars}}, etc.)
Common fields:
  • capabilities: optional list (image, audio, video).
  • prompt, maxChars, maxBytes, timeoutSeconds, language: per-entry overrides.
  • Failures fall back to the next entry.
Provider auth follows standard order: auth profiles โ†’ env vars โ†’ models.providers.*.apiKey.

tools.agentToAgent

tools.sessions

Controls which sessions can be targeted by the session tools (sessions_list, sessions_history, sessions_send). Default: tree (current session + sessions spawned by it, such as subagents).
Notes:
  • self: only the current session key.
  • tree: current session + sessions spawned by the current session (subagents).
  • agent: any session belonging to the current agent id (can include other users if you run per-sender sessions under the same agent id).
  • all: any session. Cross-agent targeting still requires tools.agentToAgent.
  • Sandbox clamp: when the current session is sandboxed and agents.defaults.sandbox.sessionToolsVisibility="spawned", visibility is forced to tree even if tools.sessions.visibility="all".

tools.subagents

  • model: default model for spawned sub-agents. If omitted, sub-agents inherit the callerโ€™s model.
  • Per-subagent tool policy: tools.subagents.tools.allow / tools.subagents.tools.deny.

Custom providers and base URLs

Datzi uses the pi-coding-agent model catalog. Add custom providers via models.providers in config or ~/.datzi/agents/<agentId>/agent/models.json.
  • Use authHeader: true + headers for custom auth needs.
  • Override agent config root with DATZI_AGENT_DIR (or PI_CODING_AGENT_DIR).

Provider examples

Shortcut: datzi onboard --auth-choice opencode-zen.
z.ai/* and z-ai/* are accepted aliases. Shortcut: datzi onboard --auth-choice zai-api-key.
  • General endpoint: https://api.z.ai/api/paas/v4
  • Coding endpoint (default): https://api.z.ai/api/coding/paas/v4
  • For the general endpoint, define a custom provider with the base URL override.
Datzi runs on Ollama (qwen3-coder:14b). No external API keys required.
Shortcut: datzi onboard --auth-choice moonshot-api-key-cn.
Datzi runs on Ollama (qwen3-coder:14b). No external API keys required.
Shortcut: datzi onboard --auth-choice kimi-code-api-key.
Datzi runs on Ollama (qwen3-coder:14b). No external API keys required.
Datzi runs on Ollama (qwen3-coder:14b). No external API keys required.
See Local Models. TL;DR: run MiniMax M2.1 via LM Studio Responses API on serious hardware; keep hosted models merged for fallback.

Skills

  • allowBundled: optional allowlist for bundled skills only (managed/workspace skills unaffected).
  • entries.<skillKey>.enabled: false disables a skill even if bundled/installed.
  • entries.<skillKey>.apiKey: convenience for skills declaring a primary env var.

Plugins

  • Loaded from ~/.datzi/extensions, <workspace>/.datzi/extensions, plus plugins.load.paths.
  • Config changes require a gateway restart.
  • allow: optional allowlist (only listed plugins load). deny wins.
See Plugins.

Browser

  • evaluateEnabled: false disables act:evaluate and wait --fn.
  • Remote profiles are attach-only (start/stop/reset disabled).
  • Auto-detect order: default browser if Chromium-based โ†’ Chrome โ†’ Brave โ†’ Edge โ†’ Chromium โ†’ Chrome Canary.
  • Control service: loopback only (port derived from gateway.port, default 18791).

UI

  • seamColor: accent color for native app UI chrome (Talk Mode bubble tint, etc.).
  • assistant: Control UI identity override. Falls back to active agent identity.

Gateway

  • mode: local (run gateway) or remote (connect to remote gateway). Gateway refuses to start unless local.
  • port: single multiplexed port for WS + HTTP. Precedence: --port > DATZI_GATEWAY_PORT > gateway.port > 18789.
  • bind: auto, loopback (default), lan (0.0.0.0), tailnet (Tailscale IP only), or custom.
  • Auth: required by default. Non-loopback binds require a shared token/password. Onboarding wizard generates a token by default.
  • auth.mode: "none": explicit no-auth mode. Use only for trusted local loopback setups; this is intentionally not offered by onboarding prompts.
  • auth.mode: "trusted-proxy": delegate auth to an identity-aware reverse proxy and trust identity headers from gateway.trustedProxies (see Trusted Proxy Auth).
  • auth.allowTailscale: when true, Tailscale Serve identity headers can satisfy Control UI/WebSocket auth (verified via tailscale whois); HTTP API endpoints still require token/password auth. This tokenless flow assumes the gateway host is trusted. Defaults to true when tailscale.mode = "serve".
  • auth.rateLimit: optional failed-auth limiter. Applies per client IP and per auth scope (shared-secret and device-token are tracked independently). Blocked attempts return 429 + Retry-After.
    • auth.rateLimit.exemptLoopback defaults to true; set false when you intentionally want localhost traffic rate-limited too (for test setups or strict proxy deployments).
  • tailscale.mode: serve (tailnet only, loopback bind) or funnel (public, requires auth).
  • remote.transport: ssh (default) or direct (ws/wss). For direct, remote.url must be ws:// or wss://.
  • gateway.remote.token is for remote CLI calls only; does not enable local gateway auth.
  • trustedProxies: reverse proxy IPs that terminate TLS. Only list proxies you control.
  • allowRealIpFallback: when true, the gateway accepts X-Real-IP if X-Forwarded-For is missing. Default false for fail-closed behavior.
  • gateway.tools.deny: extra tool names blocked for HTTP POST /tools/invoke (extends default deny list).
  • gateway.tools.allow: remove tool names from the default HTTP deny list.

OpenAI-compatible endpoints

  • Chat Completions: disabled by default. Enable with gateway.http.endpoints.chatCompletions.enabled: true.
  • Responses API: gateway.http.endpoints.responses.enabled.
  • Responses URL-input hardening:
    • gateway.http.endpoints.responses.maxUrlParts
    • gateway.http.endpoints.responses.files.urlAllowlist
    • gateway.http.endpoints.responses.images.urlAllowlist

Multi-instance isolation

Run multiple gateways on one host with unique ports and state dirs:
Convenience flags: --dev (uses ~/.datzi-dev + port 19001), --profile <name> (uses ~/.datzi-<name>). See Multiple Gateways.

Hooks

Auth: Authorization: Bearer <token> or x-datzi-token: <token>. Endpoints:
  • POST /hooks/wake โ†’ { text, mode?: "now"|"next-heartbeat" }
  • POST /hooks/agent โ†’ { message, name?, agentId?, sessionKey?, wakeMode?, deliver?, channel?, to?, model?, thinking?, timeoutSeconds? }
    • sessionKey from request payload is accepted only when hooks.allowRequestSessionKey=true (default: false).
  • POST /hooks/<name> โ†’ resolved via hooks.mappings
  • match.path matches sub-path after /hooks (e.g. /hooks/gmail โ†’ gmail).
  • match.source matches a payload field for generic paths.
  • Templates like {{messages[0].subject}} read from the payload.
  • transform can point to a JS/TS module returning a hook action.
    • transform.module must be a relative path and stays within hooks.transformsDir (absolute paths and traversal are rejected).
  • agentId routes to a specific agent; unknown IDs fall back to default.
  • allowedAgentIds: restricts explicit routing (* or omitted = allow all, [] = deny all).
  • defaultSessionKey: optional fixed session key for hook agent runs without explicit sessionKey.
  • allowRequestSessionKey: allow /hooks/agent callers to set sessionKey (default: false).
  • allowedSessionKeyPrefixes: optional prefix allowlist for explicit sessionKey values (request + mapping), e.g. ["hook:"].
  • deliver: true sends final reply to a channel; channel defaults to last.
  • model overrides LLM for this hook run (must be allowed if model catalog is set).

Gmail integration

  • Gateway auto-starts gog gmail watch serve on boot when configured. Set DATZI_SKIP_GMAIL_WATCHER=1 to disable.
  • Donโ€™t run a separate gog gmail watch serve alongside the Gateway.

Canvas host

  • Serves agent-editable HTML/CSS/JS and A2UI over HTTP under the Gateway port:
    • http://<gateway-host>:<gateway.port>/__datzi__/canvas/
    • http://<gateway-host>:<gateway.port>/__datzi__/a2ui/
  • Local-only: keep gateway.bind: "loopback" (default).
  • Non-loopback binds: canvas routes require Gateway auth (token/password/trusted-proxy), same as other Gateway HTTP surfaces.
  • Node WebViews typically donโ€™t send auth headers; after a node is paired and connected, the Gateway advertises node-scoped capability URLs for canvas/A2UI access.
  • Capability URLs are bound to the active node WS session and expire quickly. IP-based fallback is not used.
  • Injects live-reload client into served HTML.
  • Auto-creates starter index.html when empty.
  • Also serves A2UI at /__datzi__/a2ui/.
  • Changes require a gateway restart.
  • Disable live reload for large directories or EMFILE errors.

Discovery

mDNS (Bonjour)

  • minimal (default): omit cliPath + sshPort from TXT records.
  • full: include cliPath + sshPort.
  • Hostname defaults to datzi. Override with DATZI_MDNS_HOSTNAME.

Wide-area (DNS-SD)

Writes a unicast DNS-SD zone under ~/.datzi/dns/. For cross-network discovery, pair with a DNS server (CoreDNS recommended) + Tailscale split DNS. Setup: datzi dns setup --apply.

Environment

env (inline env vars)

  • Inline env vars are only applied if the process env is missing the key.
  • .env files: CWD .env + ~/.datzi/.env (neither overrides existing vars).
  • shellEnv: imports missing expected keys from your login shell profile.
  • See Environment for full precedence.

Env var substitution

Reference env vars in any config string with ${VAR_NAME}:
  • Only uppercase names matched: [A-Z_][A-Z0-9_]*.
  • Missing/empty vars throw an error at config load.
  • Escape with $${VAR} for a literal ${VAR}.
  • Works with $include.

Auth storage

Datzi runs on Ollama (qwen3-coder:14b). No external API keys required. Auth profiles are not needed for local Ollama.

Logging

  • Default log file: /tmp/datzi/datzi-YYYY-MM-DD.log.
  • Set logging.file for a stable path.
  • consoleLevel bumps to debug when --verbose.

Wizard

Metadata written by CLI wizards (onboard, configure, doctor):

Identity

Written by the macOS onboarding assistant. Derives defaults:
  • messages.ackReaction from identity.emoji (falls back to ๐Ÿ‘€)
  • mentionPatterns from identity.name/identity.emoji
  • avatar accepts: workspace-relative path, http(s) URL, or data: URI

Bridge (legacy, removed)

Current builds no longer include the TCP bridge. Nodes connect over the Gateway WebSocket. bridge.* keys are no longer part of the config schema (validation fails until removed; datzi doctor --fix can strip unknown keys).

Cron

  • sessionRetention: how long to keep completed cron sessions before pruning. Default: 24h.
  • webhookToken: bearer token used for cron webhook POST delivery (delivery.mode = "webhook"), if omitted no auth header is sent.
  • webhook: deprecated legacy fallback webhook URL (http/https) used only for stored jobs that still have notify: true.
See Cron Jobs.

Media model template variables

Template placeholders expanded in tools.media.*.models[].args:

Config includes ($include)

Split config into multiple files:
Merge behavior:
  • Single file: replaces the containing object.
  • Array of files: deep-merged in order (later overrides earlier).
  • Sibling keys: merged after includes (override included values).
  • Nested includes: up to 10 levels deep.
  • Paths: resolved relative to the including file, but must stay inside the top-level config directory (dirname of the main config file). Absolute/../ forms are allowed only when they still resolve inside that boundary.
  • Errors: clear messages for missing files, parse errors, and circular includes.

Related: Configuration ยท Configuration Examples ยท Doctor