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

# Configuration

> Full reference for the MeepaGateway config file.

MeepaGateway uses a YAML config file. The default location is `~/.meepagateway/config.yaml`. Specify a custom path with `--config`:

```bash theme={null}
meepagateway --config /path/to/config.yaml start
```

If no config file exists on first run, the gateway enters setup mode.

## File format

The config is YAML. Top-level sections:

```yaml theme={null}
providers:        # LLM providers and routing
cron:             # Cron scheduler settings
captain:          # Captain Dashboard settings
hooks:            # Inbound webhook configuration
agents:           # List of agent definitions
```

***

## `providers`

```yaml theme={null}
providers:
  primary: anthropic
  fallback:
    - openai
  health_check_interval: 30s
  providers:
    anthropic:
      api_key_env: ANTHROPIC_API_KEY
      model: claude-opus-4-6
    openai:
      api_key_env: OPENAI_API_KEY
      model: gpt-4o
      base_url: https://api.openai.com/v1  # optional
      max_tokens: 8192                     # optional
```

| Field                   | Type     | Required | Description                                                                 |
| ----------------------- | -------- | -------- | --------------------------------------------------------------------------- |
| `primary`               | string   | yes      | Name of the primary provider. Must match a key under `providers.providers`. |
| `fallback`              | list     | no       | Ordered list of fallback provider names tried when primary is unhealthy.    |
| `health_check_interval` | duration | yes      | How often to poll provider health (e.g. `30s`, `5m`).                       |

**Per-provider fields** (under `providers.providers.<name>`):

| Field         | Type    | Required | Description                                                                              |
| ------------- | ------- | -------- | ---------------------------------------------------------------------------------------- |
| `api_key_env` | string  | yes      | Environment variable holding the API key.                                                |
| `model`       | string  | yes      | Default model for this provider.                                                         |
| `base_url`    | string  | no       | Override the provider's API base URL. Useful for proxies or OpenAI-compatible endpoints. |
| `max_tokens`  | integer | no       | Maximum tokens per response.                                                             |

***

## `captain`

```yaml theme={null}
captain:
  enabled: true
  bind: 127.0.0.1
  port: 63372
  exposure: local
  password_hash: "$argon2..."      # set via setup wizard
  api_keys: []                     # managed by the gateway, not hand-edited
  webauthn_credentials: []         # managed by the gateway
  public_url: ""                   # for cloudflare_tunnel / reverse_proxy modes
  cloudflare_token: ""             # for cloudflare_tunnel mode
```

| Field              | Type    | Default     | Description                                                       |
| ------------------ | ------- | ----------- | ----------------------------------------------------------------- |
| `enabled`          | bool    | `true`      | Enable the Captain Dashboard.                                     |
| `bind`             | string  | `127.0.0.1` | IP address to bind the dashboard listener.                        |
| `port`             | integer | `63372`     | Port for the dashboard.                                           |
| `exposure`         | string  | `local`     | How the dashboard is exposed. See below.                          |
| `password_hash`    | string  | —           | Argon2-hashed password. Set via setup wizard, not by hand.        |
| `public_url`       | string  | —           | Public URL (for `cloudflare_tunnel` or `reverse_proxy` exposure). |
| `cloudflare_token` | string  | —           | Cloudflare tunnel token (for `cloudflare_tunnel` exposure).       |

**Exposure modes:**

| Value               | Behavior                                                   |
| ------------------- | ---------------------------------------------------------- |
| `local`             | Bind `127.0.0.1` — localhost only (default)                |
| `lan`               | Bind `0.0.0.0` — local network                             |
| `tailscale_private` | Bind `127.0.0.1`, `tailscale serve` proxies                |
| `cloudflare_tunnel` | Bind `127.0.0.1`, Cloudflare tunnel routes to captain port |
| `tailscale_funnel`  | Bind `0.0.0.0`, Tailscale Funnel                           |
| `reverse_proxy`     | Bind `0.0.0.0`, user-managed reverse proxy                 |

***

## `cron`

```yaml theme={null}
cron:
  enabled: true
  max_concurrent_runs: 3
```

| Field                 | Type    | Default | Description                                     |
| --------------------- | ------- | ------- | ----------------------------------------------- |
| `enabled`             | bool    | `true`  | Enable the cron subsystem.                      |
| `max_concurrent_runs` | integer | `3`     | Maximum concurrent cron jobs across all agents. |

Cron jobs are defined per-agent under `agents[].cron_jobs`. See [Cron](/gateway/cron).

***

## `agents`

Each item in the `agents` list defines one agent. All configuration fields are set directly on the agent.

