Contributing

What kinds of help are most useful, how to set up for development, and what to run before opening a pull request.

View Markdown
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

  1. Fork the repo and work on a focused branch.
  2. Add or update tests for what you changed, including regressions.
  3. If you're fixing a real accounting error, add a synthetic or fully redacted fixture that would have caught it.
  4. 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.