Skip to content

Writing an adapter

An adapter translates a native harness contract into Majlis types. It supplies evidence about capabilities and delivery; application services own permission and state transitions. Existing adapters live in internal/adapters/ over the shared clibase core, with installation assets under plugins/.

Implement app.HarnessAdapter from internal/app/ports.go:

type HarnessAdapter interface {
Capabilities(context.Context) (CapabilityReport, error)
NormalizeHook([]byte) (HookEvent, error)
RenderReply(HookReply) ([]byte, error)
Wake(context.Context, WakePointer) (TransportReceipt, error)
}
Method Contract
Capabilities Report an exact native version and genuinely observed capabilities. Untested versions get a warning and a conservative fallback. A caller cancellation must not become a cached empty result.
NormalizeHook Parse bounded native input into a complete event. Keep native session and subagent IDs; never derive them from cwd, branch, PID ancestry or a handle.
RenderReply Emit only the reply shape valid for that native event. Majlis replies never grant a harness approval.
Wake Send an opaque pointer through a verified transport. Return honest receipts and typed unavailable errors.

A concrete adapter may import app, domain, its own subtree and permitted external libraries. It cannot import storage, delivery, runtime, another adapter or a transport. Add an explicit import-checker rule for a new package.

  • Bound input size. Reject trailing data, malformed JSON, missing identities, invalid types, ambiguous paths and unknown events.
  • Normalize the complete file set for multi-file edits before admission.
  • Treat uncertain extraction as experimental and fail closed where full strict enforcement cannot be established.
  • On outage, overload, invalid identity, timeout or helper launch failure, strict pre-write callbacks deny.
  • Local diagnostics hold bounded gap metadata, never raw payloads or transcripts.

Create synthetic fixtures under tests/fixtures/<harness>/ and contract tests under tests/contracts/, recording the exact native version, provenance and fixture hashes. Cover:

  • Session, subagent, start, resume, compaction and end identity, plus unknown-identity failure.
  • Read and edit payloads, complete multi-file path sets, malformed, oversized and trailing input.
  • Valid denial replies, deadline behavior, and warn, block and ask failure semantics.
  • Busy, idle, disconnected, restart and capability-discovery cancellation.
  • Wake acceptance, refusal and item acknowledgment only where native evidence exists.

Synthetic fixtures establish parser contracts. They are not native integration evidence and never make an untested version supported.

Terminal window
make fmt-check vet
go test -count=1 ./...
make checks
make test-race # for delivery and runtime paths

Record commands and results, and mark native integration claims as passed, failed, untested or environmentally blocked. Never install a permission bypass.