Runner Configuration

The runner is a local daemon that watches the Supabase tasks table for queued work and executes it using an AI CLI (Claude Code or OpenAI Codex). It runs on your machine where the CLI is installed with all your plugins, skills, and configuration.

What the Runner Does

The runner is the execution engine of oversight. It continuously polls for queued tasks and dispatches them to the configured AI CLI. Task types include:

Starting the Runner

Terminal bash
pnpm runner

On first launch, the runner copies .env.example to .env if no .env exists. If required env vars are missing, it runs the interactive setup wizard (pnpm runner:setup).

User Resolution

Tasks are shared but scoped: each runner only picks up tasks created by its authenticated user. The runner resolves its identity in this order:

  1. Disk cache~/.oversight/runner-user-id from a previous session.
  2. RUNNER_USER_ID env var — explicit Supabase user UUID (useful for CI).
  3. Auto-detect — if exactly one user exists in the database, uses them automatically.
  4. Browser OAuth — opens the browser to GitHub login, same flow as the dashboard.

Poll Interval

The runner polls the tasks table every 3 seconds for new queued tasks. When a task is found, it is claimed atomically (status set to running) to prevent double-execution by other runners.

Concurrency: The runner processes tasks concurrently up to the MAX_CONCURRENT_TASKS limit defined in the shared package. When at capacity, the runner skips polling until a slot opens up.

Nightly Auto-Refresh

Every night during the 2:00–2:59 AM local time window, the runner automatically queues fresh PR and issue analyses for all repos where it is the designated steward. This keeps dashboards up to date without manual intervention.

The nightly refresh:

Steward Mode

Each repo can have a designated steward — a user whose runner picks up tasks from other users when their runners are offline. The steward runner polls for additional tasks on repos it stewards, checking:

Heartbeat Monitoring

The runner sends a heartbeat to the runner_heartbeats table every 60 seconds, recording:

The dashboard uses this to show runner status (online/offline). A runner is considered offline if its heartbeat is older than 90 seconds.

On shutdown, the runner sends a final heartbeat with running_tasks: 0 so the dashboard immediately reflects the offline state.

CLI Adapter System

The runner uses a pluggable adapter system to support different AI CLIs. Each adapter implements the same interface: spawning the process, parsing output, and detecting retryable errors.

AdapterCLIOutput FormatRetry Patterns
ClaudeAdapter claude Stream JSON (--output-format stream-json) 529, overloaded, rate limit, 502, 503, ETIMEDOUT, ECONNRESET
CodexAdapter codex JSON events (--json --full-auto) 429, 502, 503, rate limit, ETIMEDOUT, ECONNRESET, timeout

Adapter Selection

Controlled by the OVERSIGHT_CLI environment variable:

Retry Logic

When the CLI process fails with a transient error (overloaded API, rate limit, network timeout), the runner automatically retries up to 3 times with increasing delays: 30s, 60s, 90s. Non-transient errors (e.g. invalid prompt, missing permissions) fail immediately.

Self-Update

The runner can update itself to the latest code when triggered remotely via the runner_commands table. A self-update:

  1. Records the current git commit for rollback.
  2. Runs git fetch origin.
  3. Checks out and hard-resets to the target branch.
  4. Runs pnpm install --frozen-lockfile.
  5. If any step fails, rolls back to the original commit.
Remote restart: The dashboard can send a restart command to the runner via the runner_commands table. The runner watches for these commands using Supabase Realtime and restarts itself (with optional self-update) when triggered.

Repo Cache

The runner clones repositories into a local cache directory for review tasks. By default this is $TMPDIR/oversight-repo-cache, which is lost on reboot. For persistence, set OVERSIGHT_REPO_DIR to a stable path.

Each PR review checks out a fresh worktree from the cached clone, so reviews are isolated from each other and from the main clone.

Configuration Summary

SettingValueConfigurable
Poll interval 3 seconds Hardcoded
Heartbeat interval 60 seconds Hardcoded
Stale threshold 90 seconds Hardcoded
Nightly refresh window 2:00–2:59 AM local Hardcoded
Nightly refresh cooldown 20 hours Hardcoded
Max retry attempts 3 Hardcoded
CLI adapter Auto-detect (claude > codex) OVERSIGHT_CLI
Repo cache directory $TMPDIR/oversight-repo-cache OVERSIGHT_REPO_DIR
Runner user identity Auto-detect / browser login RUNNER_USER_ID