Skip to main content
MeepaGateway uses a YAML config file. The default location is ~/.meepagateway/config.yaml. Specify a custom path with --config:
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:
providers:        # LLM providers and routing
cron:             # Cron scheduler settings
captain:          # Captain Dashboard settings
hooks:            # Inbound webhook configuration
agent_defaults:   # Defaults inherited by all agents
agents:           # List of agent definitions

Resolution order

Settings are resolved with this priority (first match wins):
  1. Agent-level setting (under agents)
  2. Agent defaults (agent_defaults)
  3. Built-in default

providers

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
FieldTypeRequiredDescription
primarystringyesName of the primary provider. Must match a key under providers.providers.
fallbacklistnoOrdered list of fallback provider names tried when primary is unhealthy.
health_check_intervaldurationyesHow often to poll provider health (e.g. 30s, 5m).
Per-provider fields (under providers.providers.<name>):
FieldTypeRequiredDescription
api_key_envstringyesEnvironment variable holding the API key.
modelstringyesDefault model for this provider.
base_urlstringnoOverride the provider’s API base URL. Useful for proxies or OpenAI-compatible endpoints.
max_tokensintegernoMaximum tokens per response.

captain

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
FieldTypeDefaultDescription
enabledbooltrueEnable the Captain Dashboard.
bindstring127.0.0.1IP address to bind the dashboard listener.
portinteger63372Port for the dashboard.
exposurestringlocalHow the dashboard is exposed. See below.
password_hashstringArgon2-hashed password. Set via setup wizard, not by hand.
public_urlstringPublic URL (for cloudflare_tunnel or reverse_proxy exposure).
cloudflare_tokenstringCloudflare tunnel token (for cloudflare_tunnel exposure).
Exposure modes:
ValueBehavior
localBind 127.0.0.1 — localhost only (default)
lanBind 0.0.0.0 — local network
tailscale_privateBind 127.0.0.1, tailscale serve proxies
cloudflare_tunnelBind 127.0.0.1, Cloudflare tunnel routes to captain port
tailscale_funnelBind 0.0.0.0, Tailscale Funnel
reverse_proxyBind 0.0.0.0, user-managed reverse proxy

cron

cron:
  enabled: true
  max_concurrent_runs: 3
FieldTypeDefaultDescription
enabledbooltrueEnable the cron subsystem.
max_concurrent_runsinteger3Maximum concurrent cron jobs across all agents.
Cron jobs are defined per-agent under agents[].cron_jobs. See Cron.

agent_defaults

Defaults inherited by all agents. Any field can be overridden per-agent.
agent_defaults:
  provider: anthropic
  max_iterations: 10
  max_tool_failures: 3
  allowed_dirs: []      # empty = unrestricted file tool access
  image_config:         # sandbox settings (alias: sandbox)
    enabled: false
    runtime: docker
  isolation: null
FieldTypeDefaultDescription
providerstringproviders.primaryDefault LLM provider for all agents.
max_iterationsinteger10Maximum agent loop iterations per message.
max_tool_failuresinteger3Maximum consecutive failures of the same tool before the agent is nudged to try something else.
allowed_dirslist[]Directories read_file/write_file tools can access. Empty means unrestricted.
image_configobjectdisabledSandbox image configuration. Alias: sandbox.
isolationobjectnullIsolation configuration.

agents

Each item in the agents list defines one agent.
agents:
  - id: meepa
    name: Meepa
    default: true
    provider: anthropic       # optional, inherits from agent_defaults
    model: claude-opus-4-6    # optional, overrides provider default
    max_iterations: 10        # optional
    max_tool_failures: 3      # optional
    allowed_dirs: []          # optional
    connectors:
      - name: chat
        type: meepachat
        meepachat:
          url: wss://chat.example.com/api/bot-gateway
          bot_token: BOT_ID.SECRET
    cron_jobs:
      - name: daily-digest
        enabled: true
        schedule:
          every: 24h
        message: "Post the daily digest"
FieldTypeRequiredDescription
idstringyesUnique identifier. Used in API paths and logs.
namestringyesDisplay name.
defaultboolnoMark as the default agent. Exactly one agent must be default.
providerstringnoOverride provider for this agent.
modelstringnoOverride model for this agent.
max_iterationsintegernoOverride max loop iterations.
max_tool_failuresintegernoOverride max tool failures before nudge.
allowed_dirslistnoOverride allowed directories for file tools.
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.

Connectors

connectors:
  - name: chat
    type: meepachat
    meepachat:
      url: wss://chat.example.com/api/bot-gateway
      bot_token: BOT_ID.SECRET
      initial_history_limit: 20   # messages to fetch on session start, 0 to disable

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

  - name: telegram-bot
    type: telegram
    telegram:
      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
    slack:
      bot_token: "xoxb-..."       # bot OAuth token
      app_token: "xapp-..."       # app-level token for Socket Mode

  - name: whatsapp-bot
    type: whatsapp
    whatsapp:
      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

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

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.

Sandbox

image_config:       # alias: sandbox
  enabled: true
  runtime: docker   # docker | none
See Sandbox for full sandbox configuration.

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:
{
  "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

VariableDescription
ANTHROPIC_API_KEYAPI key for the Anthropic provider
OPENAI_API_KEYAPI key for the OpenAI provider
MEEPA_URLDefault gateway URL for CLI management commands
MEEPA_API_KEYAPI key for CLI authentication
RUST_LOGLog 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

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

agent_defaults:
  provider: anthropic
  max_iterations: 10
  max_tool_failures: 3

agents:
  - id: meepa
    name: Meepa
    default: true
    connectors:
      - name: chat
        type: meepachat
        meepachat:
          url: wss://chat.example.com/api/bot-gateway
          bot_token: BOT_ID.SECRET

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