Zum Inhalt

Automatisierung

Wie sich dieses Repository selbst pflegt: seine 46 Workflows von GitHub Actions in .github/workflows/ prüfen jede Änderung, machen ein Release aus dem, was main erreicht, beantworten Issues und Pull Requests, suchen nach Schwachstellen und halten das Repository aktuell. Die Website schreibt diese Seite bei jedem Build aus den Workflows, mit dem englischen Kommentar am Anfang jedes Workflows, und bleibt so immer auf ihrem Stand.

Wie sich ein Repository selbst pflegt: copier copy legt aus dem Blueprint ein Repository an. Jede Änderung, deine oder die eines Bots, ist ein Pull Request, der merged, sobald alle Prüfungen grün sind, und der Release-Bot macht aus dem, was auf main ankommt, ein signiertes Release. Renovate, der Blueprint-Bot und der Settings-Bot halten das Repository von selbst aktuell.Wie sich ein Repository selbst pflegt: copier copy legt aus dem Blueprint ein Repository an. Jede Änderung, deine oder die eines Bots, ist ein Pull Request, der merged, sobald alle Prüfungen grün sind, und der Release-Bot macht aus dem, was auf main ankommt, ein signiertes Release. Renovate, der Blueprint-Bot und der Settings-Bot halten das Repository von selbst aktuell.

Was ein Pull Request braucht

Ein Pull Request kommt nach main, sobald jede dieser Prüfungen besteht, wie es die Einstellungen in .github/repository.toml und .github/repository.project.toml verlangen:

Auf einen Blick

Die Zeiten sind UTC. GitHub startet einen geplanten Lauf, wenn es kann: oft einige Minuten später und zu Spitzenzeiten auch gar nicht.

Workflow Wann
Action test jeder Push auf main, jeder Pull Request, jeden Donnerstag um 04:29 UTC, von Hand
Canary jeden Montag um 07:23 UTC, jeder Push auf main, der bestimmte Dateien ändert, von Hand
CI (github-action) jeder Push auf main, jeder Pull Request, jeden Freitag um 04:46 UTC, von Hand
Diagrams jeder Push auf main, der bestimmte Dateien ändert, jeden Donnerstag um 04:02 UTC, von Hand
Docs jeder Push auf main, jeder Pull Request, jeden Montag um 06:39 UTC, von Hand
Links jeder Push auf main, der bestimmte Dateien ändert, jeder Pull Request, der bestimmte Dateien ändert, jeden Mittwoch um 05:07 UTC, von Hand
Lint jeder Pull Request, jeden Freitag um 04:46 UTC, von Hand
Mutation jeden Montag um 01:31 UTC, von Hand, jeder Pull Request, der bestimmte Dateien ändert
Newest Python jeder Push auf main, jeden Donnerstag um 03:41 UTC, von Hand
Property tests jeden Tag um 02:57 UTC, von Hand
Pull request title jeder Pull Request
Workflow test jeder Push auf main, jeder Pull Request
Build the release wenn ein anderer Workflow ihn aufruft
Release gate jeder Pull Request
Release jeder Push auf main, jeden Tag um 05:41 UTC, von Hand
SBOM jeden Freitag um 04:04 UTC, von Hand
Release verification wenn ein anderer Workflow ihn aufruft, jeden Freitag um 05:33 UTC, ein Release, von Hand
After the checks nach 15 Workflows
Area labels jeder Pull Request
Blueprint update jeden Donnerstag um 04:56 UTC, von Hand
Build the image wenn ein anderer Workflow ihn aufruft
Commands Kommentare
Dependabot maintenance jeder Pull Request
Evaluate von Hand
Issue assistant neue und geänderte Issues, Kommentare, von Hand
Issue lifecycle jeden Tag um 06:41 UTC, jeder Pull Request, ein Release, nach 2 Workflows, von Hand
Discussion assistant wenn ein anderer Workflow ihn aufruft
Issue assistant wenn ein anderer Workflow ihn aufruft
Issue lifecycle wenn ein anderer Workflow ihn aufruft
Screenshots jeder Push auf main, nach einem Lauf von Release, jeden Sonntag um 04:45 UTC, von Hand
Update branches jeder Push auf main, jeder Pull Request, alle 6 Stunden um :26, von Hand
Welcome jeder Pull Request
CodeQL jeder Push auf main, jeder Pull Request, jeden Freitag um 04:33 UTC, von Hand
Dependency review jeder Pull Request, von Hand
Findings jeden Tag um 07:17 UTC, jeder Push auf main, der bestimmte Dateien ändert, nach 4 Workflows, von Hand
Fuzzing jeder Pull Request, der bestimmte Dateien ändert, jeden Dienstag um 03:39 UTC, von Hand
OSV-Scanner jeder Pull Request, der bestimmte Dateien ändert, jeder Push auf main, jeden Mittwoch um 05:49 UTC, von Hand
Findings wenn ein anderer Workflow ihn aufruft
OpenSSF Scorecard jeder Push auf main, jeden Dienstag um 03:04 UTC, von Hand
Secret scan jeder Pull Request, jeden Sonntag um 04:12 UTC, von Hand
Workflow security jeder Push auf main, jeder Pull Request, jeden Donnerstag um 05:51 UTC, von Hand
Bot health nach 27 Workflows, jeden Tag um 01:04 UTC, von Hand
Clean-up jeden Dienstag um 05:56 UTC, von Hand
Labels jeder Push auf main, der bestimmte Dateien ändert, von Hand
Labels wenn ein anderer Workflow ihn aufruft
Settings jeder Push auf main, der bestimmte Dateien ändert, jeden Samstag um 06:21 UTC, von Hand

Prüfungen

Sie prüfen jede Änderung, bevor sie main erreicht.

Action test

The templates in templates/, which every repository that uses the action gets, pass actionlint and zizmor. Then the action runs as its users run it, on the runner of the templates and on the two others that the README names, whose images differ, as ubuntu-latest and the free ARM runners do from the runner of the templates: installed into the sample repository and into a copy of this repository, whose set-ups it checks, and behind the egress block of the templates. The legs run side by side, so they add no time to the check, and the leg on the runner of the templates keeps the name of the job, which main requires. The block of the AI's runner in reserve holds, and on a Python that is too old the action stops with its message. The action runs on the runner's own Python, without installing PyYAML: check falls back to yq where the image has no PyYAML, and it runs once with PyYAML hidden on every leg, so that each image's yq really reads the set-up. The commands that only read run against GitHub itself, and every week the GraphQL documents and the REST requests of the script meet GitHub's schema and description of that day, so that a field that GitHub deprecates fails here months before GitHub removes it, and copies that are behind but still pass come in a pull request. The names that keep each engine to reading, such as the inputs of its action and the flags of its command line, meet the versions that the workflows pin, on a pull request that changes an engine and every week, so that an update that renames one fails before a release.

