docs: propose host adapters as a published extension point (ADR-0028/0029/0030) - #131
Open
adrianco wants to merge 1 commit into
Open
docs: propose host adapters as a published extension point (ADR-0028/0029/0030)#131adrianco wants to merge 1 commit into
adrianco wants to merge 1 commit into
Conversation
…0029/0030) ADR-0029 asks for one thing: publish the seam that already exists. ADR-0016 specified every contract a host adapter needs, ADR-0017 proved them by using them, and ADR-0018 generalized execution behind them — sync and host pick already drive OpenCode through the generic runLifecycle. What is left is a last mile: adapter selection is a named import, and status hand-rolls a per-host block importing eight functions from lib/opencode.mjs. Both in-tree changes delete host-specific code rather than adding it. The alternative considered and rejected was absorbing each new host in-tree, as ADR-0017 did for OpenCode. It works, and it is why the contracts exist — but it makes every host a permanent obligation of whoever maintains this repository, including hosts they may not run and cannot verify. The first request for a fourth host is the right moment to decide that once rather than four times. Constraints that make the surface safe to publish rather than merely convenient: explicit kit.json registration, never naming-convention discovery (an unrelated npm install must not get third-party code executed inside ak); disclosure rather than a sandbox claim, since in-process adapters cannot be sandboxed; capability caps on canBePrimary, aqeProvider, and commandStatusline, matching the shape OpenCode already occupies; fail-closed per adapter, so a broken third-party adapter cannot brick ak status while built-ins keep throwing at construction; and contract: 1 with an explicit statement that the surface is unstable while the package is alpha. ADR-0030 is the conformance evidence. Hermes Agent breaks five assumptions the built-in hosts share — YAML config, no npm package, plain-text output, no interceptable permission event, no ruflo backend flag — and carrying it needed exactly one widening (a plain-text summary capture alongside the JSONL one) and one guard (npmRoot on an absent npmPackage). It ships as an externally maintained adapter, not vendored here. ADR-0028 is independent of both: the registry knows one local provider, ollama, while a local model is normally an OpenAI-compatible loopback endpoint, frequently under a user-chosen name no vendor enumeration can cover. docs/HOST-ADAPTER-EXTENSION-PROPOSAL.md is the companion product proposal, following the shape of PR pacphi#112. All three ADRs are Proposed. No implementation is authorized or claimed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Documentation only. Three ADRs, all Proposed — no implementation is authorized or claimed. Follows the shape of #112.
The short version
I wanted agentic-kit to manage a fourth agent CLI (Hermes Agent, which is what I use to drive local models). The obvious route was ADR-0017's: an owner module and edits across nine files. Its own references section lists fourteen source files and eight test suites for one host.
That route makes every host your permanent obligation, including hosts you don't run and can't verify. So this proposes the smaller thing instead: publish the seam that already exists.
The seam is already built, and already partly adopted
Reading through 0016/0017/0018, every contract a host adapter needs is already specified and enforced:
validateHostAdaptervalidateRegistries(at construction)validateLifecycleAdapter— detect/plan/apply/verify/undoownership,mayUndo,undoOwnedValuesvalidateExecutionAdapter,validateWorkerResultnormalizedFacts(schemaVersion: 1, provenance-bearing)registry(customBlocks)— already user-extensibleAnd
OPENCODE_LIFECYCLE_ADAPTERimplements the full five-verb contract, driven fromsync.mjsandx/host.mjsthrough the genericrunLifecycle.What's left is a last mile, and it's small:
runLifecycle({ adapter: OPENCODE_LIFECYCLE_ADAPTER, … })status.mjshand-rolls a per-host block importing eight functions fromlib/opencode.mjs, even thoughdetectalready returnsnormalizedFactsBoth changes delete host-specific code rather than adding it, which is why they seem worth making even if no external adapter is ever registered.
ADR-0029 — the actual ask
An adapter is one module exporting one manifest, validated by the validators above. Four constraints make it safe to publish rather than merely convenient:
kit.jsonregistration, never naming-convention discovery. Scanning forak-host-*would make an unrelatednpm installsufficient to get third-party code executed inside ak on the nextak status— the fail-open pattern ADR-0023 exists to prevent.canBePrimary,aqeProvider, orcommandStatusline. Those three carry first-party obligations you can't discharge for code you don't ship. It's exactly the shape OpenCode already occupies, so it's a tested configuration, not new policy.ak status. Built-ins keep throwing at construction, because a broken built-in is a build error.Plus
contract: 1and an explicit statement that the surface is unstable while the package is alpha — publishing an extension point acquires an obligation, and that statement is what bounds it.The package stays zero-runtime-dependency: an adapter is something the user installs and registers, never a dependency of
@pacphi/agentic-kit.ADR-0030 — conformance evidence
A contract never satisfied by code its authors didn't write is a guess. Hermes is a useful first consumer because it's awkward — it breaks five assumptions the built-in hosts share: YAML config, no npm package, plain-text output, no interceptable permission event, no ruflo
ENABLE_*flag.Carrying it needed one widening (a plain-text summary capture alongside
createJsonlSummaryCapture) and one guard (npmRoot(host.install.npmPackage)infootprint/install.mjs, since hermes is the first host with no npm package). Everything else fit unmodified.It would ship as an externally maintained adapter — not vendored here, and not asking you to take on hermes's correctness or NousResearch's release cadence. I'd maintain it.
Two findings are in the ADR because they'd otherwise resurface as bug reports:
hermes mcp addisn't safely idempotent — its overwrite prompt defaults to No on EOF (which is what a non-TTYak syncsupplies) and exits zero, so a bare re-add is a silent no-op that reads as convergence.hermes -zsetsHERMES_YOLO_MODE=1by its own headless contract, so unlike OpenCode there's no permission event to intercept and nopermission_requiredresult to return. ADR-0030 discloses that at enable time rather than letting a hermes worker appear to carry a guarantee it doesn't have.ADR-0028 — independent of both
The registry knows exactly one local provider,
ollama, while a local model is normally an OpenAI-compatible loopback endpoint (MLX, LM Studio, llama.cpp, vLLM) — frequently under a name the user chose, which no vendor enumeration can cover. One genericlocal-openairow that deliberately claims less thanollama: no catalogue, no runtime probe, no digest, and no discovery facts this repo hasn't measured.Useful to the hosts you already ship, and lands on its own merits regardless of what happens to 0029/0030.
Sequencing
docs/HOST-ADAPTER-EXTENSION-PROPOSAL.md§7 lays this out; each step is independently reversible, and declining at ADR-0029 costs nothing already spent. §8 is an honest case against the proposal, including the real cost: a published contract acquires consumers, and consumers constrain refactors.Happy to take this in a different direction — including "no, absorb hermes in-tree the ADR-0017 way" or "not now" — the ADRs are written to be argued with rather than merged as-is. Unrelated: #130 is a small bug fix that currently blocks new test evidence on Homebrew-node macOS.
markdownlintand internal link checks pass; no source changes in this PR.