brief-spec · git:20260807.8b156e3 · 2026-08-07 · sha256 e3a6f25258543181

brief-spec git:20260807.8b156e3A

Immutable. This exact content is served forever at /api/v1/blob/e3a6f25258543181.

---
name: brief-spec
description: Use when the user wants to create a brief or spec for a feature before planning
---

# Brief Spec

Conversational brief creation. The orchestrator loads this inline to
co-create a brief with the user before dispatching to gaia-planner. The
brief you write here is the contract you will audit the plan against: **you
own the resulting plan -- its tasks and its acceptance criteria** -- and the
planner produces it *for you to check*, not to approve on your behalf.

## DB is the source of truth (read this first)

Briefs live in the Gaia substrate database (`~/.gaia/gaia.db`). They are
created and mutated through the `gaia brief` CLI -- never by writing files
on disk. The DB row IS the brief: there is no `brief.md`, no
`<status>_<slug>/` directory, no frontmatter on disk. When in doubt, there
is no file to write -- there is a CLI command to run.

**Execution follows authority.** The orchestrator co-creates the brief and may
use its trusted Gaia CLI lane for bounded reads and user-confirmed
`new`/headless `edit`/`set-status`/AC writes. `gaia-operator` remains the
alternative for batching or operational separation. Destructive deletion is
outside the direct lane. The orchestrator owns the questions, confirmation,
and content whichever executor carries the command.

If you find code, docs, or skills that still describe a filesystem layout
under `.claude/project-context/briefs/`, that is legacy: flag it in
`cross_layer_impacts` -- do not edit it as a side effect of a brief task.

## Cuando llegas aquí

El orquestador cargó esta skill porque la conversación entró en Cerrar:
el usuario y él han acordado varias cosas y es momento de materializarlas.
No estás aquí porque la petición superó un umbral de tamaño. Estás aquí
porque hay acuerdos que capturar.

Tu trabajo:
1. Resumir los acuerdos que ya emergieron en la conversación previa --
   no re-descubrirlos desde cero.
2. Preguntar sólo lo que falte para convertir los acuerdos en AC
   reproducibles (evidence types, surface type).
3. Materializar el brief en la DB con `gaia brief new --headless`, y
   presentarlo al usuario para validar.

## Process

1. **Ask questions** -- Target gaps, not completeness:
   - **Surface type** (always, before AC): Is this a UI a human uses, an API,
     or a background job? Determines valid evidence types for the ACs.
   - What problem does this solve?
   - What constraints matter? (cloud, performance, security, timeline)
   - How will you verify each AC yourself? (reproduce steps, not just "it works")
   - What artifact do you want to review after execution?
     (log file, screenshot, JSON snapshot, HTTP response, diff)
   - If this failed silently, what symptom would you look for?
   - What is explicitly NOT in scope?

   One question per round via AskUserQuestion. Stop when each AC has
   a declared evidence type and every question above has an answer or
   an explicit "N/A".

2. **Create the brief in the DB (headless)** -- Run through the trusted Gaia CLI lane:

   ```bash
   gaia brief new --headless \
     --title="<human title>" \
     --status=draft \
     --surface-type=<ui|api|job|cli> \
     --objective="<1-3 sentences>" \
     --context="<project constraints>" \
     --approach="<high-level strategy, 3-5 sentences>" \
     --out-of-scope="<explicit non-goals>"
   ```

   The slug is derived from `--title` (kebab-case). The CLI writes a row to
   the `briefs` table and prints the slug back. **Do not write any file in
   `.claude/project-context/briefs/`.** No directory, no `brief.md`, no
   frontmatter on disk. The DB row IS the brief.

   `--status=draft` is the canonical entry point. Move it to `open` only when
   the user is ready to plan against it.

3. **Add Acceptance Criteria** -- ACs are rows in the `acceptance_criteria`
   table, added one at a time with `gaia brief ac add` per AC:

   ```bash
   gaia brief ac add <slug> \
     --id=AC-1 \
     --description="<user observation>" \
     --evidence-type=<command|url|playwright|artifact|metric> \
     --evidence-shape='<free-form string or JSON>'
   ```

   Do not predeclare a repository-relative artifact such as
   `evidence/AC-1.txt`. During execution, persist the actual result with
   `gaia evidence add`; Gaia stores small results inline and larger blobs below
   `~/.gaia/evidence/`, then returns the canonical record/path.

   Remove one the same way, dispatching `gaia brief ac remove <slug>
   --id=AC-1`. The shapes per evidence type are under "Evidence Types" below;
   the `## Acceptance Criteria` section that `gaia brief show` renders is the
   human summary of these rows.

