Skip to main content

ollama-watch

Terminal observability for local model status via Ollama

python stdlib-only license

Live prefill and decode progress from Ollama's runner.

Standard library only. No dependencies.

ollama serves models for that various harnesses consume (OpenCode, Hermes, Pi, etc). but they're built for low-latency, high throughput remote servers. When running locally, high latency, slow prefills and a lack of observability for these is bad UX.

ollama-watch is a parser of the ollama server logs, that formats them and displays them conveniently either as a log or CLI dashboard.

ollama-watch dashboard

Dashboard · Library · Quickstart · Tests · Contributing


Contents


Quickstart

pip install ollama-watch

Or with uv:

uv pip install ollama-watch

Run it:

ollama-watch

With a historical log + pinned bottom current state:

✔ 16:23:34 200 32.243998125s | input 48.2k cached 47.9k processed 343 @ 44 tok/s (7.8s) | out ~307 @ ~13 tok/s (23.6s) mtp_accept_rate 0.79 | peak 32.78 GiB
✔ 16:24:15 200 26.539759625s | input 48.5k cached 48.2k processed 231 @ 51 tok/s (4.5s) | out ~194 @ ~9 tok/s (21.9s) mtp_accept_rate 0.80 | peak 34.38 GiB
✔ 16:26:54 200 2m27s | input 48.8k cached 48.5k processed 282 @ 60 tok/s (4.7s) | out ~1632 @ ~11 tok/s (2m21s) mtp_accept_rate 0.67 | peak 32.83 GiB

[qwen3.8:27b-mlx 34GB 100%GPU ctx65536 ∞] Processing input ███████████████████████████░  99.3% 48.7k/49.1k cached 48.7k

Ctrl+C prints a session summary: median input and output rates, total tokens, cache hit share, and failure count.

Or run it straight from a clone:

PYTHONPATH=src python3 -m ollama_watch.cli

Options

ollama-watch                       # follow live, one status line
ollama-watch -d                    # full-screen dashboard
ollama-watch --replay              # replay this log's history, then follow
ollama-watch --replay --no-follow  # history + summary, then exit
ollama-watch --log /path/to/server.log --host 127.0.0.1:11434
ollama-watch --no-server           # skip /api/ps (no model details in the header)

Dashboard

ollama-watch -d gives a full-screen view. q quits.

ollama-watch
 model   qwen3.8:27b-mlx  33GB  100% GPU  ctx65536  ∞

 status  Generating
         ████████████████████████████████████████████████████████████████████████████████ 2m01s
         input 48.8k  last ~9 tok/s

 input   █▇▆▄▄▇▅▄▁▂▂▄▄▅▄▃▂▅▇▄▅▅▅▂▄▃▅▄▄▄     60 tok/s req   5-92
 output  ▅█▆▅▅▅▅▃▇▅▅▄▅▇▄▆▅▅▅▅▅▅▆▄            9 tok/s last  6-18

 memory  ██████████████████████████████████░░░░┊░  30.7 of 36 GiB   peak 34.4 (96%)

 session 1h20m   working 1h00m (75%)   idle 20m24s (25%)
         █████████████████▓▓▓▓▓▓▓▓▓▓▓▓▒░░░░░░░░░░  █ input 35m21s  ▓ output 22m51s  ▒ other 2m11s  ░ idle 20m24s

       time      code    input   in/s   cache     out   out/s   queue    ttft     dur       peak
 + 15:59:26       200    54.8k     58     99%   ~3028     ~11            4.6s   4m44s   33.1 GiB
 + 16:03:42       200    12.2k     88      0%   ~1759     ~17           2m15s   3m57s   35.5 GiB
 - 16:09:40    cancel    43.9k     51     72%                                   4m05s   52.5 GiB
 - 16:12:05     super    43.9k     59    100%   ~1349     ~10                   2m24s   33.0 GiB
 + 16:13:19       200    44.9k     57     98%    ~719     ~13           16.5s   1m13s   35.5 GiB
 + 16:14:22       200    45.5k     66     99%    ~396     ~12   359ms   10.4s   44.3s   34.8 GiB
 + 16:17:57       200    45.8k     19     99%    ~239     ~10   569ms   13.9s   36.9s   34.9 GiB
 + 16:18:57       200    46.4k     52     99%    ~277     ~12   769ms   13.5s   37.1s   34.2 GiB
 + 16:20:27       200    46.6k     28    100%    ~599     ~10   169ms    7.2s   1m05s   35.5 GiB
 + 16:21:34       200    47.3k     61     99%    ~411     ~11   572ms   11.1s   49.1s   32.4 GiB
 + 16:22:45       200    47.9k     49     99%    ~466     ~12   927ms   14.4s   53.2s   33.2 GiB
 + 16:23:34       200    48.2k     44     99%    ~307     ~13   850ms    8.7s   32.2s   32.8 GiB
 + 16:24:15       200    48.5k     51    100%    ~194      ~9    92ms    4.6s   26.5s   34.4 GiB

 30 req  cache 82%  median in 52 tok/s  median out 12 tok/s  median ttft 16.5s  failed 4  q quit

