AI Coding Workflows

How to Use OpenSpec Across the Full Development Workflow

A practical workflow for using OpenSpec from exploration to proposal, implementation, quality checks, PR review, merge, and archive without letting specs drift from the code.

28 min read

TL;DR

Use OpenSpec as the working memory for a feature, not as a document you write once and forget.

My default workflow for a team looks like this:

explore idea
  -> create feature branch
  -> /opsx:propose
  -> review proposal, specs, design, tasks
  -> /opsx:apply
  -> update artifacts as implementation teaches you things
  -> run quality gates
  -> open PR
  -> address review
  -> merge PR
  -> archive the OpenSpec change

The most important rule is simple:

Archive after the PR is merged, not before, if your main specs are meant to describe merged product behavior.

OpenSpec’s docs say archiving merges delta specs into openspec/specs/ and moves the completed change to openspec/changes/archive/. That means archive is not just cleanup. It updates the source of truth. In a PR-based team, the cleanest policy is to archive only after the code it describes has landed.

You can still iterate while coding. OpenSpec’s current OPSX workflow is intentionally fluid: update proposal.md, design.md, delta specs, and tasks.md as you learn. For the same intent, update the current change. For a genuinely different intent, create a new sibling change, even in the same chat thread.

For team work, keep the collaboration contract explicit: one owner coordinates the OpenSpec change, reviewers comment on the artifacts, and implementation agents work in isolated branches or worktrees. If you delegate /opsx:apply to subagents, give each subagent one change, one worktree, and one verification contract.

What You Will Learn Here

  • How to use /opsx:explore, /opsx:propose, /opsx:apply, /opsx:verify, /opsx:sync, and /opsx:archive in a real delivery flow.
  • Where a feature branch belongs in the OpenSpec workflow.
  • Why archive should usually happen after PR merge.
  • How to handle small implementation tweaks without creating noisy new specs.
  • When a second proposal in the same chat should be a new OpenSpec change.
  • How to split a proposal that generates many spec deltas into smaller branches and PRs.
  • How to update tasks.md so code review, source audit, app checks, lint, tests, and Playwright e2e are part of the workflow.
  • How engineers and PMs can review the same artifacts without forcing every product discussion into GitHub comments.
  • How to use OpenSpec collaboratively in a team without losing ownership of the source of truth.
  • How to combine OpenSpec, git worktrees, and assigned implementation subagents safely.

What The Sources Confirm

As of July 2, 2026, the primary sources I used are the Fission-AI/OpenSpec repository and documentation.

The source-backed parts are:

  • OpenSpec is a spec-driven development framework for AI coding assistants.
  • The default core profile includes /opsx:explore, /opsx:propose, /opsx:apply, /opsx:sync, and /opsx:archive.
  • The expanded workflow can add commands like /opsx:new, /opsx:continue, /opsx:ff, /opsx:verify, /opsx:bulk-archive, and /opsx:onboard.
  • OpenSpec separates openspec/specs/ as the source of truth from openspec/changes/ as proposed modifications.
  • A change folder usually contains proposal.md, design.md, tasks.md, and delta specs under specs/.
  • /opsx:explore is a no-stakes conversation that creates no artifacts and writes no code.
  • /opsx:apply works through tasks.md, writes code, runs checks as needed, and marks tasks complete.
  • /opsx:verify validates implementation against artifacts across completeness, correctness, and coherence. It reports issues but does not block archive.
  • /opsx:archive checks artifacts and tasks, offers to sync delta specs, moves the change into openspec/changes/archive/, and preserves artifacts for audit history.
  • /opsx:sync can merge delta specs into main specs without archiving the active change, and the command docs call out long-running changes and parallel changes as cases where manual sync can be useful.
  • /opsx:bulk-archive can archive multiple completed changes and is documented as handling spec conflicts between changes.
  • OpenSpec’s existing-projects guide recommends one openspec/ directory at the monorepo root for most monorepos.
  • For multi-repo planning, OpenSpec has beta stores: standalone OpenSpec repos that code repos can reference.
  • OpenSpec worksets are local, personal views that can open a planning root together with related code folders; they are not committed or shared.
  • Git worktrees let one repository have multiple working trees, so different branches can be checked out at the same time.
  • OpenSpec installs skills and/or command files for many AI coding tools, including Cursor, Claude Code, Windsurf, GitHub Copilot, and others.

