Contributing
What kinds of help are most useful, how to set up for development, and what to run before opening a pull request.
Browse documentation
On this page
Balsa is early, and help is welcome, especially anything that makes the
numbers more correct, easier to trace, more secure, or more useful. The code,
issues, and pull requests are at
In private testing and not yet available..
If this page and CONTRIBUTING.md in the repo ever disagree, go with
CONTRIBUTING.md.
Before you start
- Check existing issues before opening a new one.
- For big changes to the product, data model, or accounting, open an issue first so we can talk it through.
- Don't put real company data, credentials, personal information, or unredacted financial documents in issues, fixtures, tests, or pull requests.
- Report security problems privately, as described in
SECURITY.md, not in a public issue.
Local development
You'll need Node.js 22+, pnpm 10+, Docker, and an OpenAI or OpenRouter API key.
pnpm run setup
pnpm run doctor
pnpm dev
AUTH_MODE=disabled is fine for local development. Just don't expose that
instance to a network.
Making a change
- Fork the repo and work on a focused branch.
- Add or update tests for what you changed, including regressions.
- If you're fixing a real accounting error, add a synthetic or fully redacted fixture that would have caught it.
- Update the docs if behavior or configuration changes.
Before opening a pull request
pnpm run verify
pnpm lint
Also run pnpm acceptance if you touched ingestion, financial calculations,
database behavior, or the Company Zero workflow.
pnpm test includes database tests. They run when DATABASE_URL or
TEST_DATABASE_URL points at a migrated PostgreSQL and skip otherwise. Run
pnpm db:migrate first to include the company repository and row level
security tests.
Run pnpm isolation if you changed company switching, company-scoped routes,
provisioning or roles, the audit log, or row level security. It tests a running
app from the outside rather than unit-testing code, so start the app first, set
BASE_URL to it, and choose a mode with ISOLATION_AUTH_MODE=disabled or
ISOLATION_AUTH_MODE=better-auth. Both modes need to pass. Use an isolated synthetic database and application;
the script creates and deletes companies and is not safe as a customer-data fixture. In Better Auth mode
it also checks that registering without the sign-up code fails, and that a
second user sees the existing companies instead of getting a new one. For that,
run the app with AUTH_ALLOW_SIGN_UP=true and pass its AUTH_SIGN_UP_CODE as
ISOLATION_SIGN_UP_CODE.
In the pull request
Describe the problem, what happened before and after your change, how you tested it, and anything it affects in the schema, security, migrations, deployment, or accounting. Also say whether the model suggests the result or code decides and calculates it. That line matters a lot in this project.
Licensing
Balsa is licensed under the Apache License 2.0. Under Section 5, anything you submit for inclusion is covered by the same license unless you say otherwise. There's no separate contributor agreement to sign.
For private questions, email Taylor Davidson at hello@hemrock.com.
Documentation contributions
The website lives in balsa-site, separately from the application. Public
guides are Markdown in content/docs; private plans in internal/ are not
published. Keep claims tied to implemented behavior and distinguish accounting
foundation features from narrower planning-workflow support.
In the site repository, run pnpm check:docs, pnpm typecheck, pnpm lint,
pnpm build, and pnpm check:export. The build regenerates raw Markdown and
llms.txt; include those generated public files with source documentation changes.