Skip to main content

Overview

The config module provides environment-based configuration loading with comprehensive validation and sensible defaults. All orchestrator settings are centralized here. Location: packages/orchestrator/src/config.ts

Main Functions

loadConfig()

Loads and validates configuration from environment variables.
function loadConfig(): OrchestratorConfig
Returns: Complete OrchestratorConfig object Throws: Error if required environment variables are missing or invalid

getConfig()

Returns cached config, loading it if not already loaded.
function getConfig(): OrchestratorConfig
Returns: Cached OrchestratorConfig

clearConfigCache()

Clears the configuration cache.
function clearConfigCache(): void
Useful for testing or dynamic reconfiguration.

Configuration Types

OrchestratorConfig

Main configuration interface extending HarnessConfig from @longshot/core.
interface OrchestratorConfig extends HarnessConfig {
  targetRepoPath: string         // Local path to target repository
  pythonPath: string             // Path to Python interpreter
  healthCheckInterval: number    // Monitor tick interval (seconds)
  readinessTimeoutMs: number     // LLM readiness probe timeout (ms)
  finalization: FinalizationConfig
}

FinalizationConfig

interface FinalizationConfig {
  maxAttempts: number      // Max finalization sweep attempts
  enabled: boolean         // Whether to run finalization phase
  sweepTimeoutMs: number   // Max time to wait for fix tasks
}

LLMConfig

Extracted from HarnessConfig:
type LLMConfig = OrchestratorConfig['llm']

interface LLMConfig {
  endpoints: LLMEndpoint[]
  model: string
  maxTokens: number
  temperature: number
  timeoutMs?: number
}

Environment Variables

Required

LLM_ENDPOINTS
JSON string
Array of LLM endpoint configurations. Format:
[
  {
    "name": "primary",
    "endpoint": "http://localhost:8000",
    "apiKey": "optional-key",
    "weight": 70
  }
]
LLM_BASE_URL
string
Fallback if LLM_ENDPOINTS not provided. Single endpoint URL.
GIT_REPO_URL
string
required
Target repository URL (e.g., https://github.com/user/repo.git)

Optional - LLM

LLM_MODEL
string
default:"glm-5"
Model identifier
LLM_API_KEY
string
API key for single-endpoint mode (used with LLM_BASE_URL)
LLM_MAX_TOKENS
number
default:"65536"
Maximum tokens per completion
LLM_TEMPERATURE
number
default:"0.7"
Sampling temperature (0.0 - 2.0)
LLM_TIMEOUT_MS
number
default:"120000"
Request timeout in milliseconds (2 minutes)
LLM_READINESS_TIMEOUT_MS
number
default:"120000"
Startup readiness probe timeout (0 = skip probe)

Optional - Git

GIT_MAIN_BRANCH
string
default:"main"
Main branch name
GIT_BRANCH_PREFIX
string
default:"worker/"
Prefix for worker branches
MERGE_STRATEGY
'fast-forward' | 'rebase' | 'merge-commit'
default:"rebase"
Primary merge strategy

Optional - Orchestrator

MAX_WORKERS
number
default:"50"
Maximum concurrent workers (min: 1)
WORKER_TIMEOUT
number
default:"1800"
Worker timeout in seconds (30 minutes)
TARGET_REPO_PATH
string
default:"./target-repo"
Local path to target repository
PYTHON_PATH
string
default:"python3"
Path to Python interpreter
HEALTH_CHECK_INTERVAL
number
default:"10"
Monitor tick interval in seconds

Optional - Sandbox

SANDBOX_IMAGE_TAG
string
default:"latest"
Sandbox container image tag
SANDBOX_CPU_CORES
number
default:"4"
CPU cores per sandbox
SANDBOX_MEMORY_MB
number
default:"8192"
Memory per sandbox in MB (8 GB)
SANDBOX_IDLE_TIMEOUT
number
default:"300"
Idle timeout in seconds (5 minutes)

Optional - Finalization

FINALIZATION_ENABLED
boolean
default:"true"
Whether to run finalization phase (set to “false” to disable)
FINALIZATION_MAX_ATTEMPTS
number
default:"3"
Maximum finalization sweep attempts (min: 1)
FINALIZATION_SWEEP_TIMEOUT_MS
number
default:"120000"
Max time to wait for fix tasks in milliseconds (2 minutes)

Optional - Logging

LOG_LEVEL
'debug' | 'info' | 'warn' | 'error'
default:"info"
Logging verbosity

Validation & Defaults

Endpoint Parsing

function parseEndpoints(): LLMEndpoint[]
Priority:
  1. LLM_ENDPOINTS (JSON array)
  2. LLM_BASE_URL (single endpoint, backwards compatible)
Validation:
  • At least one endpoint required
  • Each endpoint must have name, endpoint, and numeric weight
  • URLs normalized: trailing slashes removed, /v1 suffix stripped
Example:
export LLM_ENDPOINTS='[
  {"name":"primary","endpoint":"http://localhost:8000/v1/","weight":70},
  {"name":"backup","endpoint":"http://backup:8000","weight":30}
]'
Normalized to:
[
  { name: 'primary', endpoint: 'http://localhost:8000', weight: 70 },
  { name: 'backup', endpoint: 'http://backup:8000', weight: 30 }
]

