DeepSeek TUI: The Coding Agent That Became Codewhale

DeepSeek TUI: The Coding Agent That Became Codewhale

If you have run npm install -g deepseek-tui at some point in the last year, you installed a terminal coding agent that no longer goes by that name. The project has been renamed Codewhale, and the DeepSeek-specific version — the one described here — is a snapshot of what it looked like at v0.8.11, before it opened up to every provider.

That makes this an unusual thing to write about. It is not the current release, and you should not start a new project on it. But it is a genuinely interesting document, because it shows what a coding agent looks like when it is built for one model family instead of thirty — and a few of those decisions are better than what most provider-agnostic tools manage.

The short version

  • This project is now called Codewhale. The name changed; the config and sessions carry over. Read the current release if you want something to actually install.
  • Built around one context window — DeepSeek V4's 1M tokens, with compaction that is aware of the prefix cache so it does not throw away the discount.
  • A published price table, with cache-hit and cache-miss input priced separately. Almost nobody does this.
  • RLM fan-outrlm_query dispatches 1–16 cheap flash children in parallel against the same API client.
  • Project config cannot override your credentials — a checked-in .deepseek/config.toml is forbidden from setting api_key, base_url or provider.
  • Single Rust binary, MIT licensed, no Node or Python runtime required to run it — though the recommended installer is npm, which is a wrinkle we will get to.

First, the name — and the fork problem

DeepSeek TUI is the former name of the project now published as Codewhale. The rename came with a broadening of scope: what began as a native terminal experience for DeepSeek's models became a community project that treats every provider equally and privileges none of them. The README even carried a disclaimer — not affiliated with DeepSeek Inc. — which is a reasonable thing to want to stop explaining.

There is a practical trap here. Search for deepseek-tui today and you will find plenty of forks, some of them thousands of commits behind. A fork frozen at v0.8.11 looks superficially like a real project: it has a full README, a changelog, a Cargo manifest. But GitHub shows forks with their own counters, and those counters are meaningless.

How to tell a stale fork from the real thing

A forked repository will typically show no releases published and no contributors, because both live on the upstream repo. GitHub also prints a line like "This branch is 5,656 commits behind" directly above the file list. If you see that, you are looking at a snapshot, not the project. The star and fork counts on such a page describe the fork's own popularity — usually a handful — and say nothing about the software.

The maintained project is github.com/Hmbown/CodeWhale.

If you have an existing deepseek-tui install, the migration is not a re-onboarding: config and sessions carry across to Codewhale, documented in docs/REBRAND.md. Everything below describes the older, DeepSeek-native line — accurate to that snapshot, and mostly still recognisable in the current tool.

What it actually is

DeepSeek TUI is a coding agent that lives entirely in your terminal. It gives the model direct access to your workspace: reading and editing files, running shell commands, searching the web, driving git, and dispatching sub-agents, all through a keyboard-driven interface built on ratatui.

The wiring, as the README describes it, is a two-binary arrangement:

deepseek (dispatcher CLI) → deepseek-tui (companion binary) → ratatui interface ↔ async engine ↔ OpenAI-compatible streaming client.

Tool calls route through a typed registry — shell, file operations, git, web, sub-agents, MCP, RLM — and results stream back into the transcript. The engine owns session state, turn tracking, the durable task queue, and an LSP subsystem that feeds post-edit diagnostics into the model's context before the next reasoning step, which is the detail that matters most and we will come back to.

Two binaries rather than one is worth noticing at install time, because if you install via Cargo you have to install both, and the dispatcher will not work without its companion.

Installing it, and the runtime wrinkle

The headline claim is that this is distributed as a single binary requiring no Node.js or Python runtime. That is true of the program. It is not true of the recommended install path:

node --version
npm --version

npm install -g deepseek-tui
deepseek --version
deepseek

So the binary needs no runtime, but the blessed installer is an npm global. In practice npm is being used as a cross-platform binary distributor here, which is now common — but it does mean the "no runtime required" claim describes execution, not installation. If you want to avoid Node entirely, Cargo and the prebuilt release archives both work:

cargo install deepseek-tui-cli --locked   # provides `deepseek`
cargo install deepseek-tui     --locked   # provides `deepseek-tui`
deepseek --version

