Configuration Reference¶
Every setting that shapes how Yeti operates, from the org it watches to the intervals between each patrol of your repositories.
Config file: ~/.yeti/config.json
Priority: Environment variables > config file > defaults
Changes to live-reloadable fields take effect without restarting the service. Other fields require a restart.
General Settings¶
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
githubOwners |
string[] |
["frostyard"] |
YETI_GITHUB_OWNERS (comma-sep) |
Yes | GitHub orgs/users to scan for repositories |
selfRepo |
string |
frostyard/yeti |
YETI_SELF_REPO |
Yes | Repository where Yeti files error issues about itself |
port |
number |
9384 |
PORT |
No | HTTP dashboard port |
authToken |
string |
"" |
YETI_AUTH_TOKEN |
Yes | Dashboard auth token (empty = no auth) |
allowedRepos |
string[] \| null |
null |
YETI_ALLOWED_REPOS (comma-sep) |
Yes | Repo allow-list. null means all repos under githubOwners are scanned |
logLevel |
"debug" \| "info" \| "warn" \| "error" |
"debug" |
YETI_LOG_LEVEL |
Yes | Minimum log level for console and stored logs |
logRetentionDays |
number |
14 |
-- | Yes | Delete logs older than N days |
logRetentionPerJob |
number |
20 |
-- | Yes | Max log runs to keep per job |
includeForks |
boolean |
false |
YETI_INCLUDE_FORKS |
Yes | Include forked repositories when scanning for work |
queueScanIntervalMs |
number |
300000 (5 min) |
-- | Yes | How often the lightweight queue label scanner runs |
AI Backend Settings¶
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
maxClaudeWorkers |
number |
2 |
YETI_MAX_CLAUDE_WORKERS |
Yes | Max concurrent Claude CLI processes |
claudeTimeoutMs |
number |
1200000 (20 min) |
YETI_CLAUDE_TIMEOUT_MS |
Yes | Timeout per Claude call (minimum 60s) |
maxCopilotWorkers |
number |
1 |
YETI_MAX_COPILOT_WORKERS |
Yes | Max concurrent Copilot CLI processes |
copilotTimeoutMs |
number |
1200000 (20 min) |
YETI_COPILOT_TIMEOUT_MS |
Yes | Timeout per Copilot call (minimum 60s) |
maxCodexWorkers |
number |
1 |
YETI_MAX_CODEX_WORKERS |
Yes | Max concurrent Codex CLI processes (0 to disable) |
codexTimeoutMs |
number |
1200000 (20 min) |
YETI_CODEX_TIMEOUT_MS |
Yes | Timeout per Codex call (minimum 60s) |
jobAi |
Record<string, {backend?, model?}> |
{} |
-- | Yes | Per-job AI backend and model overrides |
Discord Integration¶
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
discordBotToken |
string |
"" |
YETI_DISCORD_BOT_TOKEN |
No | Discord bot token (requires restart to connect) |
discordChannelId |
string |
"" |
YETI_DISCORD_CHANNEL_ID |
No | Discord channel for notifications |
discordAllowedUsers |
string[] |
[] |
YETI_DISCORD_ALLOWED_USERS (comma-sep) |
Yes | Discord user IDs allowed to run commands |
GitHub App Authentication¶
All three fields must be set to enable GitHub App auth. These fields require a restart --- they are read once at startup. See GitHub App Setup for a step-by-step guide.
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
githubAppId |
string |
"" |
YETI_GITHUB_APP_ID |
No | GitHub App ID (numeric string) |
githubAppInstallationId |
string |
"" |
YETI_GITHUB_APP_INSTALLATION_ID |
No | Installation ID for the App on your org |
githubAppPrivateKeyPath |
string |
"" |
YETI_GITHUB_APP_PRIVATE_KEY_PATH |
No | Absolute path to the App's .pem private key file |
GitHub OAuth (Dashboard Sign-In)¶
Optional. Enables "Sign in with GitHub" on the dashboard login page. All three fields must be set to activate OAuth. These fields require a restart. See GitHub App Setup — OAuth for setup steps.
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
githubAppClientId |
string |
"" |
YETI_GITHUB_APP_CLIENT_ID |
No | OAuth client ID from the GitHub App |
githubAppClientSecret |
string |
"" |
YETI_GITHUB_APP_CLIENT_SECRET |
No | OAuth client secret (sensitive — masked in API/dashboard) |
externalUrl |
string |
"" |
YETI_EXTERNAL_URL |
No | Public URL for OAuth callback, e.g., https://yeti.example.com |
Webhooks¶
Optional. Enables GitHub webhook support for near-real-time job triggers. See GitHub App Setup — Webhooks for setup steps.
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
webhookSecret |
string |
"" |
YETI_WEBHOOK_SECRET |
No | HMAC-SHA256 secret for verifying GitHub webhook payloads (sensitive — masked in API/dashboard) |
Job Control¶
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
enabledJobs |
string[] |
[] |
-- | Yes | Jobs to register. Empty = nothing runs. |
pausedJobs |
string[] |
[] |
-- | Yes | Paused job names (registered but not executing) |
skippedItems |
{repo, number}[] |
[] |
-- | Yes | Issues/PRs to skip during processing |
prioritizedItems |
{repo, number}[] |
[] |
-- | Yes | High-priority items processed first |
Plan Review Loop¶
| Field | Type | Default | Env Var | Live Reload | Description |
|---|---|---|---|---|---|
reviewLoop |
boolean |
false |
-- | Yes | Enable iterative plan refinement. When true, plan-reviewer can send plans back to issue-refiner instead of always marking Ready. |
maxPlanRounds |
number |
3 |
-- | Yes | Maximum plan→review cycles before falling through to human review. Minimum 1. |
Intervals¶
All interval fields live inside the intervals object, are specified in milliseconds, and are live-reloadable.
| Field | Default | Description |
|---|---|---|
issueWorkerMs |
300000 (5 min) |
issue-worker poll interval |
issueRefinerMs |
300000 (5 min) |
issue-refiner poll interval |
ciFixerMs |
600000 (10 min) |
ci-fixer poll interval |
reviewAddresserMs |
300000 (5 min) |
review-addresser poll interval |
autoMergerMs |
600000 (10 min) |
auto-merger poll interval |
triageYetiErrorsMs |
600000 (10 min) |
triage-yeti-errors poll interval |
planReviewerMs |
600000 (10 min) |
plan-reviewer poll interval |
Schedules¶
All schedule fields live inside the schedules object, are specified as hour of day in local timezone (0-23), and are live-reloadable.
| Field | Default | Description |
|---|---|---|
docMaintainerHour |
1 (1 AM) |
doc-maintainer run hour |
repoStandardsHour |
2 (2 AM) |
repo-standards run hour |
improvementIdentifierHour |
3 (3 AM) |
improvement-identifier run hour |
mkdocsUpdateHour |
4 (4 AM) |
mkdocs-update run hour |
issueAuditorHour |
5 (5 AM) |
issue-auditor run hour |
promptEvaluatorHour |
0 (Midnight) |
prompt-evaluator run hour |
Example: Per-Job AI Overrides¶
The jobAi field lets you route specific jobs to different AI backends or models. This is useful when you want a second perspective -- for instance, running plan reviews through a different provider than the one that wrote the plan.
{
"jobAi": {
"plan-reviewer": { "backend": "copilot" },
"doc-maintainer": { "backend": "codex" },
"issue-refiner": { "model": "opus" }
}
}
Supported backends: claude (default), copilot, and codex. When a backend is specified, the job's work is queued through that backend's worker pool (respecting its own concurrency limits and timeouts). When only a model is specified, the job still uses the default Claude backend but passes the model name through.
Example: Minimal Config¶
A cold-start configuration to get Yeti running on a single org with the essential jobs:
{
"githubOwners": ["my-org"],
"selfRepo": "my-org/yeti",
"authToken": "a-secret-token",
"enabledJobs": [
"issue-refiner",
"issue-worker",
"ci-fixer",
"auto-merger",
"repo-standards"
]
}
Example: Full Config¶
A more complete configuration with intervals, schedules, and integrations:
{
"githubOwners": ["my-org"],
"selfRepo": "my-org/yeti",
"authToken": "a-secret-token",
"discordBotToken": "discord-bot-token",
"discordChannelId": "1234567890",
"discordAllowedUsers": ["user-id-1", "user-id-2"],
"githubAppId": "123456",
"githubAppInstallationId": "78901234",
"githubAppPrivateKeyPath": "/home/yeti/.yeti/github-app.pem",
"githubAppClientId": "Iv1.abc123...",
"githubAppClientSecret": "your-client-secret",
"externalUrl": "https://yeti.example.com",
"webhookSecret": "your-webhook-secret",
"maxClaudeWorkers": 2,
"claudeTimeoutMs": 1200000,
"maxCopilotWorkers": 1,
"maxCodexWorkers": 1,
"includeForks": false,
"enabledJobs": [
"issue-refiner",
"plan-reviewer",
"issue-worker",
"ci-fixer",
"auto-merger",
"review-addresser",
"triage-yeti-errors",
"doc-maintainer",
"repo-standards",
"improvement-identifier",
"issue-auditor",
"mkdocs-update",
"prompt-evaluator"
],
"intervals": {
"issueWorkerMs": 300000,
"issueRefinerMs": 300000,
"ciFixerMs": 600000
},
"schedules": {
"docMaintainerHour": 1,
"repoStandardsHour": 2,
"improvementIdentifierHour": 3,
"mkdocsUpdateHour": 4,
"issueAuditorHour": 5,
"promptEvaluatorHour": 0
},
"jobAi": {
"plan-reviewer": { "backend": "copilot" }
},
"reviewLoop": false,
"maxPlanRounds": 3,
"logLevel": "debug",
"logRetentionDays": 14,
"logRetentionPerJob": 20
}