You're reading the 0.10.0 archive.

Model resolution

Every codon in a hank names a model, and that one string has to answer several questions before any work starts: which provider and model identity does it mean, which harness will run the session, and does the target actually exist in the catalogs Hankweave can see? This page is the reference for that pipeline. It covers how a model spelling is resolved, how the harness is chosen, where validation can fail, and what changed in 0.10.0.

The terms used throughout: a hank is the workflow configuration in hank.json; a codon is one task in that workflow; a model-session harness is the component that executes the codon. Hankweave first resolves the codon's model spelling to a provider and model identity, then selects a harness. The sections below follow that order: the field and its shortcuts, the resolution steps, harness routing, aliases and special cases, and finally the failure points.

Why model resolution is inspectable#

Model resolution is deterministic, and you can observe it without running a codon. The shipped registry is Hankweave's provider/model catalog; it keeps the resolved identity separate from the harness selected later at dispatch. Shortcut expansion, provider inference, and harness routing all follow fixed rules, and --validate exposes the result. For a local hank, invoke the root flag as bunx hankweave@0.10.0 --validate <hank.json> <data-path>.

One consequence of the separation is worth knowing up front: registry resolution and Pi catalog lookup are distinct checks, so a spelling can resolve in the registry and still fail catalog preflight before a codon runs. When the default route is not the one you need, an explicit pi/<provider>/<model> spelling is the supported way to force the Pi harness.

Pi is Hankweave's in-process coding-agent harness, supplied by @earendil-works/pi-coding-agent; the other model-session harness is the Claude Agent SDK harness. See Hank JSON for the codon field and Authentication and models for the two model-selection planes.

Choosing shortcuts safely#

The codon model field#

Everything on this page starts from one field: the codon's model value, a non-empty string. The schema strip below is the full field contract.

Scroll to explore the table →
fieldtypedefaultrequiredconstraintsdescription
modelstringyesminLength 1Model to use for this codon. Can be a Claude model ('sonnet', 'opus'), Gemini model ('gemini-2.0-flash-exp', 'flash'), or any other model supported by the configured shim.

The description in that strip still contains the older phrase "configured shim". Here, a shim means the removed provider-adapter path, not a third current harness: shim execution was removed in 0.8.0, and current execution uses the two harnesses described above and below.

Shortcut expansion#

To keep hanks short, a few spellings expand before resolution. The shortcuts opus, sonnet, and haiku expand to Claude model names. gpt-5.6 expands to the gpt-5.6-sol sibling variant; -sol is part of that model ID, not a separate harness. Expansion also applies after a provider prefix and before the -high or -xhigh effort suffixes used by reasoning-capable OpenAI variants. The table shows each shortcut, its bare expansion, and how it behaves with a provider prefix or effort suffix.

Scroll to explore the table →
ShortcutBare resolves toProvider-qualified exampleEffort-suffixed example
opusclaude-opusanthropic/opusanthropic/claude-opus
sonnetclaude-sonnetanthropic/sonnetanthropic/claude-sonnet
haikuclaude-haikuanthropic/haikuanthropic/claude-haiku
gpt-5.6gpt-5.6-solopenai/gpt-5.6openai/gpt-5.6-solgpt-5.6-highgpt-5.6-sol-high

For a provider-qualified Claude shortcut, expansion applies to the segment after the first slash. A spelling such as sonnet-high expands textually to claude-sonnet-high, but effort variants are registered only for reasoning-capable OpenAI models; do not assume that the expanded Claude spelling is a registered effort variant.

The complete gpt-5.6 matrix below is useful when checking both qualification and effort, since it shows every accepted spelling and its resolved form:

Scroll to explore the table →
You writeResolved spelling
gpt-5.6gpt-5.6-sol
openai/gpt-5.6openai/gpt-5.6-sol
gpt-5.6-highgpt-5.6-sol-high
gpt-5.6-xhighgpt-5.6-sol-xhigh
openai/gpt-5.6-xhighopenai/gpt-5.6-sol-xhigh