The workflow policy in this article is my synthesis:

Documented OpenSpec behavior:
  archive merges specs and preserves the change

Recommended team policy:
  merge the PR first, then archive, so specs describe merged reality

That distinction matters. OpenSpec gives you the mechanism. Your team still needs an operating model.

The End-To-End Flow

Here is the whole loop I would teach a team.

                    no files changed
                         |
                         v
                  /opsx:explore
                         |
                         v
                 choose viable scope
                         |
                         v
               git checkout -b feature/x
                         |
                         v
                  /opsx:propose
                         |
                         v
        proposal + specs + design + tasks
                         |
                         v
                 human artifact review
                         |
                         v
                    /opsx:apply
                         |
                         v
            code + task updates + tests
                         |
                         v
           verify + lint + unit + e2e
                         |
                         v
                      open PR
                         |
                         v
              review comments + fixes
                         |
                         v
                       merge PR
                         |
                         v
                   /opsx:archive
                         |
                         v
           specs now describe merged behavior

For engineers, this keeps implementation and verification close to the code. For PMs, it keeps intent, scope, and acceptance behavior visible in Markdown before the PR becomes a wall of diffs.

Step 1: Explore Before You Commit To A Change

OpenSpec’s docs explicitly position /opsx:explore as a thinking partner. It can read the codebase, compare options, draw diagrams, and help sharpen a fuzzy idea into a concrete plan. It does not create a change folder, write artifacts, or modify code.

That makes it safe before a branch exists.

Use it when the problem is real but the solution is not obvious:

/opsx:explore

We want to reduce checkout failures, but I do not know whether the
problem is payment retries, client double-submit, inventory reservation,
or webhook handling.

Please inspect the relevant code paths, summarize the likely causes,
compare implementation options, and recommend one small first change.

The output you want is not “write code.” The output is a scoped decision:

Problem:
  duplicate checkout events can create duplicate orders

Recommended first change:
  add idempotency around order creation

Not in scope:
  redesign the entire payment workflow

That is the point where a proposal becomes useful.

Step 2: Create The Feature Branch Before /opsx:propose

Because /opsx:propose creates files, I prefer to branch before running it.

git checkout main
git pull --ff-only
git checkout -b feature/add-order-idempotency

Then create the OpenSpec change:

/opsx:propose add-order-idempotency

The docs say /opsx:propose creates a change folder and generates the planning artifacts needed before implementation. In the default spec-driven schema, that usually means:

openspec/changes/add-order-idempotency/
+-- proposal.md
+-- design.md
+-- tasks.md
+-- specs/
    +-- checkout/
        +-- spec.md

That folder belongs on the branch because it is part of the work. It gives reviewers the “why” and “what” before they review the implementation.

The practical mapping is:

feature branch = code review boundary
OpenSpec change = intent, requirements, design, and task boundary

Most of the time those should be one-to-one.

Step 3: Review The Proposal Before Coding

Before /opsx:apply, pause long enough to review the artifacts.

Engineers should check:

  • Does design.md match the actual architecture?
  • Are the tasks small enough to verify?
  • Are risky migrations, contracts, and rollback paths visible?
  • Are tests and app checks listed as tasks, not left as vibes?

PMs should check:

  • Does proposal.md describe the user or business outcome clearly?
  • Are non-goals explicit?
  • Do the delta specs describe observable behavior?
  • Are acceptance scenarios understandable without reading code?

A good pre-implementation review comment sounds like this:

The proposal says "prevent duplicate orders," but the spec only covers
client double-submit. Please add a webhook retry scenario or mark webhook
dedupe out of scope.

