> ## Documentation Index
> Fetch the complete documentation index at: https://ancplua.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

# Configuration

Datzi reads an optional <Tooltip>**JSON5**</Tooltip> config from `~/.datzi/datzi.json`.

If the file is missing, Datzi uses safe defaults. Common reasons to add a config:

* Connect channels and control who can message the bot
* Set models, tools, sandboxing, or automation (cron, hooks)
* Tune sessions, media, networking, or UI

See the [full reference](/datzi/gateway/configuration-reference) for every available field.

<Tip>
  **New to configuration?** Start with `datzi onboard` for interactive setup, or
  check out the [Configuration Examples](/datzi/gateway/configuration-examples) guide
  for complete copy-paste configs.
</Tip>

## Minimal config

```json5 theme={null}
// ~/.datzi/datzi.json
{
  agents: {
    defaults: {
      workspace: '~/.datzi/workspace'
    }
  },
  channels: {
    whatsapp: {
      allowFrom: ['+15555550123']
    }
  }
}
```

## Editing config

<Tabs>
  <Tab title="Interactive wizard">
    ```bash theme={null}
    datzi onboard       # full setup wizard
    datzi configure     # config wizard
    ```
  </Tab>

  <Tab title="CLI (one-liners)">
    ```bash theme={null}
    datzi config get agents.defaults.workspace
    datzi config set agents.defaults.heartbeat.every "2h"
    datzi config unset tools.web.search.apiKey
    ```
  </Tab>

  <Tab title="Control UI">
    Open [http://127.0.0.1:18789](http://127.0.0.1:18789) and use the **Config**
    tab. The Control UI renders a form from the config schema, with a **Raw
    JSON** editor as an escape hatch.
  </Tab>

  <Tab title="Direct edit">
    Edit `~/.datzi/datzi.json` directly. The Gateway watches the file and
    applies changes automatically (see [hot reload](#config-hot-reload)).
  </Tab>
</Tabs>

## Strict validation

<Warning>
  Datzi only accepts configurations that fully match the schema. Unknown keys,
  malformed types, or invalid values cause the Gateway to **refuse to start**.
  The only root-level exception is `$schema` (string), so editors can attach
  JSON Schema metadata.
</Warning>

When validation fails:

* The Gateway does not boot
* Only diagnostic commands work (`datzi doctor`, `datzi logs`, `datzi health`, `datzi status`)
* Run `datzi doctor` to see exact issues
* Run `datzi doctor --fix` (or `--yes`) to apply repairs

## Common tasks

<AccordionGroup>
  <Accordion title="Set up a channel (WhatsApp, Telegram, Discord, etc.)">
    Each channel has its own config section under `channels.<provider>`. See the dedicated channel page for setup steps:

    * [WhatsApp](/datzi/channels/whatsapp) — `channels.whatsapp`
    * [Telegram](/datzi/channels/telegram) — `channels.telegram`
    * [Discord](/datzi/channels/discord) — `channels.discord`
    * [Slack](/datzi/channels/slack) — `channels.slack`
    * [iMessage](/datzi/channels/imessage) — `channels.imessage`

    All channels share the same DM policy pattern:

    ```json5 theme={null}
    {
      channels: {
        telegram: {
          enabled: true,
          botToken: "123:abc",
          dmPolicy: "pairing",   // pairing | allowlist | open | disabled
          allowFrom: ["tg:123"], // only for allowlist/open
        },
      },
    }
    ```
  </Accordion>

  <Accordion title="Choose and configure models">
    Set the primary model and optional fallbacks:

    ```json5 theme={null}
    {
      agents: {
        defaults: {
          model: {
            primary: "ollama/qwen3-coder:14b",
            fallbacks: ["ollama/deepseek-r1:32b"],
          },
          models: {
            "ollama/qwen3-coder:14b": { alias: "Sonnet" },
            "ollama/deepseek-r1:32b": { alias: "GPT" },
          },
        },
      },
    }
    ```

    * `agents.defaults.models` defines the model catalog and acts as the allowlist for `/model`.
    * Model refs use `provider/model` format (e.g. `ollama/qwen3-coder:32b`).
    * `agents.defaults.imageMaxDimensionPx` controls transcript/tool image downscaling (default `1200`); lower values usually reduce vision-token usage on screenshot-heavy runs.
    * See [Models CLI](/datzi/concepts/models) for switching models in chat and [Model Failover](/datzi/concepts/model-failover) for auth rotation and fallback behavior.
    * For custom/self-hosted providers, see [Custom providers](/datzi/gateway/configuration-reference#custom-providers-and-base-urls) in the reference.
  </Accordion>

  <Accordion title="Control who can message the bot">
    DM access is controlled per channel via `dmPolicy`:

    * `"pairing"` (default): unknown senders get a one-time pairing code to approve
    * `"allowlist"`: only senders in `allowFrom` (or the paired allow store)
    * `"open"`: allow all inbound DMs (requires `allowFrom: ["*"]`)
    * `"disabled"`: ignore all DMs

    For groups, use `groupPolicy` + `groupAllowFrom` or channel-specific allowlists.

    See the [full reference](/datzi/gateway/configuration-reference#dm-and-group-access) for per-channel details.
  </Accordion>

  <Accordion title="Set up group chat mention gating">
    Group messages default to **require mention**. Configure patterns per agent:

    ```json5 theme={null}
    {
      agents: {
        list: [
          {
            id: "main",
            groupChat: {
              mentionPatterns: ["@datzi", "datzi"],
            },
          },
        ],
      },
      channels: {
        whatsapp: {
          groups: { "*": { requireMention: true } },
        },
      },
    }
    ```

    * **Metadata mentions**: native @-mentions (WhatsApp tap-to-mention, Telegram @bot, etc.)
    * **Text patterns**: regex patterns in `mentionPatterns`
    * See [full reference](/datzi/gateway/configuration-reference#group-chat-mention-gating) for per-channel overrides and self-chat mode.
  </Accordion>

  <Accordion title="Configure sessions and resets">
    Sessions control conversation continuity and isolation:

    ```json5 theme={null}
    {
      session: {
        dmScope: "per-channel-peer",  // recommended for multi-user
        threadBindings: {
          enabled: true,
          ttlHours: 24,
        },
        reset: {
          mode: "daily",
          atHour: 4,
          idleMinutes: 120,
        },
      },
    }
    ```

    * `dmScope`: `main` (shared) | `per-peer` | `per-channel-peer` | `per-account-channel-peer`
    * `threadBindings`: global defaults for thread-bound session routing (Discord supports `/focus`, `/unfocus`, `/agents`, and `/session ttl`).
    * See [Session Management](/datzi/concepts/session) for scoping, identity links, and send policy.
    * See [full reference](/datzi/gateway/configuration-reference#session) for all fields.
  </Accordion>

  <Accordion title="Enable sandboxing">
    Run agent sessions in isolated Docker containers:

    ```json5 theme={null}
    {
      agents: {
        defaults: {
          sandbox: {
            mode: "non-main",  // off | non-main | all
            scope: "agent",    // session | agent | shared
          },
        },
      },
    }
    ```

    Build the image first: `scripts/sandbox-setup.sh`

    See [Sandboxing](/datzi/gateway/sandboxing) for the full guide and [full reference](/datzi/gateway/configuration-reference#sandbox) for all options.
  </Accordion>

  <Accordion title="Set up heartbeat (periodic check-ins)">
    ```json5 theme={null}
    {
      agents: {
        defaults: {
          heartbeat: {
            every: "30m",
            target: "last",
          },
        },
      },
    }
    ```

    * `every`: duration string (`30m`, `2h`). Set `0m` to disable.
    * `target`: `last` | `whatsapp` | `telegram` | `discord` | `none`
    * See [Heartbeat](/datzi/gateway/heartbeat) for the full guide.
  </Accordion>

  <Accordion title="Configure cron jobs">
    ```json5 theme={null}
    {
      cron: {
        enabled: true,
        maxConcurrentRuns: 2,
        sessionRetention: "24h",
      },
    }
    ```

    See [Cron jobs](/datzi/automation/cron-jobs) for the feature overview and CLI examples.
  </Accordion>

  <Accordion title="Set up webhooks (hooks)">
    Enable HTTP webhook endpoints on the Gateway:

    ```json5 theme={null}
    {
      hooks: {
        enabled: true,
        token: "shared-secret",
        path: "/hooks",
        defaultSessionKey: "hook:ingress",
        allowRequestSessionKey: false,
        allowedSessionKeyPrefixes: ["hook:"],
        mappings: [
          {
            match: { path: "gmail" },
            action: "agent",
            agentId: "main",
            deliver: true,
          },
        ],
      },
    }
    ```

    See [full reference](/datzi/gateway/configuration-reference#hooks) for all mapping options and Gmail integration.
  </Accordion>

  <Accordion title="Configure multi-agent routing">
    Run multiple isolated agents with separate workspaces and sessions:

    ```json5 theme={null}
    {
      agents: {
        list: [
          { id: "home", default: true, workspace: "~/.datzi/workspace-home" },
          { id: "work", workspace: "~/.datzi/workspace-work" },
        ],
      },
      bindings: [
        { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
        { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
      ],
    }
    ```

    See [Multi-Agent](/datzi/concepts/multi-agent) and [full reference](/datzi/gateway/configuration-reference#multi-agent-routing) for binding rules and per-agent access profiles.
  </Accordion>

  <Accordion title="Split config into multiple files ($include)">
    Use `$include` to organize large configs:

    ```json5 theme={null}
    // ~/.datzi/datzi.json
    {
      gateway: { port: 18789 },
      agents: { $include: "./agents.json5" },
      broadcast: {
        $include: ["./clients/a.json5", "./clients/b.json5"],
      },
    }
    ```

    * **Single file**: replaces the containing object
    * **Array of files**: deep-merged in order (later wins)
    * **Sibling keys**: merged after includes (override included values)
    * **Nested includes**: supported up to 10 levels deep
    * **Relative paths**: resolved relative to the including file
    * **Error handling**: clear errors for missing files, parse errors, and circular includes
  </Accordion>
</AccordionGroup>

## Config hot reload

The Gateway watches `~/.datzi/datzi.json` and applies changes automatically — no manual restart needed for most
settings.

### Reload modes

| Mode                   | Behavior                                                                                |
| ---------------------- | --------------------------------------------------------------------------------------- |
| **`hybrid`** (default) | Hot-applies safe changes instantly. Automatically restarts for critical ones.           |
| **`hot`**              | Hot-applies safe changes only. Logs a warning when a restart is needed — you handle it. |
| **`restart`**          | Restarts the Gateway on any config change, safe or not.                                 |
| **`off`**              | Disables file watching. Changes take effect on the next manual restart.                 |

```json5 theme={null}
{
  gateway: {
    reload: {
      mode: 'hybrid',
      debounceMs: 300
    }
  }
}
```

### What hot-applies vs what needs a restart

Most fields hot-apply without downtime. In `hybrid` mode, restart-required changes are handled automatically.

| Category            | Fields                                                               | Restart needed? |
| ------------------- | -------------------------------------------------------------------- | --------------- |
| Channels            | `channels.*`, `web` (WhatsApp) — all built-in and extension channels | No              |
| Agent & models      | `agent`, `agents`, `models`, `routing`                               | No              |
| Automation          | `hooks`, `cron`, `agent.heartbeat`                                   | No              |
| Sessions & messages | `session`, `messages`                                                | No              |
| Tools & media       | `tools`, `browser`, `skills`, `audio`, `talk`                        | No              |
| UI & misc           | `ui`, `logging`, `identity`, `bindings`                              | No              |
| Gateway server      | `gateway.*` (port, bind, auth, tailscale, TLS, HTTP)                 | **Yes**         |
| Infrastructure      | `discovery`, `canvasHost`, `plugins`                                 | **Yes**         |

<Note>
  `gateway.reload` and `gateway.remote` are exceptions — changing them does
  **not** trigger a restart.
</Note>

## Config RPC (programmatic updates)

<Note>
  Control-plane write RPCs (`config.apply`, `config.patch`, `update.run`) are
  rate-limited to **3 requests per 60 seconds** per `deviceId+clientIp`. When
  limited, the RPC returns `UNAVAILABLE` with `retryAfterMs`.
</Note>

<AccordionGroup>
  <Accordion title="config.apply (full replace)">
    Validates + writes the full config and restarts the Gateway in one step.

    <Warning>
      `config.apply` replaces the **entire config**. Use `config.patch` for partial updates, or `datzi config set` for single keys.
    </Warning>

    Params:

    * `raw` (string) — JSON5 payload for the entire config
    * `baseHash` (optional) — config hash from `config.get` (required when config exists)
    * `sessionKey` (optional) — session key for the post-restart wake-up ping
    * `note` (optional) — note for the restart sentinel
    * `restartDelayMs` (optional) — delay before restart (default 2000)

    Restart requests are coalesced while one is already pending/in-flight, and a 30-second cooldown applies between restart cycles.

    ```bash theme={null}
    datzi gateway call config.get --params '{}'  # capture payload.hash
    datzi gateway call config.apply --params '{
      "raw": "{ agents: { defaults: { workspace: \"~/.datzi/workspace\" } } }",
      "baseHash": "<hash>",
      "sessionKey": "agent:main:whatsapp:dm:+15555550123"
    }'
    ```
  </Accordion>

  <Accordion title="config.patch (partial update)">
    Merges a partial update into the existing config (JSON merge patch semantics):

    * Objects merge recursively
    * `null` deletes a key
    * Arrays replace

    Params:

    * `raw` (string) — JSON5 with just the keys to change
    * `baseHash` (required) — config hash from `config.get`
    * `sessionKey`, `note`, `restartDelayMs` — same as `config.apply`

    Restart behavior matches `config.apply`: coalesced pending restarts plus a 30-second cooldown between restart cycles.

    ```bash theme={null}
    datzi gateway call config.patch --params '{
      "raw": "{ channels: { telegram: { groups: { \"*\": { requireMention: false } } } } }",
      "baseHash": "<hash>"
    }'
    ```
  </Accordion>
</AccordionGroup>

## Environment variables

Datzi reads env vars from the parent process plus:

* `.env` from the current working directory (if present)
* `~/.datzi/.env` (global fallback)

Neither file overrides existing env vars. You can also set inline env vars in config:

```json5 theme={null}
{
  env: {
    vars: {}
  }
}
```

<Accordion title="Shell env import (optional)">
  If enabled and expected keys aren't set, Datzi runs your login shell and imports only the missing keys:

  ```json5 theme={null}
  {
    env: {
      shellEnv: {
        enabled: true,
        timeoutMs: 15000
      }
    }
  }
  ```

  Env var equivalent: `DATZI_LOAD_SHELL_ENV=1`
</Accordion>

<Accordion title="Env var substitution in config values">
  Reference env vars in any config string value with `${VAR_NAME}`:

  ```json5 theme={null}
  {
    gateway: {
      auth: {
        token: '${DATZI_GATEWAY_TOKEN}'
      }
    },
    models: {
      providers: {
        custom: {
          apiKey: '${CUSTOM_API_KEY}'
        }
      }
    }
  }
  ```

  Rules:

  * Only uppercase names matched: `[A-Z_][A-Z0-9_]*`
  * Missing/empty vars throw an error at load time
  * Escape with `$${VAR}` for literal output
  * Works inside `$include` files
  * Inline substitution: `"${BASE}/v1"` → `"https://api.example.com/v1"`
</Accordion>

See [Environment](/datzi/help/environment) for full precedence and sources.

## Full reference

For the complete field-by-field reference, see **[Configuration Reference](/datzi/gateway/configuration-reference)**.

***

*Related: [Configuration Examples](/datzi/gateway/configuration-examples) · [Configuration Reference](/datzi/gateway/configuration-reference) · [Doctor](/datzi/gateway/troubleshooting)*