Each part of a job runs also when one before it failed, so that the check reports every failure at once, and the last step of each job lets the PR coach explain each part that failed, from .github/checks.project.toml: in the summary of the check, as its annotation and in the one comment on the pull request, also on one from a fork.

  • Wann: jeder Push auf main, jeder Pull Request, jeden Donnerstag um 04:29 UTC, von Hand
  • Pflichtprüfungen: engine contracts
  • Umgebungen: release
  • Secrets: RELEASE_AUTOMATION_PRIVATE_KEY
  • Quelle: .github/workflows/action-test.yml, aus dem Repo Blueprint

Canary

The path of an issue through the AI, end to end, as every repository that uses the action runs it: a call of the reusable workflow .github/workflows/reusable-issue-assistant.yml that passes the engine's secrets by name, its job analyze with their values from the environment issue-assistant and the variable ISSUE_ASSISTANT_AI of the repository, the engine on GitHub's egress-firewall runner, its structured answer, and apply, which checks that answer. The tests and the Action test reach neither the engine, the outputs of its action, the hosts of the firewall, the secret nor the variables of a caller, and this repository gets few issues, so a broken path would show first as issues without an answer in every repository that uses the action. The job queue measures how long analyze waits for the runner with the firewall, a technical preview, or analyze-in-reserve for the runner that ISSUE_ASSISTANT_AI_RUNNER names in its place, and fails when it waits for longer than 30 minutes.

The issue is tests/fixtures/canary-issue.json, which exists nowhere on GitHub: the input canary of the reusable workflow, which only this repository may pass, gives it to context and apply in place of a real one through ISSUE_ASSISTANT_FIXTURE, which makes apply a dry run whose summary shows the comment it would post. The job event sets no labels for it, so nothing is written to an issue.

Every Monday, after every change on main of what the path runs, and by hand. Only main may use the secret of the environment, so no pull request runs the canary; an update of the engine's action merges on its own once its checks passed (.github/renovate.json5), and the pull request of the next release waits until the latest canary of main passed (.github/workflows/release-gate.yml, decision 0030). docs/architecture.md describes it.

  • Wann: jeden Montag um 07:23 UTC, jeder Push auf main, der bestimmte Dateien ändert, von Hand
  • Secrets: ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, COPILOT_GITHUB_TOKEN, GEMINI_API_KEY, OPENAI_API_KEY
  • Quelle: .github/workflows/canary.yml

CI (github-action)

GitHub Action: the hash-pinned tools of requirements-dev.txt and the checks of scripts/check.sh, the same ones that run locally, and a run of the action with its defaults, as its users run it. The Newest Python workflow runs the checks with the newest Python.

Diagrams

The diagram bot of main. The GitHub app, the stores and other renderers of Markdown show a ```mermaid block as code, so every diagram is a picture of its source in docs/diagrams/, and the check diagrams of each pull request keeps it that way. When main still has a ```mermaid block, a missing or stale picture, or a picture without its source, after the update of the blueprint that brought the pictures, a merge that went around the check or a change of the renderer, this workflow draws the diagrams with scripts/diagrams.sh --extract and keeps one pull request with the fix from the branch bot/diagrams, as the release app, which merges itself once every check passes. It runs after every change of main that touches a diagram or a page of Markdown, and every week; when main is fixed otherwise, it closes the pull request. Drawing runs without secrets; only the job of the pull request has the release app, and runs nothing that it drew; without the release app, the run warns and names the command that fixes main. A failed run opens an issue, which the next weekly run closes once the bot passes again.

  • Wann: jeder Push auf main, der bestimmte Dateien ändert, jeden Donnerstag um 04:02 UTC, von Hand
  • Umgebungen: release
  • Secrets: RELEASE_AUTOMATION_PRIVATE_KEY
  • Quelle: .github/workflows/diagrams.yml, aus dem Repo Blueprint

Docs

The documentation website. MkDocs with the Material theme builds it from mkdocs.yml and the pages in docs/, strictly, so that a link or an anchor that leads nowhere fails: in every pull request as the check docs, and on main, where the same job hands the website that it built to GitHub Pages, and a second one publishes it. A repository without mkdocs.yml or a home page in docs/ has no website, and the check passes, so that it can be required everywhere. Where another workflow publishes GitHub Pages, as the Dashboard of the blueprint does with its dashboard, a run on main only builds the website; in a fork, where the Dashboard doesn't run, Docs publishes it. A pull request keeps the website that it built as the artifact website for a week, which the report of the PR coach links. The tools are the hash-pinned ones of .github/docs-requirements.txt, which the blueprint keeps current, and the files that Material downloads for the website stay in a cache for a week. After the build, lychee checks every link and anchor of the pages that were built and the links of llms.txt, the map of the website for AI assistants, blueprint.py site-check what the hooks of the website promise, and axe-core the pages in the light and the dark scheme, at the width of a desktop and of a phone, for what WCAG 2.2 A and AA ask, also that no page scrolls sideways on a phone, with the locked tools of .github/a11y/: on a pull request those that differ from main, by the digest that main keeps in the cache, and on main and every week every page. A serious or critical violation fails the check, unless .github/a11y-accepted.toml accepts it with its reason. The job that publishes the website signs its provenance, and the job website, which holds no token, asks the published website for its pages.

The link bot. lychee checks the links of the documentation, and the anchors that they lead to, also in the README of another repository, on every change of a Markdown file or of a page of HTML in docs/, and every week, since sites move without a change here. A pull request checks the documents that it changes, so that a site that is down for a moment fails only the pull requests that link to it; one that changes the rules or lychee itself, such as an update of its version in .github/lychee.sh, or moves or deletes a file checks every document, as main and the weekly run do. The answers of the sites stay in a cache for a day. A broken link fails the check of a pull request; the weekly run keeps one issue with the broken links open until they are fixed, and closes it then. lychee.toml holds the rules, .lycheeignore the exceptions of this repository. The entry in the changelog that most pull requests bring, in CHANGELOG.md or in a fragment of changelog.d/, starts no check on its own; the weekly run checks the links of the changelog.

  • Wann: jeder Push auf main, der bestimmte Dateien ändert, jeder Pull Request, der bestimmte Dateien ändert, jeden Mittwoch um 05:07 UTC, von Hand
  • Quelle: .github/workflows/links.yml, aus dem Repo Blueprint

Lint

