Workflow reference

Repair and conflict publication are optimistic exact-head updates. Immediately before committing, and again after any non-fast-forward push rejection, the trusted publisher compares the PR head with the SHA that was evaluated. A concurrent update converts the old run into a successful stale no-op; it never force-pushes, overwrites newer work, consumes a repair attempt, or mutates a permanent branch from an obsolete checkout.

Issue automation turns an eligible published issue into one guarded solution branch and linked pull request, which then enters this same path with no exemption. Branch intake opens draft PRs. CI and provenance validate code. Documentation validates the complete docs contract and periodically authors guarded refresh PRs. PR automation aggregates exact-head scans, reviews outside contributions, repairs failures, and resolves conflicts. The merge train squash-merges to develop and rebase-merges promotions to main. Release publishes develop builds to TestPyPI and main builds to PyPI. Release surfaces publish branch-specific ProperDocs and GHCR artifacts; repository profile maintains description, homepage, topics, and verifies releases, deployments, and packages. If a trusted post-merge workflow fails on develop or main, release repair reviews its logs and returns a fixable problem through an ordinary guarded PR.

CI and Release are not managed templates; vibey-gh install never writes them, because every repository's build, test, and publish steps differ. They must exist under those exact names, because github-release.yml, release-surfaces.yml, and release-repair.yml all key off a workflow_run named Release (and release-repair.yml also watches CI). A Release workflow that runs on develop/main, derives the version with vibey-gh version --apply, builds, and publishes through the testpypi/pypi trusted-publishing environments is what the rest of this reference assumes exists.

Issue automation

Issue automation runs on issues (opened, reopened, labeled), workflow_dispatch with an issue number, and — when [issue_automation].retain_schedule_backstop is set — a twice-daily recovery sweep that dispatches only the issues vibey-gh issue-automation list-eligible reports.

