singularity-forge/docs/ENV.md

11 KiB

Environment Configuration Schema

Status: Implemented and tested (25 test cases) File: src/env.ts Tests: src/tests/env.test.ts

Overview

SF uses 80+ SF_* environment variables to control behavior at startup and runtime. Previously, these were read directly from process.env throughout the codebase, leading to:

  • Silent failures when config was missing (no errors, just wrong behavior)
  • Type-unsafe access (IDE couldn't auto-complete, linters couldn't check)
  • No documentation about what variables exist or what they do
  • Scattered default logic (each module computed its own defaults)

This schema provides centralized, type-safe, validated access to all SF configuration.

Quick Start

Using the env schema

import { getCompleteSfEnv } from "./env";

// Get fully validated, type-safe environment config
const config = getCompleteSfEnv();

// IDE completion works:
config.SF_DEBUG;      // boolean
config.SF_HOME;       // string
config.sfHome;        // computed default
config.stateDir;      // computed default (SF_STATE_DIR or SF_HOME)

Setting variables

# Enable debug mode
export SF_DEBUG=1

# Set custom home directory
export SF_HOME=/opt/sf

# Disable RTK compression
export SF_RTK_DISABLED=1

# Enable the machine surface with prompt tracing
export SF_HEADLESS=1
export SF_HEADLESS_PROMPT_TRACE=1

Schema Categories

Core Paths (set by loader.ts)

  • SF_PKG_ROOT — Package installation root (where SF is installed)
  • SF_BIN_PATH — Path to the SF executable (used for spawning)
  • SF_VERSION — Package version from package.json
  • SF_WORKFLOW_PATH — Path to bundled SF-WORKFLOW.md
  • SF_BUNDLED_EXTENSION_PATHS — Serialized extension manifests
  • SF_CODING_AGENT_DIR — PI SDK agent directory

Directories

All directory variables are optional and have sensible defaults:

  • SF_HOME (default: ~/.sf) — Root state directory
  • SF_STATE_DIR (default: SF_HOME) — Milestone/slice/task state
  • SF_WORKSPACE_BASE (default: SF_STATE_DIR/workspace) — User workspaces
  • SF_HISTORY_BASE (default: SF_STATE_DIR/history) — Session history
  • SF_NOTIFICATIONS_BASE (default: SF_STATE_DIR/notifications) — Notifications
  • SF_SCHEDULE_FILE (legacy import only; default: SF_STATE_DIR/schedule.jsonl) — pre-DB schedule queue compatibility input
  • SF_RECOVERY_BASE (default: SF_STATE_DIR/recovery) — Recovery artifacts
  • SF_FORENSICS_BASE (default: SF_STATE_DIR/forensics) — Diagnostics
  • SF_SETTINGS_BASE (default: SF_STATE_DIR/settings) — User settings
  • And 5+ more for specific recovery/export/cleanup artifacts

Performance Tuning

  • SF_RTK_DISABLED (boolean: 0/1, default: 0) — Disable RTK compression
  • SF_RTK_PATH — Custom path to RTK tool (auto-detected)
  • SF_RTK_REWRITE_TIMEOUT_MS (integer, default: 5000) — Timeout in ms
  • SF_CIRCUIT_BREAKER_OPEN_DURATION_MS (integer, default: 60000)
  • SF_CIRCUIT_BREAKER_FAILURE_THRESHOLD (integer, default: 5)
  • SF_CIRCUIT_BREAKER_HALF_OPEN_MAX_ATTEMPTS (integer, default: 2)
  • SF_HEADLESS_PROMPT_TRACE_CHARS (integer, default: 1000)

Debug Flags

