Skip to main content

vibey-gh

Release automation for a GitHub repository: provenance fingerprints, derived version bumps, a merge train, and post-release branch realignment.

No dependencies. Everything is stdlib. This runs in every CI job of every repository that adopts it, so a dependency it grows is a dependency all of them grow.

pip install vibey-gh
vibey-gh install

install writes the git hooks and workflow files into your repository and points core.hooksPath at them. A hook you already have is moved aside to <name>.local and chained, never discarded — adopting this should not silently drop checks somebody thought were important.

What it does

Provenance, enforced in two places

Every code change carries a fingerprint. Source files get a header comment; every commit gets a trailer. The trailer is what makes the rule total — a change to a Markdown file or a JSON manifest still arrives as a commit, and the commit is fingerprinted even when the file cannot be.

vibey-gh check                 # are the hooks installed and the fingerprints intact?
vibey-gh check --apply         # add the missing file headers
vibey-gh check --commits main..HEAD    # and every commit trailer in a range

The pre-push hook refuses the push if either half is missing, to any branch, local or remote. git push --no-verify still works, because a hook that cannot be bypassed in an emergency gets uninstalled instead; CI applies the same rule server-side, so skipping it locally defers the failure rather than avoiding it.

Versions derived, not remembered

vibey-gh version --since origin/main --explain     # what should this release be?
vibey-gh version --since origin/main --apply       # write it to every version file
vibey-gh version --dev "$GITHUB_RUN_NUMBER"        # <release>.dev<n> for a TestPyPI build
what changed bump
a content_path minor — users receive something new
only a code_path patch — an internal fix
neither none — docs and CI do not reach an installed user
the version already moved none — a deliberate bump is in place; never double it

none is a legitimate answer. This has to be automatic: a PyPI upload with skip-existing turns an unbumped release into a green run that publishes nothing, silently, with no warning anywhere. A human-maintained version is a silent-failure generator.

Version files may be Python (__version__ = "..."), JSON (a version key, at the top level or under metadata), or TOML (the [project] table — and only that table, because pyproject.toml has others carrying a version key and bumping the wrong one is worse than not bumping).

The merge train

vibey-gh merge-train --dry-run
vibey-gh merge-train --method squash

The normal path is event-driven: the PR-automation gate dispatches vibey-gh merge-train --pr NUMBER as soon as the exact current head is green. The weekly and manual modes remain recovery backstops. A ready PR is open, current with its target, conflict-free, green, free of requested changes, and carries a successful exact-head PR automation / gate when an outside-author review is required.

Outside authors receive a fresh structured Claude review after scans pass. Findings feed the same bounded repair loop as failed scans. Forks are never mutated with privileged credentials; when a fork needs edits, automation preserves its exact head in a linked repository-owned replacement PR.

PR review and repair automation

branch-intake.yml opens exactly one draft PR when a new same-repository topic branch is first pushed. It ignores the integration branch, release branch, and automation-owned fork repair branches. Later pushes reuse the existing PR. Once the configured scans for the exact draft head are complete and green, PR automation marks it ready and immediately continues through review, repair, gating, and the merge train. Pending, failing, stale, conflicting, closed, and fork draft heads are no-ops; they are never promoted prematurely.

pr-automation.yml reacts to configured scan-workflow completions, re-reads the entire current-head check rollup, and publishes an explicit check run on that exact SHA. It waits for pending scans, separates cancelled infrastructure from actionable failures, and allows at most three repair commits per contributor lineage. A new contributor commit starts a new lineage; bot repair pushes do not reset the counter.

Conflicting same-repository PRs enter a bounded conflict-resolution job instead of failing permanently. The job materializes Git's exact unresolved path set without executing repository code, gives the constrained agent read/search/edit access only, rejects edits outside that set, rechecks the head SHA, and publishes one ordinary non-force resolution commit. Fork conflicts continue through the repository-owned replacement-PR path. Conflict attempts share the three-attempt repair budget, so an ambiguous merge cannot loop forever.

Review and repair use the immutable-pinned Claude Code Action with selected vibey-skills. The privileged jobs may inspect source and CI logs but may not execute contributor package managers, tests, builds, scripts, or binaries. Ordinary PR CI validates every repair push. The agent has no Git mutation tool: one trusted publisher may push a non-empty source (HEAD:refs/heads/<exact-pr-branch>) only to the exact PR branch. This deliberately permits forward updates to develop or main when either is the PR head, while making a Git deletion refspec (:branch) structurally impossible. Managed merges automatically update develop and main, but no managed command uses --delete, --delete-branch, an empty-source refspec, or a branch-deletion API. Repositories must configure ANTHROPIC_API_KEY; AUTOMERGE_TOKEN is required where the default Actions token cannot push or merge through the repository ruleset. Installation does not create either secret.

