# Project Structure

Forge keeps all of its per-project state under a single directory: `.forge/`.
Everything there is plain files you can read, diff, and commit — which is why
Forge's state survives context compaction, agent restarts, and team handoffs.

::: tip Commit `.forge/`
Commit the `.forge/` directory so your team shares the same specs, changes, and
memory. See [Best Practices](/guide/best-practices).
:::

## `specs/` vs `changes/` — the core distinction

Two directories carry most of the meaning, and they are easy to confuse. The
one-line version:

- **`specs/` is what the system _is_.** The canonical, settled truth — the
  current agreed-upon behavior of your project. The deterministic gates read
  from here: [`forge drift`](/concepts/drift-and-reconcile) cross-references
  _these_ specs against your code, and [`forge analyze`](/features/quality)
  scores _these_. You don't hand-edit them mid-work; they are the record of
  decisions already made.
- **`changes/` is what you are _doing to it_ right now.** One directory per
  in-flight change, each a self-contained workspace for a single unit of work
  (proposal, exploration, design, tasks, gate state — and a **delta spec**).

The word that ties it together is **delta**. The spec inside a change is _not_
the whole truth — it describes only the slice that this change adds or alters.
That is deliberate: it keeps every unit of work small, reviewable, and
reversible. You reason about one change, not the entire system.

The two connect through **promotion, and only in one direction**. When every
task in a change is Done, [`forge archive`](/guide/workflow) merges that change's
delta spec **into `specs/`** (so the canonical truth now reflects the change) and
moves the change folder to `changes/archive/`. Work always flows
`changes/ → specs/`, never the reverse.

> Asking "what does this system do?" → read `specs/`. Asking "what's being
> worked on?" → look in `changes/`. A change is a renovation work order scoped to
> one room; `specs/` is the as-built blueprint that gets amended once the work is
> signed off.

## The `.forge/` layout

```text
.forge/
├── config.yaml            # optional per-project overrides
├── config.local.yaml      # gitignored, per-machine
├── memory/                # constitution, discovery memory, refinement notes
├── specs/{domain}/spec.md # canonical capability specs (promoted from changes/)
├── changes/
│   ├── archive/YYYY-MM-DD-<name>/   # immutable audit trail
│   └── <change-name>/
│       ├── state.yaml           # DAG state (survives compaction)
│       ├── exploration.md proposal.md plan.md tasks.md verify-report.md
│       ├── data-model.md         # (optional) entities, written by design phase
│       ├── contracts/            # (optional) {interface-name}.md per interface
│       ├── roadmap.md            # (optional) delivery sequencing, written by forge.roadmap
│       ├── test-coverage.md      # (optional) scenario -> test map, written by sdd-tests
│       ├── swarm-log.md          # (optional) wave dispatch record, written by sdd-swarm
│       ├── specs/{domain}/spec.md   # delta spec
│       ├── verify-attempts.yaml     # circuit-breaker state
│       ├── budget.yaml              # spend ledger
│       └── session-log.jsonl        # attributed timeline
├── templates/  skills/  extensions/  backups/  design/
├── site/                  # generated dashboard (forge docs)
└── _imported/             # lossless catch-all from `forge import`
```

## What each part is

### Top-level files

- **`config.yaml`** — the single optional per-project override file. Committed
  with the repo so the whole team shares it. See
  [Configuration](/guide/configuration).
- **`config.local.yaml`** — per-machine overrides. **Gitignored** so
  machine-specific settings never leak into the shared config.

### `memory/`

`forge init` creates this directory empty. It fills up as you run the
foundation and discovery commands: `.forge/memory/constitution.md` from
`/forge.constitution`, `project-discovery.md` / `current-architecture.md` /
`current-capabilities.md` / `current-gaps.md` from `/forge.discover`, and
`refinement-suggestions.md` / `knowledge-index.json` as `/forge.refine` and
other commands accumulate context over time. When `memory.team_sync` is
enabled, it doubles as the **Engram team-sync export** — either way, it is
committable, so project memory travels with the repository and every teammate
benefits from the same accumulated context.

