Contributing
How we work on this codebase.
How we work on this codebase.
Branch and PR flow
- Branch from
main:git checkout -b <name>/<short-description> - Commit early and often locally; tidy commits before PR
- Open a PR against
main. CI runs lint + typecheck + tests + builds preview deploy - Get a review, address feedback
- Merge — squash by default unless the commits genuinely tell a story
PR title: present-tense, imperative. Example: add paper broker partial fill support.
PR description: what changed and why. Link the relevant ADR if applicable.
Commits
- Imperative present tense:
add X, notadded Xoradds X - One logical change per commit (within reason — don't split rename + edit hair-splitty)
- Don't commit
console.logdebugging - Don't commit commented-out code. If it's worth keeping, it's worth a real implementation; if not, delete
Code style
- TypeScript strict mode everywhere. No
any, no@ts-ignorewithout a comment explaining why. - Prefer
typeoverinterfaceunless declaration merging is needed. - Functions over classes unless state genuinely benefits from class encapsulation.
- Named exports over default exports, except where a tool / framework expects defaults (Next.js page/layout/route, default-exported tool definitions).
- Path imports:
@repo/<package>for cross-package; relative for within-package. - No barrel re-exports that hide where things live (i.e., don't make a
packages/everything/index.ts). - Comments: only when the why isn't obvious from the code. Never describe what the code does — the code does that.
ESLint + Prettier enforce most of this. CI fails if pnpm lint fails.
Adding a new tool
- Create
packages/tools/src/tools/<name>.tsexportingdefineTool(...) - Register it in
packages/tools/src/registry.ts - Write a unit test in
packages/tools/src/tools/__tests__/<name>.test.ts - If it's mode-restricted (e.g., write-only), set
modesaccordingly - If it's an introspection tool, also add to
introspectionToolNames - Verify it shows up in the tool catalog UI by running
pnpm devand opening the skill editor
Adding a new database table or column
- Create a new migration:
supabase migration new <description> - Write the SQL in the generated file
- Apply locally:
supabase migration up - Regenerate types:
supabase gen types typescript > packages/db/types.ts - Update
docs/architecture/data-model.mdwith the new shape + RLS notes - PR — CI applies the migration to the dev project on preview deploy
Migrations are append-only. Don't edit a migration that has merged. Add a new one to change it.
Adding a new ADR
When you make a non-trivial architectural decision:
- Copy
docs/decisions/0000-template.mdtodocs/decisions/<next-number>-<slug>.md - Fill it out — Context, Decision, Alternatives, Consequences
- Update
docs/README.mdto list the new ADR - Reference it from any relevant doc that touches the decision
- PR with the code change + the ADR together
A decision is non-trivial if:
- It affects multiple packages / services
- It commits us to a vendor / library / pattern
- It has a real alternative that wasn't picked
- A future reader would ask "why did they do it this way?"
Trivial decisions (file naming, choice of one helper library among equivalents) don't need ADRs.
Tests
- Co-locate tests next to source:
foo.ts+foo.test.ts(or in__tests__/foo.test.tsfor many tests) - Unit tests with
vitest— fast, watchable - Integration tests for the Execution Engine and broker adapters
- For the agent runtime, use AI SDK's
MockLanguageModelV2to keep tests deterministic - No live network calls in tests (no real Hyperliquid, no real model calls)
Coverage isn't a number we enforce. Cover what's load-bearing — the engine, the schemas, anything where a bug means lost money.
Documentation
If your change affects how the system works:
- Update the relevant doc in
docs/ - A docs-only PR is fine; small docs updates with code changes are even better
- If you add a new package or service, add it to
docs/architecture/overview.md's component list
If your change introduces a new vocabulary term: add it to docs/product/glossary.md.
Reviewing PRs
When reviewing:
- Read the description — confirm what the PR claims to do matches the diff
- Check trust boundaries — does the diff cross a boundary defined in trust-boundaries.md? Extra scrutiny.
- Check engine path — any change to
packages/execution-engine,packages/brokers/*, or risk caps gets careful read - Run it — for UI changes, pull the preview deploy and click around
- Test scenarios the PR didn't cover — edge cases, empty states, error paths
- Question additions — every new file, dependency, abstraction is debt; the bar is "do we need this?"
Approve when it ships value without regressions. Request changes when something is wrong, not when it's stylistic.
Don't
- Don't add a dependency without checking bundle impact for client code, security history (
npm audit), and license - Don't disable CI checks with
--no-verifyto land a PR. Fix the underlying issue. - Don't merge with failing CI. If CI is flaky, fix the flake, don't bypass.
- Don't bypass the Execution Engine. Every code path that hits a broker goes through it.
- Don't add
if (process.env.NODE_ENV === 'production') { ... }for behavior differences. Use real config / feature flags. - Don't catch and swallow errors. Log + rethrow, or handle deliberately.
- Don't write comments that restate the code. Write code that doesn't need them.
What to do when you find a bug
- Reproduce locally
- Write a failing test that captures the bug
- Fix the bug
- Confirm the test passes
- PR
For trading-critical bugs (anything in the engine, risk path, or broker adapters): also flag in the PR description so reviewers know to look closely.
Releases
In MVP: continuous deployment. Merge to main = prod deploy. No release process beyond that.
Post-MVP, we may introduce a release-train pattern if deploy cadence outpaces our ability to QA. Adding this isn't planned, just acknowledged.
When in doubt
- Re-read the relevant ADR
- Ask in PR comments
- Open an issue for discussion before writing code if the direction isn't clear
The cost of confirming a direction is low. The cost of rewriting after merging the wrong direction is high.