vibey-gh pr-automation evaluate --pr 123 --head-sha HEAD_SHA
vibey-gh pr-automation ready-draft --pr 123 --head-sha HEAD_SHA
vibey-gh pr-automation mirror-fork --pr 123
vibey-gh merge-train --pr 123

The promotion

vibey-gh promote --dry-run
vibey-gh promote

Moves the integration branch to the release branch, which is what publishes. Three things it gets right that a hand-written workflow usually does not:

  • It compares by content, not by commit count. The release branch is rebase-merged, so its commits are rewritten copies with different SHAs; the integration branch always looks "ahead" even when the trees are identical. A diff is the only honest test.
  • It derives the version before opening anything. An upload with skip-existing turns an unbumped promotion into a green run that publishes nothing, silently.
  • It hands the PR to the same event gate as every other change. promote no longer holds a runner open with gh pr checks --watch; scans, automated review, and the exact-head merge train finish the promotion asynchronously. --wait retains the legacy synchronous mode for recovery.

Realignment

vibey-gh realign

When the release branch is rebase-merged its commits are rewritten copies with new SHAs, so the integration branch's tip is never an ancestor of it and a fast-forward is impossible — yet a ruleset with a strict up-to-date policy treats it as behind, which blocks the next promotion.

The guard is tree equality, not ancestry: this runs only when a diff between the two branches is empty, so it converges two identical contents onto one history and cannot discard work. If the integration branch has anything the release branch does not, it is left alone and says so.

Configuration

[pr_automation]
enabled = true
scan_workflows = ["CI", "Provenance", "CodeQL", "Docs", "API drift (Cloud Agents OpenAPI)"]
ignored_checks = ["PR automation / gate", "Merge train / merge"]
max_repair_attempts = 3
model = "claude-sonnet-5"
review_untrusted_authors = true
repair_untrusted_authors = true
replace_fork_prs = true
retain_schedule_backstop = true

[github_release]
enabled = true
tag_prefix = "v"
generate_notes = true

[repository_profile]
enabled = true
description = "A configurable repository description"
topics = ["automation", "documentation", "github-actions"]

After the configured Release workflow succeeds on main, the managed github-release.yml workflow tags that exact commit and creates a generated-notes GitHub Release. It is safe to rerun: an existing matching tag/release is reused, while an existing tag at a different SHA is never moved and fails loudly.

The managed release-surfaces.yml workflow follows every successful release on either branch. It builds two persistent ProperDocs sites under the repository's GitHub Pages domain: /develop/ is the test documentation released with TestPyPI, while /main/ is the production documentation released with PyPI. A small root page links both channels. Because GitHub Pages has one deployment per repository, each run restores the latest successful artifact for the other channel before deploying; one branch never erases the other branch's site.

GitHub Packages does not provide a PyPI registry. The workflow therefore publishes the exact wheel and source distribution from the successful Release run as an OCI artifact at ghcr.io/<owner>/<repository>/python. Every artifact receives its immutable version and sha-<commit> tags, plus develop for test releases or main and latest for production releases. The normal TestPyPI and PyPI uploads remain authoritative and are unchanged.

After release surfaces succeed, repository-profile.yml reconciles the repository's description, topics, and homepage with this configuration. An empty description derives a repository-specific description from the consuming repository name. It verifies that Pages, a GitHub Release, a deployment, and the OCI package really exist—the public API does not expose fictional “show Releases/Deployments/Packages” switches. Profile updates use AUTOMERGE_TOKEN when available and never create, update, push, or delete a branch.

If a trusted post-merge workflow fails on develop or main, release-repair.yml reviews its logs with the same constrained agent used for PR repair. A fixable problem is committed to a new vibey-gh/repair/release-* branch and returned through a normal PR, where all checks and the merge train apply. It never pushes a repair directly to—and can never delete—develop or main. Credential, billing, repository-setting, registry, and other operator-only failures are reported with an explicit required action instead of being disguised as code fixes.

Everything project-specific lives in .vibey-gh.toml, so the logic beside it stays general. Every key has a default; a repository that agrees with them needs no file at all.