That is much cheaper before code exists.

Step 4: Apply, But Keep The Artifacts Alive

Once the artifacts are good enough, run:

/opsx:apply add-order-idempotency

OpenSpec’s command reference says /opsx:apply reads tasks.md, identifies incomplete tasks, works through them, writes code, runs tests as needed, and marks tasks complete with [x].

The useful habit is to keep tasks.md current while the implementation evolves. Treat it as a living checklist:

## 1. Implementation

- [x] 1.1 Add idempotency key column to orders table
- [x] 1.2 Reject duplicate order creation for the same payment intent
- [x] 1.3 Make webhook handler reuse the same idempotency path

## 2. Verification

- [x] 2.1 Add unit tests for duplicate request handling
- [x] 2.2 Add integration test for payment webhook retry
- [ ] 2.3 Run checkout Playwright flow in headed mode
- [ ] 2.4 Run lint, typecheck, and build

If implementation teaches you the design was slightly wrong, update design.md. If it teaches you the behavior changed, update the delta spec. The OpenSpec editing docs are clear that artifacts are Markdown files you can edit at any time.

That is not process failure. That is the process working.

Step 5: Handle Tweaks And Small Changes In Place

Not every discovery deserves a new change.

Use this rule:

same intent, same user outcome, refined execution -> update current change
new intent, independent outcome, scope explosion   -> create a new change

Examples that should usually stay in the current change:

  • A component name changed during implementation.
  • You swapped one internal library for another.
  • The task list needs an extra test.
  • The spec needs one more edge-case scenario for the same requirement.
  • The design needs to reflect a codebase constraint you discovered.

Examples that should usually become a new OpenSpec change:

  • “Add idempotency” becomes “redesign checkout orchestration.”
  • The PM adds a new admin dashboard to the same branch.
  • The security review finds a broader auth policy gap.
  • The original change can merge cleanly, and the new idea can ship later.

This is similar to branch hygiene:

small correction to the same feature -> keep going
new feature hiding inside this feature -> split it

Can You Generate A New Explore Or Proposal After Applying An Existing Proposal?

Yes, with one important clarification.

You can explore again at any time. OpenSpec’s docs even encourage stepping back to explore a sub-problem mid-change. Exploration creates no artifacts, so it is a safe way to think through an implementation surprise.

You can also create another proposal in the same chat thread, but do not think of it as a nested folder inside the first change. OpenSpec changes are sibling units under openspec/changes/.

openspec/changes/
+-- add-order-idempotency/
|   +-- proposal.md
|   +-- design.md
|   +-- tasks.md
|   +-- specs/
+-- add-checkout-risk-dashboard/
    +-- proposal.md
    +-- design.md
    +-- tasks.md
    +-- specs/

Same chat thread is fine. Same branch can be fine for local exploration. Same PR is where I become cautious.

Use this decision flow:

new idea appears during /opsx:apply
  |
  v
is it required to finish the current user outcome?
  |
  +-- yes -> update current proposal/specs/tasks
  |
  +-- no  -> can current PR merge without it?
              |
              +-- yes -> create a new change and usually a new branch/PR
              |
              +-- no  -> decide whether original scope was wrong;
                         update current change if the story remains coherent

The risk is not technical. It is review clarity. A PR with two unrelated OpenSpec changes forces reviewers to answer two product questions and two implementation questions at once.

What If One Proposal Generates Many Specs?

Sometimes /opsx:propose creates a change that touches several spec domains:

openspec/changes/add-team-billing/
+-- proposal.md
+-- design.md
+-- tasks.md
+-- specs/
    +-- auth/spec.md
    +-- billing/spec.md
    +-- notifications/spec.md
    +-- admin-ui/spec.md

That is a signal to pause. It may be a real cross-cutting feature, or it may be a proposal that is too large to review and ship safely.

My default split is:

big idea:
  add team billing

