-
Notifications
You must be signed in to change notification settings - Fork 4.4k
12.1 Contributing
Relevant source files
The following files were used as context for generating this wiki page:
This document explains how to contribute code to ZeroClaw through pull requests (PRs). It covers the PR lifecycle, readiness requirements, review process, and merge criteria. ZeroClaw uses a high-volume, risk-based PR workflow that balances fast throughput with security and stability.
For CI workflow details and troubleshooting, see CI/CD Workflows. For testing requirements, see Testing. For subsystem ownership, see Code Ownership.
ZeroClaw's contribution workflow is designed for high PR volume while maintaining:
- Deterministic validation: Merge gates depend on reproducible checks, not subjective review comments
- Risk-based routing: High-risk paths (security, runtime, gateway, workflows) receive deep review; low-risk paths stay fast
- Automated triage: Labels route PRs to appropriate review depth automatically
- Rollback-first contracts: Every merge includes concrete recovery steps
The workflow uses automation to assist with intake classification and queue management, but final merge decisions remain with human maintainers and PR authors.
Sources: docs/pr-workflow.md:1-91
stateDiagram-v2
[*] --> Intake: "PR opened"
Intake --> Validation: "Template complete"
Validation --> Failed: "CI Required Gate fails"
Failed --> Validation: "Fix committed"
Validation --> Review: "CI Required Gate passes"
Review --> NeedsWork: "Review feedback"
NeedsWork --> Validation: "Changes committed"
Review --> MergeReady: "All approvals received"
MergeReady --> Merged: "Squash merge"
Merged --> [*]
note right of Intake
- PR Labeler applies labels
- PR Auto Responder posts guidance
- Template completeness checked
end note
note right of Validation
- CI Required Gate is merge gate
- Lint, test, build checks
- Docs quality for doc changes
end note
note right of Review
- Fast lane: template + CI + risk check
- Deep lane: security + failure modes
- CODEOWNERS approval required
end note
note right of MergeReady
- DoD checklist complete
- Rollback plan documented
- Conventional Commit title
end note
Sources: docs/pr-workflow.md:109-138
| Step | System Component | Actions | Automation |
|---|---|---|---|
| Intake | .github/pull_request_template.md |
Contributor completes template |
PR Labeler applies scope, size, risk, module labelsPR Auto Responder posts first-time guidance |
| Validation | .github/workflows/ci-run.yml |
CI runs lint, test, build |
CI Required Gate status check blocks merge until green |
| Review | CODEOWNERS + maintainers | Reviewers prioritize by risk/size labels |
PR Hygiene nudges stale PRs every 12 hours |
| Merge | Maintainer | Squash merge with Conventional Commit title | Stale approvals dismissed on new commits |
Sources: docs/pr-workflow.md:110-138, docs/ci-map.md:11-23
Before requesting review, PRs must satisfy these requirements:
| Section | Requirement | Enforcement |
|---|---|---|
| Summary | Explicit scope boundary (what changed, what didn't) | Manual review |
| Validation Evidence | Attached proof (logs, screenshots, test output) | Manual review |
| Security Impact | Completed for risky paths (src/security, src/runtime, src/gateway, src/tools) |
Manual review |
| Rollback Plan | Concrete, fast recovery steps | Manual review |
| Privacy/Data Hygiene | Neutral/project-scoped test language, no personal data |
PR Intake Checks blocks PII patterns |
flowchart TD
PR["PR Opened"] --> CheckTemplate{"Template<br/>complete?"}
CheckTemplate -->|No| IntakeBlock["BLOCKED: Request completion"]
CheckTemplate -->|Yes| CheckEvidence{"Validation<br/>evidence<br/>attached?"}
CheckEvidence -->|No| IntakeBlock
CheckEvidence -->|Yes| CheckSecurity{"High-risk<br/>paths touched?"}
CheckSecurity -->|Yes| CheckSecFields{"Security/rollback<br/>sections complete?"}
CheckSecFields -->|No| IntakeBlock
CheckSecFields -->|Yes| ReadyForReview["Ready for Review"]
CheckSecurity -->|No| ReadyForReview
IntakeBlock -.-> StopReview["Stop deep review<br/>until blockers resolved"]
Sources: docs/pr-workflow.md:143-159, docs/ci-map.md:21-22
The PR template is defined in .github/pull_request_template.md. Contributors must complete all sections relevant to their change. The PR Intake Checks workflow (.github/workflows/pr-intake-checks.yml) validates template completeness and safe content patterns before CI runs.
Sources: docs/pr-workflow.md:143-151, docs/ci-map.md:21-22
PRs are merge-ready when all these criteria are satisfied:
| Criterion | Validation Method | Blocker |
|---|---|---|
| CI Required Gate green |
CI Required Gate status check |
Yes |
| Required reviews approved | CODEOWNERS + maintainer approval | Yes |
| Risk labels match touched paths |
PR Labeler automation + manual verification |
No (automation corrects) |
| Migration/compatibility impact documented | Template section review | Yes for breaking changes |
| Rollback path is concrete and fast | Template section review | Yes for risky paths |
| Conventional Commit title | Squash merge commit message | Yes (enforced at merge) |
flowchart LR
Review["Review Approved"] --> CheckCI{"CI Required<br/>Gate green?"}
CheckCI -->|No| WaitCI["Wait for CI fix"]
CheckCI -->|Yes| CheckCodeowners{"CODEOWNERS<br/>approved?"}
CheckCodeowners -->|No| WaitApproval["Request owner review"]
CheckCodeowners -->|Yes| CheckRisk{"Risk labels<br/>correct?"}
CheckRisk -->|No| CorrectLabels["Automation auto-corrects<br/>or apply 'risk: manual'"]
CheckRisk -->|Yes| CheckRollback{"Rollback plan<br/>documented?"}
CheckRollback -->|No| BlockMerge["BLOCKED: Document rollback"]
CheckRollback -->|Yes| ReadyToMerge["Ready to Merge"]
CorrectLabels --> CheckRollback
Sources: docs/pr-workflow.md:152-159, docs/ci-map.md:13-17
The CI Required Gate check (.github/workflows/ci-run.yml) aggregates these validation steps:
-
Rust quality gates (blocks merge):
cargo fmt --all -- --checkcargo clippy --locked --all-targets -- -D clippy::correctness- Strict delta lint on changed Rust lines (./scripts/ci/rust_strict_delta_gate.sh)
cargo test- Release build smoke check
-
Docs quality gates (blocks merge when docs changed):
-
markdownlinton changed lines (./scripts/ci/docs_quality_gate.sh) - Link check on added links (./scripts/ci/collect_changed_links.py + lychee)
-
-
Workflow approval gate (blocks merge when workflows changed):
- Requires approving review from
WORKFLOW_OWNER_LOGINSfor.github/workflows/**changes
- Requires approving review from
Sources: docs/ci-map.md:13-17, docs/pr-workflow.md:122-126
| Label | Changed Lines | Policy |
|---|---|---|
size: XS |
≤ 80 | Fast track, minimal review depth |
size: S |
≤ 250 | Standard review |
size: M |
≤ 500 | Standard review, justify scope |
size: L |
≤ 1000 | Requires explicit justification + tighter test evidence |
size: XL |
> 1000 | Split into stacked PRs unless justified |
flowchart TD
PR["PR Opened"] --> CalcSize["PR Labeler calculates<br/>effective changed lines"]
CalcSize --> NormSize["Normalize for docs-only<br/>and lockfile changes"]
NormSize --> ApplyLabel{"Effective<br/>size?"}
ApplyLabel -->|"≤ 80"| XS["size: XS<br/>Fast track"]
ApplyLabel -->|"≤ 250"| S["size: S<br/>Standard"]
ApplyLabel -->|"≤ 500"| M["size: M<br/>Standard + justification"]
ApplyLabel -->|"≤ 1000"| L["size: L<br/>Requires tighter evidence"]
ApplyLabel -->|"> 1000"| XL["size: XL<br/>Request split or justify"]
XS --> FastReview["Prioritize in review queue"]
S --> StandardReview["Standard review depth"]
M --> StandardReview
L --> DeepReview["Deep review + split discussion"]
XL --> DeepReview
Sources: docs/pr-workflow.md:163-183
-
Target:
XS/S/Mby default for faster review cycles -
Large features: Split into stacked PRs with explicit
Depends on #...links - Unavoidable large PRs: Must include comprehensive test evidence and failure-mode analysis
Sources: docs/pr-workflow.md:163-183
PRs are automatically classified by touched paths and can be manually overridden:
| Label | Paths | Review Depth | Required Evidence |
|---|---|---|---|
risk: high |
src/security/**, src/runtime/**, src/gateway/**, src/tools/**, .github/workflows/**
|
Deep review + security check | Threat model, mitigation notes, rollback steps, failure-mode scenario |
risk: medium |
Core subsystems, provider implementations, channel implementations | Standard review | Rollback steps, compatibility notes |
risk: low |
Docs, tests, examples, minor refactors | Fast triage | Template completeness |
flowchart TD
PR["PR Ready"] --> CheckPaths{"Touched<br/>paths?"}
CheckPaths -->|"Security/Runtime/<br/>Gateway/Tools/Workflows"| HighRisk["risk: high"]
CheckPaths -->|"Core subsystems/<br/>Providers/Channels"| MedRisk["risk: medium"]
CheckPaths -->|"Docs/Tests/<br/>Examples"| LowRisk["risk: low"]
HighRisk --> ManualOverride{"Maintainer<br/>applies<br/>'risk: manual'?"}
ManualOverride -->|Yes| FreezeRisk["Risk label frozen"]
ManualOverride -->|No| DeepReview["Deep Review Lane"]
MedRisk --> StandardReview["Standard Review Lane"]
LowRisk --> FastTriage["Fast Triage Lane"]
DeepReview --> RequireEvidence["Require:<br/>- Threat model<br/>- Mitigation notes<br/>- Rollback steps<br/>- Failure scenario"]
StandardReview --> RequireBasic["Require:<br/>- Rollback steps<br/>- Compatibility notes"]
FastTriage --> RequireTemplate["Require:<br/>- Template complete"]
Sources: docs/pr-workflow.md:243-266, docs/ci-map.md:52
Maintainers can apply risk: manual to freeze automated risk recalculation when context requires human judgment. This prevents the PR Labeler from auto-correcting the risk label on subsequent edits.
Sources: docs/pr-workflow.md:238, docs/ci-map.md:51
ZeroClaw uses a two-lane review model to handle high PR volume efficiently:
Applicable to risk: low PRs:
| Check | Purpose | Automation Support |
|---|---|---|
| Template completeness | Ensure scope is documented |
PR Intake Checks validates |
| CI gate signal | Confirm tests pass |
CI Required Gate status |
| Risk class verification | Confirm labels match paths |
PR Labeler applies |
| Rollback statement | Verify recovery plan exists | Manual review |
| Privacy/data hygiene | Confirm neutral test language |
PR Intake Checks validates |
Required for risk: high PRs:
| Check | Purpose | Review Focus |
|---|---|---|
| Threat model validation | Ensure security assumptions are sound | Security boundaries, attack vectors |
| Failure mode analysis | Verify degradation behavior | Error handling, fallback paths |
| Backward compatibility | Check migration impact | Breaking changes, version skew |
| Observability impact | Verify logging/metrics | Debugging capability |
Sources: docs/pr-workflow.md:294-316
flowchart TD
Queue["Open PRs"] --> Priority{"Triage<br/>order"}
Priority -->|"1. High"| P1["size: XS/S<br/>+<br/>Bug/Security fixes"]
Priority -->|"2. Medium"| P2["size: M<br/>Focused changes"]
Priority -->|"3. Low"| P3["size: L/XL<br/>Split request or<br/>staged review"]
P1 --> FastLane["Fast Triage Lane"]
P2 --> CheckRisk{"Risk<br/>class?"}
CheckRisk -->|High| DeepLane["Deep Review Lane"]
CheckRisk -->|Low/Medium| FastLane
P3 --> SplitDiscussion["Discuss split strategy"]
FastLane --> Target48h["Target: 48h first triage"]
DeepLane --> Target48h
Sources: docs/pr-workflow.md:319-335
- First triage target: Within 48 hours of PR opening
- Blocked PRs: Maintainer leaves one actionable checklist of blockers
-
Stale automation:
pr-check-stale.ymlmarks dormant PRs; maintainers can applyno-stalefor accepted work -
Hygiene automation:
pr-check-status.ymlnudges PRs every 12 hours when behindmainor missing CI Required Gate
Sources: docs/pr-workflow.md:212-217, docs/ci-map.md:59-64
AI-assisted and agent-generated PRs are welcome. Review can also be agent-assisted.
| Requirement | Purpose |
|---|---|
| Clear PR summary with scope boundary | Enable fast context acquisition |
| Explicit test/validation evidence | Prove correctness without full manual verification |
| Security impact and rollback notes | Document risk for risky changes |
- Brief tool/workflow notes when automation materially influenced the change
- Optional prompt/plan snippets for reproducibility
- Not required: Quantifying AI-vs-human line ownership
For agent-assisted PRs, reviewers should verify:
- Contract compatibility: Does the change honor existing trait contracts and API boundaries?
- Security boundaries: Are path checks, allowlists, and sandboxing preserved?
- Error handling: Are failure modes handled gracefully with fallback behavior?
- Performance: Are there memory leaks, N+1 queries, or hot-loop regressions?
Sources: docs/pr-workflow.md:185-208
When one agent hands off review to another (or to a maintainer), include:
- Scope boundary (what changed, what didn't)
- Validation evidence
- Open risks and unknowns
- Suggested next action
Sources: docs/pr-workflow.md:337-348
flowchart TD
PROpen["PR Opened/Updated"] --> Labeler["PR Labeler Workflow<br/>.github/workflows/pr-labeler.yml"]
Labeler --> CalcScope["Calculate scope labels<br/>from changed paths"]
CalcScope --> CalcSize["Calculate size label<br/>from effective lines"]
CalcSize --> CalcRisk["Calculate risk label<br/>from touched paths"]
CalcRisk --> CalcModule["Extract module labels<br/>from keywords"]
CalcModule --> CalcTier["Apply contributor tier<br/>by merged PR count"]
CalcTier --> Dedupe["De-duplicate less-specific<br/>scope labels"]
Dedupe --> Compact["Compact module namespaces<br/>to reduce noise"]
Compact --> Priority["Priority-sort labels:<br/>risk → size → tier → module"]
Priority --> Apply["Apply to PR"]
Apply --> Colors["Set label colors for<br/>smooth gradient"]
Colors --> Tooltips["Update label descriptions<br/>with rule summaries"]
Sources: docs/pr-workflow.md:110-120, docs/ci-map.md:41-53
| Category | Example Labels | Auto-Applied? | Manual Override |
|---|---|---|---|
| Risk |
risk: low, risk: medium, risk: high
|
Yes | Apply risk: manual to freeze |
| Size |
size: XS, size: S, size: M, size: L, size: XL
|
Yes | Auto-corrected on edits |
| Contributor Tier |
trusted (≥5 merged), experienced (≥10), principal (≥20), distinguished (≥50) |
Yes | Auto-corrected on edits |
| Module |
channel:telegram, provider:kimi, tool:shell, memory:sqlite
|
Yes | Can add manually |
| Scope |
scope:agent, scope:gateway, scope:scheduler, scope:ci
|
Yes | Can add manually |
| Route |
r:needs-repro, r:support, stale-candidate, superseded
|
No | Apply manually for triage |
Sources: docs/pr-workflow.md:113-119, docs/ci-map.md:41-53
-
Hierarchical de-duplication: More specific scope labels suppress less specific ones (e.g.,
tool:composiosuppressestool:coreandtool) -
Module compaction: One specific module keeps
prefix:component, but multiple collapse to baseprefix - Color gradient: Managed labels are colored to produce a smooth visual gradient when many labels are present
- Tooltip descriptions: Hovering a label shows its auto-managed description explaining the rule/threshold
Sources: docs/pr-workflow.md:113-119, docs/ci-map.md:43-49
ZeroClaw uses squash merge exclusively to keep main history compact and bisectable.
Squash merge commit titles must follow Conventional Commits:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Examples:
feat(channels): add WhatsApp signature verificationfix(security): prevent symlink escape in workspace_only modedocs: update onboarding wizard screenshotschore(deps): update rust crate tokio to 1.42.0
Before clicking "Squash and merge", maintainers verify:
| Check | Purpose |
|---|---|
| Scope is focused and understandable | Ensure change is reviewable and revertible |
| CI Required Gate is green | Confirm all merge gates pass |
| Docs quality checks green (if docs changed) | Ensure documentation standards are met |
| Security impact fields complete | Document security boundary changes |
| Privacy/data hygiene complete | Prevent PII/sensitive data leakage |
| Rollback plan explicit | Enable fast recovery if issues arise |
| Commit title follows Conventional Commits | Maintain clean history for changelog generation |
Sources: docs/pr-workflow.md:281-291
-
Fast path:
risk: low+size: XS/SPRs with clean CI can merge same-day -
Standard path:
risk: medium+size: MPRs typically merge within 48-72 hours -
Deep review path:
risk: highorsize: L/XLPRs may take 3-5 days depending on review queue depth
Sources: docs/pr-workflow.md:212-217
If a merged PR causes regressions or incidents:
flowchart LR
Incident["Regression Detected"] --> Revert["1. Revert PR immediately<br/>on main branch"]
Revert --> Issue["2. Open follow-up issue<br/>with root cause analysis"]
Issue --> RegressionTest["3. Write regression test<br/>proving failure"]
RegressionTest --> Fix["4. Re-introduce fix<br/>with test"]
Fix --> Verify["5. Verify fix resolves<br/>original issue"]
-
Revert immediately: Use
git revertto restoremainto working state - Root cause analysis: Open issue documenting what failed, why, and blast radius
- Regression test: Write test that would have caught the failure
- Re-introduce fix: New PR with regression test + original fix
- Verify: Confirm both original issue and regression are resolved
Prefer fast restore of service quality over delayed perfect fixes.
If a revert causes temporary feature loss but restores stability, revert immediately and re-introduce the feature properly in a follow-up PR.
Sources: docs/pr-workflow.md:270-277
When a new PR replaces an older open PR:
- Add
Supersedes #<old-pr-number>to new PR description - Maintainer confirms superseding PR is superior
- Close old PR with comment linking to new PR
- Apply
supersededlabel to old PR
The pr-check-stale.yml workflow marks PRs stale after inactivity:
- Stale threshold: 60 days no activity
- Close threshold: 7 days after stale label applied
-
Exceptions: Apply
no-stalelabel for accepted-but-blocked work
Maintainers use queue budget controls to prevent review overload:
- Limit concurrent deep-review PRs per maintainer
- Keep remaining PRs in triage state
- For stacked work, require explicit
Depends on #...for deterministic review order
Sources: docs/pr-workflow.md:219-240
While this page focuses on PR workflow, related issue triage labels help keep the bug backlog healthy:
| Label | Purpose | Action |
|---|---|---|
r:needs-repro |
Bug report lacks deterministic reproduction | Request concrete repro steps |
r:support |
Usage/help question better suited for discussions | Route to support channels |
invalid |
Not a bug or request | Close with explanation |
duplicate |
Already tracked elsewhere | Close with link to original |
Note: Automated close routes apply to issues only, never PRs. Maintainers own PR close/merge decisions.
Sources: docs/pr-workflow.md:228-233
- CI/CD Workflows — CI workflow ownership and troubleshooting
- Testing — Testing strategy and test types
- Code Ownership — CODEOWNERS structure and responsibilities
- Security Model — Five-layer security architecture
- Gateway Security — Gateway authentication and rate limiting
Sources: docs/pr-workflow.md:350-356