You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduce a capability-driven abstraction for hosts, model providers/endpoints, configuration projections, and observability sources so adding OpenCode, OpenRouter, Ollama-backed models, and future providers does not require editing overlapping hardcoded lists throughout ak.
This is a follow-on architecture issue, not part of PR #67. It should provide the foundation for:
OpenCode and future agent CLIs as managed hosts;
OpenRouter and other gateways as model providers behind one or more hosts;
Ollama models served through both Claude and Codex compatibility integrations;
ADRs 0001–0006 — current Claude/Codex routing and leadership model
Why this is needed
The current provider/host implementation has grown incrementally and now represents several different concepts with adjacent arrays, maps, and conditionals:
Today these concepts are easy to conflate. For example:
OpenCode is a host, but is not currently a primary/activity-routing target.
OpenRouter is a provider/gateway, but a request may still be executed and logged by Claude, Codex, OpenCode, ruflo, or AQE.
Ollama is a local provider/runtime, and ollama launch claude / ollama launch codex serve Ollama models through two different hosts and compatibility transports.
A transcript host is not enough to establish billing/provider provenance. A Claude transcript can represent Anthropic-hosted or Ollama-served inference.
Without a clearer abstraction, each new integration risks:
another hardcoded list that drifts from the others;
documentation that calls providers “hosts” or hosts “providers”;
invalid routing choices;
incorrect ownership/install behavior;
fabricated pricing, quota, or update claims;
dashboards grouping by the wrong dimension;
command paths that support only part of the lifecycle.
Goals
Define one validated registry for built-in host adapters and one for built-in provider adapters.
Make capabilities explicit so commands and UI derive behavior rather than checking ids.
Represent a resolved execution as at least:
host + provider + model + transport/endpoint + provenance
Allow a provider to bind to multiple hosts where supported.
Allow a host to expose multiple provider bindings without becoming a new provider itself.
Preserve existing Claude/Codex routing behavior and existing kit.json configurations.
Make setup/status/sync/verify/uninstall and the dashboard consume the same normalized facts.
Support honest attribution for local and gateway-served models:
local vs subscription vs metered billing;
known vs inferred vs unknown provenance;
exact model id when observed;
no fabricated price/quota/cache fields.
Keep the runtime zero-dependency and offline-first.
Make future built-in integrations additive and testable without loading arbitrary third-party code.
Non-goals
Do not implement every provider in this issue.
Do not turn ak into a generic third-party plugin runtime.
Do not store API keys or OAuth credentials in kit.json.
Do not make every host a valid primary or activity-routing target.
Do not make OpenCode routable unless a separate, grounded design establishes that capability.
An OpenCode host adapter could set canBePrimary:false and canRouteActivities:false while still supporting install, MCP, guidance,
agents, skills, status, sync, and teardown.
2. Provider adapter
A provider adapter describes inference service/runtime behavior independently of the host:
OpenRouter would be billing:'metered', use an environment credential descriptor,
support an OpenAI-compatible transport, and expose dated/offline pricing metadata
without being described as a host.
3. Provider binding
A binding connects a provider to a host/projection:
Status rows, dashboard cards, verification, and sync planning should project from
these facts. A missing fact must remain unknown rather than becoming a plausible default.
Capability-driven behavior
Commands should ask capabilities rather than compare ids:
Setup/sync install only adapters with an install capability.
Provider selection lists all managed host integrations, but primary-host selection lists only canBePrimary.
Activity routing accepts only canRouteActivities.
Guidance/statusline/transcript work runs only when the host exposes that surface.
Pricing/quota/cache views render only when the provider/observability source can support them.
Update drift applies only to packages ak actually owns (for example npm-managed host CLIs); external installs remain visible but unmanaged.
Verification runs a host/provider/binding-specific proof contract.
Configuration and migration
The design must preserve current configuration and provide a deterministic migration.
Questions for the ADR:
Keep existing providers.hosts and add providers.bindings, or introduce a versioned top-level integrations model?
Should existing dualRouting gain an optional provider field, or should provider resolution remain a separate binding lookup?
How is an inferred legacy route represented without rewriting user intent?
Which values are owned by ak, and how are {prior,written} guards generalized across JSON, TOML, env, and CLI-managed surfaces?
Minimum requirements:
Existing Claude-only and Claude+Codex kit.json files load unchanged.
Migration is additive, versioned, idempotent, and covered by fixtures.
Missing provider information remains unknown or is marked with explicit inferred provenance.
API keys remain environment-only.
Endpoint validation distinguishes trusted loopback local endpoints from remote HTTPS endpoints.
No adapter may silently overwrite externally managed host/provider configuration.
#59 should remain the delivery issue for usage-scorecard ingestion and pricing decisions.
This abstraction issue should give it a correct identity/provenance model.
Important distinction:
A Claude/Codex/OpenCode transcript is evidence of the host.
OpenRouter request/model metadata is evidence of the provider.
They may describe the same execution and should be joined where correlation is grounded.
If no client-side OpenRouter transcript exists, the scorecard must not invent a third host merely to represent provider usage.
The eventual scorecard should be able to answer separately:
Which host executed the session?
Which provider served the model?
Which model was observed?
What billing/pricing source applies?
Which claims are observed, configured, inferred, or unknown?
Ollama through Claude and Codex
The first concrete proving case for multi-host provider bindings should be Ollama:
Configure/observe ollama launch claude.
Configure/observe ollama launch codex.
Preserve host-specific transcript parsing.
Attribute the provider as Ollama only when configuration or runtime evidence supports it.
Resolve the exact local model/digest from the bounded catalog approach in ADR-0011.
Show billing as local/$0 without fabricating cache, quota, or exact token semantics.
Keep both bindings independent: disabling one must not disable or rewrite the other.
This should use the validation evidence requested by docs/LOCAL-MODEL-VALIDATION.md
rather than assumptions about compatibility-layer behavior.
Suggested delivery phases
Phase 0 — ADR and inventory
Inventory every current host/provider hardcoded list and its consumer.
Define terminology and capability contracts.
Decide configuration/migration shape.
Define ownership and provenance vocabulary.
Record non-goals and backward-compatibility rules.
Deliverable: accepted ADR plus a test matrix; no behavior change.
Phase 1 — Registry extraction with behavior parity
Move existing Claude/Codex host metadata into the validated host registry.
Move current provider metadata/credentials/billing into the provider registry.
Derive existing exported lists for compatibility during migration.
Add registry validation for duplicate ids, missing required capabilities, invalid projections, and invalid billing/auth combinations.
Keep current CLI output and routing behavior byte-for-byte where practical.
Deliverable: internal refactor with no new provider behavior.
Documentation uses the same vocabulary across README, providers, routing, usage, transcripts, local models, and upgrading.
Open design questions
Should this remain internal-only, or should a stable JSON schema be documented for kit.json bindings?
Should provider bindings be machine-wide, project-scoped, or support both with explicit precedence?
Should routing policies name a provider directly, or resolve one through a host/model binding?
How should multiple endpoints for the same provider be selected and displayed?
What is the minimum grounded evidence required to upgrade provider provenance from configured/inferred to observed?
How should host-native profiles created by external tools such as ollama launch be adopted, referenced, or left externally owned?
Can ruflo and AQE share a normalized provider intent without pretending their native configuration schemas are identical?
Definition of done
This issue is complete when the architecture and compatibility layer are implemented,
the first multi-host provider binding is proven with Ollama, OpenRouter attribution has
a supported integration point for #59, and new built-in hosts/providers can be added
without modifying unrelated command, routing, dashboard, and usage hardcoded lists.
Summary
Introduce a capability-driven abstraction for hosts, model providers/endpoints, configuration projections, and observability sources so adding OpenCode, OpenRouter, Ollama-backed models, and future providers does not require editing overlapping hardcoded lists throughout
ak.This is a follow-on architecture issue, not part of PR #67. It should provide the foundation for:
Related:
docs/adr/0011-local-model-provenance-zero-cost-and-transcript-fidelity.mddocs/LOCAL-MODEL-VALIDATION.mdWhy this is needed
The current provider/host implementation has grown incrementally and now represents several different concepts with adjacent arrays, maps, and conditionals:
src/lib/hosts.mjsHOST_ADAPTERSsrc/lib/providers.mjsHOSTSAPI_PROVIDERSAQE_PROVIDER_TYPESsrc/lib/routing.mjsPRIMARY_HOSTSThose are not all the same axis.
The four axes we need to distinguish
Host / execution driver
Model provider / endpoint
Configuration projection
akprojects intent.Observability source
akderives truth.Today these concepts are easy to conflate. For example:
ollama launch claude/ollama launch codexserve Ollama models through two different hosts and compatibility transports.Without a clearer abstraction, each new integration risks:
Goals
Define one validated registry for built-in host adapters and one for built-in provider adapters.
Make capabilities explicit so commands and UI derive behavior rather than checking ids.
Represent a resolved execution as at least:
Allow a provider to bind to multiple hosts where supported.
Allow a host to expose multiple provider bindings without becoming a new provider itself.
Preserve existing Claude/Codex routing behavior and existing
kit.jsonconfigurations.Make setup/status/sync/verify/uninstall and the dashboard consume the same normalized facts.
Support honest attribution for local and gateway-served models:
Keep the runtime zero-dependency and offline-first.
Make future built-in integrations additive and testable without loading arbitrary third-party code.
Non-goals
akinto a generic third-party plugin runtime.kit.json.Proposed conceptual model
Names are illustrative; the ADR created by this issue may refine them.
1. Host adapter
A host adapter describes a driver and its native surfaces:
An OpenCode host adapter could set
canBePrimary:falseandcanRouteActivities:falsewhile still supporting install, MCP, guidance,agents, skills, status, sync, and teardown.
2. Provider adapter
A provider adapter describes inference service/runtime behavior independently of the host:
OpenRouter would be
billing:'metered', use an environment credential descriptor,support an OpenAI-compatible transport, and expose dated/offline pricing metadata
without being described as a host.
3. Provider binding
A binding connects a provider to a host/projection:
and independently:
The same model/provider can therefore be reached through multiple hosts without
duplicating the provider definition.
4. Normalized runtime facts
Detection should return facts, not pre-rendered conclusions:
Status rows, dashboard cards, verification, and sync planning should project from
these facts. A missing fact must remain unknown rather than becoming a plausible default.
Capability-driven behavior
Commands should ask capabilities rather than compare ids:
canBePrimary.canRouteActivities.akactually owns (for example npm-managed host CLIs); external installs remain visible but unmanaged.Configuration and migration
The design must preserve current configuration and provide a deterministic migration.
Questions for the ADR:
providers.hostsand addproviders.bindings, or introduce a versioned top-levelintegrationsmodel?dualRoutinggain an optionalproviderfield, or should provider resolution remain a separate binding lookup?ak, and how are{prior,written}guards generalized across JSON, TOML, env, and CLI-managed surfaces?Minimum requirements:
kit.jsonfiles load unchanged.unknownor is marked with explicit inferred provenance.OpenRouter relationship (#59)
#59 should remain the delivery issue for usage-scorecard ingestion and pricing decisions.
This abstraction issue should give it a correct identity/provenance model.
Important distinction:
The eventual scorecard should be able to answer separately:
Ollama through Claude and Codex
The first concrete proving case for multi-host provider bindings should be Ollama:
ollama launch claude.ollama launch codex.This should use the validation evidence requested by
docs/LOCAL-MODEL-VALIDATION.mdrather than assumptions about compatibility-layer behavior.
Suggested delivery phases
Phase 0 — ADR and inventory
Deliverable: accepted ADR plus a test matrix; no behavior change.
Phase 1 — Registry extraction with behavior parity
Deliverable: internal refactor with no new provider behavior.
Phase 2 — Lifecycle/projection interfaces
Deliverable: one lifecycle path consumed by all commands.
Phase 3 — Binding and provenance model
dualRoutingsemantics.observed,configured,inferred,unknown) to usage/model facts.Deliverable: a Claude/Codex route can resolve through a named provider without conflation.
Phase 4 — Proving integrations
Deliverable: at least one provider bound to two hosts and one metered gateway represented behind an existing host.
Phase 5 — UI and documentation convergence
Test strategy
Registry contract tests
Adapter conformance tests
Every adapter must pass a shared contract:
Matrix tests
At minimum:
Command tests
Observability tests
Acceptance criteria
Open design questions
kit.jsonbindings?ollama launchbe adopted, referenced, or left externally owned?Definition of done
This issue is complete when the architecture and compatibility layer are implemented,
the first multi-host provider binding is proven with Ollama, OpenRouter attribution has
a supported integration point for #59, and new built-in hosts/providers can be added
without modifying unrelated command, routing, dashboard, and usage hardcoded lists.