- src/headless-events.ts: add case "reload" → EXIT_RELOAD (12).
EXIT_RELOAD sentinel was defined but unused — "reload" status fell
through to EXIT_ERROR (1).
- src/resources/extensions/sf/notification-store.ts:109: use <= for
dedup window so a second identical notification at exactly
DEDUP_WINDOW_MS still gets suppressed (was off-by-one at boundary).
- src/resources/extensions/sf/definition-loader.ts: pending docstring
tweaks from autonomous sweep.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- new worktree-root.ts / worktree-session-state.ts: track and restore
original project root after /worktree merge or /worktree return
- new tools/skip-slice.ts: cascade skip to tasks in the slice so milestone
completion isn't blocked by pending tasks (#4375)
- auto/run-unit.ts: anchor cwd to basePath before newSession() captures it
(GAP-10) — prevents tool runtime / system prompt from rooting on drifted
cwd from async_bash, background jobs, or prior unit cleanup
- safety/git-checkpoint.ts: harden HEAD-rev-parse against execFileSync
errors, surface stderr properly
- broad JSDoc / docstring pass across the rest of the SF extension surface
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace ~700 LOC of hand-rolled OAuth and onboarding with cli-core's own
getOauthClient + setupUser. The provider now reads ~/.gemini/oauth_creds.json
itself (via cli-core), refreshes tokens, and discovers the Code Assist
project + tier server-side — exactly like the real gemini CLI does.
- provider/google-gemini-cli.ts: drop apiKey={token,projectId} JSON
plumbing; getCodeAssistServer() uses cli-core for everything
- delete utils/oauth/google-gemini-cli.ts (457 LOC: hand-rolled login,
PKCE, callback server, discoverProject, onboardUser, tier handling)
- delete utils/oauth/google-oauth-utils.ts (201 LOC: only consumed by
the deleted gemini-cli helper)
- oauth/index.ts: remove gemini-cli from BUILT_IN_OAUTH_PROVIDERS
registry; google-gemini-cli is no longer SF-managed
- auth-storage.ts: update 3 error messages to direct users to the real
gemini CLI for authentication instead of the removed /login command
Login UX: users authenticate with the real gemini CLI; we just consume
~/.gemini/oauth_creds.json. Whole-provider disable goes through manual
settings.json edit (per-model toggle still works in interactive UI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`/sf autonomous full` (or `--full`) plumbs through to AutoSession.fullAutonomy,
to be consumed at milestone-complete to skip the human-review pause and
auto-merge + chain to the next milestone. Git revert is the safety net
(see ADR-019/021 conversation on autonomy and reversibility).
Plumbing path:
- commands/handlers/auto.ts: parses `full` / `--full` modifier, threads
fullAutonomy through launchAuto options
- commands/catalog.ts: completion entries for `full` and `--full`
- auto.ts: startAuto and startAutoDetached accept fullAutonomy in options;
startAuto pins it on the session up-front so resume paths preserve it
- auto/session.ts: AutoSession.fullAutonomy field with full docstring
Behavior change is staged: the milestone-complete consumer that auto-merges
and chains is intentionally not in this commit (parallel session is active
in auto-post-unit.ts and auto/loop.ts; will land in a follow-up).
Also adds JSDoc to the functions on the touched path:
- handleAutoCommand (full command-family doc)
- launchAuto (headless vs detached routing)
- startAutoDetached (fire-and-forget rationale, why it diverges from startAuto)
- AutoSession.fullAutonomy (full inline doc)
Typecheck clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
loop.ts:
- saveStuckState on main dev path (was only on custom-engine path — P1 fix)
- Add pid to stuck-state JSON to prevent test pollution across process runs
- Use atomicWriteSync in saveCustomVerifyRetryCounts for crash-safety
- Add enforceMinRequestInterval + call before both runUnitPhaseViaContract sites
- Update s.lastRequestTimestamp from requestDispatchedAt on each unit
session.ts:
- Add lastRequestTimestamp and lastUnitAgentEndMessages fields
phases.ts:
- Add consecutiveSessionTimeouts + exponential-backoff auto-resume (up to 3x)
for session-creation timeouts before pausing for manual review
- Add loadEvidenceFromDisk after resetEvidence to rehydrate evidence on restart
- Add USER_DRIVEN_DEEP_UNITS + isAwaitingUserInput guard to skip artifact
verification when a deep-planning unit is paused awaiting user input
- Store s.lastUnitAgentEndMessages after each unit run
- Add requestDispatchedAt to runUnitPhase return type
evidence-collector.ts: add loadEvidenceFromDisk export
auto-post-unit.ts: add USER_DRIVEN_DEEP_UNITS set + re-export isAwaitingUserInput
user-input-boundary.ts: port from gsd2 (isAwaitingUserInput + approval helpers)
run-unit.ts: capture requestDispatchedAt at API dispatch time
kernel.ts: remove redundant !legacyFallback guard (enabled already encodes it)
tests/uok-kernel-path.test.ts: add SF_UOK_AUDIT_ENVELOPE env var assertions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The test was checking for a literal single-line ternary in auto-post-unit.ts,
but the formatter naturally renders the same ternary multi-line. The semantic
content is identical; the test was failing on whitespace alone.
Normalize runs of whitespace before substring-matching so the assertion
survives prettier/biome formatting changes.
After this fix: 39/39 uok tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- loop.ts: add DispatchContract type, AutoLoopOptions, resolveDispatchNodeKind,
runUnitPhaseViaContract — kernel path routes unit execution through
ExecutionGraphScheduler; legacy path passes through directly
- loop.ts: export runUokKernelLoop (contract=uok-scheduler) and
runLegacyAutoLoop (contract=legacy-direct)
- auto-loop.ts: re-export both new loop functions
- auto.ts: use runUokKernelLoop/runLegacyAutoLoop at both call sites
- phases.ts: use uokFlags.planningFlow for plan gate (was bypassing
legacyFallback via raw pref read)
- auto-dispatch.ts: use hasFinalizedMilestoneContext for execution-entry
context check (picks up SF_PROJECT_ROOT artifact fallback)
- tests: port uok-writer, uok-parity-report, uok-loop-adapter-writer,
uok-kernel-path test files from gsd2 — all 8 tests pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Follow-up to commit 39e2dc70c. Two small improvements that surfaced when
the parallel Phase D subagent finished and inspected the worktree:
- commands-scaffold-sync.ts:
- Tighten ScaffoldKeeperFn to match Phase D's actual dispatcher signature
(basePath, ctx) => Promise<number>. Define a local minimal
ScaffoldKeeperCtxShape for the lazy loader so we don't form a hard
import dependency on scaffold-keeper.ts.
- Remove duplicated "Upgradable" line from the report table — keep only
"Pending" since ADR-021 §10 names that the user-facing label.
- tests/scaffold-keeper.test.ts: better-typed notify stub; covers Phase E
arg-parser helpers (parseScaffoldSyncArgs, matchesOnly, applyOnlyFilter).
Typecheck clean. 49/49 scaffold tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase D: scaffold-keeper background agent
- scaffold-keeper.ts: dispatchScaffoldKeeperIfNeeded fires async after milestone
completion and on stopAuto cleanup. Detects editing-drift items, writes
<file>.proposed artifacts (template-only stub for now; later wires the
records-keeper skill subagent for code-as-fact merging), emits a structured
approval_request notification with stable dedupe_key so repeated runs don't
spam the user.
- Wired into auto-post-unit.ts and auto.ts:stopAuto via fire-and-forget so
the auto loop is never blocked by scaffold work.
- Failure modes non-fatal: try/catch around the dispatch, errors logged via
logWarning("scaffold").
Phase E: /sf scaffold sync command (escape hatch)
- commands-scaffold-sync.ts: parseScaffoldSyncArgs + handleScaffoldSync.
- Flags:
--dry-run report what would change, no writes
--include-editing run scaffold-keeper synchronously for editing-drift items
--only=<glob> scope to a path glob (suffix/prefix match)
- Wired into the SF command system via commands-bootstrap.ts, commands/catalog.ts,
and commands/handlers/ops.ts following the existing /sf <verb> pattern.
- Reuses ensureAgenticDocsScaffold from Phase C — doesn't reimplement sync logic.
Doctor finding (checkScaffoldFreshness) refined to reference the new command.
Tests: 8 new cases in scaffold-keeper.test.ts. All 49 scaffold tests green.
Together with Phases A-C, this completes ADR-021. Documents are now versioned,
upgrades are automatic for the safe cases, and editing-drift surfaces through
.proposed artifacts and structured notifications. The scaffold-keeper agent
body is currently a template-only stub; replacing it with a real records-keeper
subagent dispatch is a follow-up that the architecture now enables.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase C (automatic silent sync) had no dedicated tests when committed.
Added 8 cases covering:
- ensureAgenticDocsScaffold on empty dir creates files with markers
- old-version pending marker silently re-renders to current
- editing-drift file left untouched
- legacy unmarked file matched against archive promoted to pending
- migrateLegacyScaffold idempotency
Total scaffold test count: 41 (was 33).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The user-visible "automatic" upgrade behavior. After this lands, projects
pointed at SF silently catch up to the current scaffold without any user
action — for the simple cases.
Drift-aware ensureAgenticDocsScaffold:
- Step 1: migrateLegacyScaffold runs first to promote unmarked-but-recognised
files via SCAFFOLD_VERSION_ARCHIVE hash matching
- Step 2: per-template walk:
- Missing → create + stamp + manifest entry (existing behavior)
- Present, marker, state=pending, version drifted, hash matches stamp
→ silent re-render with current template + restamp (NEW)
- Editing/completed/customized → leave alone (Phase D handles editing-drift)
- Silent contract: no stdout/stderr, only logWarning("scaffold") for I/O
failures. All failure modes non-fatal.
SCAFFOLD_VERSION_ARCHIVE bootstrap:
- Lazily seeded with current SF version's body hashes from SCAFFOLD_FILES
- Future SF releases append entries when templates change so legacy projects
can match against any prior version
checkScaffoldFreshness doctor finding (ADR-021 §8):
- Surfaces missing/upgradable/editing-drift counts as "scaffold_drift" warning
- Auto-fix runs ensureAgenticDocsScaffold to handle missing+pending
- Non-fatal warning, never blocks dispatch
- Editing-drift left for Phase D (scaffold-keeper background agent)
Tests pass: 33/33 across scaffold-versioning + scaffold-drift suites.
Typecheck clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Subagent split scaffold tests into scaffold-versioning.test.ts (Phase A)
and scaffold-drift.test.ts (Phase B). Fixed an ESM-incompatible
require("node:fs") in one drift test that was breaking with
--experimental-strip-types. All 33 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Wire plan-gate in runDispatch() and verification gate in runFinalize()
- Add planningFlow gate persistence in guided-flow.ts
- Add execution-graph gate event in auto-dispatch.ts
- Flip all UOK feature flags from opt-in (=== true) to on-by-default (?? true)
- Port dispatch-envelope.ts, parity-report.ts, writer.ts from gsd2
- Add DispatchReasonCode, UokDispatchEnvelope, WriterToken, WriteRecord,
WriteSequence, DispatchExplanation to contracts.ts
- Add "refine" to UokNodeKind
- Extend auto-worktree.ts with workspace.after_create hook support
- Add workspace.after_create to preferences-types and preferences-validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 4-D fixes from the Phase 3 validation report. ace-coder is a
uv-managed Python repo with Rust crates in subdirectories; SF was
mis-detecting it in ways that would have failed every autonomous
verification.
1. detectPackageManager: return undefined when no root package.json
(previously hallucinated "npm" as default, leaking into reports)
2. detectVerificationCommands: only synthesize npm runner when
package.json actually present at root
3. ROOT_ONLY_PROJECT_FILES: expanded with Cargo.toml, go.mod,
pyproject.toml, setup.py, pom.xml, pubspec.yaml, Package.swift,
mix.exs — these are root-only signals; nested instances are
handled explicitly by emitter logic
4. Cargo block: distinguishes workspace-root vs single-crate-root vs
nested-only-crates layouts; emits per-crate bash loop for the last
case (mirrors the Go multi-module branch pattern)
5. pyprojectHasTool: matches both [tool.X] and [tool.X.subkey] so
ace-coder's [tool.ruff.lint] / [tool.ruff.format] are detected
6. Makefile branch: skip `make test` when (a) test command already
emitted by another block, or (b) the test target depends on
_verify_nix or similar nix-shell gates (ace-coder's case)
After these fixes, detectProjectSignals on ace-coder yields the
expected output: no spurious "npm", per-crate cargo loops, ruff/pyright
detected, no nix-gated `make test`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Generalizes the preferences-template-upgrade pattern to all scaffold-managed
documents with three states (pending/editing/completed), HTML-comment markers
on Markdown files, frontmatter on PREFERENCES.md, and a content-hash archive
for migrating legacy projects.
Operation is automatic-first, not command-driven:
- Synchronous on every SF startup (cheap path: missing + upgradable + legacy)
- Asynchronous after milestone completion: scaffold-keeper subagent runs the
existing records-keeper skill, treating code as the source of truth and
re-deriving doc content from source when drift is detected
- Surfaces results via the structured-notification model (kind:approval_request)
only when human review is warranted; silent runs produce no notification
- Manual /sf scaffold sync exists as an escape hatch for dry-run + forced
refresh, not as the primary interface
Five implementation phases (A-E), each independently shippable. Phase A
unlocks the architectural property; Phase D is what makes records-keeper
autonomous for code-derived docs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 1 — close SF-side polish gaps:
- codebase-generator: distinguish uv/poetry/pdm in Python stack-signals;
surface configured tooling (ruff/mypy/pyright) when config files exist
- doctor-environment: new checkPythonEnvironment — detects uv/poetry/pdm
via lockfile, verifies binary on PATH, warns with install hint when missing
- doctor-environment: new checkSiftAvailable — recommends sift install for
repos > 5000 source files when not on PATH
- tech-debt-tracker: documented future memory-as-sub-extension extraction
(defer until real backend-swap requirement)
Phase 2 — internal wire architecture:
- ADR-020: singularity-grpc as shared schema repo; gRPC + typed clients
for first-party services; MCP façade only at external-tool boundary
- ADR-019: trimmed MCP scope section to a 3-line summary linking to ADR-020
to avoid the wire-format table living in two places
- design-docs/index.md: ADR-020 added to ADR table
These changes make SF stronger for autonomous work on Python repos
(particularly ace-coder) and capture the internal wire architecture
decision as a durable ADR before any singularity-grpc code lands.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds __pycache__, .pytest_cache, .mypy_cache, .ruff_cache, .tox, .eggs,
and htmlcov to RECURSIVE_SCAN_IGNORED_DIRS so SF doesn't walk into them
when scanning project files. These directories can contain thousands of
files in mature Python projects and were slowing down detection / scan
operations on Python codebases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ADR-019 framing corrections:
- SF is single-machine, single-user, single-repo by design — character, not
limitation. Stays a standalone app permanently; does not get absorbed into ACE.
- Phase 6 reframed: "pattern transfer" not "orchestration convergence." ACE
ports patterns from SF, both apps remain independent.
- Phase 2 reframed: SF stays local. Federation is an ACE concern; SF doesn't
wire memory-store remote-mode against singularity-memory.
Detection strengthened for Python (priority for ace-coder work):
- Detect uv / poetry / pdm and prefix verification commands accordingly
- Emit ruff check when configured (file or [tool.ruff] in pyproject.toml)
- Emit mypy / pyright when configured — skip when no config to avoid false fails
- pyprojectHasTool helper for [tool.<name>] section detection
Detection strengthened for Rust:
- cargo fmt --check (fastest, catches style first)
- cargo check (type-only, faster than test)
- cargo clippy -- -D warnings (warnings as errors)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Internal services (SF↔memory, ACE↔memory, SF↔ACE) talk via typed direct
clients generated from the Go/TS APIs — HTTP/gRPC for memory, existing
JSON-RPC stdio for SF↔ACE. MCP is reserved for external LLM-driven coding
tools (Claude Code, Cursor) that don't share our build system; it is a
scaffold for the period when external coders help build the platform and
shrinks as the system becomes self-hosting.
Adds an explicit "MCP scope" table so the rule is stated once. Updates the
three-layer architecture diagram, Phase 2, and Phase 6 to remove the
inaccurate "all consumers over MCP" framing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Captures the SF↔ACE incremental convergence strategy: workspace VMs
(Firecracker) as the unified execution isolation primitive, the three-layer
architecture (orchestration/knowledge/execution), the 6-phase convergence
path, and ADR-014 Phase 4 cancellation (persistent-agent runtime reassigned
to ACE). Cross-references the matching ACE document at
docs/architecture/sf-ace-convergence.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When metadata is present, skip the text fallback entirely — the emitter
declared the event kind explicitly and the regex should not override it.
Add regression test file covering all acceptance criteria: metadata-first
classification, legacy fallback, dedupe_key dedup, and the key invariant
that automated notices cannot produce terminal/blocked signals.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace brittle string-matching in headless-events.ts with structured
source/kind/blocking/dedupe_key metadata on notify() events. String
matching is preserved as a fallback for the ~940 untagged call sites.
- Add NotificationMetadata type to headless-types.ts (canonical definition)
- Extend rpc-types.ts notify event with optional metadata field
- Extend ExtensionUIContext.notify() signature with optional 3rd arg
- Pass metadata through RPC notify implementation in rpc-mode.ts
- Update headless-events.ts: isTerminalNotification, isBlockedNotification,
isMilestoneReadyNotification, isPauseNotification all check metadata first
- Update notification-store.ts: store metadata on NotificationEntry; use
metadata.dedupe_key as dedup key when provided (falls back to message hash)
- Update notify-interceptor.ts to thread metadata through to store + original
- Tag critical emit sites with structured metadata:
stopAuto → { kind: "terminal" } (+ blocking: true when reason includes "block")
pauseAuto → { kind: "terminal", blocking: true }
guided-flow milestone ready → { kind: "approval_request", blocking: true }
- Update notification-overlay.ts to prefer metadata.source for [label] display
- Add 17-test regression suite (notification-event-model.test.ts)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add harness/ directory to SF repo (specs/, evals/, graders/ with AGENTS.md)
and seed harness/specs/bootstrap.md (agent-legibility verification)
- Extend agentic-docs-scaffold.ts: new repos get harness/ + ADR-TEMPLATE.md
and just adr / just spec / just harness-spec recipes via justfile
- Sync SF_RUNTIME_PATTERNS (gitignore.ts canonical) → git-service.ts and
worktree-manager.ts: add audit/, exec/, model-benchmarks/, reports/,
notifications.jsonl, routing-history.json, self-feedback.jsonl, repo-meta.json,
and milestone continue-marker patterns
- Inject ARCHITECTURE.md into system prompt via loadArchitectureBlock() in
system-context.ts (capped at 8 000 chars, after KNOWLEDGE block)
- Write real ARCHITECTURE.md for this repo (system map, .sf/ layout, key flows)
- Add ADR-TEMPLATE.md to docs/design-docs/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gitignore (core change):
- Remove stale blanket .sf/ entries from .gitignore (migrated to
.git/info/exclude on 2026-04-29, never cleaned up)
- gitignore.ts: split SF_RUNTIME_EXCLUSION_PATTERNS into two modes —
SF_SYMLINK_EXCLUSION_PATTERNS (blanket .sf for symlink repos where
git cannot traverse the symlink) and SF_RUNTIME_EXCLUSION_PATTERNS
(granular runtime-only patterns for directory repos, enabling
.sf/milestones/ and other durable planning artifacts to be tracked)
- ensureGitInfoExclude() now detects symlink vs directory and writes
the correct patterns, handling transitions between modes cleanly
- ADR-001 status: Proposed → Accepted
Docs:
- Fill 11 placeholder scaffold docs with real SF-specific content:
PLANS, DESIGN, PRODUCT_SENSE, QUALITY_SCORE, RELIABILITY, SECURITY,
design-docs/index.md, exec-plans/active, exec-plans/completed,
exec-plans/tech-debt-tracker, records/index
- Add records note: docs/records/2026-05-01-repo-vcs-and-notifications.md
- ADR-008 status: Accepted → Proposed (deferred — not applicable to
current usage model where Claude Code assists externally, not as a
Pi provider inside SF's dispatch loop)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add repository-vcs-context.ts to detect and inject VCS context (Git/Jujutsu)
into the agent system prompt; wire in repo-vcs bundled skill trigger
- Add src/resources/skills/repo-vcs/ skill for commit, push, and safe-push workflows
- Add JSDoc Purpose/Consumer annotations to app-paths, bundled-extension-paths,
errors, extension-discovery, extension-registry, headless-types, headless, and traces
- Add justfile and just to flake.nix devShell
- Fill out new-user-onboarding.md spec (Draft) and core-beliefs.md (Status: Accepted)
- Add notification-event-model.md design doc and notification-source-hygiene.md spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>