All debug flags are 0 or 1 (disabled or enabled):

  • SF_QUIET — Suppress startup banner
  • SF_DEBUG — Enable verbose logging
  • SF_DEBUG_EXTENSIONS — Enable extension debug logging
  • SF_TRACE_ENABLED — Collect execution traces
  • SF_HEADLESS — Suppress TUI for the machine surface, use stdio only
  • SF_HEADLESS_PROMPT_TRACE — Trace prompts in the machine surface
  • SF_STARTUP_TIMING — Measure cold-start latency
  • SF_SHOW_TOKEN_COST — Show LLM token costs
  • SF_FIRST_RUN_BANNER — Show first-run welcome
  • SF_DISABLE_STARTUP_DOCTOR — Skip health checks
  • SF_ENGINE_BYPASS — Use JS implementation instead of Rust
  • SF_DISABLE_NATIVE_SF_PARSER — Disable native parser
  • SF_DISABLE_NATIVE_SF_GIT — Disable native git

Extensions

  • SF_SKILL_MANIFEST_STRICT (boolean) — Fail on invalid manifests
  • SF_PERMISSION_LEVEL (enum: full, restricted, sandbox, default: sandbox)
  • SF_GEMINI_PERMISSION_MODE (enum: ask, auto, deny, default: ask)
  • SF_SESSION_BROWSER_DIR — Override browser session directory
  • SF_SESSION_BROWSER_CWD — Override browser working directory
  • SF_FETCH_ALLOWED_URLS — Comma-separated list of allowed URLs
  • SF_ALLOWED_COMMAND_PREFIXES — Comma-separated command prefixes

Recovery and Dispatch

  • SF_RECOVERY_DOCTOR_MODULE — Custom recovery doctor module
  • SF_RECOVERY_FORENSICS_MODULE — Custom forensics module
  • SF_RECOVERY_SCOPE (enum: unit, milestone, global, default: unit)
  • SF_RECOVERY_SESSION_FILE — Recovery session state path
  • SF_RECOVERY_ACTIVITY_DIR — Recovery activity logs
  • SF_PARALLEL_WORKER (boolean) — Enable parallel worker mode
  • SF_WORKER_MODEL — Model for worker dispatch
  • SF_MILESTONE_LOCK — Lock file for milestone operations
  • SF_SLICE_LOCK — Lock file for slice operations
  • SF_WORKTREE — Current git worktree
  • SF_CLI_WORKTREE — CLI worktree path
  • SF_CLI_WORKTREE_BASE — CLI worktree base directory
  • SF_CLEANUP_BRANCHES (boolean, default: 1) — Enable branch cleanup
  • SF_CLEANUP_SNAPSHOTS (boolean, default: 1) — Enable snapshot cleanup

Settings Modules

All optional (allow custom implementations):

  • SF_SETTINGS_BUDGET_MODULE — Custom budget settings
  • SF_SETTINGS_HISTORY_MODULE — Custom history settings
  • SF_SETTINGS_METRICS_MODULE — Custom metrics settings
  • SF_SETTINGS_PREFS_MODULE — Custom preferences settings
  • SF_SETTINGS_ROUTER_MODULE — Custom router settings
  • SF_WORKSPACE_MODULE — Custom workspace module
  • SF_SESSION_MANAGER_MODULE — Custom session manager

Miscellaneous

  • SF_TRIAGE_SUFFIX (default: _triage) — Suffix for triaged issues
  • SF_PROJECT_ID — Current project ID (UUID)
  • SF_DOCTOR_SCOPE (enum: fast, normal, deep, default: normal)
  • SF_EXPORT_FORMAT (enum: json, csv, markdown, default: json)
  • SF_TARGET_SESSION_NAME — Target session for testing
  • SF_TARGET_SESSION_PATH — Target session path for testing
  • SF_VISUALIZER_BASE — Visualization output directory

API Reference

getCompleteSfEnv(env?: NodeJS.ProcessEnv): CompleteSfEnv

Primary entry point. Returns fully validated environment configuration with computed defaults.

const config = getCompleteSfEnv();

// Type-safe access
console.log(config.SF_DEBUG);        // boolean
console.log(config.SF_HOME);         // string or undefined
console.log(config.sfHome);          // string (computed default)
console.log(config.stateDir);        // string (computed from SF_STATE_DIR || SF_HOME)
console.log(config.agentDir);        // string (computed from SF_AGENT_DIR || SF_CODING_AGENT_DIR || sfHome/agent)