Prebuilt binaries are published for Linux x64, Linux ARM64 (from v0.8.8), macOS x64, macOS ARM64 and Windows x64. Anything else — musl, riscv64, FreeBSD — means building from source. From v0.8.10 the prebuilts target a glibc 2.28 baseline via cargo zigbuild, which widens support to older distributions, and the npm postinstall fails fast with a clear "build from source" message when the host is incompatible rather than producing a binary that dies on first run.

The mirror story is unusually well handled

A noticeable amount of thought has gone into installing this from mainland China, which is not something most projects bother with. There is an npm registry mirror:

npm install -g deepseek-tui@latest --registry=https://registry.npmmirror.com

a documented Cargo source replacement pointing at the Tsinghua mirror:

# ~/.cargo/config.toml
[source.crates-io]
replace-with = "tuna"

[source.tuna]
registry = "sparse+https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/"

and a DEEPSEEK_TUI_RELEASE_BASE_URL environment variable for pointing the release downloader at mirrored assets. Localised READMEs and a UI available in English, Japanese, Simplified Chinese and Brazilian Portuguese round it out, with the locale auto-detected and separately settable from the model's language.

Getting a key in

deepseek auth set --provider deepseek   # saves to ~/.deepseek/config.toml
export DEEPSEEK_API_KEY="YOUR_KEY"      # env var alternative
deepseek doctor                         # verify setup and connectivity

On first launch you are prompted for a key and it is written to ~/.deepseek/config.toml, deliberately not the OS keychain — the stated reason being that it then works from any directory without credential prompts. That is a convenience-versus-security trade made explicitly, and it is the right call for a terminal tool, but it does mean a plaintext key sits in your home directory. Treat that file accordingly. deepseek auth clear --provider deepseek rotates or removes it.

For non-interactive shells, the README specifically suggests ~/.zshenv rather than ~/.zshrc for the env-var route, which is the kind of detail you only write down after someone files an issue about it.

Designed around one context window

This is the part that justifies building for a single model family. DeepSeek V4 offers a 1M-token context window and a prefix cache, and the agent is built around both rather than treating them as a bonus.

Long-running agent sessions have a compaction problem: eventually the transcript exceeds the window and something has to be summarised away. Naive compaction rewrites the beginning of the prompt — which is exactly the part the prefix cache was holding for you. You free up context and simultaneously destroy your cache discount, and the next turn costs many times what the previous one did.

Cache-aware compaction — compaction calls reuse cached prompt prefixes, cutting /compact costs significantly.

That is a small line in a changelog and a genuinely hard thing to get right. It is also the sort of optimisation you can only make when you know precisely which cache you are talking to — a provider-agnostic tool has to assume the worst. There is a related default worth knowing: compaction ships off by default, and the unknown-model floor was raised to 80% of context, meaning the agent waits longer before compacting a model whose true window it cannot confirm.

What it cost to run

Publishing a price table in a README is rare, and publishing cache-hit and cache-miss input prices separately is rarer still. Here is what the snapshot lists:

ModelContextInput (cache hit)Input (cache miss)Output
deepseek-v4-pro1M$0.003625 / 1M*$0.435 / 1M*$0.87 / 1M*
deepseek-v4-flash1M$0.0028 / 1M$0.14 / 1M$0.28 / 1M

The gap between the two input columns is the entire argument for prefix-cache awareness: on Pro, a cache hit is roughly 120× cheaper than a miss. If your agent silently invalidates the cache every few turns, that is not a rounding error, it is your bill.

These Pro prices have expired

The asterisked Pro rates are described as reflecting "a limited-time 75% discount, which remains valid until 15:59 UTC on 5 May 2026", after which the cost estimator reverts to base Pro rates. That date has passed. The README never publishes the base numbers, so this table no longer tells you what Pro costs.

If the discount was a straight 75% off, the base is four times the figures above — but that is arithmetic, not a quoted price, and pricing structures rarely scale that cleanly. Check the provider before you budget anything. The flash row carries no asterisk and so was presumably never discounted.

Live cost tracking is built into the TUI: per-turn and session-level token usage with cost estimates, and a cache hit/miss breakdown. Given the 120× spread, that breakdown is the number to watch, not the total.

Legacy aliases deepseek-chat and deepseek-reasoner map to deepseek-v4-flash — so old scripts do not break, but they also silently stop using the frontier model. Worth an audit if you inherited any.

