Yieldpoint

Safe model routing

Yieldpoint can describe what a change needs without selecting a model or calling a provider. Your host owns models, keys, vendor requests and final actions.

Start observe-only

{
  "routing_session": {
    "enabled": true,
    "max_model_switches": 1,
    "capsule_max_chars": 12000,
    "router_overhead_fraction": 0.05,
    "allow_unverified": false,
    "checkpoint_events": ["verification_failed", "repair_exhausted", "loop_tripped"]
  }
}

Routing is off by default, and off means off: with enabled false, assess returns exactly what it returned before routing existed. Turn it on first in a non-enforcing integration, compare the recommended tier with the model that actually completed the task, then choose any provider policy outside Yieldpoint. Do not use an uncalibrated confidence value as permission to act.

Every bound travels with the profile

The profile’s handoff block carries the switch budget, the live checkpoint events, the overhead ceiling and the unverified policy. That is deliberate: the Node and Java hosts receive only this document, so a limit left behind in Python would be a limit they could not apply. The block is covered by the profile’s profile_id digest, which the Python engine recomputes whenever it reads a profile back — so a profile edited to widen its own budget is refused by the CLI and the MCP tools rather than honoured. Node and Java validate structure and pairing and apply the bounds; the digest stays the canonical engine’s to check.

One admission, one bounded handoff

git diff > change.diff
yieldpoint assess-routing --diff change.diff --verdict verdict.json --repair-attempt 1
yieldpoint build-capsule --profile profile.json --session session.json \
  --objective "Charge each line item at its own price" --acceptance "Unit tests pass"
yieldpoint handoff-check --profile profile.json --session session.json \
  --event verification_failed --overhead 0.04 \
  --capability strong_reasoning --capability tool_use

--diff profiles the whole change set, which is usually what a task is: the riskiest file decides the tier, every file’s requirements accumulate, and one file the engine cannot read makes the whole set inexact. Use --path/--after for a single file.

Keep the admitted model for normal work. A handoff is allowed only at a checkpoint your policy lists, only within the switch budget, only when the estimated router and capsule input fits router_overhead_fraction, and only when the candidate has every capability the profile requires. Each refusal names the bound it failed.

Route on evidence, not on its absence

Pass --verdict. Without one the profile reports unverified, and an unverified change is not handed to a larger model: there is no evidence a stronger model would help, and spending one to find out is the cost this feature exists to avoid. A pass buys no second opinion and a block is a person’s decision; neither is routed around. Set allow_unverified if your pipeline genuinely wants the opposite.

Hooks and SDK integration

The MCP tools yieldpoint_routing_profile, yieldpoint_build_task_capsule and yieldpoint_handoff_check provide the same contracts for developers wiring an agent loop. The Python LangGraph adapter supplies make_admission_node and make_handoff_router; admission reads the verdict, repair count and loop state already in graph state, so placing it after a verify node is all the wiring it needs. Node and Java apply the same bounds from the same profile, checked against shared fixtures. See the runnable SDK and CLI examples, including the optional Jev adapter.

Measure without collecting content

yieldpoint routing-stats

This reads only the local .yieldpoint/routing.jsonl ledger. It contains event counts, tier, selection source, switch counts, capsule size and handoff outcomes; it never contains model names, prompts, provider payloads, diffs or secrets. Disable it with YIELDPOINT_NO_METRICS=1 or "metrics": { "enabled": false }.