Add a module
Register a workspace feature with its pages, operator guide and shared availability controls.
Updated October 7, 2026 4 min read
When your team needs a dedicated review queue or report, ask a coding agent to build it around the records already in the workspace. Reusing customer identity and access services saves repeated setup, while module registration lets an administrator choose which workspaces use the new feature.
Start with a business brief for Codex or Claude Code. The reference below is for the agent implementing your request: it writes the manifest under extensions/, implements the declared screens and verifies their behavior. The manifest is a description of the feature's registration, so the business operations still need their own implementation.
Manifest
Create extensions/<your-module>.module.json:
{
"$schema": "./module-manifest.schema.json",
"id": "acme-inventory",
"name": "Inventory",
"description": "Stock levels, reorder points, and supplier lead times.",
"category": "delivery",
"defaultEnabled": false,
"navLinks": [
{
"id": "acme-inventory",
"label": "Inventory",
"href": "/admin/acme-inventory",
"icon": "Library",
"description": "Stock levels and reorder points",
"moreGroup": "Delivery"
}
],
"routes": ["/admin/acme-inventory"],
"aiToolNames": [],
"docsUrl": "/docs/plugins/acme-inventory"
}
This example names a proposed module. To deliver it, the agent creates its page at src/app/admin/acme-inventory/page.tsx and implements the requested behavior using existing business services.
Include the operator's first task
Create plugins/acme-inventory/README.md with a worked example, required access, settings, costs, permissions, recovery and source references. The plugin documentation contract explains the required delivery so another person can use and extend the result.
Add the public task guide at src/content/docs/plugins/acme-inventory.mdx and register its matching title, description and route in src/content/docs/manifest.ts. The example's docsUrl then opens this module's guide, so a workspace owner can find its instructions from the module itself.
Generate and verify registration
Run these checks after adding the source and guides:
npm run build:extensions
npm run verify:extensions
npm run verify:module-contract
npm run docs:llms
npm run verify:docs
npm run docs:llms:check
git diff --check
The builder validates the manifest and generates the shared module registry. Commit the implementation, manifest, guides, generated docs index and src/lib/revenue-os/extension-modules.generated.ts together, with the feature's required behavior checks.
Contribute existing App records to Today
Collections and Radar declare a today object in their existing manifests, with
a supported source and a native href. The builder checks that the route belongs
to that module. Today includes only enabled contributions, reads bounded records
through their existing domain services and isolates source failures.
The current source adapters are collection_case and radar_opportunity.
Adding another source requires a reviewed adapter in today-snapshot.ts,
matching schema validation, tests and a shared demo fixture. A manifest cannot
execute arbitrary code, fetch providers or define a new lifecycle by itself.
example-inventory.module.json in that directory is a complete working example. It ships disabled.
Rules that fail the build
idis kebab-case, 3 to 49 characters, and must not collide with a core module.iconis a name from the allowlist inscripts/build-extension-modules.mjs, never a React component.- Each
routesentry must have a realpage.tsx. - Each
aiToolNamesentry must exist in the tool registry and belong to exactly one module. docsUrlis a/docs/...path or anhttps://URL. Core and optional first-party modules must resolve to a live guide.settingscannot look like secrets. Credentials go through an adapter.
What to check
Keep business implementation in source files and ordered schema changes in migrations/. A manifest describes registration; it does not create stock storage, reorder automation or new access rights. Leave a new module disabled by default until its behavior and permission checks pass in an isolated test workspace.
For module-owned API routes, use requireAdminForModule("your-module-id") in every handler and register the directories in MODULE_API_DIRECTORIES (scripts/verify-module-route-guards.mjs) so the verifier checks that boundary. Adding a directory to the verifier alone does not enforce runtime authorization.
New to the repository? Start with your first agent-built change before adding a write path.