Runner Support

Supports:

  • mlx runner (native mlx models)
  • llama.cpp runner (.gguf models)

Note: mlx Runner with MTP and llama.cpp runner expose metrics that can be used to either approximate tokens per second or read them directly. mlx runner without MTP doesn't, and ollama-watch will not display tokens per second for those configurations.

Session Accounting

The session panel splits the wall clock into where it was spent: model-work time, idle time, etc.

Working time splits again into processing input, generating output, and the remainder of a request that is neither (queueing, tokenising, templating).

Time To First Token

Ollama's Gin times the whole HTTP handler, so a request's arrival is end - duration.

From that: queue is arrival until the runner started work, and ttft is arrival until input processing finished - the wait before the first token can appear. While a request is in flight the live panel shows ttft so far, which is a lower bound, since the figure is only final once the request ends.

Sparklines

Sparklines display recent history. One bar per finished request, oldest on the left, newest on the right.

The figure to the right of each sparkline is the min-max rate across its bars. Sparklines are padded to a fixed width so that figure stays in one column even though the two rows rarely hold the same number of bars.

Also, each sparkline is scaled to its own peak.


As A Library

Everything the CLI shows is available programmatically, so you can build your own CLI, your own dashboard, or feed the numbers into something else entirely — a status bar, a progress widget in your own Ollama client, a metrics exporter, etc.

watch() is the whole pipeline as a generator. It yields an Update whenever anything changes:

from ollama_watch import Phase, watch

for update in watch():
    state = update.state
    if state.phase is Phase.PREFILL:
        print(f"{state.fraction:.0%} of {state.prompt_tokens}, eta {state.eta_s:.0f}s")
    for receipt in update.receipts:
        print(receipt.status, receipt.prompt_tokens, receipt.decode_rate)

A twenty-line progress bar, which is roughly what ollama-watch without the dashboard is:

from ollama_watch import Phase, watch

last = None
for update in watch():
    state = update.state
    if state.phase is Phase.PREFILL and state.fraction != last:
        last = state.fraction
        filled = int(state.fraction * 40)
        eta = f"eta {state.eta_s:.0f}s" if state.eta_s else ""
        print(f"\r[{'#' * filled:<40}] {state.fraction:.0%} {eta}", end="", flush=True)
    for receipt in update.receipts:
        last = None
        mark = "ok" if receipt.ok else receipt.status
        ttft = f"ttft {receipt.ttft_s:.0f}s" if receipt.ttft_s else "ttft unknown"
        print(f"\r{mark} {receipt.prompt_tokens} in, {ttft}")

Tests

uv run --with pytest python -m pytest

Contributing

Found a bug? Have an idea? PRs welcome.

  1. Fork it
  2. Create your feature branch
  3. Write tests
  4. Submit a PR

Metadata

Release files for ollama-watch 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ollama-watch 0.1.0
File Size Uploaded
ollama_watch-0.1.0.tar.gz 349.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ollama-watch 0.1.0
File Interpreter ABI Platform
ollama_watch-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 386.0 kB

Release files / ollama_watch-0.1.0.tar.gz

Download URL ollama_watch-0.1.0.tar.gz
Size 349.2 kB
Tags Source
SHA-256 checksum
How to use checksums
5f9048d84ee44ab3a4a439fbd3a408783903d0348760572ea0c42240811e40f7
BLAKE2b-256 checksum
How to use checksums
a2ae49927bb02300a83ad5556aea60cd6e1c5cec419868c23f4e7b548595ebd7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.8

Release files / ollama_watch-0.1.0-py3-none-any.whl

Download URL ollama_watch-0.1.0-py3-none-any.whl
Size 36.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b016c18c49ca3f6661df764dce271786d2bc5aa254585fa6fa2b57a69574a24b
BLAKE2b-256 checksum
How to use checksums
aaec02e93cc4b856cc66a4fa43b64e0accd3da04836549c4a1a761de9c4d30da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.8

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page