Skip to main content

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.md for the step-by-step guide.

How it works

  • The spec is a spec.md whose 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 status across 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_review notifies reviewers; → approved tells the owner "ready to build."
  • Specs are authored by Claude, not scaffolded by a CLI: hureva-init writes a CLAUDE.md with the frontmatter contract and role-seeding rules, so Claude creates a conformant spec.md and 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.0 takes 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):

  • GitHubgithub: <username>. No setup — the workflow's built-in GITHUB_TOKEN opens 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.
  • Slackslack: "<U-id>"; set the SLACK_BOT_TOKEN secret. Handles: #channel, a member ID (U…), or an email (DM via users.lookupByEmail).
  • SMTP emailemail: <addr>; set SMTP_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.

Pre-push review notifications (account-gated, no Actions required)

For teams where GitHub Actions is disabled (or a GitHub App install is an adoption blocker), hureva ships a second, additive path: a local pre-push git hook notifies approvers by email the moment a spec transitions * → in_review in the pushed range. All git/spec reading stays local to your machine; the only hosted surface is one authenticated send endpoint on the hureva app (it holds the Resend key, renders the email server-side, and dedups). The existing hureva-notify + Actions path above is untouched — this is a parallel option.

Install

pipx is the recommended install — it puts the CLI in its own isolated environment and exposes the hureva-* commands on your PATH:

pipx install hureva
# optional: OS keyring backend for the login token (falls back to a 0600 file)
pipx install "hureva[keyring]"

One-time setup per clone

hureva-init

hureva-init (run once per clone) does three things:

  1. Scaffolds config.hureva/roster.yml and .hureva/links.yml, prompting for the review surface (hureva app / GitBook / Docusaurus / custom URL template) with no silent default. This is a links.yml choice: it only sets where the notification link points; it does not host anything.
  2. Installs the pre-push hook by pointing a tracked core.hooksPath at .hureva/hooks/, so every clone that runs hureva-init gets it. If a foreign hooks dir is already configured (husky/pre-commit), it installs into / chains that dir rather than clobbering it; when chaining isn't safe it prints manual instructions and leaves your config untouched.
  3. Logs you in — runs the device-grant login (skipped if already authenticated).

Authentication

Login is a per-user hureva-app account via the OAuth 2.0 device authorization grant (the gh auth login model): the CLI prints a code you enter in a browser.

hureva-login     # device-code flow; stores a per-user token
hureva-whoami    # show the logged-in identity
hureva-logout    # clear the stored token

The token is stored at ~/.config/hureva/auth.json mode 0600 (or the OS keyring when the keyring extra is installed). The relay authorizes each call with this per-user token.

Zero configuration. The CLI ships with the deployment's Auth0 and relay defaults baked in (all non-secret public values — the device grant is a public-client flow with no client secret), so end users just run:

pipx install hureva
hureva login

with no environment setup at all. The HUREVA_AUTH0_DOMAIN, HUREVA_AUTH0_CLIENT_ID, HUREVA_AUTH0_AUDIENCE, and HUREVA_API_URL env vars are overrides only — set them to point the CLI at a non-default (staging / self-hosted / local) instance. The CLI's HUREVA_AUTH0_CLIENT_ID is the Auth0 Native app (Device Code grant), distinct from the web app's SPA client, which cannot issue the device grant.

Fail-open guarantee

The hook is fail-open: any hureva error — a crash, a missing binary, no login, a dropped network, a relay 5xx — exits 0 with a warning and never blocks your push. The only thing that can stop a push through this hook is a pre-existing hook that hureva chained: its non-zero exit is passed through unchanged, so your own test gate is never masked.

Manual fallback

If a push didn't fire the hook (a clone that never ran hureva-init, or a web-UI edit), notify for a single spec by hand:

hureva-notify-path --path specs/<slug>/spec.md            # evaluate + notify (fail-open)
hureva-notify-path --path specs/<slug>/spec.md --dry-run  # print the payload, send nothing

It notifies only if the spec is currently in_review; the relay is idempotent on (repo, spec_path, content_hash), so a manual send after the hook already fired is a no-op rather than a duplicate.

Develop

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hureva-3.0.0.tar.gz (126.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hureva-3.0.0-py3-none-any.whl (83.7 kB view details)

Uploaded Python 3

File details

Details for the file hureva-3.0.0.tar.gz.

File metadata

  • Download URL: hureva-3.0.0.tar.gz
  • Upload date:
  • Size: 126.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for hureva-3.0.0.tar.gz
Algorithm Hash digest
SHA256 8a107266dfee03f12b413e6541048ae86ff140f0b5255213d7e708d27fa154f3
MD5 e0d771660ab93a00117d15306b7ba410
BLAKE2b-256 4ebaacc3e9b88e7e36f62930f9e0f55fd190292bea1de87f95a7346b628e8f23

See more details on using hashes here.

Provenance

The following attestation bundles were made for hureva-3.0.0.tar.gz:

Publisher: publish.yml on growth-beaker/hureva-app

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hureva-3.0.0-py3-none-any.whl.

File metadata

  • Download URL: hureva-3.0.0-py3-none-any.whl
  • Upload date:
  • Size: 83.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for hureva-3.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3f30dbc5f1e82f46d7f3155bb9957ffc990d6eda157d644617dc6743f5f74f67
MD5 52aa862952d0969542bb561680902dac
BLAKE2b-256 5157ee5c4180413f08463e7e0244d7396d21c544d43c600c566b08525e33caca

See more details on using hashes here.

Provenance

The following attestation bundles were made for hureva-3.0.0-py3-none-any.whl:

Publisher: publish.yml on growth-beaker/hureva-app

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page