Nodaro Docs
DocumentationNode ReferenceModelsAI Agents (MCP)DevelopersSelf-hostingResearch

Contributing

Contribute code to Nodaro on GitHub. Prepare the development environment, branch from dev, run the tests, add a changeset and sign the contributor agreement.

Contributing to Nodaro means sending code to the public repository, github.com/nodaroai/app.nodaro.ai, as a pull request. Nodaro is source-available under the Nodaro Sustainable Use License. This page covers the development setup, branches, pull requests, tests and the contributor agreement.

To run Nodaro on your own server instead, start with the Quickstart. To build on the API, see the SDK.

The repository

The repository is one npm workspaces monorepo:

FolderWhat lives there
backend/The Fastify API, the BullMQ workers and the orchestrator. Node.js 22, TypeScript.
frontend/The Vite app: the editor, the app runner and the admin panel. React 19, React Router 7, React Flow.
packages/@nodaro/shared, pure logic shared across the stack; @nodaro/sdk, the typed REST client; @nodaro/cli; @nodaro/prompts, the prompt layer; and the Remotion video compositions.
supabase/The database schema, as forward-only SQL migrations.
docs/The documentation in the repository, including design notes that explain the reasons behind key features.
scripts/Repository utilities, such as the architecture graph generator and audits.
.changeset/Pending version bumps for the published packages.

The house rules are in CLAUDE.md at the repository root: coding standards, the checklist for adding a model provider and the checklist for adding a node. Read it before a non-trivial pull request. Architecture explains how the pieces fit together.

Prepare the development environment

You need Node.js 22 or later, with npm.

Clone and install

git clone https://github.com/nodaroai/app.nodaro.ai
cd app.nodaro.ai
npm install        # installs every workspace

Configure the environment

cp .env.example .env

Set at least SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, SUPABASE_ANON_KEY, INTERNAL_ORCHESTRATOR_SECRET and one provider key, such as KIE_API_KEY, REPLICATE_API_TOKEN or ANTHROPIC_API_KEY. Generate the secrets:

echo "INTERNAL_ORCHESTRATOR_SECRET=$(openssl rand -hex 32)" >> .env
echo "NODARO_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env

The easiest database is a free project on supabase.com. A fully local stack with the Supabase CLI, supabase start, also works but takes more setup. Workflow runs also need Redis, at REDIS_URL, which defaults to redis://localhost:6379. .env.example lists every supported variable, and Configuration explains them.

Build the shared package once

The frontend reads @nodaro/shared from its build output, so build it before the first start. Afterwards, the package's own dev script rebuilds it when you edit shared code.

npm -w @nodaro/shared run build

Start the dev servers

In two terminals:

# Terminal 1: the API on port 9000
cd backend
npm run dev

# Terminal 2: the frontend on port 3000, which forwards /v1/* to port 9000
cd frontend
npm run dev

Coding standards

The most important rules from CLAUDE.md:

  • File size. 200 to 400 lines is typical, and 800 is the hard ceiling. Split a file that grows larger.
  • No console.log in production code. Use the existing logger patterns.
  • Conventional commits: feat:, fix:, refactor:, docs:, chore:, test:, with a specific subject line.
  • Type-check before every commit, with npx tsc --noEmit in both backend/ and frontend/. CI blocks pull requests that do not type-check.
  • Fastify plugins, not Express routers. Every route file exports an async function that takes the Fastify instance.
  • Every API endpoint has a Zod schema, with no exceptions. The schema validates the request and also produces the OpenAPI document.
  • Frontend state: React Query for server state, Zustand for interface state and React Flow for canvas state. Do not mix them.
  • Never mutate objects or arrays. Always create new copies: Zustand and React Flow both rely on reference equality.

Branches and pull requests

  • The repository has two long-lived branches: dev, for staging, and main, for production.
  • Fork the repository, branch from dev, and open your pull request into dev. Never branch from main or commit to it directly.
  • Name the branch by its type: feat/, fix/, refactor/, docs/, chore/ or test/, for example feat/whisper-tts-node.
  • Merged changes run first on the staging instance, next.nodaro.ai. After a soak of about 24 hours, a maintainer promotes dev to main.

In your pull request:

  • Link the GitHub issue it relates to.
  • Add screenshots or GIFs for changes to the interface.
  • Follow the node checklist in CLAUDE.md when you add or change a node.
  • Add a changeset when you change a published package. See Changesets.

Tests

Each workspace has its own Vitest suite. Run everything from the repository root, or one workspace at a time:

npm test                       # every workspace's test script

npm -w @nodaro/shared test     # pure-logic unit tests
npm -w @nodaro/sdk test        # SDK contract tests against a mocked API
cd backend && npm test         # route and service tests
cd frontend && npm test        # component and hook tests

