The Label workflow classifies the issue or PR that triggered it using Cloudflare Workers AI (@cf/qwen/qwen3-30b-a3b-fp8). It runs when an issue or PR is opened, edited or reopened, and when a PR receives new commits. It processes open items only. There is no scheduled scan or historical backfill.
| Labels | Issues | PRs | Assignment |
|---|---|---|---|
bug, enhancement, documentation, research, release | Yes | No | AI chooses one type; it may abstain when none applies. |
releases-note/feat, releases-note/fix, releases-note/refactor, releases-note/docs, releases-note/ci, releases-note/build, releases-note/chore | No | Yes | AI chooses one release-note category. |
core, website, services/*, bindings/*, integrations/* | Yes | Yes | AI selects directly affected components from the repository catalog. |
breaking-changes | No | Yes | AI may add it for an explicit incompatible API or behavior change. |
size:* | No | Yes | The script calculates changed lines. |
The category follows the substantive purpose. For example, a docstring-only fix belongs to releases-note/docs, a routine dependency upgrade to releases-note/build, and a package compilation regression to releases-note/fix. The title prefix is evidence rather than an override. Performance optimizations without new public functionality belong to releases-note/refactor.
research covers technical investigations and unresolved design questions. release covers release tracking issues. A usage question that does not fit a type can receive component labels without a type.
Existing type/category labels are preserved, including maintainer corrections. Component labels and breaking-changes are additive; the workflow does not remove them when subsequent edits change the scope. Maintainers can correct these labels. Size labels are recalculated on PR events and replace prior size labels.
Maintainers control lgtm, run-with-secrets, release-blocker, good first issue, good first vibe, and help wanted. The model cannot select them. Language labels, dependencies, and github_actions remain under the existing Dependabot/manual workflow and are preserved.
scripts/label.py derives services from the generated service inventory in website/data/services.json, and bindings/integrations from their repository directories. Layers and HTTP transports use core.
Existing naming conventions are retained: service names use underscores in labels, and the hf service uses services/huggingface. New component labels are created when catalog inputs change on main. Synchronization only creates missing labels; it does not rename, delete or overwrite existing labels. The classifier never creates labels from model-generated names.
The size is additions plus deletions from GitHub's PR file list:
| Label | Changed lines |
|---|---|
size:XS | 0–9 |
size:S | 10–29 |
size:M | 30–99 |
size:L | 100–499 |
size:XL | 500–999 |
size:XXL | 1,000 or more |
The calculation excludes *.lock, pnpm-lock.yaml, package-lock.json, DEPENDENCIES.*, services.json, and generated.js. Other generated files still count; binary changes have the line counts reported by GitHub.
Configure these repository Actions settings before enabling classification:
CLOUDFLARE_ACCOUNT_ID: the account that provides Workers AI.CLOUDFLARE_API_TOKEN: a token scoped to that account with Workers AI inference permission. Follow the Cloudflare REST API setup.GitHub‘s workflow token receives issues: write and pull-requests: write for label assignment, and contents: read for the trusted checkout. Fork PRs use pull_request_target; the workflow always checks out the default branch and never executes the PR’s code. Titles, bodies and diff excerpts are sent to the model as data. Model output is validated locally against separate issue/PR categories and the component catalog before any label write.
The request contains at most 10,000 body characters and 6,000 characters of diff excerpts, plus the file list. Classification is approximate; large diffs are not fully analyzed. The workflow checks the current title, body and PR head again before applying its result and skips a result if the item changed during inference. These reads are not an atomic lock against concurrent edits.
Requests retry HTTP 429 and transient server errors up to three attempts. Missing credentials, quota exhaustion, truncated output and invalid labels fail the job without applying a classification. After fixing the cause, rerun the failed job. Logs contain proposed label changes and model token/Neuron usage. They do not publish model-generated explanations as comments.
Run local contract tests with:
python3 -m unittest discover -s scripts -p test_label.py
With GH_TOKEN and GITHUB_REPOSITORY configured, synchronize definitions with python3 scripts/label.py sync. To inspect one saved Actions event, also set GITHUB_EVENT_PATH and the Cloudflare credentials, then run python3 scripts/label.py event. This defaults to a dry run; --apply writes the selected labels. Neither command enumerates historical issues or PRs.