rlm_query: renting sixteen cheap brains

The most distinctive feature in this release line is rlm_query, which fans out between 1 and 16 deepseek-v4-flash children in parallel for batched analysis and parallel reasoning — all against the existing API client, with no separate infrastructure.

The economics are the point. Flash input costs $0.14 per million on a cache miss against Pro's $0.435, and output is a third of the price. For work that is wide rather than deep — classify these two hundred files, check each of these modules for a pattern, summarise every migration in this directory — you do not need the frontier model sixteen times. You need it once, to decide what to ask and to interpret what comes back.

Sub-agents are not unique to this tool, but wiring the fan-out to a deliberately cheaper sibling model in the same family, sharing one client, is a tidier design than spinning up generic sub-agents at full price. Sub-agent roles and lifecycle are documented separately in docs/SUBAGENTS.md.

One caveat: the README publishes no benchmarks for this — no latency figures, no quality comparison against doing the same work in a single Pro context. The mechanism is documented; its effectiveness is not. Measure it on your own workload before you build a process around it.

Plan, Agent, YOLO — and reasoning effort

Three modes, cycled with Tab when the composer is idle:

ModeBehaviour
Plan 🔍Read-only investigation. The model explores and proposes a plan via update_plan and checklist_write before changing anything.
Agent 🤖The default. Multi-step tool use with approval gates; work is outlined through checklist_write.
YOLOAuto-approves every tool. Intended for a trusted workspace. Still maintains the plan and checklist so you can see what happened.

Running orthogonally to that, Shift+Tab cycles reasoning effort through off → high → max. Two independent axes on two adjacent shortcuts is a slightly dangerous piece of interface design — it is easy to think you have changed mode when you have changed effort — but it does mean you can dial thinking up for a hard problem without leaving the safety of Plan mode.

Thinking-mode streaming renders the model's chain of thought live as it works. This is more useful than it sounds for an agent specifically: the failure mode you care about is the model confidently heading somewhere wrong, and watching it reason gives you a chance to hit Esc before it starts editing.

The Tab key is overloaded three ways, and the README is upfront about the precedence: it completes / or @ entries first; while a turn is running it queues your draft as a follow-up; otherwise it cycles mode.

The tool surface: LSP, rollback, durable queue

The tool registry covers the expected ground — file operations, shell execution, git, web search and browse, apply-patch, sub-agents, MCP servers. Three things go beyond the usual.

LSP diagnostics fed back before the next step

After every edit, diagnostics from rust-analyzer, pyright, typescript-language-server, gopls or clangd are surfaced inline and injected into the model's context before it reasons again. This closes the most tedious loop in agentic coding, where the model writes something that does not compile and only finds out three tool calls later when it happens to run the build. Here the type checker is part of the conversation.

Workspace rollback that does not touch your git history

Side-git pre/post-turn snapshots with /restore and revert_turn, without touching your repo's .git.

Agents that snapshot by committing to your repository leave you cleaning up a branch full of machine commits. A separate git directory used purely as a checkpoint store gives you per-turn undo while leaving your actual history exactly as you left it. This is the correct design and it is not the common one.

A durable task queue

Background tasks survive restarts — the README's examples are scheduled automation and long-running reviews. Combined with deepseek serve --http, this is the difference between a chat tool and something you can build a process on.

Two smaller hardening items from v0.8.10 are worth calling out because they are the kind of thing that bites in production: shell children now get PDEATHSIG on Linux so they self-terminate when the parent exits, closing a process-leak window; and shell cwd is boundary-validated, returning PathEscape for an out-of-workspace working directory, consistent with the file tools. An agent that could cd out of the workspace while file tools refused to is exactly the sort of inconsistency that turns into an incident.

Config, and one quietly good security decision

User config lives at ~/.deepseek/config.toml, with a per-workspace overlay at <workspace>/.deepseek/config.toml. The overlay is where the good decision is:

A project cannot redirect your API key

The workspace overlay explicitly denies api_key, base_url, provider and mcp_config_path. Those four can only be set in your user config.

This matters the moment you clone someone else's repository. Without that restriction, a checked-in config file could point your agent at an attacker-controlled base_url, or attach an MCP server config of its own choosing, and the first thing it would receive is whatever your session sends. Denying credential and endpoint keys at the project layer is a small list with a large blast radius behind it.

