Back to Zeroclaw

Labels

docs/book/src/maintainers/labels.md

0.8.327.9 KB
Original Source

Labels

Single reference for every label used on PRs and issues. Sources of truth:

  • .github/labeler.yml: path-label config consumed by actions/labeler
  • .github/label-policy.json: contributor tier thresholds
  • This page: definitions, behavior, and what's automated vs manual

When definitions conflict, update the source file first, then sync this page.

Ownership boundaries

Labels are portable metadata. They should answer what kind of work this is, what code area it touches, how risky it is to review, and whether stale policy or triage policy needs special handling.

Project board automation is a planning aid, not a second PR review queue. The current issue-dashboard planner is manual and report-only. The board should answer slower-moving planning questions: what is ready to pick up, what routing evidence keeps it active, what tracker or milestone it belongs to, and what is blocked. Native GitHub PR state should continue to answer fast-moving review and merge questions.

Keep the split based on update frequency:

  • Labels own durable classification: work type, scope/component, review risk, measured PR size, and stale exemption.
  • Project board fields are appropriate for issue planning stage, visible routing evidence, dependency state, stale-exemption reason, and roadmap grouping when those fields are actively maintained.
  • Native GitHub PR state owns fast-changing review state: review decision, required checks, mergeability, conflicts, and stale approvals.

The board should reduce maintainer work. If a field would need manual upkeep after every PR push or review, prefer labels, milestones, or native GitHub state instead.

Labels can suggest likely routing, but they are not ownership. A channel:*, provider:*, tool:*, security, or docs label identifies the surface that probably needs attention. Contributor-visible routing-evidence rules live in the Project board contract.

Use assignees for active work. Use issue comments, issue body sections, public fields, or linked trackers for routing evidence when a special stale, tracker, or deferred-decision state needs explanation. status:blocked uses the recorded-blocker rule. The Project board contract defines the accepted evidence sources and routing outcomes.

Canonical spelling

Use no-space colon spelling for scoped labels: provider:openai, channel:telegram, security:policy, risk:high, size:XS, type:docs, and similar labels. Phrase labels without a namespace stay phrase-like: good first issue, help wanted, trusted contributor, and stale-candidate.

Legacy duplicate labels such as provider: openai, channel: telegram, or tool: shell are cleanup candidates. Live spaced labels such as risk: high, size: XS, and type: docs are migration candidates now that the approved packet has created or confirmed the no-space canonical labels.

Some legacy labels may remain live during a staged migration. New or manual applications should use the canonical no-space labels, while existing legacy open refs can remain until the open-reference migration packet handles them. Migrate open issues/PRs to the canonical label before deletion. Do not delete labels with open references, broadly rename label families, or remove stale-policy labels without a maintainer decision for that cleanup batch.

Automation contract

Live PR label automation is split by source. pr-path-labeler.yml runs actions/labeler from .github/labeler.yml on PR open, reopen, and every pushed update. Because that workflow uses sync-labels: true, labels owned by .github/labeler.yml are recalculated from the current PR file set: matching path labels are added, and path labels that no longer match are removed.

Dependabot also seeds configured labels on its own PRs from .github/dependabot.yml: Cargo updates get dependencies; GitHub Actions and Docker updates get ci and dependencies. Those labels are initial Dependabot PR metadata, not the synchronized path-labeler contract.

Today .github/labeler.yml owns only path and scope labels such as docs, ci, channel, provider:openai, and tool:file. It does not own risk:*, size:*, type:*, contributor-tier, status, resolution, stale, or pickup labels.

If risk or size automation is added later, it should recalculate on every pushed PR update so the labels continue to describe the actual diff under review. Risk automation must honor risk:manual as an override that prevents future automated risk replacement for that PR until a maintainer removes the override.

Cleanup protocol

Label cleanup is a maintainer action, not a side effect of normal PR review.

Use this sequence:

  1. Refresh live label usage before acting.
  2. Split candidates into zero-history deletes, zero-open duplicate deletes, migrate-first active labels, and policy holdbacks.
  3. For labels with open refs, after the approved cleanup batch creates or confirms the canonical label, add the canonical label to each open issue/PR, remove the legacy label, verify the legacy label has zero open refs, then delete it.
  4. Do not delete governance labels, stale-policy labels, contributor-tier labels, or default GitHub labels as part of module-label cleanup.