The checks every repository of the blueprint shares: the workflows, the license of every file (REUSE), the Markdown of every document with hints at its spelling and style, the pictures of its diagrams, the sign-off of every commit (DCO), the set-up of the issue assistant and a notice for each changed file of the blueprint. In every pull request, not after a merge: main takes a pull request only when it is up to date, so a merge gives main the files that the pull request passed with. And each week on main, for what no commit changes, such as a new rule of a tool: it fails here and repairs itself through the fix bot, not in the next pull request.

Mutation

The mutation tests. Every week they change the code in thousands of small ways (mutants) and run the tests against each: a mutant that no test notices shows a line that the tests run but don't check. mutmut does it for Python, Infection for the PHP of a Nextcloud app. The plan splits the Python into parts of about the same number of mutants, each a job of its own, so that a large project finishes within the limits of GitHub. mutmut first runs the whole suite once with trampolines that record which tests reach each function, its stats, which takes ten times as long as the tests: one job collects them, every part loads them and runs only its mutants, and a test that fails without any mutant stops the run there, in one job. The report puts the parts together into one score, lists first the survivors that change the logic, with their changes, and keeps the details as an artifact; for Infection it reads the Covered Code MSI and the escaped mutants of its logs. A low score fails nothing, a run that measures nothing fails, with the tests that failed without any mutant; a score of the default branch that drops below the best of the runs before opens one issue, which closes once a run is back. A pull request that changes how the mutants run collects the stats and tries a sample of the mutants in one part, Infection the mutants of a few files, and shows a defect as a red check. That check isn't required: a pull request that merges itself, such as an update of mutmut, doesn't wait for it.

Newest Python

The checks of scripts/check.sh with the newest release of Python, which warns early of what the next Python of the runners breaks: after every change of main and every week. check-latest takes it from actions/python-versions as soon as it is out, not the older Python that the image of the runner keeps in its cache. Not in pull requests: a new Python breaks main and every pull request alike, and no pull request waits for this check. A workflow of its own, so that its warning leaves the CI of main green, whose coverage the report of the PR coach compares every pull request with. Since no pull request shows the warning, a failure keeps one issue open, which names the Python that failed and which the weekly run closes once the checks pass again.

Property tests

The property tests with new random inputs every night, beyond the fixed inputs of the CI. A failure shows its seed in the summary; run the workflow by hand with that seed to replay it.

Pull request title

Pull requests are squashed into one commit named after their title, and the release bot builds the version and the changelog from these names. So the title must be a Conventional Commit; its type also sets the label of the pull request. A pull request that changes something for users, a feat, fix or perf, also says so in a fragment of the changelog, a new file in changelog.d/, or under Unreleased in CHANGELOG.md, which becomes the notes of the release.

The check signed commits is here because this event starts on every push, also from a fork whose other workflows wait for the approval of a maintainer, and costs only a question to the API: where the rules of the base branch require signed commits, it fails for each commit of the pull request without a signature that GitHub verified, as GitHub then blocks the merge. It stays out of the required checks: GitHub's own rule already blocks that merge, and a required check would change the settings of every repository for nothing (decision 0098).

The bot for replaced commits is a step of that job for the same reason: the run of a commit that a newer push replaced tells nobody anything, yet it holds a runner of the account, and this job runs on every push anyway, so the bot needs no runner of its own (decision 0108). It cancels only runs of the checks whose commit no open pull request has as its head; the branch bot does the same for the pull requests that merge.

Workflow test

The reusable workflows in .github/workflows/reusable-*.yml, which every repository that uses the issue assistant calls at the commit of a release, run as such a repository calls them, as dry runs. The tests and actionlint only read them, the Action test runs the action by itself, and the Canary calls only the workflow of the issues, only on main and with the engine's secret: a wrong needs, if, output or permission of a job, or a checkout of the wrong issue assistant, would show first in those repositories, after a release.

Each job below calls one reusable workflow of the commit, with the permissions of its template and dry_run: the labels, the findings and the lifecycle in full. The issues and the discussions with the input smoke, which only this repository may pass, since a pull request is no event of theirs: the job event takes the issue of tests/fixtures/canary-issue.json, or the discussion of tests/fixtures/smoke-discussion.json, analyze and analyze-in-reserve are skipped, and apply checks the answer of tests/fixtures/smoke-answer.json, or of tests/fixtures/smoke-discussion-answer.json, in place of the engine's; the engine itself is the Canary's. On a pull request from a fork GitHub gives every job a token that can only read, which a dry run needs.

A called job that its condition skips passes as well as one that runs, so the last job, "reusable workflows", the check that main requires, reads the jobs of its run with scripts/workflow_test.py: each job passed, with the step that writes the plan of its dry run, or was skipped where its call has to skip it. GitHub lists the steps of a job some time after it ends, so the script reads the jobs again for up to five minutes while one is listed too early. A pull request that changes nothing that the dry runs run or read skips the calls, and the check passes in seconds. docs/architecture.md describes it.

Releases

Sie machen aus dem, was main erreicht, ein signiertes Release, liefern es aus und prüfen es so, wie seine Nutzer es können.

Von einer Änderung zum Release: Ein Pull Request mit dem Titel fix, feat oder feat! merged in main, sobald alle Prüfungen grün sind. Der Release-Bot hält einen Release-Pull-Request mit der nächsten Version und dem Text der Fragmente und von Unreleased. Sein Merge signiert zuerst seinen Tag, im nächsten Lauf des Release-Bots, baut dann das Release isoliert, sobald der Tag geprüft ist, signiert und veröffentlicht es, liefert es aus und prüft es, sofort und jede Woche. Mit BETA_CHANNEL wird außerdem jede Änderung für Nutzer zu einer Beta.Von einer Änderung zum Release: Ein Pull Request mit dem Titel fix, feat oder feat! merged in main, sobald alle Prüfungen grün sind. Der Release-Bot hält einen Release-Pull-Request mit der nächsten Version und dem Text der Fragmente und von Unreleased. Sein Merge signiert zuerst seinen Tag, im nächsten Lauf des Release-Bots, baut dann das Release isoliert, sobald der Tag geprüft ist, signiert und veröffentlicht es, liefert es aus und prüft es, sofort und jede Woche. Mit BETA_CHANNEL wird außerdem jede Änderung für Nutzer zu einer Beta.

Build the release

The build of a release, called by the release workflow only: it packages the release, writes the SBOMs of what it ships, the licenses of its third-party components and the advisories that don't affect it, attests the signed provenance of every asset and attaches all of it to the draft. As a reusable workflow of its own, it is isolated from the rest of the release workflow, and the provenance names it as the build, as SLSA Build Level 3 asks; verify-release.yml checks that. A project that ships something of its own, such as the zip of a browser extension, builds it with its scripts/release-assets.sh, in a job of this workflow that may write nothing, and the release attests and attaches it like every other asset.