Shortcuts track current provider spellings. Dated model IDs can be retired, so recheck pinned IDs after an upgrade; the --validate model self-test exposes the model check, and the startup self-test also performs the catalog check.

How a model string resolves#

Resolution normalizes the input and then follows the path below. The matchType values describe the successful registry phase. The four entries are presented in order; the implementation calls them steps 0–3, with explicit-Pi as step 0.

  1. Step 0 – explicit Pi spelling: pi/<provider>/<model> sets harnessOverride: "pi"; registry capabilities are used when the underlying model is known, and the Pi target is retained in the spelling supplied after the pi/ prefix.
  2. Step 1 – provider-scoped exact lookup: when the registry is called with a provider scope, an exact provider/model lookup returns exact; codon validation does not supply that optional scope.
  3. Step 2 – ordinary resolution with provider inference: normal config validation supplies the model spelling without a provider argument. A direct match found after preferred-provider inference returns exact-with-inferred-provider; a qualified spelling such as anthropic/claude-sonnet-4-5 follows this ordinary path in a codon.
  4. Step 3 – fuzzy matching: the registry applies its model-match threshold, preferred-provider boost, and recency tiebreak; a match here returns fuzzy.

Before these phases, legacy opencode/... is rewritten to the explicit pi/... escape-hatch form, openrouter/<org>/<model> is rewritten to pi/openrouter/..., and qualified provider aliases are normalized. Those input rewrites are distinct from the retained registry identity: the pi/ prefix in a user's spelling is a Hankweave harness override, not a registry provider name.

The table summarizes the same four steps with their match types and scopes:

Scroll to explore the table →
StepmatchTypeProvider / scopeResult
0. Explicit PiexactRegistry provider when known, or the qualified provider supplied after pi/Pi override with the supplied target
1. Provider-scoped lookupexactExplicit provider argumentCanonical registry model
2. Inferred-provider lookupexact-with-inferred-providerPreferred provider, then a direct matchCanonical registry model
3. Fuzzy matchfuzzyPreferred provider when availableClosest registry model above the model-match threshold

Steps 2 and 3 depend on provider inference, which checks exact name patterns first:

Scroll to explore the table →
PatternPreferred provider
claudeanthropic
geminigoogle
deepseekdeepseek
glm-zhipuai
kimimoonshotai
gpt-, o1-, or o3-openai
Fuzzy fallback: claude, gemini, gpt, or deepseekThe first matching term in that order when the full id or one of its words reaches 0.75 similarity

The 0.75 threshold in the last row belongs to provider inference. It is separate from the 0.6 threshold used by the later model fuzzy-match phase. A bare kimi-prefixed ID therefore prefers moonshotai; the shipped 0.10.0 identity is moonshotai/kimi-k3, replacing the kimi-k2.x spellings the old docs suggested. The bare prefix is not a shortcut that appends -k3, so write kimi-k3 when you want that exact shipped model. The older Kimi rows remain in the catalog. Use exact IDs or shortcuts in production hanks: fuzzy matching is helpful for development but unreliable for production.

For provider setup, see Authentication and models. For the codon's model field, see Hank JSON.

How harness routing is selected#

Once a model identity is resolved, harness selection happens later, at dispatch, from that retained provider/model identity. The registry does not rewrite the identity into a pi/… value. An explicit harnessOverride: "pi" forces the Pi harness, including for a model that would otherwise use the Claude Agent SDK. The routing rules are:

Scroll to explore the table →
Model identityHarnessNotes
First-party Anthropic, or Anthropic-family BedrockClaude Agent SDK harnessBedrock uses CLAUDE_CODE_USE_BEDROCK.
Non-Anthropic BedrockPi harnessRouted through Pi.
Everything elsePi harnessAn explicit harnessOverride: "pi" also forces Pi.

