mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-04-21 13:22:30 +08:00
14 KiB
14 KiB
AGENTS.MD
Telegraph style. Root rules only. Read scoped AGENTS.md before touching a subtree.
Start
- Repo:
https://github.com/openclaw/openclaw - Replies: repo-root file refs only, e.g.
extensions/telegram/src/index.ts:80. No absolute paths, no~/. - CODEOWNERS: maintenance/refactors/tests are ok. For larger behavior, product, security, or ownership-sensitive changes, get a listed owner request/review first.
- First pass: run docs list (
bin/docs-listorpnpm docs:list; ignore if unavailable), then read only relevant docs/guides. - Missing deps: run
pnpm install, rerun once, then report first actionable error. - Use "plugin/plugins" in docs/UI/changelog.
extensions/remains internal workspace layout. - Add channel/plugin/app/doc surface: update
.github/labeler.ymland matching GitHub labels. - New
AGENTS.md: add siblingCLAUDE.mdsymlink to it.
Repo Map
- Core TS:
src/,ui/,packages/ - Bundled plugins:
extensions/ - Plugin SDK/public contract:
src/plugin-sdk/* - Core channel internals:
src/channels/* - Plugin loader/registry/contracts:
src/plugins/* - Gateway protocol:
src/gateway/protocol/* - Docs:
docs/ - Apps:
apps/,Swabble/ - Installers served from
openclaw.ai: sibling../openclaw.ai
Scoped guides:
extensions/AGENTS.md: bundled plugin rulessrc/plugin-sdk/AGENTS.md: public SDK rulessrc/channels/AGENTS.md: channel core rulessrc/plugins/AGENTS.md: plugin loader/registry rulessrc/gateway/AGENTS.md,src/gateway/protocol/AGENTS.md: gateway/protocol rulessrc/agents/AGENTS.md: agent import/test perf rulestest/helpers/AGENTS.md,test/helpers/channels/AGENTS.md: shared test helpersdocs/AGENTS.md,ui/AGENTS.md,scripts/AGENTS.md: docs/UI/scripts
Architecture
- Core must stay extension-agnostic. No core special cases for bundled plugin/provider/channel ids when manifest/registry/capability contracts can express it.
- Extensions cross into core only via
openclaw/plugin-sdk/*, manifest metadata, injected runtime helpers, and documented local barrels (api.ts,runtime-api.ts). - Extension production code must not import core
src/**,src/plugin-sdk-internal/**, another extension'ssrc/**, or relative paths outside its package. - Core code/tests must not deep-import plugin internals (
extensions/*/src/**,onboard.js). Use pluginapi.ts/ public SDK facade / generic contract. - Extension-owned behavior stays in the extension: legacy repair, detection, onboarding, auth/provider defaults, provider tools/settings.
- Legacy config repair: prefer doctor/fix paths over startup/load-time core migrations.
- If a core test asserts extension-specific behavior, move it to the owning extension or a generic contract test.
- New seams: backwards-compatible, documented, versioned. Third-party plugins exist.
- Channels:
src/channels/**is implementation. Plugin authors get SDK seams, not channel internals. - Providers: core owns generic inference loop; provider plugins own provider-specific auth/catalog/runtime hooks.
- Gateway protocol changes are contract changes: additive first; incompatible needs versioning/docs/client follow-through.
- Config contract: keep exported types, schema/help, generated metadata, baselines, docs aligned. Retired public keys stay retired; compatibility belongs in raw migration/doctor paths.
- Plugin architecture direction: manifest-first control plane; targeted runtime loaders; no hidden paths around declared contracts; broad mutable registries are transitional.
- Prompt-cache rule: deterministic ordering for maps/sets/registries/plugin lists/files/network results before model/tool payloads. Preserve old transcript bytes when possible.
Commands
- Runtime: Node 22+. Keep Node and Bun paths working.
- Install:
pnpm install(Bun supported; keep lockfiles/patches aligned if touched). - Dev CLI:
pnpm openclaw ...orpnpm dev. - Build:
pnpm build - Smart local gate:
pnpm check:changed(scoped typecheck/lint/guards + relevant tests) - Explain smart gate:
pnpm changed:lanes --json - Pre-commit view:
pnpm check:changed --staged - Normal full prod sweep:
pnpm check(prod typecheck/lint/guards, no tests) - Full tests:
pnpm test - Changed tests only:
pnpm test:changed - Extension tests:
pnpm test:extensionsorpnpm test extensions= all extension shards;pnpm test extensions/<id>= one extension lane. Heavy channels/OpenAI have dedicated shards. - Shard timing artifact:
.artifacts/vitest-shard-timings.json; auto-used for balanced shard ordering. Disable withOPENCLAW_TEST_PROJECTS_TIMINGS=0. - Targeted tests:
pnpm test <path-or-filter> [vitest args...]; do not call rawvitest. - Coverage:
pnpm test:coverage - Format check/fix:
pnpm format:check/pnpm format - Typecheck:
pnpm tsgo: fastest core prod graphpnpm tsgo:prod: core + extensions prod graphs; used bypnpm checkpnpm check:test-types/pnpm tsgo:test: all test graphspnpm tsgo:all: all prod + test project refs- Debug slices exist; do not present as normal user flow.
- Profile:
pnpm tsgo:profile [core-test|extensions-test|--all]
- Type policy: use
tsgo; do not addtsc --noEmit,typecheck, orcheck:typeslanes.tsconly for declaration/package-boundary emit gaps. - Lint:
pnpm lint: core/extensions/scripts shardspnpm lint:core,pnpm lint:extensions,pnpm lint:scriptspnpm lint:apps: Swift/app surface, separate from TS lintpnpm lint:all: legacy comparison lane
- Local heavy-check behavior:
OPENCLAW_LOCAL_CHECK=1default;OPENCLAW_LOCAL_CHECK_MODE=throttled|full;OPENCLAW_LOCAL_CHECK=0for CI/shared runs.
Gates
- Pre-commit hook: staged format/lint, then
pnpm check:changed --staged; docs/markdown-only skips changed-scope check;FAST_COMMIT=1skips changed-scope check only. - Changed lanes:
- core prod => core prod typecheck + core tests
- core tests => core test typecheck/tests only
- extension prod => extension prod typecheck + extension tests
- extension tests => extension test typecheck/tests only
- public SDK/plugin contract => extension prod/test validation too
- unknown root/config => all lanes
- Local loop: prefer
pnpm check:changed; usepnpm test:changedfor tests only; usepnpm checkfor full prod TS/lint sweep without tests. - Landing on
main: verify touched surface near landing; default bar ispnpm check+pnpm testwhen feasible. - Hard build gate: run/pass
pnpm buildbefore push if build output, packaging, lazy/module boundaries, or published surfaces can change. - Do not land related failing format/lint/type/build/tests. If failures are unrelated on latest
origin/main, say so and give scoped proof. - CI architecture gate:
check-additional; local equivalentpnpm check:architecture. - Config docs drift:
pnpm config:docs:gen/check - Plugin SDK API drift:
pnpm plugin-sdk:api:gen/check - Generated docs baselines: tracked
docs/.generated/*.sha256; full JSON ignored.
Code Style
- TypeScript ESM. Strict types. Avoid
any; prefer real types/unknown/narrow adapters. - No
@ts-nocheck. No lint suppressions unless intentional and explained. - External boundaries: prefer
zodor existing schema helpers. - Runtime branching: prefer discriminated unions / closed codes over freeform strings.
- Avoid magic sentinels like
?? 0, empty object/string when semantics change. - Dynamic import: do not mix static and dynamic import for same module in prod path. Use dedicated
*.runtime.tslazy boundary. After lazy-boundary edits, runpnpm buildand check[INEFFECTIVE_DYNAMIC_IMPORT]. - Cycles: keep
pnpm check:import-cyclesand architecture/madge cycle checks green. - Classes: no prototype mixins/mutations. Use explicit inheritance/composition. Tests prefer per-instance stubs.
- Comments: brief only for non-obvious logic.
- File size: split around ~700 LOC when it improves clarity/testability.
- Product naming: OpenClaw product/docs;
openclawCLI/package/path/config. - Written English: American spelling.
Tests
- Vitest. Tests colocated
*.test.ts; e2e*.e2e.test.ts. - Example models in tests:
sonnet-4.6,gpt-5.4. - Clean up timers/env/globals/mocks/sockets/temp dirs/module state;
--isolate=falsemust stay safe. - Hot tests: avoid per-test
vi.resetModules()+ fresh heavy imports; prefer static orbeforeAllimports and reset state directly. - Measure first:
pnpm test:perf:imports <file>for import drag;pnpm test:perf:hotspots --limit Nfor suite targets. - Keep tests at seam depth: unit-test pure helpers/contracts; one integration smoke per boundary, not per branch.
- Mock expensive runtime seams directly: scanners, manifests, package registries, filesystem crawls, provider SDKs, network/process launch.
- Prefer injected deps over module mocks; if mocking modules, mock narrow local
*.runtime.tsseams, not broad barrels. - Share fixtures/builders; do not recreate temp dirs, package manifests, or plugin workspaces in every case unless state isolation needs it.
- Delete duplicate assertions when another test owns the boundary; assert only the behavior that can regress here.
- Avoid broad
importOriginal()/ broadopenclaw/plugin-sdk/*partial mocks in hot tests. Add narrow local*.runtime.tsseam and mock it. - Use existing deps/callback/runtime injection seams before module mocks.
- Import-dominated test time is a boundary smell; shrink import surface before adding cases.
- Replacing slow integration coverage: extract production composition into a named helper and test that helper.
- Do not modify baseline/inventory/ignore/snapshot/expected-failure files to silence checks without explicit approval.
- Do not set test workers above 16. For memory pressure:
OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test. - Live:
OPENCLAW_LIVE_TEST=1 pnpm test:live; full logsOPENCLAW_LIVE_TEST_QUIET=0. - Full testing guide:
docs/help/testing.md.
Docs / Changelog
- Update docs when behavior/API changes. Use docs list/read_when hints.
- Docs links: see
docs/AGENTS.md. - Changelog: user-facing only. Pure test/internal changes usually no entry.
- Changelog placement: append to active version
### Changes/### Fixes; at most one contributor mention, preferThanks @user.
Git
- Use
scripts/committer "<msg>" <file...>; stage only intended files. - Commits: conventional-ish, concise/action-oriented. Group related changes.
- No manual stash/autostash unless explicitly requested. No branch/worktree changes unless requested.
- No merge commits on
main; rebase on latestorigin/mainbefore push. - User says "commit": commit your changes only. "commit all": commit everything in grouped chunks. "push": may
git pull --rebasefirst. - Do not delete/rename unexpected files; ask if it blocks. Otherwise ignore unrelated WIP.
- If bulk PR close/reopen affects >5 PRs, ask with exact count/scope.
- PR/issue workflows: use
$openclaw-pr-maintainer. /landpr: use~/.codex/prompts/landpr.md.
Security / Release
- Never commit real phone numbers, videos, credentials, live config.
- Secrets: channel/provider credentials under
~/.openclaw/credentials/; model auth profiles under~/.openclaw/agents/<agentId>/agent/auth-profiles.json. - Env keys: check
~/.profile. - Dependency patches/overrides/vendor changes require explicit approval.
pnpm.patchedDependenciesmust use exact versions. - Carbon pins owner-only: do not change
@buape/carbonversions unless Shadow (@thewilloftheshadow, verified bygh) asks. - Releases/publish/version bumps require explicit approval.
- Release docs:
docs/reference/RELEASING.md; use$openclaw-release-maintainer. - GHSA/advisories: use
$openclaw-ghsa-maintainer. - Beta tag/version must match, e.g.
vYYYY.M.D-beta.N=> npmYYYY.M.D-beta.N --tag beta.
Apps / Platform
- Before simulator/emulator testing, check connected real iOS/Android devices first.
- "restart iOS/Android apps" = rebuild/reinstall/relaunch, not kill/launch.
- SwiftUI: prefer Observation (
@Observable,@Bindable) over newObservableObject. - mac gateway: use app or
openclaw gateway restart/status --deep; avoid ad-hoc tmux gateway sessions. Rebuild mac app locally, not over SSH. - mac logs:
./scripts/clawlog.sh. - Version bump touches:
package.json,apps/android/app/build.gradle.kts,apps/ios/version.jsonthenpnpm ios:version:sync,apps/macos/.../Info.plist,docs/install/updating.md. Appcast only for Sparkle release. - iOS Team ID:
security find-identity -p codesigning -v; fallbackdefaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers. - Mobile LAN pairing: plaintext
ws://is loopback-only by default. Trusted private-networkws://needsOPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1; Tailscale/public usewss://or a tunnel. - A2UI hash
src/canvas-host/a2ui/.bundle.hash: generated; ignore unless runningpnpm canvas:a2ui:bundle; commit separately.
External Ops
- Remote install docs:
docs/install/exe-dev.md,docs/install/fly.md,docs/install/hetzner.md. - Parallels smoke:
$openclaw-parallels-smoke; Discord roundtrip:parallels-discord-roundtrip.
Misc Footguns
- Rebrand/migration/config warnings: run
openclaw doctor. - Never edit
node_modules. - Local-only
.agentsignores: use.git/info/exclude, not repo.gitignore. - CLI progress: use
src/cli/progress.ts; status tables:src/terminal/table.ts. - Connection/provider additions: update all UI surfaces + docs + status/config forms.
- Provider-facing tool schemas: prefer flat string enum helpers over
Type.Union([Type.Literal(...)]); some providers reject generatedanyOf. Do not treat this as a repo-wide protocol/schema ban. - External messaging surfaces: no token-delta channel messages. Follow
docs/concepts/streaming.md; preview/block streaming uses message edits/chunks and must preserve final/fallback delivery.