What to test:

  • API routes — the main path, plus the edge cases your schema lists. Mock Supabase and the AI providers: a unit test never calls a real provider API. Most existing tests have a setup you can copy.
  • Frontend components — smoke tests with React Testing Library. Put heavy logic in hooks or helpers, where it can be unit-tested alone, and do not test the internals of React Flow or the Zustand stores.
  • The shared package — pure-function unit tests. Its exports must stay serializable between the frontend and the backend.

CI runs tsc --noEmit, Vitest and a small lint pass. If a test fails locally but passes in CI, or the reverse, open an issue with the steps to reproduce it.

ffmpeg output checks

Ordinary unit tests check the arguments passed to ffmpeg, not what ffmpeg renders. A separate characterization suite renders test fixtures through every ffmpeg-backed operation. It then compares measured properties of the decoded output with committed reference values: energy, spectrum, decay, duration and per-frame brightness.

The suite is left out of npm test: its numbers are valid only against the exact ffmpeg build pinned in the production image. Run it inside that image:

backend/scripts/characterize-in-image.sh check   # compare with the reference values
backend/scripts/characterize-in-image.sh bless   # rewrite the reference values, on purpose only
cd backend && npm run characterize:report -- --against ffmpeg-X.json

If you change an ffmpeg-backed operation, run check before you open the pull request. CI runs it too. If your change is meant to alter the rendered output, bless inside the image and commit the new reference values, with an explanation of every measure that moved. Never edit reference values by hand, and never bless against a local ffmpeg: the suite's version guard rejects it.

Add a node or a model provider

Adding a node touches many files: an API route, a frontend component, the executor and several registries. Missing one gives confusing results, such as a node that does not appear in one of the pickers or a Run button that does nothing. Follow the New Node Registration checklist in CLAUDE.md, step by step.

Adding a model to an existing node is a shorter job, with its own Provider Enum Sync checklist in CLAUDE.md. The step most often forgotten is the schema of the API route: without it, the editor offers an option that the API rejects with 400.

Changesets

Three packages publish to npm: @nodaro/shared, @nodaro/sdk and @nodaro/cli. Releases use Changesets and are automated. When your change touches one of them:

npx changeset

Choose the packages, the bump type (patch, minor or major) and a one-line summary. Commit the file it writes under .changeset/ with your pull request. The Changeset Guard check fails pull requests that change a published package without one. For a change that needs no release note, use npx changeset --empty.

Everything else is automatic. On dev, a Version Packages pull request collects the pending changesets. When dev is promoted to main, the release workflow publishes the new versions to npm, tags them, creates the GitHub releases and rebuilds the standalone CLI binaries. The backend, frontend and Remotion workspaces never publish and need no changeset.

Code of conduct

Be kind, be respectful and assume good faith. The project follows the Contributor Covenant 2.1, in CODE_OF_CONDUCT.md. Harassment of any kind is grounds for removal from the project.

  • Critique code, not people.
  • Disagree without being rude: "I think pattern X would be cleaner here because Y" works, "this is bad" does not.
  • Maintainers reviewing a first-time contributor: be patient.

Where to ask

  • GitHub Discussions — open questions, ideas and things you built with Nodaro. Prefer it to Issues for anything that is not a bug.
  • GitHub Issues — bug reports and feature requests.
  • Security problems — report them through a private security advisory on GitHub.

Avoid emailing maintainers privately about the project: public answers help everyone. Private contact is fine for security reports and conflicts of interest.

License and contributor agreement

The repository has four license tiers. Most code is under the Nodaro Sustainable Use License. Code in any ee folder and in files with .ee. in their name is under the Nodaro Enterprise License. @nodaro/prompts is under FSL-1.1-Apache-2.0, and @nodaro/sdk, @nodaro/shared and @nodaro/cli are under Apache 2.0. See License.

Where new code goes. Every published version of the Apache packages is an irrevocable grant. New prompt engineering, catalogs and presets belong in @nodaro/prompts or in backend/. Add to @nodaro/shared only what the public API and SDK contract needs, such as types, wire enums and validation shared with API users, or what you publish on purpose for reuse. Say which in your pull request.

The contributor agreement. By submitting a contribution, you agree to the Nodaro Contributor License Agreement. The same agreement covers individual and corporate contributions: its section 2 deals with your employer's permission. The cla-assistant bot asks you to sign it on your first pull request. If you contribute on behalf of an employer, check that its intellectual property policy allows it. The agreement lets Nodaro license your contribution under any of its licenses, including moving it between the Sustainable Use License and the Enterprise License.

Frequently asked questions

Last updated on

On this page