Openclaw · EN · Part 4
Ch 14 Contributing To OpenClaw
14-ch-14-Contributing-to-OpenClaw.md
第14章 Contributing to OpenClaw
The OpenClaw project didn't start as a polished product with thousands of tests and twenty messaging channels. It began as a personal playground—a learning experiment that evolved through names like Warelay, Clawdbot, and Moltbot before becoming OpenClaw. Today, it's maintained by a community that values thoughtful contributions over raw PR volume. If you're reading this, you're already part of that community.
OpenClaw runs on your devices, in your channels, with your rules. That local-first philosophy extends to how we build software: clear boundaries, explicit security decisions, and code that anyone can read, modify, and extend. This chapter guides you through contributing effectively—whether you're fixing a typo, adding a channel, or diving into the agent runtime.
Contribution Workflow
The path from "I want to help" to "merged" follows a familiar GitHub flow, but OpenClaw has specific expectations that make reviews smoother for everyone. Let's walk through it.
Rendering diagram...
Forking and Branching
Start by forking https://github.com/openclaw/openclaw to your GitHub account. Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/openclaw.git
cd openclaw
git remote add upstream https://github.com/openclaw/openclaw.git
Create a branch for your work. Branch names should describe what you're doing:
# Good
git checkout -b fix/telegram-reply-race
git checkout -b add/matrix-channel-provider
git checkout -b docs/update-contributing-guide
# Less helpful
git checkout -b stuff
git checkout -b fix2
Keep your branch synced with upstream while you work:
git fetch upstream
git rebase upstream/main
Committing Changes
OpenClaw follows a specific commit message convention. The project uses a committer script to enforce consistent formatting:
# Use the project's committer script
scripts/committer "CLI: add verbose flag to send" src/cli/commands/send.ts
If you commit manually, follow this pattern:
<area>: <summary>
Optional body explaining why.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Area prefixes include: CLI, Gateway, Agents, Channels, Plugins, Config, Docs, Tests, Infra.
🤿 深入底层:The committer script runs
git status,git diff, andgit login parallel to analyze changes before staging files. It ensures you don't accidentally commit credentials, large binaries, or unrelated changes—a safety net that's caught dozens of would-be mistakes.
PR Creation
When your changes are ready and tests pass, push to your fork:
git push origin fix/telegram-reply-race
Create a pull request on GitHub. OpenClaw provides a PR template that guides you through providing the right context. A well-structured PR description looks like this:
## Summary
- Problem: Telegram replies were arriving out of order when multiple messages
were sent within the same second due to race condition in reply dispatch
- Why it matters: Users received confusing, out-of-context responses that
broke conversation flow
- What changed: Added sequence ID tracking and FIFO queue for pending replies
- What did NOT change: No changes to inbound message handling or other channels
## Change Type
- [x] Bug fix
- [ ] Feature
## Root Cause
- Root cause: The Telegram send handler didn't account for network latency
variation when dispatching multiple replies rapidly
- Missing detection: No integration test covered rapid sequential sends
- Contributing context: Issue #47231 reported by user in production
## Regression Test Plan
- Coverage level that should have caught this:
- [x] Seam / integration test
- Target test: src/channels/telegram/send.test.ts
- Scenario: Send three replies within 100ms, verify order preserved
- Why smallest reliable: Unit test would mock away the actual race condition
Code Review Process
Every PR goes through review before merging. OpenClaw uses a CODEOWNERS file that automatically requests review from maintainers based on what files you changed:
# Security-sensitive code requires secops review
/src/security/ @openclaw/secops
/src/gateway/*auth*.ts @openclaw/secops
# Release workflow requires release manager approval
/.github/workflows/openclaw-npm-release.yml @openclaw/openclaw-release-managers
This means if your PR touches authentication code, the security team must approve. If it changes the release workflow, release managers sign off.
⚠️ 避坑指南:CODEOWNERS uses last-match-wins semantics. If you add overlapping rules below the secops block, include
@openclaw/secopson those entries too or you'll silently remove required security review. Several contributors have accidentally done this—the file even has a warning comment about it.
Coding Standards
OpenClaw's codebase follows specific patterns that evolved from supporting twenty channels, five thousand source files, and thirty-five hundred tests. These aren't arbitrary rules—they're lessons learned from production debugging at scale.
TypeScript Patterns
The project uses strict TypeScript. any is avoided; prefer real types, unknown, or narrow adapter helpers:
// Avoid
function parseConfig(data: any): Config {
return data.config;
}
// Prefer
function parseConfig(data: unknown): Result<Config, ParseError> {
if (!isRecord(data)) return err(new ParseError("expected object"));
// ...
}
At external boundaries (config, webhooks, APIs), use Zod or existing schema helpers:
import { z } from 'zod';
const WebhookPayloadSchema = z.object({
eventId: z.string(),
timestamp: z.number(),
payload: z.unknown(),
});
function handleWebhook(raw: unknown) {
const result = WebhookPayloadSchema.safeParse(raw);
if (!result.success) {
throw new WebhookError(`invalid payload: ${result.error}`);
}
// TypeScript knows result.data is correctly typed
}
Prefer discriminated unions when parameter shape changes runtime behavior:
// Good: TypeScript forces exhaustive handling
type AgentCommand =
| { type: 'wake', agentId: string }
| { type: 'sleep', agentId: string, duration: number };
function execute(cmd: AgentCommand) {
switch (cmd.type) {
case 'wake': return wakeAgent(cmd.agentId);
case 'sleep': return sleepAgent(cmd.agentId, cmd.duration);
// TypeScript error if you miss a case
}
}
Naming Conventions
Product/docs headings use OpenClaw; CLI commands, packages, and paths use openclaw. Written English follows American spelling: "color" not "colour", "behavior" not "behaviour".
Plugin naming keeps IDs aligned across the manifest, workspace folder, and package names. For repo-owned workspace plugins:
openclaw.plugin.json:id= plugin ID- Default workspace folder name = plugin ID
- Package name =
@openclaw/<id>or approved suffix like-provider,-plugin
☕ 茶水间时间:This alignment isn't pedantry—it's what lets the plugin system discover, validate, and install plugins without runtime loading. When IDs drift across these three locations, you get "plugin not found" errors that are frustrating to debug. The repo even has an invariant test that enforces this rule for bundled plugins.
Guardrails and Rules
Some patterns are explicitly forbidden because they've caused real bugs:
Never use ?? 0, empty-string, or magic-string sentinels when they can change runtime meaning silently:
// Dangerous: 0 might be a valid count
const count = response.count ?? 0;
if (count > 0) { /* ... */ } // Is 0 meaningful or missing?
// Better: explicit union
type CountResult = { available: true, count: number } | { available: false };
Never mix static and dynamic imports for the same module:
// Forbidden: creates split code paths
import { helper } from './utils.js'; // somewhere in the file...
const late = await import('./utils.js'); // ...and here
// Correct: create a runtime boundary
// utils.runtime.ts
export * from './utils.js';
// caller.ts
const utils = await import('./utils.runtime.js');
Never share class behavior via prototype mutation:
// Forbidden: TypeScript can't track this
function applyPrototypeMixins(target: any, ...sources: any[]) {
sources.forEach(source => {
Object.getOwnPropertyNames(source.prototype).forEach(name => {
target.prototype[name] = source.prototype[name];
});
});
}
// Correct: explicit inheritance or composition
class BaseMessenger { /* ... */ }
class TelegramMessenger extends BaseMessenger { /* ... */ }
Code Quality Expectations
Files should stay under ~700 LOC when feasible. Splitting isn't a hard rule, but longer files become harder to test and review. When you add brief comments, focus on tricky or non-obvious logic—don't document what the code already says.
The project uses Oxlint for linting and Oxfmt for formatting. These replace ESLint/Prettier but enforce similar consistency. Pre-commit hooks run pnpm check (typecheck + lint + format). For faster commit loops during development:
FAST_COMMIT=1 git commit ...
This skips the repo-wide pnpm format and pnpm check in the hook only—use it when you're covering the touched surface through other verification.
Code Review Process
Code review in OpenClaw isn't about gatekeeping—it's about maintaining quality across a distributed codebase with many contributors. Understanding how review works helps you navigate it smoothly.
Review Criteria
Maintainers evaluate PRs against several dimensions:
Correctness: Does the code do what it claims? Bug fixes must explain the root cause, not just the symptom. Features must have clear use cases.
Boundaries: Does the change respect architecture boundaries? Extensions must cross into core only through openclaw/plugin-sdk/*. Core code must not deep-import plugin internals.
Testing: Does the change include appropriate tests? For bug fixes, there should be a regression test. For features, unit or integration tests prove the behavior.
Docs: Do user-facing changes get documented? Config changes need schema updates. New features need docs. Pure test additions usually don't need changelog entries.
Security: Does the change touch security-sensitive surfaces? Auth, secrets, sandboxing, and command execution get extra scrutiny.
Common Feedback
You'll see certain patterns in review comments:
"Break this into smaller PRs" - OpenClaw prefers focused changes. PRs over 5,000 lines are reviewed only in exceptional circumstances. One PR = one issue/topic.
"Add a regression test" - Bug fixes should lock in the fix with a test. The PR template even has a section for this.
"Update the public contract" - If you change config schema or the Plugin SDK, regenerate the baselines. The project has drift detection for exactly this.
"Use the SDK boundary" - If your core code reaches into plugin internals, the reviewer will ask you to expose a helper through the public SDK instead.
Responding to Reviews
When you receive feedback:
- Address each point - Don't leave comments hanging
- Explain if you disagree - Good maintainers are open to being wrong
- Push updates - New commits trigger re-review automatically
- Resolve bot conversations - If a bot review is fixed, resolve that conversation yourself. Don't leave cleanup for maintainers.
The PR workflow emphasizes conversation over rigid process. If something is unclear, ask. The Discord community and GitHub Issues are both good places for questions.
🤿 深入底层:The project includes a
$openclaw-pr-maintainerskill that maintainers use for PR triage, review, and landing workflows. This includes auto-close labels, bug-fix evidence gates, and GitHub comment/search footnotes that have caught many would-be mistakes. The skill essentially encodes maintainer judgment as a checklist—useful to understand what maintainers are looking for.
Maintainer Workflow
When maintainers review your PR, they're checking it against a mental (and sometimes literal) checklist:
- Does the PR template have proper context?
- Is there evidence the fix works?
- Are tests affected appropriately?
- Did the contributor run
pnpm checklocally? - Does security impact need special review?
- Are CODEOWNERS requirements met?
For bug fixes, maintainers look for evidence—logs, screenshots, or before/after test output. "Trust but verify" means maintainers trust you're reporting a real bug, but they need to see proof the fix actually addresses it.
Getting Help and Staying Updated
OpenClaw has a community that welcomes questions and helps contributors get unstuck. Knowing where to ask saves time for everyone.
Discord Community
The Discord server is the best place for real-time conversation:
- Questions about how something works: Ask in
#helpor#dev - Design discussions: Use
#devbefore writing major code - Show your work:
#show-and-tellis for sharing what you built
The community includes maintainers, plugin authors, and users. Someone has probably hit the same problem you're facing.
GitHub Issues
Before creating an issue, search existing ones. OpenClaw has thousands of issues covering:
- Bug reports: Include reproduction steps, environment, and logs
- Feature requests: Explain the use case, not just the proposed solution
- Documentation gaps: Point to what's unclear or missing
Well-written issues get faster responses. Include:
## Environment
- OS: macOS 15.2
- Node version: v22.14.0
- OpenClaw version: 2026.4.4
## Steps to Reproduce
1. Run `openclaw gateway run`
2. Send message via Telegram
3. Gateway crashes
## Actual Behavior
Error: Cannot read property 'userId' of undefined
## Expected Behavior
Message should be processed normally
VISION Document
The VISION.md file at the repo root explains project direction and priorities:
- Current focus: security, bug fixes, setup reliability
- Next priorities: model providers, channel support, performance
- What won't be merged: skills that can live on ClawHub, heavy orchestration layers
Reading this before proposing features saves everyone time. If your idea aligns with stated priorities, it's more likely to be accepted. If it conflicts with "what we will not merge," consider whether there's a different approach.
Asking Questions
Good questions get good answers. Include:
- What you're trying to do: "I want to add a new channel..."
- What you've tried: "I looked at the Telegram plugin and..."
- Where you're stuck: "I don't understand how the pairing flow..."
Bad questions are vague: "It doesn't work" or "How do I contribute?" give responders nothing to work with.
Staying Informed
To follow OpenClaw development:
- Watch the repo on GitHub - See commits, PRs, and releases
- Join Discord - Real-time discussion and announcements
- Read CHANGELOG.md - User-facing changes in each version
- Check docs.openclaw.ai - Updated documentation
The project moves fast—iteration is quick by design. What's true today might change next month. Staying plugged in helps you contribute effectively.
You've now seen the full contribution lifecycle from finding an issue to landing code in main. The workflow might seem involved, but each step exists for a reason: someone once shipped a bug that step would have caught.
OpenClaw runs on your devices, in your channels, with your rules. That philosophy extends to how we build it—transparently, with clear boundaries, and as a community. Your contributions, whether documentation fixes, bug reports, or major features, make OpenClaw better for everyone.
Chapter Exercises
-
Create a fork and submit a documentation PR - Find a typo or unclear section in the docs, fix it, and open your first PR following the template.
-
Review an existing PR using the criteria - Browse open PRs at github.com/openclaw/openclaw/pulls and evaluate one against the review criteria in this chapter. What feedback would you give?
-
Write a commit following the conventions - Take a hypothetical change (e.g., "fix memory leak in agent runtime") and write a proper commit message with the
scripts/committerformat.