Skip to content
Download PDF

Full SDD and Fast SDD ​

Forge has two paths through the SDD spine. Full SDD is the complete path, with a written spec and a design before any code. Fast SDD is the short path for small, low-risk changes: it skips the spec and the design and goes straight from proposal to a short plan.

The path is called the track. In files, config, and JSON it is written track: full or track: fast. This page explains how to tell the paths apart, how Forge chooses one, and what happens when a fast change turns out not to be small.

The two paths at a glance ​

Full SDD (track: full)Fast SDD (track: fast)
Phases that runpropose → specify → plan → tasks → implement → verify → archive (and explore when warranted)propose → tasks → implement → verify → archive
Phases skippedNonespecify and plan, shown as skipped
Artifactsproposal.md, specs/**/spec.md, plan.md, tasks.md, verify-report.mdproposal.md, tasks.md (with a ## Fast Plan and its Review Workload Guard lines), verify-report.md
TasksAs many as the work needs1 to 5
Use it whenNew behavior, a new capability, anything sensitive, or anything you are unsure aboutA small, low-risk change: typo, doc fix, config tweak, a contained bug fix
Size limitsNoneAt most 150 changed lines, 5 files, 5 tasks
Cost and timeMore ceremony, more tokens, a spec you can review before code existsA fraction of the planning cost; no spec to review
Review gateYesYes. The track never relaxes it.
Verify evidenceRequiredRequired. A fast change with no passing test or build is FAIL.

Fast is not "skip the checks"

Fast SDD skips planning documents, not verification. Strict TDD, the review gate, and verify all still run. What you lose is a spec and a design, which is why the path is only open to changes small enough not to need them.

The two paths as diagrams ​

Full SDD

Fast SDD

The fast path is always a subset of the same spine. It never invents a different one, and the phase order never changes.

How Forge picks the path ​

propose writes a ## Track block in proposal.md. It is a fenced YAML block, and it is where the agent argues for one path:

markdown
## Track

```yaml
track: fast            # fast | full
proposed_by: agent     # agent | human
complexity: low
risk: Low              # fast requires Low
estimated_lines: 40
estimated_files: 2
new_capabilities: 0
touches: [docs]
reasons:
  - "typo in one help string"
```

The block is a proposal, not a decision. A deterministic resolver in Forge (the track field of forge sdd-status --json) has the last word, and it reports the track together with its source and reasons:

json
{ "track": { "value": "full", "source": "veto", "reasons": ["estimated_files 7 exceeds 5"] } }

source is one of proposal, config, veto, sticky, or fallback.

Thresholds ​

A change can be fast only when all of these hold:

SignalFast limit
riskLow
estimated_lines150 or fewer
estimated_files5 or fewer
tasks in tasks.md5 or fewer
new_capabilities0, and the proposal's "New Capabilities" section says "None"

The limits are built into Forge. They are not config keys, so no repo can quietly raise them.

Vetoes ​

A veto forces Full SDD no matter what the proposal asked for. Any of these is one:

  • risk is not Low.
  • estimated_lines, estimated_files, or new_capabilities is missing, is not a plain non-negative integer, or is over its limit. "many" or a range such as "20-40" counts as missing.
  • touches names any of: security, auth, payments, permissions, pii, secrets, migration, schema, public-api.
  • The proposal declares a new capability.
  • tasks.md holds more than 5 tasks.

Fail closed

Forge never guesses toward the short path. A missing proposal, a missing or malformed ## Track block, an unknown key, an unreadable config, or an unparseable number all resolve to Full SDD, with the reason listed in the status output.

Overrides ​

Two keys under workflow can steer the choice:

ConfigEffect
adaptive_depth: falseAlways Full SDD. Forge stops proposing the short path.
force_depth: trivialRequest Fast SDD for every change. Vetoes still apply.
force_depth: standard or fullAlways Full SDD.

The vetoes are not overridable. force_depth: trivial cannot push an auth change onto the fast path; the change resolves to full with source: veto.

The track is not the review tier ​

The track decides which planning phases run. The review risk tier decides how many adversarial lenses inspect the finished diff, and it is always derived from that diff. The two are independent (recorded as ADR-0002, "workflow track independent of review tier"). A fast change that touches executable code is still reviewed as a normal code change would be.

Escalation: fast to full, never back ​

Fast SDD is a bet that the change is small. sdd-apply checks the bet after it edits, using forge sdd-fast-check. If the diff has outgrown the limits, the change escalates:

  1. sdd-apply writes two lines into the proposal's ## Track block and stops:

    yaml
    escalated_from: fast
    escalation_reason: "forge sdd-fast-check exit 2: 212 changed lines exceeds 150"
  2. The marker is sticky. From then on the change resolves to Full SDD, with source: sticky.

  3. The orchestrator runs the skipped phases (specify, plan), then re-plans tasks. Work already done is kept, not reverted.

Escalation also fires when sdd-tasks finds the work needs more than 5 tasks, and a change that already has a specs/ folder or a plan.md is sticky-full from the start. Nothing downgrades a full change to fast, and no config key does either. If a change grew, trust the escalation.

The skipped state ​

On Fast SDD, specify and plan are not "missing" and not "blocked". They are skipped by design, a state of their own:

text
$ forge status typo-fix
✓ propose
– specify
– plan
✓ tasks
⠇ implement

skipped shows up in forge sdd-status (state: skipped), forge status, forge board, the spec viewer, and the generated spec site. A skipped phase is never the "next" phase and never counts as done. verify records spec and design coherence as skipped (fast track) rather than raising a warning.

Measuring the diff: forge sdd-fast-check ​

text
forge sdd-fast-check [change] [--cwd <path>] [--json] [--base-ref <rev>]

The command measures how much a fast change has actually changed and tells sdd-apply whether it still fits. It counts <baseline>..HEAD plus staged, unstaged, and untracked work, and ignores the change's own .forge/changes/<name>/ folder.

The baseline is the first of these that resolves to an ancestor of HEAD:

OrderBaselineWhere it comes from
1override--base-ref <rev>; if it fails, there is no fall-through
2planbase_commit pinned by sdd-tasks in ## Fast Plan
3merge-basemerge-base of HEAD with origin/HEAD, main, or master

The verdict is carried by the exit code:

VerdictExitMeaningsdd-apply does
within0At least one file changed and the diff is inside every limitCarries on to review and verify
escalate2Over a limit, a high-risk path, or no usable baselineWrites the escalation marker and stops
empty3Baseline resolved, but nothing changedReports apply as failed; no marker
usage error1Unknown flag or changeTreated as an escalation

With --json the command prints the forge.sdd-fast-check/v1 payload for all three verdicts. It never changes refs, HEAD, your index, or your working tree. See the CLI reference.

Worked example: Fast SDD ​

You ask: "Fix the typo in the forge sync help text."

  1. propose. The agent writes proposal.md with track: fast, risk: Low, estimated_lines: 2, estimated_files: 1, new_capabilities: 0, touches: [docs].

  2. Resolve. forge sdd-status --json reports track: { value: "fast", source: "proposal" }, and specify and plan show as skipped.

  3. tasks. sdd-tasks pins base_commit and writes one task:

    markdown
    ## Fast Plan
    
    ```yaml
    base_commit: 3f1c0a9e8b7d6c5b4a39281706f5e4d3c2b1a098
    ```
    
    - [ ] 1.1 Fix "sychronize" in the `sync` help string and its golden
    
    400-line budget risk: Low
    Chained PRs recommended: No
    Decision needed before apply: No
  4. implement. sdd-apply edits two lines, then runs forge sdd-fast-check typo-fix --json: verdict: within, exit 0.

  5. verify. Tests and build pass; the report records them as evidence.

  6. archive. forge archive moves the change aside and writes Track: fast. There are no specs to merge.

Worked example: Full SDD ​

You ask: "Add rate limiting to the public API."

  1. propose. The agent writes track: full. The touches list includes public-api and the change adds a capability, so even a fast proposal would be vetoed.
  2. specify. A delta spec describes the new requirements and scenarios.
  3. plan. plan.md records the design: where the limiter lives, the storage, and the contracts.
  4. tasks. tasks.md lists the work with tiers and a review workload forecast.
  5. implement. sdd-apply works task by task with strict TDD. There is no fast check on this path.
  6. review and verify. The review gate inspects the diff; verify checks the result against the spec scenarios.
  7. archive. The delta spec merges into .forge/specs/, and the change moves to the archive with Track: full.

Which model runs a Fast SDD change ​

Fast SDD: the proposal runs on its normal model because it is what classifies the change; once the track resolves to fast, run the remaining phases (tasks, apply, verify, archive) on sonnet when the change involves real logic, or on haiku for trivial edits. The default model table and how to override it are in Configuration: models.