At dispatch, Hankweave derives the route Pi receives from the retained identity. zhipuai becomes zai/<model>, moonshotai becomes openrouter/moonshotai/<model>, and other providers become <provider>/<model>. These are dispatch targets; the pi/ prefix is the separate input spelling that requests the Pi harness.

Scroll to explore the table →
Registry providerPi route
zhipuaizai/<model>
moonshotaiopenrouter/moonshotai/<model>
Any other provider<provider>/<model>

Bedrock has its own split. Anthropic-family IDs use the Claude Agent SDK path. Non-Anthropic IDs use Pi; pi/amazon-bedrock/<model> is the explicit Pi spelling for forcing Anthropic-on-Bedrock through Pi. The spellings and their routes:

Scroll to explore the table →
SpellingHarnessAuth / purpose
anthropic.claude-… or <geo>.anthropic.claude-… (us, eu, jp, au, global, or us-gov)Claude Agent SDK harnessBedrock mode via CLAUDE_CODE_USE_BEDROCK.
pi/amazon-bedrock/<non-Anthropic model>Pi harnessRuns a non-Anthropic Bedrock model through Pi.
pi/amazon-bedrock/<Anthropic model>Pi harnessForces Anthropic-on-Bedrock onto Pi.

Credentials, IAM, and Bedrock limitations belong to AWS Bedrock.

Note that pi/<provider>/<model> is an escape hatch, not an unchecked launch: the spelling goes through model validation, sets the harness override, and must be present in Pi's catalog at startup self-test. When the underlying model is known, its registry capabilities are retained for validation.

Handling aliases and special cases#

Beyond the main path, a few spellings need normalization or extra handling. Qualified aliases normalize input before matching; Pi then derives its dispatch route from the resolved provider identity. The registry's zhipuai identity and Pi's zai route are deliberately different names, as the normalization table shows:

Scroll to explore the table →
You writeQualified input normalizes toPi routes as
zhipuai/<model>zai/<model>zai/<model>
z-ai/<model>zai/<model>zai/<model>
moonshot/<model>moonshotai/<model>openrouter/moonshotai/<model>
moonshot-ai/<model>moonshotai/<model>openrouter/moonshotai/<model>
moonshotai/<model>moonshotai/<model>openrouter/moonshotai/<model>

GLM routing is provider inference (glm-zhipuai) followed by the zhipuaizai route alias. A stale registry comment names rewriteGlmModel, but there is no such function in the 0.10.0 model validator and no additional rewrite step.

Reasoning effort in Pi#

Reasoning-capable OpenAI models receive auto-generated -high and -xhigh variants. Pi strips the suffix at dispatch, resolves the base model, and passes the suffix as thinkingLevel. An unsuffixed OpenAI model defaults to high; high has a ×1 multiplier and xhigh has a ×2 multiplier against the registered base-model cost. The three spellings and their costs:

Scroll to explore the table →
SpellingEffortCost multiplier
gpt-5.6-solhigh (default)×1
gpt-5.6-sol-highhigh×1
gpt-5.6-sol-xhighxhigh×2

Legacy stored identities#

A stored execution plan is the saved model identity for a resumable run. Older plans can contain removed Gemini, Codex, or OpenCode shim provider IDs, or the retired pi pseudo-provider encoding. Migration restores the real provider/model identity; a retired pi model ID is split at its first slash, and a legacy plan that forced Anthropic onto Pi resumes on the Claude Agent SDK route. Each legacy encoding and its migration:

Scroll to explore the table →
Legacy encodingMigrationResume behavior
Removed Gemini and Codex shims stored as provider IDs google and openaiShims are removed; models run natively.Resume uses the native provider/model route.
Removed OpenCode shim stored as provider ID opencodeShim is removed; bare spellings are resolved through the registry.Resume uses the native provider/model route.
Retired pi pseudo-provider with providerId: "pi" and modelId: "<provider>/<model>"Split the model ID on its first slash; openrouter/… remains provider openrouter.Legacy Anthropic-on-Pi plans resume on the Claude Agent SDK route.

