Skip to main content
Use this page when you want to make a change to Clawboo and open a pull request. It summarizes the contributor workflow and points at the canonical sources: the repo’s CONTRIBUTING.md is the authority on process; the Internals section explains why the code is shaped the way it is.
The single source of truth for process is CONTRIBUTING.md at the repo root. This page is a guided tour of it with cross-links into the rest of the docs. If the two ever disagree, CONTRIBUTING.md and the root package.json win.

Prerequisites

  • Node.js 22+ and pnpm 9+ (the root package.json declares engines.node >=22.0.0 and engines.pnpm >=9.0.0; the pinned package manager is pnpm@9.15.0).
  • No external runtime is required to develop or test. Clawboo runs agents natively; paste a provider key and the in-process clawboo-native harness handles execution. Connecting OpenClaw, Claude Code, Codex, or Hermes is only needed when you are working on those adapters.

Steps

1. Clone and install

pnpm install resolves the whole workspace, the four globs packages/*, packages/adapters/*, apps/*, and docs (see Monorepo and build for the layout).

2. Run the dev stack

The root dev script runs turbo dev. For the dashboard, apps/web’s dev orchestrator picks a free API port first, then starts the Express API and the Vite SPA on the same port so there is no race. It prints a banner like:
  • The Vite SPA serves on :5173.
  • The Express API binds the resolved port: default 18790, with an auto-fallback that scans up to 20 consecutive ports if 18790 is busy. Pin it with CLAWBOO_API_PORT (see Environment variables).
Clawboo stores all of its state under ~/.clawboo/ (auto-created on first run). To point a dev instance at a throwaway directory, set CLAWBOO_HOME. There are no feature flags; every subsystem ships on, so there is nothing to enable.
Governance ships in track-and-warn mode: budgets record spend and warn at thresholds, but nothing auto-pauses a run until you set a hard cap. See Production defaults.

3. Make your change on a branch

Clawboo follows GitHub Flow: branch from main, push, open a PR, and squash-merge once CI is green. Use a descriptive prefix:

4. Run the local gate before pushing

Run the same checks CI runs, in this order. They are all root scripts in package.json:
What each one guards:
  • pnpm test runs two Vitest projects: a node project for pure logic (*.test.ts) and a jsdom project for React components (*.test.tsx, RTL + MSW + jest-dom + jest-axe). See Testing.
  • pnpm e2e runs Playwright end-to-end, including the durable-board round-trip and the eval smoke suite.
  • pnpm verify:catalog checks the committed marketplace catalog (304 agents, 82 teams) against its committed integrity manifest. It is offline, and it is the gate CI and the release path run.
  • pnpm verify:ingest re-derives the codegen’d catalog from the pinned upstream commits and fails on any drift. It needs network, and runs weekly plus on PRs touching ingestion. If you touched ingestion, regenerate with pnpm ingest:marketplace first. See Codegen and ingestion.
  • pnpm assemble && pnpm test:clean-install (aliased as pnpm prepublish:check) bundles the CLI, packs it, installs the tarball into a throwaway temp dir, and boots that install to catch first-run regressions — through a headless-Chromium pass that fails on any uncaught exception or first-party console error, right up to one real agent run and a second-launch check that the CLI reuses a dashboard already running instead of forking another. It needs network access for the npm install and the same pnpm exec playwright install chromium download as pnpm e2e, and it refuses to run while another Clawboo dashboard holds 1879018809 (stop your pnpm dev server first). This is the same gate the release workflow runs: see Release process.
Running the full gate locally avoids review back-and-forth. Every PR must pass CI: pnpm build, pnpm format:check and pnpm lint (two separate steps of CI’s Lint job, format check first because it takes seconds while turbo lint has to build every workspace dependency), pnpm typecheck, pnpm test:coverage (the same suites as pnpm test, plus a coverage table in the log: informational, not a threshold), pnpm e2e, and CodeQL code scanning. Not every one of those blocks the merge button today, but a red check is a red check. Note pnpm e2e needs a built workspace and a Chromium download (pnpm build, then pnpm exec playwright install chromium).

5. Add a changeset for user-facing changes

Clawboo uses Changesets for versions and changelogs. Any change that affects a published package needs one:
The interactive CLI asks which packages changed, the bump type (patch / minor / major), and a one-line summary, then writes a file under .changeset/. Commit it alongside your code.
Every @clawboo/* library is private: true; only the clawboo CLI publishes to npm, with the libraries inlined into its bundle. So in practice a changeset matters when your change reaches the clawboo CLI’s bundled behavior. Documentation-only, CI-only, and apps/web-only changes do not need a changeset; the dashboard package (@clawboo/web) and @clawboo/docs are in the changeset ignore list, and the dashboard is not published.

6. Open the pull request

Push your branch and open a PR. The PR template walks the checklist. Keep it to one concern per PR; split unrelated changes. Add a test for anything you add (unit logic in Vitest, components in the jsdom project, new end-to-end behavior in Playwright). CI must be green before review, and PRs are squash-merged into main.

Documentation changes

The page you are reading lives in the repo at docs/, and that directory is this site: hand-edited Mintlify Markdown with no build or generation step. Merging a docs PR to main redeploys docs.claw.boo as-is, so the files in the diff are exactly what ships. See Monorepo and build for where docs/ sits in the workspace.
Frontmatter is parsed as YAML, so quote any title or description value that contains a colon, or that starts with @ or a backtick. An unquoted : followed by a space parses as a nested mapping, and Mintlify serves the page as a 404 instead of rendering it. Single and double quotes are both valid YAML; Prettier normalizes them to single quotes when the pre-commit hook formats the page.Same class of breakage, opposite symptom: never put a bare % in a body heading. Mintlify URI-decodes headings into anchor slugs, so invalid percent-encoding fails the page. A % in prose is fine.
The two rules fail in opposite tools, which is why you want both. mint broken-links only validates links, so it misses the frontmatter one entirely; a full mint dev build catches that. The heading % is the reverse: broken-links reports it as a whole-page parse error, while a mint dev build can render straight past it. pnpm check:docs catches both without needing the Mintlify CLI: it is the docs package’s lint script, so it also runs under pnpm lint and in CI’s Lint job on every PR. The repo’s docs/README.md covers the rest: the directory layout, the hand-maintained docs.json navigation, and local preview. Documentation-only changes do not need a changeset (see the note in step 5).

Code guidelines

These are enforced by review and, where possible, by lint:
  • TypeScript strict. No any, no @ts-ignore, no leaking unknown.
  • No console.log. Log through @clawboo/logger (pino).
  • Lucide icons only, never emoji in the UI.
  • Theme tokens, never raw hex: use the CSS variables and Tailwind tokens (brand marks are the only exception). See the design system.
  • Pure where it claims to be. Policy and projection functions stay side-effect-free and unit-testable.
  • No secrets in logs, responses, or storage. A credential’s presence may be shown (the env-var name plus true/false), never its value. See Security.

Architecture invariants to respect

A change must not break the seven architecture invariants. The ones most likely to bite a first contribution:
  • The registry is the source of truth for who exists; the Gateway is the source of truth for how OpenClaw agents run. Reads go through an AgentSource, not directly off the Gateway client.
  • Packages never import apps. Dependency flow is one-way (apps/webpackages/**, packages/adapters/*@clawboo/executor). See the package dependency graph.
  • A teammate is a RuntimeAdapter. New runtimes implement the trait and emit the normalized RuntimeEvent union rather than special-casing the orchestrator.
  • The board is canonical for task/coordination state. Prefer board mutations over prose-scanning heuristics: see Board internals and Delegation and orchestration.
  • Schema changes are additive. There is no migration ladder; the CREATE TABLE IF NOT EXISTS DDL in ensureSchema (packages/db/src/schemaBootstrap.ts) is the sole source of the schema, and reconcileSchema derives the in-place upgrade from it by adding whatever columns an existing database is missing. So a new column is fine as long as it is addable (it may not use PRIMARY KEY, UNIQUE, or a STORED generated column; any DEFAULT must be a literal rather than an expression; a NOT NULL column must carry one; and a REFERENCES column must not have a non-NULL one). A test fails the build on one that is not, comparing against the snapshot in packages/db/src/__tests__/schemaBaseline.ts, which needs no upkeep when you add a column. Changing or removing an existing column still means a fresh ~/.clawboo. See the database schema reference.
The Internals pages flag “caution surfaces”: files that encode load-bearing fixes (cascade prevention, stop-generation, history-hydration gating, deterministic plan keys). Read the relevant internals page before changing one, so you preserve the invariant or replace it with a documented reason.

Release process

Releases are automated and maintainer-only: when changesets land on main, the publish.yml workflow opens a “Version Packages” PR; merging it bumps versions, updates changelogs, and publishes the clawboo CLI. No manual npm publish. The workflow re-runs the whole PR gate before publishing (verify:catalog, build, lint, typecheck, test, then assemble and the pnpm test:clean-install gate), so a release cannot skip a check a pull request had to pass. The catalog gate on that path is the offline one; the live re-derive (verify:ingest) runs in its own workflow so an upstream outage cannot block a release. See Release process for the full pipeline.

License

By contributing, you agree your contributions are licensed under the MIT License. See License and notices.

See also

Last modified on August 10, 2026