Release gate

The pull request of the release bot brings what is on main to every repository that uses the action. An update of an engine merges on its own once every required check of its pull request passed, and no check of a pull request runs the AI with a key: only main may use the engine's secret. The Canary (.github/workflows/canary.yml) runs the AI's whole path with it on main, after every change of what it runs, so the release waits for the Canary instead of a person who watches it (decision 0030). The job canary, a required check of .github/repository.project.toml, runs scripts/release_gate.py on the release's pull request: it waits while a Canary of main runs, and passes only when the latest one passed. On every other pull request GitHub skips the job, which counts as passed, and starts no runner for it. docs/architecture/dry-runs.md describes it.

Release

The release bot. release-please keeps a pull request for the next release, up to date with main. Its version follows from the Conventional Commit titles merged since the last release (fix: a patch, feat: a minor, ! or BREAKING CHANGE: a major version) and is decided anew with every merge. What the pull requests wrote in the fragments of changelog.d/ and under "## Unreleased" of CHANGELOG.md becomes the section of the release, and the fragments leave with it; without such text, the section lists the pull requests. Merging the pull request creates the release as a draft, on a tag that this workflow signs first, and the build checks the tag before anything else. The jobs below attach the package, its SBOMs (SPDX and CycloneDX), the licenses of its third-party components, the advisories that don't affect it (OpenVEX) and its signed provenance, write the notes, make the release public, announce it in the discussions, and then deliver it where the repository variable PUBLISH_TO says: pypi, npm, ghcr, hacs, nextcloud-appstore, github-action, chrome-web-store, which publish-store.yml takes over once this workflow has passed, cloudflare-workers, which Workers Builds deploys outside GitHub, or none. Last, verify-release.yml checks the release as its users can. A release that only updates dependencies merges itself once its checks pass, once a day, or at once with a fix of a vulnerability.

  • Wann: jeder Push auf main, jeden Tag um 05:41 UTC, von Hand
  • Umgebungen: appstore, npm, pypi, release
  • Secrets: APPSTORE_TOKEN, RELEASE_AUTOMATION_PRIVATE_KEY
  • Quelle: .github/workflows/release.yml, aus dem Repo Blueprint

SBOM

A software bill of materials of the whole repository in SPDX, every week, with the tools of its checks, its website and its workflows, as an artifact of the run. A release carries the SBOMs of what it ships instead (build-release.yml), which its users' scanners read. Not for every change: no pull request reads it, and the dependency review checks what a pull request brings in.

Release verification

The release verification bot. It checks a release the way its users can: every asset carries the signed provenance of this repository's release workflow, both in GitHub and in the attached bundle; the SBOMs are attached and describe what the release ships, by its name and version; the release is immutable and its commit signed; and where the repository variable PUBLISH_TO delivers it, the same release is there. The release workflow runs it after every release, it checks the latest release every week, and a release that anybody else publishes, by hand or with a token, at once. A failed check fails the run, which the bot-health bot reports in an issue.

Bots

Sie beantworten Issues und Pull Requests, beheben, was ein Befehl beheben kann, und bringen die Pull Requests voran.

After the checks

The bots that act on a finished run of the checks and of the release. One workflow for all, so that every run starts one run after it, not one for each bot that mostly has nothing to do. None checks out or runs the code of a pull request.

The flaky-test bot: when a run of the tests fails for the first time, or a job of it runs out of time, it runs the failed jobs once more. A job that passes then failed without a change of the code: its test is flaky, and the bot reports it in one issue, with the step, the test and the error that failed, so that it gets fixed instead of failing pull requests at random: a comment for each run, and in the body how often each job and test flaked, and when it last did. The test is one that pytest names in the log, or else the step or test that the log names last before the failure, after the answer test_marker of the blueprint, such as "Browser step:" before each step of the tests of a browser. A job that fails again is a real failure and stays red, and so does one that failed the same way for the commit before: running it again would only keep a runner busy. A run whose failed jobs ran no step, which GitHub couldn't start, as in its outage of 9 November 2026, it leaves alone with a notice: another try while GitHub fails would only fail and mail again, and a bot that GitHub keeps failing ends with a notice as well (decision 0136). A pull request names its jobs and steps and writes its logs, so the issue shows them only as code, and the branch of a fork not at all.

The start of the branch bot: a required check of a pull request that failed for good, also of one from a fork, moves the line of the branch bot in update-branches.yml on to the next pull request, so a job of its own starts that workflow then, with the run that failed. Before, the end of every check started a run of Update branches by itself, and nearly all of them skipped, each with a run of Bot health behind it (decision 0151).

The bot for cancelled checks: a newer run of a workflow cancels the one still running for the same pull request, and that of a check or a scanner for the push to main before. GitHub doesn't always create the runs in the order of the commits, so a late run for an older commit can cancel the run for the head of the pull request, whose required checks then stay cancelled and block the merge, or that for the head of main, whose coverage, alerts of code scanning and fixes the bots read. When a run for the head of an open pull request or of main was cancelled that way and no newer run of its workflow for the same commit exists, the bot starts it again. A run that a person cancelled, or one whose commit a newer push replaced, stays cancelled. The quick checks avoid the race: their runs for different commits never cancel each other. A job of the first attempt that ran out of time, as one behind Harden-Runner can even after its last step, runs once more, where the flaky-test bot doesn't do it.

A run of a commit that a newer push replaced, or whose pull request has closed, starts no job here that would only find that out, as the concurrency of a workflow and the bot for replaced commits cancel such runs by the hundred on a busy day. The event names the open pull requests of the branch of a run from this repository, so that their heads tell it before a runner starts; a run from a fork names none, and its jobs ask GitHub, as before.

The bot for failed releases: when the release that a merge started fails, such as at a push of its tag that GitHub refused for a moment, it runs the failed jobs once more, where they stopped, instead of leaving the release and its rollout to a person. The release workflow takes up a tag that it pushed already. A release that a person or another bot already runs again, or ran again, is theirs: the bot leaves it alone, and so it does a release that GitHub couldn't start, which the scheduled run of the release takes up.

