Skip to content

Commit 5a5429e

Browse files
committed
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
1 parent d1b2d40 commit 5a5429e

File tree

9 files changed

+71
-87
lines changed

9 files changed

+71
-87
lines changed

.opencode/agents/product-owner.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Load `skill session-workflow` first — it reads TODO.md, orients you to the cur
3333
- You are the **sole owner** of `.feature` files and `docs/features/discovery.md`
3434
- No other agent may edit these files
3535
- 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
3736
- **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
3837

3938
## Step 5 — Accept
@@ -60,4 +59,4 @@ When a gap is reported (by software-engineer or reviewer):
6059

6160
- `session-workflow` — session start/end protocol
6261
- `feature-selection` — when TODO.md is idle: score and select next backlog feature using WSJF
63-
- `scope` — Step 1: 3-session discovery (Phase 1 + 2), stories (Phase 3), and criteria (Phase 4)
62+
- `scope` — Step 1: 3-session discovery (Phase 1 + 2), stories (Phase 3), and criteria (Phase 4)

.opencode/agents/reviewer.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,6 @@ You never edit `.feature` files or add Examples yourself.
5858
## Available Skills
5959

6060
- `session-workflow` — session start/end protocol
61+
- `refactor` — Code refactoring heuristics
62+
- `design-patterns` — Reference for code smell and design patterns
6163
- `verify` — Step 4: full verification protocol with all tables, gates, and report template

.opencode/agents/software-engineer.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ Load `skill session-workflow` first — it reads TODO.md, orients you to the cur
4545

4646
- You own all technical decisions: module structure, patterns, internal APIs, test tooling, linting config
4747
- **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
4948

5049
## Spec Gaps
5150

@@ -61,4 +60,4 @@ If during implementation you discover behavior not covered by existing acceptanc
6160
- `design-patterns` — on-demand when smell detected during architecture or refactor
6261
- `pr-management` — Step 5: PRs with conventional commits
6362
- `git-release` — Step 5: calver versioning and themed release naming
64-
- `create-skill` — meta: create new skills when needed
63+
- `create-skill` — meta: create new skills when needed

.opencode/skills/feature-selection/SKILL.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ Read each `.feature` file in `docs/features/backlog/`. Check its discovery secti
3838
- Non-BASELINED features are not eligible — they need Step 1 (scope) first
3939
- If no BASELINED features exist: inform the stakeholder; run `@product-owner` with `skill scope` to baseline the most promising backlog item first
4040

41+
**IMPORTANT**
42+
43+
**NEVER move a feature to `in-progress/` unless its discovery section has `Status: BASELINED`**
44+
4145
### 3. Score Each Candidate
4246

4347
For each BASELINED feature, fill this table:

.opencode/skills/implementation/SKILL.md

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ Steps 2 (Architecture) and 3 (TDD Loop) combined into a single skill. The softwa
1515

1616
During implementation, correctness priorities are (in order):
1717

18-
1. **Design correctness** — YAGNI > KISS > DRY > SOLID > Object Calisthenics > appropriate design patterns
18+
1. **Design correctness** — YAGNI > KISS > DRY > SOLID > Object Calisthenics > appropriate design patterns > complex code > complicated code > failing code > no code
1919
2. **One @id green** — the specific test under work passes, plus `test-fast` still passes
2020
3. **Commit** — when a meaningful increment is green
2121
4. **Quality tooling**`lint`, `static-check`, full `test` with coverage run at end-of-feature handoff
2222

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.
2424

2525
---
2626

@@ -37,7 +37,7 @@ Design correctness is far more important than lint/pyright/coverage compliance.
3737

3838
1. Read `pyproject.toml` → locate `[tool.setuptools]` → record `packages = ["<name>"]`
3939
2. Confirm directory exists: `ls <name>/`
40-
3. All new source files go under `<name>/` — never under a template placeholder.
40+
3. All new source files go under `<name>/`
4141

4242
### Move Feature File
4343

@@ -118,7 +118,7 @@ Place stubs where responsibility dictates — do not pre-create `ports/` or `ada
118118

119119
### Write ADR Files (significant decisions only)
120120

121-
For each significant architectural decision, create `docs/architecture/adr-NNN-<title>.md`:
121+
For each significant architectural decision, create or append to `docs/architecture/adr.md`:
122122

123123
```markdown
124124
# ADR-NNN: <title>
@@ -153,25 +153,21 @@ Commit: `feat(<feature-name>): add architecture stubs`
153153

154154
### Prerequisites
155155

156+
- [ ] Exactly one .feature `in_progress`. If not present, Load `skill feature-selection`
156157
- [ ] 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
158+
- [ ] Read all `docs/architecture/adr.md` files — understand the architectural decisions before writing any test
159+
- [ ] 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
159160