4. **Confirm with the user** -- run `gaia brief show <slug>`, which prints the
   full row. Read it back and ask: "Does this
   capture what you want?" When confirmed, suggest dispatching to
   gaia-planner.

## How to update a brief

For a single field, run the headless patch --
scriptable, no editor:

```bash
gaia brief edit <name> --headless \
  --field=<objective|context|approach|out_of_scope|description|title|surface_type> \
  --content="..."
```

The interactive form, `gaia brief edit <name>` (no `--headless`), opens the
full body in `$EDITOR` -- it needs a human at a terminal, so it is never the
form to dispatch; use the headless form always in this flow.

## How to change status

Run `gaia brief set-status <name> <new-status>`.
The CLI validates the state machine and rejects illegal transitions:

```
draft -> open -> in-progress -> closed -> {archived, open}
```

Examples:

```bash
gaia brief set-status my-feature open          # ready to plan against
gaia brief set-status my-feature in-progress   # work has begun
gaia brief set-status my-feature closed        # AC verified
gaia brief set-status my-feature archived      # closed -> archived
gaia brief set-status my-feature open          # closed -> reopened
```

There is no "rename the directory" step. Status is a column.

## How to delete a brief

Dispatch gaia-operator to run `gaia brief delete <name> --yes`. Hard delete
with FK cascade across acceptance_criteria, milestones, dependencies, plans,
and tasks tied to the brief. There is no undo today; soft-delete is on a
separate future brief.

Prefer dispatching `gaia brief set-status <name> archived` over delete for
anything you might want to read later.

## How to read briefs

Run any of these directly through the trusted Gaia CLI lane.

| Need | Command |
|------|---------|
| List | `gaia brief list [--status=...] [--workspace=<ws>] [--format=table\|json\|count]` |
| Show one | `gaia brief show <name> [--workspace=<ws>] [--json]` |
| FTS5 search | `gaia brief search <query>` |

`--workspace` defaults to the current workspace. Pass it explicitly when
reading from outside the workspace tree (e.g. cron, batch jobs).

## Brief Body Structure

The brief body (rendered by `gaia brief show`) follows this shape. The
frontmatter block is the executable source of truth (orchestrator parses
it with `yaml.safe_load`). The body's `## Acceptance Criteria` section
mirrors it as a human summary.

```markdown
---
status: draft
surface_type: ui | api | job | cli
acceptance_criteria:
  - id: AC-1
    description: "Login button visible on /login"
    evidence:
      type: url
      shape:
        method: GET
        url: http://localhost:3000/login
        expect:
          status: 200
          body_contains: "Sign in"
  - id: AC-2
    description: "pytest auth suite green"
    evidence:
      type: command
      shape:
        run: "pytest tests/auth/ -q"
        expect: "exit 0"
---

# [Feature Name]

## Objective
[1-3 sentences: what problem, why now, who benefits]

## Context
[Project constraints relevant to this feature]

## Approach
[High-level strategy, not implementation details. 3-5 sentences max]

## Acceptance Criteria
Human-readable summary. Source of truth lives in frontmatter.
- AC-1: Login button visible on /login (evidence: url)
- AC-2: pytest auth suite green (evidence: command)

## Milestones (M/L features only)
- M1: [name] -- [what is shippable after this]
- M2: [name] -- [what is shippable after this]

## Out of Scope
[Explicit boundaries -- what this feature does NOT include]
```

## Acceptance Criteria Rules

- Every AC has a description (user observation) and an evidence block.
- Evidence must be reproducible by the user -- not only by the agent.
- Every completed AC has a structured row created by `gaia evidence add`.
  Never invent a repository-relative output path. Small results live inline
  in Gaia's DB; larger blobs live below `~/.gaia/evidence/`.
- Vague ACs get pushed back: "Fast means what? Under 200ms p95?"
- Surface type restricts valid evidence types (see table).

### Evidence Types

The shapes below are frontmatter fragments under `acceptance_criteria:`.
The body's `## Acceptance Criteria` section mirrors them for human reading;
the frontmatter is the executable source of truth.

| type | shape | valid surface |
|------|-------|---------------|
| `command` | `run: "bash command"; expect: exit_code \| substring` | any |
| `url` | `method: GET\|POST; url; expect: {status, body_contains}` | ui, api |
| `playwright` | `url; steps: [...]; assert: "selector visible" \| screenshot` | ui |
| `artifact` | `path; kind: json\|log\|screenshot; assert: schema \| contains` | any |
| `metric` | `query; threshold: "p95 < 200ms"` | api, job |

