Skip to content

Latest commit

 

History

History
211 lines (184 loc) · 20.5 KB

File metadata and controls

211 lines (184 loc) · 20.5 KB

AGENTS.MD

Telegraph style. Root rules only. Read scoped AGENTS.md before subtree work.

Start

  • Repo: https://github.com/openclaw/openclaw
  • Replies: repo-root refs only: extensions/telegram/src/index.ts:80. No absolute paths, no ~/.
  • Run docs list first: pnpm docs:list if available; read relevant docs only.
  • High-confidence answers only when fixing/triaging: verify source, tests, shipped/current behavior, and dependency contracts before deciding.
  • Dependency-backed behavior: read upstream dependency docs/source/types first. Do not assume APIs, defaults, errors, timing, or runtime behavior.
  • Live-verify when feasible. Check env/~/.profile for keys before assuming live tests are blocked; keep secret output redacted.
  • Missing deps: pnpm install, retry once, then report first actionable error.
  • CODEOWNERS: maint/refactor/tests ok. Larger behavior/product/security/ownership: owner ask/review.
  • Wording: product/docs/UI/changelog say "plugin/plugins"; extensions/ is internal.
  • New channel/plugin/app/doc surface: update .github/labeler.yml + GH labels.
  • New AGENTS.md: add sibling CLAUDE.md symlink.

Map

  • Core TS: src/, ui/, packages/; plugins: extensions/; SDK: src/plugin-sdk/*; channels: src/channels/*; loader: src/plugins/*; protocol: src/gateway/protocol/*; docs/apps: docs/, apps/, Swabble/.
  • Installers: sibling ../openclaw.ai.
  • Scoped guides exist in: extensions/, src/{plugin-sdk,channels,plugins,gateway,gateway/protocol,agents}/, test/helpers*/, docs/, ui/, scripts/.

