Spec review & approval workflow: frontmatter contract, transition detection, and role→person→channel routing.
Project description
hureva
A spec review & approval workflow you install into your team's repo: generate
specs with Claude, get structured review from non-technical teammates (PM, UX, QA)
before code is written, and record approval in git.
Based on docs/spec-review-workflow-specification.md.
hureva is a versioned package teams install, not copy. Your specs live in your
own repo under specs/; you add a small workflow that pip installs a pinned
version of hureva and runs it, plus a bit of config. Nothing is hosted, and none
of hureva's code lives in your repo.
Installing it? See
SETUP.mdfor the step-by-step guide.
How it works
- The spec is a
spec.mdwhose frontmatter is the contract (§4.2):status, role-based access (owner/approvers/commenters/viewers), and the sign-off trail. People are named by roster key; channels resolve from.hureva/roster.yml. - Work happens on whatever branch you like — no naming convention required.
Pushing a status change fires the workflow, which compares the spec's
statusacross the push's two commits and acts only on a transition (§7.4). (A push directly to the repo's default branch still fires the workflow, but there's no PR to open from there, so GitHub-channel delivery has nothing to attach a review request to.) draft → in_reviewnotifies reviewers;→ approvedtells the owner "ready to build."- Specs are authored by Claude, not scaffolded by a CLI:
hureva-initwrites aCLAUDE.mdwith the frontmatter contract and role-seeding rules, so Claude creates a conformantspec.mdand branch directly from those instructions.
Library
| Piece | Module | Spec |
|---|---|---|
| Frontmatter / roster / defaults models | hureva.models |
§4.2–4.4 |
Frontmatter parsing (+ lenient status reader) |
hureva.frontmatter |
§4.2 |
.hureva/ config loading + specs_dir-derived paths |
hureva.config |
§4.1, §4.4 |
| Two-commit transition detection (pure fn) | hureva.transitions |
§7.4 |
| Changed-spec discovery from a push | hureva.discovery |
§7.4 |
| Event → role → person → channel routing | hureva.routing |
§7.1 |
| Sender interface + dry-run + Slack + SMTP | hureva.senders |
§7.3 |
| Notify orchestration + CLI | hureva.notify |
§7 |
The logic is a pure library (git/env reading is a thin shell), delivery is behind
a Sender interface, and the specs path is configurable — nothing hard-codes
specs.
How teams install it
hureva is a PyPI package (hureva), published on each GitHub Release. The
fastest path is to scaffold the setup, then follow the printed checklist:
pip install hureva
hureva-init # writes the workflow + config, prints next steps
Under the hood that adds one small, static workflow that installs the versioned package and runs its notify command:
# team-repo/.github/workflows/hureva-spec-review.yml
on:
push:
branches: ["**"] # any branch, but excludes tag pushes
paths: ["specs/**"] # (literal — Actions can't use a variable here)
jobs:
hureva-spec-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 } # both push commits reachable (§7.4)
- uses: actions/setup-python@v5
with: { python-version: "3.12" }
- run: pip install "hureva~=2.0" # ← version pin lives here
- run: hureva-notify --specs-dir specs
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
# SMTP_* too, if using email
Nothing of hureva's code lives in the team repo — the workflow is generic "install
a tool and run it" plumbing, and all behavior is in the versioned package. The
hureva- prefix in its filename is deliberate: this file is hureva-owned, not
yours to hand-edit — hureva-init regenerates it on every run (no --force
needed), unlike the roster/defaults/CLAUDE.md content files, which are yours
and are left alone once they exist.
Versioning — pin the package
pip install "hureva~=2.0" is the version pin (like "hureva": "^2.0" in a
dependency list). It's the alternative to copying hureva's code in (which drifts
and never gets fixes): you install a released version.
~=2.0takes any 2.x release, so compatible fixes flow in automatically.- Pin exactly with
==2.0.0; move to the next major (~=3.0) when you choose, after reading its release notes.
CLIs
Commands (also runnable as python -m hureva.<module>). The operational ones take
--specs-dir (default specs).
# One-time: scaffold the workflow + config into this repo, print next steps
hureva-init
# Route notifications for a push (--dry-run prints without delivering)
hureva-notify --dry-run
hureva-notify reads the GitHub push event ($GITHUB_EVENT_PATH, set by the
runner; or --event-file) to get the before/after commits. Recipients come
from the spec's frontmatter roles; each person's channel is their handle in
roster.yml. A name missing from the roster is reported loudly, never dropped
silently.
Channels
Each person is reached on the channel whose handle you give them in roster.yml
(list only one; the order below breaks ties):
- GitHub —
github: <username>. No setup — the workflow's built-inGITHUB_TOKENopens a PR for the spec branch and requests the person as a reviewer, so GitHub emails/notifies them. They just need access to the repo. - Slack —
slack: "<U-id>"; set theSLACK_BOT_TOKENsecret. Handles:#channel, a member ID (U…), or an email (DM viausers.lookupByEmail). - SMTP email —
email: <addr>; setSMTP_HOST(+SMTP_PORT,SMTP_USERNAME,SMTP_PASSWORD,SMTP_FROM).
GitHub works out of the box; Slack/email activate only when their secret is set.
--dry-run needs no credentials.
Independent of channels: .hureva/links.yml says where reviewers read specs.
Each entry is a notification label and a URL template, rendered fresh per spec
from {repo}, {branch}, {slug}, and {path} (a template naming none of
them is used as-is — all a plain docs site needs). hureva-init writes it from
your answer; every label resolves independently, so a prototype: link never
displaces your review link. The file is optional: without it, notifications
carry the pull request link alone.
Templating is the whole mechanism — no network call at notify time. A Hureva
(repo, branch, path) link is only resolved to a ReviewDoc lazily, in the
app, the first time a reviewer clicks it.
Develop
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hureva-2.1.0.tar.gz.
File metadata
- Download URL: hureva-2.1.0.tar.gz
- Upload date:
- Size: 80.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0690022499528d5abc178321f5d658f36a2e7a99867fa529e343dd898d61f69c
|
|
| MD5 |
53a89539538eb0bc2f129cdd9fc89827
|
|
| BLAKE2b-256 |
acdddb355d67789b4f3a46d2c4ae5d2755efdb2acd367a4d076bc42cc260ffa7
|
Provenance
The following attestation bundles were made for hureva-2.1.0.tar.gz:
Publisher:
publish.yml on growth-beaker/hureva-app
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hureva-2.1.0.tar.gz -
Subject digest:
0690022499528d5abc178321f5d658f36a2e7a99867fa529e343dd898d61f69c - Sigstore transparency entry: 2188377181
- Sigstore integration time:
-
Permalink:
growth-beaker/hureva-app@bf87efa62afec1d36630ce90cd2182e04facd58c -
Branch / Tag:
refs/tags/hureva-v2.1.0 - Owner: https://github.com/growth-beaker
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@bf87efa62afec1d36630ce90cd2182e04facd58c -
Trigger Event:
release
-
Statement type:
File details
Details for the file hureva-2.1.0-py3-none-any.whl.
File metadata
- Download URL: hureva-2.1.0-py3-none-any.whl
- Upload date:
- Size: 52.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de3473b0b2b803bba123bdcce6e703c25a3077fd8ccda80c7e9c229b180a537a
|
|
| MD5 |
a57905d15418b870cb0cdf6f209ff381
|
|
| BLAKE2b-256 |
789bd900f4586314bc9c334144d100b2413083ff0dace811360db4e0b8fac030
|
Provenance
The following attestation bundles were made for hureva-2.1.0-py3-none-any.whl:
Publisher:
publish.yml on growth-beaker/hureva-app
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hureva-2.1.0-py3-none-any.whl -
Subject digest:
de3473b0b2b803bba123bdcce6e703c25a3077fd8ccda80c7e9c229b180a537a - Sigstore transparency entry: 2188377186
- Sigstore integration time:
-
Permalink:
growth-beaker/hureva-app@bf87efa62afec1d36630ce90cd2182e04facd58c -
Branch / Tag:
refs/tags/hureva-v2.1.0 - Owner: https://github.com/growth-beaker
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@bf87efa62afec1d36630ce90cd2182e04facd58c -
Trigger Event:
release
-
Statement type: