Skip to content

Latest commit

 

History

History
539 lines (488 loc) · 32.2 KB

File metadata and controls

539 lines (488 loc) · 32.2 KB

2.0 Backend Freedom: Capability Routing + Pluggable Inference

Status: STARTED - second 2.0 pillar to start (after 1.x step 1 lands, since local-quality judgments need trustworthy instruments). ROADMAP anchors: Active Queue #18; "Local Inference Mode" (Considered for Later); existing provider abstraction (v1.22-1.24).

Motivation

A run should be cost-tunable from sub-$1 cloud down to $0 API local, and should eventually be able to use official agent hosts when both sanctioned tooling and trustworthy billing provenance or explicit operator acknowledgment are available, without changing the pipeline. Local is a moving default candidate, not a permanent discount tier: as desk-side AI hardware improves, more stages should graduate to $0 API local execution when eval proves the quality bar holds. The provider abstraction, role-based routing, and the Ollama provider already exist; what's missing is (a) stages declaring what they need rather than which model they want, (b) eval-validated direct/local/hybrid recipes, and (c) a bounded host runner seam that does not mistake authentication type for billing proof.

Current state

  • Provider ABC + xAI/Gemini/OpenAI/Anthropic/Ollama providers; per-model usage and cache accounting; finite HTTP timeouts everywhere (v1.30.0)
  • pick_model_for_role routes UTILITY/WRITING/REASONING by key availability with hardcoded preference chains
  • ModelCircuitBreaker + call_with_failover live at all production call sites (v1.30.0) - quota events already fail over across providers
  • Local eval judging (Ollama) and named local model lists exist in the eval harness
  • Agent-host integrations exist as MCP/skill surfaces that let compatible agent hosts operate primr. The first in-run host-agent pilot is an unpromoted fast.source_relevance adapter through the official Codex CLI. A single-company experimental route is exposed only with --inference hybrid --acknowledge-host-agent-may-bill because Primr cannot determine whether Codex authentication is plan-backed or API-key billed. It records potentially metered billing and pending-eval status, not plan usage.
  • ai/host_agent_runner.py now defines the transport-free runner contract: bounded stage packet, host billing policy, normalized result metadata, and evidence fencing. ai/host_agent_cli.py provides the first concrete Codex CLI transport for the source-relevance pilot; additional official runners and stages are still planned.
  • The complementary host-native, keyless path is shipped: primr prep collects a versioned evidence bundle with model calls disabled, and the portable .agents/skills/primr-zero skill lets the surrounding host research and synthesize from its existing plan allowance after the host billing basis is verified. This is an artifact handoff, not an internal backend or a claim that the host produced the measured full Primr pipeline.
  • ai/capability_routing.py now defines the pure StageRequirements router: backend capability rows, cloud/agent/hybrid/local profiles, billing-mode guards, ordered route plans, and explicit rejection reason codes. It has no provider calls; production execution now consumes it first for fast.scrape_summary, fast.source_relevance, and fast.hiring_signals.
  • ai/provider_availability.py now defines the pure quota/availability contract: normalized quota windows, binding headroom, elapsed-reset handling, stale last-known-good snapshots, and deterministic provider ranking. It has no provider calls and is the seam live quota collectors should feed.
  • ai/provider_availability_collectors.py adds the first generic collector layer: non-secret cloud provider configuration snapshots and local OpenAI-compatible service probes using the user's configured endpoint. It does not store API key values, raw endpoint URLs, account ids, or installed model names.
  • ai/capability_routing.py can now apply provider availability snapshots to backend capability rows with sanitized metadata. This is the deterministic bridge between generic collectors and route_stage().
  • primr doctor now surfaces the same generic provider availability view without paid cloud probes, raw endpoint URLs, installed local model names, API key material, account ids, or raw exception payloads.
  • core/stage_inventory.py now declares the production-stage capability inventory for fast-mode and premium deep-research execution. Each row records the stage id, module, role, reasoning and trust requirements, context and token estimates, egress/deep-research/structured-output needs, accepted backend families, budget checkpoints, current backend ownership, promotion gate, and emitted artifacts.
  • ai/stage_routing.py is the first production runtime bridge from the stage inventory to route_stage(). fast.scrape_summary, fast.source_relevance, and fast.hiring_signals now resolve their legacy utility models through the capability router behind --inference cloud|hybrid, log safe route metadata, append capped body-free stage_routes entries to _run_state.json, include measured token/cache/cost deltas when provider counters expose them, and execute through existing provider seams with today's role defaults preserved as fallback. fast.source_relevance has an explicit, single-company experimental Codex CLI adapter; other agent/local stage execution remains planned until each stage has a dedicated adapter and eval evidence. If tests or evals select the internal agent profile before those adapters exist, fast.scrape_summary and fast.hiring_signals now record body-free agent_profile_unavailable fallbacks and use deterministic source-excerpt or posting-metadata output instead of silently falling back to cloud APIs.
  • First production local slice shipped (1.x, calibration judge): ai/local_inference.py detects any OpenAI-compatible server via the generic /v1/models endpoint (fail-open, cached, env-chain base URL) and picks a judge model from whatever is installed by family preference; primr calibrate --judge auto|local runs the traceability judge locally at $0 with fail-closed local-call behavior, sidecar provenance stamping, and a --judge-compare cloud-vs-local agreement measurement. These detection, fail-closed, and agreement-validation patterns are the template the utility-tier routing below should reuse.
  • Provider-specific xAI browse/search behavior and Gemini terminal quota guidance now live in provider-owned seams. The xAI surrogate is owned by XAIProvider and exposed through the legacy grok_browse_and_summarize() wrapper; Gemini quota copy is owned by GeminiProvider and rendered by the legacy Gemini llm() path.
  • Cost estimates now expose live input, cached input, cached-input cost, and long-context surcharge fields. Historical cached-token averages are included when available, but pre-run estimates assume zero speculative cache hits.

Current external practice checkpoint

Reviewed 2026-06-30:

  • OpenTelemetry's GenAI semantic conventions have moved to the dedicated GenAI conventions surface. Backend-freedom telemetry should preserve provider, model, operation, token, and usage concepts so stage route records can map to those conventions when runtime spans are wired. See OpenTelemetry GenAI semantic conventions.
  • OpenAI prompt caching is automatic for recent models and depends on exact prompt-prefix reuse, with cached-token counts exposed in usage metadata and discounted cached input pricing. Stage requirements and estimates therefore need room for stable-prefix and cached-token accounting. See OpenAI Prompt caching.
  • OpenAI's current API pricing page labels GPT-5-family standard pricing as applying under 270K context. Estimates therefore model the >270K long-context tier explicitly where the registered context window can cross that boundary. See OpenAI API pricing.
  • Anthropic prompt caching changed to workspace-level isolation on the Claude API, Claude Platform on AWS, and Microsoft Foundry as of February 5, 2026, while requiring exact prompt segment matches. Provider-specific cache semantics must stay provider-owned, not hardcoded in a generic stage. See Anthropic Prompt caching.
  • Gemini's current API docs describe implicit caching, explicit caching on the generateContent API, context-cache token reporting, Gemini 3 long-context support, and current Interactions API limitations. Long-context estimates need provider-specific cache and API-surface fields before routes can be compared honestly. See Gemini context caching, Gemini generateContent caching, and Gemini 3 developer guide.

Immediate next slice

The three cheap utility-stage pilots now prove the runtime bridge: fast.scrape_summary, fast.source_relevance, and fast.hiring_signals record route metadata in _run_state.json: backend id/kind, billing mode, route/fallback reason, expected stage token budget, latency, input/output item counts, failure class, and measured token/cache/cost deltas when provider counters expose them. Body-free route comparison artifacts now aggregate those records by stage/backend/profile, and scorecards can join those route rows with explicit quality evidence to mark candidates for human review. The CLI can now write those artifacts through primr --eval --eval-stage-scorecard from route ledgers plus explicit quality evidence JSON, and MCP clients can inspect the compact scorecard summary at primr://eval/stage_scorecard/{eval_id} without raw prompt, report, source, or run-state content. The website-summary local stage eval now writes website_summary_stage_quality_evidence.json as structured scorecard input, and same-command scorecard generation can consume it when no manual quality-evidence path is supplied. The same local stage eval can now add --eval-local-stage-semantic-judge to produce body-free semantic quality evidence from a local OpenAI-compatible judge or comma-separated local judge panel and feed that evidence to the same-command scorecard. Panel runs record score-spread agreement metadata. This is still review-only: calibrated samples and human-reviewed acceptance criteria are required before any host or local candidate can be promoted.