delivery slices:
  1. add-team-billing-data-model
  2. add-team-billing-checkout
  3. add-team-billing-admin-ui
  4. add-team-billing-notifications

Each slice gets its own branch and usually its own PR:

branch: feature/team-billing-data-model
  OpenSpec change: add-team-billing-data-model

branch: feature/team-billing-checkout
  OpenSpec change: add-team-billing-checkout

branch: feature/team-billing-admin-ui
  OpenSpec change: add-team-billing-admin-ui

The parent proposal can still be useful, but I would not let it become a forever-open implementation branch. Use it as a planning artifact, then create reviewable child changes.

umbrella proposal:
  explains the end state and phase order

slice proposals:
  explain exactly what this PR changes

main specs:
  evolve after each slice is merged and archived

The archive order matters. Archive the first accepted slice before building later slices that depend on its behavior. That lets the next proposal start from current canonical specs instead of a stale umbrella plan.

PR 1 merged
  -> archive add-team-billing-data-model
  -> openspec/specs/billing now has the new base behavior

PR 2 starts
  -> propose checkout against the updated billing spec

If multiple slices are truly independent, they can run in parallel branches or worktrees. But avoid parallel MODIFIED deltas against the same requirement unless the owners coordinate carefully.

Use this split test:

can this slice merge without the others?
  yes -> separate branch/PR
  no  -> keep it in the same change or create a prerequisite slice first

does this slice change the same requirement as another open slice?
  yes -> serialize, merge one first, then rebase/rewrite the next delta
  no  -> safe candidate for parallel work

What not to do:

one giant OpenSpec change
  -> six weeks open
  -> many spec domains drift
  -> several agents edit the same proposal
  -> final PR is impossible to review

Better:

umbrella decision
  -> small spec-backed PR
  -> merge
  -> archive
  -> next spec-backed PR starts from updated truth

This is the same reason long-running feature branches hurt normal Git workflows: the longer the branch is open, the more the base moves under it. In OpenSpec, the moving base is not only code. It is also openspec/specs/.

Step 6: Add Quality Gates To tasks.md

The user-facing tasks should include quality work. Do not leave it as an afterthought.

Here is a practical tasks.md quality section for a web app:

## 4. Review And Quality Gates

- [ ] 4.1 Run `openspec validate add-order-idempotency`
- [ ] 4.2 Run unit and integration tests for changed modules
- [ ] 4.3 Run app checks: lint, typecheck, and build
- [ ] 4.4 Run Playwright checkout flow in headed mode and record findings
- [ ] 4.5 Perform code review for correctness, maintainability, and rollback risk
- [ ] 4.6 Perform source/spec audit: proposal, delta specs, design, and tasks match implementation
- [ ] 4.7 Update artifacts for any implementation drift found during review

For an Astro/React project, that might map to:

npm run lint
npm run build
npx playwright test --headed

For CI, headed Playwright is usually not the default. I would run headed locally when a human needs to see the browser behavior, then run headless in CI for repeatability:

local inspection:
  npx playwright test --headed

CI gate:
  npx playwright test

For PMs, the important part is not the exact command. It is that the task list exposes evidence:

Acceptance scenario -> test or manual verification -> PR note

Step 7: Use /opsx:verify Before PR Or Before Archive

If the expanded workflow is enabled, /opsx:verify is the command that checks implementation against artifacts. The docs describe three dimensions:

  • Completeness: tasks done, requirements implemented, scenarios covered.
  • Correctness: implementation matches spec intent and handles edge cases.
  • Coherence: code structure reflects the design and local patterns.

Run it after implementation and before you claim the work is ready:

/opsx:verify add-order-idempotency

Then convert warnings into tasks:

## 5. Verification Findings

- [ ] 5.1 Add missing test for webhook retry scenario
- [ ] 5.2 Update `design.md` because implementation uses advisory locks, not a queue
- [ ] 5.3 Re-run `/opsx:verify add-order-idempotency`

If you are on the default core profile and do not have /opsx:verify, you can still do the same review manually:

Compare:
  proposal.md -> did we build the promised scope?
  specs/**/*.md -> does behavior match implemented behavior?
  design.md -> does architecture match the code?
  tasks.md -> are checks complete?
  app test output -> did the product path work?

Step 8: Open The PR With Both Code And OpenSpec Context

The PR description should not duplicate every artifact. It should point reviewers to the right reading path.

A useful PR body:

## Summary

- Adds idempotency to checkout order creation.
- Covers duplicate client submits and payment webhook retries.
- Keeps follow-up risk dashboard work out of scope.

## OpenSpec

- Change: `openspec/changes/add-order-idempotency/`
- Proposal: intent and scope
- Delta specs: checkout behavior changes
- Design: idempotency approach and rollback considerations
- Tasks: implementation and verification checklist

## Validation

- `openspec validate add-order-idempotency`
- `npm run lint`
- `npm run build`
- `npx playwright test --headed` for checkout flow

This gives PMs a product review path and engineers a code review path.

PM review:
  proposal.md -> specs/**/*.md -> PR summary

Engineer review:
  design.md -> tasks.md -> diff -> tests

QA review:
  specs scenarios -> Playwright/manual evidence -> edge cases

How To Use OpenSpec Collaboratively In A Team

OpenSpec is not just an individual prompting aid. Used well, it becomes a shared delivery artifact.

The team model I recommend is:

PM / product owner:
  reviews proposal.md and behavior scenarios

Tech lead:
  owns design.md, risk, boundaries, and split decisions

Implementer or coding agent:
  works from tasks.md and updates it as evidence appears

Reviewer:
  reviews both the diff and the OpenSpec artifacts

Release owner:
  verifies checks, merges PR, then archives the accepted change

The key is that everyone reviews the part of the change they are qualified to judge.

                    openspec/changes/<change>/
                               |
          +--------------------+--------------------+
          |                    |                    |
          v                    v                    v
     proposal.md          design.md              tasks.md
          |                    |                    |
          v                    v                    v
    PM/product review    engineering review    delivery evidence
          |                    |                    |
          +--------------------+--------------------+
                               |
                               v
                            PR review

For a single repo, keep the change folder in the same repo as the code. That gives you one PR with both intent and implementation.

For a monorepo, OpenSpec’s existing-projects guide says the simplest model is one openspec/ directory at the repo root, with domains that map to packages, services, or product areas. I would start there unless you have a strong reason not to.

repo/
+-- apps/
+-- packages/
+-- services/
+-- openspec/
    +-- specs/
        +-- checkout/
        +-- auth/
        +-- billing/
    +-- changes/

For multi-repo work, OpenSpec’s beta stores feature is the relevant research thread. The docs describe a store as a standalone OpenSpec repo whose job is planning. Code repos can reference a store, and openspec context can assemble the current root plus referenced stores. Worksets are different: they are personal, machine-local views that open a planning root together with the code folders you work on. The docs explicitly call this beta, so I would treat it as promising but not yet a process you force on every team.

Practical adoption path:

one repo:
  keep openspec/ in the repo

monorepo:
  keep one openspec/ at repo root

multi-repo feature:
  consider a beta store as the planning home
  reference it from code repos
  use local worksets to open planning + code together

That lets teams keep the product decision in one place without pretending one agent should edit every repo in one giant session.

Using Worktrees And Assigned Apply Subagents

Git worktrees are the clean isolation primitive for parallel agent work. The Git docs describe git worktree as managing multiple working trees attached to the same repository, allowing more than one branch to be checked out at a time.

That maps well to OpenSpec because OpenSpec changes are already folder-scoped units of work.

coordinator chat
  |
  +-- worktree A: feature/add-order-idempotency
  |     subagent A applies openspec/changes/add-order-idempotency
  |
  +-- worktree B: feature/add-checkout-risk-dashboard
  |     subagent B applies openspec/changes/add-checkout-risk-dashboard
  |
  +-- worktree C: fix/checkout-copy
        subagent C applies openspec/changes/fix-checkout-copy