The evaluate job holds contents: read and issues: read. It runs trusted default-branch workflow code, installs the published vibey-gh package (never the adopting repository's own package), and emits one structured decision: solve, skip, or blocked, each with a stated reason. Only solve starts the privileged solve job; blocked labels and comments once through the exhausted job.

The solve job checks out trusted automation under automation/ and the configured base branch under target/ with persist-credentials: false. A trusted step renders the issue into briefing/issue.md; the pinned Claude Code Action then runs from a disposable credential-free Git context with Read,Glob,Grep,Edit,Write and no Bash, gh, or Agent tool, and is told the briefing is an untrusted report rather than an instruction. It edits files only.

Publication is a separate trusted step that validates the branch against the configured namespace and the permanent branches, normalizes provenance headers with vibey-gh check --ci --apply, commits with the repository's own configured trailer from vibey-gh trailer, pushes one non-empty-source refspec, and opens one linked pull request containing Closes #N. It publishes nothing when the agent returned solved=false or produced no diff. branch-intake.yml is rendered to ignore the same namespace so the two never race. From there the proposal is an ordinary pull request with no exemption from scans, review, repair, or the merge train.

Attempts are budgeted per issue content fingerprint and stored in one machine-readable issue comment, so a redispatch of unchanged text is a no-op and an edit starts a new lineage.

Conversation

Conversation runs on issue_comment (created) and pull_request_review_comment (created) against any thread, plus workflow_dispatch with a subject number and an optional exact comment ID. The cheapest possible loop guard runs before a runner is even claimed: github.event.sender.type != 'Bot', combined with a check that the triggering comment contains the configured mention (workflow_dispatch is exempt, since a human explicitly named the subject). This is the one failure mode unique to conversation — a reply that mentions the trigger again would otherwise recurse and bill indefinitely — so it is excluded before anything else is considered.

The evaluate job holds read-only contents: read, issues: read, and pull-requests: read. It runs trusted default-branch workflow code, installs the published vibey-gh package, resolves the subject and comment ID from either the dispatch inputs or the triggering event, and calls vibey-gh conversation evaluate to compute one of skip, blocked, answer, or act with a stated reason. evaluate checks, in order: the automation's own identities (never answered), whether conversation is enabled, whether the comment mentions the configured trigger, whether the thread is open, whether this exact comment was already answered, whether the author is trusted or respond_to_untrusted is set, and whether the thread's interaction budget is exhausted. Only answer or act starts the privileged respond job.

The respond job checks out trusted automation under automation/ and the thread's branch (a pull request head) or the default branch (an issue) under target/, both with persist-credentials: false for the read-only pull-request case. A trusted step renders the thread into briefing/thread.md with vibey-gh conversation context; the pinned Claude Code Action then runs from a disposable credential-free Git context with Read,Glob,Grep,Edit,Write and no Bash, gh, or Agent tool, and is told the briefing is an untrusted report rather than an instruction. When may_change_files is false — every case except a trusted author on a pull request with changes allowed — it answers only and any edits are discarded. When true, it may also make a clear, bounded change to the pull request, following existing conventions and updating documentation and tests as the change requires.

Publication is a separate trusted step. When files changed and may_change_files was true, it refuses an unsafe or permanent (develop/main) head ref, refuses a cross-repository (fork) head, normalizes provenance headers with vibey-gh check --ci --apply, commits with the repository's own configured trailer, and pushes directly to the existing PR branch — no new branch or pull request is opened, since the change belongs to the thread it answers. The answer is then always posted with vibey-gh conversation reply, noting whether a commit was pushed, whether the request needs a human decision, and whether part of the thread tried to redirect the request, and the interaction is recorded against the thread's budget with vibey-gh conversation record-response. Attempts are budgeted per thread and stored in one machine-readable issue comment, the same vibey_gh.github_state mechanism issue automation uses.

CodeQL

CodeQL runs on push and pull request against develop and main, plus a weekly Monday schedule as a backstop. With security-events: write and read-only contents: read, it runs the immutably pinned github/codeql-action initializer and analyzer against the Python codebase. It is one of the required scan_workflows entries PR automation aggregates before publishing the merge gate.

API drift — not installed, and not yours

API drift (Cloud Agents OpenAPI) is this project's own self-test and is not a managed template. It calls vibey_gh.surfaces.parity() to prove every canonical capability is exposed through all five surfaces — MCP, API, CLI, SDK, and webhook — which is a statement about vibey-gh, not about a repository that installs it.

It used to ship to every adopter and sit in the default scan_workflows, so an adopting repository received a required-looking gate that tested this library rather than their own product, and had to work out for themselves that it should come back out. It now lives in this repository's own .github/workflows/, hand-authored, exactly as ci.yml and release.yml do — what is specific to one repository is that repository's to author.

Conventional Commits

Conventional Commits runs from trusted base-branch workflow code on PR open, reopen, synchronization, and ready-for-review events. It inspects the exact PR head without executing repository code. For same-repository, linear topic branches, it normalizes every nonconforming subject, preserves commit bodies and provenance trailers, and publishes the rewritten history with an exact-SHA --force-with-lease. It refuses forks, merge commits, stale heads, and any branch named by the configured integration or release branch; the literal develop and main names are denied independently as defense in depth. It never deletes a branch. The resulting synchronize event reruns all ordinary scans.

Branch intake

Branch intake runs on every push whose branch is not develop, main, or under the vibey-gh/repair/ or vibey-gh/issue/ namespaces — issue automation and repair publish their own linked pull requests, and intake must not race them. With contents: read and pull-requests: write, it opens exactly one draft pull request against develop for a branch that has no open PR yet. This intentionally runs on every push rather than once per branch name: a branch name reused after its previous PR merged must still get a fresh draft, since a historical closed PR must never suppress intake for the new lineage.

CI

CI and Release are the two workflows vibey-gh install never renders, because every repository's build, test, and publish steps differ; they must exist under those exact names because other release workflows key off a workflow_run named Release (and release-repair.yml also watches CI). CI runs on push and pull request against develop and main with the default read-only token. Its test job runs pytest across Python 3.11–3.13; lint runs Black, isort, Ruff, and mypy, then dogfoods the managed automation by asserting vibey_gh.install.installed() reports no drift between the repository's rendered workflows and its configuration; build builds the wheel and sdist, checks them with twine check, and asserts every managed template and release theme asset is packaged inside the wheel. CI is one of the required scan_workflows entries PR automation aggregates.

Provenance

Provenance runs on push to every branch and on every pull request, with read-only contents: read. It installs the tooling (from source when the repository under test is vibey-gh/vibey-bootstrap itself, otherwise the published package) and runs vibey-gh check --ci, which performs the fingerprint and Conventional Commits verification that is the server-side half of the provenance rule — backstopping the pre-push hook, which lives in a clone and can be skipped with --no-verify or simply never installed. A promotion PR from develop into main checks provenance without rewriting or re-auditing already-admitted history; an ordinary PR checks only the commits it adds, via --commits BASE_SHA..HEAD.

Docs (documentation contract and maintenance)

Docs (workflow file documentation.yml) runs on pull request, push to develop/main, a weekly Monday 07:23 UTC schedule, and manual dispatch. Its contract job holds read-only contents: read and runs vibey-gh check --ci — the same fingerprint-checking entry point Provenance uses — to verify every required documentation surface exists and is current. Its maintain job runs only on schedule or workflow_dispatch, holds contents: write, id-token: write, and pull-requests: write, checks out develop onto a fresh vibey-gh/docs/refresh-<run_id> branch, and runs the pinned Claude Code Action as a comprehensive documentation author restricted to Read,Glob,Grep,Edit,Write. The job fails unless Claude's structured result reports complete=true with zero gaps_remaining; only then does a trusted step commit, push the branch, and open one pull request against develop.

PR automation

PR automation is the aggregation, review, repair, and merge-gating hub. It triggers on pull_request_target (opened, reopened, synchronize, ready-for-review) against develop/main; on completion of every workflow named in scan_workflows (CI, Provenance, CodeQL, Docs, and Conventional Commits by default); on a six-hourly recovery schedule; and on manual dispatch. Top-level permissions are actions: read, checks: read, contents: read, and pull-requests: read, with individual jobs elevating further. evaluate resolves the PR and its exact head SHA and calls vibey-gh pr-automation evaluate to compute an aggregate state (ready, review, repair, conflict, blocked, or pending). review (when state is ready or review) checks out the untrusted head read-only beside trusted automation and runs the pinned Claude Code Action, restricted to Read,Glob,Grep plus a scoped inline-comment tool and read-only gh pr commands, to produce the structured semantic review this repair task itself receives as input. mirror-fork opens a repository-owned replacement PR when a fork needs repair or has a conflict. repair collects exact-head failed-check evidence into diagnostics/, runs Claude with Read,Glob,Grep,Edit,Write and no execution tools, and — only when the branch is still at the expected head — publishes one commit back to the PR branch. resolve-conflict materializes a same-repository merge conflict, lets Claude edit only the conflicting paths, and publishes one resolution commit. escalate labels and comments once when the repair-attempt budget is exhausted.

review-fallback runs only when [pr_automation.fallback].enabled is set, the primary review job produced no verdict at all (not a review that ran and found something), the event is not a fork pull request (trusted_only), and the run is not a dry run. Unlike every other job in this workflow it targets a distinct [self-hosted, vibey-local-gh] runner rather than ubuntu-latest, and holds only contents: read — no secret, and no token capable of mutating the repository. It fetches the exact-head diff with gh pr diff, falling back to a local merge-base reconstruction when GitHub's diff API refuses a pull request beyond roughly 300 changed files, then runs vibey-gh local-review against an Ollama-compatible endpoint (qwen2.5-coder:14b by default) with the diff as the only input: no shell, no tools, and no network beyond the local inference port reach the model. See Configuration for the full field reference and Security for the trust boundary this runner introduces. gate publishes the final PR automation / gate check run for the exact head and, on success, dispatches merge-train.yml. When the primary review returned no verdict and the fallback ran and found nothing blocking, the gate still succeeds but titles the check run PR automation: gate (local fallback) so the weaker signal is never mistaken for the primary review's; when neither produced a usable verdict, it titles the check run PR automation: review incomplete for an operator to resolve.

Every [pr_automation].scan_workflows entry names a workflow_run this aggregation waits on, so each one must be a workflow that runs on pull_request or pull_request_target. A workflow that only triggers on push can never complete for a pull request: state never leaves pending, gate — which requires state != 'pending' — never runs, and the PR automation / gate check-run is never published. Made a required check on the branch ruleset, that is a silent, total, and permanent lockout. vibey-gh check fails on any named workflow that exists but cannot fire for a pull request; a name absent from .github/workflows/ is not an error, since it may live elsewhere or under another name.

Merge train

Merge train runs on completion of PR automation, a weekly Monday recovery schedule, and manual dispatch (optionally scoped to one PR, optionally dry_run). With actions: read, contents: write, and pull-requests: write, it resolves the gated PR and runs vibey-gh merge-train, which squash-merges every currently ready PR into develop.

Branch sync

Branch sync runs on every push to develop, a nightly 37 5 * * * schedule, and manual dispatch with an optional dry_run input. Top-level permissions are read-only contents: read; each job elevates only what it needs. It holds two independent jobs that never run in the same trigger.

The sync job (push or manual dispatch, never schedule; contents: write, pull-requests: write) checks out trusted default-branch automation and runs vibey-gh reconcile-branches, the CLI entry point over vibey_gh/reconcile.py. For every open pull request it classifies the branch by git cherry patch identity against develop: a branch with nothing unique has its PR closed and (when configured) its branch deleted; a branch automation owns and that is behind is rebased onto the new tip, dropping the now-duplicated commits; a contributor's own branch is left untouched and, when behind, either merged forward through GitHub's update-branch endpoint (with the contributor's consent implied by "allow maintainer edits") or left with an explanatory comment. Forks are only ever moved forward, never rewritten, rebased, closed, or deleted. dry_run decides and reports without mutating anything. [branch_sync] and [realign] in configuration control this behavior; see Configuration.

The heal job (schedule only; actions: write, contents: read, pull-requests: write) runs vibey-gh pr-automation self-heal to refill the repair budget of every pull request labeled vibey-gh:repair-exhausted, up to branch_sync.max_self_heals refills per lineage, so a transient outage does not permanently strand a PR that a human has not yet noticed. Each healed pull request then has pr-automation.yml re-dispatched against its exact head SHA, returning it to ordinary review and repair with no exemption.

Promote

Promote (workflow file promote-to-main.yml) runs on completion of Merge train, a weekly Monday schedule, and manual dispatch. With contents: write and pull-requests: write, it runs vibey-gh promote, which compares develop and main by tree content rather than commit count, derives the next version, and opens or reuses a promotion pull request; that PR then goes through the same scans, PR automation gate, and a rebase merge to main as any other change. AUTOMERGE_TOKEN is required here because a ruleset-required approving review cannot be satisfied by the default GITHUB_TOKEN.

Release

Release (not a managed template) runs on push to main and develop with read-only contents: read. Its build job dogfoods vibey_gh.install.installed() before publishing, stamps a --dev version on develop builds via vibey-gh version --apply, and builds the wheel and sdist. testpypi (needs build, develop only) and pypi (needs build, main only) each hold id-token: write and publish through trusted-publishing environments pinned to their respective branch. realign (needs build and pypi, main only, contents: write) runs vibey-gh realign to converge develop back onto main when their trees are content-identical; it never force-pushes over unmerged develop work and skips gracefully when AUTOMERGE_TOKEN is absent. A successful realign then reconciles every open pull request against the rewritten develop, the same as Branch sync; because this job only holds contents: write, that follow-up can fail for lack of pull-requests: write or because GitHub is unreachable, and such a failure is logged rather than failing the job — the realign already succeeded and must stand regardless of whether the follow-up reconciled every branch. This repository's own testpypi/pypi jobs additionally run vibey-gh report-superseded right after each publish step, printing which already-released versions the new one supersedes; see Releases.

GitHub Release

GitHub Release runs on completion of Release (only when it succeeded on main) or manual dispatch with an explicit target SHA. With contents: write, it checks out the exact released commit and runs vibey-gh github-release --target <sha> to create an immutable tag and an idempotent GitHub Release for that commit.

Release surfaces

Release surfaces runs on completion of Release on develop or main, or manual dispatch naming a channel and a source run. Its context job resolves the channel; package (actions: read, contents: read, packages: write) publishes the built wheel and sdist as an OCI artifact to GitHub Packages, tagged with the channel and latest on main; docs (actions: read, contents: read, pages: write, id-token: write) builds a branch-specific ProperDocs site with the managed release theme and deploys it to the shared github-pages environment under a channel-specific path, restoring the other channel's existing site alongside it. When documentation.google_analytics_id is set, the same GA4 measurement ID is injected into every generated page and the channel-picker page; left empty (the default), no analytics script is emitted anywhere.

Repository profile

Repository profile runs on completion of Release surfaces or manual dispatch, with read-only actions: read, contents: read, deployments: read, and packages: read. It reconciles the repository's description, homepage, topics, and collaboration/security settings to the configured values, then — when [rulesets].enabled — checks out the default branch, installs vibey-gh, and reconciles the integration and release branch rulesets from [rulesets] before verifying the public release surfaces are actually live: the Pages homepage responds, at least one release and one deployment exist, the GHCR package is reachable, and develop/main remain protected. Ruleset reconciliation runs before that verification step in the same job, so the branches it protects are already current by the time the check runs. A ruleset the API refuses fails the job with the API's own reason instead of being silently skipped.

Release repair

Release repair runs on completion of CI, Provenance, Release, Release surfaces, or GitHub Release on develop or main, only when that run's conclusion was failure. With contents: write, id-token: write, issues: write, pull-requests: write, and read-only actions/checks, it first confirms the branch is still at the failed SHA (a stale failure is a no-op) and that no repair branch already exists for that run. It checks out the exact failed revision, runs Claude in a credential-free context restricted to Read,Glob,Grep,Edit,Write plus read-only CI-log tools, and — only when the structured result reports fixable=true and the branch is still current — publishes one commit to a new vibey-gh/repair/release-<branch>-<run_id> branch and opens an ordinary pull request that re-enters the same scans, review, and merge train as any other change. It never pushes directly to or deletes a permanent branch.

Automation bootstrap

Automation bootstrap is a manual workflow_dispatch with three required inputs: the PR number, the exact reviewed head SHA, and an explicit authorize boolean. It exists only for the case where privileged workflow code itself is broken and a PR therefore cannot repair its own gate. With contents: write, pull-requests: write, and checks: read, the job verifies that the dispatching actor holds administrator permission; that the PR is open, non-draft, targets develop, and exactly matches the dispatched head SHA; that changed files are confined to workflow, template, or automation-core paths; and that every non-gate check run on that exact SHA — including CodeQL, the API-drift parity check, the Documentation contract, Provenance, Build, and Lint — completed successfully. Only then does it perform an admin --match-head-commit squash merge into develop, bypassing ordinary PR automation review, and delete the source branch, and only when that branch is same-repository and not a configured or literal permanent branch. See Security and Threat model for the full rationale.