We're glad you're here. SF is an open project and contributions are welcome across the entire codebase. We hold a high bar for what gets merged — not to be gatekeepers, but because every change ships to real users and stability matters.
1.**Check existing issues.** Someone may already be working on it.
2.**Claim the issue.** Comment on the issue to get it assigned to you before writing code. This prevents duplicate work and wasted effort.
3.**No issue? Create one first** for new features. Bug fixes for obvious problems can skip this step.
4.**Architectural changes require an RFC.** If your change touches core systems (auto-mode, agent-core, orchestration), open an issue describing your approach and get approval before writing code. We use Architecture Decision Records (ADRs) for significant decisions.
**Commit messages** must follow [Conventional Commits](https://www.conventionalcommits.org/). The commit-msg hook enforces this locally; CI enforces it on push.
This enables unique milestone IDs, branch pushing, and pre-merge checks — preventing milestone ID collisions when multiple contributors run auto-mode simultaneously. Each developer gets their own isolated worktree; squash merges to `main` happen independently.
For full details see [docs/working-in-teams.md](docs/working-in-teams.md) and [docs/git-strategy.md](docs/git-strategy.md).
Every PR needs a **TL;DR** and a **detailed explanation**. Use this structure:
```
## TL;DR
**What:** One sentence — what does this change?
**Why:** One sentence — why is it needed?
**How:** One sentence — what's the approach?
## What
Detailed description of the change. What files, modules, or systems are affected?
## Why
The motivation. What problem does this solve? What was broken, missing, or suboptimal?
Link issues where applicable: `Closes #123`
## How
The approach. How does the implementation work? What were the key decisions?
If this is a non-trivial change, explain the design and any alternatives you considered.
```
### Requirements
- **CI must pass.** If your PR breaks tests, fix them before requesting review.
- **One concern per PR.** A bug fix is a bug fix. A feature is a feature. Don't bundle unrelated changes.
- **No drive-by formatting.** Don't reformat code you didn't change. Don't reorder imports in files you're not modifying.
- **Link issues when relevant.** Not mandatory for every PR, but if an issue exists, reference it.
### Change type checklist
Include in your PR:
- [ ]`feat` — New feature or capability
- [ ]`fix` — Bug fix
- [ ]`refactor` — Code restructuring (no behavior change)
- [ ]`test` — Adding or updating tests
- [ ]`docs` — Documentation only
- [ ]`chore` — Build, CI, or tooling changes
### Breaking changes
If your PR changes any public API, CLI behavior, config format, or file structure, say so explicitly. Breaking changes need extra scrutiny and may need migration guidance.
## AI-assisted contributions
AI-generated PRs are first-class citizens here. We welcome them. We just ask for transparency:
AI agents opening PRs must follow the same workflow as human contributors: clean working tree, new branch per task, CI passing before requesting review. Multi-phase work should start as a Draft PR and only move to Ready when complete.
Reading a diff is not the same as verifying a change. Our review standard is execution-based, not static-analysis-based.
**What reviewers do:**
1.**Check out the branch** — check out the PR branch locally (or in a worktree). Don't review from the diff view alone.
2.**Build the branch** — run `npm run build`. A diff that doesn't compile is not reviewable.
3.**Run the test suite** — run `npm test`. CI status is a signal, not a substitute for local verification.
4.**Trace root cause for bug fixes** — confirm the diff addresses the root cause described in the issue, not just the symptom.
5.**Check for a regression test** — bug fixes must include a test that would have caught the original bug. If it's absent, the fix is incomplete.
Only after completing these steps should a reviewer make claims about correctness.
**What "looks right" means:**
"Looks right" is the starting point for review, not the conclusion. "The tests pass" only means the tests pass — not that the claimed bug is fixed or the feature works as described. A well-written commit message on a broken change is still a broken change.
### What contributors must provide to unblock review
- **Bug fixes** — include a regression test. A fix without a test is an assertion, not a proof.
- **Features** — include tests covering the primary success path and at least one failure path.
- **Behavior changes** — update or replace any existing tests that cover the changed behavior. Don't leave passing-but-wrong tests in place.
If your PR claims to fix issue #N, reviewers will verify the fix addresses the root cause described in #N — not just that CI is green.
-`beforeEach`/`afterEach` — when all tests in a `describe` block share the same setup/teardown pattern
-`t.after()` — when each test has unique cleanup (different fixtures, env vars, etc.)
-`try`/`finally` — only inside standalone helper functions that don't have access to the test context `t` (e.g., `withEnv()`, `capture()`)
### Template literal fixture data
When constructing multi-line fixture content (markdown, YAML, etc.) inside indented test blocks, use array join to avoid unintended leading whitespace:
// Each line now has 2 leading spaces, breaking ^## regex anchors
```
### Test-first for bug fixes
Bug fixes must include a regression test that fails before the fix and passes after. Write the test first, confirm it fails, then apply the fix. See the `test-first-bugfix` skill.