The first official host-agent transport is an unpromoted fast.source_relevance Codex adapter. Primr builds a fixed stage packet and invokes official codex exec with a read-only sandbox, disabled web search and shell tools, no approvals, no persisted history, a JSON-array output schema, and bounded time/output limits. If no runner qualifies under the internal agent profile, Primr records agent_profile_unavailable and keeps all sources rather than spending cloud API dollars silently. The public CLI remains --inference cloud|hybrid; an installed Codex runner becomes eligible only for a single-company command that also supplies --acknowledge-host-agent-may-bill. Primr records that route as potentially metered and experimental with its promotion eval pending. Unknown host charges are outside Primr's estimate and budget, and batch fan-out is rejected. Promotion still requires calibrated eval evidence plus billing provenance or the explicit billing acknowledgment.

Source-relevance fixture evals can now produce the first review-only quality evidence for that pilot: --eval-source-relevance-fixture accepts labeled source-number keep lists and candidate keep lists, then writes body-free precision, recall, F1, exact-match, and scorecard quality evidence for fast.source_relevance. It measures selection behavior without inspecting prose or copying source URLs/text into scorecards.

Production stage inventory

The canonical inventory lives in src/primr/core/stage_inventory.py.

Stage ID Role Trust Accepted non-cloud candidates Budget checkpoint
fast.scrape_summary utility medium host, local no
fast.source_relevance utility medium host, local no
fast.hiring_signals utility medium host, local no
fast.research_deepening reasoning high none yet yes
fast.analysis_workbook reasoning high none yet no
fast.report_sections writing high none yet no
fast.cross_validation reasoning high none yet yes
fast.trust_polish writing high none yet no
fast.label_honesty utility high none yet optional
fast.strategy_generation writing high none yet yes
premium.deep_research reasoning high none yet no

Only the first three fast-mode utility stages are declared as local or host pilot candidates. Every high-trust stage remains cloud/gateway-only until the standing eval corpus proves a candidate backend preserves trust, citation, reasoning, and utility behavior.

Design

