Use any provider in Crush
To give Charm's Crush another provider, yoink adds a providers.<id> block to ~/.config/crush/crush.json, typed openai-compat or anthropic, and with --default points models.large at your model. It never edits Crush's state folder. One command does it: yoink connect <name> --to crush --default <model>.
On this page
At a glance
| Fact | Value |
|---|---|
| Harness id | crush |
| Config yoink writes | ~/.config/crush/crush.json |
| Format | JSON |
| Protocols, in order of preference | openai-chat, anthropic-messages |
| Default model | models.large: { provider, model } |
| Path override | CRUSH_GLOBAL_CONFIG, XDG_CONFIG_HOME/crush |
| Providers at once | many, side by side |
| Experimental | no |
| Presets that reach it | 7 of 7: openai, kimi-code, moonshot, openrouter, deepseek, zai, ollama |
| Connect command | yoink connect <name> --to crush |
Generated from the yoink CLI source and docs/harnesses.md.
What yoink writes
On a fresh machine yoink creates crush.json with Crush's $schema line, then adds the provider. This is the OpenRouter preset after --default z-ai/glm-4.7, key redacted; the limits come from models.dev:
{
"$schema": "https://charm.land/crush.json",
"providers": {
"openrouter": {
"name": "OpenRouter",
"type": "openai-compat",
"base_url": "https://openrouter.ai/api/v1",
"api_key": "<your key>",
"models": [
{
"id": "z-ai/glm-4.7",
"name": "GLM-4.7",
"cost_per_1m_in": 0,
"cost_per_1m_out": 0,
"cost_per_1m_in_cached": 0,
"cost_per_1m_out_cached": 0,
"context_window": 204800,
"default_max_tokens": 131072,
"can_reason": true,
"supports_attachments": false
}
]
}
},
"models": {
"large": { "model": "z-ai/glm-4.7", "provider": "openrouter" }
}
}The four cost fields are always 0: yoink has no price list, so it writes zero instead of guessing. context_window, default_max_tokens and can_reason come from the model data yoink stores with the provider, and supports_attachments follows whether the model takes images.
Which providers work
Crush takes OpenAI Chat Completions first and Anthropic Messages second. It has no Responses support through yoink, so:
- the
openaipreset lands asopenai-compatagainsthttps://api.openai.com/v1, not as Crush's ownopenaitype; - the five dual-endpoint presets (
openrouter,kimi-code,moonshot,deepseek,zai) use their Chat endpoint; ollamaworks onhttp://localhost:11434/v1;- a custom gateway that only answered the
/responsesprobe is refused with "has no endpoint Crush can use".
yoink connect openrouter --to crush --default z-ai/glm-4.7
yoink connect ollama --to crushCrush is not experimental
Crush carries no experimental tag in yoink; the experimental harnesses are Goose, Zed and Claude Desktop. The key goes straight into crush.json as a literal api_key, so there is no environment variable to export afterwards.
Two notices to read after connecting
A crushrc beside the file. Crush's README (checked 2026-10-10) documents a newer crushrc format and calls the JSON format still supported but deprecated. When a crushrc sits in the same folder as crush.json, yoink prints "If Crush reads it instead of crush.json, add OpenRouter there too." yoink only looks in that folder; a project-level .crushrc is not checked.
A model picked in the Crush UI. Crush remembers your last picker choice in its state file, ~/.local/share/crush/crush.json. yoink reads that file but never writes it. If it names a different provider than the one you just set as default, yoink tells you to pick <provider>/<model> in Crush with ctrl+m.
Paths
| Setting | Effect |
|---|---|
CRUSH_GLOBAL_CONFIG | folder that holds crush.json |
XDG_CONFIG_HOME | crush.json goes in $XDG_CONFIG_HOME/crush |
CRUSH_GLOBAL_DATA, XDG_DATA_HOME | where yoink looks for the state file |
| Windows, neither set | %LOCALAPPDATA%\crush |
Default and disconnect
--default merges model and provider into models.large and leaves any other keys you set there alone. yoink disconnect openrouter --from crush removes the provider block and clears models.large and models.small when either points at it. The first write keeps the original file as crush.json.yoink.bak.
FAQ
Do I need to migrate to crushrc for yoink to work?
No. Crush still reads crush.json, and that is the file yoink manages. If you have already moved to crushrc, yoink's notice is the cue to add the provider there by hand, because yoink does not write crushrc.
Why are the cost fields zero?
yoink writes every cost_per_1m_* field as 0 because it has no price list to fill them from. The provider still bills you as usual; check usage on the provider's own dashboard, or edit the numbers by hand. A hand edit to a cost field is overwritten on the next re-sync, since those fields belong to yoink.
Related
- Harnesses
What yoink writes into pi, omp, opencode, codex, Claude Code, Qwen Code, Kilo, Droid, Crush, Continue, Goose, Zed and Claude Desktop: paths and keys.
- Use OpenRouter in your coding agents
Add your OpenRouter key once and yoink writes it into Claude Code, opencode, pi, Qwen Code, Crush and 7 more. Codex is not supported: no Responses endpoint.
- Security
Atomic owner-only writes, kept symlinks, one-time backups, seven managed Claude Code keys, a git-tracked config guard, and keys passed on stdin, never argv.
- Use any provider in pi
Connect any OpenAI- or Anthropic-compatible provider to pi. yoink writes ~/.pi/agent/models.json with model limits from models.dev and sets the default.
- Use any provider in omp
Connect a provider to omp. yoink writes ~/.omp/agent/models.yml (or models.yaml), carries over a legacy models.json and sets modelRoles.default in config.yml.
- Use any provider in opencode
Connect OpenRouter, DeepSeek, Ollama or any compatible API to opencode. yoink edits opencode.json or .jsonc in place, keeping your comments and formatting.