It fits a pattern visible elsewhere in the repo — the contributor guide carries explicit "treat external input as untrusted" guidance, and earlier releases took SSRF protection in fetch_url from outside contributors. Someone is thinking about this properly.

The environment variables are conventional: DEEPSEEK_API_KEY, DEEPSEEK_BASE_URL, DEEPSEEK_MODEL, DEEPSEEK_PROVIDER, DEEPSEEK_PROFILE, and DEEPSEEK_MEMORY=on to enable the optional persistent user-memory note injected into the system prompt. Two others are easy to miss and save real time: SSL_CERT_FILE for a custom CA bundle behind a corporate proxy, and NO_ANIMATIONS=1 to force accessibility mode at startup.

Despite the name, this release already supported providers other than DeepSeek — NVIDIA NIM, Fireworks, and self-hosted SGLang:

SGLANG_BASE_URL="http://localhost:30000/v1" deepseek --provider sglang --model deepseek-v4-flash

Which tells you the rebrand was less a change of direction than an acknowledgement of one already underway.

Skills, and borrowing other tools' folders

Skills are composable instruction packs: a directory containing a SKILL.md with frontmatter.

---
name: my-skill
description: Use this when DeepSeek should follow my custom workflow.
---

# My Skill
Instructions for the agent go here.

They are managed with /skills, /skill <name>, /skill new, and /skill install github:<owner>/<repo>, plus update, uninstall and trust. Community installs come straight from GitHub with no backend service in between — no registry to go down, no account to create.

The discovery order is the interesting bit. It searches .agents/skills, then skills, then .opencode/skills, then .claude/skills, then global ~/.deepseek/skills. Reading two competing tools' directories means a repository that already carries agent instructions works here without anyone porting anything.

Installed skills appear in the model-visible session context and the agent can auto-select relevant ones through a load_skill tool when a task matches their descriptions. That makes the description field load-bearing — it is the retrieval key, not documentation. Vague descriptions mean skills that never fire.

The presence of a trust subcommand alongside install implies installed skills are not automatically trusted, which is the right default for instructions you fetched from a stranger's repository and are about to inject into a system prompt.

MCP and the HTTP/SSE runtime API

MCP support is full client-side: deepseek mcp list, deepseek mcp validate to check config and connectivity before you are mid-task, and deepseek mcp-server to run the dispatcher itself as an MCP stdio server so another agent can drive it. On shutdown, stdio servers get SIGTERM with a two-second grace period instead of an immediate SIGKILL — again, small, and again the difference between clean shutdown and orphaned processes.

The runtime API is deepseek serve --http, exposing HTTP with SSE streaming for headless workflows. The v0.8.10 additions sketch what it is for: configurable CORS origins, full thread editing via PATCH /v1/threads/{id}, an archived_only query filter, and an aggregate usage endpoint at GET /v1/usage?group_by=day|model|provider|thread.

That usage endpoint is a giveaway. Grouping spend by day, model, provider and thread is not what a single developer needs — it is what someone running this for a team needs, and it pairs with the desktop integration the release notes mention. Full reference is in docs/RUNTIME_API.md.

The rest of the CLI is broad enough to script against:

deepseek "explain this function"                 # one-shot prompt
deepseek --model deepseek-v4-flash "summarize"   # model override
deepseek --yolo                                  # auto-approve tools
deepseek doctor --json                           # machine-readable diagnostics
deepseek models                                  # list live API models
deepseek sessions                                # list saved sessions
deepseek resume --last                           # resume latest session
deepseek pr <N>                                  # fetch PR, pre-seed a review prompt

deepseek doctor --json deserves a mention: a machine-readable health check means you can gate a CI job on the agent actually being able to reach its provider, rather than discovering it in the middle of a run.

What to do with this today

Do not install deepseek-tui. Install Codewhale, which is the same project under its current name, actively released, and no longer tied to one provider. If you already have deepseek-tui, migrate — your config and sessions come with you.

