Build a module
Every feature in Celerp is a module on one loader API: inventory, accounting, manufacturing, and the rest are all built exactly the way your own module will be. A module is a Python package you drop into a folder; Celerp discovers it, wires up its database tables, API routes, and UI pages, and it appears in the app. No fork, no build step.
Start from the template. The fastest path is to clone the celerp-module-template repository - a working "Equipment Maintenance" module you can run in about ten minutes, then edit into your own.
Anatomy of a module
A module is a folder with an __init__.py that defines a PLUGIN_MANIFEST, plus an inner Python package holding its code:
your-module/ outer folder (hyphens ok); the module's name
__init__.py PLUGIN_MANIFEST - identity, slots, route paths
your_module/ inner package (underscores; Python can't do hyphens)
models.py database tables (inherit celerp's Base)
routes.py API routes; defines setup_api_routes(app)
ui_routes.py UI pages; defines setup_ui_routes(app)
migrations/ Alembic migration(s) on the module's own branch
The manifest
PLUGIN_MANIFEST is the whole contract. It names the module, points at its route modules and migrations, and lists the extension slots it fills:
PLUGIN_MANIFEST = {
"name": "your-module", # not "celerp-..." - that prefix is reserved
"version": "0.1.0",
"display_name": "Your Feature",
"license": "MIT",
"api_routes": "your_module.routes",
"ui_routes": "your_module.ui_routes",
"migrations": "your_module.migrations",
"slots": {
"nav": {"key": "yours", "label": "Your Feature",
"href": "/yours", "icon": "★", "order": 50},
},
}
Slots
Slots are named places in Celerp's UI and API your module can extend. The one to start with is nav - it adds a sidebar entry, so your page is reachable the moment you restart. Other slots include bulk_action, item_action, and settings_tab; see the template and the built-in modules for examples.
Models and migrations
Module tables inherit from celerp.models.base.Base so they share the app's database. Each module ships an Alembic migration on its own branch (down_revision = None, branch_labels = ("your-module",)), so its schema is independent of core and of other modules. Celerp runs it on the next launch.
Celerp is multi-company: every table carries a company_id, and every query must filter on the current company. The template shows the pattern with the get_current_company_id dependency.
Run it
- Copy your module folder into Celerp's data directory
modules/folder:- macOS:
~/Library/Application Support/Celerp/celerp-data/modules/ - Linux:
~/.config/Celerp/celerp-data/modules/ - Windows:
%APPDATA%\Celerp\celerp-data\modules\
- macOS:
- Open Settings → Modules in Celerp and enable your module.
- Restart. Your sidebar entry appears; open it.
Run python lint.py your-module/ from the template before each restart - it runs the same checks the loader runs, so you catch mistakes in seconds instead of on a failed launch.
The boundary
Module code may use Celerp's public helpers freely (database sessions, auth dependencies, and the module API). It may not import Celerp's revenue-gated internals - celerp.session_gate, celerp.ai.*, celerp.gateway, celerp.connectors. The loader rejects any module that does. For AI features, use the public module API - see the module AI API.
Share it
Publish your module in your own repository, then list it in the community-modules directory by opening a PR. Celerp's built-in modules are MIT and the template is too, but your module is yours: license it open-source, or keep it source-available and commercial if you plan to sell it. A paid marketplace is on the roadmap; a standout module may also, with its author, be adopted into the official distribution.
A note on compatibility
The loader API is still evolving between releases. Build against the current release; the template tracks it.