feat: comprehensive environment schema with type-safe validation
- Expand env.ts with completeSfEnvSchema covering all 80+ SF_* variables
- Organize variables into logical categories (core, directories, performance, debug, extensions, recovery, settings, misc)
- Add typed API: getCompleteSfEnv(), parseCompleteSfEnv(), getEnvValidationSummary()
- Support graceful degradation (missing config returns partial data, never throws)
- Add 25 comprehensive test cases covering schema, parsing, defaults, round-trips
- Document in docs/ENV.md with quick start, API reference, migration guide
Purpose: Prevent silent misconfiguration by centralizing environment validation,
enabling IDE auto-completion, and providing clear defaults. Callers get type-safe
access to all config instead of scattered process.env reads.
Consumers: loader.ts for startup validation, all modules reading configuration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 00:31:59 +02:00
# 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
```typescript
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
```bash
# Enable debug mode
export SF_DEBUG=1
# Set custom home directory
export SF_HOME=/opt/sf
# Disable RTK compression
export SF_RTK_DISABLED=1
2026-05-08 00:17:47 +02:00
# Enable the machine surface with prompt tracing
feat: comprehensive environment schema with type-safe validation
- Expand env.ts with completeSfEnvSchema covering all 80+ SF_* variables
- Organize variables into logical categories (core, directories, performance, debug, extensions, recovery, settings, misc)
- Add typed API: getCompleteSfEnv(), parseCompleteSfEnv(), getEnvValidationSummary()
- Support graceful degradation (missing config returns partial data, never throws)
- Add 25 comprehensive test cases covering schema, parsing, defaults, round-trips
- Document in docs/ENV.md with quick start, API reference, migration guide
Purpose: Prevent silent misconfiguration by centralizing environment validation,
enabling IDE auto-completion, and providing clear defaults. Callers get type-safe
access to all config instead of scattered process.env reads.
Consumers: loader.ts for startup validation, all modules reading configuration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 00:31:59 +02:00
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
2026-05-07 05:34:42 +02:00
- `SF_SCHEDULE_FILE` (legacy import only; default: `SF_STATE_DIR/schedule.jsonl` ) — pre-DB schedule queue compatibility input
feat: comprehensive environment schema with type-safe validation
- Expand env.ts with completeSfEnvSchema covering all 80+ SF_* variables
- Organize variables into logical categories (core, directories, performance, debug, extensions, recovery, settings, misc)
- Add typed API: getCompleteSfEnv(), parseCompleteSfEnv(), getEnvValidationSummary()
- Support graceful degradation (missing config returns partial data, never throws)
- Add 25 comprehensive test cases covering schema, parsing, defaults, round-trips
- Document in docs/ENV.md with quick start, API reference, migration guide
Purpose: Prevent silent misconfiguration by centralizing environment validation,
enabling IDE auto-completion, and providing clear defaults. Callers get type-safe
access to all config instead of scattered process.env reads.
Consumers: loader.ts for startup validation, all modules reading configuration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 00:31:59 +02:00
- `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
2026-05-08 00:17:47 +02:00
- `SF_HEADLESS` — Suppress TUI for the machine surface, use stdio only
- `SF_HEADLESS_PROMPT_TRACE` — Trace prompts in the machine surface
feat: comprehensive environment schema with type-safe validation
- Expand env.ts with completeSfEnvSchema covering all 80+ SF_* variables
- Organize variables into logical categories (core, directories, performance, debug, extensions, recovery, settings, misc)
- Add typed API: getCompleteSfEnv(), parseCompleteSfEnv(), getEnvValidationSummary()
- Support graceful degradation (missing config returns partial data, never throws)
- Add 25 comprehensive test cases covering schema, parsing, defaults, round-trips
- Document in docs/ENV.md with quick start, API reference, migration guide
Purpose: Prevent silent misconfiguration by centralizing environment validation,
enabling IDE auto-completion, and providing clear defaults. Callers get type-safe
access to all config instead of scattered process.env reads.
Consumers: loader.ts for startup validation, all modules reading configuration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 00:31:59 +02:00
- `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
2026-05-14 21:11:36 +02:00
- `SF_PERMISSION_LEVEL` (enum: `minimal` , `low` , `medium` , `high` , `bypassed` , default: `minimal` )
feat: comprehensive environment schema with type-safe validation
- Expand env.ts with completeSfEnvSchema covering all 80+ SF_* variables
- Organize variables into logical categories (core, directories, performance, debug, extensions, recovery, settings, misc)
- Add typed API: getCompleteSfEnv(), parseCompleteSfEnv(), getEnvValidationSummary()
- Support graceful degradation (missing config returns partial data, never throws)
- Add 25 comprehensive test cases covering schema, parsing, defaults, round-trips
- Document in docs/ENV.md with quick start, API reference, migration guide
Purpose: Prevent silent misconfiguration by centralizing environment validation,
enabling IDE auto-completion, and providing clear defaults. Callers get type-safe
access to all config instead of scattered process.env reads.
Consumers: loader.ts for startup validation, all modules reading configuration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 00:31:59 +02:00
- `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.
```typescript
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.
```typescript
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 ](https://zod.dev ) for composable, type-safe schema definition:
```typescript
// 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
2026-05-14 21:11:36 +02:00
SF_PERMISSION_LEVEL: z.enum(["minimal", "low", "medium", "high", "bypassed"]).optional()
feat: comprehensive environment schema with type-safe validation
- Expand env.ts with completeSfEnvSchema covering all 80+ SF_* variables
- Organize variables into logical categories (core, directories, performance, debug, extensions, recovery, settings, misc)
- Add typed API: getCompleteSfEnv(), parseCompleteSfEnv(), getEnvValidationSummary()
- Support graceful degradation (missing config returns partial data, never throws)
- Add 25 comprehensive test cases covering schema, parsing, defaults, round-trips
- Document in docs/ENV.md with quick start, API reference, migration guide
Purpose: Prevent silent misconfiguration by centralizing environment validation,
enabling IDE auto-completion, and providing clear defaults. Callers get type-safe
access to all config instead of scattered process.env reads.
Consumers: loader.ts for startup validation, all modules reading configuration.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-07 00:31:59 +02:00
```
### 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
```bash
# Run tests
npm run test:unit -- src/tests/env.test.ts
```
## Migration Guide
### For existing code reading `process.env.SF_*` directly
**Before**:
```typescript
const debug = process.env.SF_DEBUG === "1";
const home = process.env.SF_HOME || join(homedir(), ".sf");
```
**After**:
```typescript
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:
```typescript
import { getCompleteSfEnv } from "./env";
```
2. Call in initialization (not hot path):
```typescript
const config = getCompleteSfEnv();
```
3. Pass config to functions instead of re-reading process.env
## Why This Matters
**Problem**: Silent misconfiguration
```bash
# 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
```typescript
const config = getCompleteSfEnv();
// Now SF knows all 80+ valid variable names
// Unknown variables can trigger warnings
```
**Benefit**: Type safety
```typescript
// 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)