160161
### Write Test Stubs (if not present)
161162

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:
163+
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:
163164

164165
```python
165166
@pytest.mark.skip(reason="not yet implemented")
166-
def test_<rule_slug>_<8char_hex>() -> None:
167+
def test_<feature_slug>_<@id>() -> None:
167168
"""
168-
Given: ...
169-
When: ...
170-
Then: ...
169+
<@id steps raw text including new lines>
171170
"""
172-
# Given
173-
# When
174-
# Then
175171
```
176172

177173
Run `uv run task gen-todo` after writing stubs to sync `@id` rows into `TODO.md`.
@@ -192,17 +188,17 @@ For each pending `@id`:
192188
```
193189
INNER LOOP
194190
├── RED
195-
│ ├── Confirm stub for this @id exists in tests/features/<feature-name>/ with @pytest.mark.skip
191+
│ ├── Confirm stub for this @id exists in tests/features/<feature-name>/<rule_slug>.feature with @pytest.mark.skip
196192
│ ├── Read existing stubs in `<package>/` — base the test on the current data model and signatures
197193
│ ├── Write test body (Given/When/Then → Arrange/Act/Assert); remove @pytest.mark.skip
198-
│ ├── Update stub signatures as needed — edit the `.py` file directly
194+
│ ├── Update <package> stub signatures as needed — edit the `.py` file directly
199195
│ ├── uv run task test-fast
200196
│ └── EXIT: this @id FAILS
201197
│ (if it passes: test is wrong — fix it first)
202198
203199
├── GREEN
204200
│ ├── Write minimum code — YAGNI + KISS only
205-
│ │ (no DRY, SOLID, OC here — those belong in REFACTOR)
201+
│ │ (no DRY, SOLID, OC, Docstring, type hint here — those belong in REFACTOR)
206202
│ ├── uv run task test-fast
207203
│ └── EXIT: this @id passes AND all prior tests pass
208204
│ (fix implementation only; do not advance to next @id)
@@ -221,7 +217,7 @@ Commit when a meaningful increment is green
221217
```bash
222218
uv run task lint
223219
uv run task static-check
224-
uv run task test # coverage must be 100%
220+
uv run task test-coverage # coverage must be 100%
225221
timeout 10s uv run task run
226222
```
227223

@@ -231,7 +227,7 @@ All must pass before Self-Declaration.
231227

232228
### Self-Declaration (once, after all quality gates pass)
233229

234-
Write into `TODO.md` under a `## Self-Declaration` block:
230+
Answer honestly the `## Self-Declaration` report:
235231

236232
```markdown
237233
## Self-Declaration
@@ -256,6 +252,7 @@ As a software-engineer I declare:
256252
* OC-7: ≤20 lines per function, ≤50 per class — AGREE/DISAGREE | longest: file:line
257253
* OC-8: ≤2 instance variables per class (behavioural classes only; dataclasses, Pydantic models, value objects, and TypedDicts are exempt) — AGREE/DISAGREE | file:line
258254
* OC-9: no getters/setters — AGREE/DISAGREE | file:line
255+
* Patterns: I have no good reason to refactor parts of the code using OOP or Design Patterns — AGREE/DISAGREE | file:line
259256
* Patterns: no creational smell — AGREE/DISAGREE | file:line
260257
* Patterns: no structural smell — AGREE/DISAGREE | file:line
261258
* Patterns: no behavioral smell — AGREE/DISAGREE | file:line
@@ -268,7 +265,7 @@ A `DISAGREE` answer is not automatic rejection — state the reason inline and f
268265

269266
Signal completion to the reviewer. Provide:
270267
- Feature file path
271-
- Self-Declaration from TODO.md
268+
- Self-Declaration report
272269
- Summary of what was implemented
273270

274271
---
@@ -278,40 +275,35 @@ Signal completion to the reviewer. Provide:
278275
### Test File Layout
279276

280277
```
281-
tests/features/<feature-name>/<rule-slug>_test.py
278+
tests/features/<feature-name>/<rule_slug>_test.py
282279
```
283280

284281
- `<feature-name>` = the `.feature` file stem
285-
- `<rule-slug>` = the `Rule:` title slugified
282+
- `<rule_slug>` = the `Rule:` title slugified
286283

287284
### Function Naming
288285

289286
```python
290-
def test_<rule_slug>_<8char_hex>() -> None:
287+
def test_<rule_slug>_<@id>() -> None:
291288
```
292289

293290
- `rule_slug` = the `Rule:` title with spaces/hyphens replaced by underscores, lowercase
294-
- `8char_hex` = the `@id` from the `Example:` block
291+
- `@id` = the `@id` from the `Example:` block
295292

296293
### Docstring Format (mandatory)
297294

298295
New tests start as skipped stubs. Remove `@pytest.mark.skip` when implementing in the RED phase.
299296

300297
```python
301298
@pytest.mark.skip(reason="not yet implemented")
302-
def test_wall_bounce_a3f2b1c4() -> None:
299+
def test_<feature_slug>_<@id>() -> None:
303300
"""
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
301+
<@id steps raw text including new lines>
307302
"""
308-
# Given
309-
# When
310-
# Then
311303
```
312304

313305
**Rules**:
314-
- Docstring contains `Given:/When:/Then:` on separate indented lines
306+
- Docstring contains `Gherkin steps` as raw text on separate indented lines
315307
- No extra metadata in docstring — traceability comes from function name `@id` suffix
316308

317309
### Markers
@@ -320,6 +312,7 @@ def test_wall_bounce_a3f2b1c4() -> None:
320312
- `@pytest.mark.deprecated` — auto-skipped by conftest; used for superseded Examples
321313

322314
```python
315+
@pytest.mark.deprecated
323316
def test_wall_bounce_a3f2b1c4() -> None:
324317
...
325318

