How the StepTracker Class Provides Live Progress Updates in the Spec-Kit CLI

The StepTracker class uses Rich's Live context manager with a refresh callback mechanism to render real-time hierarchical progress trees in the terminal.

The StepTracker class in the github/spec-kit repository powers the command-line interface’s live progress reporting. By combining an internal state machine with Rich’s terminal UI capabilities, it delivers smooth, self-updating step trees without blocking the main execution thread.

StepTracker Architecture and State Management

The StepTracker class is defined in src/specify_cli/__init__.py (lines 304–389). It maintains a list of step dictionaries, each containing key, label, status, and detail fields.

Core state methods include:

  • add(key, label) – Registers a new step with pending status.
  • start(key) – Marks a step as running.
  • complete(key, detail=None) – Sets status to done and attaches optional completion details.
  • error(key, message) – Records an error state with a message.
  • skip(key) – Marks the step as skipped.

Each mutating method triggers _maybe_refresh(), which invokes a registered callback only when a live display is active.

The Refresh Callback Mechanism

Live updates rely on a callback pattern rather than polling. The StepTracker exposes attach_refresh(cb) (line 340) to register a callable that redraws the UI.

When state changes occur, _maybe_refresh() executes:

def _maybe_refresh(self):
    if self._refresh_cb:
        try:
            self._refresh_cb()
        except Exception:
            pass

This design decouples the tracker from the rendering layer. The CLI attaches a lambda that calls live.update(tracker.render()), ensuring the terminal redraws instantly after every state transition without manual intervention.

Rendering Real-Time Progress Trees

The render() method (lines 360–389) constructs a Rich Tree object. It maps internal status values to colored symbols:

  • pending → dimmed circle
  • running → blue spinner arrow
  • done → green checkmark
  • error → red cross
  • skipped → yellow dash

The CLI consumes this tree inside Rich’s Live context manager (lines 1460–1470):

tracker = StepTracker("Initialize Specify Project")
with Live(tracker.render(), console=console,
          refresh_per_second=8, transient=True) as live:
    tracker.attach_refresh(lambda: live.update(tracker.render()))
    # ... perform work, updating tracker state ...

The transient=True parameter ensures the progress tree disappears after completion, leaving a clean terminal.

Practical Implementation Examples

Project Initialization Workflow

The init command demonstrates the full lifecycle. It instantiates StepTracker with the operation title, attaches the refresh callback, then sequences through validation, API calls, and file generation, updating the tracker at each phase.

Tool Verification Steps

In check_tool (lines 544–558), the tracker reports binary availability checks:

tracker.add("git", "Check Git installation")
tracker.start("git")
if shutil.which("git"):
    tracker.complete("git", shutil.which("git"))
else:
    tracker.error("git", "Not found in PATH")

Template Download Operations

The download_and_extract_template function (lines 2220–2270) uses granular steps for network and disk operations:

  • fetch – Resolve release metadata
  • download – Stream archive bytes
  • extract – Unzip to target directory
  • cleanup – Remove temporary files

Each step transitions through startcomplete or error, giving users immediate visibility into long-running I/O.

Summary

  • StepTracker maintains hierarchical step state in src/specify_cli/__init__.py (lines 304–389).
  • Live updates are driven by a callback registered via attach_refresh(), triggered after every state mutation.
  • Rich integration occurs through the render() method, which builds a colored Tree displayed inside a Live context manager (lines 1460–1470).
  • Usage patterns include tool checking (lines 544–558), project initialization, and template downloads (lines 2220–2270).

Frequently Asked Questions

What is the StepTracker class in Spec-Kit?

The StepTracker class is a state management utility in the Spec-Kit CLI that tracks the lifecycle of discrete operations. It stores step metadata—such as labels, statuses, and completion details—and provides methods to transition steps through pending, running, done, error, and skipped states.

How does StepTracker integrate with the Rich library?

StepTracker integrates with Rich through its render() method, which constructs a Rich Tree object decorated with status symbols and colors. The CLI wraps this tree in Rich’s Live context manager and attaches a refresh callback to StepTracker. Whenever a step’s state changes, the callback triggers live.update(), causing Rich to redraw the terminal display instantly.

Can I use StepTracker outside of the Spec-Kit CLI?

While StepTracker is designed for the Spec-Kit CLI, the class is self-contained and can be reused in any Python project requiring hierarchical progress tracking. You would need to install the rich library separately and provide your own rendering logic or use the built-in render() method if you want the same tree-style output.

Where is the StepTracker class defined in the source code?

The StepTracker class is defined in src/specify_cli/__init__.py between lines 304 and 389. Key integration points that use the class—such as the project initialization command and the check_tool function—appear at lines 1460–1470 and 544–558 respectively.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →