Programmatic Usage
The package exports AgentPluginCompiler for build tools and other Node.js integrations.
Create a compiler
import {
AgentPluginCompiler,
CLAUDE,
CODEX,
} from "@fam-tung-lam/ptlam-agent-plugin-compiler";
const compiler = new AgentPluginCompiler({
rootDir: process.cwd(),
providers: [CLAUDE, CODEX],
});rootDir is required and may be absolute or relative. Omit providers to use plugin/plugin.yml; pass a list to replace it; pass [] for shared skills only. The options are copied and frozen when the instance is created.
Built-in constants are CLAUDE, CODEX, COPILOT, GEMINI, and KIMI.
Operations
const initialized = await compiler.init();
const validation = await compiler.validate();
const compiled = await compiler.compile();
const checked = await compiler.check();The Node.js method corresponding to the CLI compile command is compile().
| Method | Main result facts |
|---|---|
init() | createdPaths, existingPaths, warnings |
validate() | plugin, selection, hookDiagnostics, warnings |
compile() | Validation facts, writeResult, verified, drift |
check() | Validation facts, upToDate, drift |
Results and their nested public collections are immutable snapshots. Methods reject when repository I/O, validation, planning, or verification cannot complete.
The plugin returned by every validating operation exposes normalized immutable manifest configuration:
const { plugin } = await compiler.validate();
const limit: number | null = plugin.config.skill_dependency_depth_limit;Omitted schema-v2 configuration and every schema-v1 plugin report null. Configured depth violations reject validate(), check(), and compile() with PluginValidationError before generated state is read or written.
Check before publication
const result = await compiler.check();
if (!result.upToDate) {
for (const entry of result.drift) {
console.error(`${entry.path}: ${entry.reason}`);
}
process.exitCode = 1;
}Register an additional provider
Advanced integrations can create a per-instance registry:
import {
AgentPluginCompiler,
ArtifactKind,
OwnershipKind,
ProviderAdapterRegistry,
createPlanFragment,
createProjectPath,
createProviderId,
type ProviderAdapter,
} from "@fam-tung-lam/ptlam-agent-plugin-compiler";
const EXTERNAL = createProviderId("external");
const manifestPath = createProjectPath(".external-plugin/plugin.json");
const adapter = {
id: EXTERNAL,
// Omit supportedHookEvents to compile other output and skip hook handlers.
compile: ({ plugin }) =>
createPlanFragment({
ownerId: EXTERNAL,
ownership: {
kind: OwnershipKind.ExactFiles,
paths: [manifestPath],
},
artifacts: [
{
kind: ArtifactKind.File,
path: manifestPath,
content: new TextEncoder().encode(
`${JSON.stringify({ name: plugin.name })}\n`,
),
},
],
}),
} satisfies ProviderAdapter;
const registry = new ProviderAdapterRegistry().register(adapter);
const externalCompiler = new AgentPluginCompiler(
{ rootDir: process.cwd(), providers: [EXTERNAL] },
registry,
);
await externalCompiler.compile();Each registry is immutable and isolated. register() returns a new registry, and adapters must use stable exact-file ownership. Hook support is event-level: supportedHookEvents promises that the adapter compiles those universal events into valid native configuration. Omitted events are removed from its plugin view, and results contain a non-fatal skipped diagnostic for each affected handler.
Next: compare the built-in providers, or see how the same check runs in continuous integration.