You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
chore(workflow): refine agents, skills, commands, and ADR structure for v5 (#70)
* chore(workflow): refine agents, skills, commands, and ADR structure for v5
- Consolidate ADR files into single adr.md (drop adr-NNN-<title>.md pattern)
- Add test-coverage and test-build tasks; fix test-fast/test flags
- Clarify design priority chain with full complexity ladder
- Remove self-selection language from agent instructions
- Add refactor and design-patterns skills to reviewer agent
- Add BASELINED guard to feature-selection skill
- Fix scope skill: drop silent pre-mortem requirement from Session 1
- Align function/class line-count wording to code-lines-only
* chore(workflow): document model v6 — 2-stage discovery, PO-owned feature moves, unified session protocol
- Split docs/discovery.md into three append-only files:
docs/discovery_journal.md (raw Q&A), docs/discovery.md (synthesis),
docs/architecture.md (architectural decisions)
- Remove docs/features/discovery.md (superseded)
- Replace Phase 1/Phase 2 model with 2-stage model: Stage 1 Discovery
(unified iterative sessions) + Stage 2 Specification (stories + criteria)
- PO is sole owner of all .feature file moves; SE and reviewer never move
or edit .feature files; explicit escalation when no in-progress feature
- Add bug handling protocol: PO adds @bug@id, SE writes both @id test
and @given Hypothesis property test
- Add real-time split rule: >2 concerns or >8 Examples splits immediately
within the same session
- Add session status markers to discovery_journal.md: IN-PROGRESS/COMPLETE
- Update all agent files, skills, workflow docs, and research docs to match
|**Step 5 — ACCEPT**| See acceptance protocol below |
30
30
31
31
## Ownership Rules
32
32
33
-
- You are the **sole owner** of `.feature` filesand `docs/features/discovery.md`
33
+
- You are the **sole owner** of `.feature` files, `docs/discovery_journal.md`, and `docs/discovery.md`
34
34
- No other agent may edit these files
35
+
-**You are the sole owner of all `.feature` file moves**: backlog → in-progress (before Step 2) and in-progress → completed (after Step 5 acceptance). No other agent moves `.feature` files.
35
36
- Software-engineer escalates spec gaps to you; you decide whether to extend criteria
36
-
-**You pick** the next feature from backlog — the software-engineer never self-selects
37
-
-**NEVER move a feature to `in-progress/` unless its discovery section has `Status: BASELINED`** — if not baselined, complete Step 1 (Phase 2 + 3 + 4) first
37
+
-**NEVER move a feature to `in-progress/` unless its `.feature` file has `Status: BASELINED`** — if not baselined, complete Step 1 (Stage 1 Discovery + Stage 2 Specification) first
38
38
39
39
## Step 5 — Accept
40
40
@@ -56,8 +56,17 @@ When a gap is reported (by software-engineer or reviewer):
56
56
| Behavior contradicts an existing Example | Write a new Example with new `@id`. |
57
57
| Post-merge defect | Move the `.feature` file back to `in-progress/`, add new Example with `@id`, resume at Step 3. |
58
58
59
+
## Bug Handling
60
+
61
+
When a defect is reported against any feature:
62
+
63
+
1. Add a `@bug @id:<new-8-char-hex>` Example to the relevant `Rule:` block in the `.feature` file.
64
+
2. Write the Example using the standard `Given/When/Then` format describing the correct behavior.
65
+
3. Update TODO.md to note the new `@id` for the SE to implement.
66
+
4. SE implements the `@id` test in `tests/features/`**and** a `@given` Hypothesis property test in `tests/unit/`. Both are required.
67
+
59
68
## Available Skills
60
69
61
70
-`session-workflow` — session start/end protocol
62
71
-`feature-selection` — when TODO.md is idle: score and select next backlog feature using WSJF
Copy file name to clipboardExpand all lines: .opencode/agents/reviewer.md
+10Lines changed: 10 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -42,6 +42,14 @@ Load `skill session-workflow` first. Then load `skill verify` for Step 4 verific
42
42
-**Never suggest `noqa`, `type: ignore`, or `pytest.skip` as a fix.** These are bypasses, not solutions.
43
43
-**Report specific locations.** "`physics/engine.py:47`: unreachable return" not "there is dead code."
44
44
-**Every PASS/FAIL cell must have evidence.** Empty evidence = UNCHECKED = REJECTED.
45
+
-**Never move `.feature` files.** The PO is the sole owner of all feature file moves. After producing an APPROVED report, update TODO.md and stop — the PO accepts and moves the file.
46
+
47
+
## After APPROVED
48
+
49
+
When your report verdict is APPROVED:
50
+
1. Write the report as described in `skill verify`.
Copy file name to clipboardExpand all lines: .opencode/agents/software-engineer.md
+9-2Lines changed: 9 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -45,7 +45,14 @@ Load `skill session-workflow` first — it reads TODO.md, orients you to the cur
45
45
46
46
- You own all technical decisions: module structure, patterns, internal APIs, test tooling, linting config
47
47
-**PO approves**: new runtime dependencies, changed entry points, scope changes
48
-
- You are **never** the one to pick the next feature — only the PO picks from backlog
48
+
-**You never move `.feature` files.** The PO is the sole owner of all feature file moves (backlog → in-progress → completed). If you find no `.feature` file in `docs/features/in-progress/`, **STOP** — do not self-select a feature. Write the gap in TODO.md and escalate to PO.
49
+
50
+
## No In-Progress Feature
51
+
52
+
If `docs/features/in-progress/` contains only `.gitkeep` (no `.feature` file):
53
+
1. Do not pick a feature from backlog yourself.
54
+
2. Update TODO.md: `Next: Run @product-owner — load skill feature-selection and pick the next BASELINED feature from backlog.`
55
+
3. Stop. The PO must move the chosen feature into `in-progress/` before you can begin Step 2.
49
56
50
57
## Spec Gaps
51
58
@@ -61,4 +68,4 @@ If during implementation you discover behavior not covered by existing acceptanc
61
68
-`design-patterns` — on-demand when smell detected during architecture or refactor
62
69
-`pr-management` — Step 5: PRs with conventional commits
63
70
-`git-release` — Step 5: calver versioning and themed release naming
64
-
-`create-skill` — meta: create new skills when needed
71
+
-`create-skill` — meta: create new skills when needed
Copy file name to clipboardExpand all lines: .opencode/skills/feature-selection/SKILL.md
+5-1Lines changed: 5 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,6 +38,10 @@ Read each `.feature` file in `docs/features/backlog/`. Check its discovery secti
38
38
- Non-BASELINED features are not eligible — they need Step 1 (scope) first
39
39
- If no BASELINED features exist: inform the stakeholder; run `@product-owner` with `skill scope` to baseline the most promising backlog item first
40
40
41
+
**IMPORTANT**
42
+
43
+
**NEVER move a feature to `in-progress/` unless its discovery section has `Status: BASELINED`**
44
+
41
45
### 3. Score Each Candidate
42
46
43
47
For each BASELINED feature, fill this table:
@@ -96,7 +100,7 @@ Run @<agent-name> — <first concrete action for this feature>
96
100
```
97
101
98
102
- If the feature has no `Rule:` blocks yet → Step 1 (SCOPE): `Run @product-owner — load skill scope and write stories`
99
-
- If the feature has `Rule:` blocks but no `@id` Examples → Step 1 Phase 4 (Criteria): `Run @product-owner — load skill scope and write acceptance criteria`
103
+
- If the feature has `Rule:` blocks but no `@id` Examples → Step 1 Stage 2 Step B (Criteria): `Run @product-owner — load skill scope and write acceptance criteria`
100
104
- If the feature has `@id` Examples → Step 2 (ARCH): `Run @software-engineer — load skill implementation and write architecture stubs`
2.**One @id green** — the specific test under work passes, plus `test-fast` still passes
20
20
3.**Commit** — when a meaningful increment is green
21
21
4.**Quality tooling** — `lint`, `static-check`, full `test` with coverage run at end-of-feature handoff
22
22
23
-
Design correctness is far more important than lint/pyright/coverage compliance. Never run lint, static-check, or coverage during the TDD loop — those are handoff-only checks.
23
+
Design correctness is far more important than lint/pyright/coverage compliance. Never run lint (ruff check, ruff format), static-check (pyright), or coverage during the TDD loop — those are handoff-only checks.
24
24
25
25
---
26
26
27
27
## Step 2 — Architecture
28
28
29
29
### Prerequisites (stop if any fail — escalate to PO)
30
30
31
-
1.`docs/features/in-progress/` contains only `.gitkeep` (no `.feature` files). If another `.feature` file exists, **STOP** — another feature is already in progress.
31
+
1.`docs/features/in-progress/` contains exactly one `.feature` file (not just `.gitkeep`). If none exists, **STOP** — update TODO.md `Next:` to `Run @product-owner — move the chosen feature to in-progress/` and stop. Never self-select or move a feature yourself.
32
32
2. The feature file's discovery section has `Status: BASELINED`. If not, escalate to PO — Step 1 is incomplete.
33
33
3. The feature file contains `Rule:` blocks with `Example:` blocks and `@id` tags. If not, escalate to PO — criteria have not been written.
34
34
4. Package name confirmed: read `pyproject.toml` → locate `[tool.setuptools]` → confirm directory exists on disk.
@@ -37,26 +37,20 @@ Design correctness is far more important than lint/pyright/coverage compliance.
Update `TODO.md` Source path from `backlog/` to `in-progress/`.
42
+
**Note on feature file moves**: The PO moves `.feature` files between folders. The software-engineer never moves or edits `.feature` files. Update TODO.md `Source:` path to reflect `in-progress/` once the PO has moved the file.
4. Read **ALL** existing `.py` files in `<package>/` — understand what already exists before adding anything
56
50
57
51
### Domain Analysis
58
52
59
-
From Entities table + Rules (Business) in `.feature` file:
53
+
From the Domain Model table in `docs/discovery.md`+ Rules (Business) in the`.feature` file:
60
54
-**Nouns** → named classes, value objects, aggregates
61
55
-**Verbs** → method names with typed signatures
62
56
-**Datasets** → named types (not bare dict/list)
@@ -116,19 +110,20 @@ class UserRepository(Protocol):
116
110
117
111
Place stubs where responsibility dictates — do not pre-create `ports/` or `adapters/` folders unless a concrete external dependency was identified in scope. Structure follows domain analysis, not a template.
118
112
119
-
### Write ADR Files (significant decisions only)
113
+
### Record Architectural Decisions
120
114
121
-
For each significant architectural decision, create`docs/architecture/adr-NNN-<title>.md`:
115
+
Append a new dated block to`docs/architecture.md` for each significant decision:
-[ ] Exactly one .feature `in_progress`. If not present, Load `skill feature-selection`
156
152
-[ ] Architecture stubs present in `<package>/` (committed by Step 2)
157
-
-[ ] Read all `docs/architecture/adr-NNN-*.md`files — understand the architectural decisions before writing any test
158
-
-[ ] Test stub files exist in `tests/features/<feature-name>/` — one file per `Rule:` block, all `@id` functions present with `@pytest.mark.skip`; if missing, write them now before entering RED
153
+
-[ ] Read `docs/architecture.md` — understand all architectural decisions before writing any test
154
+
-[ ] Test stub files exist in `tests/features/<feature-name>/<rule_slug>_test.py` — one file per `Rule:` block, all `@id` stub functions present with `@pytest.mark.skip`; if missing, write them now before entering RED
159
155
160
156
### Write Test Stubs (if not present)
161
157
162
-
For each `Rule:` block in the in-progress `.feature` file, create `tests/features/<feature-name>/<rule-slug>_test.py` if it does not already exist. Write one function per `@id` Example, all skipped:
158
+
For each `Rule:` block in the in-progress `.feature` file, create `tests/features/<feature-name>/<rule_slug>_test.py` if it does not already exist. Write one function per `@id` Example, all skipped:
163
159
164
160
```python
165
161
@pytest.mark.skip(reason="not yet implemented")
166
-
def test_<rule_slug>_<8char_hex>() ->None:
162
+
def test_<feature_slug>_<@id>() ->None:
167
163
"""
168
-
Given: ...
169
-
When: ...
170
-
Then: ...
164
+
<@id steps raw text including new lines>
171
165
"""
172
-
# Given
173
-
# When
174
-
# Then
175
166
```
176
167
177
168
Run `uv run task gen-todo` after writing stubs to sync `@id` rows into `TODO.md`.
@@ -192,17 +183,17 @@ For each pending `@id`:
192
183
```
193
184
INNER LOOP
194
185
├── RED
195
-
│ ├── Confirm stub for this @id exists in tests/features/<feature-name>/ with @pytest.mark.skip
186
+
│ ├── Confirm stub for this @id exists in tests/features/<feature-name>/<rule_slug>.feature with @pytest.mark.skip
196
187
│ ├── Read existing stubs in `<package>/` — base the test on the current data model and signatures
197
188
│ ├── Write test body (Given/When/Then → Arrange/Act/Assert); remove @pytest.mark.skip
198
-
│ ├── Update stub signatures as needed — edit the `.py` file directly
189
+
│ ├── Update <package> stub signatures as needed — edit the `.py` file directly
199
190
│ ├── uv run task test-fast
200
191
│ └── EXIT: this @id FAILS
201
192
│ (if it passes: test is wrong — fix it first)
202
193
│
203
194
├── GREEN
204
195
│ ├── Write minimum code — YAGNI + KISS only
205
-
│ │ (no DRY, SOLID, OC here — those belong in REFACTOR)
196
+
│ │ (no DRY, SOLID, OC, Docstring, type hint here — those belong in REFACTOR)
206
197
│ ├── uv run task test-fast
207
198
│ └── EXIT: this @id passes AND all prior tests pass
208
199
│ (fix implementation only; do not advance to next @id)
@@ -221,7 +212,7 @@ Commit when a meaningful increment is green
221
212
```bash
222
213
uv run task lint
223
214
uv run task static-check
224
-
uv run task test# coverage must be 100%
215
+
uv run task test-coverage# coverage must be 100%
225
216
timeout 10s uv run task run
226
217
```
227
218
@@ -231,7 +222,7 @@ All must pass before Self-Declaration.
231
222
232
223
### Self-Declaration (once, after all quality gates pass)
233
224
234
-
Write into `TODO.md` under a `## Self-Declaration`block:
225
+
Answer honestly the `## Self-Declaration`report:
235
226
236
227
```markdown
237
228
## Self-Declaration
@@ -256,6 +247,7 @@ As a software-engineer I declare:
256
247
* OC-7: ≤20 lines per function, ≤50 per class — AGREE/DISAGREE | longest: file:line
257
248
* OC-8: ≤2 instance variables per class (behavioural classes only; dataclasses, Pydantic models, value objects, and TypedDicts are exempt) — AGREE/DISAGREE | file:line
258
249
* OC-9: no getters/setters — AGREE/DISAGREE | file:line
250
+
* Patterns: I have no good reason to refactor parts of the code using OOP or Design Patterns — AGREE/DISAGREE | file:line
259
251
* Patterns: no creational smell — AGREE/DISAGREE | file:line
260
252
* Patterns: no structural smell — AGREE/DISAGREE | file:line
261
253
* Patterns: no behavioral smell — AGREE/DISAGREE | file:line
@@ -268,7 +260,7 @@ A `DISAGREE` answer is not automatic rejection — state the reason inline and f
268
260
269
261
Signal completion to the reviewer. Provide:
270
262
- Feature file path
271
-
- Self-Declaration from TODO.md
263
+
- Self-Declaration report
272
264
- Summary of what was implemented
273
265
274
266
---
@@ -278,40 +270,35 @@ Signal completion to the reviewer. Provide:
278
270
### Test File Layout
279
271
280
272
```
281
-
tests/features/<feature-name>/<rule-slug>_test.py
273
+
tests/features/<feature-name>/<rule_slug>_test.py
282
274
```
283
275
284
276
-`<feature-name>` = the `.feature` file stem
285
-
-`<rule-slug>` = the `Rule:` title slugified
277
+
-`<rule_slug>` = the `Rule:` title slugified
286
278
287
279
### Function Naming
288
280
289
281
```python
290
-
def test_<rule_slug>_<8char_hex>() ->None:
282
+
def test_<feature_slug>_<@id>() ->None:
291
283
```
292
284
293
-
-`rule_slug` = the `Rule:` title with spaces/hyphens replaced by underscores, lowercase
294
-
-`8char_hex` = the `@id` from the `Example:` block
285
+
-`feature_slug` = the `.feature` file stem with spaces/hyphens replaced by underscores, lowercase
286
+
-`@id` = the `@id` from the `Example:` block
295
287
296
288
### Docstring Format (mandatory)
297
289
298
290
New tests start as skipped stubs. Remove `@pytest.mark.skip` when implementing in the RED phase.
299
291
300
292
```python
301
293
@pytest.mark.skip(reason="not yet implemented")
302
-
deftest_wall_bounce_a3f2b1c4() -> None:
294
+
deftest_<feature_slug>_<@id>() ->None:
303
295
"""
304
-
Given: A ball moving upward reaches y=0
305
-
When: The physics engine processes the next frame
306
-
Then: The ball velocity y-component becomes positive
296
+
<@id steps raw text including new lines>
307
297
"""
308
-
# Given
309
-
# When
310
-
# Then
311
298
```
312
299
313
300
**Rules**:
314
-
- Docstring contains `Given:/When:/Then:` on separate indented lines
301
+
- Docstring contains `Gherkin steps` as raw text on separate indented lines
315
302
- No extra metadata in docstring — traceability comes from function name `@id` suffix
-`@pytest.mark.slow` is mandatory on every `@given`-decorated test
352
340
-`@example(...)` is optional but encouraged
353
-
-Never use Hypothesis for: I/O, side effects, network calls, database writes
341
+
-Do not use Hypothesis for: I/O, side effects, network calls, database writes
354
342
355
343
### Semantic Alignment Rule
356
344
357
-
The test's Given/When/Then must operate at the **same abstraction level** as the AC's Given/When/Then.
345
+
The test's Given/When/Then must operate at the **same abstraction level** as the AC's Steps.
358
346
359
347
| AC says | Test must do |
360
348
|---|---|
@@ -369,7 +357,7 @@ If testing through the real entry point is infeasible, escalate to PO to adjust
369
357
- No `isinstance()`, `type()`, or internal attribute (`_x`) checks in assertions
370
358
- One assertion concept per test (multiple `assert` ok if they verify the same thing)
371
359
- No `pytest.mark.xfail` without written justification
372
-
-`pytest.mark.skip` is only valid on stubs (`reason="not yet implemented"`) — remove it when implementing
360
+
-`pytest.mark.skip(reason="not yet implemented")` is only valid on stubs — remove it when implementing
373
361
- Test data embedded directly in the test, not loaded from external files
374
362
375
363
### Test Tool Decision
@@ -396,7 +384,7 @@ Extra tests in `tests/unit/` are allowed freely (coverage, edge cases, etc.) —
396
384
397
385
## Signature Design
398
386
399
-
Signatures are written during Step 2 (Architecture) and refined during Step 3 (RED). They live directly in the package `.py` files — never in the `.feature` file.
387
+
<package> signatures are written during Step 2 (Architecture) and refined during Step 3 (RED). They live directly in the package `.py` files — never in the `.feature` file.
400
388
401
389
Key rules:
402
390
- Bodies are always `...` in the architecture stub
0 commit comments