[fingerprint]
text    = "Made with love by ..."          # the source-header comment
trailer = "Made-With: ..."                 # the commit trailer
sources = ["src/**/*.py", ".github/workflows/*.yml"]

[version]
files         = ["pyproject.toml", "src/pkg/__init__.py"]
content_paths = ["plugins/"]               # a change here is a MINOR release
code_paths    = ["src/"]                   # a change here alone is a PATCH

[branches]
integration = "develop"
release     = "main"

[merge_train]
owner           = "your-login"
trusted_authors = ["your-login", "dependabot[bot]"]

Taking the hooks without the workflows

install writes the managed workflows alongside the hooks. A repository that already has richer ones of its own can decline them:

[install]
workflows = []          # hooks and the CLI only
# workflows = ["provenance.yml"]   # or just the ones you want

This is not cosmetic. check verifies that everything it manages is present and current, so without it a repository that deliberately keeps its own workflows would fail the check forever — and a check that cannot pass is a check people route around.

trusted_authors is matched after normalising app/name and name[bot] to the same thing. gh reports a bot author with the app/ prefix while the rest of GitHub writes [bot]; a literal allow-list matches whichever spelling it happens to contain and silently distrusts the other, which once caused an automation to quarantine its own pull request as an outside contribution.

What is deliberately not fingerprinted

  • Files whose bytes are meaningful — generated documents verified against a source, Markdown loaded into a model's context. A header would be a diff against the source.
  • Anything without comment syntax — JSON, most notably.

The commit trailer covers both without touching them. A naive "comment in every changed file" rule cannot express itself in JSON and corrupts content that is checked byte for byte.

Licence

MIT. See LICENSE.

Download files

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

Source Distribution

vibey_gh-1.11.0.tar.gz (76.3 kB view details)

Uploaded Source

Built Distribution

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

vibey_gh-1.11.0-py3-none-any.whl (71.5 kB view details)

Uploaded Python 3

File details

Details for the file vibey_gh-1.11.0.tar.gz.

File metadata

  • Download URL: vibey_gh-1.11.0.tar.gz
  • Upload date:
  • Size: 76.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vibey_gh-1.11.0.tar.gz
Algorithm Hash digest
SHA256 6b5f67f34eef06ec40bcc05f05fcec8315b3f23bc0e3acf18f830912dddfd4ce
MD5 5967874c7f47e1ed9189e3c09a0d2c90
BLAKE2b-256 dba4b5cebd2d652bd38aebb14ac613ac3c65f80e8ee769287d71a467982825ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for vibey_gh-1.11.0.tar.gz:

Publisher: release.yml on adammatthewsteinberger/vibey-gh

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

File details

Details for the file vibey_gh-1.11.0-py3-none-any.whl.

File metadata

  • Download URL: vibey_gh-1.11.0-py3-none-any.whl
  • Upload date:
  • Size: 71.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vibey_gh-1.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ce5d0f4aa0e6e4df4c39915853d30594d6f0ae75095f8dadeffc0503f8500aab
MD5 ab887a008b314c6cb1366bc6c24ee145
BLAKE2b-256 232a5483ac1b08f3509c4011b2371c7d6333012e36c2050d34166dfbcf2573cd

See more details on using hashes here.

Provenance

The following attestation bundles were made for vibey_gh-1.11.0-py3-none-any.whl:

Publisher: release.yml on adammatthewsteinberger/vibey-gh

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

Release history Release notifications | RSS feed

1.43.0

2 files

1.42.0

2 files

1.41.0

2 files

1.40.0

2 files

1.39.0

2 files

1.38.0

2 files

1.37.0

2 files

1.36.0

2 files

1.35.0

2 files

1.34.0

2 files

1.33.0

2 files

1.32.0

2 files

1.31.0

2 files

1.30.0

2 files

1.29.0

2 files

1.28.0

2 files

1.27.0

2 files

1.26.0

2 files

1.25.0

2 files

1.24.0

2 files

1.23.0

2 files

1.22.0

2 files

1.21.0

2 files

1.20.0

2 files

1.19.0

2 files

1.18.0

2 files

1.17.0

2 files

1.16.0

2 files

1.15.0

2 files

1.14.0

2 files

1.13.0

2 files

1.12.0

2 files

This release

1.11.0 This release

2 files

1.10.0

2 files

1.9.0

2 files

1.8.0

2 files

1.7.0

2 files

1.6.0

2 files

1.5.0

2 files

1.4.0

2 files

1.2.0

2 files

1.1.1

2 files

1.1.0

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page