Compose capabilities
Use composition when one engine should publish capabilities from its own package and from reusable packages. The consuming engine owns the final IDs, supplies all dependencies, and detects collisions before serving traffic.
If you are publishing the reusable package first, read the capability packages guide or start with the atomic export and capability library recipes.
This recipe follows the composed-engine example. It combines one local
capability, two atomic exports, and two selected capabilities from a library.
Build the composition
Section titled “Build the composition”-
Keep the composition module safe to import
Create
src/capabilities.tsas a module that starts no adapter and creates no engine. This lets the build gate inspect it without starting the application. -
Add the local and imported capabilities
import {composeCapabilities,importCapabilities,importCapability,} from "@invokta/core";import {createScoreTicketPriorityExport,} from "@invokta/example-community-capabilities";import {createClassifyTicketExport,} from "@invokta/example-community-capabilities/classify-ticket";import {createCommunitySupportLibrary,} from "@invokta/example-community-capabilities/library";import type { OperationsDependencies } from "./application/ports.js";import { createGenerateReport } from "./capabilities/generate-report.js";import {createDefaultOperationsDependencies,} from "./infrastructure/default-dependencies.js";export function createOperationsCapabilities(dependencies: OperationsDependencies,) {return composeCapabilities({local: {"operations.generate-report":createGenerateReport(dependencies.reports),},imports: [importCapability(createScoreTicketPriorityExport(dependencies.community),),importCapability(createClassifyTicketExport(dependencies.community),{ as: "operations.classify-ticket" },),importCapabilities(createCommunitySupportLibrary(dependencies.community),{include: ["community.search-knowledge-base","community.draft-reply",],remap: {"community.draft-reply": "operations.draft-reply",},},),],});}export const capabilities = createOperationsCapabilities(createDefaultOperationsDependencies(),);asandremapreplace a default ID. They do not create aliases. The effective capability set is:operations.generate-reportcommunity.score-ticket-priorityoperations.classify-ticketcommunity.search-knowledge-baseoperations.draft-reply -
Create the engine from the composed map
import { createEngine } from "@invokta/core";import { capabilities } from "./capabilities.js";export const engine = createEngine({name: "composed-engine",version: "0.1.0",capabilities,});Local and imported capabilities now use the same
engine.invokepipeline. The engine composition root remains responsible for constructing every repository, classifier, policy checker, and other dependency.
Run it
Section titled “Run it”From the repository root, build and run the direct example:
yarn buildnode examples/composed-engine/dist/direct.jsInspect the effective IDs, then invoke an atomic and a remapped library capability through the CLI:
node examples/composed-engine/dist/cli.js listnode examples/composed-engine/dist/cli.js run community.score-ticket-priority \ --input '{"ticketId":"T-789"}'node examples/composed-engine/dist/cli.js run operations.draft-reply \ --input '{"ticketId":"T-123","tone":"friendly"}'Verify it
Section titled “Verify it”Run the composition build gate before the example tests and type checks:
yarn workspace @invokta/example-composed check:capabilitiesyarn workspace @invokta/example-composed testyarn workspace @invokta/example-composed typecheckyarn workspace @invokta/example-composed buildcheck:capabilities imports the built composition module and rejects duplicate
effective IDs, invalid selections, and untracked raw maps without starting an
adapter.
Read the complete
composed-engine
example for the export package, injected dependencies, inbound adapters, and
collision tests.
The @invokta/tooling reference documents named exports,
diagnostic boundaries, and every check-capabilities exit code.