# ADR-0001: Promote-Only SF State

**Status:** Accepted
**Date:** 2026-05-02
**Source:** M009 S02 (promote-only sf-state migration)

## Context

SF agent planning state (`.sf/` directory) accumulates during agent execution in `~/.sf/projects/<hash>/`. This state is private to each agent session and should never enter the repository unless explicitly promoted by a human.

Historically, `.sf/` paths could accidentally be committed via symlink traversal, literal reference, or manual `git add`. This ADR establishes the rules and mechanisms for preventing that.

## Decision

SF planning state lives exclusively in `~/.sf/`. The repository boundary is enforced at three layers:

1. **Native layer** — `nativeAddPaths` in `native-git-bridge.js` skips any path whose first segment is `.sf`.
2. **Collection layer** — `stageExplicitIncludePaths` in `git-service.js` applies the same filter before calling `nativeAddPaths`.
3. **Pre-commit layer** — `validateStagedFileChanges` in `safety/file-change-validator.js` detects staged `.sf/` paths after `git.stageOnly` and emits a high-severity warning.

The canonical promotion path is `sf plan promote <source> [--to <target-dir>] [--rename <new-name>] [--edit]`, which copies a file from `~/.sf/projects/<hash>/` to `docs/` and prints a suggested `git add` line. Companion commands `sf plan list` and `sf plan diff` provide visibility.

For audit purposes, a human should run `sf plan list` periodically to review what planning state exists in `~/.sf/` and decide what to promote or discard.

## Consequences

**Positive:**
- Planning state is isolated from the repository — no accidental commits of agent working state.
- Explicit promotion creates a clean separation between agent work (`~/.sf/`) and human-reviewed artifacts (`docs/`).
- Multiple barriers prevent `.sf/` paths from entering staging even if one layer is bypassed.

**Negative:**
- Planning state is not backed up in the repository unless explicitly promoted.
- Agents must remember to use `sf plan promote` for anything worth preserving.

**Historical `.sf/` adds:** none found. No `.sf/` files were ever committed to this repository. The `.gitignore` has always contained `.sf` entries, and the three-layer defense was added in M009 S01 as a belt-and-suspenders measure. The audit was run as part of M009 S04.

## See also

- `docs/plans/README.md` — what belongs in `docs/plans/`
- `docs/adr/README.md` — what belongs in `docs/adr/`
- `docs/specs/README.md` — what belongs in `docs/specs/`
- `AGENTS.md` — agent instructions covering planning state rules
