Skip to content

Config Files

All runtime behavior is controlled by JSON files in the configs/ directory. This page documents every config surface.

configs/gateway.json — Email Transport

Controls how Protege sends and receives email.

json
{
  "mode": "default",
  "host": "127.0.0.1",
  "port": 2525,
  "mailDomain": "mail.protege.bot",
  "transport": {
    "host": "smtp.example.com",
    "port": 587,
    "secure": true,
    "auth": {
      "user": "agent@example.com",
      "pass": "smtp-password"
    }
  },
  "relay": {
    "enabled": true,
    "relayWsUrl": "wss://relay.protege.bot/ws",
    "reconnectBaseDelayMs": 250,
    "reconnectMaxDelayMs": 8000,
    "heartbeatTimeoutMs": 30000
  },
  "attachmentLimits": {
    "maxAttachmentBytes": 10485760,
    "maxAttachmentsPerMessage": 10,
    "maxTotalAttachmentBytes": 26214400
  }
}
FieldTypeDescription
mode"dev" or "default"dev skips real email delivery for local testing
hoststringSMTP server bind address
portinteger (1-65535)SMTP server bind port
mailDomainstringEmail domain for persona addresses (e.g., mail.protege.bot)
transportobjectOutbound SMTP settings (for local mode)
relayobjectRelay bridge settings
attachmentLimitsobjectPer-message attachment size limits

Validation rule

If relay.enabled is true, mailDomain cannot be localhost.

configs/inference.json — LLM Settings

Controls which LLM provider and model your agent uses.

json
{
  "provider": "anthropic",
  "model": "claude-sonnet-4-20250514",
  "temperature": 0.7,
  "max_output_tokens": 4096,
  "max_tool_turns": 8,
  "recursion_depth": 3
}
FieldTypeDefaultDescription
providerstringopenai, anthropic, gemini, or grok
modelstringProvider-specific model name
temperaturenumberSampling temperature
max_output_tokensnumberMax tokens per LLM response
max_tool_turnsinteger8Max tool-call rounds before forcing a text response
recursion_depthnumber3Max agent-to-agent email reply depth (recursion guard)

recursion_depth prevents infinite loops when agents email each other. Each outbound email carries an X-Protege-Recursion header that counts down. Messages arriving at 0 are rejected.

configs/security.json — Access Policy

Controls who can send email to your agent.

json
{
  "gateway_auth": {
    "enabled": true,
    "mode": "monitor",
    "policy": "require_dmarc_or_aligned_spf_dkim",
    "trusted_relays": []
  },
  "gateway_access": {
    "enabled": true,
    "default_decision": "deny",
    "allow": [
      "alice@example.com",
      "*@trusted-company.com"
    ],
    "deny": [
      "spam@trusted-company.com"
    ]
  }
}

Gateway Auth

FieldTypeDefaultDescription
enabledbooleantrueEnables sender-auth policy evaluation surface
mode"monitor" or "enforce""monitor"monitor logs/auth-evaluates without blocking; enforce blocks policy failures
policystring"require_dmarc_or_aligned_spf_dkim"Default auth policy strategy
trusted_relaysobject[][]Trusted relay key list for signed relay attestation verification

INFO

The default scaffold ships gateway_auth enabled in monitor mode so first-time installs work out of the box while still exposing auth telemetry.

Gateway Access

FieldTypeDefaultDescription
enabledbooleanfalseWhether to enforce access rules
default_decision"allow" or "deny""allow"What to do when no rule matches
allowstring[][]Addresses/patterns to allow
denystring[][]Addresses/patterns to deny

Evaluation order: deny rules → allow rules → default decision. Deny always wins if both match.

Wildcards: Use * for pattern matching. *@example.com matches any sender from that domain.

TIP

This policy only applies to inbound gateway email. Local chat is not filtered.

configs/system.json — Runtime Settings

Controls logging, chat, and scheduler behavior.

json
{
  "logs_dir_path": "tmp/logs",
  "console_log_format": "pretty",
  "theme_config_path": "configs/theme.json",
  "admin_contact_email": "admin@example.com",
  "chat": {
    "default_display_mode": "light",
    "poll_interval_ms": 1500,
    "keymap": {
      "send": "ctrl+s",
      "refresh": "ctrl+r",
      "toggle_display_mode": "ctrl+v",
      "quit": "ctrl+q",
      "move_selection_up": "up",
      "move_selection_down": "down",
      "open_thread": "enter",
      "back_to_inbox": "esc",
      "new_local_thread": "ctrl+n",
      "enter_compose_mode": "i"
    }
  },
  "scheduler": {
    "poll_interval_ms": 1000,
    "max_global_concurrent_runs": 5,
    "admin_contact_email": "ops@example.com"
  }
}

Global settings

FieldTypeDefaultDescription
logs_dir_pathstringtmp/logsWhere log files are written
console_log_format"json" or "pretty""json"Log output format
theme_config_pathstringconfigs/theme.jsonPath to theme file
admin_contact_emailstringEmail for failure alerts

Chat settings

FieldDefaultDescription
default_display_mode"light""light" (minimal) or "verbose" (full headers)
poll_interval_ms1500How often chat polls for new messages
keymapKey bindings (see Chat Guide)

Scheduler settings

FieldDefaultDescription
poll_interval_ms1000How often the scheduler checks for queued runs
max_global_concurrent_runs5Max simultaneous responsibility runs
admin_contact_emailOverride for scheduler-specific alerts

configs/context.json — Context Pipeline

Defines the resolver sequence for each inference run. See the Resolvers page for full documentation.

json
{
  "thread": [
    "load-file(prompts/system.md)",
    "load-file(personas/{persona_id}/PERSONA.md)",
    "load-file(memory/{persona_id}/active.md)",
    "thread-memory-state",
    "thread-history",
    "load-file(personas/{persona_id}/knowledge/CONTENT.md)",
    "invocation-metadata",
    "current-input"
  ],
  "responsibility": [
    "load-file(prompts/system.md)",
    "load-file(personas/{persona_id}/PERSONA.md)",
    "load-file(memory/{persona_id}/active.md)",
    "load-file(personas/{persona_id}/knowledge/CONTENT.md)",
    "current-input"
  ]
}

configs/theme.json — Visual Theming

Controls colors for pretty log output and the chat TUI.

json
{
  "pretty_logs": {
    "enabled": true,
    "indent": "\t",
    "header": {
      "timestamp": ["dim"],
      "level": ["bold"],
      "scope": ["cyan"],
      "event": ["magenta"]
    },
    "level": {
      "info": ["green"],
      "error": ["red"]
    },
    "context": {
      "key": ["blue"],
      "value": ["white"]
    }
  },
  "chat_ui": {
    "inbox": {
      "title_tag": ["bold", "blue-fg"],
      "timestamp_tag": ["dim", "gray-fg"],
      "selected_marker_tag": ["blue-fg"],
      "marker_glyph": "│"
    },
    "thread": {
      "title_tag": ["bold", "blue-fg"],
      "message_dot_glyph": "•",
      "message_header_tag": ["cyan-fg"]
    }
  }
}

Style tokens for pretty_logs: bold, dim, red, green, yellow, blue, magenta, cyan, white.

prompts/system.md — System Prompt

The base system prompt loaded into every inference run. This is the first piece of context the LLM sees (via the context pipeline).

markdown
You are a helpful AI assistant. You communicate via email.

When you want to respond to the user, use the send_email tool with their
email address. Always be concise and helpful.

Available tools: shell, read_file, write_file, web_search, send_email.

If this file is missing, the system prompt contribution is empty.