Thanks for your interest in contributing to Manifest! This guide will help you get up and running.
| Layer | Technology |
|---|---|
| Frontend | SolidJS, uPlot, custom CSS theme |
| Backend | NestJS 11, TypeORM, sql.js (local) / PostgreSQL (cloud) |
| Auth | Better Auth (auto-login on localhost) |
| Routing | OpenAI-compatible proxy (/v1/chat/completions) |
| Build | Turborepo + npm workspaces |
The full NestJS + SolidJS stack runs locally backed by sql.js (WASM SQLite). The same codebase also powers the cloud version with PostgreSQL — the only differences are the database driver and auth guard.
- Node.js 22.x (LTS)
- npm 10.x
Manifest is a monorepo managed with Turborepo and npm workspaces.
packages/
├── shared/ # Shared TypeScript types and constants
├── backend/ # NestJS API server (TypeORM, PostgreSQL, Better Auth)
└── frontend/ # SolidJS single-page app (Vite, uPlot)
Self-hosting is supported via the Docker image.
- Fork and clone the repository:
git clone https://github.com/<your-username>/manifest.git
cd manifest
npm install- Set up environment variables:
cp packages/backend/.env.example packages/backend/.envEdit packages/backend/.env with at least:
PORT=3001
BIND_ADDRESS=127.0.0.1
NODE_ENV=development
BETTER_AUTH_SECRET=<run: openssl rand -hex 32>
DATABASE_URL=postgresql://myuser:mypassword@localhost:5432/mydatabase
API_KEY=dev-api-key-12345
SEED_DATA=true- Start the development servers (in separate terminals):
# Backend (must preload dotenv)
cd packages/backend && NODE_OPTIONS='-r dotenv/config' npx nest start --watch
# Frontend
cd packages/frontend && npx viteThe frontend runs on http://localhost:3000 and proxies API requests to the backend on http://localhost:3001.
- With
SEED_DATA=true, you can log in withadmin@manifest.build/manifest.
Manifest is a smart router for any personal AI agent that speaks OpenAI-compatible HTTP. The list of supported agents lives in packages/shared/src/agent-type.ts — OpenClaw, Hermes, OpenAI SDK, Vercel AI SDK, LangChain, and cURL are all first-class. The dashboard's "Connect Agent" flow generates the right setup snippet for whichever platform you pick.
This section walks through OpenClaw because it's the deepest integration and the easiest to wire up end-to-end. The same backend also handles all other agents — just follow the dashboard instructions after creating the agent, or grab the snippet shown by the setup modal.
To test routing against your local backend, add Manifest as a model provider in your OpenClaw config:
- Build and start the backend in local mode:
npm run build
MANIFEST_MODE=local PORT=38238 BIND_ADDRESS=127.0.0.1 \
node -r dotenv/config packages/backend/dist/main.js-
Create an agent in the dashboard at
http://localhost:38238and get the API key. -
Add Manifest as a provider in OpenClaw:
openclaw config set models.providers.manifest '{"baseUrl":"http://localhost:38238/v1","api":"openai-completions","apiKey":"mnfst_YOUR_KEY","models":[{"id":"auto","name":"Manifest Auto"}]}'
openclaw config set agents.defaults.model.primary manifest/auto
openclaw gateway restartThe backend runs standalone and OpenClaw talks to it as a regular OpenAI-compatible provider — no plugin needed. For other agents (OpenAI SDK, Vercel AI SDK, LangChain, cURL, …) follow the corresponding tab in the dashboard's "Connect Agent" modal — the underlying endpoint and auth are identical.
When to use this:
- Testing routing, tier assignment, or model resolution
- Debugging the proxy or message recording
- Working on the dashboard UI with live data
| Command | Description |
|---|---|
npm run dev |
Start frontend in watch mode (start backend separately) |
npm run build |
Production build (shared, backend, frontend via Turborepo) |
npm start |
Start the production server |
npm test --workspace=packages/backend |
Run backend unit tests (Jest) |
npm run test:e2e --workspace=packages/backend |
Run backend e2e tests (Jest + Supertest) |
npm test --workspace=packages/frontend |
Run frontend tests (Vitest) |
npm test --workspace=packages/shared |
Run shared tests (Jest) |
- Framework: NestJS 11 with TypeORM 0.3 and PostgreSQL 16
- Auth: Better Auth (email/password + Google, GitHub, Discord OAuth)
- Tests: Jest for unit tests (
*.spec.ts), Supertest for e2e tests (test/) - Key directories:
entities/(data models),analytics/(dashboard queries),routing/(proxy, scoring, tier assignment),auth/(session management)
- Framework: SolidJS with Vite
- Charts: uPlot for time-series visualization
- Tests: Vitest
- Key directories:
pages/(route components),components/(shared UI),services/(API client, auth client)
- TypeScript types, constants, and helpers used by both the backend and the frontend.
- Built with
tsc— both CJS and ESM outputs are produced so it can be consumed from either package.
- Create a branch from
mainfor your change - Make your changes in the relevant package(s)
- Write or update tests as needed
- Add a changeset if your change should appear in the release notes:
npx changeset
# → select "manifest"
# → choose patch / minor / major
# → write a one-line summaryAlways target manifest — it's the canonical release version for the whole project, and it's the only package changesets will accept. manifest-backend, manifest-frontend, and manifest-shared are ignored regardless of what you pick. Commit the generated .changeset/*.md alongside your code. Changesets are optional for internal/tooling changes; skip this step if the change doesn't need a CHANGELOG entry.
See packages/manifest/README.md for why this package exists.
- Run the test suite to make sure everything passes:
npm test --workspace=packages/shared
npm test --workspace=packages/backend
npm run test:e2e --workspace=packages/backend
npm test --workspace=packages/frontend- Verify the production build works:
npm run build- Open a pull request against
main
Manifest ships as the Docker image at manifestdotbuild/manifest. Releases are manual:
- After merging PRs with changesets, a
chore: version packagesPR will be open onmain— merge it to land the version bump inpackages/manifest/package.jsonand updatepackages/manifest/CHANGELOG.md. - Go to GitHub Actions → Docker → Run workflow, leave the
versioninput blank, click Run. - The workflow reads the version from
packages/manifest/package.jsonand pushesmanifestdotbuild/manifest:{version}(plus{major}.{minor},{major}, and asha-<short>rollback tag).
If you need to retag an older commit or publish a version that doesn't match the current package.json, pass a semver string in the version input and it overrides the auto-detected value.
Write clear, concise commit messages that explain why the change was made. Use present tense (e.g., "Add token cost breakdown to overview page").
- Keep PRs focused on a single concern
- Include a short summary of what changed and why
- Reference any related issues
- Single-service deployment: In production, NestJS serves both the API and the frontend static files from the same port via
@nestjs/serve-static. - Dev mode: Vite on
:3000proxies/apiand/v1to the backend on:3001. CORS is enabled only in development. - Database: PostgreSQL 16. Schema changes are managed via TypeORM migrations (
migrationsRun: trueon boot). After modifying an entity, generate a migration withnpm run migration:generate -- src/database/migrations/Name. - Validation: Global
ValidationPipewithwhitelist: trueandforbidNonWhitelisted: true. - TypeScript: Strict mode across all packages.
Found a bug or have a feature request? Open an issue with as much detail as possible.
This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.
By contributing, you agree that your contributions will be licensed under the MIT License.