@@ -350,11 +343,11 @@ def test_wall_bounce_c4d5e6f7(x: float) -> None:
350343
**Rules**:
351344
- `@pytest.mark.slow` is mandatory on every `@given`-decorated test
352345
- `@example(...)` is optional but encouraged
353-
- Never use Hypothesis for: I/O, side effects, network calls, database writes
346+
- Do not use Hypothesis for: I/O, side effects, network calls, database writes
354347

355348
### Semantic Alignment Rule
356349

357-
The test's Given/When/Then must operate at the **same abstraction level** as the AC's Given/When/Then.
350+
The test's Given/When/Then must operate at the **same abstraction level** as the AC's Steps.
358351

359352
| AC says | Test must do |
360353
|---|---|
@@ -369,7 +362,7 @@ If testing through the real entry point is infeasible, escalate to PO to adjust
369362
- No `isinstance()`, `type()`, or internal attribute (`_x`) checks in assertions
370363
- One assertion concept per test (multiple `assert` ok if they verify the same thing)
371364
- No `pytest.mark.xfail` without written justification
372-
- `pytest.mark.skip` is only valid on stubs (`reason="not yet implemented"`) — remove it when implementing
365+
- `pytest.mark.skip(reason="not yet implemented")` is only valid on stubs — remove it when implementing
373366
- Test data embedded directly in the test, not loaded from external files
374367

375368
### Test Tool Decision
@@ -396,7 +389,7 @@ Extra tests in `tests/unit/` are allowed freely (coverage, edge cases, etc.) —
396389

397390
## Signature Design
398391

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.
392+
<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.
400393

401394
Key rules:
402395
- Bodies are always `...` in the architecture stub
@@ -420,4 +413,4 @@ class EmailAddress:
420413
class UserRepository(Protocol):
421414
def save(self, user: "User") -> None: ...
422415
def find_by_email(self, email: EmailAddress) -> "User | None": ...
423-
```
416+
```

.opencode/skills/scope/SKILL.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,7 @@ Commit: `feat(discovery): baseline project discovery`
149149

150150
1. Write the **Session 1 Synthesis** in the `.feature` file: summarize the key entities, their relationships, and the constraints that emerged.
151151
2. Present the synthesis to the stakeholder. Stakeholder confirms or corrects. PO refines until approved.
152-
3. Run a **silent pre-mortem** on the confirmed synthesis.
153-
4. Mark `Template §1: CONFIRMED`. This unlocks Session 2.
152+
3. Mark `Template §1: CONFIRMED`. This unlocks Session 2.
154153

155154
### Session 2 — Behavior Groups / Big Picture for This Feature
156155

AGENTS.md

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ docs/features/
9090
completed/<feature-name>.feature ← file moves here at Step 5
9191
9292
docs/architecture/
93-
STEP2-ARCH.md ← Step 2 reference diagram (canonical)
94-
adr-NNN-<title>.md ← one per significant architectural decision
93+
adr.md ← one per significant architectural decision
9594
9695
tests/
9796
features/<feature-name>/
@@ -112,25 +111,14 @@ Tests in `tests/unit/` are software-engineer-authored extras not covered by any
112111
tests/features/<feature-name>/<rule_slug>_test.py
113112
```
114113

115-
### Function Naming
116-
117-
```python
118-
def test_<rule_slug>_<8char_hex>() -> None:
119-
```
120-
121-
### Docstring Format (mandatory)
114+
### Stub Format (mandatory)
122115

123116
```python
124117
@pytest.mark.skip(reason="not yet implemented")
125-
def test_wall_bounce_a3f2b1c4() -> None:
118+
def test_<feature_slug>_<@id>() -> None:
126119
"""
127-
Given: A ball moving upward reaches y=0
128-
When: The physics engine processes the next frame
129-
Then: The ball velocity y-component becomes positive
120+
<@id steps raw text including new lines>
130121
"""
131-
# Given
132-
# When
133-
# Then
134122
```
135123

136124
### Markers
@@ -155,41 +143,39 @@ uv run task test-fast
155143
# Run full test suite with coverage
156144
uv run task test
157145

158-
# Run slow tests only
159-
uv run task test-slow
146+
# Run tests with coverage report generation
147+
uv run task test-build
160148

161149
# Lint and format
162150
uv run task lint
163151

164152
# Type checking
165153
uv run task static-check
166154

167-
# Serve documentation
168-
uv run task doc-serve
155+
# Build documentation
156+
uv run task doc-build
169157
```
170158