See Hanks for model-override semantics and configuration precedence; those settings are separate from this resolution path.

Where model validation fails#

Resolution can succeed while execution still fails, so it helps to know exactly which gates a model passes through. Validation has two model-availability gates here: registry resolution and the Pi catalog when Pi will run the model. Provider health checks are a separate mechanism; they use candidates from provider configuration rather than the codon's model value. The candidates per provider:

Scroll to explore the table →
ProviderHealth-check candidates
anthropicclaude-haiku-4-5 (pinned, stable)
openaigpt-5.4-mini (pinned)
googlegemini-flash-latest (pinned)
deepseekdeepseek-v4-flash (pinned)
groqNone; falls back to findCheapestModel.
amazon-bedrockbedrockHealthCheckModels(); region-dependent candidates use us.<haiku>, eu.<haiku>, jp.<haiku>, au.<haiku>, global.<haiku>, or us-gov.<haiku>.

The provider health-check candidate is in provider configuration, not hank.json; changing a codon's model does not change that candidate. The full distinction between the codon's self-test and provider health check, including when the health check runs and what it tests, belongs to Authentication and models.

Since 0.10.0, startup self-test performs the model_catalog check for Pi-routed models on every startup, not only with --validate. Any registry result that routes to Pi–including an inferred or fuzzy match–still faces this catalog gate; a Claude Agent SDK route does not. Pi's catalog combines a static vendored snapshot with ~/.pi/agent/models.json, and the same lookup is used when Pi spawns a session. A catalog miss therefore fails config load before any Pi-routed codon runs. The two stages and their failure behavior:

Scroll to explore the table →
StageWhat it checksWhere it runs / failure
1. Registry resolutionvalidateModel confirms the model identity and capabilities.Model validation.
2. Pi catalog checklookupPiModel confirms presence in the static snapshot plus ~/.pi/agent/models.json.Startup self-test; a miss fails config load before codon execution. Pi model not found: <provider>/<model>. Available '<provider>' models: <list> or Unknown pi provider '<provider>'. Known providers: <list>.

CodonRunner.canRun(model) delegates to selectHarness(model). That selector is total in 0.10.0: every registry-resolvable model maps to one of the two harnesses, with Pi as the fallback. The supported-provider list anthropic, amazon-bedrock, pi is a list of provider IDs, not a list of three production harnesses; it should not be read as an additional harness-failure gate.

Scroll to explore the table →
GuardCheck0.10.0 behavior
CodonRunner.canRun(model)selectHarness(model) chooses Claude Agent SDK or Pi.Returns true for every registry-resolvable model; the Pi catalog gate remains the relevant preflight for Pi-routed models.

There is no hankweave models list subcommand. The --validate output shows each codon's resolved model, and a per-model self-test failure reports its reason, including a Pi-catalog miss. The curated supported-models table and registry/Pi selection universe belong to Models and harnesses, not this page.

See Authentication and models for the two model-selection planes, Models and harnesses for the curated model table, and Errors and exit codes for error classification.

What changed in 0.10.0#

For a 0.9.x user, the relevant 0.10.0 changes are late-bound harness selection, retired Pi pseudo-provider encodings, and Pi catalog preflight. The remaining rows identify when the older resolution surfaces first shipped, which matters when reading documentation written against an earlier version:

Scroll to explore the table →
Model-resolution surfaceSince
GLM routing via pi/zai and ZAI_API_KEY0.7.4+
GPT-5.6 → -sol shortcut and Kimi routing via OpenRouter / OPENROUTER_API_KEY0.7.5+
Two-harness routing and shim removal0.8.0+
Late-bound harness selection and Pi pseudo-provider retirement0.10.0+
Pi catalog preflight during startup self-test0.10.0+

The 0.10.0+ markers cover late-bound harness selection, retired Pi pseudo-provider encodings, and catalog preflight. See Upgrading when checking a pinned model spelling after a version change.