parseCompleteSfEnv(env?: NodeJS.ProcessEnv): CompleteSfEnv

Alternative: Parse environment with graceful degradation (doesn't throw on validation errors).

getSfEnv(env?: NodeJS.ProcessEnv): SfEnv

Backward-compatible: Parses minimal schema (original set of variables). Use getCompleteSfEnv() for new code.

getEnvValidationSummary(env?: NodeJS.ProcessEnv): { configured: string[], defaults: string[], total: number }

For diagnostics: Shows which variables are explicitly set vs using defaults.

const summary = getEnvValidationSummary();
console.log(`Configured: ${summary.configured.length}/${summary.total}`);
console.log(`Using defaults: ${summary.defaults.length}`);

Schema Design

Zod-based validation

Uses Zod for composable, type-safe schema definition:

// Boolean flags (0 or 1)
const booleanOneZero = z
  .enum(["0", "1"])
  .transform((value) => value === "1")
  .optional();

// Positive integers (parsed from strings)
const positiveInteger = z
  .string()
  .transform((v) => parseInt(v, 10))
  .pipe(z.number().int().positive());

// Enums with defaults
SF_PERMISSION_LEVEL: z.enum(["full", "restricted", "sandbox"]).optional()

Two-schema approach

Minimal schema (sfEnvSchema):

  • Backward-compatible with existing code
  • 8 essential variables
  • Used by loader.ts, CLI entry points

Complete schema (completeSfEnvSchema):

  • All 80+ known SF_* variables
  • Organized by category
  • Comprehensive validation and defaults
  • Used by modules needing full environment access

Graceful degradation

If validation fails:

  • getCompleteSfEnv() returns partial config (missing fields undefined)
  • No throws (never blocks dispatch)
  • Warnings logged to stderr if SF_DEBUG=1
  • Allows SF to run with misconfigured variables (degraded behavior)

Testing

All 25 tests passing. Coverage includes:

  • Boolean flag parsing (0 → false, 1 → true)
  • Enum validation (rejects invalid values)
  • Integer parsing and validation (positive only)
  • Default computation (SF_HOME, SF_STATE_DIR, agentDir)
  • Fallback behavior (graceful degradation)
  • Round-trip parsing consistency
# Run tests
npm run test:unit -- src/tests/env.test.ts

Migration Guide

For existing code reading process.env.SF_* directly

Before:

const debug = process.env.SF_DEBUG === "1";
const home = process.env.SF_HOME || join(homedir(), ".sf");

After:

import { getCompleteSfEnv } from "./env";
const config = getCompleteSfEnv();
const debug = config.SF_DEBUG;  // already parsed boolean
const home = config.sfHome;     // already computed default

For modules needing environment access

  1. Import at module level:

    import { getCompleteSfEnv } from "./env";
    
  2. Call in initialization (not hot path):

    const config = getCompleteSfEnv();
    
  3. Pass config to functions instead of re-reading process.env

Why This Matters

Problem: Silent misconfiguration

# Typo in env var name (SF_DEBG instead of SF_DEBUG)
export SF_DEBG=1

# SF runs normally but without debug logging (silent failure)
sf run

Solution: Centralized validation catches mistakes early

const config = getCompleteSfEnv();
// Now SF knows all 80+ valid variable names
// Unknown variables can trigger warnings

Benefit: Type safety

// IDE auto-completion works
config.SF_DEBUG              // ✓ recognized
config.SF_DEBG               // ✗ compile error
config.unknownVar            // ✗ compile error

// Future refactors are safe (rename variables with confidence)

Future Enhancements

  1. Config file support (.sfrc.json with env override)
  2. Env schema generation (export schema as JSON Schema for docs)
  3. Config diagnostics (sf doctor --env shows all settings)
  4. Secrets redaction (API keys not logged)
  5. Per-project overrides (project-specific .sf/.env)

See Also

  • src/env.ts — Implementation
  • src/tests/env.test.ts — Test suite
  • .nvmrc — Node.js version (requires Zod support)