The PR coach: after every run of the checks of a pull request, one comment on it explains each check that failed: what it found, why that matters and how to fix it, with the commands to run, from the explanations of .github/checks.toml and .github/checks.project.toml. It works for a pull request from a fork as well, whose own runs can't write to it. The comment follows every push and turns into a short all-clear once every check passes. A check that was cancelled, as a job that ran out of time is, hasn't passed either, and commits that block the merge, because the rules of its base branch require a verified signature that they lack, allow no all-clear and no word about the merge, also before their check signed commits has ended: the coach asks GitHub for them itself. It reads the check runs and their annotations from the API and shows their text only as code, and waits up to three minutes for the checks of other apps, such as the alerts of code scanning, which end after the last workflow. The scanners, which run in the pull requests that change what they read, start it as well, and so does the check of the rules of Renovate where Renovate runs in the repository. On a pull request of a person, the comment also says what the pull request makes: the next version, from its title and the release-please files of main, and the entry that it adds to the changelog; the coverage of its tests against that of main, file by file, from the coverage reports that the checks keep as the artifact "coverage", which a pull request from a fork writes as it likes; the website that the check docs built, with the pages that it changes; and the part that a workflow of the project adds, such as one of visual tests: the report.md of its artifact pr-report-<name> for the head, under the title that [report.<name>] of .github/checks.project.toml of main gives it, with its text only as code. A pull request whose checks never failed gets the comment only when it has something of this to say, and one of a bot never.

The fix bot: a check whose findings a command fixes, such as the format of the code, the whitespace of a text file or the rules of markdownlint, runs the commands of autofix in .github/checks.toml when it fails, on the head of the pull request or on main, and keeps the files that they changed as an artifact fixes-*. A check in any workflow of the list below may do so, also in one of the project's own, and no other workflow can: the list of main decides. Once the checks of the commit whose workflows on main keep fixes have ended, the bot takes these files as data: on a pull request from a branch of this repository, also one of Renovate or another bot, it commits them as one commit onto the branch, as the release app, so that the checks run again; on one from a fork, which this bot never pushes to, it suggests them at their lines, at most ten in one review, never one twice, and a person with write access asks for the commit there with /fix, in commands.yml; on main, it keeps one pull request from bot/self-heal with them, which merges itself, and closes it once main needs no fix. Lint and the CI also run on main each week, by their schedule or by hand, as bot health starts a schedule that GitHub missed, so that what no commit changes, such as a new rule of a tool, repairs itself the same way before it fails the next pull request; a weekly run that passes starts no job here, so a quiet week takes no runner of the bot. blueprint.py of main lets through only text files that the commit has already, outside .git and the workflows. It commits at most twice in a row onto its own commits, and leaves a pull request with the label no-bot-fixes alone. When the bot fails, it says so on the pull request; on main, it keeps one issue open until it passes again. A check still running after the wait, such as long end-to-end tests, leaves the commit to the job after its own end, however it ends: so that job starts after every run of a check for the head of a pull request from a branch of this repository, and ends at once when the commit has no fix. A commit before would cancel that run and use up one of the two commits. A fork and main act on what has ended, since a suggestion and the pull request of main cancel no run.

The title and the entry of the changelog fix themselves in a job of their own, after a failed run of the check of the title, on a branch of this repository: the bot sets the title that the PR coach suggests when only its form differs, as the type and the breaking mark decide the version, and commits one draft of the missing entry from that title, once for each pull request. The draft is the one new file that a bot of the fixes adds, which blueprint.py of main names and writes itself in changelog.d/. No artifact and nothing of the code of a pull request reaches this job.

