Skip to content
GUIDE · AUTHORING WORKFLOW

Programmatic Usage ​

The package exports AgentPluginCompiler for build tools and other Node.js integrations.

Create a compiler ​

ts
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 ​

ts
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().

MethodMain 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:

ts
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 ​

ts
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:

ts
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.

Released under the MIT License.