--- name: trekbrief description: Interactive interview that produces a task brief with explicit research plan. Feeds /trekresearch and /trekplan. Optionally orchestrates the full pipeline end-to-end. argument-hint: "[--quick] | --approve " allowed-tools: Agent, Read, Glob, Grep, Write, Edit, Bash, AskUserQuestion, Skill --- # Ultrabrief Local v2.1 Interactive requirements-gathering command. Produces a **task brief** — a structured markdown file that declares intent, goal, constraints, and an **explicit research plan** with copy-paste-ready `/trekresearch` commands. Pipeline position: ``` /trekbrief → brief.md (this command) /trekresearch --project → research/*.md /trekplan --project → plan.md /trekexecute --project → execution ``` The brief is the contract between the user's intent and `/trekplan`. Every decision the plan makes must trace back to content in the brief. **This command is always interactive.** There is no background mode — the interview requires user input. After the brief is written, the command optionally orchestrates the rest of the pipeline (research + plan) in foreground if the user opts in. ## Phase 1 — Parse mode and validate input Parse `$ARGUMENTS`: 1. If arguments start with `--quick`: set **mode = quick**. The interview proposes `small` as the starting size class (Phase 3 still says the class aloud, the operator can override it, and it moves up if the task proves bigger). Strip the flag; remainder is the task description. 2. Otherwise: **mode = default**. Interview probes each section until the completeness gate (Phase 3) and brief-review gate (Phase 4) both pass. 3. `--gates` flag (autonomy control, may combine with any mode): `--gates` takes the next token as its value only when it is `true`, `false`, `closed` or `open` (strip both); any other next token is not its value (strip only the flag). Run the shim once to map the value, bare when there is no value: ```bash node ${CLAUDE_PLUGIN_ROOT}/lib/util/autonomy-gate.mjs --state idle --event start --gates [value] ``` `next_state: gates_on` sets `gates_mode = true`, `auto_running` sets it false, and nothing else reads the state. On exit 1 or no JSON (a broken shim; the four values cannot cause it), print the error in one line and map in prose instead: bare, `true`, `closed` → true; `false`, `open` → false. The run goes on either way. `gates_mode = true` adds one pause, before the auto chain starts (Phase 5); the chain does not pass `--gates` on to `/trekresearch` or `/trekplan`. Default `gates_mode = false` skips that pause. Strip the flag (and its value, when it has one) from `$ARGUMENTS` before further parsing. 4. `--approve `: set **mode = approve**. No interview, no drafting. Set `APPROVE_ARG` to the argument and resolve it: ```bash node ${CLAUDE_PLUGIN_ROOT}/lib/validators/intent-approval.mjs --resolve "{APPROVE_ARG}" ``` A directory resolves to `/brief.md` (a `/trekplan --project` brief). A file resolves to itself, whatever its name (a `/trekplan --brief` brief). On exit 1, print its `error` and stop. Otherwise set `BRIEF_PATH`, `PROJECT_DIR` and `PLAN_COMMAND` from `brief_path`, `project_dir` and `plan_command`, jump straight to **Phase 4h**, run it and print its report; if the stamp printed `stamped: true`, run **Phase 7** with the approve-mode values it names, then stop. This is the remedy `/trekplan` names when it halts on an unapproved or stale intent, on both of its brief modes. In every other mode, `BRIEF_PATH = {PROJECT_DIR}/brief.md` and `PLAN_COMMAND = /trekplan --project {PROJECT_DIR}`. If no task description is provided (and mode is not approve), output usage and stop: ``` Usage: /trekbrief /trekbrief --quick /trekbrief --approve Modes: default Dynamic interview until quality gates pass — brief with research plan --quick Compact start; still escalates on weak sections — brief with research plan --approve Approve an existing brief's ## Intent + ## Goal so /trekplan will plan it Examples: /trekbrief Add user authentication with JWT tokens /trekbrief --quick Add rate limiting to the API /trekbrief Migrate from Express to Fastify ``` Report: ``` Mode: {default | quick | approve} Task: {task description} ``` ## Phase 2 — Generate slug and create project directory Generate a slug from the task description: first 3-4 meaningful words, lowercase, hyphens. Example: "Migrate from Express to Fastify" → `fastify-migration`. Set today's date as `YYYY-MM-DD` (UTC). Create the project directory: ```bash PROJECT_DIR=".claude/projects/{YYYY-MM-DD}-{slug}" mkdir -p "$PROJECT_DIR/research" ``` Report: ``` Project directory: .claude/projects/{YYYY-MM-DD}-{slug}/ ``` If the directory already exists and is non-empty, warn and ask: > "Directory {path} exists. Overwrite, reuse (keep existing files), or pick new slug?" Use `AskUserQuestion` with three options. If "pick new slug", ask for a new slug and restart Phase 2. ## Phase 2.5 — Framing declaration (v5.5) Before gathering ANY brief content, the operator MUST declare how this brief relates to prior operator intent. This is the **first layer of the framing-alignment defense** (CLAUDE.md cross-cutting invariant): the premise is declared explicitly *before* the interview can drift, and long before `/trekplan` can polish a wrong premise with reasoning power. **This runs BEFORE any brief prose is drafted.** The committed value is written to brief frontmatter as `framing: ` in Step 4a and is REQUIRED for `brief_version: "2.2"` (the validator emits `BRIEF_MISSING_FRAMING` otherwise). It is the **first question of the Phase 3 round** — asked in the same `AskUserQuestion` call as the round's other questions, not as a call of its own — with four canonical options: | Option | Maps to `framing:` | Meaning | |--------|--------------------|---------| | **Preserve** | `preserve` | Same intent as before; this brief continues a prior direction unchanged. | | **Refine** | `refine` | Same core intent, sharpened or narrowed scope. | | **Replace** | `replace` | Supersedes a prior brief's approach; intent re-stated from scratch. | | **New direction** | `new-direction` | Net-new intent; no prior brief to anchor against. | Commit the answer to `state.framing` immediately. **No safe default.** `framing` cannot be guessed — the danger the invariant guards against is exactly "delta from last is a dangerous default anchor after a rejected iteration." Therefore **this question is asked even in `--quick` mode** and is the one dialog that has no skip path. If the operator force-stops here, re-surface the four options once more; the brief cannot be written at `brief_version: "2.2"` without a committed framing value. A hollow answer («høres bra ut», «gjør som du vil», an empty reply) is not a framing value either: ask it again. Report: ``` Framing: {preserve | refine | replace | new-direction} ``` ## Phase 3 — Completeness loop Phase 3 gathers the brief's content in **one question round**, sized by the task's **size class** (ceremony by size). Use `AskUserQuestion` for every question. **The interview form is the skill `voyage:interviewing`.** Call the Skill tool with `voyage:interviewing` before the first question and run the round in its form: facts looked up first, never asked; one round with the recommended answer first; what you can predict and what is over the budget written down; the stop rule. This phase holds only what is `/trekbrief`'s own: the size class and its budget (Step 3b), the fixed questions and where each answer lands in the brief (Step 3c). ### Step 3b — Ceremony by size (K1) Put the task in one of three size classes. In doubt, take the heaviest that fits. | Class | Typical task | What the pipeline does | |---|---|---| | `small` | one change in one place, no new dependency, no interface change, easy to undo | one round, no follow-up; brief-reviewer runs once and its gaps become written assumptions, not questions, written after the review stamp (Step 4e, passed gate, step 4); Phase 3.5 is skipped | | `bounded` | several files or one module behind a clear boundary, no architecture decision | the round + at most one follow-up; at most one brief-review follow-up; Phase 3.5 asks one question for all four phases | | `architectural` | a new module, interface, dependency, data model or migration; anything hard to undo | follow-up rounds while answers open new branches; the full brief-review loop; Phase 3.5 asks per phase | - **Said aloud.** State the class and why in one line *before* the round ("This reads as `small`: one setting on one screen, no new dependency."), and put it to the operator as one of the round's questions: your class as the recommendation, the other two as the override. - **Only ever moves up.** When an answer, the brief-reviewer or the repo shows more than the class assumed (a migration, a new dependency, an interface change), raise the class, say so in one line, and use the new budget from then on. You never lower it yourself; only the operator's explicit override lowers it. - **Written to the brief** as `ceremony: ` in Step 4a. An absent field reads as `architectural`, so a brief from another producer gets the heaviest treatment downstream. ### Step 3c — The question round The round runs in the form of `voyage:interviewing`. What `/trekbrief` adds: 1. **Candidates.** The coverage list is the question bank below (Intent, Goal, Success Criteria, Research Plan, Non-Goals, Constraints, Preferences, NFRs, Prior Attempts), plus three fixed questions every round carries: framing (Phase 2.5, first), the size class (Step 3b) and where the brief is stored (`artifact_store`, below). 2. **The budget is the class budget** (table below). A `bounded` or `architectural` round is consecutive `AskUserQuestion` calls with no drafting in between. 3. **Where the written-down answers land.** Predictions ("assumed, not asked") and the Deferred list, one line of why each, go into `## Open Questions / Assumptions`, where the operator sees them before approving; the Deferred list is also printed with the round. 4. **Follow-ups by class.** A follow-up round is only for an answer that opens a branch you cannot predict (`small`: never; `bounded`: at most one). 5. **Answers that decide nothing.** «høres bra ut», «gjør som du vil», "sounds good", "whatever you think" and an empty reply are not a decision. Record the recommended answer as an assumption ("not confirmed — the answer was «…»"), never as the operator's choice. **Budget per class** (interview questions, the three fixed ones included; the Phase 4h approval is not counted): | Class | Questions | Rounds | |---|---|---| | `small` | 4 | one `AskUserQuestion` call, no follow-up | | `bounded` | 8 | the round + at most one follow-up | | `architectural` | 12 per round | the round + follow-ups while answers open new branches | **Where the brief is stored** (`artifact_store`; operator decision 2026-10-06: the approval log is always committed, the brief only by choice). One question every round. Recommend `git` for a private repo and `local` when the repo is public or you cannot tell: | Option | Maps to | Consequence | |---|---|---| | **In git** | `artifact_store: git` | `brief.md` (and later `plan.md`) is committed together with its approval. | | **Only on this machine** | `artifact_store: local` | The project folder is kept out of git through the repo's `.git/info/exclude`, a file that is never committed. | The approval log is committed either way; it holds hashes, times and file names, never the text. **Borrowed, with credit.** The size classes, "heaviest in doubt" and the one-way ratchet: obra/superpowers@8ca22db (MIT, © 2025 Jesse Vincent), skills/brainstorming. The class ladder: Kiro's docs (kiro.dev — Plan mode, Quick Spec, full spec; read 2026-10-06; an idea only, Kiro is a closed product). The answers that decide nothing (Step 3c, point 5): addyosmani/agent-skills@9d0c60d (MIT, © 2025 Addy Osmani), skills/interview-me. The interview form's own credits are in `voyage:interviewing`. ### Internal state Track this structure in memory as the loop runs: ``` state = { intent: { content: "", probes: 0 }, # required goal: { content: "", probes: 0 }, # required success_criteria: { content: [], probes: 0 }, # required research_plan: { topics: [], probes: 0 }, # required non_goals: { content: [], probes: 0 }, # optional constraints: { content: [], probes: 0 }, # optional preferences: { content: [], probes: 0 }, # optional nfrs: { content: [], probes: 0 }, # optional prior_attempts: { content: "", probes: 0 }, # optional ceremony: "small | bounded | architectural", # Step 3b; only moves up artifact_store: "git | local", # Step 3c assumptions: [], # predicted, hollow or force-stopped answers deferred: [], # over budget, with why question_history: [] # list of questions asked } ``` `content` is raw user answers merged; `probes` is how many times this section has been asked; `question_history` prevents re-asking the same variant twice. ### Required sections (initial-signal gate) Four sections MUST have substantive content before exiting Phase 3: 1. **Intent** — full sentence or paragraph (not a single word or phrase) 2. **Goal** — full sentence or paragraph 3. **Success Criteria** — at least one concrete, testable item 4. **Research Plan** — either ≥ 1 topic probed, OR the user has explicitly confirmed "no external research needed", OR (when you can predict it) it is written down as the assumption "no external research needed", which the operator sees in the brief before approving "Substantive" means: non-empty, not a trivial one-word reply, not "I don't know" without a recorded assumption. The strict falsifiability check happens in Phase 4 (brief-review gate); Phase 3 is just the initial-signal bar. Optional sections (Non-Goals, Constraints, Preferences, NFRs, Prior Attempts) do not gate exit. If they remain empty after the required sections pass, they will be recorded as "Not discussed — no constraints assumed" in Phase 4's draft. ### Question bank (per section) The coverage list Step 3c draws its candidates from. Each variant is a starting point for a round question, not a script; write it as a full sentence with your recommended answer first. **Intent** (required): - _Anchor_ (probes=0, content empty): "Why are we doing this? What is the motivation, the user need, or the strategic context behind the task?" - _Follow-up_ (probes≥1, content present but shallow): "What happens if we do nothing? Who is affected?" - _Sharpen_ (user mentioned a symptom): "You mentioned {X}. Is {X} the symptom or the underlying cause?" **Goal** (required): - _Anchor_: "Describe the end state in 1–3 sentences — specific enough to disagree with." - _Follow-up_: "How would you recognize this is done when looking at the UI / API / codebase?" **Success Criteria** (required): how a criterion is written so the review can run it is the skill `voyage:writing-criteria`; call it before proposing one. - _Anchor_: "How do we verify it is actually done? List 2–4 concrete, testable conditions — commands to run, observations, or metrics." A command the review can run is one test-runner call (`npm test`, `node --test `, `bash tests/