console-rs/indicatif
A command line progress reporting library for Rust
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2d ago
- ✓25+ active contributors
- ✓Distributed ownership (top contributor 29% of recent commits)
Show all 6 evidence items →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/console-rs/indicatif)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/console-rs/indicatif on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: console-rs/indicatif
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/console-rs/indicatif shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 2d ago
- 25+ active contributors
- Distributed ownership (top contributor 29% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live console-rs/indicatif
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/console-rs/indicatif.
What it runs against: a local clone of console-rs/indicatif — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in console-rs/indicatif | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of console-rs/indicatif. If you don't
# have one yet, run these first:
#
# git clone https://github.com/console-rs/indicatif.git
# cd indicatif
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of console-rs/indicatif and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "console-rs/indicatif(\\.git)?\\b" \\
&& ok "origin remote is console-rs/indicatif" \\
|| miss "origin remote is not console-rs/indicatif (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "src/lib.rs" \\
&& ok "src/lib.rs" \\
|| miss "missing critical file: src/lib.rs"
test -f "src/progress_bar.rs" \\
&& ok "src/progress_bar.rs" \\
|| miss "missing critical file: src/progress_bar.rs"
test -f "src/draw_target.rs" \\
&& ok "src/draw_target.rs" \\
|| miss "missing critical file: src/draw_target.rs"
test -f "src/multi.rs" \\
&& ok "src/multi.rs" \\
|| miss "missing critical file: src/multi.rs"
test -f "src/format.rs" \\
&& ok "src/format.rs" \\
|| miss "missing critical file: src/format.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/console-rs/indicatif"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
indicatif is a Rust library for rendering real-time progress bars, spinners, and multi-bar progress reporting in terminal applications. It provides styled, colorized output via the console crate and handles concurrent progress tracking through ProgressBar, MultiProgress, and ProgressDrawTarget abstractions. Core capability: displaying download/computation progress with ETA estimation, speed metrics, and hierarchical bar management without blocking I/O. Modular single crate: src/progress_bar.rs (main public API), src/multi.rs (MultiProgress for concurrent bars), src/draw_target.rs (output routing abstraction), src/state.rs (internal bar state), src/style.rs (visual formatting), src/format.rs (template string rendering). src/iter.rs wraps iterators; src/rayon.rs integrates with rayon; examples/ contains 15+ runnable demos showing patterns (download.rs, multi.rs, tokio.rs, iterator.rs).
👥Who it's for
Rust CLI and backend developers building command-line tools (file downloaders, build systems, data processing pipelines) that need to report progress to users with minimal boilerplate. Contributors include library authors integrating with rayon parallelism, tokio async runtimes, and logging ecosystems via companion crates like indicatif-log-bridge and tracing-indicatif.
🌱Maturity & risk
Production-ready and actively maintained. The project uses semantic versioning (0.18.4), has comprehensive CI via GitHub Actions (rust.yml), includes test suites (tests/render.rs, tests/multi-autodrop.rs), and supports Rust 1.85+. Recent updates visible in Cargo.lock and feature flags (wasmbind, in_memory, improved_unicode) indicate ongoing refinement, though pre-1.0 versioning suggests API may evolve.
Low operational risk but upstream dependency quality matters: relies on console 0.16 for terminal abstraction and portable-atomic 1.12.0 for cross-platform atomics. Feature-gated dependencies (tokio, rayon, futures-core, vt100) keep minimal builds lean. Single-digit GitHub issues suggest either excellent design or small user base; wasm32 platform support (web-time, vt100) adds complexity. No obvious breaking changes visible in recent structure.
Active areas of work
Active maintenance on multi-platform support (added web-time for wasm32), improved Unicode handling (improved_unicode feature with unicode-segmentation), and in-memory rendering via vt100 integration (in_memory feature). Recent focus appears to be feature completeness and ecosystem integration rather than core refactoring, evidenced by optional dependency additions and example expansion.
🚀Get running
git clone https://github.com/console-rs/indicatif.git && cd indicatif && cargo build && cargo test && cargo run --example download
Daily commands:
Single library (not a binary): cargo build --all-features for full feature set, or cargo build for minimal. Run examples with cargo run --example <name> (e.g., cargo run --example download, cargo run --example multi). Tests: cargo test. Documentation: cargo doc --open.
🗺️Map of the codebase
src/lib.rs— Main crate entry point exposing ProgressBar, MultiProgress, and spinner APIs; every contributor must understand the public API surface.src/progress_bar.rs— Core ProgressBar struct managing state, drawing, and rendering logic; the heaviest single component in the codebase.src/draw_target.rs— Abstraction layer for terminal output (stdout, stderr, file); critical for all rendering and output redirection.src/multi.rs— MultiProgress coordinator managing multiple concurrent progress bars; essential for understanding concurrent bar synchronization.src/format.rs— Template and formatting engine for progress bar display strings; required for customizing bar appearance.src/state.rs— ProgressState struct holding atomic progress values and metadata; the data backbone of all progress tracking.Cargo.toml— Dependency manifest with feature flags (rayon, tokio, futures); defines optional integration points.
🧩Components & responsibilities
- ProgressBar (ProgressState, DrawTarget, ProgressStyle, console crate) — Public interface for single progress bar: tracks position, renders on interval, manages draw target and style
- Failure mode: Panic on invalid position (> length); silent no-op if terminal is closed or write fails
- ProgressState (portable-atomic (u64, bool)) — Atomic storage for position, length, and metadata; enables lock-free updates from worker threads
- Failure mode: Overflow silent if position incremented past u64::MAX; no bounds checking
- MultiProgress (Vec<ProgressBar>, DrawTarget coordination) — Coordinates rendering of multiple ProgressBar instances; manages alignment and z-order on terminal
- Failure mode: Bars may misalign if terminal width changes during execution; no dynamic re
🛠️How to make changes
Add a custom progress bar template
- Define a ProgressStyle with a custom template string in your code or load from examples/finebars.rs (
examples/finebars.rs) - Review available template variables in src/format.rs ProgressDrawTarget documentation (
src/format.rs) - Apply style to a ProgressBar using .with_style() method from src/progress_bar.rs (
src/progress_bar.rs)
Integrate progress tracking with an iterator
- Wrap any iterator with .progress() or .progress_with() method via ProgressBarIter (
src/iter.rs) - See example usage in examples/iterator.rs for patterns (
examples/iterator.rs) - For Rayon parallel iterators, enable the 'rayon' feature and use .progress() on par_iter() (
src/rayon.rs)
Create a multi-bar progress display
- Instantiate MultiProgress and add() individual ProgressBar instances (
src/multi.rs) - Review examples/multi.rs and examples/multi-tree.rs for multi-bar coordination patterns (
examples/multi.rs) - Call .join() on MultiProgress to wait for all bars to finish, or let it auto-drop (
src/multi.rs)
Redirect progress output to a custom target
- Choose or implement a DrawTarget variant: Terminal, Hidden, or InMemoryTerm (
src/draw_target.rs) - Create ProgressBar with .with_draw_target() method, passing your DrawTarget (
src/progress_bar.rs) - See InMemoryTerm in tests/render.rs for testing without terminal output (
tests/render.rs)
🔧Why these technologies
- console crate (ansi-parsing, std features) — Provides terminal detection, ANSI color support, and safe terminal I/O primitives
- portable-atomic 1.12.0 — Enables atomic state mutations without std::sync::Mutex; critical for lock-free progress updates across threads
- unit-prefix 0.5.1 — Formats byte counts with SI/binary prefixes (KB, MB, GiB, etc.) in download speed displays
- unicode-segmentation (optional) — Correctly measures display width of multi-codepoint Unicode characters for accurate bar alignment
- rayon 1.1 (optional feature) — Enables zero-cost progress integration with data-parallel iterators without modifying rayon itself
- tokio 1 (optional feature) — Supports async progress updates in tokio-based async runtimes without blocking event loops
⚖️Trade-offs already made
-
Use portable-atomic instead of std::sync::Mutex for state
- Why: Avoid lock contention on the hot path of progress updates which may happen thousands of times per second
- Consequence: Limits state to simple atomic values (u64, bool); complex state transitions require multi-step operations with potential races
-
Render throttling (default 15ms between draws)
- Why: Prevent terminal I/O saturation and flickering; redraw frequency bounded
- Consequence: Terminal output may lag behind actual progress by up to 15ms; not suitable for sub-millisecond precision displays
-
DrawTarget enum instead of trait object
- Why: Enable stack allocation and zero-cost abstraction of output redirection
- Consequence: Adding new output targets requires modifying DrawTarget enum and all match arms; less extensible via custom implementations
-
Format templates as strings rather than builder API
- Why: Simpler API surface; mirrors conventions from progressbar (Go) and other libraries
- Consequence: Template errors discovered at runtime, not compile-time; users must memorize variable names like {bar}, {pos}, {eta}
🚫Non-goals (don't propose these)
- Does not provide authentication or credential management for remote progress reporting
- Does not handle real-time synchronization or networking of progress across multiple machines
- Does not provide persistent progress state serialization (e.g., resume interrupted downloads)
- Does not manage application exit or signal handling (delegates to user code)
- Does not auto-detect or adapt bar style based on terminal capabilities—requires manual style selection
🪤Traps & gotchas
No required env vars or external services, but: (1) Terminal width detection via console::Term::size() can behave unexpectedly in non-TTY contexts (piped output, CI containers); use ProgressDrawTarget::hidden() for headless scenarios. (2) The in_memory feature requires vt100 crate which adds ~50KB dependency; use feature gates carefully. (3) WASM support (wasmbind feature) requires web-time for timer fallback—std Instant unavailable in WASM. (4) Unicode width calculations can fail without unicode-width feature on edge cases; improved_unicode feature adds segmentation support. (5) Atomic operations may differ on wasm32-unknown-unknown (non-wasmbind target).
🏗️Architecture
💡Concepts to learn
- Atomic lock-free state — indicatif uses
portable-atomicin src/state.rs to update progress without mutexes, enabling high-frequency updates from multiple threads without contention - Double buffering / terminal buffer management — Progress bars must clear and redraw efficiently; draw_target.rs manages buffer flushing to avoid flicker and terminal corruption
- ANSI escape sequences — Terminal colors, cursor positioning, and line clearing all rely on ANSI codes handled by the console crate; indicatif's style.rs formats these codes
- Unicode width calculation — Progress bars must align correctly despite multi-byte UTF-8 characters and variable-width glyphs; unicode-width feature handles column width, improved_unicode adds segmentation
- Template-based rendering — format.rs uses a custom template syntax (e.g., {bar} {percent} {eta}) allowing users to customize layout without recompiling; similar to format strings but domain-specific
- Hierarchical progress tracking — MultiProgress in src/multi.rs manages parent-child relationships between progress bars, enabling complex workflows like outer loop + inner loops with proper cleanup on drop
- Rate limiting / ETA calculation — Progress bars estimate completion time by tracking update rate and remaining work; requires exponential smoothing or moving averages to handle bursty I/O patterns
🔗Related repos
console-rs/console— Direct dependency providing terminal abstractions, ANSI parsing, and color support that indicatif builds uponconsole-rs/indicatif-log-bridge— Official integration crate that prevents log output from fighting with progress bars in the same terminalettle/tracing-indicatif— Ecosystem companion for automatic progress bar management via tracing spans, avoiding manual progress trackingrayon-rs/rayon— Optional integration target: indicatif wraps rayon iterators in src/rayon.rs for parallel work progress reportingtokio-rs/tokio— Optional async integration: examples/tokio.rs and features support async streams with progress tracking
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive tests for multi-progress bar autodrop behavior
The repo has tests/multi-autodrop.rs but it appears to be a single test file. Given the complexity of the MultiProgress API (src/multi.rs) and the visual differences shown in screenshots/mp-drop-before.svg and screenshots/mp-drop-after.svg, there's an opportunity to add more granular unit tests covering edge cases like: dropping progress bars in different orders, behavior when all bars are dropped, interaction with async contexts (given examples/tokio.rs exists), and memory safety in concurrent scenarios.
- [ ] Review src/multi.rs to identify untested code paths and edge cases
- [ ] Expand tests/multi-autodrop.rs with test cases for: partial drops, concurrent drops, and cleanup behavior
- [ ] Add tests verifying correct behavior with tokio integration (src/lib.rs likely has tokio feature gates)
- [ ] Run coverage tools to identify lines in src/multi.rs without test coverage
Add missing tests for draw_target rendering modes
The repo has tests/render.rs but draw_target.rs implements multiple rendering modes (likely including hidden, stderr, stdout, and in-memory modes based on the in_memory feature). The vt100 optional dependency suggests in-memory terminal capture exists but may lack test coverage. Adding targeted tests would validate rendering correctness across platforms.
- [ ] Review src/draw_target.rs to identify all rendering target types and modes
- [ ] Check tests/render.rs for coverage gaps against draw_target.rs implementations
- [ ] Add tests for the 'in_memory' feature (which depends on vt100) to validate terminal capture
- [ ] Add platform-specific tests for stderr vs stdout handling on Windows and Unix (given console crate handles platform differences)
Add CI workflow for WASM target and web-time integration validation
The Cargo.toml shows wasmbind feature with web-time dependency and cfg(target_arch = "wasm32") conditional compilation, but .github/workflows/rust.yml likely doesn't test WASM builds. This is a high-value addition as WASM is increasingly important and the conditional dependencies could silently break.
- [ ] Review .github/workflows/rust.yml to confirm wasm32 target is not being tested
- [ ] Add GitHub Actions job to test with
cargo build --target wasm32-unknown-unknown --features wasmbind - [ ] Add a job to verify the 'wasmbind' feature compiles correctly and pulls web-time correctly
- [ ] Consider adding a basic WASM example or integration test that could run in a WASM environment
🌿Good first issues
- Add tests to
tests/render.rsfor the newimproved_unicodefeature with East Asian width characters and emoji sequences; currently only basic ASCII width is covered - Document and add examples for the
in_memoryfeature (using vt100 for testing/logging scenarios); only one passing test exists, no examples or doc comments insrc/in_memory.rs - Create a new example
examples/ansi-color-variants.rsshowing all Style color options and template variables fromsrc/style.rsandsrc/format.rs; currently examples don't systematically demonstrate color/formatting customization
⭐Top contributors
Click to expand
Top contributors
- @djc — 29 commits
- @dependabot[bot] — 17 commits
- @spoutn1k — 16 commits
- @chris-laplante — 5 commits
- @jaheba — 5 commits
📝Recent commits
Click to expand
Recent commits
d65c4f0— FixProgressDrawTarget.is_stderr()forMultiProgress(kojiishi)d263328— MakeMultiState.draw_targetaspub(crate)(kojiishi)aacb5ae— Bump tokio from 1.52.1 to 1.52.2 (dependabot[bot])53a6fc2— Bump actions/checkout from 4 to 6 (dependabot[bot])7592e70— Bump tokio from 1.52.0 to 1.52.1 (dependabot[bot])f65cf5c— Bump tokio from 1.51.1 to 1.52.0 (dependabot[bot])dd5ff26— Always clear the rest of the line after drawing (ChrisDenton)3b0294a— Use div_duration_f64 (ChrisDenton)d2896b7— Upgrade rand to 0.10.1 (ChrisDenton)e372653— multi: document common MultiProgress bugs + behavior (#595) (chris-laplante)
🔒Security observations
The indicatif codebase demonstrates strong security posture. No critical or high-severity vulnerabilities were identified. The library is a pure Rust progress bar utility with minimal external dependencies, reducing attack surface. Dependencies are pinned to specific versions with good version management practices. The presence of deny.toml indicates proactive dependency security scanning. Minor recommendations include reconsidering default feature enablement and maintaining regular dependency audits. The code structure shows no obvious injection risks, hardcoded secrets, or misconfiguration issues typical of CLI tools.
- Low · Permissive Default Features —
Cargo.toml - [features] section. The 'wasmbind' feature is enabled by default, which includes optional web-time dependency for WASM targets. While not inherently dangerous, this increases the attack surface for web-based deployments without explicit opt-in. Fix: Consider making 'wasmbind' an opt-in feature rather than default, or document the implications for WASM consumers clearly. - Low · Indirect Dependency Risk —
Cargo.toml - [dependencies] console. The crate depends on 'console' (0.16) which itself may have external dependencies. While pinned to a specific minor version, transitive dependency vulnerabilities could affect the security of this library. Fix: Regularly audit dependencies using 'cargo audit' and consider using 'cargo-deny' (already present in deny.toml) to enforce security policies. Keep dependencies updated. - Low · Missing MSRV Security Considerations —
Cargo.toml - rust-version field. The rust-version is set to 1.85, which is very recent. While this ensures modern compiler safety features, it may exclude older projects that need to use this library. Fix: Document MSRV policy clearly. Consider if supporting older Rust versions is necessary for your user base, as older versions may have resolved security issues.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.