The diagram bot: when the check diagrams of Lint finds a ```mermaid block, which the GitHub app shows as code, or pictures of diagrams that differ from their sources in docs/diagrams/, in a pull request from a branch of this repository, it commits what scripts/diagrams.sh --extract changed in the check onto that branch, as the release app, so that the checks run again, and says in a comment which blocks became pictures. blueprint.py of main takes only sources, SVG pictures and pages of Markdown from the artifact "diagrams". When the bot can't commit, it says so on the pull request, with the command. A pull request from a fork keeps the failing check, with the command that fixes it.

Area labels

The labeler bot. It gives a pull request the labels of the areas whose files it changes, by the paths in .github/labeler.yml, and takes them away when it no longer changes them. The type label comes from the title check.

Blueprint update

The blueprint bot. Every week, and on demand, it brings the repository up to the latest published release of the blueprint with copier update, once it has verified that the release workflow of the blueprint made that release, and keeps one pull request for it as the release app, so that its checks run: a newer release moves that pull request on. Without conflicts, it merges itself once every check passes; conflicts stay in it as markers for the maintainer, with auto-merge off. Once the maintainer commits to its branch, the bot leaves the branch alone. The repository variable BLUEPRINT_AUTOMERGE set to off makes every update wait.

Build the image

The build of the container image of a release, called by the release workflow only, once the release is public and where PUBLISH_TO is ghcr: it builds the image of the signed tag for linux/amd64 and linux/arm64, pushes it to the GitHub Container Registry with the tags of the version and its SBOM, and attests its signed provenance there. As a reusable workflow of its own, it is isolated from the rest of the release workflow, as build-release.yml is for the other assets, and the provenance names it as the build, as SLSA Build Level 3 asks; verify-release.yml checks that.

Commands

The commands that a person gives a pull request in a comment, as its first line.

/fix: the fix bot commits the fixes of the checks of the head of the pull request onto its branch, as the release app, also onto the branch of a fork whose author allows edits by maintainers, which the fix bot after the checks only suggests at their lines. Only a person with write access to the repository starts it, as GitHub answers when the command comes; anybody else gets that answer. The bot takes the fixes that the checks of the head kept, the artifacts fixes-* of the workflows of the list of after-checks.yml of main, as data, once those that keep fixes have ended, and blueprint.py of main lets through only text files that the commit has already, outside .git and the workflows. On a fork, it commits only the files that the pull request changes and none that decides what a workflow runs, such as a file of .github/ or scripts/ or pyproject.toml, whose fix stays with a person. Whether GitHub lets the app push onto the branch of a fork isn't settled, so a refusal is no failure: the bot suggests the fixes at their lines, as a fork gets them without the command, and so it does on a fork that allows no edits. One comment answers each command, with what the bot did and why; the label no-bot-fixes stops the bot's own commits, not those that a person asks for. Nothing of the pull request runs here: the job checks out main alone.

Dependabot maintenance

Dependabot keeps only the Features of the dev container (dependabot.yml); Renovate merges its own updates, those of actions pinned to a commit of a branch included. Every update merges on its own once every required check passes, a major one too: the checks are the gate, and one whose checks fail stays open and shows the failure (decision 0150). Updates of runtime dependencies are committed as fix(deps) and so lead to a patch release (see release.yml). Auto-merge is turned on as the release app, as Renovate's is: a merge that auto-merge does with the token of a workflow starts no workflow, so the release bot and the branch bot would wait for their schedules, which GitHub runs as it can, often hours late. The merge of the app starts them at once.

Evaluate

The numbers of docs/accuracy.md: how often the assistant's labels, duplicates and questions match what the maintainers of a repository decided, by the command evaluate, on GitHub in place of a maintainer's computer. Only by hand, since a run costs about $0.20 for each issue with Opus at the prices of the API, from the secret of the environment issue-assistant, which only main may use.

The job replay runs the AI on GitHub's egress-firewall runner, with a read-only token and the engine's secret, and only its tools that read the checkout of the repository. The job publish runs no AI and takes only numbers from the report, which the command accuracy-page checks, into a pull request of the release app. Each run adds its repository to the one open pull request. A repository without a closed issue to replay ends the run with a notice and no report, and publish doesn't run. docs/accuracy.md describes it.

  • Wann: von Hand
  • Umgebungen: issue-assistant, release
  • Secrets: ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, RELEASE_AUTOMATION_PRIVATE_KEY
  • Quelle: .github/workflows/evaluate.yml

Issue assistant

A first analysis of new issues, the labels of the issue forms and the answers that the assistant or the maintainer waits for: https://github.com/Dennis-Otto/issue-assistant

The jobs are the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below. event and apply run no AI; analyze runs the engine of .github/issue-assistant/config.toml with a read-only token and read-only tools on the egress-firewall runner (.github/egress-firewall.yaml), and apply checks its answer before anything is written. The permissions below are the most that any of its jobs gets.

Without the engine's secret in the environment issue-assistant, or with the repository variable ISSUE_ASSISTANT_AI set to "off", only labels and the lifecycle work. The issue assistant's check command keeps this file equal to its template.

A run by hand, also through the REST API, answers an issue that has no comment of its task yet. Someone with write access starts it, and may add an instruction; a maintainer, with the role admin or maintain, may tick override to have the assistant answer again past its one comment. The job event checks the role of the person who started the run, and its summary records every override.

  • Wann: neue und geänderte Issues, Kommentare, von Hand
  • Secrets: ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, COPILOT_GITHUB_TOKEN, GEMINI_API_KEY, OPENAI_API_KEY
  • Quelle: .github/workflows/issue-assistant.yml

Issue lifecycle

Without AI: reminds reporters who were asked for information after 15 days, closes their issue after 30 days without an answer, closes a possible duplicate 3 days after the notice unless someone objected, labels the issues that a merged pull request fixes, and closes them with a link once a release ships the fix. Merges and releases start it at once, and every morning catches what was missed. A fixed issue that a release closes is filed under the release's milestone. The job is the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below; it blocks every host but GitHub's. https://github.com/Dennis-Otto/issue-assistant

Discussion assistant

The jobs of templates/.github/workflows/discussion-assistant.yml, which a repository that answers questions in its Discussions calls at the commit of a release. https://github.com/Dennis-Otto/issue-assistant

event no AI: whether the new discussion gets a first answer: its category is one of [discussions] answer_categories, and the limits of the day analyze the AI engine reads the checkout and a context folder and answers with JSON, exactly as in reusable-issue-assistant.yml, which a test keeps analyze-in-reserve the same steps on the runner of ISSUE_ASSISTANT_AI_RUNNER, behind Harden-Runner, as in reusable-issue-assistant.yml apply no AI: checks the engine's answer and is the only job that writes, one comment on the discussion, and the only one that may write to discussions

The jobs of the issues can't write to discussions: a called workflow that asks for more than its caller grants doesn't start, and a repository that only moves the pin of issue-assistant.yml grants them only reading. Decision 0018 says why.

The Workflow test, .github/workflows/workflow-test.yml, calls it on every pull request that changes what it runs, with the input smoke, as it calls the workflow of the issues: the job event takes the discussion of tests/fixtures/smoke-discussion.json in place of that of an event, analyze and analyze-in-reserve are skipped, and apply checks the answer of tests/fixtures/smoke-discussion-answer.json in place of the engine's, as a dry run. Every step and value of the smoke test names inputs.smoke, which every other caller leaves false.

Issue assistant

The jobs of templates/.github/workflows/issue-assistant.yml, which every repository that uses the issue assistant calls at the commit of a release. A new release reaches a repository as a move of that pin, without running install again. https://github.com/Dennis-Otto/issue-assistant

event no AI: labels, the /assistant commands of a comment and the next task; for a run by hand, the role of the person who started it, and the override of the one-comment rule that only a maintainer may give; for the task backlog, the issues that the caller's job backlog analyzes, one call of this workflow with the input backlog_issue for each analyze the AI engine of .github/issue-assistant/config.toml reads the checkout and a context folder and answers with JSON; read-only token, read-only tools, egress-firewall runner (the caller's .github/egress-firewall.yaml) analyze-in-reserve the same steps on the runner of the caller's variable ISSUE_ASSISTANT_AI_RUNNER, in place of analyze, with the same hosts behind Harden-Runner apply no AI: checks the engine's answer and is the only job that writes; it checks an override again before it posts a second comment

event and apply block every host but GitHub's with Harden-Runner. A called workflow runs in the caller's repository: its event, its variables, its environments, its runners and its firewall policy. Each job runs the issue assistant of this workflow's own commit, which it checks out next to the repository; decision 0015 says why.

The Canary of the issue assistant, .github/workflows/canary.yml, calls it as every repository does, with the input canary: the issue of tests/fixtures/canary-issue.json in place of that of an event, no labels, apply as a dry run, and a failure wherever a repository's run would skip the AI. Every step and value of the canary names inputs.canary, which every other caller leaves false; docs/architecture.md describes it.

The Workflow test, .github/workflows/workflow-test.yml, calls it on every pull request that changes what it runs, with the input smoke: the same issue, no AI, and apply as a dry run of the answer of tests/fixtures/smoke-answer.json in place of the engine's. Every step and value of the smoke test names inputs.smoke, which every other caller leaves false too.

  • Wann: wenn ein anderer Workflow ihn aufruft
  • Umgebungen: issue-assistant
  • Secrets: ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, COPILOT_GITHUB_TOKEN, GEMINI_API_KEY, OPENAI_API_KEY
  • Quelle: .github/workflows/reusable-issue-assistant.yml

Issue lifecycle

The job of templates/.github/workflows/issue-lifecycle.yml, which every repository that uses the issue assistant calls at the commit of a release. Without AI: reminds reporters who were asked for information, closes their issue without an answer, closes a possible duplicate unless someone objected, labels the issues that a merged pull request fixes, and closes them with a link once a release ships the fix. The job blocks every host but GitHub's with Harden-Runner and runs the issue assistant of this workflow's own commit (decision 0015). https://github.com/Dennis-Otto/issue-assistant

Screenshots

The screenshot bot. A repository turns it on with scripts/screenshots.sh, which renders its pictures in place, wherever the documentation, the stores or the social preview take them from, and lists in .github/screenshots-paths.txt the files whose change can change them, as the paths of a workflow; without the script, every run ends after its plan. After a change of main that touches a file of the list, after every release, whose version a picture may show, and every week, the plan starts a run that renders, as the branch bot and a person do by hand. That run renders the newest main, one at a time, without secrets, with Docker, the whole history and the tools of the website in .venv-docs as CONTRIBUTING.md sets them up; the script of a new repository photographs the website and, by its kind, the integration in Home Assistant or the app in Nextcloud, each in Docker. .github/screenshots.toml, which belongs to the project, can name shards, which render side by side on runners of their own, each with SCREENSHOTS_SHARD set to its name, the files besides pictures that the script renders, such as a recording that a page plays, and the hosts that the jobs that render may reach, of which Harden-Runner then lets through no other (decision 0120); it can also leave hosts out of the wait, give the script a time limit and name the folder that a failed shard keeps (decision 0124). It compares each picture that changed with the one of main by its pixels: a picture whose pixels stayed the same keeps its file, so that a new encoder, browser or runner changes nothing; for each other one of the same size and frames, it draws the changed pixels in red into diff/ of the artifact, and the place of the change before and after into comparison/, which the bot never commits (decisions 0131 and 0149). When pixels changed, the job collect puts the shards together, and the bot keeps one pull request from the branch bot/screenshots, as the release app, which merges itself once every check passes, and closes it when main looks as rendered without it. When main changed a picture or a page of the pull request while it rendered, as when the pull request before merged, it starts itself anew rather than open one that conflicts; the branch bot starts it for one that conflicts later (decision 0118). The bot commits only pictures and the files of the settings, by plain paths, outside .git and the workflows, and for a picture that came out at another size the width and the height that the pages of main name for it, so that the pull request passes a check of those sizes; without the release app, the run warns and keeps the pictures as an artifact. A failed run keeps an issue of the bot-health bot open until the jobs that failed pass again in a run; a push that only plans leaves it open.

Update branches

The branch bot. main only takes pull requests that are up to date with it, and auto-merge doesn't update a branch by itself. So only one pull request can merge next, and each merge leaves the others behind again: bringing all of them up to date after every merge ran the checks of every waiting pull request for the one that merged. The bot keeps a line instead, the pull requests that wait for auto-merge in the order in which it was turned on, and brings only the first one up to date that can merge, as the release app, so that its checks run again and it merges once they pass. While its checks run, the others wait; its merge starts the next run, and so does a required check of it that fails for good, through the bots after the checks, which start this workflow then and only then: GitHub would create a run here after the end of every check, which skipped in all but a few (decision 0151). Turning auto-merge on starts one at once. A pull request whose required check failed waits for a fix and leaves its place to the next one. One that conflicts with main gets the label merge-conflict and one comment. The label goes once it no longer conflicts; the comment stays for the history, so a later conflict brings back only the label. One of a bot that builds its branch anew from main, the screenshot bot, the picture bot or the issue assistant sync, gets the label and no comment, and the bot starts the workflow of that bot once for each conflict (decision 0118). A request that GitHub refuses is a warning about that pull request, and the bot goes on with the next one. The release bot keeps its own pull request current. Renovate's pull requests take their place in the line as well, which spares them the wait for its next run: Renovate commits as the release app too, so it still takes the branch for its own; one that conflicts with main it builds anew itself. A pull request from a fork takes its place as well, once its author allows edits by maintainers; without that, or with a commit that the rules of main refuse for its signature, it waits outside the line, and the summary says so. GitHub holds the runs of each new head of a fork for an approval, so such a head isn't in flight: it waits for a person and leaves its place to the next one, and the bot doesn't update it again until someone approved. Only a head that the bot made itself, on top of commits that a person approved, gets its runs approved by the bot, in the summary of the run, since nothing new from the fork runs then (decision 0099). Every merge leaves the runs of its pull request behind, and every update the runs of the commit that it replaced: after the line, the bot cancels those that no open pull request has as its head any more, as this job runs anyway (decision 0108). The bot checks out main alone, for blueprint.py, which holds the logic, and runs nothing of a pull request.

Welcome

The welcome bot: a person's first pull request in this repository gets a comment with what helps it along. New issues get the issue assistant's analysis instead.

Sicherheit

Sie suchen nach Schwachstellen, verratenen Secrets und riskanten Abhängigkeiten.

CodeQL

The code analysis of GitHub. CodeQL reads the code of every language of this repository and its workflows with the queries of security-extended, for every pull request, every push to main and every week, and sends what it finds to code scanning, where a new alert of a pull request stops its merge. A private repository without GitHub Code Security has no code scanning: there the settings bot sets the variable CODE_SCANNING to off, and the check passes without an analysis, because the terms of CodeQL allow it on private code only with GitHub Code Security or Advanced Security.

Dependency review

The review of the dependencies that a pull request adds or changes: one with a known vulnerability of moderate severity or more, or with a license outside the list of .github/dependency-review.yml, fails it. An advisory that the repository accepts goes into allow-ghsas there, with its reason. Started by hand, it compares two commits. A private repository without GitHub Code Security has no dependency review: there the settings bot sets the variable DEPENDENCY_REVIEW to off, and the check leaves the vulnerabilities of the lock files to OSV-Scanner. In a pull request of Renovate's weekly refresh of the lock files, which merges by itself only from versions at least a week old, it fails on a younger one as well (decision 0137).

Findings

Without AI, every morning, after each scan of code scanning on main and when the accepted findings change: dismisses the code scanning alerts that .github/findings.toml accepts, with its reason, and fails while any other alert is open. The run names an open alert by its number and link only, which only maintainers can follow; nothing becomes a public issue. The job is the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below; it blocks every host but GitHub's. https://github.com/Dennis-Otto/issue-assistant

Fuzzing

Coverage-guided fuzzing with Atheris of every target in fuzz/: a minute each in every pull request that changes the code, the targets or the tools, and every week 25 minutes shared by all targets, so the job ends within its timeout however many targets there are. Not after a merge, which gives main the tree that its pull request fuzzed. A finding fails the run, with the input that caused it in the log.

OSV-Scanner

Every lock file of the repository against the OSV database of known vulnerabilities: in every pull request that changes a lock file the vulnerabilities that it brings in, and on main and every week all of them. Findings go to code scanning, where the Findings workflow keeps them fixed or accepted; osv-scanner.toml lists those that the project accepts, each with its reason, such as an advisory in a test base that pins its dependencies. Dependabot doesn't read that file: on main, every week and by hand, the job dependabot alerts closes each Dependabot alert that an acceptance covers, with its reason and its end, and opens again each one that it closed once the acceptance is gone. It also warns of each acceptance that ends within two weeks and keeps one issue that names them, so that the end is handled before the checks turn red.

  • Wann: jeder Pull Request, der bestimmte Dateien ändert, jeder Push auf main, jeden Mittwoch um 05:49 UTC, von Hand
  • Umgebungen: release
  • Secrets: RELEASE_AUTOMATION_PRIVATE_KEY, SETTINGS_APP_PRIVATE_KEY
  • Quelle: .github/workflows/osv-scanner.yml, aus dem Repo Blueprint

Findings

The job of templates/.github/workflows/findings.yml, which every repository that uses the issue assistant calls at the commit of a release. Without AI: dismisses the code scanning alerts that .github/findings.toml accepts, with its reason, and fails once for every other alert, in the first run that finds it open, and again only when it opens again; the runs after it warn of it (decision 0026). After the scan of a pull request of the repository itself, it dismisses the alerts of the pull request that .github/findings.toml of the default branch accepts, whose review threads would block the merge, and fails for none (decision 0028). The run names an open alert by its number and link only, which only maintainers can follow; nothing becomes a public issue. The job blocks every host but GitHub's with Harden-Runner and runs the issue assistant of this workflow's own commit (decision 0015). https://github.com/Dennis-Otto/issue-assistant

OpenSSF Scorecard

The OpenSSF Scorecard: it rates the security practices of the repository, such as its branch protection, its pinned actions and its signed releases, after every push to main and every week, publishes the score for the badge of the README and sends each finding to code scanning.

Secret scan

Gitleaks looks for secrets in the commits of every pull request, and every week in the whole history of every branch. Not after a merge, which brings only the commits of a pull request that it scanned; GitHub's secret scanning with push protection guards every push as well.

Workflow security

zizmor checks every workflow for the ways a workflow gets attacked: template injection, permissions wider than needed, credentials that persist, unpinned actions and dangerous triggers, and asks GitHub for the advisories of the actions that they pin. In every pull request into main, also the release pull request, whatever it changes: the rules of main stop a merge while the pull request adds an alert of zizmor, and while its analysis is missing. On main after every merge and every week, for the analysis that code scanning compares the pull requests with; an advisory published since shows as an alert of the next pull request, until a run on main by hand gives main the alert. Its findings go to code scanning, where the Findings workflow keeps them fixed or accepted; .github/zizmor.yml holds what the repository accepts on purpose.

Pflege

Sie halten das Repository, seine Einstellungen, seine Labels und seine Berichte aktuell.

Bot health

The bot-health bot. GitHub mails the failure of a scheduled run only to whoever last changed its schedule, and that of another run to whoever started it, which here is mostly the release app, so a failing bot went unnoticed for days. When a run of a bot or a scheduled workflow ends on the default branch, or the verification of a release that someone published by hand or with a token, this bot runs its failed jobs once more if a second try can pass, as it does with a job that GitHub cancelled at its time limit; a failure that stays keeps one issue per workflow open, with the label bot-failure, the failed jobs, their steps and their first errors, and the next run that passes closes it once every job that failed ran again in it, in every leg of its matrix, and passed: a run that skipped such a job, as a push that only plans the screenshots, leaves it open. Every night it also looks at the latest run of every workflow, those of the project and the checks of main too, in case GitHub lost an event, and starts a workflow whose schedule GitHub missed or switched off. A failure of Lint at a commit that the branch has left says nothing any more, because a pull request reaches the branch only when it passes Lint: it gets no issue, and an open one starts Lint by hand, so that a run that passes closes it. The same look compares the social preview that GitHub shows with .github/social-preview.png, which only a person can upload, and keeps one issue open, Upload the new social preview, until they are the same, in a public repository only, since GitHub shows no social preview of a private one; its label is manual-step, not bot-failure, since nothing fails there. The same look starts the blueprint bot when the blueprint has a newer release than .copier-answers.yml names and the pull request of the bot doesn't bring it yet, so that a repository that the Rollout doesn't start gets it within a day. Runs of pull requests start nothing here, and neither does a run that GitHub couldn't start, as in its outage of 9 November 2026: the nightly look runs it again once. A look that GitHub keeps failing ends with a notice, not a failure (decision 0136). The bots of events, Area labels, Welcome, Dependabot maintenance and Commands, also those of a pull request or of a fork, and the workflows that keep an issue of their own, such as Newest Node, get neither a second try nor an issue here, unless Harden-Runner stopped a job of their first attempt: then their failed jobs run once more, as nothing else would run them again (decision 0141). Nothing follows the end of Bot health itself, so the nightly look runs the failed jobs of its own runs of the last two days once more that Harden-Runner stopped at their first attempt. It checks out the default branch only, for blueprint.py, never the code of a pull request; blueprint.py bot-health holds the logic.

Clean-up

The clean-up bot. Every week it deletes what nobody needs any more: the branches that main holds completely and that no open pull request uses, and the caches of the Actions that belong to closed pull requests. A branch with commits that main doesn't have stays; the bot lists it once it is a month old, so that its owner decides. It never touches main, release, Renovate or Dependabot branches.

Labels

Creates and updates the repository's labels from .github/labels.toml. It never deletes a label; one that is missing from the file is reported in the summary. The job is the issue assistant's reusable workflow at the commit of a release, so an update is a move of the pin below; it blocks every host but GitHub's. https://github.com/Dennis-Otto/issue-assistant

Labels

The job of templates/.github/workflows/labels.yml, which every repository that uses the issue assistant calls at the commit of a release. Creates and updates the repository's labels from .github/labels.toml and never deletes a label; one that is missing from the file is reported in the summary. The job blocks every host but GitHub's with Harden-Runner and runs the issue assistant of this workflow's own commit (decision 0015). https://github.com/Dennis-Otto/issue-assistant

Settings

The settings bot. Every week, and after each change of the settings as code or of its own code, it brings the settings of the repository on GitHub in line with .github/repository.toml, .github/repository.project.toml and .github/labels.toml, as the settings app, a second GitHub App of the owner that only administers, once the variable SETTINGS_APP_CLIENT_ID and the secret SETTINGS_APP_PRIVATE_KEY name it, and as the release app until then, with a token that may write the administration of the repository but neither its code nor its workflows. What the API can't set, such as the value of a secret, and what GitHub refused fail the run and show in its summary, with the command that sets it or the permission that the app lacks.

  • Wann: jeder Push auf main, der bestimmte Dateien ändert, jeden Samstag um 06:21 UTC, von Hand
  • Umgebungen: release
  • Secrets: RELEASE_AUTOMATION_PRIVATE_KEY, SETTINGS_APP_PRIVATE_KEY
  • Quelle: .github/workflows/settings.yml, aus dem Repo Blueprint