The safest pattern is one OpenSpec change per subagent:

one subagent
  -> one worktree
  -> one branch
  -> one OpenSpec change
  -> one PR

Example setup:

git fetch origin

git worktree add -b feature/add-order-idempotency \
  ../repo-add-order-idempotency origin/main

git worktree add -b feature/add-checkout-risk-dashboard \
  ../repo-add-checkout-risk-dashboard origin/main

Then assign each implementation agent a bounded prompt:

You are implementing exactly one OpenSpec change.

Repository:
  ../repo-add-order-idempotency

Change:
  openspec/changes/add-order-idempotency/

Workflow:
  1. Read proposal.md, design.md, tasks.md, and delta specs.
  2. Run /opsx:apply add-order-idempotency.
  3. Update tasks.md as you complete work.
  4. If implementation changes behavior, update the delta spec.
  5. Run the checks listed in tasks.md.
  6. Do not archive. Archive happens only after the PR is merged.
  7. Return a summary with changed files, tests run, and unresolved risks.

The coordinator keeps the merge discipline:

subagent applies change in isolated worktree
  -> subagent opens or prepares PR
  -> coordinator reviews artifact drift
  -> CI and human review run
  -> PR merges
  -> coordinator archives accepted change

This prevents two common agent failures:

  • Two agents editing the same working tree and overwriting each other.
  • One agent archiving specs before another agent’s PR has actually merged.

For complex features, use subagents for implementation slices, not for product authority. The owner should still decide whether discoveries update the current OpenSpec change or become a sibling change.

subagent can decide:
  "I found a missing test task"

owner should decide:
  "This is a new product requirement"

That keeps the team in control while still getting the speed benefit of parallel agent execution.

Why Archive Only After Merging The PR?

This is the question that matters most.

OpenSpec’s docs say openspec/specs/ is the source of truth for how the system currently behaves. They also say archiving merges delta specs into that source of truth and moves the change folder into the archive.

If a PR is still open, the system does not yet behave that way on main.

So if you archive before merge, you can create this drift:

main branch specs:
  "Checkout prevents duplicate orders"

main branch code:
  old checkout path without idempotency

open PR:
  code that would make the spec true, but has not merged

That is exactly the kind of confusion specs are supposed to prevent.

In a PR-based workflow, archive after merge because:

  • The main specs should describe merged reality, not pending intent.
  • Rejected or heavily changed PRs should not pollute openspec/specs/.
  • Rollback is cleaner when archived specs correspond to shipped commits.
  • Reviewers can still inspect active change artifacts while the PR is open.
  • The archive becomes an audit trail of completed work, not abandoned attempts.

There are exceptions. A solo project may archive before merge because branch and main are effectively the same decision boundary. A long-running change may use /opsx:sync before archive if multiple changes need updated base specs. But for teams, “merge first, archive second” is the cleaner default.

The policy version:

Before merge:
  openspec/changes/<change>/ describes proposed behavior

After merge:
  /opsx:archive promotes accepted behavior into openspec/specs/

What About /opsx:sync Before Archive?

OpenSpec includes /opsx:sync in the default profile. The command reference describes it as merging delta specs into main specs while leaving the change active. Archive can prompt to sync if needed.

I would use manual sync sparingly:

Use /opsx:sync when:
  - a long-running change needs main specs updated before archive
  - parallel changes need the updated spec base
  - reviewers want to inspect the spec merge separately

Skip manual sync when:
  - the PR is small
  - archive will happen right after merge
  - syncing would make main specs describe unmerged behavior

For most teams, the simpler flow is:

PR open:
  active change remains under openspec/changes/

PR merged:
  run /opsx:archive, accept sync prompt, commit/archive as needed

Depending on your repo policy, the archive commit can be:

  • a tiny follow-up PR after merge
  • a bot-maintained PR
  • part of a merge queue process
  • a post-merge maintenance commit in a trunk-based solo repo

