Skip to main content

Checks

An authoring-time check. It runs while a mod is being built, not while it is running.

import { function check<TName extends string>(checkValue: CheckInput<TName>): CheckDeclaration<TName>
Declare a self-verification the host runs before it activates the mod. Checks are a gate, not a report. They run in order once everything else in the generation is staged. The first one to throw or fail an assert stops the run, the staged contributions roll back, and the generation is quarantined with the failure message as evidence. So a check that fails keeps a broken mod off the user's machine rather than letting it half-load. Use one to confirm the mod's own contributions really landed, for example that a command it depends on is registered. This is not the place for unit tests of your logic. It answers "did I wire myself up correctly here", which only the running host can tell you.
@exampleConfirm the mod's command reached the action catalog ```ts check({ name: 'my-mod.registered', run: async ctx => { const action = await ctx.describeAction('command:my-mod.hello'); ctx.assert(action !== null, 'my-mod.hello did not register'); }, }); ```@categoryAuthoring
check
, function defineMod<const TMod extends ModDefinition>(definition: TMod & ValidateModHooks<TMod>): Mod
The entry point of the SDK. A mod's module default-exports one `defineMod` call and nothing else. The returned value is data. It registers nothing, starts nothing, and touches no host state. The host folds it twice. At build time it runs the module in a throwaway sandbox and reads the value to derive the serializable manifest. At runtime it folds the same value again to wire your handlers into their lanes: ext-host for commands, tools, effects, and hooks; the sandboxed renderer for views and widgets. That double fold is why the module must be pure. It is re-executed to produce the manifest, so anything at the top level, a file read, a network call, a timer, a `console` line, runs during a build with no host attached. Put behavior inside handlers: `run`, `activate`, `handle`. The `ValidateModHooks` constraint makes the call fail to typecheck when a `hook.beforeAction` targets an action that is neither a known host action nor `command:` plus one of this mod's own command ids.
@example```ts export default defineMod({ metadata: { displayName: 'Review', description: 'Review helpers for the current change.', }, commands: [ command({ id: 'review.open', title: 'Review: Open', run: openPanel }), slashCommand({ id: 'review', description: 'Review this change', run: review }), ], ai: { tools: [reviewTool], }, }); ```@categoryAuthoring
defineMod
} from '@modular/sdk';
export default
defineMod<{
    readonly metadata: {
        readonly displayName: "Hello";
        readonly description: "A first mod";
    };
    readonly checks: readonly [CheckDeclaration<string>];
}>(definition: {
    readonly metadata: {
        readonly displayName: "Hello";
        readonly description: "A first mod";
    };
    readonly checks: readonly [CheckDeclaration<string>];
}): Mod
The entry point of the SDK. A mod's module default-exports one `defineMod` call and nothing else. The returned value is data. It registers nothing, starts nothing, and touches no host state. The host folds it twice. At build time it runs the module in a throwaway sandbox and reads the value to derive the serializable manifest. At runtime it folds the same value again to wire your handlers into their lanes: ext-host for commands, tools, effects, and hooks; the sandboxed renderer for views and widgets. That double fold is why the module must be pure. It is re-executed to produce the manifest, so anything at the top level, a file read, a network call, a timer, a `console` line, runs during a build with no host attached. Put behavior inside handlers: `run`, `activate`, `handle`. The `ValidateModHooks` constraint makes the call fail to typecheck when a `hook.beforeAction` targets an action that is neither a known host action nor `command:` plus one of this mod's own command ids.
@example```ts export default defineMod({ metadata: { displayName: 'Review', description: 'Review helpers for the current change.', }, commands: [ command({ id: 'review.open', title: 'Review: Open', run: openPanel }), slashCommand({ id: 'review', description: 'Review this change', run: review }), ], ai: { tools: [reviewTool], }, }); ```@categoryAuthoring
defineMod
({
metadata: {
    readonly displayName: "Hello";
    readonly description: "A first mod";
}
metadata
: { displayName: "Hello"displayName: 'Hello', description: "A first mod"description: 'A first mod' },
checks: readonly [CheckDeclaration<string>]checks: [ check<string>(checkValue: CheckInput<string>): CheckDeclaration<string>
Declare a self-verification the host runs before it activates the mod. Checks are a gate, not a report. They run in order once everything else in the generation is staged. The first one to throw or fail an assert stops the run, the staged contributions roll back, and the generation is quarantined with the failure message as evidence. So a check that fails keeps a broken mod off the user's machine rather than letting it half-load. Use one to confirm the mod's own contributions really landed, for example that a command it depends on is registered. This is not the place for unit tests of your logic. It answers "did I wire myself up correctly here", which only the running host can tell you.
@exampleConfirm the mod's command reached the action catalog ```ts check({ name: 'my-mod.registered', run: async ctx => { const action = await ctx.describeAction('command:my-mod.hello'); ctx.assert(action !== null, 'my-mod.hello did not register'); }, }); ```@categoryAuthoring
check
({
name: stringname: 'hello.commands-registered', run: (ctx: CheckContext) => Promise<void>run: async ctx: CheckContextctx => { const const actions: readonly ModularActionDescriptorDto[]actions = await ctx: CheckContextctx.CheckContext.listActions(): Promise<readonly ModularActionDescriptorDto[]>
Every action the host currently offers, this mod's included.
listActions
();
ctx: CheckContextctx.CheckContext.assert(condition: boolean, message: string): void
Fails the check with `message` when `condition` is false.
assert
(const actions: readonly ModularActionDescriptorDto[]actions.ReadonlyArray<T>.length: number
Gets the length of the array. This is a number one higher than the highest element defined in an array.
length
> 0, 'the mod registered no actions');
}, }), ], });

Members

CheckDeclarationname, run, kind.

Three members. No id, no when, no title — a check is not addressable and not user-facing, which is the difference between it and every other contribution kind.

What it is for

A check encodes a rule about your own mod that TypeScript cannot express — a naming convention, a required pairing between two contributions, an invariant across the mod value.

It is not a lint rule for a person's code, and it is not a runtime guard. If the rule has to hold at runtime, it belongs in the handler.

The authoring entry point

@modular/sdk/authoring holds the authoring-time surface — 7 exports covering lint and diagnostics. Browse them at @modular/sdk/authoring.