### `specs/{domain}/spec.md`

The **canonical** capability specifications, organized by domain. These are the
project's source of truth for behavior. Specs land here by being **promoted**
from a change's delta spec when that change is archived.

### `changes/`

Home for changes — both in-flight and archived.

- **`archive/YYYY-MM-DD-<name>/`** — the **immutable audit trail**. Once a change
  is archived it is frozen here, dated and named, as a permanent record.
- **`<change-name>/`** — an in-flight change directory. Its contents:
  - **`state.yaml`** — the change's DAG state. It survives context compaction,
    so an interrupted change can always be resumed.
  - **`exploration.md`, `proposal.md`, `plan.md`, `tasks.md`,
    `verify-report.md`** — the phase artifacts (see the
    [phase-to-artifact map](/guide/workflow#phase-to-artifact-map)).
  - **`data-model.md`** *(optional)* — entities and data structures, written by
    the design phase only when the change introduces or modifies any.
  - **`contracts/{interface-name}.md`** *(optional)* — one file per new or
    modified external-facing interface, written by the design phase when
    applicable. Both companions are skipped for purely internal changes.
  - **`roadmap.md`** *(optional)* — the task execution graph sequenced into a
    value-first delivery order of vertical slices, written by
    `/forge.roadmap` once `tasks.md`'s execution graph exists.
  - **`test-coverage.md`** *(optional)* — a scenario -> REQ ID -> test file
    map for the RED-phase tests it generates, written by `sdd-tests`.
  - **`swarm-log.md`** *(optional)* — a wave-by-wave dispatch, specialist
    classification, and conflict record, written by `sdd-swarm` when it
    implements a change's tasks in parallel instead of `sdd-apply`'s
    sequential path.
  - **`specs/{domain}/spec.md`** — the **delta spec**: the change's proposed
    additions/edits, merged into canonical `specs/` on archive.
  - **`verify-attempts.yaml`** — the **circuit-breaker** state that bounds
    verify loops. See [circuit-breaker](/harness/circuit-breaker).
  - **`budget.yaml`** — the **spend ledger** for this change.
  - **`session-log.jsonl`** — the **attributed timeline** of what happened,
    line by line.

::: warning Treat the archive as read-only
`changes/archive/` is an **audit trail**, not a working directory. Forge writes
it on archive and never rewrites it — hand-editing an archived change breaks the
record it exists to preserve. Reopen work as a new change instead.
:::

### Supporting directories

- **`templates/`** — not created by `forge init`. It only appears when
  [`forge import specify`](/features/migration) brings over an existing
  Spec-Kit project's `.specify/templates/`; the foundation and spec commands
  draft their artifacts directly and never require it to exist.
- **`skills/`** — project skills.
- **`extensions/`** — installed extensions.
- **`backups/`** — automatic snapshots taken before mutations (used by
  `forge restore`).
- **`design/`** — design-system artifacts from the `design` foundation phase.

### `site/`

The **generated dashboard**, produced by `forge docs`. Serve it with
`forge docs serve` to browse your specs, changes, tasks, budget, and timeline.
See the [dashboard overview](/features/dashboard).

### `_imported/`

A **lossless catch-all** populated by `forge import`. When you migrate an
existing project, anything that does not yet map cleanly onto Forge's model
lands here rather than being dropped. See [migration](/features/migration).

## Agent files live outside `.forge/`

Not everything Forge writes lives under `.forge/`. **Agent-specific
directories** are written wherever each agent expects them — for example
`.claude/commands/` and `.claude/agents/` for Claude Code. This keeps Forge's
own state cleanly separated from each agent's native configuration, and it is
how the same unified command set appears natively inside every configured agent.

See [Agents](/guide/agents) for how per-agent adapters map commands into each
agent's native format.

## Next steps

- [The Workflow](/guide/workflow) — how artifacts are produced and promoted.
- [Configuration](/guide/configuration) — the `config.yaml` / `config.local.yaml`
  files.
- [Agents](/guide/agents) — where per-agent files are written.
- [Dashboard](/features/dashboard) — the `site/` output.
