* fix(sandbox): allow ~/.cargo/registry under macOS seatbelt (#558)
Sandboxed shell sessions on macOS were rejecting reads/writes to
~/.cargo/registry/{cache,index,src} and ~/.cargo/git, making
`cargo build`/`cargo publish` unrunnable from inside the TUI's shell tool
(hit while shipping v0.8.9).
* Resolve cargo home via `CARGO_HOME` env (cargo's own override) with a
`$HOME/.cargo` fallback. New helper `resolve_cargo_home()` is shared by
the policy generator and the param table to keep them in lockstep —
emit one without the other and `sandbox-exec` refuses to load the
profile.
* Always allow read access on `(param "CARGO_HOME")`. Grant write access
to the `registry/` and `git/` subpaths whenever the policy isn't
read-only — those directories must be mutable for `cargo` to populate
them on a cache miss.
* Skip the cargo block entirely when neither `CARGO_HOME` nor `HOME` is
set so we never reference an undefined `(param ...)`. (Practically
only fires in stripped CI containers.)
Two tests cover the policy/param sync — one with HOME set, one with
both vars cleared — using a module-local `ENV_LOCK` mutex to serialize
env mutation, mirroring the pattern landed in `main.rs` at d06eaed0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(mcp): graceful SIGTERM shutdown for stdio servers (#420)
Stdio MCP child processes were getting SIGKILL'd via tokio's
`kill_on_drop(true)` on TUI exit. The contract calls for SIGTERM so
well-behaved servers can flush pending state before dying.
Changes:
* New `async fn shutdown(&mut self)` on `McpTransport` (default no-op).
`StdioTransport` overrides it to send SIGTERM via `libc::kill` and
await child exit up to a 2-second grace window before letting drop
fire SIGKILL as the backstop. Graceful path on Unix; on Windows the
`kill_on_drop` (TerminateProcess) path remains unchanged because
there's no SIGTERM-equivalent.
* New `Drop` on `StdioTransport` sends SIGTERM as a fallback for code
paths that didn't call `shutdown` explicitly. Drop is sync, so the
signal arrives microseconds before tokio's own Child drop fires
SIGKILL, but it still gives MCP servers that handle SIGTERM idempotently
a chance to start cleanup.
* New `McpPool::shutdown_all` walks every connection, calls the async
shutdown, and clears the pool.
* The agent engine's run loop calls `shutdown_all` on `Op::Shutdown`
before the pool drops so graceful exit is the default path. Best-effort
— if the pool isn't initialized or the lock is contended, the Drop
fallback still sends SIGTERM.
Test: `stdio_transport_shutdown_terminates_child` spawns a real `cat`
child, calls `shutdown`, asserts the call returns within the grace
window, and confirms the pid is reaped (`kill(pid, 0)` returns ESRCH).
Unix-only — Windows already exercised by the kill_on_drop path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(shell): set PR_SET_PDEATHSIG on Linux to reap orphaned children (#421)
Shell-spawned children survive the TUI on abnormal exit (panic without
unwind, SIGKILL of the parent, OOM). The existing cooperative cancel
path SIGKILLs the whole process group via the cancellation token, but
that only fires when the parent gets to run its drop / cleanup code.
A crashed parent leaves children orphaned to init.
* New `install_parent_death_signal` helper called on every shell
Command setup. On Linux it adds a `pre_exec` hook that runs
`prctl(PR_SET_PDEATHSIG, SIGTERM)` immediately after fork — the
kernel then sends SIGTERM to the child the moment our process exits,
even on SIGKILL of the TUI itself.
* All three Command spawn sites in `tools/shell.rs` (one-shot, wait,
interactive) get the same hook.
* Documented the macOS / Windows gap: those platforms have no kernel
equivalent. The cooperative path still handles normal shutdown;
abnormal exit there is tracked as a watchdog follow-up per the
issue's acceptance criteria.
The pre_exec body is `unsafe`-marked because it runs in the post-fork
async-signal-safe window. The closure only calls `libc::prctl` with
stack-allocated constants; no heap, no locks. Errno is surfaced via
`std::io::Error::last_os_error` but the spawn is not aborted — losing
the safety net is strictly less bad than failing the user's command.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(subagent): interleave Chinese whale names with English in nickname pool
Sub-agent UI labels rotate through `WHALE_NICKNAMES`. The list was
English-only — every spawn produced "Blue", "Humpback", etc. Adding
Simplified-Chinese names (蓝鲸, 座头鲸, 抹香鲸, …) interleaved with the
English ones doubles the pool size and gives a roughly even mix on
each new spawn, with the same wraparound behavior at index >= 48.
Goal is friendly variety, not strict locale matching — a CN-locale user
still gets some English names and vice versa. Pure cosmetic; no
behavioral or persistence-format change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* style: cargo fmt for seatbelt cargo home block
* memory: polish help and docs (#569)
- add /memory help and clearer invalid-subcommand guidance
- register /memory in shared slash-command help
- align memory docs with current behavior and config
- add focused tests for help and discovery
* feat(onboarding): language picker step before API key (#566)
First-run users hit Welcome → API key → Trust → Tips with no obvious way
to discover that a Chinese / Japanese / Portuguese UI exists.
Issue #566 surfaced this from a Chinese user. The TUI already has full
translations for `en`, `ja`, `zh-Hans`, `pt-BR` (plus `auto` detection
from `LC_ALL` / `LANG`); the only gap was discoverability.
* New `OnboardingState::Language` variant inserted between Welcome and
ApiKey. `Welcome → Language → ApiKey/Trust/Tips` is the new flow;
`Esc` from Language returns to Welcome.
* New `tui/onboarding/language.rs` panel renders the picker with hotkeys
1-5 for `auto` / `en` / `ja` / `zh-Hans` / `pt-BR`. Each row shows the
native name (日本語, 简体中文, …) plus an English label so the user
doesn't have to read the target language to pick it. The currently
persisted setting is highlighted with a filled bullet.
* Selecting a hotkey calls the new `App::set_locale_from_onboarding`
which writes through `Settings::set("locale", …)` + `Settings::save`
and re-resolves `app.ui_locale` immediately so the rest of onboarding
renders in the chosen language. Pressing Enter keeps the current
setting (defaults to `auto`).
* `onboarding_step` now reports `1/N` … `N/N` correctly with the new
step inserted (Welcome=1, Language=2, ApiKey=3 if needed, …).
* Doesn't expand the supported-locale set — the QA-pending list in
`localization::PLANNED_QA_LOCALES` is unchanged. We only show what
ships with full coverage today.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: 20bytes <133551439+20bytes@users.noreply.github.com>
DeepSeek TUI
A terminal-native coding agent built around DeepSeek V4's 1M-token context and prefix cache. Single binary, no Node/Python runtime required — ships an MCP client, sandbox, and durable task queue out of the box.
npm i -g deepseek-tui
What is it?
DeepSeek TUI is a coding agent that runs entirely in your terminal. It gives DeepSeek's frontier models direct access to your workspace — reading and editing files, running shell commands, searching the web, managing git, and orchestrating sub-agents — all through a fast, keyboard-driven TUI.
Built for DeepSeek V4 (deepseek-v4-pro / deepseek-v4-flash) with 1M-token context windows and native thinking-mode (chain-of-thought) streaming. See the model's reasoning unfold in real time as it works through your tasks.
Key Features
- Native RLM (
rlm_querytool) — fans out 1–16 cheapdeepseek-v4-flashchildren in parallel against the existing DeepSeek client for batched analysis, decomposition, or parallel reasoning - Thinking-mode streaming — shows DeepSeek's chain-of-thought as it reasons about your code
- Full tool suite — file ops, shell execution, git, web search/browse, apply-patch, sub-agents, MCP servers
- 1M-token context — automatic intelligent compaction when context fills up
- Three interaction modes — Plan (read-only explore), Agent (interactive with approval), YOLO (auto-approved). Decomposition-first system prompts teach the model to
checklist_write,update_plan, and spawn sub-agents before acting - Reasoning-effort tiers — cycle through
off → high → maxwith Shift+Tab - Session save/resume — checkpoint and resume long sessions
- Workspace rollback — side-git pre/post-turn snapshots with
/restoreandrevert_turn, without touching your repo's.git - HTTP/SSE runtime API —
deepseek serve --httpfor headless agent workflows - MCP protocol — connect to Model Context Protocol servers for extended tooling; see docs/MCP.md
- Live cost tracking — per-turn and session-level token usage and cost estimates
- Dark theme — DeepSeek-blue palette
How it's wired
DeepSeek TUI's architecture follows a dispatcher → TUI → engine → tools pattern.
The deepseek CLI binary is a lightweight dispatcher that parses subcommands and
delegates to the deepseek-tui companion binary for interactive sessions. The TUI
runs a ratatui-based interface that communicates with an async engine executing
an agent loop: user input flows to the LLM via a streaming client (OpenAI-compatible
Chat Completions), tool calls are extracted from the response and dispatched through
a typed tool registry (shell, file ops, git, web, sub-agents, MCP), and results
stream back into the transcript.
Behind the scenes, the engine manages session state, turn tracking, and a durable
task queue. The LSP subsystem (crates/tui/src/lsp/) provides post-edit diagnostics
by spawning language servers (rust-analyzer, pyright, etc.) and injecting errors
into the model's context before the next reasoning step. A recursive language model
(RLM) subsystem gives the agent a sandboxed Python REPL for batch classification
and sub-LLM orchestration. See docs/ARCHITECTURE.md for
the full walkthrough.
Quickstart
npm install -g deepseek-tui
deepseek
Prebuilt binaries are published for Linux x64, Linux ARM64 (v0.8.8+), macOS x64, macOS ARM64, and Windows x64. For everything else — musl, riscv64, FreeBSD, etc. — see Build from source below or the full docs/INSTALL.md walkthrough.
Linux ARM64 (Raspberry Pi, Asahi, Graviton, HarmonyOS PC)
npm i -g deepseek-tui works on glibc-based ARM64 Linux from v0.8.8
onward. If you're stuck on v0.8.7 or earlier (where you'll see
Unsupported architecture: arm64), upgrade or use cargo install:
# requires Rust 1.85+ (https://rustup.rs)
cargo install deepseek-tui-cli --locked # provides `deepseek`
cargo install deepseek-tui --locked # provides `deepseek-tui`
You can also download deepseek-linux-arm64 and deepseek-tui-linux-arm64
directly from the Releases page
and drop both side by side into a directory on your PATH. Cross-compiling
from x64 to ARM64 is documented in
docs/INSTALL.md.
China / mirror-friendly install
If GitHub or npm downloads are slow from mainland China, install the Rust crates through a Cargo registry mirror:
# ~/.cargo/config.toml
[source.crates-io]
replace-with = "tuna"
[source.tuna]
registry = "sparse+https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/"
Then install the canonical deepseek dispatcher and the companion TUI binary
(both are required — the dispatcher delegates to the TUI runtime):
cargo install deepseek-tui-cli --locked # provides `deepseek`
cargo install deepseek-tui --locked # provides `deepseek-tui`
deepseek --version
You can also download prebuilt binaries directly from the
GitHub Releases page when
GitHub release assets are reachable. TUNA, rsproxy, Tencent COS, or Aliyun OSS
mirrors can also be used with DEEPSEEK_TUI_RELEASE_BASE_URL when a mirrored
release-asset directory is available.
On first launch you'll be prompted for your DeepSeek API key. The TUI saves it to your user config at ~/.deepseek/config.toml so it works from every folder without OS credential prompts.
You can also set it ahead of time:
# Recommended — saves to ~/.deepseek/config.toml; works everywhere
# (interactive shells, IDE terminals, scripts, cron):
deepseek auth set --provider deepseek
# Env var alternative — note that on zsh, exports in ~/.zshrc only
# reach interactive shells. Put it in ~/.zshenv if you want it in
# every context (login shells, IDEs, scripts):
export DEEPSEEK_API_KEY="YOUR_DEEPSEEK_API_KEY"
deepseek
# Verify which source the binary is reading:
deepseek doctor
To rotate or remove a saved key, run
deepseek auth clear --provider deepseek(ordeepseek logoutfor the legacy alias), then rundeepseek auth set --provider deepseekagain.
Using NVIDIA NIM
deepseek auth set --provider nvidia-nim --api-key "YOUR_NVIDIA_API_KEY"
deepseek --provider nvidia-nim
# or per-process:
DEEPSEEK_PROVIDER=nvidia-nim NVIDIA_API_KEY="..." deepseek
Other DeepSeek V4 providers
deepseek auth set --provider fireworks --api-key "YOUR_FIREWORKS_API_KEY"
deepseek --provider fireworks --model deepseek-v4-pro
# SGLang is self-hosted; auth is optional for localhost deployments.
SGLANG_BASE_URL="http://localhost:30000/v1" deepseek --provider sglang --model deepseek-v4-flash
Install from source
Works on any Tier-1 Rust target — including Linux musl/riscv64, FreeBSD, and ARM64 distros that pre-date our prebuilt binaries.
# Linux build deps (Debian/Ubuntu/openEuler/Kylin):
# sudo apt-get install -y build-essential pkg-config libdbus-1-dev
# # RHEL family: sudo dnf install -y gcc make pkgconf-pkg-config dbus-devel
git clone https://github.com/Hmbown/DeepSeek-TUI.git
cd DeepSeek-TUI
cargo install --path crates/cli --locked # requires Rust 1.85+; provides `deepseek`
cargo install --path crates/tui --locked # provides `deepseek-tui`
Both binaries are required — the deepseek dispatcher delegates to
deepseek-tui at runtime. Cross-compilation, mirror, and platform-specific
notes live in docs/INSTALL.md.
What's new in v0.8.8
A stabilization-focused release: a thick band of UX polish on top of the v0.8.6 / v0.8.7 base, plus runtime fixes for the rough edges that surfaced in production sessions. No model or API changes; every existing config and session keeps working.
🪟 TUI polish
- Visual retry / backoff banner when the upstream rate-limits or 5xxs, with a per-second countdown so a stalled session is obviously stalled instead of silently frozen (#499).
- MCP health chip in the footer — a coloured
MCP n/nglyph reflects how many configured servers are actually reachable, hidden when no servers are configured (#502). - Tool-output spillover routes full bodies to
~/.deepseek/tool_outputs/<id>.txtwith a 32 KiB head visible in the cell; the existing details pager appends the full output so nothing is hidden, just paged (#500). - Multi-day duration formatting —
humanize_durationwalkss → m → h → d → wand caps at two units, so a long-running session reads2d 3hinstead of188415s(#447). - Cumulative
worked Nh Mmfooter chip appears once a session crosses 60s, dropping first under narrow widths so it never shoves more important chips off-screen (#448). - OSC 8 hyperlinks — URLs in the transcript are Cmd+click-openable on iTerm2, Terminal.app, Ghostty, Kitty, WezTerm, Alacritty, and modern gnome-terminal/konsole; legacy terminals just show the visible text (#498).
- Inline diff rendering for
edit_fileandwrite_file— tool results emit a unified diff at the head of the body, picked up by the diff-aware renderer with line numbers and coloured+/-gutters (#505). - Composer prompt stash — Ctrl+S parks the current draft to
~/.deepseek/composer_stash.jsonl,/stash listshows parked drafts,/stash poprestores LIFO,/stash clearwipes the file. Self-healing JSONL parser, 200-entry cap, multi-line drafts preserved (#440). - Slash-menu layout no longer jitters the chat area as the matched-entry count changes mid-typing — reported on Windows 10 PowerShell + WSL where the per-cell write cost made the redraw visibly laggy. The composer now reserves its panel-max envelope for the whole slash/mention session.
♿ Accessibility
NO_ANIMATIONS=1env var (also1/true/yes/on) forceslow_motion = trueandfancy_animations = falseat startup regardless of saved settings; newdocs/ACCESSIBILITY.mddocuments every motion / output knob (#450).- Keyboard-enhancement flags pop on every shutdown path including panic, Ctrl+Z suspend, and external-editor invocation, so a crashed TUI never leaves your terminal in raw mode (#443/#444).
- Kitty keyboard protocol (
DISAMBIGUATE_ESCAPE_CODES) pushed at startup so kitty-protocol terminals report unambiguous events for Option/Alt-modified keys; legacy terminals are unaffected (#442).
🤖 Agents / sub-agents
- Sub-agent cap raised 5 → 10 (configurable via
[subagents].max_concurrent, hard ceiling 20). Completed agents no longer count against the running cap (#509). - Multi-agent fan-out UI freeze fixed —
SharedSubAgentManageris nowArc<RwLock<…>>; read paths take read locks instead of contending on aMutex(#510). - Sub-agent output summarized before being folded into the parent's context, so a child returning 100KB of evidence doesn't wreck the parent's window (#511).
Implementer+Verifiersub-agent roles wired intoagent_spawn/agent_assignschemas so the model surfaces them by name (#404).agent_listdefaults to current-session view — prior sessions filtered out unlessinclude_archived=true(#405).- Compact
agent_spawnrendering in live mode collapses to a single header line; transcript replay keeps the full block (#409). agent_swarm/spawn_agents_on_csv//swarmremoved in v0.8.5 — confirmed gone in this release; multi-child fanout is no longer a model-callable tool.
🛠️ Workflows / extensibility
load_skillmodel-callable tool — takes a skill id, returns the SKILL.md body plus sibling companion-file list in one call. Available in Plan and Agent / Yolo modes (#434).- Cross-tool skill discovery — skills catalogue and
load_skillwalk.agents/skills,skills,.opencode/skills,.claude/skills, and~/.deepseek/skillswith first-wins precedence (#432). /hooksread-only lifecycle hook listing groups configured hooks by event with name / command preview / timeout / condition. Notes the global[hooks].enabledstate./hooks eventslists every supportedHookEventvalue (#460).- Every
HookEventnow has a live producer —tool_call_before/tool_call_after/message_submit/on_errorfire from the runtime in addition to the existing session-lifecycle and mode-change events. Hooks remain read-only observers in v0.8.8 (#455). instructions = [...]config array lets you stack additional system-prompt files; paths capped at 100 KiB each, project array replaces user array wholesale (#454).deepseek pr <N>subcommand fetches a PR's title / body / diff viaghand launches the TUI with a review prompt already in the composer. Codepoint-safe diff cap at 200 KiB; optional--repo/--checkout(#451).- User-memory MVP (opt-in) —
~/.deepseek/memory.mdinjected into the system prompt as a<user_memory>block;# footyped in the composer appends a timestamped bullet without firing a turn;/memory [show|path|clear|edit|help]for inspection. Default off; enable with[memory] enabled = trueorDEEPSEEK_MEMORY=on. See docs/MEMORY.md for the full guide and examples (#489–#493).
🔒 Security
- Project-config keys denied at workspace scope — a malicious
./.deepseek/config.tomlcan no longer overrideapi_key,base_url,provider, ormcp_config_path. The loosest values (approval_policy = "auto",sandbox_mode = "danger-full-access") are also denied at project scope (#417). SSL_CERT_FILEhonoured in the HTTPS client so corporate-CA / MITM-proxy users can connect — PEM bundle and DER fallback; failures log a warning and continue (#418).- Execpolicy heredoc parsing —
normalize_commandstrips heredoc bodies before shlex tokenization soauto_allow = ["cat > file.txt"]matches the heredoc formcat <<EOF > file.txt\nbody\nEOF. Recognises<<DELIM/<<-DELIM/<<'DELIM'/<<"DELIM"; leaves<<<(here-string) untouched (#419). Don't auto-approve git -C ...runtime fix shipped on v0.8.7 main (#416) — included for completeness.
📦 Packaging
- Linux ARM64 prebuilts added to the release matrix; npm wrapper picks the right binary on
aarch64-linuxautomatically. Newdocs/INSTALL.mdcovers every install path (npm, cargo, prebuilt, source). deepseek updatefixed — the v0.8.7 self-updater used Rust ARCH constants (aarch64/x86_64) instead of release-asset naming (arm64/x64), so the command failed on every platform. Now maps correctly and rejects.sha256siblings as primary binaries (#503).- CI workflow cleanup — pruned three duplicated/dead workflows;
release.ymlbuildjob now allows theparitygate to be skipped on manualworkflow_dispatch(#507).
🐛 Bug fixes
- Composer Option+Backspace deletes by word now (#488).
- Offline composer queue is session-scoped — legacy unscoped queues fail closed instead of leaking content into unrelated chats (#487).
display_pathtest race + Windows separator — tests no longer mutate$HOME; home-relative suffix joins withMAIN_SEPARATOR_STRso Windows shows~\projects\foo(#506).- Footer reads statusline colours from
app.ui_theme(#449).
🔑 Auth & onboarding
- No automatic OS credential prompts — startup,
doctor,doctor --json, and normal dispatcher setup now use CLI flag →~/.deepseek/config.toml→ env. - One setup command works everywhere —
deepseek auth set --provider deepseekand the in-TUI onboarding screen both write the shared user config file, so the key is available from any folder without relying on~/.zshrcpropagation. - Onboarding screen wording rewritten — "Step 1: open https://platform.deepseek.com/api_keys" / "Step 2: paste below and press Enter" with an explicit note showing where the key is saved.
- Missing-key error is now actionable — the
DeepSeek API key not foundbail message lists the config-backed CLI command first and the env-var alternative second, with a~/.zshrcvs~/.zshenvnote for zsh users whose env var only reaches interactive shells. - Dispatcher provider/auth parity — the canonical
deepseekentry point now accepts the same DeepSeek V4 providers advertised by the TUI (fireworks,sglangincluded), and legacydeepseek login --api-key/deepseek logoutnow share the same config-backed path.
Full changelog: CHANGELOG.md.
What's new in v0.8.7
Quick patch on top of v0.8.6 to unblock copy/select.
✂️ Selection works across the whole transcript
The selection-tightening from v0.8.6 restricted copy/select to user and assistant message bodies, which made it impossible to copy text out of system notes, thinking blocks, or tool output. v0.8.7 drops that gate so the rendered transcript block is selectable end-to-end again.
Known issues in v0.8.7 (fixed in v0.8.8):
deepseek updatefails withno asset found for platform …because the platform-string mapping in the self-updater usesaarch64/x86_64instead of the release artifact'sarm64/x64(#503).npm i -g deepseek-tuiexits withUnsupported architecture: arm64 on platform linuxon ARM64 Linux because v0.8.7 didn't publish adeepseek-linux-arm64asset.Until v0.8.8 ships, install via:
# x64 Linux / macOS / Windows npm i -g deepseek-tui # ARM64 Linux (HarmonyOS, openEuler, Asahi, Raspberry Pi, Graviton, …) — # build from source with Cargo (Rust 1.85+): cargo install deepseek-tui-cli --locked # provides `deepseek` cargo install deepseek-tui --locked # provides `deepseek-tui`
Full changelog: CHANGELOG.md.
What's new in v0.8.6
📝 AGENTS.md bootstrap (/init)
/init walks the workspace, auto-detects the project type (Cargo.toml,
package.json, pyproject.toml, etc.), and writes a starter AGENTS.md with
build/test commands, workspace layout, and conventions derived from git log.
Re-running shows a diff of the proposed update without overwriting changes.
🔍 Inline LSP diagnostics
After every apply_patch/edit_file/write_file, the engine sends a
textDocument/didChange to the LSP server and surfaces errors/warnings
inline in the tool result. Configurable via /lsp on|off and the
[lsp] config section. Currently supports rust-analyzer, pyright,
typescript-language-server, gopls, and clangd.
🔄 Self-update (deepseek update)
deepseek update fetches the latest GitHub release, downloads the
platform-correct binary with SHA256 verification, and atomically replaces
the running binary. No more remembering cargo install or npm install -g.
🌐 Session sharing (/share)
/share exports the current session as a static HTML page and uploads it
to a GitHub Gist via the gh CLI, producing a clickable URL you can paste
anywhere.
📖 Docs refresh
README hero updated with intent statement and architecture summary. ARCHITECTURE.md cleaned up for v0.8.6 (removed swarm tool surface, current crate map). CONTRIBUTING.md now has a "shape of a PR" section.
Full changelog: CHANGELOG.md.
What's new in v0.8.5
🛡️ SSRF protection for fetch_url
fetch_url now validates target hostnames and IPs before connecting —
localhost-only HTTP for loopback, DNS pinning for remote hosts, and
blocked internal IP ranges. Contributed by Hafeez Pizofreude (#261)
and Jason.
🖥️ Schema-driven config editor
/config tui opens a forms-style config editor powered by schemaui.
Bare /config opens the legacy native modal; /config web launches a
browser surface (requires the web feature). Contributed by Unic
(YuniqueUnic) via #365.
🏷️ DeepseekCN provider
ApiProvider::DeepseekCN targets api.deepseeki.com for China-based
users. Auto-detects when zh-* is the system locale on first run.
🔐 Atomic file writes
All writes to ~/.deepseek/ now go through write_atomic (tempfile +
fsync + rename), preventing corruption from mid-write crashes.
🧵 Panic safety foundations
spawn_supervised catches and logs task panics with crash dumps instead
of silently dropping the task.
⌨️ /config <key> <value> wiring
/config model deepseek-v4-flash, /config locale zh-Hans, etc. change
settings live in-session without opening the editor.
Full changelog: CHANGELOG.md.
Thanks
v0.8.5 shipped with help from these contributors:
- Hafeez Pizofreude — SSRF protection in
fetch_urland Star History chart - Unic (YuniqueUnic) — Schema-driven config UI (TUI + web)
- Jason — SSRF security hardening
What's new in v0.8.0
⚡ Shell stability and post-send responsiveness
Completed background shell jobs now release their live process and pipe
handles as soon as completion is observed, while keeping the job record
inspectable. This prevents long-running sessions from hitting Too many open files (os error 24), which could make checkpoint saves fail and
cause shell spawning, message send, close, and Esc/cancel paths to lag
or fail.
🪟 Windows REPL runtime CI hardening
Windows gets a longer Python bootstrap readiness timeout for the REPL runtime tests, matching GitHub runner startup contention without weakening bootstrap failures on other platforms.
🌏 Cargo mirror install docs
The README now includes a TUNA Cargo mirror setup and direct release asset guidance for users with slow GitHub/npm access.
🧪 Test hardening
New regression coverage proves completed background shell jobs drop
their live process handles after exec_shell_wait.
Full changelog: CHANGELOG.md.
What's new in v0.7.8
⚡ Shell controls: foreground-to-background detach + exec_shell_cancel
A running foreground command can now be moved to the background interactive
session — press Ctrl+B while a command is executing to open shell
controls, then either detach it (it continues running and can be polled
with exec_shell_wait) or cancel the current turn.
New tool: exec_shell_cancel — cancel a specific background shell
task by task_id, or cancel all running background tasks with all: true.
Cancel-aware exec_shell_wait — canceling a turn while
exec_shell_wait is blocking now stops the wait but leaves the background
task running.
🐛 Unicode glob search fix
Filenames containing multi-byte characters (e.g., dialogue_line__冰糖.mp3)
no longer panic the matches_glob function — byte-index slicing was replaced
with char_indices() boundary-safe iteration.
🔄 Fanout UI reconciliation
The fanout card no longer pre-seeds with zero-state workers, eliminating the "0 done · 0 running · 0 failed · N pending" vs sidebar "N running" contradiction. The sidebar now shows "dispatching N" before the first progress event arrives from a legacy fanout invocation.
Full changelog: CHANGELOG.md.
What's new in v0.7.6
🌐 UI Localization
DeepSeek TUI now speaks your language. The new locale setting
in settings.toml controls UI chrome — composer, history search,
/config, help overlay, and status hints — without changing model
output language.
| Setting | Display |
|---|---|
locale = \"auto\" |
Checks LC_ALL → LC_MESSAGES → LANG (default) |
locale = \"ja\" |
Japanese |
locale = \"zh-Hans\" |
Chinese Simplified |
locale = \"pt-BR\" |
Portuguese (Brazil) |
locale = \"en\" |
English fallback |
Unsure what to pick? Run locale in your terminal; the first matching
tag is used automatically.
📋 Smarter paste handling
Paste-burst detection catches rapid-key pastes in terminals that don't
send bracketed-paste events — CRLF is normalized, and multiline pastes
stay buffered until you stop typing. Configurable via paste_burst_detection.
🔍 Composer history search
Forgot that prompt you wrote an hour ago? Alt+R opens a live search
across input history and recovered drafts. Type to filter, Enter to
accept, Esc to restore what you were typing.
👁️ Pending input preview
During a running turn, queued messages, pending steers, and context chips
appear above the composer so you can see what will be sent next.
Alt+↑ pops the last queued message back for editing.
⚙️ Grouped /config editor
/config now groups settings by section (Model, Permissions, Display,
...) with a live filter. ↑/↓ (or j/k when the filter is empty)
navigate; Enter/e edit the selected row; Esc clears the filter
or closes.
⌨️ Searchable help overlay
? (with empty input), F1, or Ctrl+/ opens a searchable help
overlay. Type to filter commands and keybindings; multi-term searches
act as AND.
Full history: CHANGELOG.md.
Models & Pricing
DeepSeek TUI targets DeepSeek V4 models with 1M-token context windows by default.
| Model | Context | Input (cache hit) | Input (cache miss) | Output |
|---|---|---|---|---|
deepseek-v4-pro |
1M | $0.003625 / 1M* | $0.435 / 1M* | $0.87 / 1M* |
deepseek-v4-flash |
1M | $0.0028 / 1M | $0.14 / 1M | $0.28 / 1M |
Legacy aliases deepseek-chat and deepseek-reasoner silently map to deepseek-v4-flash.
NVIDIA NIM hosted variants (deepseek-ai/deepseek-v4-pro, deepseek-ai/deepseek-v4-flash) use your NVIDIA account terms — no DeepSeek platform billing.
*DeepSeek lists the Pro rates above as a limited-time 75% discount valid until 2026-05-05 15:59 UTC; the TUI cost estimator falls back to base Pro rates after that timestamp.
Usage
deepseek # interactive TUI
deepseek "explain this function" # one-shot prompt
deepseek --model deepseek-v4-flash "summarize" # model override
deepseek --yolo # YOLO mode (auto-approve tools)
deepseek auth set --provider deepseek # save API key to ~/.deepseek/config.toml
deepseek doctor # check setup & connectivity
deepseek doctor --json # machine-readable diagnostics
deepseek setup --status # read-only setup status
deepseek setup --tools --plugins # scaffold local tool/plugin dirs
deepseek models # list live API models
deepseek sessions # list saved sessions
deepseek resume --last # resume latest session
deepseek serve --http # HTTP/SSE API server
deepseek mcp list # list configured MCP servers
deepseek mcp validate # validate MCP config/connectivity
deepseek mcp-server # run dispatcher MCP stdio server
Keyboard shortcuts
| Key | Action |
|---|---|
Tab |
Complete / or @ entries; while a turn is running, queue the draft as a follow-up; otherwise cycle mode |
Shift+Tab |
Cycle reasoning-effort: off → high → max |
F1 |
Help |
Esc |
Back / dismiss |
Ctrl+K |
Command palette |
Ctrl+R |
Resume an earlier session |
Alt+R |
Search prompt history and recover cleared drafts |
@path |
Attach file/directory context in composer |
↑ (at composer start) |
Select attachment row for removal |
Alt+↑ |
Edit last queued message |
/attach <path> |
Attach image/video media references; select the row with ↑ at composer start and remove with Backspace/Delete |
Modes
| Mode | Behavior |
|---|---|
| Plan 🔍 | Read-only investigation — model explores and proposes a decomposition plan (update_plan + checklist_write) before making changes |
| Agent 🤖 | Default interactive mode — multi-step tool use with approval gates; model outlines work via checklist_write before requesting writes |
| YOLO ⚡ | Auto-approve all tools in a trusted workspace; model still creates checklist_write/update_plan to keep work visible and trackable |
Configuration
~/.deepseek/config.toml — see config.example.toml for every option.
Key environment overrides:
| Variable | Purpose |
|---|---|
DEEPSEEK_API_KEY |
API key |
DEEPSEEK_BASE_URL |
API base URL |
DEEPSEEK_MODEL |
Default model |
DEEPSEEK_PROVIDER |
Provider: deepseek (default), nvidia-nim, fireworks, or sglang |
DEEPSEEK_PROFILE |
Config profile name |
NVIDIA_API_KEY |
NVIDIA NIM API key |
FIREWORKS_API_KEY |
Fireworks AI API key |
SGLANG_BASE_URL |
Self-hosted SGLang endpoint |
SGLANG_API_KEY |
Optional SGLang bearer token |
Quick diagnostics: deepseek setup --status checks API key, MCP, sandbox, and
.env state without network calls; deepseek doctor --json is suitable for CI;
deepseek setup --tools --plugins scaffolds local tool and plugin directories.
DeepSeek context caching is automatic — when the API returns cache hit/miss token fields, the TUI includes them in usage and cost tracking.
Full reference: docs/CONFIGURATION.md and docs/MCP.md.
UI locale is separate from model language — set locale in settings.toml
or via the LC_ALL/LANG environment variables. See docs/CONFIGURATION.md.
Publishing your own skill
DeepSeek-TUI discovers skills from the active skills directory. Workspace-local
.agents/skills wins when present, then ./skills, then the configured global
directory (~/.deepseek/skills by default). Each skill is a directory with a
SKILL.md file:
~/.deepseek/skills/my-skill/
└── SKILL.md
SKILL.md must start with YAML frontmatter:
---
name: my-skill
description: Use this when DeepSeek should follow my custom workflow.
---
# My Skill
Instructions for the agent go here.
Run /skills to list discovered skills, /skill <name> to activate one for
the next message, or /skill new to use the bundled skill-creator helper.
Installed skills are also listed in the model-visible session context so the
agent can choose relevant skills when the user names them or when the task
matches their descriptions.
DeepSeek-TUI can also install community skills directly from a GitHub repo, with no backend service in the loop:
- Create a public GitHub repo with a
SKILL.mdat the root containing the usual---frontmatter (name,description). - Multi-skill bundles use
skills/<name>/SKILL.mdinstead — the installer picks the first match and names the install after the frontmattername. - Push to
main(ormaster); the installer fetchesarchive/refs/heads/main.tar.gzand falls back tomaster.tar.gz. - Users install via
/skill install github:<owner>/<repo>— installs are gated by the[network]policy, validated for path traversal and size, and placed under~/.deepseek/skills/<name>/. - Submit a PR to the curated
index.json(default registry) to make the skill installable by name (/skill install <name>) instead of the GitHub spec. - Use
/skill update <name>,/skill uninstall <name>, or/skill trust <name>for installed community skills. Trust is only needed when you want scripts bundled with a skill to be eligible for execution.
Documentation
| Doc | Topic |
|---|---|
| ARCHITECTURE.md | Codebase internals |
| CONFIGURATION.md | Full config reference |
| MODES.md | Plan / Agent / YOLO modes |
| MCP.md | Model Context Protocol integration |
| RUNTIME_API.md | HTTP/SSE API server |
| RELEASE_RUNBOOK.md | Release process |
| OPERATIONS_RUNBOOK.md | Ops & recovery |
Contributing
See CONTRIBUTING.md. Pull requests welcome!
Not affiliated with DeepSeek Inc.
