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:
| Concern | Helpers |
|---|---|
| Capability and author overrides | featureCapability, resolveHookTier, recordUnsupported, applyOverride |
| Diagnostics | warnDrop, warnDegrade, failHard |
| Markdown and configuration | withFrontmatter, json, managedInstructions |
| Common adapter output | emitSkillFiles, 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 myharnessDocument 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.