The key is that the archive happens when the behavior is accepted, not while it is still speculative.

A Practical PR-To-Archive Checklist

Here is the complete checklist I would use for a feature:

## OpenSpec Delivery Checklist

### Exploration
- [ ] Explore problem and alternatives with `/opsx:explore`
- [ ] Decide the smallest useful scope

### Branch And Proposal
- [ ] Create feature branch
- [ ] Run `/opsx:propose <change-id>`
- [ ] Review `proposal.md` with PM/product owner
- [ ] Review delta specs for observable behavior and acceptance scenarios
- [ ] If the proposal generated many spec deltas, decide whether it should split into smaller changes
- [ ] Review `design.md` with engineering owner
- [ ] Add quality gates to `tasks.md`
- [ ] Decide whether this is single-repo, monorepo, or multi-repo planning
- [ ] For multi-repo work, decide whether a beta OpenSpec store/workset is useful

### Implementation
- [ ] Run `/opsx:apply <change-id>`
- [ ] Update proposal/spec/design/tasks if implementation discovers drift
- [ ] Keep tasks checked off as evidence is produced
- [ ] If using subagents, assign one change per worktree and branch
- [ ] Make archive off-limits to implementation subagents until after merge

### Verification
- [ ] Run `openspec validate <change-id>`
- [ ] Run lint/typecheck/build commands
- [ ] Run relevant unit/integration tests
- [ ] Run Playwright e2e, headed when human inspection is needed
- [ ] Run `/opsx:verify <change-id>` if available
- [ ] Fix or explicitly accept verification warnings

### PR
- [ ] Open PR with OpenSpec change path in the description
- [ ] Resolve product, engineering, QA, security, and review comments
- [ ] Update artifacts when comments change behavior or design
- [ ] Re-run affected checks

### Merge And Archive
- [ ] Merge PR
- [ ] Run `/opsx:archive <change-id>`
- [ ] Confirm delta specs are synced into `openspec/specs/`
- [ ] Preserve archive under `openspec/changes/archive/`

The checklist is intentionally boring. Boring is good here. It means people can repeat it.

Example: Adding A Checkout Idempotency Change

Here is what the flow looks like in a realistic chat.

You: /opsx:explore

We have occasional duplicate orders. Please inspect checkout, payment
webhooks, and client submit behavior. I want the smallest safe fix.

AI:
  Found two duplicate paths:
  1. client double-submit
  2. payment webhook retry

  The webhook retry is higher risk.
  Recommended first change: idempotency around order creation keyed by
  payment intent id.

Create the branch:

git checkout -b feature/add-order-idempotency

Create the change:

You: /opsx:propose add-order-idempotency

Review the artifacts. Then implement:

You: /opsx:apply add-order-idempotency

During implementation, suppose the agent discovers the existing database cannot add a unique constraint without a short migration. Do not hide that in code. Update the artifacts:

Update design.md:
  - document the migration approach
  - document rollback
  - explain why application-level retry is still needed

Update tasks.md:
  - add migration test
  - add rollback note
  - add Playwright checkout verification

Then verify:

openspec validate add-order-idempotency
npm run lint
npm run build
npx playwright test --headed

Open the PR. Merge it. Then archive:

You: /opsx:archive add-order-idempotency

At the end, your repository tells the full story:

git history:
  implementation and review trail

openspec/changes/archive/:
  why this change existed and how it was delivered

openspec/specs/:
  current behavior after the merge

Common Failure Modes

Archiving Too Early

Symptom:

specs say behavior exists, but code is still in an open PR

Fix:

keep the change active until PR merge

Treating tasks.md As A Generated Artifact Only

Symptom:

tasks are checked, but tests, review, and e2e were never tracked

Fix:

add quality gates as first-class tasks before apply finishes

Creating One Mega Change

Symptom:

proposal says "checkout idempotency"
PR also adds admin dashboard, logging redesign, and payment retry UI

Fix:

split into sibling OpenSpec changes and usually separate branches

One Proposal Became A Forever Branch

Symptom:

one proposal touches five specs
three teams depend on it
the PR stays open for weeks
main specs keep changing underneath it

Fix:

turn the large proposal into an umbrella decision
ship smaller spec-backed slices one by one
archive each accepted slice before starting dependent slices

The goal is not to delete the big idea. The goal is to stop treating the big idea as one implementation unit.

Updating Code But Not Specs

Symptom:

implementation behavior changed during review, but delta specs still
describe the old behavior

Fix:

update delta specs before archive, because archive promotes specs into truth

Proposal And Apply Diverged Into The Wrong Thing

Symptom:

proposal says "add checkout idempotency"
apply produced "rewrite checkout orchestration"
team does not want the broader result

Fix:

stop before archive
decide whether the proposal is wrong, the implementation is wrong, or both

OpenSpec’s editing docs say artifacts are plain Markdown and can be edited at any time. Use that deliberately:

same intent, bad implementation:
  keep proposal/specs/design
  update tasks.md with the correction
  replace or revise the code until it matches the artifacts

same intent, better discovered approach:
  amend design.md and tasks.md
  update delta specs if behavior changed
  run /opsx:apply again against the amended artifacts

intent changed or scope exploded:
  stop the current PR
  create a new OpenSpec change and usually a new branch
  do not archive the abandoned change as completed behavior

The mistake is trying to “fix” the story only in the PR description. The source of truth before archive is the active change folder. If the final code is not what you want, either make the code match the current artifacts or make the artifacts honestly describe the wanted final behavior. If neither is true, start over with a cleaner change.

New Change Conflicts With Old Specs

Symptom:

new change is correct, but openspec/specs/ still describes old behavior
or
delta spec modifies a requirement that has drifted since the change began

Fix:

reconcile the canonical spec before archive

Treat this as a spec merge problem, not a prompting problem.

1. Read the current canonical spec under openspec/specs/<domain>/spec.md.
2. Read any active sibling changes touching the same domain.
3. Decide whether the old spec is stale or the new change is wrong.
4. If the old spec is stale, update it through an explicit delta.
5. If the new change is wrong, amend the active change.
6. Re-run validation and verify before archive.

Be especially careful with MODIFIED Requirements. OpenSpec issue discussions describe MODIFIED as a whole-requirement replacement keyed by requirement name, not a tiny patch. If two changes both modify the same requirement from different starting points, the later archive can overwrite scenarios from the earlier change unless the delta has been reconciled.

My practical rule:

adding a new independent behavior:
  prefer ADDED Requirements

changing an existing behavior:
  use MODIFIED Requirements
  include the full updated requirement and all scenarios you want to keep

removing obsolete behavior:
  use REMOVED Requirements
  explain why in the proposal/design

old spec is simply wrong:
  create a small spec-repair change, or make the repair explicit
  inside the current change if it is required for this PR

Do not archive until the delta is based on the current canonical spec, not on the version you vaguely remember from the start of the branch.

If I were introducing OpenSpec to an engineering team, I would start with these rules:

1. Explore freely before branching.
2. Create a feature branch before proposal.
3. Keep one OpenSpec change per PR unless there is a strong reason.
4. Treat proposal/spec/design/tasks as reviewable source files.
5. Add quality gates to tasks before calling the work done.
6. Run app checks and e2e before PR is ready.
7. Update artifacts when implementation or review changes behavior.
8. Merge PR before archive.
9. Archive only accepted behavior into main specs.
10. For team work, make artifact ownership explicit.
11. For subagent work, use one worktree, one branch, one change, one PR.
12. Keep archive as the coordinator or release-owner responsibility.
13. Split many-spec proposals into reviewable slices before implementation.

The rules are not about ceremony. They are about preventing the most expensive failure in AI-assisted development: a confident implementation with no durable agreement about what changed.

OpenSpec is useful because it keeps that agreement close to the code.

Sources