```yaml theme={null}
agents:
  - id: meepa
    name: Meepa
    default: true
    provider: null
    model: null
    max_iterations: 10
    max_tool_failures: 3
    image_config:
      enabled: false
      base_image: ghcr.io/bogpad/meepagateway-sandbox:latest
      packages: []
      env_vars: {}
      inject_credentials_env: true
      inject_secrets_env: true
      redact_secrets: true
    tools: null
    file_access:
      unrestricted: true
      allow_read: []
      allow_read_write: []
      deny: []
      allow_home_dotfiles: false
      allow_network: true
    container_mode:
      enabled: true
      image: ''
      memory_limit: 512m
      timeout_seconds: 300
      network: bridge
    connectors:
      - name: meepachat
        type: meepachat
        webhook: false
        bot_token: ${sops:meepachat.bot_token}
        url: https://chat.meepachat.ai
    cron_jobs: []
```

| Field               | Type    | Required | Description                                                            |
| ------------------- | ------- | -------- | ---------------------------------------------------------------------- |
| `id`                | string  | yes      | Unique identifier. Used in API paths and logs.                         |
| `name`              | string  | yes      | Display name.                                                          |
| `default`           | bool    | no       | Mark as the default agent. Exactly one agent must be default.          |
| `provider`          | string  | no       | LLM provider to use. Defaults to `providers.primary`.                  |
| `model`             | string  | no       | Model override for this agent.                                         |
| `max_iterations`    | integer | no       | Maximum agent loop iterations per message. Default: `10`.              |
| `max_tool_failures` | integer | no       | Maximum consecutive failures before the agent is nudged. Default: `3`. |

Agent workspace is auto-derived from the ID: `~/.meepagateway/agents/{id}/`. Files in the workspace (`SOUL.md`, `MEMORY.md`, `USER.md`, `memory.db`, `skills/`, `.mcp.json`) are not configured here.

### `file_access`

Controls which paths the file tools can read or write.

```yaml theme={null}
file_access:
  unrestricted: true        # if true, all other fields are ignored
  allow_read: []            # paths allowed for read-only access
  allow_read_write: []      # paths allowed for read+write access
  deny: []                  # paths explicitly denied
  allow_home_dotfiles: false
  allow_network: true
```

| Field                 | Type | Default | Description                                                       |
| --------------------- | ---- | ------- | ----------------------------------------------------------------- |
| `unrestricted`        | bool | `true`  | Allow access to all paths. When `true`, other fields are ignored. |
| `allow_read`          | list | `[]`    | Paths the agent may read.                                         |
| `allow_read_write`    | list | `[]`    | Paths the agent may read and write.                               |
| `deny`                | list | `[]`    | Paths explicitly blocked. Takes precedence over allow lists.      |
| `allow_home_dotfiles` | bool | `false` | Allow reading dotfiles in the home directory.                     |
| `allow_network`       | bool | `true`  | Allow network access from tools.                                  |

### `image_config`

Configuration for the sandbox image used in container mode.

```yaml theme={null}
image_config:
  enabled: false
  base_image: ghcr.io/bogpad/meepagateway-sandbox:latest
  packages: []
  env_vars: {}
  inject_credentials_env: true
  inject_secrets_env: true
  redact_secrets: true
```

| Field                    | Type   | Default | Description                                         |
| ------------------------ | ------ | ------- | --------------------------------------------------- |
| `enabled`                | bool   | `false` | Enable image-based sandboxing.                      |
| `base_image`             | string | —       | OCI image to use as the sandbox base.               |
| `packages`               | list   | `[]`    | Extra packages to install in the image.             |
| `env_vars`               | map    | `{}`    | Environment variables to inject into the container. |
| `inject_credentials_env` | bool   | `true`  | Inject provider credential env vars.                |
| `inject_secrets_env`     | bool   | `true`  | Inject SOPS-managed secrets as env vars.            |
| `redact_secrets`         | bool   | `true`  | Redact secret values from logs.                     |

### `container_mode`

Runtime settings for the container execution environment.

```yaml theme={null}
container_mode:
  enabled: true
  image: ''
  memory_limit: 512m
  timeout_seconds: 300
  network: bridge
```

| Field             | Type    | Default  | Description                                                          |
| ----------------- | ------- | -------- | -------------------------------------------------------------------- |
| `enabled`         | bool    | `false`  | Run agent tools inside a container.                                  |
| `image`           | string  | `''`     | Override the container image (empty uses `image_config.base_image`). |
| `memory_limit`    | string  | `512m`   | Memory limit for the container.                                      |
| `timeout_seconds` | integer | `300`    | Maximum seconds a container run may take.                            |
| `network`         | string  | `bridge` | Docker network mode.                                                 |

