MadQTT
Live TUI for the claude-prime hooks MQTT + MongoDB stream — turn the firehose into something a Mad Tinker can read.
┌ Sessions ─────────────┬ Session 4c0f8355 · madnessDesktop ──────────┐
│▶ 4c0f… madnessDesktop │ 01:06:36 Bash grep -n private async… │
│ ae97… element-dupe │ 01:06:38 Bash ✓ 1.5s │
│ 9439… Inventorium │ 01:06:42 Read lib/api.ts │
│ 6465… madnessDesk │ 01:06:44 Read ✓ 2.2s │
│ failures: 3 │ 01:06:51 Bash grep -rn ^export.func… │
│ active: 4 │ 01:06:52 Bash ✗ failure │
└───────────────────────┴─────────────────────────────────────────────┘
[s]essions [p]rojects [t]opics [c]hat [f]ilter [v]iew [m]sg [q]uit
Install
pip install madqtt # from PyPI
madqtt # run it
Or for local dev from a checkout:
uv venv .venv
uv pip install -p .venv/bin/python -e .
If your global uv cache has root-owned subdirs from a past
sudoinstall, route around it:UV_CACHE_DIR=.uv-cache uv pip install -p .venv/bin/python -e .
Run
.venv/bin/python -m madqtt # live: broker + Mongo backfill
.venv/bin/python -m madqtt --replay dataset1.txt # replay a mosquitto_sub -v capture
.venv/bin/python -m madqtt --host eaws --port 1883
Where the data comes from
MadQTT is the consumer. It renders a stream that something else has to produce: Claude Code hooks that publish to an MQTT broker and (optionally) mirror to MongoDB. No producer running → empty timeline.
The contract MadQTT subscribes to:
| source | what | shape |
|---|---|---|
MQTT status/<device>/activity/# |
every tool call (pre/post) | {tool, target, session, project, ts} |
MQTT status/<device>/claude/# |
session/compact/idle lifecycle | per-topic payloads |
Mongo claudehooks_<project> |
backfill on startup so history survives a cold broker | same events |
<device> is the DeNa env var on the publishing host (default macbook).
The full topic + payload reference is in the docs (--docs, below).
Just want to see it work? No broker, no Mongo, no hooks needed — replay a captured stream:
madqtt --replay dataset1.txt # a mosquitto_sub -v capture, ships in the repo
Wiring up a live producer. The reference producer is the claude-prime
hook set in the Madness workshop — a
bundle of Claude Code PreToolUse/PostToolUse/SessionStart/… hooks that
mosquitto_pub the events above. It's workshop-coupled (dvttestkit, a
hooks_config.json of feature flags), so treat it as a worked example of the
contract rather than a drop-in: any hook that publishes those topics in that
shape will light up MadQTT. Point it at your broker with:
export MADNESS_MQTT_HOST=your-broker # default localhost
export MADNESS_MQTT_PORT=1883
export CLAUDE_MONGO_URI=mongodb://localhost:27017/ # optional backfill
madqtt
Documentation
Everything else — keys, configuration, architecture, the full topic & payload reference — lives in the docs site:
uv pip install -p .venv/bin/python -e '.[docs]'
.venv/bin/python -m madqtt --docs
Spawns mkdocs serve on a free port and opens your browser.
Optional extras
| extra | install | what you get |
|---|---|---|
[docs] |
uv pip install -e '.[docs]' |
mkdocs-material site behind --docs |
[web] |
uv pip install -e '.[web]' |
textual-serve "python -m madqtt" exposes the TUI in a browser |
Dev
.venv/bin/python -m pytest tests/ -q # parser regression against dataset1.txt
.venv/bin/python scripts/smoke_replay.py # headless: all views, SVG captures
.venv/bin/python scripts/smoke_live.py # live: backfill + 4 synthetic publishes
.venv/bin/python -m mkdocs build --strict # build docs site to ./site
Project layout
madqtt/ package
├── events.py Event dataclass + topic parser
├── store.py EventStore + ring + per-session/topic rollups + Mongo backfill
├── ingest.py aiomqtt subscriber + replay
├── app.py Textual App, key bindings, view switching
├── docs.py --docs implementation
├── config.py env-var Config
└── widgets/ sessions, projects, topics, chat, filter, transcript, message
docs/ mkdocs-material site (built behind --docs)
tests/ parser regression
scripts/ smoke_replay.py, smoke_live.py
Status
| feature | shipped |
|---|---|
| Sessions + Projects + Topics views | v1.0 |
| Filter modal (project/topic/idle) | v1.0 |
| Filter chips actually prune views | v1.1 |
Transcript viewer (v) |
v1.1 |
Swarm chat pane (c) |
v1.1 |
Write-back (m) to swarm/chat_in |
v1.2 |
Fleet Mongo (MADQTT_MONGO_URIS) |
v1.2 |
| Browser exposure (textual-serve) | v1.2 |
Docs site + --docs CLI |
v1.3 |
| Persistent memory (UI state + log) | v1.4 |
| tool_failure toast + fail/hr counter | v1.5 |
Per-session task list (T) |
v1.6 |
| Pinned sessions + unread counts | v1.7 |
| Inline transcript jumping | v1.8 |
Export filtered transcript (e) |
v1.9 |
Global transcript search (/) |
v1.10 |
Event inspector modal (enter, i) |
v1.11 |
Agent control panel (a) |
v1.12 |
Roadmap candidates: "open cwd in editor" key, per-tool aggregate stats view.
Persistent memory
Two files under ~/.madqtt/ (override with MADQTT_STATE_DIR, disable with
MADQTT_NO_PERSIST=1):
state.json— last view, filter chips, idle toggle, last selected session. Restored on launch, saved on quit + every 30s.events.jsonl— append-only mirror of every Event. Replayed into the ring on startup so the timeline survives broker + Mongo being down.
Metadata
Release files for madqtt 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| madqtt-0.1.2.tar.gz | 62.0 kB | Without provenance | Details for madqtt-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| madqtt-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for madqtt-0.1.2-py3-none-any.whl |
Total release size: 113.2 kB
Release files / madqtt-0.1.2.tar.gz
| Download URL | madqtt-0.1.2.tar.gz |
|---|---|
| Size | 62.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ae11d51127c1eb97b090340f7cc5c4366259ce6e6d55dc48ea29a634246d2cb1
|
|
BLAKE2b-256 checksum How to use checksums |
73f367c8361fbba21ca895d501294ff8de45e230e768cde5c3996f481b93a0a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|
Release files / madqtt-0.1.2-py3-none-any.whl
| Download URL | madqtt-0.1.2-py3-none-any.whl |
|---|---|
| Size | 51.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dbd199833611d231495f2e8734a6c8915a59fa86f6b31f2e7606f9aece72e97a
|
|
BLAKE2b-256 checksum How to use checksums |
b9c0ddf0aafe5d401901a9c0c63b5130dc9a28f050b5616650a2572c51079422
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|
Security for madqtt 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.