Architecture

  • SparseKernel is a local multi-agent kernel, not just a database wrapper. In OpenClaw docs/code, call this OpenClaw SparseKernel when discussing the implementation direction.
  • SparseKernel keeps many logical agents as compact durable state and materializes only the active slice through leased tools, files, browsers, and sandboxes.
  • Do not add ad hoc JSON files for runtime coordination. Use SQLite migrations for structured runtime state.
  • SQLite is the SparseKernel ledger, not a dumping ground. Store agents, sessions, transcript events, tasks, leases, tool calls, capabilities, trust zones, broker state, artifact metadata, audit logs, and usage records there.
  • Large blobs must go through the content-addressed artifact store. Do not store screenshots, videos, browser traces, downloads, PDFs, repo snapshots, or exported transcript blobs directly in SQLite by default.
  • Agents/plugins never get raw SparseKernel DB access. Route state changes through kernel APIs, SDKs, and brokers that enforce capabilities and emit audit records.
  • Expensive resources are leased by trust zone. Sandboxes are allocated by trust boundary, not by logical agent.
  • Browser processes are pooled by trust zone; browser contexts are leased by task/session/agent.
  • BrowserContext isolation is session isolation, not host isolation. Playwright route blocking is not a hard security boundary.
  • Do not disable browser sandboxing or weaken sandbox network/filesystem policy casually. If a backend provides only local/no isolation, name that explicitly in docs, status, and tests.
  • Tool calls must go through the tool broker where feasible. Sensitive tool, browser, sandbox, and artifact operations need capability checks plus audit events.
  • SparseKernel must stay usable on small VMs: bounded active workers, scarce browser/sandbox leases, compact logs, and retention policies.
  • Add tests for migrations, task leases, artifact dedupe, capability allow/deny, audit events, and broker lifecycle behavior.
  • Preserve backwards compatibility when introducing SparseKernel into existing OpenClaw runtime paths.
  • Core stays extension-agnostic. No bundled ids in core when manifest/registry/capability contracts work.
  • Runtime coordination belongs in the local kernel ledger. Prefer typed runtime DB migrations over ad hoc JSON state files for sessions, tasks, leases, tool calls, broker state, resource accounting, permissions, and audit trails.
  • SQLite is structured state only. Large screenshots, downloads, PDFs, traces, videos, HTML dumps, workspace snapshots, and exported transcripts are artifacts in a content-addressed store with DB metadata/access records.
  • Agents/plugins never get raw kernel DB access. Route state changes through runtime APIs/brokers that enforce capabilities and emit audit records.
  • Pool expensive isolation by trust zone, not logical agent. Browser process pools and sandbox pools are keyed by trust zone; browser contexts and leases are per task/session/agent.
  • BrowserContext isolation is session isolation, not host isolation. Route blocking and Playwright request guards are convenience controls, not hard security boundaries.
  • Do not disable browser sandboxing or weaken sandbox network/filesystem policy casually. If a backend provides only local/no isolation, name that explicitly in docs, status, and tests.
  • Brokered tools are the target shape. Sensitive tool invocation, browser allocation, sandbox allocation, and artifact reads/writes need capability checks plus audit events.
  • Add migration and broker operation tests with every runtime-ledger schema or broker API change.
  • Extensions cross into core only via openclaw/plugin-sdk/*, manifest metadata, injected runtime helpers, documented barrels (api.ts, runtime-api.ts).
  • Extension prod code: no core src/**, src/plugin-sdk-internal/**, other extension src/**, or relative outside package.
  • Core/tests: no deep plugin internals (extensions/*/src/**, onboard.js). Use api.ts, SDK facade, generic contracts.
  • Extension-owned behavior stays extension-owned: repair, detection, onboarding, auth/provider defaults, provider tools/settings.
  • Owner boundary: fix owner-specific behavior in the owner module. Shared/core gets generic seams only; no owner ids, dependency strings, defaults, migrations, or recovery policy. If a bug names an extension or its dependency, start in that extension and add a generic core seam only when multiple owners need it.
  • Legacy config repair: doctor/fix paths, not startup/load-time core migrations.
  • Core test asserting extension-specific behavior: move to owner extension or generic contract test.
  • New seams: backwards-compatible, documented, versioned. Third-party plugins exist.
  • Channels: src/channels/** is implementation; plugin authors get SDK seams.
  • Providers: core owns generic loop; provider plugins own auth/catalog/runtime hooks.
  • Gateway protocol changes: additive first; incompatible needs versioning/docs/client follow-through.
  • Config contract: exported types, schema/help, metadata, baselines, docs aligned. Retired public keys stay retired; compat in raw migration/doctor.
  • Direction: manifest-first control plane; targeted runtime loaders; no hidden contract bypasses; broad mutable registries transitional.
  • Prompt cache: 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 + Bun paths working.
  • Install: pnpm install (keep Bun lock/patches aligned if touched).
  • CLI: pnpm openclaw ... or pnpm dev; build: pnpm build.
  • Smart gate: pnpm check:changed; explain pnpm changed:lanes --json; staged preview pnpm check:changed --staged.
  • Sparse worktrees: pnpm check:changed is sparse-safe and may skip sparse-missing typecheck projects; do not expand sparse checkout just to satisfy changed-gate tsgo. Direct pnpm tsgo* remains strict; use a fuller worktree when you need direct typecheck proof.
  • Prod sweep: pnpm check; tests: pnpm test, pnpm test:changed, pnpm test:serial, pnpm test:coverage.
  • Extension tests: pnpm test:extensions, pnpm test extensions, pnpm test extensions/<id>.
  • Targeted tests: pnpm test <path-or-filter> [vitest args...]; never raw vitest.
  • Vitest flags only; no Jest flags like --runInBand. For serial runs use pnpm test:serial or OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test ....
  • Typecheck: tsgo lanes only (pnpm tsgo*, pnpm check:test-types); do not add tsc --noEmit, typecheck, check:types.
  • Formatting: use oxfmt, not Prettier. Prefer pnpm format:check / pnpm format; for targeted files use pnpm exec oxfmt --check --threads=1 <files...> or pnpm exec oxfmt --write --threads=1 <files...>.
  • Linting: use repo wrappers (pnpm lint:*, scripts/run-oxlint.mjs); do not invoke generic JS formatters/lints unless a repo script uses them.
  • Heavy checks: OPENCLAW_LOCAL_CHECK=1, mode OPENCLAW_LOCAL_CHECK_MODE=throttled|full; CI/shared use OPENCLAW_LOCAL_CHECK=0.
  • Blacksmith/Testbox is maintainer opt-in, not a repo-wide default. If Blacksmith access is available and OPENCLAW_TESTBOX=1 is set, or a maintainer's personal AGENTS rules ask for it, use Testbox for broad, slow, Docker, live, E2E, full-suite, or CI-parity validation instead of running those heavy lanes locally. Use OPENCLAW_LOCAL_CHECK_MODE=throttled|full as the explicit local escape hatch.
  • Testbox use: run from repo root, pre-warm early with blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90, reuse the returned tbx_... id for all run/download commands, and stop boxes you created before handoff. Timeout bins: 90 minutes default, 240 multi-hour, 720 all-day, 1440 overnight; anything above 1440 needs explicit approval and cleanup.
  • Testbox full-suite profile: blacksmith testbox run --id <ID> "env NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test". For installable package proof, prefer the GitHub Package Acceptance workflow over ad hoc Testbox commands.

GitHub / CI

  • Triage: list first, hydrate few. Use bounded gh --json --jq; avoid repeated full comment scans.
  • Automatic PR/issue discovery: skip maintainer-owned items unless directly relevant. Do not comment, close, label, retitle, rebase, fix up, or land them without Peter asking.
  • PR scan/triage: no unsolicited PR comments/reviews. Report in chat only unless explicitly asked, or a close/duplicate action needs a reason comment.
  • Search/dedupe: prefer gh search issues 'repo:openclaw/openclaw is:open <terms>' --json number,title,state,updatedAt --limit 20.
  • GitHub search boolean text is fussy. If OR queries return empty, split exact terms and search title/body/comments separately before concluding no hits.
  • PR shortlist: gh pr list ...; then gh pr view <n> --json number,title,body,closingIssuesReferences,files,statusCheckRollup,reviewDecision.
  • After landing PR: search duplicate open issues/PRs. Before closing: comment why + canonical link.
  • GH comments with markdown backticks, $, or shell snippets: avoid inline double-quoted --body; use single quotes or --body-file.
  • PR execution artifacts/screenshots: attach them to the PR, comment, or an external artifact store. Do not add .github/pr-assets or other PR-only assets to the repo.
  • PR review answer must explicitly cover: what bug/behavior we are trying to fix; PR/issue URL(s) and affected endpoint/surface; whether this is the best possible fix, with high-certainty evidence from code, tests, CI, and shipped/current behavior.
  • CI polling: exact SHA, needed fields only. Example: gh api repos/<owner>/<repo>/actions/runs/<id> --jq '{status,conclusion,head_sha,updated_at,name,path}'.
  • Post-land wait: minimal. Exact landed SHA only. If superseded on main, same-branch cancel-in-progress cancellations are expected; stop once local touched-surface proof exists. Never wait for newer unrelated main unless asked.
  • Wait matrix:
    • never: Auto response, Labeler, Docs Sync Publish Repo, Docs Agent, Test Performance Agent, Stale.
    • conditional: CI exact SHA only; Docs only docs task/no local docs proof; Workflow Sanity only workflow/composite/CI-policy edits; Plugin NPM Release only plugin package/release metadata.
    • release/manual only: Docker Release, OpenClaw NPM Release, macOS Release, OpenClaw Release Checks, Cross-OS Release Checks, NPM Telegram Beta E2E.
    • explicit/surface only: QA-Lab - All Lanes, Scheduled Live And E2E, Install Smoke, CodeQL, Sandbox Common Smoke, Parity gate, Blacksmith Testbox, Control UI Locale Refresh.
  • /landpr: do not idle on auto-response or check-docs. Treat docs as local proof unless check-docs already failed with actionable relevant error.
  • Poll 30-60s. Fetch jobs/logs/artifacts only after failure/completion or concrete need.

Gates

  • Pre-commit hook: staged formatting only. Validation explicit.
  • Changed lanes:
    • core prod: core prod typecheck + core tests
    • core tests: core test typecheck/tests
    • extension prod: extension prod typecheck + extension tests
    • extension tests: extension test typecheck/tests
    • public SDK/plugin contract: extension prod/test too
    • unknown root/config: all lanes
  • Before handoff/push for code/test/runtime/config changes: pnpm check:changed. Tests-only: pnpm test:changed. Full prod sweep: pnpm check.
  • Docs/changelog-only and CI/workflow metadata-only changes are not changed-gate work by default. Use git diff --check plus the relevant formatter/docs/workflow sanity check; escalate to pnpm check:changed only when scripts, test config, generated docs/API, package metadata, or runtime/build behavior changed.
  • Rebase sanity: after a green pnpm check:changed, a clean rebase onto current origin/main does not require rerunning the full changed gate when the rebase has no conflicts and the branch diff is materially unchanged. Do a quick git status, git diff --check, and diff/stat sanity check; rerun targeted or full checks only if conflict resolution, upstream overlap, generated drift, dependency/config changes, or touched-file content changes make the prior result stale.
  • Landing on main: verify touched surface near landing. Default feasible bar: pnpm check + pnpm test.
  • Hard build gate: pnpm build before push if build output, packaging, lazy/module boundaries, or published surfaces can change.
  • Do not land related failing format/lint/type/build/tests. If unrelated on latest origin/main, say so with scoped proof.
  • Generated/API drift: pnpm check:architecture, pnpm config:docs:gen/check, pnpm plugin-sdk:api:gen/check. Track docs/.generated/*.sha256; full JSON ignored.

Code

  • TS ESM, strict. Avoid any; prefer real types, unknown, narrow adapters.
  • No @ts-nocheck. Lint suppressions only intentional + explained.
  • External boundaries: prefer zod or existing schema helpers.
  • Runtime branching: discriminated unions/closed codes over freeform strings.
  • Avoid semantic sentinels: ?? 0, empty object/string, etc.
  • Dynamic import: no static+dynamic import for same prod module. Use *.runtime.ts lazy boundary. After edits: pnpm build; check [INEFFECTIVE_DYNAMIC_IMPORT].
  • Cycles: keep pnpm check:import-cycles + architecture/madge green.
  • Classes: no prototype mixins/mutations. Prefer inheritance/composition. Tests prefer per-instance stubs.
  • Comments: brief, only non-obvious logic.
  • Split files around ~700 LOC when clarity/testability improves.
  • Naming: OpenClaw product/docs; openclaw CLI/package/path/config.
  • English: American spelling.

Tests

  • Vitest. Colocated *.test.ts; e2e *.e2e.test.ts; example models sonnet-4.6, gpt-5.4.
  • Avoid brittle tests that grep workflow/docs strings for operator policy. Prefer executable behavior, parsed config/schema checks, or live run proof; put release/CI policy reminders in AGENTS/docs instead.
  • Clean timers/env/globals/mocks/sockets/temp dirs/module state; --isolate=false safe.
  • Hot tests: avoid per-test vi.resetModules() + heavy imports. Measure with pnpm test:perf:imports <file> / pnpm test:perf:hotspots --limit N.
  • Seam depth: pure helper/contract unit tests; one integration smoke per boundary.
  • Mock expensive seams directly: scanners, manifests, registries, fs crawls, provider SDKs, network/process launch.
  • Prefer injection; if module mocking, mock narrow local *.runtime.ts, not broad barrels or openclaw/plugin-sdk/*.
  • Share fixtures/builders; delete duplicate assertions; assert behavior that can regress here.
  • Do not edit baseline/inventory/ignore/snapshot/expected-failure files to silence checks without explicit approval.
  • Do not run multiple independent pnpm test/Vitest commands concurrently in the same worktree. They can race on node_modules/.experimental-vitest-cache and fail with ENOTEMPTY. Use one grouped pnpm test ... invocation, run targeted lanes sequentially, or set distinct OPENCLAW_VITEST_FS_MODULE_CACHE_PATH values when true parallel Vitest processes are needed.
  • Test workers max 16. Memory pressure: OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test.
  • Live: OPENCLAW_LIVE_TEST=1 pnpm test:live; verbose OPENCLAW_LIVE_TEST_QUIET=0.
  • Guide: docs/help/testing.md.

Docs / Changelog

  • Docs change with behavior/API. Use docs list/read_when hints; docs links per docs/AGENTS.md.
  • Changelog user-facing only; pure test/internal usually no entry.
  • Changelog placement: active version ### Changes/### Fixes; every added entry must include at least one Thanks @author attribution, using credited GitHub username(s). Never add Thanks @codex, Thanks @openclaw, or Thanks @steipete.
  • Changelog bullets are always single-line. No wrapping/continuation across multiple lines. Long entries stay on one long line so dedupe, PR-ref, and credit-audit tooling work and so the visual style stays uniform.

Git

  • Commit via scripts/committer "<msg>" <file...>; stage intended files only. It formats staged files; still run gates.
  • Commits: conventional-ish, concise, grouped.
  • No manual stash/autostash unless explicit. No branch/worktree changes unless requested.
  • main: no merge commits; rebase on latest origin/main before push. Do not keep chasing main with repeated full gates after one green run plus a clean rebase sanity pass.
  • User says commit: your changes only. commit all: all changes in grouped chunks. push: may git pull --rebase first.
  • Do not delete/rename unexpected files; ask if blocking, else ignore.
  • Bulk PR close/reopen >5: ask with count/scope.
  • PR/issue workflows: $openclaw-pr-maintainer. /landpr: ~/.codex/prompts/landpr.md.

Security / Release

  • Never commit real phone numbers, videos, credentials, live config.
  • Secrets: channel/provider creds in ~/.openclaw/credentials/; model auth profiles in ~/.openclaw/agents/<agentId>/agent/auth-profiles.json.
  • Env keys: check ~/.profile.
  • Dependency patches/overrides/vendor changes need explicit approval. pnpm.patchedDependencies exact versions only.
  • Carbon pins owner-only: do not change @buape/carbon unless Shadow (@thewilloftheshadow, verified by gh) asks.
  • Releases/publish/version bumps need explicit approval. Release docs: docs/reference/RELEASING.md; use $openclaw-release-maintainer.
  • GHSA/advisories: $openclaw-ghsa-maintainer.
  • Beta tag/version match: vYYYY.M.D-beta.N -> npm YYYY.M.D-beta.N --tag beta.

Apps / Platform

  • Before simulator/emulator testing, check real iOS/Android devices.
  • "restart iOS/Android apps" = rebuild/reinstall/relaunch, not kill/launch.
  • SwiftUI: Observation (@Observable, @Bindable) over new ObservableObject.
  • Mac gateway: use app or openclaw gateway restart/status --deep; no ad-hoc tmux gateway. Logs: ./scripts/clawlog.sh.
  • Version bump touches: package.json, apps/android/app/build.gradle.kts, apps/ios/version.json + pnpm ios:version:sync, macOS Info.plist, docs/install/updating.md. Appcast only for Sparkle release.
  • Mobile LAN pairing: plaintext ws:// loopback-only. Private-network ws:// needs OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1; Tailscale/public use wss:// or tunnel.
  • A2UI hash src/canvas-host/a2ui/.bundle.hash: generated; ignore unless running pnpm canvas:a2ui:bundle; commit separately.

Ops / Footguns

  • Remote install docs: docs/install/{exe-dev,fly,hetzner}.md. Parallels smoke: $openclaw-parallels-smoke; Discord roundtrip: parallels-discord-roundtrip.
  • Rebrand/migration/config warnings: run openclaw doctor.
  • Never edit node_modules.
  • Local-only .agents ignores: .git/info/exclude, not repo .gitignore.
  • CLI progress: src/cli/progress.ts; status tables: src/terminal/table.ts.
  • Connection/provider additions: update all UI surfaces + docs + status/config forms.
  • Provider tool schemas: prefer flat string enum helpers over Type.Union([Type.Literal(...)]); some providers reject anyOf. Not a repo-wide protocol/schema ban.
  • External messaging: no token-delta channel messages. Follow docs/concepts/streaming.md; preview/block streaming uses edits/chunks and preserves final/fallback delivery.