Skip to content
ChatfuelSDK
Reference

module.json

Every field of a module manifest — the required five, the two enums, the two regex patterns, and what reads each one.

Five fields are required — id, name, description, status, skill — and additionalProperties is false, so a field the schema does not know is a failed gate rather than a silent no-op.

The top level

Prop

Type

What status and selection actually do

ValueEffect
status: "planned"The module is in the tree and validated like every other, and ready() filters it out. The picker never offers it, and --modules naming it ends the run with the list of ids that are ready.
status: "ready"Offered.
selection: "default"Taken by --yes.
selection: "opt-in"Offered in the picker with an extra hint, and never taken by --yes — name it in --modules to get it. Two modules use it: auth and admin, both because they need credentials the wizard cannot invent.

requires is resolved into a closure before anything is written: dependencies first, core always, and the ids it added are printed. recommends is only ever offered — under --yes or --modules it is logged and not installed, and a mutual recommendation between two modules is legal where a requires cycle is not.

hidden

A hidden module contributes no rail item and no /<id> route. The flag lives in the manifest as well as on the shell descriptor because the wizard writes the agent handoff from manifests alone and would otherwise print a deep link to a route that does not exist — and the two are compared, so they cannot drift.

auth is the only module that sets it: it contributes a host integration instead of a page. railHidden, which keeps the route and only takes the listing away, is a descriptor field with no manifest counterpart — see the module contract.

skill

Prop

Type

app.env

An array of the variables this module needs. The wizard writes the union across the selected modules, first declaration wins, preceded by the app's own two (VITE_APP_NAME, VITE_APP_LOGO), which belong to no manifest.

Prop

Type

Values resolve in this order: a step-resolved value, then the token for CHATFUEL_TOKEN, then the manifest default, then ''.

resolve documents which step fills the variable; no code reads the field. The steps write into the answer bag by variable name — the workspace picker sets VITE_CHATFUEL_WORKSPACE_ID and CHATFUEL_WORKSPACE_ID, the auth setup sets the SUPABASE_* ones, the admin step sets ADMIN_PASSWORD — so a resolve value that is wrong changes nothing, and a variable nobody writes comes out empty however it is annotated.

The TypeScript type beside the schema is one value behind: ModuleManifest's resolve union is 'authSetup' | 'workspacePick', while the schema allows adminSetup and modules/admin/module.json uses it. The schema is the authority and the ajv gate passes; a manifest edited through the TypeScript type would not type-check.

app.embed

What --embed copies into a host project.

Prop

Type

permissions

Prop

Type

Nothing checks these at runtime. They are read once, when the wizard writes the handoff notes, so the agent that continues the work knows what the token has to be allowed to do.

What the gates check

pnpm validate runs both of these; a failure is a failed build, not a warning.

CheckFailure
ajv against the schemaReported per field path — a bad pattern, a value outside an enum, a property the schema does not have.
id vs the directoryid "x" does not match directory name "y".
skill.installAsAlready used by another module.
SKILL.md frontmatterIts name must equal installAs.
requires / recommendsMay not name themselves, or a module that does not exist.
requires cyclesDetected over requires edges only.
The shell side, for a ready module with an app blockapps/shell/src/modules/<id>/index.tsx exists and exports moduleDescriptor under that exact name; its hidden matches the manifest's; the id is in the shell registry; modules/<id>/handoff.md exists; every embed root, the playbook and the entry component resolve.

On this page