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
Kai is moving toward multiple execution harnesses: Claude Code, Codex CLI, OpenCode-style ACP backends, and possibly other one-shot or role-specific reasoners. The useful design is a harness router: a small policy layer that maps a normalized task shape to a known execution route.
The risky design is a meta-agent that asks a model which other model or tool to call on every turn. Do not build that. The router should be boring infrastructure with explicit inputs, capability checks, policy, adapters, and logs.
Design note: harness-router-architecture.md.
Goal
Design and implement a deterministic harness router that can select a harness, adapter, model policy, permission profile, and fallback route for each task while preserving shared memory, scheduling, tool access, operator preferences, and behavior rules.
Why this matters
Different harnesses are good at different work, and not every installation has every harness available.
Claude Code is the incumbent adapter and remains useful where available.
Codex CLI is a practical coding and one-shot harness with model-aware routing value.
OpenCode-style ACP backends may provide a cleaner protocol-shaped integration.
Scheduled jobs, PR review, spec review, fact extraction, implementation, and lightweight chat do not all need the same route.
A router lets Kai use backend diversity deliberately instead of making one backend carry every workload.
This should not ship before backend-neutral memory context and scoped retrieval are solid. Routing the right task to the right harness with the wrong memory context is still wrong.
The first implementation does not need to route every profile. It should define the vocabulary up front, then wire one narrow profile first, likely fact_extraction.
Adapter contract
The core abstraction is an adapter contract, not a router prompt.
Each harness adapter should normalize invocation, environment setup, timeout handling, permissions, model resolution, logging, and result parsing.
The exact signature can change, but the boundary must stay strict. The router chooses a route. The adapter owns harness-specific details.
Capability registry
Harness availability is install-local. Kai should support installations where any given harness is missing, unconfigured, unauthenticated, disabled by policy, or available only for some roles.
Use explicit availability states:
missing
unconfigured
unauthenticated
disabled
blocked_by_policy
available
Useful capability fields include:
interactive support
one-shot support
structured output support
streaming support
tool permission controls
workspace editing support
read-only mode
protocol type, such as CLI, ACP, or HTTP
timeout support
model override support
permission policy support
available models or symbolic model classes
cost and context classes
auth state
verified modes
Capability checks happen at the route level, not only the harness level. A harness may be generally available but still ineligible for a specific model, permission profile, or task profile.
Model policy
The router selects harness and model policy together. Do not pick a model first and then ask which harness can run it.
Task-profile model classes should be symbolic where portability matters:
small-fast
structured-cheap
coding-strong
reasoning-strong
long-context-strong
Adapters resolve symbolic classes into harness-specific model IDs. Exact model IDs can be supported as local overrides, but provider-specific strings should not spread through generic routing policy.
Fact extraction should prefer the smallest reliable structured-output route. PR and spec review should prefer strong reasoning and citation discipline. Implementation should prefer tool-competent models with safe permission handling.
Policy model
The first policy table should be small:
Conversation uses the configured primary backend.
Review uses a dedicated review backend if configured, otherwise the primary backend.
Spec review uses the review backend with a spec-review prompt profile.
Memory uses the configured one-shot reasoner.
Jobs use a dedicated jobs backend if configured, otherwise the primary backend in one-shot mode.
Implementation uses the active conversational backend unless explicitly delegated.
Policy should be configuration, not hidden code. If the strategic direction is to prefer non-Claude-Code routes where available, that belongs in routing policy with explicit fallback rules.
Reason strings should be closed enum-like values so logs remain queryable:
preferred_route_available
configured_route_available
fallback_route_selected
acp_not_verified
missing
unconfigured
unauthenticated
disabled
blocked_by_policy
model_unavailable
permission_profile_unsupported
lower_priority_by_policy
operator_confirmation_required
Fallback policy
Fallbacks must be explicit and conservative.
If a configured review harness is unavailable, fail closed unless policy allows a specific fallback.
If a jobs harness is unavailable, use the primary backend only for low-risk read-only jobs.
If a memory extraction harness is unavailable, skip extraction and log the reason rather than route to an unapproved harness.
If an implementation harness is unavailable, ask before silently using another write-capable route.
If a model is available but the harness cannot enforce the required permission profile, reject the route.
Read-only tasks may have broader fallback options. Write-capable tasks should not silently change harnesses.
Logging and debuggability
Every routed task should log the routing decision.
Minimum fields:
role
task profile
selected harness
selected adapter
selected model or symbolic model class
reason for selection
workspace
timeout
permission profile
read-only or write-capable flag
fallback behavior
harness availability state
model availability state
considered and rejected routes with reasons
Bad routing will happen. The log must make it clear whether policy was wrong, an adapter failed, a harness was unavailable, or a model route was ineligible.
Operator controls
The operator should be able to inspect and override routing policy without reading adapter code:
List available harnesses and their state.
Show task profiles and preferred routes.
Show disabled routes and reasons.
Override the model for a task profile.
Disable a harness globally.
Override a route for a single task when policy allows it.
Explain why a route was selected.
Harness-specific notes
OpenCode is the main ACP-protocol test case. Its ACP path should be empirically verified before it becomes a primary route. Kai must represent partial capability states such as "available for conversation, not eligible for memory extraction."
Codex CLI is a strong one-shot and implementation harness, but its contract is CLI-shaped. The Codex adapter owns binary path, login preconditions, working directory, sandbox and approval flags, output mode, timeout behavior, and model selection.
Claude Code remains a supported adapter and compatibility fallback, but it should not define the generic abstraction. The strategic goal is to demote Claude Code from foundation to adapter, not remove it.
Context
Kai is moving toward multiple execution harnesses: Claude Code, Codex CLI, OpenCode-style ACP backends, and possibly other one-shot or role-specific reasoners. The useful design is a harness router: a small policy layer that maps a normalized task shape to a known execution route.
The risky design is a meta-agent that asks a model which other model or tool to call on every turn. Do not build that. The router should be boring infrastructure with explicit inputs, capability checks, policy, adapters, and logs.
Design note:
harness-router-architecture.md.Goal
Design and implement a deterministic harness router that can select a harness, adapter, model policy, permission profile, and fallback route for each task while preserving shared memory, scheduling, tool access, operator preferences, and behavior rules.
Why this matters
Different harnesses are good at different work, and not every installation has every harness available.
A router lets Kai use backend diversity deliberately instead of making one backend carry every workload.
This should not ship before backend-neutral memory context and scoped retrieval are solid. Routing the right task to the right harness with the wrong memory context is still wrong.
Canonical routing contract
Use one route contract throughout the design:
Inputs:
role: outer intent bucket.task_profile: normalized workload inside the role.capability_registry: install-local description of harnesses, models, permissions, modes, auth state, and verified capabilities.routing_policy: operator and installation preferences.Output:
Roles and task profiles are separate. Role assignment chooses intent. Harness routing chooses the concrete execution route.
Initial roles and task profiles
conversationinteractive_conversationmemoryfact_extraction,memory_summarizationreviewpr_reviewspec_reviewspec_reviewjobsscheduled_statusimplementationimplementation,repo_exploration,small_shell_taskresearchresearchThe first implementation does not need to route every profile. It should define the vocabulary up front, then wire one narrow profile first, likely
fact_extraction.Adapter contract
The core abstraction is an adapter contract, not a router prompt.
Each harness adapter should normalize invocation, environment setup, timeout handling, permissions, model resolution, logging, and result parsing.
Conceptual operation:
The exact signature can change, but the boundary must stay strict. The router chooses a route. The adapter owns harness-specific details.
Capability registry
Harness availability is install-local. Kai should support installations where any given harness is missing, unconfigured, unauthenticated, disabled by policy, or available only for some roles.
Use explicit availability states:
missingunconfiguredunauthenticateddisabledblocked_by_policyavailableUseful capability fields include:
Capability checks happen at the route level, not only the harness level. A harness may be generally available but still ineligible for a specific model, permission profile, or task profile.
Model policy
The router selects harness and model policy together. Do not pick a model first and then ask which harness can run it.
Task-profile model classes should be symbolic where portability matters:
small-faststructured-cheapcoding-strongreasoning-stronglong-context-strongAdapters resolve symbolic classes into harness-specific model IDs. Exact model IDs can be supported as local overrides, but provider-specific strings should not spread through generic routing policy.
Fact extraction should prefer the smallest reliable structured-output route. PR and spec review should prefer strong reasoning and citation discipline. Implementation should prefer tool-competent models with safe permission handling.
Policy model
The first policy table should be small:
Policy should be configuration, not hidden code. If the strategic direction is to prefer non-Claude-Code routes where available, that belongs in routing policy with explicit fallback rules.
Reason strings should be closed enum-like values so logs remain queryable:
preferred_route_availableconfigured_route_availablefallback_route_selectedacp_not_verifiedmissingunconfiguredunauthenticateddisabledblocked_by_policymodel_unavailablepermission_profile_unsupportedlower_priority_by_policyoperator_confirmation_requiredFallback policy
Fallbacks must be explicit and conservative.
Read-only tasks may have broader fallback options. Write-capable tasks should not silently change harnesses.
Logging and debuggability
Every routed task should log the routing decision.
Minimum fields:
Bad routing will happen. The log must make it clear whether policy was wrong, an adapter failed, a harness was unavailable, or a model route was ineligible.
Operator controls
The operator should be able to inspect and override routing policy without reading adapter code:
Harness-specific notes
OpenCode is the main ACP-protocol test case. Its ACP path should be empirically verified before it becomes a primary route. Kai must represent partial capability states such as "available for conversation, not eligible for memory extraction."
Codex CLI is a strong one-shot and implementation harness, but its contract is CLI-shaped. The Codex adapter owns binary path, login preconditions, working directory, sandbox and approval flags, output mode, timeout behavior, and model selection.
Claude Code remains a supported adapter and compatibility fallback, but it should not define the generic abstraction. The strategic goal is to demote Claude Code from foundation to adapter, not remove it.
Dependency order
fact_extraction.Scope
Out of scope
Candidate child issues
Acceptance criteria