Product development workflow¶
This is OGUR's durable product-development process for work performed by founders,
Claude Code, and Codex. The active scope and release dates live in
mvp-scope.md; this document defines how an idea becomes a shipped
change without quietly becoming a new milestone.
The workflow¶
flowchart TD
Idea["Feature idea or user request"] --> PM["Product manager gate<br/>read-only; emits a structured verdict"]
PM --> Verdict["Structured verdict<br/>verdict + disposition + scope citation"]
Verdict --> Intake["/linear-feature-intake<br/>the only Linear writer;<br/>records the decision, never re-decides it"]
Intake -->|"STOP"| Stop["Decision record only; no execution ticket"]
Intake -->|"EVIDENCE"| Research["One blocked customer-research issue"]
Research --> PM
Intake -->|"BACKLOG"| Backlog["One Backlog issue in the future milestone"]
Intake -->|"SPEC"| Design["Designer"]
Intake -->|"SPEC"| Tech["Technical lead"]
Design --> Spec["One implementation spec"]
Tech --> Spec
Spec --> Founder["Founder approves scope, estimate, and cut"]
Founder --> Issues["Meta issue + implementation children in Linear"]
Issues --> Build["Implementation agent"]
Issues -.->|"not built"| Dispatch["/dispatch-implementation<br/>selects harness + model; owns routing only"]
Dispatch -.-> Plan["Executor plan-only session<br/>read-only; returns a technical plan"]
Plan -.-> PlanOK["Plan approval<br/>checked against the approved spec"]
PlanOK -.-> Build
Build --> EngineReview{"Diff touches<br/>ogur/engine/?"}
EngineReview -->|"yes"| ProofReview["review-engine on the resolved PR head<br/>(+ coverage-eval for discovery_modality)"]
EngineReview -->|"no"| QA
ProofReview --> QA["QA executes acceptance gate"]
QA -->|"FAIL"| Build
QA -->|"PASS"| Audit["/linear-release-audit<br/>gates vs Linear + GitHub evidence"]
Audit -->|"gate not met"| Build
Audit -->|"all gates met"| Release["Release"]
Release --> Learn["User evidence and release evidence"]
Learn --> Decision["Decision log or ADR"]
Decision --> PM
Steward["/linear-steward<br/>keeps the board's claims true"] -.->|"audits, does not decide"| Issues
The expensive path starts only after the product-manager gate. Rejected ideas do not receive designs, estimates, implementation plans, or speculative branches.
The product-manager → Linear handoff¶
The gate decides; Linear records. Those are two jobs and they are held by two things, because a component that both decides and creates will find a reason to create.
product-manager emits, alongside its prose verdict, one machine-readable block:
proposal: # one sentence, the PM's words
verdict: # IN-MVP-1 | IN-MVP-2 | OUT | NEEDS-EVIDENCE
milestone: # the milestone the verdict places it in; null for OUT
scope_citation: # the quoted line of mvp-scope.md the verdict rests on
user_evidence: # named evidence, or null
reversal_condition: # the concrete observable that would change the verdict
disposition: # STOP | EVIDENCE | BACKLOG | SPEC
disposition is what /linear-feature-intake switches on. The valid pairings are
OUT→STOP, NEEDS-EVIDENCE→EVIDENCE, a non-active milestone→BACKLOG, and the
active milestone→SPEC; any other pairing is a malformed gate output and the intake
skill stops rather than picking a half.
Three properties are load-bearing:
product-managerremains the sole scope authority./linear-feature-intakeperforms no assessment of its own and may not override, soften, or re-interpret a verdict.product-managerremains read-only. It has noEditorWrite, and it does not touch Linear. The handoff is either the PM workflow invoking the intake skill, or an orchestrator passing the verdict block to it.OUTnever becomes a backlog feature. It yields a decision record — statusDone, carrying the reversal condition — and no execution ticket in any form.- One execution record per accepted idea. An idea that already has a Linear issue is updated, never duplicated. The intake skill's §2 duplicate search runs before any write, and finding an equivalent issue stops the run.
- No parallel backlog file. Linear is the only execution record;
/specdoes not maintain a Markdown backlog beside it.OUTverdicts append one line todocs/product/spec-log.mdfor gate calibration — that log schedules nothing and records nothing accepted, so it is an audit trail, not a second board.
Status. The structured block is the contract the intake skill is written against, and
product-manageremits it as of PR #223 — so--verdictis live rather than blocked.--verdict --specis the persistence-only path/specuses after it has already run the gate and written the spec; supplying--specmeans the intake skill must not invoke/spec, which is what keeps the two orchestrators from calling each other.
Linear skills¶
Three harness-neutral skills implement the Linear half of this workflow. Their
canonical definitions are in .agents/skills/; the files under .claude/skills/
are adapters that point at them, so Claude Code and Codex cannot drift. All three
read linear-workspace-contract.md first — the
statuses, the one-primary-project rule, what Done requires per work type, and the
mutation-safety protocol.
| Skill | Answers | Default |
|---|---|---|
/linear-steward |
Are the board's claims true? Includes focused GitHub→Linear finished-work reconciliation | read-only audit; explicit apply writes |
/linear-feature-intake |
What records does this verdict imply? | writes only what the disposition implies |
/linear-release-audit |
Would the release gate pass today? | read-only; --apply writes |
The rule they share, and the reason they are worth having: a merged implementation PR is not evidence that a release gate passed. The gate needs the gate's own acceptance artifact. Everything else in the contract follows from taking that seriously.
Downstream dependency — dispatch-implementation (named, not built)¶
The chain above stops at "implementation agent", which is a hand-wave: today a human
picks a harness, opens a session, and hopes the session does not re-open scope. The
seam that closes it is a separate harness-neutral skill, dispatch-implementation.
It does not exist yet. It is named here so the skills that feed it are built against
a known consumer rather than retro-fitted to one.
product-manager (#223)
→ linear-feature-intake
→ founder approval
→ dispatch-implementation
→ executor plan-only session
→ plan approval
→ implementation session
→ draft PR
→ independent review / eval gates
→ Linear read-back
It is a dispatcher, not a fourth gate. It consumes an approved,
implementation-ready Linear issue and may not reconsider scope, rewrite acceptance
criteria, or create a second ticket — the same three refusals linear-feature-intake
carries, for the same reason: a component that both routes and decides will decide in
favour of routing.
Specification is not planning¶
The originating harness may produce the product specification — user problem, scope decision, constraints, acceptance criteria, reversal condition. It may not silently produce and approve the executor's technical plan. Those are two artifacts, authored by two parties, and they are preserved separately in the handoff.
Every dispatched executor therefore starts in a hard plan-only stage:
| Executor | Plan-only mechanism |
|---|---|
| Claude | Launch with --permission-mode plan. It may inspect the repository and return a technical plan; it may not edit |
| Codex | The installed CLI has no literal --plan switch. Launch codex exec --sandbox read-only with a plan-only structured-output schema — the filesystem boundary, not a prompt, is what prevents implementation |
Only after the returned plan has been checked against the approved spec is the same scoped task resumed with write access. This is what stops the dispatcher — or the agent that wrote the spec — from smuggling unreviewed architectural choices into implementation under cover of "it was already approved".
It runs in both directions¶
The dispatcher selects an executor. It is not a one-way Codex-to-Claude bridge.
Codex triage/spec → dispatch → Claude plan → Claude implementation
Claude triage/spec → dispatch → Codex plan → Codex implementation
Both directions use the same Linear issue, the same spec schema, the same approval checkpoint, worktree isolation, structured completion report, and independent review gates. A Claude-authored implementation is normally reviewed by Codex; a Codex-authored implementation by Claude or another independent review task. The implementing session never certifies its own gate.
Dispatcher responsibilities¶
- Validate the PM verdict and spec, the acceptance criteria, the exact Linear identifier, and explicit approval to begin planning.
- Select both harness and model by risk, ambiguity, relevant strengths, and expected horizon — not by task size alone.
- Create an isolated worktree and branch, and run the chosen executor plan-only.
- Stop for plan approval before granting edit permissions, then resume the same scoped task for implementation.
- Return branch, draft PR, tests, acceptance evidence, blockers, costs, and the originating Linear issue.
- Trigger independent review gates —
review-claude-pr,/review-engine, domain evals such as/coverage-eval, or the symmetric review path — before any issue or release gate advances.
Current CLI surface, for whoever builds it: Claude supports --worktree,
--permission-mode plan, --model fable|opus|sonnet, --effort,
--max-budget-usd, background execution, session resumption, and structured output.
Codex supports non-interactive execution, read-only and workspace-write sandbox
stages, session resumption, model selection, and structured output.
Invariants it inherits¶
- Linear is shared state between harnesses, not one harness's scratchpad.
product-managerowns scope. The dispatcher owns routing. Neither owns the other's.- The receiving executor owns the technical plan.
- Plan approval precedes edits.
- Neither harness may merge automatically.
Prerequisite: tool access is present, repo-local skill discovery is unverified. Both harnesses reach Linear — Codex through the
linearplugin (~/.codex/plugins/cache/openai-curated-remote/linear/…/.mcp.json→https://mcp.linear.app/mcp, OAuth), Claude through its own MCP configuration — so the Linear tool surface the three skills call is available on both sides.What has not been demonstrated is that a project-local
.agents/skills/directory is discovered from a repository checkout. The layout matches what Codex's own plugin skills use (SKILL.md+agents/openai.yaml), but those are distributed through a marketplace, not read out of a working tree. Until one skill has been invoked end to end from a real Codex session, treat.agents/as the agreed home for the canonical definition rather than as proven wiring. The repository'sAGENTS.mdalso points Codex at a.Codex/skills/path that does not exist — it is a find-replaced mirror ofCLAUDE.md, and it is untracked. Fixing it is the cheapest way to close the gap.
Roles and refusal conditions¶
| Role | Decides | Produces | Refuses to do |
|---|---|---|---|
| Product manager | Whether the proposal is required by the active milestone | One scope verdict with contract citation | Turn founder enthusiasm, competitor parity, or sunk cost into scope |
| Designer | How the approved user task fits the existing product surface | Surface, states, data, and provenance contract | Invent a component when an existing one fits; silently contradict the UX spec |
| Technical lead | What exists, what changes, and where the architectural seam is | File-grounded delta, risks, collisions, half-day estimate | Estimate work without naming real files and symbols |
| QA | What observable evidence proves the feature and release | Runnable acceptance criteria and false-positive definition | Sign off on a criterion with no execution path |
| Founder | Scope amendments, trade-offs, and release judgement | Approval, explicit cut, or contract amendment | Delegate product judgement to the agents |
| Implementation agent | The approved code and tests | One reviewable branch or PR | Reopen scope inside a coding session |
The role agents are read-only. They decide and specify; they do not implement. This prevents a gate from approving its own work after it has already built it.
How that is enforced, precisely. product-manager, designer, and qa are
granted file-reading and search tools only, so the refusal holds at the tool
boundary and no prompt can talk them past it. tech-lead additionally needs a
shell — its collision check reads open PRs and worktrees — and a shell can write,
push, and call APIs whatever the other tool grants say. Its restriction is
prompt-level and its contract lists the inspect-only commands it may run. The
distinction is recorded rather than smoothed over: three enforced, one asserted.
One feature, one record¶
The four roles populate one feature spec under docs/product/specs/; they do not
produce four independent plans. A feature record contains:
- User problem and evidence
- Scope verdict and milestone citation
- Surface and data contract
- Reuse/build delta and estimate
- Runnable acceptance and release checks
Temporary agent plans are disposable. Permanent decisions belong in an ADR or the decision log. Release evidence belongs with the feature or release record.
Milestone behavior¶
IN means in the currently active milestone, not permanently IN-MVP-1.
After a release, the founder advances the active milestone in the scope contract;
the same workflow then gates that milestone's work. Future-milestone ideas receive
a backlog entry but no implementation spec until their milestone becomes active.
Release transition and harness reset¶
After MVP-1, reserve a maximum of two working days for a harness reset before MVP-2 execution resumes:
- Archive superseded plans and demo-only workflows
- Confirm every role and shared skill still has exactly one canonical file under
.agents/, with harness adapters that point rather than duplicate - Merge or retire overlapping skills; do not rewrite proven skills for tidiness
- Update the active milestone and its release gate
- Resume product work when those four outcomes exist, even if broader cleanup remains
The reset is not a repository-wide cleanup milestone. Unbounded cleanup has no natural stopping condition and may not consume the MVP-2 delivery window.
The scope contract is amended only when all four conditions hold:
- Named user evidence requires the change
- The active release gate fails without it
- The technical lead has produced a file-grounded estimate
- Existing scope is cut to pay for it, or the deadline moves explicitly
Session and release discipline¶
Before implementation¶
- Read the active scope contract
- Run the product-manager gate
- Run designer and technical-lead assessment in parallel
- Define QA acceptance before code starts
- Obtain founder approval for the spec and its scope trade-off
During implementation¶
- One approved feature per branch or worktree
- No new product decisions inside the coding session
- Tests and proof artifacts land with the implementation
- New architectural seams require an ADR
After implementation¶
- QA executes the acceptance artifact
- A reviewer inspects the merge-base diff
- Proof-based engine review, when the merge-base diff touches
ogur/engine/ortests/unit/engine/— see below. Required, not advisory - The founder checks that the user need—not merely the specification—was answered
- Merge or reject the change
- Record a decision only when a decision was actually ratified
Proof-based engine review — a conditional, required gate¶
"A reviewer inspects the diff" is too weak for the engine. PR #211 carried a green submitted suite while exact-head reproductions exposed adapter-routing, record-evidence, cache-fingerprint, and classification defects. Reading the diff did not find those; running against the head did.
So when the merge-base diff touches ogur/engine/ or tests/unit/engine/:
- Run
review-engineagainst the resolved PR head, not whichever branch happens to be checked out — pass the PR number, orbase_ref+head_sha. Its output records the reviewed SHA; that SHA is the evidence, and a review of the wrong ref produces valid-looking proof about code the PR does not contain. - If the diff touches
ogur/engine/discovery_modality/, also runcoverage-evalover the cross-deck surface and report the delta against the prior comparable run. If the shared matcher changed, the number is not comparable — say so and re-baseline rather than reporting a delta. - Attach the proven findings and the clearly-marked questions to the review record.
- Every accepted defect gains a permanent regression test in the repository. Review-only reproductions used to prove a finding may stay outside it.
Canonical artifacts¶
Keep the permanent process surface small:
| Artifact | Purpose |
|---|---|
docs/product/mvp-scope.md |
Active release gates, explicit exclusions, cuts, and founder decisions |
docs/product/product-development-workflow.md |
Durable path from idea to release |
docs/product/specs/ |
Approved, implementation-ready feature records |
docs/adr/ |
Ratified architectural decisions and consequences |
| Release evidence | Runnable QA results and user evidence |
Skills and agent prompts implement this process; they are not the source of truth.
One role contract, two harnesses. The canonical role contracts are tracked
under .agents/roles/ — product-manager.md, tech-lead.md, designer.md,
qa.md. Codex and any other harness read them directly; .claude/agents/<role>.md
is a thin Claude Code adapter carrying frontmatter, harness-specific notes, and a
pointer to the canonical file. Harness-neutral skills follow the same shape:
canonical under .agents/skills/<name>/SKILL.md, adapter under
.claude/skills/<name>/SKILL.md.
The rule this enforces: a role's behaviour is never restated in two files. A second copy of a prompt cannot be kept in sync by discipline, and its divergence is invisible until the two harnesses return different verdicts on the same proposal. Adding a role or a shared skill means adding the canonical file first; an adapter that duplicates rather than points is the defect.