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:archivein 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.mdso 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
coreprofile 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 fromopenspec/changes/as proposed modifications. - A change folder usually contains
proposal.md,design.md,tasks.md, and delta specs underspecs/. /opsx:exploreis a no-stakes conversation that creates no artifacts and writes no code./opsx:applyworks throughtasks.md, writes code, runs checks as needed, and marks tasks complete./opsx:verifyvalidates implementation against artifacts across completeness, correctness, and coherence. It reports issues but does not block archive./opsx:archivechecks artifacts and tasks, offers to sync delta specs, moves the change intoopenspec/changes/archive/, and preserves artifacts for audit history./opsx:synccan 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-archivecan 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.mdmatch 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.mddescribe 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.
My Recommended Team Policy
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
- Fission-AI/OpenSpec, README
- OpenSpec Docs, Getting Started
- OpenSpec Docs, Explore First
- OpenSpec Docs, Workflows
- OpenSpec Docs, Commands
- OpenSpec Docs, CLI Reference
- OpenSpec Docs, Concepts
- OpenSpec Docs, Editing & Iterating on a Change
- OpenSpec Docs, Using OpenSpec in an Existing Project
- OpenSpec Docs, How Commands Work
- OpenSpec Docs, Supported Tools
- OpenSpec Docs, Glossary
- Fission-AI/OpenSpec, Issue #1112: validate MODIFIED/REMOVED/RENAMED headers against base specs
- Fission-AI/OpenSpec, Issue #1246: archiving two changes that modify the same requirement can drop scenarios
- Git, git-worktree Documentation