171159
## Code Quality Standards
172160

173-
- **Principles (in priority order)**: YAGNI > KISS > DRY > SOLID > Object Calisthenics
174-
- **Linting**: ruff, Google docstring convention, `noqa` forbidden
161+
- **Principles (in priority order)**: YAGNI > KISS > DRY > SOLID > Object Calisthenics > appropriate design patterns > complex code > complicate code > failing code > no code
162+
- **Linting**: ruff format, ruff check, Google docstring convention, `noqa` forbidden
175163
- **Type checking**: pyright, 0 errors required
176164
- **Coverage**: 100% (measured against your actual package)
177-
- **Function length**: ≤ 20 lines
178-
- **Class length**: ≤ 50 lines
165+
- **Function length**: ≤ 20 lines (code lines only, excluding docstrings)
166+
- **Class length**: ≤ 50 lines (code lines only, excluding docstrings)
179167
- **Max nesting**: 2 levels
180168
- **Instance variables**: ≤ 2 per class *(exception: dataclasses, Pydantic models, value objects, and TypedDicts are exempt — they may carry as many fields as the domain requires)*
181169
- **Semantic alignment**: tests must operate at the same abstraction level as the acceptance criteria they cover
182-
- **Integration tests**: multi-component features require at least one test in `tests/features/` that exercises the public entry point end-to-end
183170

184171
### Software-Engineer Quality Gate Priority Order
185172

186173
During Step 3 (TDD Loop), correctness priorities are:
187174

188-
1. **Design correctness** — YAGNI > KISS > DRY > SOLID > Object Calisthenics > appropriate design patterns
175+
1. **Design correctness** — YAGNI > KISS > DRY > SOLID > Object Calisthenics > appropriated design patterns > complex code > complicated code > failing code > no code
189176
2. **One test green** — the specific test under work passes, plus `test-fast` still passes
190-
3. **Reviewer code-design check** — reviewer verifies design + semantic alignment (no lint/pyright/coverage)
191-
4. **Commit** — only after reviewer APPROVED
192-
5. **Quality tooling**`lint`, `static-check`, full `test` with coverage run only at software-engineer handoff (before Step 5)
177+
3. **Reviewer code-design check** — reviewer verifies design + semantic alignment (no lint/pyright/coverage yet)
178+
5. **Quality tooling**`lint`, `static-check`, full `test` with coverage run only at software-engineer handoff (before Step 4)
193179

194180
Design correctness is far more important than lint/pyright/coverage compliance. A well-designed codebase with minor lint issues is better than a lint-clean codebase with poor design.
195181

@@ -200,10 +186,6 @@ Design correctness is far more important than lint/pyright/coverage compliance.
200186
- Both are required. All-green automated checks are necessary but not sufficient for APPROVED.
201187
- Reviewer defaults to REJECTED unless correctness is proven.
202188

203-
## Deprecation Process
204-
205-
This template does not support deprecation. Criteria changes are handled by adding new Examples with new `@id` tags.
206-
207189
## Release Management
208190

209191
Version format: `v{major}.{minor}.{YYYYMMDD}`
@@ -212,13 +194,13 @@ Version format: `v{major}.{minor}.{YYYYMMDD}`
212194
- Same-day second release: increment minor, keep same date
213195
- Each release gets a unique adjective-animal name
214196

215-
Use `@software-engineer /skill git-release` for the full release process.
197+
Use `@software-engineer /skill git-release` for the full release process. When requested by the stakeholder
216198

217199
## Session Management
218200

219201
Every session: load `skill session-workflow`. Read `TODO.md` first, update it at the end.
220202

221-
`TODO.md` is a session bookmark — not a project journal. See `docs/workflow.md` for the full structure including the Cycle State and Self-Declaration blocks used during Step 4.
203+
`TODO.md` is a session bookmark — not a project journal. See `docs/workflow.md` for the full structure including the Cycle State and Self-Declaration blocks used during Step 3.
222204

223205
## Setup
224206

0 commit comments

Comments
 (0)