Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
6052899
feat(discovery): scope example-scaffold — pytest --beehave-sample gen…
nullhack Apr 19, 2026
bdafa43
feat(discovery): rename scaffold → hatch; flag --beehave-hatch replac…
nullhack Apr 19, 2026
e3a7173
feat(criteria): write acceptance criteria for example-hatch
nullhack Apr 19, 2026
442f476
chore: move example-hatch to in-progress, begin Step 2 (Architecture)
nullhack Apr 19, 2026
b7d7fa5
feat(example-hatch): add architecture stubs
nullhack Apr 19, 2026
724df46
chore: add test-coverage task and fix implementation skill quality ga…
nullhack Apr 19, 2026
fe1ae92
feat(example-hatch): implement hatch command — all 16 @id tests green
nullhack Apr 19, 2026
4cdd5ac
chore: step 4 REJECTED for example-hatch — 4 fixes required
nullhack Apr 19, 2026
5890a80
chore(skills): number SE Self-Declaration 1–25 and add completeness c…
nullhack Apr 19, 2026
14c386a
fix(example-hatch): address 4 reviewer findings from REJECTED report
nullhack Apr 19, 2026
1366bfc
chore: step 4 APPROVED for example-hatch — all 4 fixes verified
nullhack Apr 19, 2026
ce19e64
feat(example-hatch): accept feature at Step 5
nullhack Apr 19, 2026
9fd1af2
chore: remove hatch demo artifact from in-progress/
nullhack Apr 19, 2026
14a2956
chore: remove hatch demo artifact from backlog/
nullhack Apr 19, 2026
f8c62a9
chore: remove hatch demo artifact from completed/
nullhack Apr 19, 2026
e0944f3
docs: add beehave-hatch demo section to README
nullhack Apr 19, 2026
c6b7195
chore(release): bump version to v3.1.20260419 — Generative Augochlora
nullhack Apr 19, 2026
b1e98ab
ci: add tag-release workflow — auto-tag on pyproject.toml version bum…
nullhack Apr 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .github/workflows/tag-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Tag Release

on:
push:
branches: [main]
paths: [pyproject.toml]

permissions:
contents: write

jobs:
tag:
name: Create version tag
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout code
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.1

