Soubi

Add an Adapter

Add a harness by declaring its capabilities, implementing its emitter, and registering the target.

An adapter translates one PortablePlugin into the files and diagnostics a harness understands. Soubi 0.0.1 supports built-in adapters only; the previous plugin-local registry was removed because arbitrary adapter IDs did not have a complete capability or installation contract.

A built-in adapter lives under packages/soubi/src/adapters/, has a capability-map entry, participates in the CLI registry, and is covered by the harness regression suite.

Use this path for a production target that every Soubi installation should recognize.

Add a built-in adapter

Scaffold the source folder

pnpm soubi add-harness myharness --name "My Harness"

The command creates packages/soubi/src/adapters/myharness/ with a named stub. The stub compiles, but deliberately excludes the target until the native emitter is ready.

Add the harness ID and capability data

Add "myharness" to ALL_HARNESSES in packages/soubi/src/core/types.ts (the HarnessId union is derived from that tuple), then define the target in packages/soubi/src/core/capabilities.ts:

const MY_HARNESS: HarnessCapabilities = {
  features: {
    agent: { tier: "unsupported-hard", note: "No native subagents." },
    asset: { tier: "support" },
    command: { tier: "support" },
    hook: { tier: "support" },
    instructions: { tier: "support" },
    mcp: { tier: "support" },
    skill: { tier: "degrade", note: "Folded into project guidance." },
    tool: { tier: "drop", note: "No executable tool surface." },
  },
  harness: "myharness",
  hooks: {
    PostToolUse: {
      flow: "blocking",
      handlerTypes: ["command"],
      nativeName: "after_tool",
      tier: "support",
    },
    PreToolUse: {
      flow: "blocking",
      handlerTypes: ["command"],
      nativeName: "before_tool",
      tier: "support",
    },
  },
};

Add the constant to CAPABILITIES. Every feature must have a tier; hook entries additionally record the native event, flow control, and executable handler types.

Implement the native emitter

Replace the generated stub with a HarnessAdapter. Start from the existing adapter whose native surface most closely matches the new harness.

Use the shared emission helpers to keep behavior consistent:

ConcernHelpers
Capability and author overridesfeatureCapability, resolveHookTier, recordUnsupported, applyOverride
DiagnosticswarnDrop, warnDegrade, failHard
Markdown and configurationwithFrontmatter, json, managedInstructions
Common adapter outputemitSkillFiles, emitCommandFiles, emitAgentFiles, emitMcpJson, emitPluginAssets

The adapter must return all three result arrays:

return {
  failures: ctx.failures,
  files: ctx.files,
  warnings: ctx.warnings,
};

Do not write files from emit(). The compiler validates returned paths and owns artifact writes.

Register native paths

Import the adapter in packages/soubi/src/adapters.ts and add one defineHarness() entry to HARNESS_DEFINITIONS. The descriptor owns its installation base and JSON merge containers; the adapter and installation registries are derived from it.

Use "." when the adapter emits complete repository-relative paths across multiple top-level directories. Use a harness directory such as ".myharness" when every emitted path belongs beneath one native root.

Add coverage and verify the target

Extend packages/soubi/test/adapters/builtins.integration.test.ts with the native paths and translations the new adapter guarantees. Then run:

pnpm exec tsc --build packages/soubi/tsconfig.json
pnpm test
pnpm soubi check --cwd examples/diff-river --harness myharness

Document the adapter under /docs/adapters/ once the emitted layout and fallback behavior are stable.

Keep failures explicit

If an adapter cannot represent a load-bearing feature, return a named unsupported-hard failure. Do not emit an empty artifact that appears successful.

On this page