Files
openclaw/AGENTS.md
2026-03-18 23:01:22 -05:00

22 KiB
Raw Blame History

Repository Guidelines

  • Repo: https://github.com/openclaw/openclaw
  • In chat replies, file references must be repo-root relative only (example: extensions/bluebubbles/src/channel.ts:80); never absolute paths or ~/....
  • Do not edit files covered by security-focused CODEOWNERS rules unless a listed owner explicitly asked for the change or is already reviewing it with you. Treat those paths as restricted surfaces, not drive-by cleanup.

Project Structure & Module Organization

  • Source code: src/ (CLI wiring in src/cli, commands in src/commands, web provider in src/provider-web.ts, infra in src/infra, media pipeline in src/media).
  • Tests: colocated *.test.ts.
  • Docs: docs/ (images, queue, Pi config). Built output lives in dist/.
  • Plugins/extensions: live under extensions/* (workspace packages). Keep plugin-only deps in the extension package.json; do not add them to the root package.json unless core uses them.
  • Plugins: install runs npm install --omit=dev in plugin dir; runtime deps must live in dependencies. Avoid workspace:* in dependencies (npm install breaks); put openclaw in devDependencies or peerDependencies instead (runtime resolves openclaw/plugin-sdk via jiti alias).
  • Import boundaries: extension production code should treat openclaw/plugin-sdk/* plus local api.ts / runtime-api.ts barrels as the public surface. Do not import core src/**, src/plugin-sdk-internal/**, or another extension's src/** directly.
  • Installers served from https://openclaw.ai/*: live in the sibling repo ../openclaw.ai (public/install.sh, public/install-cli.sh, public/install.ps1).
  • Messaging channels: always consider all built-in + extension channels when refactoring shared logic (routing, allowlists, pairing, command gating, onboarding, docs).
    • Core channel docs: docs/channels/
    • Core channel code: src/telegram, src/discord, src/slack, src/signal, src/imessage, src/web (WhatsApp web), src/channels, src/routing
    • Extensions (channel plugins): extensions/* (e.g. extensions/msteams, extensions/matrix, extensions/zalo, extensions/zalouser, extensions/voice-call)
  • When adding channels/extensions/apps/docs, update .github/labeler.yml and create matching GitHub labels (use existing channel/extension label colors).

Docs Linking (Mintlify)

  • Docs are hosted on Mintlify (docs.openclaw.ai).
  • Internal doc links in docs/**/*.md: root-relative, no .md/.mdx (example: [Config](/configuration)).
  • When working with documentation, read the mintlify skill.
  • For docs, UI copy, and picker lists, order services/providers alphabetically unless the section is explicitly describing runtime behavior (for example auto-detection or execution order).
  • Section cross-references: use anchors on root-relative paths (example: [Hooks](/configuration#hooks)).
  • Doc headings and anchors: avoid em dashes and apostrophes in headings because they break Mintlify anchor links.
  • When Peter asks for links, reply with full https://docs.openclaw.ai/... URLs (not root-relative).
  • When you touch docs, end the reply with the https://docs.openclaw.ai/... URLs you referenced.
  • README (GitHub): keep absolute docs URLs (https://docs.openclaw.ai/...) so links work on GitHub.
  • Docs content must be generic: no personal device names/hostnames/paths; use placeholders like user@gateway-host and “gateway host”.

Docs i18n (zh-CN)

  • docs/zh-CN/** is generated; do not edit unless the user explicitly asks.
  • Pipeline: update English docs → adjust glossary (docs/.i18n/glossary.zh-CN.json) → run scripts/docs-i18n → apply targeted fixes only if instructed.
  • Before rerunning scripts/docs-i18n, add glossary entries for any new technical terms, page titles, or short nav labels that must stay in English or use a fixed translation (for example Doctor or Polls).
  • pnpm docs:check-i18n-glossary enforces glossary coverage for changed English doc titles and short internal doc labels before translation reruns.
  • Translation memory: docs/.i18n/zh-CN.tm.jsonl (generated).
  • See docs/.i18n/README.md.
  • The pipeline can be slow/inefficient; if its dragging, ping @jospalmbier on Discord instead of hacking around it.

exe.dev VM ops (general)

  • Access: stable path is ssh exe.dev then ssh vm-name (assume SSH key already set).
  • SSH flaky: use exe.dev web terminal or Shelley (web agent); keep a tmux session for long ops.
  • Update: sudo npm i -g openclaw@latest (global install needs root on /usr/lib/node_modules).
  • Config: use openclaw config set ...; ensure gateway.mode=local is set.
  • Discord: store raw token only (no DISCORD_BOT_TOKEN= prefix).
  • Restart: stop old gateway and run: pkill -9 -f openclaw-gateway || true; nohup openclaw gateway run --bind loopback --port 18789 --force > /tmp/openclaw-gateway.log 2>&1 &
  • Verify: openclaw channels status --probe, ss -ltnp | rg 18789, tail -n 120 /tmp/openclaw-gateway.log.

Build, Test, and Development Commands

  • Runtime baseline: Node 22+ (keep Node + Bun paths working).
  • Install deps: pnpm install
  • If deps are missing (for example node_modules missing, vitest not found, or command not found), run the repos package-manager install command (prefer lockfile/README-defined PM), then rerun the exact requested command once. Apply this to test/build/lint/typecheck/dev commands; if retry still fails, report the command and first actionable error.
  • Pre-commit hooks: prek install (runs same checks as CI)
  • Also supported: bun install (keep pnpm-lock.yaml + Bun patching in sync when touching deps/patches).
  • Prefer Bun for TypeScript execution (scripts, dev, tests): bun <file.ts> / bunx <tool>.
  • Run CLI in dev: pnpm openclaw ... (bun) or pnpm dev.
  • Node remains supported for running built output (dist/*) and production installs.
  • Mac packaging (dev): scripts/package-mac-app.sh defaults to current arch.
  • Type-check/build: pnpm build
  • TypeScript checks: pnpm tsgo
  • Lint/format: pnpm check
  • Format check: pnpm format (oxfmt --check)
  • Format fix: pnpm format:fix (oxfmt --write)
  • Tests: pnpm test (vitest); coverage: pnpm test:coverage
  • Hard gate: before any commit, pnpm check MUST be run and MUST pass for the change being committed.
  • Hard gate: before any push to main, pnpm check MUST be run and MUST pass, and pnpm test MUST be run and MUST pass.
  • Hard gate: if the change can affect build output, packaging, lazy-loading/module boundaries, or published surfaces, pnpm build MUST be run and MUST pass before pushing main.
  • Hard gate: do not commit or push with failing format, lint, type, build, or required test checks.

Coding Style & Naming Conventions

  • Language: TypeScript (ESM). Prefer strict typing; avoid any.
  • Formatting/linting via Oxlint and Oxfmt; run pnpm check before commits.
  • Never add @ts-nocheck and do not disable no-explicit-any; fix root causes and update Oxlint/Oxfmt config only when required.
  • Dynamic import guardrail: do not mix await import("x") and static import ... from "x" for the same module in production code paths. If you need lazy loading, create a dedicated *.runtime.ts boundary (that re-exports from x) and dynamically import that boundary from lazy callers only.
  • Dynamic import verification: after refactors that touch lazy-loading/module boundaries, run pnpm build and check for [INEFFECTIVE_DYNAMIC_IMPORT] warnings before submitting.
  • Extension SDK self-import guardrail: inside an extension package, do not import that same extension via openclaw/plugin-sdk/<extension> from production files. Route internal imports through a local barrel such as ./api.ts or ./runtime-api.ts, and keep the plugin-sdk/<extension> path as the external contract only.
  • Extension package boundary guardrail: inside extensions/<id>/**, do not use relative imports/exports that resolve outside that same extensions/<id> package root. If shared code belongs in the plugin SDK, import openclaw/plugin-sdk/<subpath> instead of reaching into src/plugin-sdk/** or other repo paths via ../.
  • Extension API surface rule: openclaw/plugin-sdk/<subpath> is the only public cross-package contract for extension-facing SDK code. If an extension needs a new seam, add a public subpath first; do not reach into src/plugin-sdk/** by relative path.
  • Never share class behavior via prototype mutation (applyPrototypeMixins, Object.defineProperty on .prototype, or exporting Class.prototype for merges). Use explicit inheritance/composition (A extends B extends C) or helper composition so TypeScript can typecheck.
  • If this pattern is needed, stop and get explicit approval before shipping; default behavior is to split/refactor into an explicit class hierarchy and keep members strongly typed.
  • In tests, prefer per-instance stubs over prototype mutation (SomeClass.prototype.method = ...) unless a test explicitly documents why prototype-level patching is required.
  • Add brief code comments for tricky or non-obvious logic.
  • Keep files concise; extract helpers instead of “V2” copies. Use existing patterns for CLI options and dependency injection via createDefaultDeps.
  • Aim to keep files under ~700 LOC; guideline only (not a hard guardrail). Split/refactor when it improves clarity or testability.
  • Naming: use OpenClaw for product/app/docs headings; use openclaw for CLI command, package/binary, paths, and config keys.
  • Written English: use American spelling and grammar in code, comments, docs, and UI strings (e.g. "color" not "colour", "behavior" not "behaviour", "analyze" not "analyse").

Release / Advisory Workflows

  • Use $openclaw-release-maintainer at .agents/skills/openclaw-release-maintainer/SKILL.md for release naming, version bump coordination, GHSA patch/publish flow, release auth, and changelog-backed release-note workflows.
  • Release and publish remain explicit-approval actions even when using the skill.

Testing Guidelines

  • Framework: Vitest with V8 coverage thresholds (70% lines/branches/functions/statements).
  • Naming: match source names with *.test.ts; e2e in *.e2e.test.ts.
  • Run pnpm test (or pnpm test:coverage) before pushing when you touch logic.
  • Agents MUST NOT modify baseline, inventory, ignore, snapshot, or expected-failure files to silence failing checks without explicit approval in this chat.
  • For targeted/local debugging, keep using the wrapper: pnpm test -- <path-or-filter> [vitest args...] (for example pnpm test -- src/commands/onboard-search.test.ts -t "shows registered plugin providers"); do not default to raw pnpm vitest run ... because it bypasses wrapper config/profile/pool routing.
  • Do not set test workers above 16; tried already.
  • If local Vitest runs cause memory pressure (common on non-Mac-Studio hosts), use OPENCLAW_TEST_PROFILE=low OPENCLAW_TEST_SERIAL_GATEWAY=1 pnpm test for land/gate runs.
  • Live tests (real keys): CLAWDBOT_LIVE_TEST=1 pnpm test:live (OpenClaw-only) or LIVE=1 pnpm test:live (includes provider live tests). Docker: pnpm test:docker:live-models, pnpm test:docker:live-gateway. Onboarding Docker E2E: pnpm test:docker:onboard.
  • Full kit + whats covered: docs/help/testing.md.
  • Changelog: user-facing changes only; no internal/meta notes (version alignment, appcast reminders, release process).
  • Changelog placement: in the active version block, append new entries to the end of the target section (### Changes or ### Fixes); do not insert new entries at the top of a section.
  • Changelog attribution: use at most one contributor mention per line; prefer Thanks @author and do not also add by @author on the same entry.
  • Pure test additions/fixes generally do not need a changelog entry unless they alter user-facing behavior or the user asks for one.
  • Mobile: before using a simulator, check for connected real devices (iOS + Android) and prefer them when available.

Commit & Pull Request Guidelines

  • Use $openclaw-pr-maintainer at .agents/skills/openclaw-pr-maintainer/SKILL.md for maintainer PR triage, review, close, search, and landing workflows.

  • This includes auto-close labels, bug-fix evidence gates, GitHub comment/search footguns, and maintainer PR decision flow.

  • For the repo's end-to-end maintainer PR workflow, use $openclaw-pr-maintainer at .agents/skills/openclaw-pr-maintainer/SKILL.md.

  • /landpr lives in the global Codex prompts (~/.codex/prompts/landpr.md); when landing or merging any PR, always follow that /landpr process.

  • Create commits with scripts/committer "<msg>" <file...>; avoid manual git add/git commit so staging stays scoped.

  • Follow concise, action-oriented commit messages (e.g., CLI: add verbose flag to send).

  • Group related changes; avoid bundling unrelated refactors.

  • PR submission template (canonical): .github/pull_request_template.md

  • Issue submission templates (canonical): .github/ISSUE_TEMPLATE/

Git Notes

  • If git branch -d/-D <branch> is policy-blocked, delete the local ref directly: git update-ref -d refs/heads/<branch>.
  • Agents MUST NOT create or push merge commits on main. If main has advanced, rebase local commits onto the latest origin/main before pushing.
  • Bulk PR close/reopen safety: if a close action would affect more than 5 PRs, first ask for explicit user confirmation with the exact PR count and target scope/query.

Security & Configuration Tips

  • Web provider stores creds at ~/.openclaw/credentials/; rerun openclaw login if logged out.
  • Pi sessions live under ~/.openclaw/sessions/ by default; the base directory is not configurable.
  • Environment variables: see ~/.profile.
  • Never commit or publish real phone numbers, videos, or live configuration values. Use obviously fake placeholders in docs, tests, and examples.
  • Release flow: use the private maintainer release docs for the actual runbook, docs/reference/RELEASING.md for the public release policy, and $openclaw-release-maintainer for the maintainership workflow.

Local Runtime / Platform Notes

  • Vocabulary: "makeup" = "mac app".
  • Rebrand/migration issues or legacy config/service warnings: run openclaw doctor (see docs/gateway/doctor.md).
  • Use $openclaw-parallels-smoke at .agents/skills/openclaw-parallels-smoke/SKILL.md for Parallels smoke, rerun, upgrade, debug, and result-interpretation workflows across macOS, Windows, and Linux guests.
  • For the macOS Discord roundtrip deep dive, use the narrower .agents/skills/parallels-discord-roundtrip/SKILL.md companion skill.
  • Never edit node_modules (global/Homebrew/npm/git installs too). Updates overwrite. Skill notes go in tools.md or AGENTS.md.
  • If you need local-only .agents ignores, use .git/info/exclude instead of repo .gitignore.
  • When adding a new AGENTS.md anywhere in the repo, also add a CLAUDE.md symlink pointing to it (example: ln -s AGENTS.md CLAUDE.md).
  • Signal: "update fly" => fly ssh console -a flawd-bot -C "bash -lc 'cd /data/clawd/openclaw && git pull --rebase origin main'" then fly machines restart e825232f34d058 -a flawd-bot.
  • CLI progress: use src/cli/progress.ts (osc-progress + @clack/prompts spinner); dont hand-roll spinners/bars.
  • Status output: keep tables + ANSI-safe wrapping (src/terminal/table.ts); status --all = read-only/pasteable, status --deep = probes.
  • Gateway currently runs only as the menubar app; there is no separate LaunchAgent/helper label installed. Restart via the OpenClaw Mac app or scripts/restart-mac.sh; to verify/kill use launchctl print gui/$UID | grep openclaw rather than assuming a fixed label. When debugging on macOS, start/stop the gateway via the app, not ad-hoc tmux sessions; kill any temporary tunnels before handoff.
  • macOS logs: use ./scripts/clawlog.sh to query unified logs for the OpenClaw subsystem; it supports follow/tail/category filters and expects passwordless sudo for /usr/bin/log.
  • If shared guardrails are available locally, review them; otherwise follow this repo's guidance.
  • SwiftUI state management (iOS/macOS): prefer the Observation framework (@Observable, @Bindable) over ObservableObject/@StateObject; dont introduce new ObservableObject unless required for compatibility, and migrate existing usages when touching related code.
  • Connection providers: when adding a new connection, update every UI surface and docs (macOS app, web UI, mobile if applicable, onboarding/overview docs) and add matching status + configuration forms so provider lists and settings stay in sync.
  • Version locations: package.json (CLI), apps/android/app/build.gradle.kts (versionName/versionCode), apps/ios/Sources/Info.plist + apps/ios/Tests/Info.plist (CFBundleShortVersionString/CFBundleVersion), apps/macos/Sources/OpenClaw/Resources/Info.plist (CFBundleShortVersionString/CFBundleVersion), docs/install/updating.md (pinned npm version), and Peekaboo Xcode projects/Info.plists (MARKETING_VERSION/CURRENT_PROJECT_VERSION).
  • "Bump version everywhere" means all version locations above except appcast.xml (only touch appcast when cutting a new macOS Sparkle release).
  • Restart apps: “restart iOS/Android apps” means rebuild (recompile/install) and relaunch, not just kill/launch.
  • Device checks: before testing, verify connected real devices (iOS/Android) before reaching for simulators/emulators.
  • iOS Team ID lookup: security find-identity -p codesigning -v → use Apple Development (…) TEAMID. Fallback: defaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers.
  • A2UI bundle hash: src/canvas-host/a2ui/.bundle.hash is auto-generated; ignore unexpected changes, and only regenerate via pnpm canvas:a2ui:bundle (or scripts/bundle-a2ui.sh) when needed. Commit the hash as a separate commit.
  • Release signing/notary credentials are managed outside the repo; maintainers keep that setup in the private maintainer release docs.
  • Lobster palette: use the shared CLI palette in src/terminal/palette.ts (no hardcoded colors); apply palette to onboarding/config prompts and other TTY UI output as needed.
  • When asked to open a “session” file, open the Pi session logs under ~/.openclaw/agents/<agentId>/sessions/*.jsonl (use the agent=<id> value in the Runtime line of the system prompt; newest unless a specific ID is given), not the default sessions.json. If logs are needed from another machine, SSH via Tailscale and read the same path there.
  • Do not rebuild the macOS app over SSH; rebuilds must be run directly on the Mac.
  • Voice wake forwarding tips:
    • Command template should stay openclaw-mac agent --message "${text}" --thinking low; VoiceWakeForwarder already shell-escapes ${text}. Dont add extra quotes.
    • launchd PATH is minimal; ensure the apps launch agent PATH includes standard system paths plus your pnpm bin (typically $HOME/Library/pnpm) so pnpm/openclaw binaries resolve when invoked via openclaw-mac.

Collaboration / Safety Notes

  • When working on a GitHub Issue or PR, print the full URL at the end of the task.
  • When answering questions, respond with high-confidence answers only: verify in code; do not guess.
  • Never update the Carbon dependency.
  • Any dependency with pnpm.patchedDependencies must use an exact version (no ^/~).
  • Patching dependencies (pnpm patches, overrides, or vendored changes) requires explicit approval; do not do this by default.
  • Multi-agent safety: do not create/apply/drop git stash entries unless explicitly requested (this includes git pull --rebase --autostash). Assume other agents may be working; keep unrelated WIP untouched and avoid cross-cutting state changes.
  • Multi-agent safety: when the user says "push", you may git pull --rebase to integrate latest changes (never discard other agents' work). When the user says "commit", scope to your changes only. When the user says "commit all", commit everything in grouped chunks.
  • Multi-agent safety: do not create/remove/modify git worktree checkouts (or edit .worktrees/*) unless explicitly requested.
  • Multi-agent safety: do not switch branches / check out a different branch unless explicitly requested.
  • Multi-agent safety: running multiple agents is OK as long as each agent has its own session.
  • Multi-agent safety: when you see unrecognized files, keep going; focus on your changes and commit only those.
  • Lint/format churn:
    • If staged+unstaged diffs are formatting-only, auto-resolve without asking.
    • If commit/push already requested, auto-stage and include formatting-only follow-ups in the same commit (or a tiny follow-up commit if needed), no extra confirmation.
    • Only ask when changes are semantic (logic/data/behavior).
  • Multi-agent safety: focus reports on your edits; avoid guard-rail disclaimers unless truly blocked; when multiple agents touch the same file, continue if safe; end with a brief “other files present” note only if relevant.
  • Bug investigations: read source code of relevant npm dependencies and all related local code before concluding; aim for high-confidence root cause.
  • Code style: add brief comments for tricky logic; keep files under ~500 LOC when feasible (split/refactor as needed).
  • Tool schema guardrails (google-antigravity): avoid Type.Union in tool input schemas; no anyOf/oneOf/allOf. Use stringEnum/optionalStringEnum (Type.Unsafe enum) for string lists, and Type.Optional(...) instead of ... | null. Keep top-level tool schema as type: "object" with properties.
  • Tool schema guardrails: avoid raw format property names in tool schemas; some validators treat format as a reserved keyword and reject the schema.
  • Never send streaming/partial replies to external messaging surfaces (WhatsApp, Telegram); only final replies should be delivered there. Streaming/tool events may still go to internal UIs/control channel.
  • For manual openclaw message send messages that include !, use the heredoc pattern noted below to avoid the Bash tools escaping.
  • Release guardrails: do not change version numbers without operators explicit consent; always ask permission before running any npm publish/release step.
  • Beta release guardrail: when using a beta Git tag (for example vYYYY.M.D-beta.N), publish npm with a matching beta version suffix (for example YYYY.M.D-beta.N) rather than a plain version on --tag beta; otherwise the plain version name gets consumed/blocked.