Every live cleanup batch needs exact maintainer approval for the labels and issue/PR refs being changed.

Policy holdbacks

Some label families are intentionally outside mechanical cleanup, even when they look inconsistent with newer spelling or taxonomy preferences. They should change only after a separate policy decision and an exact live operation packet.

FamilyCurrent maintainer action it supportsBefore changing live labels
Terminal and resolution labelsExplain why work left the active queue: not pursued, invalid, duplicate, or explicitly declined.Preserve historical closure meaning and contributor expectations; define any rename, alias, migration, or deletion packet before mutating live labels. Replacement and superseding remain documented processes unless a later approved packet creates or maps a live label.
Status and stale labelsDrive issue lifecycle and stale behavior, including accepted work, blockers, active implementation, status:stale, status:no-stale, and PR backlog stale handling.Treat as policy-first because automation may protect, warn, or close issues differently. Do not change these labels as cosmetic or module-label cleanup; handle them through a stale/lifecycle policy packet that accounts for automation and routing-evidence rules.
Contributor-tier labelsSignal reviewer trust and contributor experience using .github/label-policy.json thresholds.Update the policy file and this guide together; do not delete or rename tiers as cosmetic cleanup because the labels affect people and review routing.
GitHub default labelsPreserve familiar contributor entry points such as bug, enhancement, documentation, and question.Replace or retire only through an explicit contributor-facing taxonomy decision. Defaults may be used by templates, searches, external links, and integrations.

The test for keeping a sensitive label live is operational: can maintainers name a real action that becomes harder if the live label disappears? If yes, keep or replace it deliberately. If no, preserve the historical mapping in the audit packet and migrate or delete through the approved operation.

Type labels

Type labels capture the high-level work class. They are separate from path labels such as docs, ci, or dependencies.

New or manual applications should use the canonical no-space labels below when the live label exists. Existing legacy open refs may keep spaced labels until the open-reference migration packet handles them; see Canonical spelling.

type:tracker is the canonical tracker-marker spelling for active parent coordination issues. Do not create or apply roadmap, type:roadmap, or another tracker marker as an alias. If the live type:tracker label does not exist yet, label creation and any tracker-marker migration must happen only through a separate exact maintainer-approved packet.

LabelPurpose
type:ciCI, workflow, or repository automation work
type:dependenciesDependency or lockfile maintenance
type:docsDocumentation-only or docs-primary work
type:rfcRFC issue or proposal; protected from stale closure while active
type:refactorCode-structure cleanup or internal reorganization intended to preserve user-visible behavior
type:testTest-only or test-primary work
type:trackerActive parent coordination issue for a release, roadmap, RFC/design thread, implementation batch, cleanup, or audit. Issue-only marker; does not by itself create stale protection, assignment, acceptance, or contributor-ready scope.

Path labels

Applied automatically by pr-path-labeler.yml. Globs live in .github/labeler.yml; when this page and the config disagree, treat .github/labeler.yml as the operational source and update this page.

Base scope labels

