| name | linear-project-workflow |
|---|---|
| description | Opinionated end-to-end Linear workflow for a small multi-dev project (design → decisions → issues → build → capture → retro). Use when kicking off, running, or wrapping a multi-person project in Linear that wants a design doc, a decision log, mid-flight knowledge capture, and a retro. Delegates issue/branch/PR mechanics to the linear-workflow and linear-cli skills. |
The execution layer (issues, branches, status, PRs) is owned by linear-workflow and linear-cli — this skill does not repeat it. This is the layer above: how a project is shaped in Linear so a few devs move fast without losing the decisions and discoveries that only surface mid-build.
Every rule here was retrofitted from a real project (Native 2FA, 2026-07) where the code shipped in ~90 minutes but key security invariants (challenge-token jti consumption, replay ratcheting, a 401-vs-400 convention) were designed in commit messages and Slack with no durable home — and only caught by luck-adjacent review. The workflow's job is to make that catch systematic.
Four docs, four distinct lifecycles. Keeping them separate is the point — a living plan and an immutable record read differently, and mixing them makes both untrustworthy.
| Doc | Answers | Lifecycle |
|---|---|---|
| Tech Design | What are we building? | Living during design, frozen-ish after |
| PRD | What must it do? (requirements + acceptance) | Stable; the contract |
| Decision Log (ADRs) | Why is it this way, not the obvious alternative? | Append-only, forever true |
| Retro | What tripped us up; what we'd change | Written at the end, one per project |
The Decision Log opens with a glossary — the domain's vocabulary (each entity, state, and mechanism named once). New readers need the words before the decisions parse, and the act of naming the states is what surfaces the lifecycle questions in Phase 0. On 2FA the glossary (first factor, challenge token, jti consumption, gate, …) earned its keep immediately.
Plus a lightweight Discoveries stream (see Phase 3) — can be a section of the retro doc, a pinned issue, or a .worklogs/ file; lower ceremony than an ADR.
Write the Tech Design doc, but generate its content by state-transition modeling, not prose-first. The failure mode is not "the doc was wrong" — it's "the doc named a thing but never interrogated it." (2FA named the "primed session between password and 2FA" state but never modeled its transitions → the jti invalidation decision had no home.)
Modeling forces the questions instead of hoping you think of them. For every entity/state/boundary, draw the transitions and ask:
- How is it created? How is it invalidated / expired / revoked? What are all the edges out of this state?
- What stops replay or double-use while it's live?
- What's the failure mode — throttle, abuse bound, lockout?
- What's the degraded path — license lapse, no network, restart, concurrent request?
A "primed session" state with only one drawn edge out is the smell: real states have several, and the missing edges are the undiscussed decisions. An unanswered question is fine — it becomes a visible TBD the build fills in. A missing question is the bug. The TBDs are the build's checklist.
Run a relentless interview on the model (the grill-with-docs mode over domain-modeling): interrogate each decision, refuse the first plausible answer, and capture the outcome in the same motion — the ADRs and glossary fall out of the grilling, they aren't a separate write-up afterward. Same discipline as Phase 3's "same PR" rule, one phase earlier: grill into the Decision Log, not into a meeting that someone later transcribes.
- Each settled contested call → an ADR (one decision, its rationale, the rejected alternative), written as it's decided.
- Each newly-named term → a glossary entry.
- Each unresolved fork → a TBD flagged in the Tech Design, owned by a build issue.
2FA's ADRs 1–8 came from this phase and held up. The gap was ADR 9 — invariants that couldn't be known until build; that's Phase 3's job, not a Phase-1 failure.
Only cut issues once grilling settles the genuinely-contested calls. Underspecified issues are churn.
Hand off to linear-workflow / linear-cli. One issue per reviewable slice (per-PR, not per-feature). Sequence by dependency, mark the release bar. Keep the slice small enough that review is deep, not shallow — security-sensitive code especially.
Parallelization rule (learned): for a small, fast project, do not split the build across devs — by the time you split work and sync state, one person has finished (2FA backend was 90 min serial). Parallelize review, research, and audit instead — those are genuinely independent. Reserve multi-dev/multi-agent fan-out for the slow, wide phases (large migrations, broad audits), not a tight build.
The core discipline. Up-front docs capture what's knowable before code; this phase captures what's only knowable during — and that knowledge is where projects rot.
Two homes, two kinds of mid-build knowledge:
- Decision (a choice with a rationale + rejected alternative) → append an ADR, in the same PR that makes the decision. Not a separate ceremony — the same diff. If the PR changed why the code is the way it is, it touches the Decision Log. Examples from 2FA:
jticonsumption, 401-reserved-for-no-session, email-OTP-eviction-on-write. - Gotcha (a non-obvious fact you paid to learn) → a dated bullet in the Discoveries stream. Lower ceremony. Examples: "this keyword is kebab not snake — bit CI twice", "the REPL runs stale defs after a rename; only fresh-JVM catches it", "adding a premium feature touches 5 enumerations, here's the list."
Enforcement is review-time, not author-time. Nobody documents their own decisions while heads-down; they do it when asked. So the catch layer is a checklist item on every PR review:
Did this change add or alter a decision or a gotcha? If yes — where is it written down?
That single question is the whole system. It generalizes "does the code match the doc?" into "did the code produce knowledge the docs don't have yet?" — which is the failure the whole workflow exists to fix.
State-sharing during the build:
- Board vs. code reconciliation and factual mechanics → fine to automate via linear-cli (issue comments, state changes).
- Never auto-generate project/initiative status updates — humans write those (team rule, linear-cli skill).
- A running decision/gotcha capture belongs in the docs above, not scattered in Slack — Slack is a record, not a findable home.
Per-PR: fresh-JVM/full-suite tests (not REPL-green — the REPL lies about renames/splits), the relevant /review-pr adversarial passes (parallel = good here), and a manual QA playbook for the whole feature. The playbook doubles as the PRD's acceptance evidence and as the tracking-issue checklist.
Write the Retro doc. Reconstruct the timeline from the git record, not memory — sequencing is the point and memory smooths it. For each stumble, name: what happened, what it cost (commits/time), and the systemic fix (a checklist, a phase gate, a skill). End with a one-line takeaway.
The retro's output is changes to this workflow — it's the loop that keeps the workflow honest. If a class of miss recurs across projects, it becomes a new phase gate or a new checklist item here.
Phase 0 Design — model states+transitions; every new state must show ALL its edges out
Phase 1 Grill — relentless interview → ADRs+glossary fall OUT of it, into the log, BEFORE issues
Phase 2 Issues — [linear-workflow] per-PR slices; parallelize review not build
Phase 3 Build — capture as you go: decision→ADR (same PR), gotcha→Discoveries
review-time gate: "did this produce a decision/gotcha? where's it written?"
Phase 4 Verify — fresh-JVM tests + parallel /review-pr + manual QA playbook
Phase 5 Retro — timeline from git; each stumble → systemic fix; feeds back into THIS doc
- Pre-digging every possible issue up front. Waterfall fallacy — diminishing returns; the invariants that matter surface at build time. Force the questions up front, defer the answers, and have a reliable catch layer. Don't over-index on any single up-front miss.
- Trusting REPL-green. It runs stale definitions after a rename/split. Always fresh-JVM before push.
git add -Aon a dirty tree. Swept 47 local session files into a pushed commit. Usegit add -p/ explicit paths.- Feature-registration incompleteness. New premium feature / setting / enum → grep every enumeration (define site, token-features map, FE type, stats/snowplow mirror, tests). Missing one = a red CI you chase across the matrix.
- Editing someone else's design doc without a nod. Docs have owners; propose, don't overwrite. (Issue comments and factual reconciliation are fine to just do.)