Configuration
Dark Factory is configured through godark.yaml in your project root, with CLI flags available as overrides.
godark.yaml
Here's a complete example showing all available fields:
# ── Required ──
repo: owner/my-project
# ── Build Commands (auto-detected by godark init) ──
format_command: "gofmt -w ."
build_command: "go build ./..."
test_command: "go test ./..."
lint_command: "go vet ./..."
generate_command: "go generate ./..."
# ── Agent Behavior ──
model: "" # Claude model: "sonnet" (default) or "opus"
max_retries: 3 # Review/fix retry cycles per issue
max_resume_retries: 2 # At attempt N >= this, start fresh session
max_rebase_attempts: 1 # Auto-rebase cycles before needs-human-review
agent_timeout: "30m" # Timeout per agent execution
quality_strictness_decay: true # Relax quality gates on successive retries
# ── Safety ──
protected_paths: # Files agents cannot modify
- godark.yaml
denied_commands: # Patterns forbidden in agent execution
- "rm -rf"
- "git push --force"
- "git push -f"
- "git reset --hard"
- "git clean -f"
generated_paths: # Files agents must not hand-edit (generated)
- "api/gen/"
- "**/*.freezed.dart"
enforce_architecture: false # Reviewer rejects layer violations when true
# ── Paths ──
roadmap_path: "docs/ROADMAP.md"
planning_dir: "docs/planning/"
scenario_dir: "tests/scenarios/"
review_dir: "tests/review/"
architecture_doc: "docs/architecture.md"
architecture_json: "docs/architecture.json"
conventions_doc: "docs/conventions.md"
base_branch: "main"
default_branch: "main" # Auto-detected from GitHub if omitted
branch_prefix: "godark" # Prefix for auto-generated branch names
label_prefix: "godark" # Prefix for GitHub labels
# ── Auth ──
auth_preference: "oauth" # "oauth" or "api_key"
required_env: # Must be set before run starts
- CUSTOM_API_KEY Runtime & Docker
Configure the project runtime and Docker sandbox settings:
runtime:
name: "go" # go, flutter, node, rust, python, elixir
version: "1.26.0" # Optional — auto-detected if empty
docker:
image: "ubuntu:22.04" # Base Docker image
dockerfile: "Dockerfile.devloop" # Custom Dockerfile (optional)
mount: "/workspace" # Container mount point
user: "devloop" # Container user
node_version: "20" # Node.js version if needed
extra_packages: # Additional APT packages
- chromium
- ffmpeg
install_commands: # Custom install commands
- "pip install -r requirements.txt"
sandbox_env: # Environment vars passed to Docker
GOOS: linux
GOARCH: arm64 Auto Merge
Merging happens at two points, each with its own strategy:
feature— controls each issue PR merging into the base branch (e.g.,42-add-endpoint→godark/phase-3)rollup— controls the base branch merging into the default branch (e.g.,godark/phase-3→main)
# issue PR ──┐
# issue PR ──┼──► base branch ──► main
# issue PR ──┘
# ^ ^
# feature merge rollup merge
auto_merge:
feature: "none" # none | low_risk | all
rollup: "manual" # none | manual | auto When base_branch equals your default branch (or isn't set), there is no rollup step — issue PRs merge directly to main and the rollup setting is ignored.
| Strategy | Issue PRs (feature) | Base → Main (rollup) |
|---|---|---|
none | PRs are created but not merged | No rollup PR created |
low_risk | Merge if under risk thresholds | — |
all | Merge all approved PRs | — |
manual | — | Create rollup PR, wait for human merge |
auto | — | Merge rollup PR automatically |
Risk Thresholds
Used by the low_risk feature merge strategy to classify PRs:
risk_thresholds:
max_lines: 200 # Max changed lines for low_risk classification
max_files: 10 # Max changed files for low_risk classification Prompts
Override the default prompt templates for each agent role:
prompts:
implementer: "prompts/implementer.txt"
implementer_retry: "prompts/implementer_retry.txt"
reviewer: "prompts/reviewer.txt"
quality_reviewer: "prompts/quality_reviewer.txt"
spec_generator: "prompts/spec_generator.txt"
punchlist: "prompts/punchlist.txt"
verify_fix: "prompts/verify_fix.txt"
recon: "prompts/recon.txt" Prompt templates support template variables that are populated at runtime with issue data, file paths, and configuration values.
Modules
For monorepos or multi-module projects, override build commands per module:
modules:
backend:
build_command: "go build ./..."
test_command: "go test ./..."
lint_command: "go vet ./..."
depends_on: ["core"]
frontend:
build_command: "npm run build"
test_command: "npm test"
lint_command: "eslint ."
core:
build_command: "go build ./..."
test_command: "go test ./..." Module names must match ^[a-zA-Z0-9._-]+$. Dependencies are validated for cycles.
Quality & Verification
quality:
min_review_cost_usd: 0.0 # Quality gate: minimum review cost (0 = disabled)
min_review_duration_seconds: 0 # Quality gate: minimum review duration (0 = disabled)
verify:
max_fix_attempts: 2 # Fix cycles per verify failure
blocking: true # Verify failures block merge
truncation:
verify_output: 4096 # Max bytes from verify command output
pr_diff: 30000 # Max bytes from PR diff in prompts CI Checks
Wait for CI checks to pass before merging:
wait_for_checks:
timeout: "10m" # Max wait time (Go duration string)
required: # CI check names to wait for
- "test"
- "lint"
- "build" Notifications
Get notified about run events. Environment variable references (${VAR}) are expanded from the host environment:
notify:
- provider: "telegram"
events:
- "run_complete"
- "implementation_complete"
- "abort"
settings:
bot_token: "${TELEGRAM_BOT_TOKEN}"
chat_id: "${TELEGRAM_CHAT_ID}" Watch Mode
watch:
poll_interval: "60s" # How often to check for review feedback Judge (Container Health Monitor)
The judge monitors agent containers for hangs, tool thrashing, and transport failures. Disable with --no-judge on the CLI.
judge:
enabled: true # Enable/disable the judge
default_idle_timeout: 300 # Seconds before killing an idle container
idle_timeout_by_role: {} # Per-role overrides (e.g. implementer: 600)
default_no_progress_timeout: 0 # Seconds with no progress before kill (0 = disabled)
no_progress_timeout_by_role: {} # Per-role overrides
tool_thrash_threshold: 3 # Repeated tool calls to trigger thrash detection
tool_thrash_window_secs: 60 # Window for thrash detection
transport_failure_threshold: 10 # Max consecutive transport failures
container_retry_limit: 2 # Max container restarts before giving up Docker Compose
Bring up dependent services (databases, caches, etc.) alongside agent containers:
docker_compose:
file: "docker-compose.test.yml" # Path to compose file (required)
project_name: "" # Optional prefix (auto-generated if empty)
services: # Optional service descriptions
- name: postgres
description: "PostgreSQL 16 test database on port 5432"
- name: redis
description: "Redis 7 cache on port 6379" Host Services
Declare services running on the host that agents depend on. Health checks run before each agent execution:
host_services:
- name: supabase
description: "Supabase local stack"
health_check:
command: "curl -sf http://localhost:54321/rest/v1/"
timeout: "5s"
retries: 3 GitHub Authentication
Godark resolves a GitHub token using the following priority:
- GitHub App installation token - all three
GODARK_APP_*variables set GH_TOKEN- a personal access token exported in the environmentgh auth token- falls back to the GitHub CLI's stored credential
App auth is preferred for shared or team use: installation tokens are short-lived, rotate automatically before each agent launch, and commits are attributed to the App's bot account (godark-runner[bot]) instead of a human user.
GitHub App Setup
Once IT (or an org admin) provisions a GitHub App and installs it on the target repository, you'll have an App ID, an Installation ID, and a downloaded .pem private key. Configure godark in three steps:
1. Save the private key to disk.
mkdir -p ~/.godark
mv ~/Downloads/your-app.*.private-key.pem ~/.godark/github-app.pem
chmod 600 ~/.godark/github-app.pem 2. Export the three environment variables (add these to ~/.zshrc or ~/.bashrc):
export GODARK_APP_ID=<App ID>
export GODARK_APP_INSTALLATION_ID=<Installation ID>
export GODARK_APP_PRIVATE_KEY_PATH="$HOME/.godark/github-app.pem" All three must be set together. If any one is missing, godark silently falls back to GH_TOKEN / gh auth - it does not partially use App config.
3. (Optional) Keep GH_TOKEN for personal gh CLI use. When App creds are present, godark mints an installation token and overrides GH_TOKEN only within its own process and the containers it spawns. Your interactive shell's GH_TOKEN is untouched, so gh commands you run yourself still use your PAT.
App Configuration
Repository permissions the App needs:
- Actions: Read-only
- Checks: Read-only
- Contents: Read & Write
- Issues: Read & Write
- Pull requests: Read & Write
Other settings:
- Webhook: disabled (godark polls GitHub; no callback URL needed)
- User authorization (OAuth): not required (server-to-server installation auth only)
Once the App is created and installed on the target repo, the three values godark needs are:
- App ID - shown on the App's General settings page
- Installation ID - the numeric segment in the URL after installing:
/installations/<id> - Private key - generate and download the
.pem; keep it only on the workstation that runs godark
Environment Variables
| Variable | Purpose | Required |
|---|---|---|
ANTHROPIC_API_KEY | Anthropic API authentication | If OAuth not set |
CLAUDE_CODE_OAUTH_TOKEN | Anthropic OAuth token (preferred) | If API key not set |
GH_TOKEN | GitHub authentication (PAT) | If App auth not configured |
GODARK_APP_ID | GitHub App ID (app-based auth) | App auth: all three required |
GODARK_APP_INSTALLATION_ID | GitHub App installation ID | App auth: all three required |
GODARK_APP_PRIVATE_KEY_PATH | Path to GitHub App private key (PEM) | App auth: all three required |
See GitHub Authentication for how App creds and GH_TOKEN interact. Additional variables listed in required_env must be set or the run will fail. These are forwarded into the Docker sandbox automatically.