- name: Extract version from pyproject.toml
id: version
run: |
VERSION=$(grep '^version' pyproject.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT"

- name: Check if tag already exists
id: check
run: |
if git ls-remote --tags origin "refs/tags/v${{ steps.version.outputs.version }}" | grep -q .; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi

- name: Create and push tag
if: steps.check.outputs.exists == 'false'
env:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
run: |
git tag "${{ steps.version.outputs.tag }}"
git push origin "${{ steps.version.outputs.tag }}"
echo "Created tag ${{ steps.version.outputs.tag }} at $(git rev-parse HEAD)"

- name: Skip (tag already exists)
if: steps.check.outputs.exists == 'true'
run: echo "Tag ${{ steps.version.outputs.tag }} already exists — skipping."
42 changes: 31 additions & 11 deletions .opencode/skills/git-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,31 @@ git add pyproject.toml CHANGELOG.md uv.lock docs/c4/context.md docs/c4/container
git commit -m "chore(release): bump version to v{version} — {Adjective Genus}"
```

### 8. Create GitHub release
### 8. Open a PR and merge it

Push to a release branch and open a PR against `main`:

```bash
git checkout -b release/v{version}
git push -u origin release/v{version}
gh pr create \
--title "chore(release): v{version} — {Adjective Genus}" \
--body "Version bump to v{version}. Merging this PR will automatically create the tag and trigger PyPI publish."
```

Once the PR is merged to `main`, the `tag-release` CI workflow fires automatically:
- Reads `version` from `pyproject.toml`
- Creates tag `v{version}` at the merge commit
- The `pypi-publish` workflow triggers on the new tag and publishes to PyPI
- The `publish-docs` CI job triggers on the push to `main` and deploys gh-pages

**Do not create the tag manually.** Let CI handle it.

### 9. Create GitHub release

After the tag is created by CI (check Actions to confirm), create the GitHub release pointed at the new tag:

```bash
SHA=$(git rev-parse --short HEAD)
gh release create "v{version}" \
--title "v{version} — {Adjective Genus}" \
--notes "# v{version} — {Adjective Genus}
Expand All @@ -206,24 +227,21 @@ gh release create "v{version}" \
2-3 sentences describing what this release accomplishes and why the genus name fits.

---
**SHA**: \`${SHA}\`"
**SHA**: \`$(git rev-parse --short v{version})\`"
```

### 9. If a hotfix commit follows the release tag
### 10. If the tag was created before the version bump landed on main

If CI fails after the release (e.g. a stale lockfile) and a hotfix commit is pushed, reassign the tag and GitHub release to that commit:
This can happen if CI is triggered by something other than the merge. Reassign the tag:

```bash
# Delete the old tag locally and on remote
git tag -d "v{version}"
git push origin ":refs/tags/v{version}"

# Recreate the tag on the hotfix commit
git tag "v{version}" {hotfix-sha}
# Recreate the tag on the correct commit
git tag "v{version}" {correct-sha}
git push origin "v{version}"

# Update the GitHub release to point to the new tag
gh release edit "v{version}" --target {hotfix-sha}
```

The release notes and title do not need to change — only the target commit moves.
Expand All @@ -240,4 +258,6 @@ The release notes and title do not need to change — only the target commit mov
- [ ] Genus chosen from curated pool (or new entry added to pool with character note)
- [ ] Release notes follow the template format
- [ ] `living-docs` skill run — C4 diagrams and glossary reflect the new feature
- [ ] If a hotfix was pushed after the tag: tag reassigned to hotfix commit
- [ ] PR merged to `main` before creating GitHub release
- [ ] Tag created automatically by `tag-release` CI workflow (verify in Actions)
- [ ] Do NOT create the tag manually
62 changes: 33 additions & 29 deletions .opencode/skills/implementation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ During implementation, correctness priorities are (in order):
1. **Design correctness** — YAGNI > KISS > DRY > SOLID > Object Calisthenics > appropriate design patterns
2. **One @id green** — the specific test under work passes, plus `test-fast` still passes
3. **Commit** — when a meaningful increment is green
4. **Quality tooling** — `lint`, `static-check`, full `test` with coverage run at end-of-feature handoff
4. **Quality tooling** — `lint`, `static-check`, `test-coverage` run only at end-of-feature handoff (after all @id are green)

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.

Expand Down Expand Up @@ -219,43 +219,47 @@ Commit when a meaningful increment is green
```bash
uv run task lint
uv run task static-check
uv run task test # coverage must be 100%
uv run task test-coverage # coverage must be 100%
timeout 10s uv run task run
```

If coverage < 100%: add test in `tests/unit/` for uncovered branch (do NOT add @id tests for coverage).
Only add coverage tests for branches introduced or changed by the current feature. Pre-existing uncovered lines are a separate concern — note them in TODO.md and hand off; do not block on them.

All must pass before Self-Declaration.

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

Communicate verbally to the reviewer. Answer honestly for each principle:

- YAGNI: no code without a failing test — AGREE/DISAGREE | file:line
- YAGNI: no speculative abstractions — AGREE/DISAGREE | file:line
- KISS: simplest solution that passes — AGREE/DISAGREE | file:line
- KISS: no premature optimization — AGREE/DISAGREE | file:line
- DRY: no duplication — AGREE/DISAGREE | file:line
- DRY: no redundant comments — AGREE/DISAGREE | file:line
- SOLID-S: one reason to change per class — AGREE/DISAGREE | file:line
- SOLID-O: open for extension, closed for modification — AGREE/DISAGREE | file:line
- SOLID-L: subtypes substitutable — AGREE/DISAGREE | file:line
- SOLID-I: no forced unused deps — AGREE/DISAGREE | file:line
- SOLID-D: depend on abstractions, not concretions — AGREE/DISAGREE | file:line
- OC-1: one level of indentation per method — AGREE/DISAGREE | deepest: file:line
- OC-2: no else after return — AGREE/DISAGREE | file:line
- OC-3: primitive types wrapped — AGREE/DISAGREE | file:line
- OC-4: first-class collections — AGREE/DISAGREE | file:line
- OC-5: one dot per line — AGREE/DISAGREE | file:line
- OC-6: no abbreviations — AGREE/DISAGREE | file:line
- OC-7: ≤20 lines per function, ≤50 per class — AGREE/DISAGREE | longest: file:line
- OC-8: ≤2 instance variables per class (behavioural classes only; dataclasses, Pydantic models, value objects, and TypedDicts are exempt) — AGREE/DISAGREE | file:line
- OC-9: no getters/setters — AGREE/DISAGREE | file:line
- Patterns: I have no good reason to refactor parts of the code using OOP or Design Patterns — AGREE/DISAGREE | file:line
- Patterns: no creational smell — AGREE/DISAGREE | file:line
- Patterns: no structural smell — AGREE/DISAGREE | file:line
- Patterns: no behavioral smell — AGREE/DISAGREE | file:line
- Semantic: tests operate at same abstraction as AC — AGREE/DISAGREE | file:line
Communicate verbally to the reviewer. Answer honestly for each principle.

**The Self-Declaration has exactly 25 numbered items. Count yours before submitting. Fewer than 25 means you omitted something — find it and add it.**

As a Software Engineer, I declare that:
1. YAGNI: no code without a failing test — AGREE/DISAGREE | file:line
2. YAGNI: no speculative abstractions — AGREE/DISAGREE | file:line
3. KISS: simplest solution that passes — AGREE/DISAGREE | file:line
4. KISS: no premature optimization — AGREE/DISAGREE | file:line
5. DRY: no duplication — AGREE/DISAGREE | file:line
6. DRY: no redundant comments — AGREE/DISAGREE | file:line
7. SOLID-S: one reason to change per class — AGREE/DISAGREE | file:line
8. SOLID-O: open for extension, closed for modification — AGREE/DISAGREE | file:line
9. SOLID-L: subtypes substitutable — AGREE/DISAGREE | file:line
10. SOLID-I: no forced unused deps — AGREE/DISAGREE | file:line
11. SOLID-D: depend on abstractions, not concretions — AGREE/DISAGREE | file:line
12. OC-1: one level of indentation per method — AGREE/DISAGREE | deepest: file:line
13. OC-2: no else after return — AGREE/DISAGREE | file:line
14. OC-3: primitive types wrapped — AGREE/DISAGREE | file:line
15. OC-4: first-class collections — AGREE/DISAGREE | file:line
16. OC-5: one dot per line — AGREE/DISAGREE | file:line
17. OC-6: no abbreviations — AGREE/DISAGREE | file:line
18. OC-7: ≤20 lines per function, ≤50 per class — AGREE/DISAGREE | longest: file:line
19. OC-8: ≤2 instance variables per class (behavioural classes only; dataclasses, Pydantic models, value objects, and TypedDicts are exempt) — AGREE/DISAGREE | file:line
20. OC-9: no getters/setters — AGREE/DISAGREE | file:line
21. Patterns: I have no good reason to refactor parts of the code using OOP or Design Patterns — AGREE/DISAGREE | file:line
22. Patterns: no creational smell — AGREE/DISAGREE | file:line
23. Patterns: no structural smell — AGREE/DISAGREE | file:line
24. Patterns: no behavioral smell — AGREE/DISAGREE | file:line
25. Semantic: tests operate at same abstraction as AC — AGREE/DISAGREE | file:line

A `DISAGREE` answer is not automatic rejection — state the reason and fix before handing off.

Expand Down
23 changes: 12 additions & 11 deletions .opencode/skills/scope/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,17 +283,18 @@ All Rules must have their pre-mortems completed before any Examples are written.

Communicate verbally to the next agent. Every `DISAGREE` is a **hard blocker** — fix before committing. Do not commit until all items are AGREE or have a documented resolution.

- INVEST-I: each Rule is Independent (no hidden ordering or dependency between Rules) — AGREE/DISAGREE | conflict:
- INVEST-V: each Rule delivers Value to a named user — AGREE/DISAGREE | Rule:
- INVEST-S: each Rule is Small enough for one development cycle — AGREE/DISAGREE | Rule:
- INVEST-T: each Rule is Testable (I can write a pass/fail Example for it) — AGREE/DISAGREE | Rule:
- Observable: every Then is a single, observable, measurable outcome — AGREE/DISAGREE | file:line
- No impl details: no Example tests internal state or implementation — AGREE/DISAGREE | file:line
- Coverage: every entity in the feature description appears in at least one Rule — AGREE/DISAGREE | missing:
- Distinct: no two Examples test the same observable behavior — AGREE/DISAGREE | file:line
- Unique IDs: all @id values are unique within this feature — AGREE/DISAGREE
- Pre-mortem: I ran a pre-mortem on each Rule and found no hidden failure modes — AGREE/DISAGREE | Rule:
- Scope: no Example introduces behavior outside the feature boundary — AGREE/DISAGREE | file:line
As a Product Owner, I declare that:
1 INVEST-I: each Rule is Independent (no hidden ordering or dependency between Rules) — AGREE/DISAGREE | conflict:
2 INVEST-V: each Rule delivers Value to a named user — AGREE/DISAGREE | Rule:
3 INVEST-S: each Rule is Small enough for one development cycle — AGREE/DISAGREE | Rule:
4 INVEST-T: each Rule is Testable (I can write a pass/fail Example for it) — AGREE/DISAGREE | Rule:
5 Observable: every Then is a single, observable, measurable outcome — AGREE/DISAGREE | file:line
6 No impl details: no Example tests internal state or implementation — AGREE/DISAGREE | file:line
7 Coverage: every entity in the feature description appears in at least one Rule — AGREE/DISAGREE | missing:
8 Distinct: no two Examples test the same observable behavior — AGREE/DISAGREE | file:line
9 Unique IDs: all @id values are unique within this feature — AGREE/DISAGREE
10 Pre-mortem: I ran a pre-mortem on each Rule and found no hidden failure modes — AGREE/DISAGREE | Rule:
11 Scope: no Example introduces behavior outside the feature boundary — AGREE/DISAGREE | file:line

Commit: `feat(criteria): write acceptance criteria for <name>`

Expand Down
55 changes: 32 additions & 23 deletions .opencode/skills/verify/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ Run before code review. If any row is FAIL, stop immediately with REJECTED.

Read the software-engineer's Self-Declaration from the handoff message.

**Completeness check (do this first):** The Self-Declaration must contain exactly 25 numbered items matching the template in the implementation skill. Count the SE's items. If fewer than 25 are present, issue REJECTED immediately with: "Incomplete Self-Declaration — missing items: [list the missing numbers and their names]." Do not proceed with the audit.

For every **AGREE** claim:
- Find the `file:line` — does it hold?

Expand Down Expand Up @@ -175,29 +177,36 @@ Record what input was given and what output was observed.
| uv run task test | PASS / FAIL | |

### Self-Declaration Audit
| Claim | Software-Engineer Claims | Reviewer Verdict | Evidence |
|------|-------------------------|------------------|----------|
| YAGNI | AGREE/DISAGREE | PASS/FAIL | |
| KISS | AGREE/DISAGREE | PASS/FAIL | |
| DRY | AGREE/DISAGREE | PASS/FAIL | |
| SOLID-S | AGREE/DISAGREE | PASS/FAIL | |
| SOLID-O | AGREE/DISAGREE | PASS/FAIL | |
| SOLID-L | AGREE/DISAGREE | PASS/FAIL | |
| SOLID-I | AGREE/DISAGREE | PASS/FAIL | |
| SOLID-D | AGREE/DISAGREE | PASS/FAIL | |
| OC-1 | AGREE/DISAGREE | PASS/FAIL | |
| OC-2 | AGREE/DISAGREE | PASS/FAIL | |
| OC-3 | AGREE/DISAGREE | PASS/FAIL | |
| OC-4 | AGREE/DISAGREE | PASS/FAIL | |
| OC-5 | AGREE/DISAGREE | PASS/FAIL | |
| OC-6 | AGREE/DISAGREE | PASS/FAIL | |
| OC-7 | AGREE/DISAGREE | PASS/FAIL | |
| OC-8 | AGREE/DISAGREE | PASS/FAIL | |
| OC-9 | AGREE/DISAGREE | PASS/FAIL | |
| Patterns Creational | AGREE/DISAGREE | PASS/FAIL | |
| Patterns Structural | AGREE/DISAGREE | PASS/FAIL | |
| Patterns Behavioral | AGREE/DISAGREE | PASS/FAIL | |
| Semantic | AGREE/DISAGREE | PASS/FAIL | |

Items present: N / 25 — if N < 25, REJECTED (incomplete declaration).

| # | Claim | SE Claims | Reviewer Verdict | Evidence |
|---|-------|-----------|-----------------|----------|
| 1 | YAGNI: no code without a failing test | AGREE/DISAGREE | PASS/FAIL | |
| 2 | YAGNI: no speculative abstractions | AGREE/DISAGREE | PASS/FAIL | |
| 3 | KISS: simplest solution that passes | AGREE/DISAGREE | PASS/FAIL | |
| 4 | KISS: no premature optimization | AGREE/DISAGREE | PASS/FAIL | |
| 5 | DRY: no duplication | AGREE/DISAGREE | PASS/FAIL | |
| 6 | DRY: no redundant comments | AGREE/DISAGREE | PASS/FAIL | |
| 7 | SOLID-S: one reason to change per class | AGREE/DISAGREE | PASS/FAIL | |
| 8 | SOLID-O: open for extension, closed for modification | AGREE/DISAGREE | PASS/FAIL | |
| 9 | SOLID-L: subtypes substitutable | AGREE/DISAGREE | PASS/FAIL | |
| 10 | SOLID-I: no forced unused deps | AGREE/DISAGREE | PASS/FAIL | |
| 11 | SOLID-D: depend on abstractions, not concretions | AGREE/DISAGREE | PASS/FAIL | |
| 12 | OC-1: one level of indentation per method | AGREE/DISAGREE | PASS/FAIL | |
| 13 | OC-2: no else after return | AGREE/DISAGREE | PASS/FAIL | |
| 14 | OC-3: primitive types wrapped | AGREE/DISAGREE | PASS/FAIL | |
| 15 | OC-4: first-class collections | AGREE/DISAGREE | PASS/FAIL | |
| 16 | OC-5: one dot per line | AGREE/DISAGREE | PASS/FAIL | |
| 17 | OC-6: no abbreviations | AGREE/DISAGREE | PASS/FAIL | |
| 18 | OC-7: ≤20 lines per function, ≤50 per class | AGREE/DISAGREE | PASS/FAIL | |
| 19 | OC-8: ≤2 instance variables (behavioural classes only) | AGREE/DISAGREE | PASS/FAIL | |
| 20 | OC-9: no getters/setters | AGREE/DISAGREE | PASS/FAIL | |
| 21 | Patterns: no good reason to refactor using OOP/Design Patterns | AGREE/DISAGREE | PASS/FAIL | |
| 22 | Patterns: no creational smell | AGREE/DISAGREE | PASS/FAIL | |
| 23 | Patterns: no structural smell | AGREE/DISAGREE | PASS/FAIL | |
| 24 | Patterns: no behavioral smell | AGREE/DISAGREE | PASS/FAIL | |
| 25 | Semantic: tests operate at same abstraction as AC | AGREE/DISAGREE | PASS/FAIL | |

### Reviewer Stance Declaration

Expand Down
Binary file added .pyproject.toml.swp
Binary file not shown.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

All notable changes to pytest-beehave will be documented in this file.

## [v3.1.20260419] — Generative Augochlora — 2026-04-19

### Added
- feat(example-hatch): add `--beehave-hatch` flag to generate bee-themed example `.feature` files and demonstrate the plugin in one command

### Fixed
- fix(example-hatch): wrap `run_hatch()` call in `pytest_configure` with `try/except SystemExit` to produce clean error exit instead of `INTERNALERROR` crash

### Changed
- docs: add "See it in 2 minutes" demo section to README showing `--beehave-hatch` output and generated stubs
- chore: add `test-coverage` task to `pyproject.toml` for explicit coverage-only runs
- chore(skills): number SE Self-Declaration items 1–25 and add completeness check to reviewer skill

## [v3.0.20260419] — Foundational Apis — 2026-04-19

### Added
Expand Down
51 changes: 0 additions & 51 deletions Dockerfile

This file was deleted.

Loading
Loading