Shape examples (frontmatter fragments):

```yaml
# command
evidence:
  type: command
  shape:
    run: "pytest tests/auth/ -q"
    expect: "exit 0"

# url
evidence:
  type: url
  shape:
    method: GET
    url: http://localhost:3000/health
    expect:
      status: 200
      body_contains: '"status":"ok"'

# playwright
evidence:
  type: playwright
  shape:
    url: http://localhost:3000/login
    steps:
      - fill: "#email with user@test.com"
      - click: "button[type=submit]"
    assert: "selector [data-testid=dashboard] visible"

# artifact
evidence:
  type: artifact
  shape:
    path: dist/build-report.json
    kind: json
    assert: ".summary.errors == 0"

# metric
evidence:
  type: metric
  shape:
    query: "curl -s http://localhost:3000/metrics | grep http_p95"
    threshold: "< 200"
```

## Why the DB, not a directory tree

The old `.claude/project-context/briefs/<status>_<slug>/` layout is gone
because a directory tree cannot be the source of truth for a brief:

- Status lived in the directory name -- renaming a directory was the
  status transition. That made transitions unverifiable, racy across
  agents, and impossible to query with anything other than `find`.
- Two writers (filesystem + DB) drift apart silently; only one can be
  authoritative.
- Cascade deletes across ACs, milestones, plans, and tasks require FK
  semantics, which a directory tree cannot provide.

## After Brief -- you own the plan the planner returns

Run `gaia brief show <slug>`, which prints the full
brief. Present it. Ask: "Does this capture what
you want?" When confirmed, dispatch to gaia-planner to create a plan.

The brief settles *whether* the work is worth doing -- that was agreed
here, with the user. The planner does not re-litigate that. What the
planner owes you back is everything you need to **audit** the plan it
produces, not just the task list:

- the **feasibility findings** it corroborated against the codebase
  (what already exists, what the brief assumed that does not),
- the **assumptions** it had to make and the **risks** it sees,
- the **rationale for task ordering** and parallelization,
- the **gate or gates on each task** -- the typed verification the
  planner authored to prove that task's outcome.

Require those in the dispatch -- a plan you cannot audit is one you
cannot own. When you review it, escalate to the user only what is
**genuinely new or blocking** (a feasibility gap, a fork the planner
could not resolve). Never re-ask what the brief already settled.

### Judge that each task's gate captures its intent

Part of owning the plan is judging its gates. The planner authors, per
task, one or more typed gates (`command`, `code`, `semantic`,
`self_review`) via `gaia task gate add`; the well-formedness of those
gates is already checked deterministically (`verify_brief` Invariant 9:
a task with no gate, or a gate with an empty evidence-shape). Your job is
the half a check cannot do: judge that each gate actually captures the
**intent** of its task. For each task ask -- does the chosen type and
evidence-shape prove how *this* task's outcome should be shown, and where
a task carries more than one gate, do they *together* cover its intent? A
`semantic` rubric on a task whose outcome is a passing command, or a lone
`command` gate on a task whose real deliverable is a design judgment, is a
gate that passes well-formedness but misses intent. This is prompt
discipline, not a deterministic check -- flag the mismatch back to the
planner; do not silently accept a gate that does not fit its task.

## Anti-Patterns

- **Writing `brief.md` to disk** -- the DB is the source of truth; any file
  on disk is either build output or stale legacy that will be deleted.
- **Renaming directories to change status** -- there are no directories;
  status is a column. Run `gaia brief set-status`.
- **Skipping `--status=draft` on creation** -- creating directly in `open`
  bypasses the review window where the user confirms ACs.
- **Hard-deleting a brief that has plan history** -- prefer
  `set-status archived`. Delete is for genuinely abandoned drafts.
- **Accepting a plan you cannot audit** -- dispatching the planner without
  requiring its feasibility findings, assumptions, risks, ordering
  rationale, and per-task gates leaves you owning a plan you cannot check.
  Require the audit inputs in the dispatch.
- **Accepting a gate that misses its task's intent** -- a gate can pass
  well-formedness (Invariant 9) yet prove the wrong thing. Judging that
  each task's gate captures its intent is yours; flag a mismatch back to
  the planner rather than accept it.
- **Re-asking the user what the brief settled** -- the brief is the agreed
  contract. Escalate only genuinely new or blocking findings surfaced by
  the plan; questions the brief already answered are noise.