Thanks for considering a contribution. codeArbiter is one repository-owned governance product with a shared internal core and three governance adapters for Claude Code, Codex, and Pi. It enforces development discipline through gates, so it holds itself to the same bar. This guide explains how to get set up, what the gates expect, and how to get a change merged.
By participating you agree to abide by our Code of Conduct. Read the contributor agreement status before submitting: no CLA is currently in force, and the retired template is not an assent mechanism.
- Report a bug. Open an issue. A failing repro (the smallest command sequence that reproduces it) is worth a great deal.
- Run a Feature Forge preview and send data. This is the fastest way to help a
preview graduate. See Feature Forge; each preview
names its opt-in and the evidence it still needs.
ca-piusers are especially welcome to report real-repository host or workflow mismatches while the adapter remains in preview. - Improve docs. Corrections and clarifications are always welcome.
- Propose or build a feature. Open an issue first so we can align on scope before you invest the work.
- Python 3 on
PATH. Every hook is Python (stdlib only; no third-party packages). Without it, Claude Code can leave an unresolved hook inactive, Codex reports a handler failure, and Pi blocks mutating calls with an interpreter breadcrumb. None of those states is active governance. git config user.emailset. Overrides and ADRs are attributed to that identity; the audit trail depends on a real attribution.- Node.js, if you touch the cost-arbitrage farm dispatcher under
plugins/ca/tools/, the Pi adapter underplugins/ca-pi/tools/, or the docs site (TypeScript + Vitest/Astro).
The structured artifact workflow also needs the installation-pinned native
ca-artifact payload. Developing that executable requires the Go version declared
in core/artifacts/go.mod. A source checkout or Python installation alone does
not establish the complete installed-host workflow capability.
git clone https://github.com/arbiterForge/codeArbiter
cd codeArbiterFor example, load the Claude Code adapter as a local marketplace to dogfood that host's changes:
/plugin marketplace add .
/plugin install ca@codearbiter
This repo is itself an arbiter-enabled repo (.codearbiter/CONTEXT.md carries
arbiter: enabled), so a session here opens with the orchestrator active.
Follow the shared
verification-boundary: run
the smallest fresh local test set that proves the changed behavior and affected
contracts. For a hook change, that normally means the directly affected test
module or case, for example:
python -m unittest plugins.ca.hooks.tests.test_<affected_module>If you touched the farm dispatcher:
cd plugins/ca/tools
npm install
npm test # VitestCI (.github/workflows/ci.yml) runs the exhaustive impact-selected suite on
GitHub's hosted Windows, macOS, and Linux runners, plus plugin-reference and
cold-install guards. The exact-head merge-readiness aggregate must be green; a
missing, stale, cancelled, or red run blocks merge. Contributors do not need to
replay that full matrix locally before opening the PR.
codeArbiter governs its own development. Two things follow from that:
-
Editing the framework itself (skill/agent/command/hook bodies,
arbiter.md, settings) goes through thedangerousmode plane: typemode --dangerous, a deterministic whole-prompt token flip — friction, not a gate — intercepted before the turn reaches the model. Entry and exit are each logged to.codearbiter/overrides.log.mode --arbiterexits it explicitly, and a new session always resolves back toarbiter. -
Every shipped adapter-payload change requires that adapter's version bump. Repository-only docs and tests are not adapter payload. The two-axis model: the affected adapter's SemVer versions its complete payload (any change to shipped adapter files bumps that adapter's version, and CI enforces this), while the Feature Forge label marks per-feature previews that are off by default until real-world data earns promotion. New behavior ships
previewand opt-in first.
- Branch off
main. Never commit tomaindirectly, and never force-push (the hooks block both). Use a descriptive branch name (fix/…,feat/…,docs/…,chore/…). - Write tests first for behavioral changes. New hook behavior needs a test
under
plugins/ca/hooks/tests/; prose/docs changes don't. - Use Conventional Commits:
feat:,fix:,docs:,chore:,refactor:, etc. The release tooling derives the SemVer bump from commit history, so the prefix matters. - Bump the version if you changed any shipped payload file, and add a
CHANGELOG.mdentry. - Record an ADR (
/ca:adr) for an architectural decision. ADRs are user-attributed and live under.codearbiter/decisions/. - Open a PR against
mainand fill out the pull request template. Reference any issue it closes.
A maintainer reviews; CI must be green. Changes land via PR. main moves only
through a merged PR, never a direct write.
If your change touches the hooks, read docs/hooks.md first. It
documents every hook, what it reads/writes, and the two bounded, nonblocking
background network operations: remote refresh through git fetch and the daily
GitHub Releases check. Preserve those boundaries: hooks are stdlib-only Python,
must degrade safely on failure, and guard hooks must exit 0 (do nothing) in a
repo that hasn't opted in.
Hook Python is canonical in core/pysrc/ and vendored byte-identically into each
plugin's hooks/ by python tools/sync-core.py (CI gates it with --check). Edit
core, re-vendor, commit both — never a vendored copy directly. The only per-plugin
Python file is hooks/_host.py.
The shared command, skill, include, orchestrator, and role-charter sources are
rendered from core/surface/ templates into each applicable host adapter by
python tools/build-surface.py — see core/surface/README.md
for the token/conditional grammar and the house rules. Never edit a rendered file:
edit the template, run the tool, commit templates and outputs together. CI's
surface job (build-surface.py --check) fails on drift in either direction.
On Windows, .gitattributes pins the generated trees to LF; if a pre-existing
checkout still has CRLF working copies, refresh them (git checkout-index -f on the
affected paths, or re-clone) before running --check locally.
Open a discussion or issue. For anything security-sensitive, follow the Security Policy instead of opening a public issue.