Installation : /plugin install tqdm-claude --marketplace ExtReMLapin/tqdm-claude
Live progress bars inside Claude Code for background tasks and subagents. A Claude Code mod (a plugin built on the function-hooks API) that draws tqdm-style bars above the prompt for every background shell task. It reads the task's own output (tqdm, cargo, git, Keras, ffmpeg and more, or a one-line protocol) and shows crashes, stalls and silent failures the moment they happen.
Named after and inspired by tqdm; not affiliated with it.
Origin of the name : "T'attends quoi ? Dépèches-toi, merde." (they will deny it but it is what is it)
…and a summary at the end of the hint line under the prompt, beside Claude
Code's own task pills: esc to interrupt ⠹ Train model 40% · ✗ Index docs.
Claude Code runs long jobs in the background and gets a notification when they end. Until then you see nothing: no progress, no ETA. And when a script dies mid-way, or a regex in a watcher never matches, nothing says so. tqdm-claude makes every background task visible and makes failure loud.
- Real progress, read from the task's output: tqdm (with or without a total, scaled units, postfix metrics, nested bars), cargo, ninja, CMake, git, Keras, docker buildx, ffmpeg (a real percentage from its duration), rsync, wget, curl, pnpm, apt, pip, robocopy, rclone, aws s3, git lfs, yt-dlp, HandBrake, pv, 7-Zip, dd, dask, Spark, XGBoost, LightGBM, webpack, Bazel, terraform, kubectl, and test runners with passes and failures in two colors: pytest, jest, vitest, go test, cargo test, dotnet test. Each checked against the tool's real output. OSC 9;4 and bare percentages too. See PROTOCOL.md.
- Two levels: a main bar and a sub-bar (step 3/7, then 1840/2400 within it).
- A one-line protocol for scripts:
##progress step=3/7 label="Train" sub=1840/2400. Claude is told about it, so the scripts it writes report progress. - Indeterminate tasks animate: a sweeping bar and the latest log line.
- Failures stay:
✗, the exit code and the error line (Python exceptions,command not found...), until you dismiss them. Exit 0 short of the total is flagged too:! (!) 45/100. - Stalls are flagged:
! no output for 02:10. Silence at start gets a hint: output is probably buffered (python -u). - ETA from tqdm's own smoothed estimate, else from the pace since progress started (start-up left out).
- Subagents from the tasks list, with elapsed time and how they ended.
- Notifications through your own channel when a task fails or ends early (or, if you like, when a long one succeeds), so you can look away.
- A stuck turn is called out: no tool call for 3 minutes.
- Outcomes in two colors:
##progress ok=30 fail=10splits the bar. - The spinner follows the pace: faster when a task speeds up, slow when it stands still (after alive-progress).
- Plays well with other mods: the band is drawn above theirs, the footer
summary is added after theirs; a task ends on its notification, on
TaskStop, or when the session stops listing it at a turn's end. - Foreground commands too: past 3 s, a foreground command gets its bar, read from the output file Claude Code writes as it runs.
- Works everywhere Claude Code does: Windows, macOS, Linux, terminal and desktop. Glyphs follow tqdm's lead: Unicode eighth-blocks by default, ASCII where the locale is not UTF-8, and a code-page-437 set for fonts that lack the others.
At the Claude Code prompt:
/plugin install tqdm-claude --marketplace ExtReMLapin/tqdm-claude
From a shell: claude plugin install tqdm-claude --marketplace ExtReMLapin/tqdm-claude.
In the desktop app: + next to the prompt → Plugins → Add marketplace
ExtReMLapin/tqdm-claude → Add plugin.
The mod is active at once; start a long command in the background to see it.
To get new versions without thinking about it, turn on auto-update for this
marketplace: /plugin → Marketplaces → tqdm-claude → Enable
auto-update (it is off by default for marketplaces other than Anthropic's).
Otherwise, update by hand with claude plugin update tqdm-claude@tqdm-claude
and restart Claude Code.
In /config (or pluginConfigs in settings):
| Option | Default | |
|---|---|---|
charset |
auto |
unicode, blocks (code page 437, if your font shows boxes), or ascii. |
footer |
mode |
Where the line under the prompt sums up tasks: mode (a label at its right, never cut), tail (after Claude Code's task pills), both, off. |
agents |
true |
Follow subagents too. |
notify |
failures |
Native notification when a task fails or ends early; always adds stops and successes of a minute or more; off. |
stuck |
true |
Warn when a turn has had no tool call for 3 minutes: Claude may be stuck. |
/tqdm: lists followed tasks with their status and output file./tqdm clear: drops finished and failed tasks from the band.
Print ##progress lines, unbuffered. The spec, with Python, Bash, PowerShell
and Node helpers, is in PROTOCOL.md. The mod adds a short note
on it to Claude's system prompt and ships the progress-protocol skill, which
says the same where organization policy keeps plugins out of the system prompt.
| Hook | What it does |
|---|---|
tool.call (Bash, PowerShell) |
Notes each background task's id and output file; times foreground calls. |
tool.call (TaskStop, every tool) |
Ends a stopped task; times tool calls for the stuck-turn warning. |
session.append |
Reads <task-notification> rows: how a task ended, with its exit code. |
classic.Stop |
At a turn's end, ends tasks the session no longer lists. |
prompt.submit, turn.complete |
Whether a turn is running. |
classic.SessionStart |
The session's id and folder, to find its tasks folder. |
ui.render SessionMode |
The footer label, after Claude Code's own mode labels. |
$.ui.notify |
Tells you of a failure through your notification channel. |
$.clock.every |
Reads changed output files once a second; animates at ~4 fps while something runs. |
$.agent.list() |
Mirrors the tasks list's subagents. |
ui.render AbovePrompt |
Draws the band. |
ui.render PromptHint |
Adds the summary after Claude Code's own hint line. |
prompt.compose |
Tells Claude about the protocol and unbuffered output. |
It never runs your tasks, never writes to their output, and never emits OSC 9;4 itself (Claude Code drives the terminal's own progress indicator).
Nothing leaves your machine. The mod makes no network request (no
$.http), starts no process (no $.process) and writes no file.
What it reads:
- Task output files (
$.fs.stat,$.fs.read,$.fs.list): the output files Claude Code writes in the session's tasks folder: the one it names when a background Bash or PowerShell task starts (Output is being written to: …), and, for a foreground command, the newb????????.outputfile that appears there when it starts. The last 64 KiB of each, to draw the bars. To find that folder before a background task names it, the mod lists the temporary folder for Claude Code's own (claude…/<project>/<session>/tasks). No other file. - Conversation rows (
session.append): only rows holding a<task-notification>, for a task's id, status and exit code. Other rows pass through untouched and unread. - Prompts (
prompt.submit): only the moment a turn starts, for the stuck-turn warning. The prompt's text is not read, kept or changed. - Tool calls (
tool.call): a Bash or PowerShell call'sdescription,command(its first line, as the title when there is no description) andrun_in_background, and the task id in its result;TaskStop's task id; the start and end of every call, for the stuck-turn warning. Every call goes on unchanged. - The tasks list (
$.agent.list,classic.Stop): subagents' description and status, and the ids of background tasks still running at a turn's end. - Six environment variables:
LC_ALL,LC_CTYPE,LANG, to pick ASCII bars where the locale is not UTF-8;TMPDIR,TEMP,TMP, to find the tasks folder.
What it sends, and where:
$.ui.notify: when a task fails or ends early (or, withnotify=always, when a long one ends), a native notification with the task's title, its exit code and its last error line. It goes to your own notification channel, the one Claude Code uses for its own notifications (your terminal's notification, or its bell), on this machine. Turn it off withnotify=off.
What it changes:
- The system prompt (
prompt.compose): adds one section,tqdm-claude:protocol, telling Claude to run long commands in the background, to keep their output unbuffered and to print##progresslines. Nothing else in the prompt is read or changed. It is not added under--bare. - The screen (
ui.render): draws the band above the prompt, above any other plugin's band, and adds a summary after the hint line under the prompt, after any other plugin's. - Commands (
command.register,command.run): adds/tqdmand answers only it; other commands pass through untouched.
The settings of the mod (its charset, footer, agents, notify, stuck
options) are Claude Code's own; the tasks it follows live in Claude Code's
session state and are gone when the session ends.
- Only the last 64 KiB of an output is parsed; past 4 MiB the band shows a sweeping bar and says the log is too large.
- Progress hidden by a tool when its output is not a terminal can't be read: see the "to get progress in a log" column in PROTOCOL.md.
- Built on Claude Code's early-access function-hooks API, which may change between releases. Needs Claude Code 2.1.302 or later (tested on 2.1.302).
- Where an organization manages Claude Code, hooks on
prompt.composeandclassic.Stoprun only for plugins it lists: there, Claude learns the protocol from the bundled skill instead, and a task ends on its notification orTaskStoponly.
claude plugin validate .
claude plugin test . # 209 tests: parser (on real output of 30+ tools), rendering, charsets, signals, the band end to endclaude --plugin-dir . runs a session with the mod loaded from this folder.
scenarios/ holds scripts that exercise every case in a
real session (tqdm single and nested, crash, stall, plain logs, sequential
bars, huge output, other tools...). tests/fixtures/real-tqdm.ts is genuine
tqdm output, regenerated with python scenarios/capture_real_tqdm.py.