Capability-requirement routing (#18)

Each pipeline stage declares a StageRequirements (frozen dataclass): minimum reasoning depth (enum value, calibrated from eval data, not vibes), required capabilities (web_search, structured_output, long_context >= N tokens), trust sensitivity, accepted backend families, and acceptable latency class. The shipped pure router solves for the cheapest compatible backend from the supplied capability rows:

  • Inputs: StageRequirements, ModelConfig capability/pricing metadata (extend with capability flags + tier_threshold_tokens for the long-input surcharge models), available backend rows, operator routing policy, and later circuit-breaker health
  • Output: a fallback chain (ordered candidates), which call_with_failover already consumes once production wiring is added
  • The requirements themselves come from observed eval cost/quality per role. Until a stage has eval evidence, it inherits today's role-based default - the migration is incremental, stage by stage

Execution profiles

The public CLI exposes --inference cloud|hybrid. Internal router profiles also represent agent and local candidates for tests and evals, but they are not supported configuration. Today the production default is the direct-cloud path because it is the validated full-report recipe. The 2.0 target for an unflagged run is the best validated route by incremental spend and quality: local capacity first where it passes the stage bar, a host runner only when its billing basis is proven or explicitly acknowledged, otherwise the best sub-dollar API recipe, with premium routes explicit.

  • cloud uses direct provider APIs and remains the reproducible baseline and fallback.
  • The internal agent profile represents an official host runner for compatible stages through a sanctioned automation, local CLI, or connector surface. It is structured and bounded and cannot own the pipeline loop, egress policy, disk writes, or completion decision. It remains eval-only until quality and billing gates both pass.
  • hybrid is the public promotion surface for stage candidates that pass their requirements and evals. Host candidates also require billing provenance or explicit operator acknowledgment. Direct cloud remains in place for reasoning/trust-critical stages until eval data says otherwise.
  • local requires local for all compatible stages and skips stages with no local equivalent (Deep Research) with clear logging. No silent fallback to paid cloud. Its quality class is per hardware/model profile and should be re-measured as local capacity improves.

The cost estimator reports dollars for direct API stages and $0 API plus runtime for local stages. A future host route may report "host plan usage" only when the billing basis is proven; otherwise it must report unknown or potentially metered billing and require acknowledgment. Progress display names the backend per stage.

External local runtimes

The local boundary is OpenAI-compatible HTTP, not one runtime brand. An operator-installed MAX Serve, Ollama, llama.cpp, vLLM, LM Studio, LocalAI, or other compatible server can be evaluated through LOCAL_LLM_BASE_URL without adding a new provider abstraction or embedding its implementation language.

Runtime comparisons use the same model, quantization, hardware, prompts, and quality corpus where possible. Record report and stage quality, success rate, time to first token, throughput, p95 latency, peak VRAM, cold start, busy and out-of-memory behavior, and total Primr run duration. The existing available/busy/unavailable contract, bounded retry guidance, and hard-zero no-paid-fallback rule remain authoritative regardless of runtime.

Primr does not embed Mojo or MAX through FFI and does not install, start, reserve, or terminate the operator's model server. Bundling any runtime requires a separate platform, distribution, security, and license review. See runtime-language-boundaries.md.

Host-native evidence handoff

primr prep serves users who have no provider key or GPU but do have a capable agent host. Primr retains deterministic collection, URL safety, DNS, hiring signals, local PDF text, source indexing, trace artifacts, and content fencing. It writes primr.host-evidence-bundle v1.0 plus a bounded research packet. The host then owns external research, synthesis, and review through the portable primr-zero skill.

The collection context disables model calls even when keys are configured, and the manifest records zero model calls and $0.00 incremental API spend. This path must remain distinct from the internal Codex adapter: Primr does not invoke or authenticate the host, and the output is labeled host-assisted. It is the supported plan-native path while in-pipeline host routes remain unpromoted until their stage eval clears. Zero total incremental spend is promised only after the host is verified not to bill API usage or overages.

Provider availability and quota headroom

Provider and host-account availability must be a deterministic routing input, not ad hoc UI text or provider-specific exception handling. Collectors return ProviderQuotaSnapshot rows. Generic collectors can report configuration and local-service availability immediately; official live quota collectors should add zero-token quota/status windows wherever supported and fall back to stale last-known-good snapshots when a quota endpoint is temporarily unavailable.

The normalized contract is intentionally small:

  • QuotaWindow represents one provider bucket, such as requests per day, tokens per minute, weekly host-account usage, or local runtime capacity.
  • binding_window() selects the most constrained window, so one exhausted bucket can prevent an otherwise healthy provider from being ranked first.
  • Elapsed reset times are treated as fresh quota because stale provider data should not keep a model marked exhausted after its reset boundary.
  • Stale snapshots preserve useful routing information, but provider_with_most_headroom() prefers fresh snapshots before stale ones.
  • Generic collectors must meet users where they are: read only their runtime environment and configured local OpenAI-compatible endpoint, never repo-owned credentials, personal account ids, raw endpoint URLs, or provider-specific private surfaces.
  • Local capacity has three explicit states: available, busy, and unavailable. A 429/503 response or probe timeout is busy; connection failure, an invalid endpoint, or no usable chat model is unavailable.
  • A busy result carries body-free retry_after_seconds and retry_at metadata. Server Retry-After hints are bounded to 30 seconds through six hours. When no hint exists, caller-supplied attempt numbers select 30 minutes, two hours, then six hours.
  • The same contract applies after actual local chat execution exhausts its short in-call retries. A structured LocalCapacityBusyError carries the safe retry metadata; large server hints are not converted into hidden in-process sleeps.
  • Retry metadata is guidance, not an in-process scheduler. Primr does not poll, sleep until capacity frees, or become a daemon. The CLI, MCP host, or external scheduler may submit a later single job after re-checking capacity.
  • An explicit local profile is a hard zero-API boundary. If no local backend qualifies, the stage returns an unavailable route and uses its deterministic no-model fallback. It never returns the paid legacy model silently. Route metadata distinguishes busy, unavailable, and unknown capacity from an available endpoint that lacks an executable stage adapter.

Next production wiring: official cloud collectors translate supported quota/status metadata into this shape, then the existing availability-to-backend adapter carries the resulting decision into route_stage(). ModelCircuitBreaker continues to handle runtime failures and quota exceptions observed mid-call.

Host agent runner

The host runner is not a generic provider API. It is a Level-2 decision point: primr hands a fixed stage packet to an official agent host and receives a schema-constrained response.

Stage packet fields: role, model capability requirements, evidence bundle, prompt, output schema, timeout, budget/plan policy, and provenance labels.

Required properties:

  • Uses only official auth surfaces and local/automation commands. No browser scraping, unofficial proxies, or private endpoints.
  • For the Codex pilot, the only transport is official codex exec with a read-only sandbox, disabled web search/shell-tool config, no approvals, no persisted history, and schema-constrained output.
  • Remains unpromoted. Single-company hybrid experiments require an explicit potentially metered billing acknowledgment, and route metadata records that the quality eval is still pending.
  • Fails open to other configured profiles when the host runner is unavailable, except when an eval harness deliberately selects the internal agent profile.
  • Records runner provenance in sidecars and usage records.
  • Treats route billing metadata as a declared policy category, not proof of the authenticated host session's actual billing basis.
  • Runs through the same semantic calibration/eval path as API-keyed recipes before promotion.

Doctor support

The standard primr doctor availability section now distinguishes a reachable local endpoint from transiently busy capacity and an unavailable endpoint. Busy capacity includes the bounded retry time. A future focused local fit check can add model-specific VRAM sufficiency without making vendor-specific GPU APIs part of the generic OpenAI-compatible probe.

Order of operations

  1. Stage-requirements schema + router as a pure function over existing ModelConfig - DONE in ai/capability_routing.py with fake-backend tests and no production behavior change while every stage still carries the legacy default.
  2. Provider availability schema + pure headroom helpers - DONE in ai/provider_availability.py with no live provider calls.
  3. Generic availability collectors - DONE in ai/provider_availability_collectors.py: non-secret cloud configuration status plus local OpenAI-compatible probe snapshots. Next is official zero-token quota/status metadata where providers expose it.
  4. Availability-to-backend bridge - DONE in ai/capability_routing.py: provider snapshots mark backend rows unavailable and attach sanitized routing metadata before the pure router ranks candidates.
  5. Doctor availability visibility - DONE in core/cli_doctor.py: sanitized generic snapshots are visible to operators without paid cloud probes or local endpoint leakage.
  6. Production stage capability inventory - DONE in core/stage_inventory.py: fast-mode and premium deep-research stages now declare router-ready capability rows and promotion gates without changing runtime behavior.
  7. Move xAI browse/search surrogate into providers - DONE in ai/providers/xai.py: XAIProvider owns the Responses API browse/search call and grok_browse_and_summarize() is compatibility glue.
  8. Move Gemini quota UI/fallback messaging into provider-owned seams - DONE in ai/providers/gemini.py: GeminiProvider owns terminal quota guidance and llm() renders it generically.
  9. Long-context surcharge and cache-token modeling in estimates - DONE: CostEstimate now exposes live input, cached input, cached-input cost, and long-context surcharge fields without assuming unobserved cache savings.
  10. First routed utility stage - DONE in ai/stage_routing.py and core/source_relevance.py: fast.source_relevance consumes route_stage() behind --inference cloud|hybrid while preserving the legacy utility model as fallback.
  11. Route usage metadata - DONE in ai/stage_routing.py and core/source_relevance.py: routed fast.source_relevance calls append capped body-free stage_routes records to _run_state.json with backend, profile, billing, route reason, fallback reason, expected token budget, latency, source counts, and failure class.
  12. Second routed utility stage - DONE in ai/summarize.py: routed fast.scrape_summary calls pass the selected model through the existing summarizer llm() seam and append capped body-free stage_routes records with backend, profile, billing, route reason, fallback reason, expected token budget, input page count, output summary count, duration, and failure class.
  13. Third routed utility stage - DONE in data/hiring_signals.py: routed fast.hiring_signals calls pass the selected model through the existing hiring triage/extraction seams and append capped body-free stage_routes records with backend, profile, billing, route reason, fallback reason, expected token budget, discovered role count, extracted role count, duration, and failure class.
  14. Route comparison artifacts - DONE in core/stage_route_comparison.py: route records aggregate by stage/backend/profile into body-free JSON and Markdown with attempts, selected/fallback/failure counts, latency, and measured token/cache/cost deltas. These artifacts are eval inputs, not promotion decisions.
  15. Stage eval scorecards - DONE in core/stage_eval_scorecard.py and core/stage_eval_scorecard_cli.py: explicit quality evidence joins with route comparison rows to classify candidates as human-review-ready, needing quality eval, below quality bar, or needing reliability review. primr --eval --eval-stage-scorecard writes JSON/Markdown artifacts from route ledgers and a supplied quality evidence JSON file. Scorecards never auto-promote a backend.
  16. Stage scorecard MCP readback - DONE in mcp_server/stage_scorecard_summary.py: primr://eval/stage_scorecard/{eval_id} returns compact route, quality-score, status, and blocker fields from the CLI-generated JSON artifact without arbitrary file paths, prompt bodies, report bodies, quality-source bodies, or raw run-state content.
  17. Generated stage quality evidence - DONE in core/local_stage_eval.py and core/cli_local_stage_eval.py: website-summary local-stage evals write scorecard-ready quality evidence from existing completeness metrics, and --eval-local-stage website-summary --eval-stage-scorecard can consume the generated evidence in the same command. This remains scorecard input only, not a promotion gate.
  18. Semantic local stage evidence - DONE in core/local_stage_eval.py and core/cli_local_stage_eval.py: --eval-local-stage-semantic-judge runs a local OpenAI-compatible judge or comma-separated local judge panel over baseline and candidate website summaries, stores body-free score rows, agreement metadata, and semantic quality evidence, and lets same-command scorecards use that semantic evidence when requested. This is a review signal, not a promotion gate.
  19. First official host-runner transport - DONE as an internal/eval-only pilot in ai/host_agent_cli.py, ai/stage_routing.py, and core/source_relevance.py: evals can route fast.source_relevance through the official Codex CLI runner, record body-free host route metadata, and refuse silent cloud API fallback when the internal agent profile has no qualifying runner. It is not a public CLI profile.
  20. Source-relevance fixture evidence - DONE in core/source_relevance_eval.py and core/cli_local_stage_eval.py: --eval-source-relevance-fixture turns labeled keep-list fixtures into body-free quality evidence for review-only fast.source_relevance scorecards.
  21. Agent-profile fail-closed safety for remaining routed utility stages - DONE in ai/summarize.py and data/hiring_signals.py: internal agent-profile unavailability for fast.scrape_summary and fast.hiring_signals records body-free route fallbacks and uses deterministic local output instead of invoking cloud LLMs before a stage-specific host adapter exists.
  22. Keyless host-native handoff - DONE in core/cli_prep.py, core/evidence_bundle.py, utils/model_policy.py, and the portable .agents/skills/primr-zero package: deterministic collection emits a versioned, bounded, fenced packet and fails closed against model egress.
  23. Hybrid profile - IN PROGRESS. The first billing-honesty slice is shipped for fast.source_relevance: an explicitly acknowledged, potentially metered Codex route is available only for single-company experimental runs, with estimate, budget, route-ledger, selected-host failure, and batch-fan-out guards. It is marked experimental_eval_pending, not promoted. Next, curate the representative source-relevance corpus and eval host vs cloud on the same labeled cases. Then route additional cheap utility stages local or through billing-proven or explicitly acknowledged hosts only after their own gates.
  24. Full local profile + doctor --local; eval again; document the quality band honestly - "local quality unacceptable for stage X on this hardware" is a valid, publishable outcome, and a prompt to re-test when local capacity improves
  25. Per-stage requirement tuning from accumulated eval data

Validation cost

Steps 1-4 are free to build with fakes. The host-native prep path is covered by zero-network unit fixtures plus hard no-model-call contract tests. Live runner validation can use official host-plan allocation only after that billing basis is verified; otherwise the operator must acknowledge potentially metered API use. Direct cloud comparison should stay under the existing ~$4-5 corpus pass. Local validation is $0 API plus GPU time. A 4090-class workstation should start with the focused 4090-report-race local stage eval against the current sub-dollar API baseline before spending time on the full local matrix. Promotion criteria pre-registered: trust-gate pass rate, decision-utility within band of cloud baseline, billing/plan behavior documented, runtime documented, and default class assigned (zero-incremental, sub-dollar API, fallback, or premium-only).

Exit criteria

  • Any stage can be answered by any backend that meets its declared requirements; chains come from the router, not hardcoded preference lists
  • A public host-runner profile ships only after at least one official runner has a published eval and either trustworthy billing provenance or an explicit potentially metered billing acknowledgment. Until then, the Codex adapter is an explicitly gated, single-company experiment with pending-eval metadata, not a supported or default backend. Additional hosts remain candidates until they meet the official invocation, structured-output, provenance, bounded-runtime, and billing-honesty requirements.
  • --inference hybrid ships as a supported mode with a published eval
  • --inference local either ships with a published eval or is documented as not-yet-meeting-bar per stage (also a valid exit)

Explicitly not

  • No new orchestration framework - the router returns a chain; execution stays in the existing failover seam
  • No fine-tuning and no bundled model server; local execution points at the user's OpenAI-compatible endpoint
  • No silent quality degradation: profile changes are explicit operator choices, surfaced in the run banner and usage records
  • Backend freedom is model-execution freedom, not a mandate to rewrite Primr in another programming language