Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 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
8069bbb
chore(stub-creation): remove @bug tag — stub format becomes configura…
nullhack Apr 19, 2026
79a9751
feat(discovery): add stub-format-config feature scope
nullhack Apr 19, 2026
6f9309e
feat(stories): write user stories for stub-format-config
nullhack Apr 19, 2026
61a6882
feat(criteria): write acceptance criteria for stub-format-config
nullhack Apr 19, 2026
874f236
chore: complete step 1 for stub-format-config
nullhack Apr 19, 2026
9a3daaf
chore: move stub-format-config to in-progress, begin Step 2 (Architec…
nullhack Apr 19, 2026
a298066
feat(stub-format-config): add architecture stubs
nullhack Apr 19, 2026
e88df41
feat(stub-format-config): implement @id:b2c3d4e5 — absent stub_format…
nullhack Apr 19, 2026
cc759ef
feat(stub-format-config): implement @id:f6a7b8c9 — invalid stub_forma…
nullhack Apr 19, 2026
4b160e1
feat(stub-format-config): implement @id:a1b2c3d4 — default format is …
nullhack Apr 19, 2026
982c647
feat(stub-format-config): implement @id:c3d4e5f6 — explicit functions…
nullhack Apr 19, 2026
eb465a4
feat(stub-format-config): all 7 @id tests green — quality gate passed
nullhack Apr 19, 2026
374a25d
chore: update TODO.md — all 7 @id green, ready for Step 4 review
nullhack Apr 19, 2026
49066b1
fix(stub-format-config): address reviewer findings — cast, unit test …
nullhack Apr 19, 2026
b4f1ee7
chore: complete step 4 for stub-format-config — APPROVED
nullhack Apr 19, 2026
3dc4f12
fix(stub-format-config): add self parameter to class-method stubs
nullhack Apr 19, 2026
417fd60
feat(stub-format-config): assign unique @id values to resolve collisions
nullhack Apr 19, 2026
d3d405d
fix(stub-format-config): rename tests to match new @id values, remove…
nullhack Apr 19, 2026
ddfc2d8
chore: update TODO.md — ready for Step 4 re-verification
nullhack Apr 19, 2026
2372266
chore: complete step 4 for stub-format-config — APPROVED
nullhack Apr 19, 2026
0bfcb30
feat(stub-format-config): accept feature at Step 5 — move to completed
nullhack Apr 19, 2026
90454c0
fix(plugin-hook): add deprecated @id:e3a13b58 AC and replace orphan s…
nullhack Apr 19, 2026
c773390
chore(release): bump version to v3.2.20260419 — Mason Osmia
nullhack Apr 19, 2026
6734a84
fix(ci): clean dist/ before build to prevent stale artifact reuse
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
3 changes: 3 additions & 0 deletions .github/workflows/pypi-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
- name: Set up Python 3.13
run: uv python install 3.13

- name: Clean dist
run: rm -rf dist/

- name: Build wheel and sdist
run: uv build

Expand Down
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."
13 changes: 6 additions & 7 deletions .opencode/agents/product-owner.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,18 @@ When a gap is reported (by software-engineer or reviewer):

| Situation | Action |
|---|---|
| Edge case within current user stories | Add a new Example with a new `@id` to the relevant `.feature` file. |
| Edge case within current user stories | Add a new Example to the relevant `.feature` file. |
| New behavior beyond current stories | Add to backlog as a new feature. Do not extend the current feature. |
| Behavior contradicts an existing Example | Write a new Example with new `@id`. |
| Post-merge defect | Move the `.feature` file back to `in-progress/`, add new Example with `@id`, resume at Step 3. |
| Behavior contradicts an existing Example | Add `@deprecated` to the old Example; write a new Example. |
| Post-merge defect | Move the `.feature` file back to `in-progress/`, add new Example, resume at Step 3. |

## Bug Handling

When a defect is reported against any feature:

1. Add a `@bug @id:<new-8-char-hex>` Example to the relevant `Rule:` block in the `.feature` file.
2. Write the Example using the standard `Given/When/Then` format describing the correct behavior.
3. Update TODO.md to note the new `@id` for the SE to implement.
4. SE implements the `@id` test in `tests/features/` **and** a `@given` Hypothesis property test in `tests/unit/`. Both are required.
1. Add a `@bug` Example to the relevant `Rule:` block in the `.feature` file using the standard `Given/When/Then` format describing the correct behavior.
2. Update TODO.md to note the new bug Example for the SE to implement.
3. SE implements the test in `tests/features/` **and** a `@given` Hypothesis property test in `tests/unit/`. Both are required.

## Available Skills

Expand Down
1 change: 1 addition & 0 deletions .opencode/agents/reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ If you discover an observable behavior with no acceptance criterion:

You never edit `.feature` files or add Examples yourself.


143 changes: 143 additions & 0 deletions .opencode/agents/setup-project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
description: Agent for setting up new projects from the Python template - gathers parameters and applies them directly
mode: subagent
temperature: 0.3
tools:
write: true
edit: true
bash: true
read: true
grep: true
glob: true
task: false
skill: false
---

# Setup Project

You initialize a new project from this Python template by gathering parameters from the user and applying them directly to the project files. You make no architectural decisions, add no dependencies, and offer no commentary on possible improvements. You only substitute the template variables with user-provided values.

## Step 1 — Gather Parameters

Read `template-config.yaml` and show the user the 6 values under `defaults:`. For **each key in order**, display the current default value and ask the user: "Use this value or enter a new one?" Accept the default if the user confirms it. Collect all 6 values before proceeding:

1. `github_username` — their GitHub handle (e.g. `myusername`)
2. `project_name` — kebab-case repo name (e.g. `my-awesome-project`)
3. `package_name` — snake_case Python package name (e.g. `my_awesome_project`). This becomes the `app/` directory.
4. `project_description` — one sentence describing what the project does
5. `author_name` — their full name
6. `author_email` — their email address

Do not ask for anything else. Do not suggest additional parameters.

## Step 2 — Show Summary and Confirm

Print a table showing old value → new value for all 6 parameters:

| Parameter | Old (default) | New |
|---|---|---|
| `github_username` | ... | ... |
| `project_name` | ... | ... |
| `package_name` | ... | ... |
| `project_description` | ... | ... |
| `author_name` | ... | ... |
| `author_email` | ... | ... |

Note explicitly: `github_username` will be used in both `pyproject.toml` URLs and `git remote set-url`. Confirm they are correct before proceeding.

Ask the user to confirm before making any changes.

## Step 3 — Apply Changes

Execute each sub-step in order. Do not skip any. Do not make any changes beyond what is listed here.

The substitution patterns are the source of truth in `template-config.yaml` under `substitutions:`. The steps below describe each file in plain terms; verify counts against the config if in doubt.

### 3a. Rename the package directory

```bash
mv app <package_name>
```

### 3b. Update `pyproject.toml`

Apply every substitution listed under `substitutions.pyproject.toml` in `template-config.yaml`. Additionally, reset the version field to `0.1.YYYYMMDD` using today's date.

### 3c. Update `README.md`

Apply every substitution listed under `substitutions.README.md`. The `eol` → `<author_name>` replacement applies only to the author credit line; do not replace `eol` in other contexts.

### 3d. Update test files referencing the package

Apply every substitution listed under `substitutions.tests/unit/app_test.py`.

After applying substitutions, verify no stale references remain:

```bash
grep -rn "from app" tests/
```

The command must return no output before proceeding to Step 3e.

### 3e. Update `.github/workflows/ci.yml`

Apply every substitution listed under `substitutions..github/workflows/ci.yml`.

### 3f. Update `Dockerfile`

Apply every substitution listed under `substitutions.Dockerfile`.

### 3g. Update `docker-compose.yml`

Apply every substitution listed under `substitutions.docker-compose.yml`.

### 3h. Update `.dockerignore`

Apply every substitution listed under `substitutions..dockerignore`.

### 3i. Update `docs/index.html`

Apply every substitution listed under `substitutions.docs/index.html`.

### 3j. Update `LICENSE`

Apply every substitution listed under `substitutions.LICENSE`.

### 3k. Update `template-config.yaml`

Apply every substitution listed under `substitutions.template-config.yaml`. This updates the `defaults:` section to reflect the user's values. This is always the last file changed.

### 3l. Set git remote

```bash
git remote set-url origin git@github.com:<github_username>/<project_name>.git
```

## Step 4 — Smoke Test

```bash
uv sync --all-extras && uv run task test-fast
```

Both must succeed. If `uv run task test-fast` fails and the failure is caused by a variable substitution that was missed (e.g. an import still referencing `app` instead of `<package_name>`), apply the same substitution pattern to fix it. If the failure has any other cause, report the error and stop — do not attempt to fix it.

## Step 5 — Done

Tell the user which files were changed (list them). Then show next steps:

```bash
# Commit the setup
git add -A && git commit -m "chore: initialize project from python-project-template"
git push -u origin main

# Optional: rename the project folder (run from the parent directory)
cd .. && mv python-project-template <project_name>
```

Then tell the user to start the workflow:

```
@product-owner
```

The PO picks the first feature from backlog and moves it to in-progress.
1 change: 0 additions & 1 deletion .opencode/skills/design-patterns/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,5 +402,4 @@ class JsonImporter(Importer):

Procedural code is open to inspection but open to modification too — every new case touches existing logic.
OOP (via Strategy, State, Observer, etc.) closes existing code to modification and opens it to extension through new types.

The smell is always the same: **a place in the codebase that must change every time the domain grows.**
12 changes: 7 additions & 5 deletions .opencode/skills/feature-selection/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: feature-selection
description: Score and select the next backlog feature by value, effort, and dependencies
version: "2.0"
version: "1.0"
author: product-owner
audience: product-owner
workflow: feature-lifecycle
Expand Down Expand Up @@ -33,11 +33,15 @@ ls docs/features/in-progress/

### 2. List BASELINED Candidates

Read each `.feature` file in `docs/features/backlog/`. Check its feature description for `Status: BASELINED`.
Read each `.feature` file in `docs/features/backlog/`. Check its discovery section for `Status: BASELINED`.

- Non-BASELINED features are not eligible — they need Step 1 (scope) first
- If no BASELINED features exist: inform the stakeholder; run `@product-owner` with `skill scope` to baseline the most promising backlog item first

**IMPORTANT**

**NEVER move a feature to `in-progress/` unless its discovery section has `Status: BASELINED`**

### 3. Score Each Candidate

For each BASELINED feature, fill this table:
Expand Down Expand Up @@ -78,8 +82,6 @@ If all BASELINED features have Dependency=1: stop and resolve the blocking depen

### 5. Move and Update TODO.md

**The PO owns this move.** Move the selected feature file:

```bash
mv docs/features/backlog/<name>.feature docs/features/in-progress/<name>.feature
```
Expand All @@ -97,7 +99,7 @@ Source: docs/features/in-progress/<name>.feature
Run @<agent-name> — <first concrete action for this feature>
```

- If the feature has no `Rule:` blocks yet → Step 1 Stage 2 Step A (Stories): `Run @product-owner — load skill scope and write user stories`
- If the feature has no `Rule:` blocks yet → Step 1 (SCOPE): `Run @product-owner — load skill scope and write stories`
- 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`
- If the feature has `@id` Examples → Step 2 (ARCH): `Run @software-engineer — load skill implementation and write architecture stubs`

Expand Down
Loading
Loading