Contributing
Set up the VitNode repository locally with pnpm and Docker, run the same build, lint and test checks as CI, and submit a pull request.
Contributions to VitNode are always welcome, whether it's a bug fix, a new feature or a docs fix. This page sets up the VitNode repository on your machine, lists the checks CI runs, and explains the docs conventions.
Before you begin
- Node.js
^22.18.0,^24.11.0or26and later (theenginesrange in the rootpackage.json). - pnpm. The repository is a pnpm workspace (
packageManager: pnpm@11.9.0,pnpm-lock.yaml,pnpm-workspace.yaml), and CI uses pnpm too, so use it rather than bun or npm here. With Corepack,corepack enablepicks the right version. - Docker, for the local PostgreSQL and Redis containers. Without Docker, point
POSTGRES_URLinapps/api/.envandapps/web/.envat your own database.
Set up the repository
Clone and install
git clone https://github.com/aXenDeveloper/vitnode.git
cd vitnode
pnpm installStart the database
pnpm docker:devThis starts PostgreSQL and Redis in Docker, using apps/api/docker-compose.yml. The apps read their connection settings from apps/web/.env and apps/api/.env; copy each .env.example next to it to .env if you do not have them yet.
Start the dev servers
pnpm devdev builds the CLI scripts and the plugins, then starts every app with Turborepo. Before the web server starts, its dev script runs the API package's db:prepare, which generates and applies migrations and seeds the initial data.
Open http://localhost:3000 for the website, the AdminCP at /admin and the live docs at /docs. On a fresh database, the first account you register becomes the administrator.
Repository layout
| Directory | Role |
|---|---|
packages/vitnode | @vitnode/core: routing, auth, models, UI primitives and the vitnode CLI |
packages/create-vitnode-app | The project and plugin generator (create-vitnode-app) |
packages/config | @vitnode/config, shared TypeScript and lint configuration |
packages/resend, packages/nodemailer | Email adapters |
packages/s3, packages/supabase-storage | Storage adapters |
packages/node-cron | In-process cron adapter |
packages/elasticsearch | Search provider adapter |
apps/web | The TanStack Start website, AdminCP and this documentation |
apps/api | The standalone Hono API server |
plugins/* | First-party plugins (@vitnode/blog, @vitnode/forum, newsroom) |
Run the checks
Before opening a pull request, run what GitHub Actions runs, from the repository root:
| Command | What it checks |
|---|---|
pnpm build:scripts | Builds the vitnode CLI (packages/vitnode/dist/scripts) |
pnpm build:plugins | Builds every plugin and adapter package with tsdown, with type checking |
pnpm build | Builds every app |
pnpm lint | Runs oxlint in every package and checks formatting with oxfmt |
pnpm test | Runs every package's tests |
pnpm test:types | Runs the type tests |
CI runs the build steps in that order, because the apps and tests read the built CLI and plugins. pnpm lint:fix fixes formatting and most lint errors for you; run it before you commit.
Docs for AI agents
The documentation portal in apps/web speaks Markdown as well as HTML, so agents and LLM tools can read it without scraping:
| URL | What you get |
|---|---|
/llms.txt | An index of every docs page with its title, URL and description |
/llms-full.txt | The whole documentation as one Markdown document |
/docs/<page>.md | A single page as Markdown, for example /docs/dev/setup.md |
Requesting a docs page with an Accept: text/markdown header redirects to its .md twin, so a curious agent gets Markdown without asking twice. Every page also has a Copy Markdown button and an Open in menu for ChatGPT, Claude and friends.
Implementation prompts
A guide that adds a feature to someone's project can also show Copy implementation prompt. One click copies a prompt for a coding agent: it links the guide and its Markdown, tells the agent to inspect the reader's project, ask a few questions, and then build the feature where the reader chose. The eye button next to it opens a preview of the exact same text, with its own copy button.
Add it only to a how-to or tutorial that ends in working code inside a plugin or app. Overviews, references and UI component demos do not get one.
Declare the implementation field in the guide's frontmatter:
---
title: Publish notifications
description: Send a notification from a VitNode plugin.
implementation:
objective: Send an in-app notification when something happens in a plugin.
decisions:
- Which plugin sends it? Offer plugins in the project with an API part (`config.api.ts`).
- Which event triggers it? Offer write routes, actions, queue tasks or cron jobs found in the chosen plugin.
- Who receives it? Offer recipients the chosen event can resolve from existing data, such as the content author.
- Should members also get email by default? None (inbox only), immediately, or in a daily or weekly digest.
constraints:
- Publish with `c.get("notifications").publish()` inside the same transaction as the write.
related:
- title: Notification types
href: /docs/dev/notifications/notification-types
---| Field | Required | What to write |
|---|---|---|
objective | Yes | One line saying what gets built, without the guide's example names |
decisions | Yes | 1 to 6 questions the reader must answer, in dependency order |
constraints | No | Up to 6 rules the agent must keep, such as the API to reuse |
related | No | Up to 4 other docs pages, as /docs/... paths, optionally with a #heading |
Write each decision as a question in the reader's words, followed by where the agent finds the answers in the project: "Offer content types from the chosen plugin". The agent discovers the real choices by reading the reader's code, so never list the guide's example plugin, such as @acme/forum, as an answer. That plugin exists in the guide, not in the reader's project. When the feature supports a fixed set of options, list exactly those and nothing it cannot do.
The shared workflow (inspect first, skip answered questions, ask dependent questions after their answer, work without a structured question tool, report the result) lives once in apps/web/src/docs/implementation/prompt.ts. Do not repeat it in a guide, and do not copy the tutorial into the metadata: the prompt links to it.
To check your prompt, run pnpm dev, open the guide, and open the preview with the eye button next to Copy implementation prompt. Every link should open, and every decision should make sense for a project that has never heard of the guide's example plugin. A typo in the field, such as an unknown key or a link that is not a /docs/ path, fails the docs build with the file name. YAML reads key: value inside a list item as an object, so wrap a line that contains : in single quotes.
Pull request guidelines
- Keep it focused. One feature or bug fix per pull request.
- Follow the conventions in
AGENTS.mdat the repository root: noany, arrow function components, semantic design tokens, i18n keys from APIs. - Add regression tests once the feature works. Tests are there to catch regressions, so write them after the feature is done, following the "Testing" section of
AGENTS.md(what to test, what not to test, and how to mock). - Document new features in
apps/web/content/docs, and runpnpm lint:fixbefore you commit.