Desktop client for ccLoad — for Claude Code, Codex, Gemini, Grok Build, and OpenCode.
English | 简体中文
Point every CLI at one gateway | Local or remote | Keep your MCP | Undo a takeover | Try in a sandbox first | Force a model to a channel | Rescue a stuck session | Ships its own vision and image MCP
ccLoad already removes the operational mess of multiple AI API upstreams: routing, failover, protocol conversion, usage. What is still messy is the laptop — five coding CLIs, five “send requests here” settings. Changing gateways means pasting an address five times. Many switchers rewrite the whole file and take your MCP servers and current model with them.
ccLoad Desktop is the window that closes that gap. Start a local ccLoad, or connect to one you already run, then point the CLIs you actually use at it. You keep working in the same terminals. Channels and keys stay in ccLoad.
| Who | Anyone already using Claude Code, Codex, Gemini CLI, Grok Build, or OpenCode, who runs (or is about to run) ccLoad as the gateway. |
| What | A desktop switchboard. Not another proxy — the app that connects that gateway to those five CLIs. |
| Why | Routing, cooldown, and billing already live in ccLoad. On the machine you still edit five configs by hand, miss one, and watch a session hit the old endpoint; typical switchers overwrite the whole file. |
| When | A new CLI, a new gateway, a friend’s instance, a suspicion that one tool is still on the old URL, or a trial that must not touch the live session. |
| Where | The gateway can be this computer, a box at home, or a shared server. The CLIs stay in the terminals you already use. Installers for Windows, macOS, and Linux; one Mac build covers Intel and Apple Silicon. |
| How | Open the app → start local ccLoad or paste an existing URL → takeover the CLIs you use → keep using those CLIs as before → come back here for usage, health, and logs. |
If you keep several AI CLIs open, these are the failure modes:
- The URL has to be pasted five times. Each tool has its own endpoint. Miss one when you change gateways, and that session dies mid-turn on the old address.
- A switcher wipes the room. Whole-file replace is how MCP servers vanish and the model you were using gets swapped out.
- The wrong CLI has no undo. Without a snapshot you are left with memory, or a full-disk backup.
- You want a trial without burning the live session. Comparing two gateways should not use the real
~/.claudeas the lab. - The gateway is up, the laptop is blind. Usage, in-flight requests, and channel health still mean opening a browser and guessing.
- You paste a screenshot and the model cannot see it. A text-only model does not know it is blind — it guesses from the filename. Generating an image is worse: it never occurs to the model that it could just draw one, so it sends you off to another tool or fakes it with SVG.
- A session dies on
400 too long. Claude Code decides when to auto-compact from the window the model declares, while the ceiling that actually stops you belongs to the relay. When those two disagree, the threshold is computed against a denominator that does not exist — by the time it fires you are already past the real ceiling, and/compactcannot save you either, because it has to send the whole transcript too.
ccLoad Desktop handles those cases with:
- One takeover, only the CLIs you use. You do not open five config files.
- Add what is needed, never replace the file. MCP, custom models, and fields you typed stay. Import appends to the catalog; it does not change the model you have selected.
- A snapshot before every write. Roll back that CLI only. The first copy is never thrown away.
- A sandbox. Writes land in a side folder until you turn sandbox off.
- An overview that matches the gateway. Spend, health, live requests, logs — the same ccLoad numbers, not a second counter.
- Eyes and hands for every CLI. Two bundled MCP servers — see the next section.
- Trimming against the real ceiling. Token counts come from the usage the upstream reported, not from an estimate.
Both are compiled into the same binary as the app and dispatched by argv[1] (vision-mcp / image-mcp). Installing one writes a single command plus a few environment variables into that CLI's native MCP config — no extra runtime to download, no resident background process, and uninstalling is deleting that one entry. Requests go through the gateway you already configured, so channels, failover and billing are shared with the rest of your traffic.
Hands the image to a multimodal model and gives the text back to the model you are talking to.
| Tool | For |
|---|---|
describe_image |
Understand an image: screenshot, photo, diagram, chart |
read_image_text |
Transcribe the text verbatim. Use it for error screenshots, terminal output, logs, forms — describe_image summarises, and these need the exact words |
compare_images |
Diff two images: before/after, visual regression |
list_pasted_images |
List what was just pasted, with on-disk paths |
describe_screen |
Capture the current screen and describe it (macOS only) |
Three ways to point at an image, all accepted: path for a local file, url for a remote or data URL, and image for a paste index ("1" is [Image 1], "latest" is the newest). The index matters — a transcript often shows only the [Image 1] placeholder with no path, and without it the model's only move is asking you to save a copy and send the path back.
generate_image makes a new image from a description. edit_image changes an existing one and saves the result as a new file, leaving the original untouched; extra_paths composes several references into one.
What it handles for you:
- It picks the endpoint. Upstreams expose image generation two entirely different ways:
/v1/chat/completionswithmodalities:["image"], and/v1/images/generations. There is no consistent rule for which model wants which, and getting it wrong fails every single time — with an error phrased by the upstream ("this model is not available on this endpoint"), so nobody thinks to come back and change a dropdown in a client. The default, Auto, orders the attempts by model name and retries on the other endpoint the moment the upstream says it is the wrong one. Only wrong-endpoint errors are retried — quota, rate limits and refused prompts do not burn a second call. - The request body is written per provider. The kernel registers no cross-protocol conversion for the images family, so whatever we send arrives verbatim. xAI does not accept
sizeand wantsaspect_ratio+resolution; dall-e returns a link unless you ask for base64; gpt-image is the opposite and rejects that parameter outright. Those differences are absorbed here. - Size takes either notation. Aspect ratio (
16:9,1:1@2k) or pixels (1024x1536) — converted to a value the configured model actually accepts. - Results go to disk; the model gets a path. Returning the image itself would pour a megabyte of base64 into the transcript per picture — exactly what Session rescue exists to clean up. To check what was drawn, call
describe_imageon that path. - The extension follows the magic bytes, not the declared MIME. An upstream claiming PNG and returning JPEG is routine, and a wrong name breaks anything that dispatches on extension (bundlers, upload endpoints).
Install both from the bottom of the Model import page; each panel picks its own model and its own set of CLIs.
The sidebar is three groups: watch what is happening, then change how it runs, then touch the environment. Pages follow that order. Screenshots match the shipped light shell (sidebar groups, kernel status in the corner). Numbers are sample data.
This is the first screen: how many requests today, how many succeeded, how busy the last minute was, how much it cost. Below that: the traffic curve, per-channel health, which models are spending. Figures come from the kernel; the client only aggregates.
The top list is in-flight requests (not in history yet). The table is finished ones. Filter by model, channel, or status, or show errors only. Turn “live” off if you do not want the laptop polling the kernel; refresh by hand instead.
Plan quota windows (5-hour / weekly / monthly) and what is left, per OAuth channel. Every number comes from the kernel, which samples the upstream quota endpoint while refreshing credentials. The client does not compute quota itself: every upstream reports it differently (Codex in percent, Z.ai in limits[], xAI in cents, Cursor as Cursor-Models / Other-Models / monthly limit), the kernel already normalised it once, and normalising again would only produce a second, disagreeing answer.
"Refresh quota" really does ask the upstream, so this page does not poll — it runs when you click. API-key channels are pay-as-you-go with no plan window and are not listed here.
For a session stuck on 400 too long.
Claude Code decides when to auto-compact from the window the model declares, but through ccLoad the ceiling that actually stops you is the relay's. The classic trap is a model name carrying [1m] while the relay grants 500k: the threshold is measured against a denominator that does not exist, and by the time it fires you are past the real ceiling — after which /compact cannot get out either, because it has to send the whole transcript too.
This page strips images and over-long text out of the transcript, summarises in chunks when it has to, and keeps the last few turns verbatim, so the session can be resumed. Check a few rows and hit Rescue selected to chunk-summarise them in turn. The token count is not an estimate: every assistant record carries the usage the upstream reported, and the real context is input_tokens + cache_read + cache_creation — the only figure that matches the number in the 400. Reading input_tokens alone is off by an order of magnitude. A backup is taken before trimming.
Clear Claude Code sessions you have not touched in a while. Filter by project or last-changed, check the ones you want gone, delete them in one go. Deleted files cannot be recovered, and any rescue backups go with them. Sessions that are currently running are left alone.
Point Claude Code, Codex, Gemini CLI, Grok Build, and OpenCode at the current gateway. Already-pointed tools can be written again (to fix a half-edited file). Every write is snapshotted; “Snapshot history” in the corner rolls one CLI back. With sandbox on in Settings, this page only writes a side folder.
A table for “this kind of work uses that provider’s that model.” After you apply it, CLIs only speak tier aliases (opus / sonnet / …). Failover and cooldown stay in the kernel. Contradictory orderings are blocked instead of silently picked.
A fallback: try this, then that. Written as channels in decreasing priority so the kernel’s picker walks the whole chain. The graph is “how traffic is split”; the chain is “where it goes when something dies.”
The chain is graceful degradation; this is the opposite mindset — send it where I say. A CLI requests a model name (claude-fable-5), and the request is forced onto the channel + upstream model you pick, exactly the way ai-go / cc-switch does it, but built from the kernel's own primitives. Pick a channel, its models cascade below, tick as many as you like; the upstream is never validated, so a name you type by hand is sent all the same.
The kernel routes by priority, so a plain redirect would only share traffic with a channel already serving that alias — a force that wins half the time. On apply, the target is pushed above any enabled channel already serving that alias (verified against a live kernel: request for claude-fable-5 → landed on the Grok channel, upstream model rewritten to grok-4.5), so it is an exclusive take-over, not a 50/50 split. Multiple targets are ordered: the first is primary, the rest are backups.
Aliases your live channels can actually serve, appended to Codex / OpenCode catalogs. Claude Code has no catalog file, only a few slots: a row is written only if you pick opus / sonnet / … — otherwise it is skipped, so the model you are using is not overwritten.
The two bundled MCP panels (vision and image) live at the bottom of this page — pick a model, pick which CLIs get it.
Writes a managed block into each CLI's global instruction file (CLAUDE.md / AGENTS.md / GEMINI.md), which is loaded into the system prompt unconditionally at startup. Only the text between our own markers is replaced; not one byte outside the block is touched — ~/.claude/CLAUDE.md is usually months of your own accumulated rules, and wiping it is not reversible.
Why it is needed: installing an MCP does not mean the model will use it. All it sees is a tool name and one line of description, so whether it remembers to call it is luck — and a text-only model does not even know it is blind. A rule in the system prompt is far stronger than a tool description.
Three optional blocks: how to use the vision MCP, how to use the image MCP, and your own rules. You can also attach one line per installed third-party extension describing when to reach for it — the usage notes you hand-wrote for Claude Code usually exist only in ~/.claude/CLAUDE.md, invisible to the other four; write them once here and all five get them.
Ticking a box is not writing. Each row has its own Write / Update, and edited-but-unwritten state is called out. So is guidance written for a server that is not installed anywhere — that teaches the model to call a tool that does not exist, which it will hunt for, fail to find, and then improvise around.
Prepares an opening exchange and writes it out in each CLI's own session format, so you can pick it up with that tool's native resume. It is for freezing a repeated opening — role setup, project background, standing working agreements — instead of retyping it every time. You write the exchange; the client only lays it down in each format. Whether the model on the other end goes along with it is up to that model.
Every generated session is confined to the chosen directory by default: no file-access checks are pre-waived, so reads and writes outside it still prompt, and Codex additionally gets its working root pinned. Built-in presets are compiled into the binary — they cannot be deleted (that would take one misclick to lose), but a toggle hides them when you only want your own.
One row per MCP / Skill / Agent / Hook, with badges for which CLIs have it. Edit once, push to every CLI that has it. File formats stay native; writes are snapshotted first.
Channels, tokens, the kernel’s own logs and settings. This opens ccLoad’s stock admin in a separate window, so fields follow kernel upgrades. There is no thinner copy of those forms here.
Where the gateway lives: run one on this machine, or paste an instance you already have. Turn on sandbox CLI writes while you experiment. The page also lists Anthropic / OpenAI / Gemini entrypoints for tools that do not go through takeover.
| System | Download |
|---|---|
| macOS | .dmg / .zip (Intel and Apple Silicon in one file) |
| Windows | .exe |
| Linux | .AppImage or .deb |
macOS builds are unsigned for now: first launch is right-click the app → Open.
Turn on “sandbox CLI writes” while developing. Building from source and contributor rules: AGENTS.md.
Every build compiles in a copy of the ccLoad kernel, pinned by a single-line file at the repo root: KERNEL_VERSION. Changing kernel version is editing that line — visible in the diff, identical for CI and for your laptop. The kernel source does not live in this repository (the hard rule is that we do not modify it).
Following upstream is automatic, on two tracks. .github/workflows/kernel-sync.yml checks the newest upstream release hourly and picks the output track from what kind of release that was:
| Upstream shipped | We ship | Client version |
|---|---|---|
| A prerelease (beta) | A beta package (prerelease) | Untouched |
| A stable release | A draft release, published by hand | Patch +1, and a tag is pushed |
Two gates: the kernel is compiled before anything is committed (upstream occasionally introduces a new build prerequisite, and that should fail in the sync pipeline rather than land an unbuildable pin on main), and the stable track produces a draft — the packages are hundreds of megabytes, so a human always clicks Publish.
Settings shows the bundled kernel and the running kernel side by side, so a mismatch is visible at a glance.
















