Skip to content

Contributing

Manablox is developed in several repositories on GitHub under github.com/manablox. Each one has its own README with the quick start, its own checks and its own release.

The repositories

RepositoryWhat it holdsLicence
manablox-cmsThe CMS: every @manablox/* package of the core (server, APIs, services, database, CLI, SDKs, admin plugin kit and more), the admin, the free plugins (workflows, webhooks, license), the api and public-api apps it runs in development, and the cms-api and cms-admin imagesMIT
manablox-plugin-aiThe premium AI plugin, @manablox/plugin-aiCommercial
manablox-plugin-websiteThe premium website plugin, @manablox/plugin-website, with @manablox/site, @manablox/site-renderer and the site process image siteCommercial
manablox-license-portalThe license server and the customer portal, license-server and license-portal imagesProprietary
manablox-websiteThe marketing website, website imageProprietary
manablox-dev-docsThese pages, dev-docs image (dev.manablox.io)MIT
manablox-user-docsThe user guide, user-docs image (docs.manablox.io)MIT

The repositories depend on each other through npm package names only: a plugin repository depends on "@manablox/core": "^0.50.0", never on a folder of another checkout. In CI and production those packages come from npmjs; in development they come from a local registry in the CMS stack (below), so a change to a CMS package can be tried in another repository before it is released.

They share one set of conventions: every package and app has the same version, a pnpm workspace on Node 24, Biome, TypeScript through @manablox/config-typescript and Vitest through @manablox/config-vitest; a development stack in docker/compose.dev.yml driven by scripts/dev.sh as pnpm dev:up, dev:down, dev:logs and dev:reset (which deletes the volumes); pnpm docker:build for the production images (ghcr.io/manablox/<image>); .github/workflows/ci.yml and, where the repository publishes, a manually dispatched release.yml (see CI and releases).

Ports

Each development stack has ports of its own, so all of them run side by side:

RepositoryPorts
manablox-cmsapi 3000, public api 3001, admin 3002, postgres 5432, valkey 6379, minio 9000/9001, mailpit 1025/8025, verdaccio 4873
manablox-plugin-websitesite 3003, instance api 3100, admin 3102, postgres 5442
manablox-plugin-aiinstance api 3200, admin 3202, postgres 5452
manablox-license-portallicense server 3110, portal 5174, postgres 5462, mailpit 8026
manablox-website3005
manablox-dev-docs3004
manablox-user-docs3008

The CMS development stack

Docker is the only prerequisite; Node 24 and pnpm (pinned by packageManager) run in the containers. In a checkout of manablox-cms:

CommandWhat it does
pnpm dev:upBuild and start everything, the apps included; pnpm install and the migrations run in the stack
pnpm dev:servicesOnly postgres, valkey, minio, mailpit and verdaccio, to run the apps on the host with pnpm dev
pnpm dev:logs [service]Follow the logs
pnpm dev:downStop, keep the data
pnpm dev:resetStop and delete every volume: database, object store, cache and the registry’s packages
pnpm dev:publishBuild every package and publish it to the local registry

The admin is then at http://localhost:3002, the management API at http://localhost:3000 and the public API at http://localhost:3001, which starts once the instance has a space. pnpm check runs what CI runs first: lint, dead code, licences, conventions, typecheck and the tests on both databases.

The local registry

The CMS stack runs a Verdaccio registry on port 4873. pnpm dev:publish builds every CMS package and publishes it there; the other repositories install @manablox/* from it:

Terminal window
pnpm dev:services # in manablox-cms, or pnpm dev:up
pnpm dev:publish # every package at 0.50.0, tag latest; run it again after a change
pnpm dev:publish --dev # or as 0.50.0-dev.<timestamp> under the dev tag
npm view @manablox/core --registry http://localhost:4873

A consuming repository commits the npmjs setting and keeps the local one out of git. On the host, its development .npmrc (gitignored, or ~/.npmrc) is one line:

@manablox:registry=http://localhost:4873/

Inside a container of that repository’s own development stack, localhost is the container. The registry also sits on the docker network manablox-registry as verdaccio; the CMS stack creates the network, and the consumer’s containers join it:

@manablox:registry=http://verdaccio:4873/

When the repository is bind-mounted into the container, the host’s .npmrc comes along, and in pnpm 11 it wins over the user config and the environment. So the container names the registry on the command line, which wins over every file:

Terminal window
pnpm install --frozen-lockfile --config.@manablox:registry=http://verdaccio:4873/

as the development stack of these pages does. The same flag goes on every other pnpm command in the container that resolves packages (pnpm add, pnpm update, pnpm dlx).

# its docker/compose.dev.yml, on every service that runs pnpm install
services:
install:
networks: [default, manablox-registry]
networks:
manablox-registry:
external: true

The network exists while the CMS stack is up (pnpm dev:services is enough), so bring that up first. pnpm’s minimumReleaseAge holds back packages published minutes ago, which every local package is, so a consumer’s pnpm-workspace.yaml excludes the scope:

minimumReleaseAgeExclude:
- '@manablox/*'

After pnpm dev:publish replaces 0.50.0, the tarball has a new checksum under the same version, and pnpm keeps what its cache and lockfile hold. A consumer picks up the new build with

Terminal window
pnpm cache delete '@manablox/*' && pnpm update '@manablox/*'

With --dev every publish is a new version under the dev tag, so nothing is cached: pnpm add @manablox/core@dev takes the newest.

Where a change goes

A change to the core, the admin, the SDKs or the free plugins goes to manablox-cms; its CONTRIBUTING.md has the map of its packages, the recipes (a field type, a procedure, a migration, a hook, an error key, an environment variable) and the conventions. Read the architecture before a change that crosses a package boundary. A change to a premium plugin goes to that plugin’s repository, and a change that needs a new CMS package version is published to the local registry first and released from the CMS before the plugin’s CI can install it.

A change that needs a documentation page comes here, or to the user guide for what editors read.

Working on these pages

The pages are the markdown files in docs/ of manablox-dev-docs, one folder per section; the site is Astro Starlight. A new page needs title and description frontmatter and an entry in the sidebar in astro.config.mjs. Link other pages by their relative .md path (../delivery/sdk.md); a link out of docs/ fails the build, so name a file of another repository by its GitHub URL.

CommandWhat it does
pnpm dev:upThe site in a container at http://localhost:3004, reloading on every edit
pnpm dev:resetStop it and delete its volumes
pnpm docs:generateRewrite the generated pages (error keys, HTTP API, hooks) with manablox docs generate from the installed packages
pnpm docs:checkFail when a generated page is stale
pnpm docs:wordsKeep change history and paths no repository has out of the pages
pnpm checkLint, dead code, wording, typecheck, the generated pages, the build and the link check
pnpm docker:buildThe ghcr.io/manablox/dev-docs image

The generated pages say so at the top; edit the code they come from in the CMS instead. After a CMS release, update the @manablox/* dependencies and run pnpm docs:generate.

Licence and the CLA

Contributions are accepted under the Contributor Licence Agreement, the same in every public Manablox repository. You keep the copyright in what you wrote; a contribution to an MIT repository is licensed under MIT, and the maintainer may relicense it. Accepting it is one flag: sign off every commit with git commit -s, which appends

Signed-off-by: Your Name <your.email@example.com>

A pull request whose commits are signed off is your acceptance for those commits. If your employer holds the rights to your work, say so in the pull request before the first merge. See Licensing for what the licences allow.