What is worth taking from this snapshot is a set of questions to ask of whatever agent you do end up using:

  • Does compaction destroy your prefix cache? If the tool cannot tell you, assume it does, and watch your cache hit rate after a long session.
  • Does it show cache-hit and cache-miss costs separately? A single blended token count hides a two-order-of-magnitude difference.
  • Do type errors reach the model before its next step, or three tool calls later?
  • Where do checkpoints go? Into your .git, or somewhere you do not have to clean up?
  • Can a cloned repository change your endpoint or your key? If yes, that is a supply-chain hole, not a feature.
  • Can wide, shallow work be dispatched to a cheaper model? Not everything needs the frontier.

The last thing worth saying is about what a single-provider tool buys you, because the industry has decided provider-agnosticism is unambiguously good. Mostly it is. But every one of the sharpest features here — cache-aware compaction, a real price table, a fan-out sized to a specific cheap sibling model — depends on knowing exactly which model you are talking to. Generic tools have to assume the worst about all of them. That is a real cost, and it is usually paid quietly, on your invoice.

Frequently asked questions

Is DeepSeek TUI still maintained?

Not under that name. The project was renamed Codewhale and continues to be actively developed at github.com/Hmbown/CodeWhale. The deepseek-tui releases described here stop at v0.8.11. Any repository still showing that name is either an old fork or a mirror, not the maintained line.

How do I migrate from deepseek-tui to Codewhale?

Install Codewhale — npm install -g codewhale is the quickest route — and your existing configuration and saved sessions carry over. The migration is documented in docs/REBRAND.md in the upstream repository. You do not need to re-enter credentials or re-onboard.

Why was DeepSeek TUI renamed?

The scope changed. It began as a terminal experience built specifically for DeepSeek's models and became a community project that supports 30+ providers with none privileged over the others. The old README already carried a "not affiliated with DeepSeek Inc." disclaimer, and a provider-neutral name removes both the confusion and the need for the disclaimer.

Is a fork of CodeWhale still called DeepSeek-TUI safe to install?

It is not dangerous by default, but it is stale, and you should not build on it. A fork thousands of commits behind upstream misses every fix and hardening change made since it diverged — in this snapshot's case, that includes shell working-directory boundary validation, MCP shutdown handling and Linux process-leak fixes. Check for a "this branch is N commits behind" banner and install from the upstream repository instead.

What is rlm_query in DeepSeek TUI?

It is a native fan-out tool that dispatches between 1 and 16 cheap deepseek-v4-flash children in parallel against the same API client, for batched analysis and parallel reasoning. It suits wide, shallow work — classifying many files, checking many modules for a pattern — where paying frontier-model prices sixteen times over would be wasteful. The README publishes no benchmarks for it, so measure it on your own workload.

Are the DeepSeek V4 prices in the README still accurate?

No, not for Pro. The Pro rates were marked as reflecting a limited-time 75% discount valid until 15:59 UTC on 5 May 2026, and that date has passed. The README does not publish the undiscounted base rates, so the table no longer tells you what Pro costs. Check current pricing with the provider directly before budgeting.

What is cache-aware compaction and why does it matter?

When an agent session outgrows the context window, older turns are summarised away. Naive compaction rewrites the start of the prompt, which invalidates the provider's prefix cache. Since a cache hit can be roughly 120× cheaper than a miss on the published Pro rates, that turns a housekeeping step into a large bill. Cache-aware compaction reuses cached prefixes so freeing context does not also throw away the discount. Note that compaction is off by default in this release.

Does DeepSeek TUI require Node.js or Python?

Not to run — it is a native Rust binary with no runtime dependency. The recommended installation method is an npm global install, which does require Node, but Cargo (cargo install deepseek-tui-cli and cargo install deepseek-tui, both needed) and prebuilt release archives avoid Node entirely. Prebuilts cover Linux x64 and ARM64, macOS x64 and ARM64, and Windows x64, targeting a glibc 2.28 baseline.

Can a project I clone override my API key or endpoint?

No. The per-workspace config overlay at <workspace>/.deepseek/config.toml explicitly denies api_key, base_url, provider and mcp_config_path. Those can only be set in your own user config at ~/.deepseek/config.toml. That prevents a checked-in configuration file from redirecting your agent — and whatever it sends — to an endpoint you did not choose.

DevGlaze
DevGlaze
DevGlaze builds web applications and writes about the tools, models, and open-source releases worth...

Comments (0)

Leave a Comment