A decision layer embedded into the harness tool-selection loop.
Harness Router intercepts the host harness at its native control point, evaluates the available tools, and routes the next tool with cache, Jev, and optional MCTS.
Website Β· Architecture Β· Integrations Β· MCP Β· Python API
Agent harnesses already have a tool-selection loop:
goal
β
βΌ
model reasoning
β
βΌ
tool selection
β
βΌ
tool execution
β
βΌ
result
β
ββββββββββββββββΊ next iteration
Harness Router inserts a decision layer inside that loop:
model proposes / harness reaches tool-selection point
β
βΌ
βββββββββββββββββββ
β Harness Router β
β β
β cache β Jev β
β β MCTS β
ββββββββββ¬βββββββββ
β
routing decision
β
βΌ
next tool call
The host harness still owns the agent.
Harness Router owns the tool-selection decision.
It does not replace the harnessβs:
This separation is intentional.
Every routing request follows the cheapest applicable path first:
routing request
β
βΌ
βββββββββββββββ
β Route cache β
ββββββββ¬βββββββ
β miss
βΌ
βββββββββββββββ
β Jev β
β fast route β
ββββββββ¬βββββββ
β
ambiguous /
downstream-dependent
β
βΌ
βββββββββββββββ
β MCTS β
β bounded β
β local searchβ
ββββββββ¬βββββββ
β
βΌ
routing decision
Repeated compact decisions can be served without invoking a decision provider.
Jev is the normal decision path for tool-selection choices.
MCTS is an optional escalation path for decisions where the best immediate action depends on possible downstream state.
MCTS operates against a side-effect-free simulator. Real tools are not executed during search.
Harness Router is framework-agnostic, but integrations use the native control point available in each host.
The control point determines how directly Router can influence the next tool.
Codex uses:
SessionStart for tool discovery,PreToolUse for routing,
Codex
β
βΌ
tool proposal
β
βΌ
PreToolUse
β
βΌ
Harness Router
β
βββ cache
βββ Jev
βββ optional MCTS
β
βββ same / fallback / error βββΊ allow
β
βββ different confident tool ββΊ deny
β
βΌ
re-plan
β
βΌ
next call
Install:
curl -fsSL https://raw.githubusercontent.com/Protocol-Lattice/harness-router/main/scripts/install_hook.py \
| python3 - --provider codex
Claude Code uses:
Claude Code
β
βΌ
tool proposal
β
βΌ
PreToolUse
β
βΌ
Harness Router
β
βββ cache β Jev β optional MCTS
β
βββ same / fallback βββββββΊ normal flow
β
βββ different tool ββββββββΊ deny + re-plan
β
βΌ
next call
The hook does not execute tools or rewrite their arguments.
See the Claude integration guide.
curl -fsSL https://raw.githubusercontent.com/Protocol-Lattice/harness-router/main/scripts/install_hook.py \
| python3 - --provider claude
ohmypi exposes a stronger control point through its active tool surface.
The integration can call setActiveTools() before the next provider request:
agent turn
β
βΌ
before_agent_start
β
βΌ
Harness Router
β
βββ cache
βββ Jev
βββ optional MCTS
β
βΌ
setActiveTools([selected])
β
βΌ
next provider request
β
βΌ
model selects from controlled tools
β
βΌ
tool execution
β
βΌ
next routing decision
The active tool set is restored on fallback, timeout, low confidence, malformed output, or router failure.
See the ohmypi integration guide.
curl -fsSL https://raw.githubusercontent.com/Protocol-Lattice/harness-router/main/scripts/install_hook.py \
| python3 - --provider ohmypi
Antigravity uses its native PreToolUse hook.
Antigravity
β
βΌ
tool proposal
β
βΌ
PreToolUse
β
βΌ
live tool inventory
β
βΌ
Harness Router
β
βββ cache β Jev β optional MCTS
β
βββ same / fallback βββββββΊ allow
β
βββ different tool ββββββββΊ deny + re-plan
The adapter uses the live conversation tool inventory and does not invent a fallback catalog when discovery fails.
See the Antigravity integration guide.
curl -fsSL https://raw.githubusercontent.com/Protocol-Lattice/harness-router/main/scripts/install_hook.py \
| python3 - --provider antigravity
DeepSeek Harness reaches Router through its supported Codex hook bridge.
DeepSeek Harness
β
βΌ
tool proposal
β
βΌ
tools/pre-execute
β
βΌ
dsh-hooks-codex
β
βΌ
Harness Router
β
βββ same / fallback / error βββΊ allow
β
βββ different tool ββββββββββββΊ deny + re-plan
The command-hook bridge does not provide a faithful live tool registry, so this integration requires a supplied catalog and fails open when a valid routing context is unavailable.
python3 hooks/deepseek/install.py
dsh --patch .dsh/harness-router.patch.yml
See the DeepSeek integration guide.
Harness Router is also available as a native MCP server.
Start it with:
harness-router-mcp
Available tools:
| Tool | Purpose |
|---|---|
route |
Fast next-tool routing |
route_mcts |
Bounded multi-step routing |
Example:
[mcp_servers.harness-router]
command = "harness-router-mcp"
MCP provides an explicit routing interface for hosts that do not use automatic hook integration.
Requires Python 3.11+.
uv tool install --force --with 'mcp>=2,<3' \
'git+https://github.com/Protocol-Lattice/harness-router.git@main'
Set the OpenRouter key:
export OPENROUTER_API_KEY="your-key"
Default decision model:
typesafe/jev-1.13
Route a tool-selection decision directly:
har route \
--goal "Fix the failing parser test" \
--observation "Failure points to src/parser.py" \
--tools-json '[
{
"name": "read_file",
"description": "Read a repository file",
"category": "inspect",
"risk": "low"
},
{
"name": "search_code",
"description": "Search repository source",
"category": "inspect",
"risk": "low"
},
{
"name": "run_tests",
"description": "Run tests",
"category": "verify",
"risk": "low"
}
]'
Example result:
{
"tool": "read_file",
"confidence": 0.93,
"fallback": false
}
python
import asyncio
from harness_router import (
HarnessState,
JevToolRouter,
OpenRouterConfig,
OpenRouterJevProvider,
RiskLevel,
RoutingConfig,
ToolDescriptor,
)
async def main():
provider = OpenRouterJevProvider.from_config(OpenRouterConfig())
router = JevToolRouter(provider, RoutingConfig())
tools = [
ToolDescriptor(
name="read_file",
description="Read a repository file",
category="inspect",
risk=RiskLevel.LOW,
),
ToolDescriptor(
name="search_code",
description="Search repository source",
category="inspect",
risk=RiskLevel.LOW,
),
]
try:
decision = await router.route(
HarnessState(
goal="Fix the failing parser test",
observation="Failure points to src/parser.py",
),
tools,
)
print(decision.tool)
print(decision.confidence)
finally:
await provider.aclose()
asyncio.run(main())
Use route_mcts when the immediate choice depends on possible downstream outcomes.
current state
β
βΌ
policy prior
β
βΌ
local simulator
β
βββ state
βββ candidate tools
βββ transition
βββ reward
βββ terminal condition
β
βΌ
best first action
mcts = MCTSToolRouter(
simulator,
policy_router=router,
config=MCTSConfig(
simulations=64,
max_depth=4,
max_policy_evaluations=1,
),
)
The simulator should model possible transitions rather than execute real tools.
Harness Router is designed for known alternatives at a tool-selection point.
Typical decisions:
Keep these in the main planner:
The intended division is:
harness / planner
β
goal + state
β
βΌ
Harness Router
β
next tool
β
βΌ
argument generation
β
βΌ
permissions
β
βΌ
execution
β
βΌ
result
β
ββββββββββΊ next iteration
Routing is particularly useful when many tools overlap semantically.
Hierarchical routing can reduce the decision surface:
current state
β
βΌ
category route
β
βββββββββββββββΌββββββββββββββ
βΌ βΌ βΌ
inspect mutate verify
β β β
read/search write/patch test/lint
Common categories include:
inspect Β· mutate Β· execute Β· verify Β· git Β· browser Β· memory Β· network Β· finish
Routing is not authorization.
A high-confidence routing decision means:
This is the strongest candidate from the supplied tool set.
It does not mean:
This action is authorized.
The host harness remains responsible for:
Harness Router does not bypass those controls.
Where the host integration supports it, routing failures fail open: if discovery, the router, or the decision provider is unavailable, the original host behavior continues.
For agents without automatic hook integration:
skills/harness-router/SKILL.md
Skill mode is explicit:
agent
β
βΌ
invoke routing skill
β
βΌ
Harness Router
β
βΌ
next tool
Use hooks when routing should be embedded in the host lifecycle. Use the skill when routing should be invoked selectively.
Harness Router is useful when:
If there are only a few obvious tools, routing can add unnecessary overhead.
Evaluate the whole agent loop, not router latency in isolation:
git clone https://github.com/Protocol-Lattice/harness-router.git
cd harness-router
python -m pip install -e ".[dev]"
Run checks:
pytest
ruff check .
mypy
Harness Router is alpha.
The project focuses on one boundary in an agentic system:
current harness state
β
βΌ
tool-selection point
β
βΌ
Harness Router
β
βΌ
next tool
The host harness remains in control of the rest of the agent lifecycle.
A decision layer embedded into the harness tool-selection loop.
Cache β Jev β MCTS
MIT.