Number Parsing

function parseNumberWithDefault(
  raw: string | undefined,
  fallback: number,
  envName: string
): number
Parses and validates numeric environment variables:
  • Returns fallback if undefined or invalid
  • Logs warning on invalid values
  • Never throws

Clamping

function clampMin(value: number, min: number, envName: string): number
Ensures value is at least min:
const maxWorkers = clampMin(
  parseNumberWithDefault(process.env.MAX_WORKERS, 50, 'MAX_WORKERS'),
  1,
  'MAX_WORKERS'
)
// MAX_WORKERS=0 → clamped to 1 (with warning)

Positive Enforcement

function ensurePositiveOrDefault(
  value: number,
  fallback: number,
  envName: string
): number
Returns fallback if value <= 0.

Usage Example

Environment File (.env)

# Required
GIT_REPO_URL=https://github.com/user/my-project.git
LLM_ENDPOINTS='[{"name":"local","endpoint":"http://localhost:8000","weight":100}]'

# Optional overrides
MAX_WORKERS=20
WORKER_TIMEOUT=3600
LLM_MODEL=gpt-4
LLM_MAX_TOKENS=32768
MERGE_STRATEGY=rebase
FINALIZATION_MAX_ATTEMPTS=5

TypeScript Usage

import { loadConfig, getConfig } from '@longshot/orchestrator'

// Load on startup
const config = loadConfig()

console.log(`Max workers: ${config.maxWorkers}`)
console.log(`LLM model: ${config.llm.model}`)
console.log(`Endpoints: ${config.llm.endpoints.map(e => e.name).join(', ')}`)
console.log(`Merge strategy: ${config.mergeStrategy}`)
console.log(`Finalization enabled: ${config.finalization.enabled}`)

// Later, get cached config
const cached = getConfig()  // Same instance

// Testing: clear cache between tests
import { clearConfigCache } from '@longshot/orchestrator'

afterEach(() => {
  clearConfigCache()
})

Merge Strategy Validation

const ALLOWED_MERGE_STRATEGIES = ['fast-forward', 'rebase', 'merge-commit'] as const
type MergeStrategy = typeof ALLOWED_MERGE_STRATEGIES[number]

const mergeStrategy = process.env.MERGE_STRATEGY || 'rebase'
if (!ALLOWED_MERGE_STRATEGIES.includes(mergeStrategy)) {
  throw new Error(`Invalid MERGE_STRATEGY: ${mergeStrategy}`)
}

Error Handling

Missing Required Vars:
if (!gitRepoUrl) {
  throw new Error('Missing required env: GIT_REPO_URL')
}
Invalid JSON:
try {
  parsedRaw = JSON.parse(endpointsJson)
} catch (error) {
  throw new Error(`Invalid JSON in LLM_ENDPOINTS: ${error.message}`)
}
Invalid Structure:
if (!isEndpointEnvConfig(ep)) {
  throw new Error('Each LLM_ENDPOINTS item must contain name, endpoint, and numeric weight')
}

Best Practices

Use Environment Files:
# Load .env automatically in main.ts
import { config as loadDotenv } from 'dotenv'
loadDotenv({ path: resolve(process.cwd(), '.env') })
Validate Early:
// Load config at application startup to fail fast
const config = loadConfig()
logger.info('Config loaded successfully', { maxWorkers: config.maxWorkers })
Use Typed Access:
// TypeScript provides autocomplete and type checking
const timeout: number = config.workerTimeout
const strategy: MergeStrategy = config.mergeStrategy
Clear Cache in Tests:
import { clearConfigCache } from '@longshot/orchestrator'

afterEach(() => {
  clearConfigCache()  // Prevent test pollution
})

Build docs developers (and LLMs) love