LabelMatches
docsdocs/**, **/*.md, **/*.mdx, LICENSE, .markdownlint-cli2.yaml
dependenciesCargo.toml, Cargo.lock, deny.toml, .github/dependabot.yml
ci.github/codeql/**, .github/workflows/**, .github/*.yaml, .github/*.yml, .github/*.json, .githooks/**
coresrc/*.rs
agentsrc/agent/**, crates/zeroclaw-runtime/src/agent/**
channelsrc/channels/**, crates/zeroclaw-channels/src/**
gatewaysrc/gateway/**, crates/zeroclaw-gateway/src/**
configsrc/config/**, crates/zeroclaw-config/src/**
cronsrc/cron/**, crates/zeroclaw-runtime/src/cron/**
daemonsrc/daemon/**, crates/zeroclaw-runtime/src/daemon/**
doctorsrc/doctor/**, crates/zeroclaw-runtime/src/doctor/**
healthsrc/health/**, crates/zeroclaw-runtime/src/health/**
heartbeatsrc/heartbeat/**, crates/zeroclaw-runtime/src/heartbeat/**
integrationsrc/integrations/**, crates/zeroclaw-runtime/src/integrations/**
memorysrc/memory/**, crates/zeroclaw-memory/src/**
securitysrc/security/**, crates/zeroclaw-runtime/src/security/**
runtimesrc/runtime/**, crates/zeroclaw-runtime/src/**
quickstartcrates/zeroclaw-runtime/src/quickstart/**, crates/zeroclaw-gateway/src/api_quickstart.rs, apps/zerocode/src/quickstart_pane.rs, web/src/pages/quickstart/**
providersrc/providers/**, crates/zeroclaw-providers/src/**
servicesrc/service/**, crates/zeroclaw-runtime/src/service/**
skillforgesrc/skillforge/**, crates/zeroclaw-runtime/src/skillforge/**
skillssrc/skills/**, crates/zeroclaw-runtime/src/skills/**
toolsrc/tools/**, crates/zeroclaw-tools/src/**
tunnelsrc/tunnel/**, crates/zeroclaw-runtime/src/tunnel/**
observabilitysrc/observability/**, crates/zeroclaw-runtime/src/observability/**
teststests/**
scriptsscripts/**
devdev/**

ci is scoped to GitHub automation/config files, not all .github/** paths. The root .github/*.json matcher is intentional for automation metadata (for example .github/label-policy.json), so files like .github/assets/**, .github/ISSUE_TEMPLATE/**, .github/CODEOWNERS, and .github/pull_request_template.md do not match ci.

Additional component labels

Some surfaces have narrower path-owned labels for maintainer routing. These labels are synchronized by .github/labeler.yml when the PR diff touches the listed files.

Scoped path labels do not guarantee a same-prefix base label. Because pr-path-labeler.yml runs with sync-labels: true, maintainers should treat .github/labeler.yml as the source of truth for which base and scoped labels a PR receives.

LabelMatches
observability:logcrates/zeroclaw-log/src/**, crates/zeroclaw-runtime/src/observability/log.rs
observability:otelotel.rs, OTel dependency feature regression coverage
observability:prometheusprometheus.rs
runtime:wasmruntime WASM platform and first-party WASM plugin host files
security:bubblewrapbubblewrap.rs
security:dockerdocker.rs
security:leak-detectorLeakDetector redaction and sensitive-output scanning
security:pairingpairing security, gateway pairing API, Tauri pairing command, and web pairing page
security:policyruntime security policy, IAM policy, and config policy files
security:secretsruntime and config secrets handling
security:traitsshared security trait and interface definitions
memory:backendmemory backend selection and storage implementation files

Manual component labels

Some scoped component labels are manual routing labels rather than synchronized path labels.

agent:prompt is for provider-visible prompt, context, and response-guidance policy. Use it when the work is about system-prompt content, tool-call formatting guidance, prompt-cache-sensitive context, channel response guidance, or other model-visible instruction surfaces that cross the base agent, channel, memory, provider, or runtime labels. Apply it in addition to applicable base or scope labels; it does not replace them. Do not apply it to every crates/zeroclaw-runtime/src/agent/** change; use the base agent label for ordinary agent runtime changes.

agent:loop is retired. For agent-loop routing, use base agent plus any matching runtime, provider, channel, tool, or risk labels.

Do not apply legacy observability: runtime_trace to new issues or PRs. Use observability:otel when the work is about OpenTelemetry tracing, add base observability only when the issue or PR also matches that base surface, and decide any future runtime-trace-specific canonical label in a separate create/migrate packet.

Do not apply legacy security: leak_detector to new issues or PRs. Use security:leak-detector for LeakDetector redaction and sensitive-output scanning work.

Gateway subarea labels such as gateway: api, gateway: sse, gateway:local_bridge, and gateway:webhook_ingress remain live migration holdbacks. New routing should use base gateway until a separate packet either creates canonical no-space/hyphenated sublabels and migrates refs, or collapses those labels into base gateway.

Per-channel labels

Each channel gets a channel:<name> label in addition to the base channel label when the change touches channel crate paths. Cross-surface channel labels such as channel:acp may instead pair with the matching base surface label, such as gateway, docs, or app/web scope labels.

channel:core is the shared channel API and orchestrator label. Use it for work on channel trait contracts, channel orchestration, delivery hooks, routing/session behavior, runtime-command handling, and cross-channel behavior that would be misleading under a single platform label.

LabelMatches
channel:acpacp_channel.rs, acp_server.rs, zeroclaw-acp-bridge.rs, acp_session_store.rs, channels/acp.md, selected ACP gateway/app/web entrypoints
channel:corecrates/zeroclaw-api/src/channel.rs, crates/zeroclaw-channels/src/lib.rs, crates/zeroclaw-channels/src/orchestrator/**, src/channels/mod.rs
channel:blueskybluesky.rs
channel:clawdtalkclawdtalk.rs
channel:clicli.rs
channel:dingtalkdingtalk.rs
channel:discorddiscord.rs, discord_history.rs
channel:emailemail_channel.rs, gmail_push.rs
channel:imessageimessage.rs
channel:ircirc.rs
channel:larklark.rs
channel:lineline.rs, channels/line.md
channel:linqlinq.rs
channel:matrixmatrix.rs
channel:mattermostmattermost.rs
channel:mochatmochat.rs
channel:mqttmqtt.rs
channel:nextcloud-talknextcloud_talk.rs
channel:nostrnostr.rs
channel:notionnotion.rs
channel:qqqq.rs
channel:redditreddit.rs
channel:signalsignal.rs
channel:slackslack.rs
channel:telegramtelegram.rs
channel:twittertwitter.rs
channel:watiwati.rs
channel:webhookwebhook.rs
channel:wecomwecom.rs, wecom_ws.rs
channel:whatsappwhatsapp.rs, whatsapp_storage.rs, whatsapp_web.rs

Per-provider labels

Provider-specific labels match dedicated provider source files. The provider router has its own scoped label because routing and model-dispatch work is a shared provider subarea, not one concrete provider integration. Shared registry or factory files should receive the base provider label only; maintainers can add a provider-specific label manually when a shared-file change is truly scoped to one provider.

LabelMatches
provider:anthropicanthropic.rs
provider:azure-openaiazure_openai.rs
provider:bedrockbedrock.rs
provider:claude-codeclaude_code.rs
provider:compatiblecompatible.rs
provider:copilotcopilot.rs
provider:geminigemini.rs, gemini_cli.rs
provider:glmglm.rs
provider:kiloclikilocli.rs
provider:ollamaollama.rs
provider:openaiopenai.rs, openai_codex.rs
provider:openrouteropenrouter.rs
provider:reliablereliable.rs
provider:routerrouter.rs
provider:telnyxtelnyx.rs

Some provider labels describe provider families that currently share the OpenAI-compatible provider implementation instead of a dedicated source file. Maintainers may apply these manually when an issue or PR is truly about that family: provider:groq, provider:kimi, provider:minimax, provider:moonshot, and provider:qwen. Do not add shared factory or compatible-provider files to these labeler rules; that would over-label unrelated shared changes.

Per-tool-group labels

Tools are grouped by logical function rather than one label per file.

LabelMatches
tool:browserbrowser.rs, browser_delegate.rs, browser_open.rs, text_browser.rs, screenshot.rs
tool:cloudcloud_ops.rs, cloud_patterns.rs
tool:composiocomposio.rs
tool:cronsrc/tools/cron_add.rs, src/tools/cron_list.rs, src/tools/cron_remove.rs, src/tools/cron_run.rs, src/tools/cron_runs.rs, src/tools/cron_update.rs, crates/zeroclaw-runtime/src/tools/cron_add.rs, crates/zeroclaw-runtime/src/tools/cron_common.rs, crates/zeroclaw-runtime/src/tools/cron_list.rs, crates/zeroclaw-runtime/src/tools/cron_remove.rs, crates/zeroclaw-runtime/src/tools/cron_run.rs, crates/zeroclaw-runtime/src/tools/cron_runs.rs, crates/zeroclaw-runtime/src/tools/cron_update.rs
tool:delegatecrates/zeroclaw-runtime/src/tools/delegate.rs
tool:filesrc/tools/file_edit.rs, src/tools/file_read.rs, src/tools/file_write.rs, src/tools/glob_search.rs, src/tools/content_search.rs, crates/zeroclaw-tools/src/file_edit.rs, crates/zeroclaw-runtime/src/tools/file_read.rs, crates/zeroclaw-tools/src/file_write.rs, crates/zeroclaw-tools/src/glob_search.rs, crates/zeroclaw-tools/src/content_search.rs
tool:google-workspacegoogle_workspace.rs
tool:mcpmcp_client.rs, mcp_deferred.rs, mcp_protocol.rs, mcp_tool.rs, mcp_transport.rs
tool:memorymemory_forget.rs, memory_recall.rs, memory_store.rs
tool:microsoft365microsoft365/**
tool:pushoverpushover.rs
tool:securitysrc/tools/security_ops.rs, src/tools/verifiable_intent.rs, crates/zeroclaw-runtime/src/tools/security_ops.rs, crates/zeroclaw-runtime/src/tools/verifiable_intent.rs
tool:shellsrc/tools/shell.rs, src/tools/node_tool.rs, src/tools/cli_discovery.rs, crates/zeroclaw-runtime/src/tools/shell.rs, crates/zeroclaw-gateway/src/node_tool.rs, crates/zeroclaw-tools/src/cli_discovery.rs
tool:sopsrc/tools/sop_advance.rs, src/tools/sop_approve.rs, src/tools/sop_execute.rs, src/tools/sop_list.rs, src/tools/sop_status.rs, crates/zeroclaw-runtime/src/tools/sop_advance.rs, crates/zeroclaw-runtime/src/tools/sop_approve.rs, crates/zeroclaw-runtime/src/tools/sop_execute.rs, crates/zeroclaw-runtime/src/tools/sop_list.rs, crates/zeroclaw-runtime/src/tools/sop_status.rs
tool:webweb_fetch.rs, web_search_tool.rs, web_search_provider_routing.rs, http_request.rs

tool:schema is a manual-only label for tool-schema serialization and cleaning issues. Do not add broad schema files to .github/labeler.yml; many schema files are shared config, provider, or API surfaces and would over-label unrelated changes.

Size labels

Based on effective changed line count, normalized for docs-only and lockfile-heavy PRs. Currently applied manually; the size automation that previously computed these was removed during CI simplification. Future size automation should follow the automation contract.

New or manual applications should use the canonical no-space labels below. Existing legacy open refs may keep spaced labels until the open-reference migration packet handles them; see Canonical spelling.

LabelThreshold
size:XS≤ 80 lines
size:S≤ 250 lines
size:M≤ 500 lines
size:L≤ 1000 lines
size:XL> 1000 lines

Risk labels

For PRs, risk labels describe the actual diff under review: touched paths, behavior change, security boundary exposure, and rollback difficulty. For issues, risk labels describe the likely fix blast radius based on the report, help triage reviewer depth and contributor fit, and may change once a concrete PR shows the actual implementation path. Currently applied manually. Future risk automation should follow the automation contract.

New or manual applications should use the canonical no-space labels below. Existing legacy open refs may keep spaced labels until the open-reference migration packet handles them; see Canonical spelling.

LabelMeaning
risk:lowNo high-risk paths touched, small change
risk:mediumBehavioral crates/*/src/** changes without boundary or security impact
risk:highTouches a high-risk path, or large security-adjacent change
risk:manualMaintainer override that freezes automated risk recalculation

High-risk paths (canonical set; other maintainer pages reference this list): crates/zeroclaw-runtime/src/**, crates/zeroclaw-gateway/src/**, crates/zeroclaw-tools/src/**, crates/zeroclaw-runtime/src/security/**, .github/workflows/**.

Apply risk:high to any PR that raises the workspace MSRV, pinned Rust toolchain, generated installer/Docker toolchain baseline, or release workflow toolchain floor. Do not downgrade the risk just because the diff looks like CI, dependency, or docs housekeeping: a higher required Rust version affects downstream source builds, distro packages, container builds, and users pinned to older toolchains.

When uncertain, treat as higher risk.

Contributor tier labels

Defined in .github/label-policy.json. Based on the author's merged PR count queried from the GitHub API. Currently applied manually.

LabelMinimum merged PRs
trusted contributor5
experienced contributor10
principal contributor20
distinguished contributor50

Status labels

Track lifecycle state of RFCs and tracked work items. Applied manually unless a maintained workflow says otherwise.

LabelDescription
status:acceptedRFC or work item ratified by the team. This does not exempt the issue from stale handling by itself.
status:blockedWork is valid but waiting on an external dependency, maintainer decision, or linked prerequisite. Exempt from stale while the blocker is recorded and unresolved. Do not pair with status:no-stale for the same blocker.
status:in-progressAn open PR is actively targeting this issue. Reconcile against live PR state during stale passes; the label is not a permanent exemption after the PR closes.
status:staleNo author activity for the stale window; may close if not refreshed
status:no-staleExplicit stale exemption for accepted or otherwise long-lived work that is not already protected by another stale exclusion. Target policy: use only when the Project board contract has a contributor-visible stale-exemption reason and routing evidence. Active release trackers and active RFC or design trackers may use the tracker itself as the visible reason and routing surface while they remain active; revisit them when the milestone closes, the tracker drifts from live state, the RFC reaches a decision, is superseded, or closes, or the issue stops representing an active project decision surface. Existing exemptions missing those facts should be audited and repaired before stale sweeps stop honoring them.

Resolution labels

Resolution labels explain why an issue or PR is being closed or removed from the active queue. They are terminal outcomes, not lifecycle status labels, and should include enough comment context for a future maintainer to understand the decision.

LabelPurpose
wontfixValid request or report that the project is explicitly choosing not to pursue. Use a brief rationale; do not silently close.
invalidNot actionable as a bug, feature request, support item, RFC, or tracked project work. Explain the mismatch or missing requirement.
duplicateSame underlying issue as another tracked issue or PR. Link the canonical target before closing or redirecting discussion.

Do not create or apply proposed terminal labels such as status:wont-do or status:wont-fix until a maintainer-approved label migration packet defines the exact rename, alias, or deletion plan. The current live label for the board-level "Won't Do" concept is wontfix.

Superseding is a replacement process, not currently a live label. Use Superseding PRs for replacement rules and attribution requirements until a later approved migration packet creates or maps a superseding label.

Triage labels

Applied manually: the auto-response automation that used to handle these was removed during CI simplification.

LabelPurpose
r:needs-reproIncomplete bug report; request a deterministic repro
r:supportUsage / help item better handled outside the bug backlog
needs-author-actionAuthor response is needed before maintainers can continue the review or merge path. For PRs, this is not a stale warning by itself.
stale-candidateDormant PR or issue that is a candidate for closing. For PRs, follow the stale ramp in Reviewer Playbook → PR backlog pruning.

Community pickup labels

Applied manually when maintainers want outside contribution.

LabelPurpose
good first issueSmall, self-contained, well-documented XS/S work that is safe for a new contributor and has acceptance criteria, relevant code or docs links, and a named mentor or contact
help wantedActionable, unblocked work that maintainers want external help on and can review, usually low or medium likely issue risk

Do not use help wanted as a generic marker for "valid but unstaffed." If an issue is blocked, architecture-dependent, missing acceptance criteria, likely high-risk, or waiting on a policy decision, leave it without pickup labels until the blocker is resolved or a maintainer writes the missing scope.

Maintenance triggers

Update this page when:

  • A new channel, provider, or tool is added to the source tree (path labels need new entries).
  • A label policy or threshold changes.
  • A new triage workflow surfaces or an old one is removed.

The automation status notes ("currently applied manually") are deliberately included so a future maintainer doesn't assume the absence of a workflow means the label tier doesn't exist.