See [Isolation](/gateway/container) for full details.

### Connectors

Connectors are flat objects — all fields are directly on the connector, not nested under a type key.

```yaml theme={null}
connectors:
  - name: meepachat
    type: meepachat
    webhook: false
    bot_token: BOT_ID.SECRET
    url: https://chat.example.com

  - name: discord-bot
    type: discord
    webhook: false
    bot_token: "Bot.Token..."
    guild_ids: []               # optional: restrict to specific guilds

  - name: telegram-bot
    type: telegram
    webhook: false
    bot_token: "1234567890:AAF..."
    poll_interval: 1s           # polling interval (or use webhook_url)
    webhook_url: ""             # optional: use webhook instead of polling
    webhook_port: null          # local port for webhook listener

  - name: slack-bot
    type: slack
    webhook: false
    bot_token: "xoxb-..."       # bot OAuth token
    app_token: "xapp-..."       # app-level token for Socket Mode

  - name: whatsapp-bot
    type: whatsapp
    webhook: false
    access_token: "..."         # WhatsApp Cloud API access token
    phone_number_id: "..."      # phone number ID from Meta dashboard
    verify_token: "..."         # webhook verification token
    webhook_port: 8444          # local port for webhook listener
```

Set `webhook: true` on any connector to use the centralized webhook system instead of per-connector polling or WebSocket.

### Cron jobs

```yaml theme={null}
cron_jobs:
  - name: daily-digest
    enabled: true
    message: "Post the daily digest to the team channel"
    schedule:
      every: 24h          # interval schedule

  - name: weekday-standup
    enabled: true
    message: "Run the standup summary"
    schedule:
      cron: "0 0 9 * * 1-5 *"  # 7-field cron expression

  - name: one-time-reminder
    enabled: true
    message: "Send the project deadline reminder"
    schedule:
      at: "2026-12-31T09:00:00Z"  # one-shot
```

### Tool filtering

```yaml theme={null}
tools:
  allow:
    - shell
    - read_file
    - write_file
  # deny:
  #   - shell
```

`allow` is an allowlist — only listed tools are available. `deny` removes specific tools. The two are mutually exclusive.

***

## MCP servers

MCP servers are **not** configured in the main config file. Each agent has a `.mcp.json` file at `~/.meepagateway/agents/{id}/.mcp.json`:

```json theme={null}
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    },
    "remote-server": {
      "url": "http://localhost:9000/mcp"
    }
  }
}
```

Edit with: `meepagateway agent mcp <id>`

***

## Environment variables

| Variable            | Description                                             |
| ------------------- | ------------------------------------------------------- |
| `ANTHROPIC_API_KEY` | API key for the Anthropic provider                      |
| `OPENAI_API_KEY`    | API key for the OpenAI provider                         |
| `MEEPA_URL`         | Default gateway URL for CLI management commands         |
| `MEEPA_API_KEY`     | API key for CLI authentication                          |
| `RUST_LOG`          | Log level (e.g. `info`, `debug`, `meepa_gateway=debug`) |

Never put secrets directly in the config file. Reference them via `api_key_env` pointing to an environment variable.

***

## Complete example

```yaml theme={null}
providers:
  primary: anthropic
  fallback:
    - openai
  health_check_interval: 30s
  providers:
    anthropic:
      api_key_env: ANTHROPIC_API_KEY
      model: claude-opus-4-6
    openai:
      api_key_env: OPENAI_API_KEY
      model: gpt-4o

cron:
  enabled: true
  max_concurrent_runs: 3

captain:
  enabled: true
  bind: 127.0.0.1
  port: 63372

agents:
  - id: meepa
    name: Meepa
    default: true
    max_iterations: 10
    max_tool_failures: 3
    file_access:
      unrestricted: true
      allow_network: true
    container_mode:
      enabled: false
    connectors:
      - name: meepachat
        type: meepachat
        webhook: false
        bot_token: ${sops:meepachat.bot_token}
        url: https://chat.example.com

  - id: coder
    name: Code Helper
    model: claude-opus-4-6
    max_iterations: 20
    file_access:
      unrestricted: false
      allow_read_write:
        - /home/user/projects
    tools:
      allow:
        - shell
        - read_file
        - write_file
    connectors:
      - name: discord-bot
        type: discord
        webhook: false
        bot_token: "Bot.Token..."
    cron_jobs:
      - name: daily-summary
        enabled: true
        message: "Summarize today's code changes"
        schedule:
          every: 24h
```
