PromptLens
Scan local AI-agent history, extract only user-authored messages, and render a PNG word cloud that supports both Chinese and English.
Quick Start
Run from the skill directory:
When invoked by an Agent, scan only that Agent's own history by default. Use the source matching the invoking harness, for example --sources codex for Codex, --sources claude for Claude Code, --sources opencode for OpenCode, --sources openclaw for OpenClaw, or --sources hermes for Hermes Agent.
uv run --with jieba --with wordcloud --with matplotlib --with pillow \
scripts/promptlens.py \
--sources codex \
--days 90 \
-o outputs/wordcloud.png \
--report-json outputs/wordcloud.json
Use --path to add arbitrary JSONL/JSON files or directories:
uv run --with jieba --with wordcloud --with matplotlib --with pillow \
scripts/promptlens.py \
--path ~/.some-tool/history --sources custom \
-o outputs/wordcloud.png
Filter by project and time range:
uv run --with jieba --with wordcloud --with matplotlib --with pillow \
scripts/promptlens.py \
--sources codex \
--project SpotAsk --exclude-project worktrees \
--since 2026-01-01 --until 2026-06-30 \
-o outputs/wordcloud.png
Source Coverage
codex: scans $CODEXHOME/sessions, $CODEXHOME/archived_sessions, and falls back to history.jsonl. Subagent threads are skipped.
claude: scans $CLAUDECONFIGDIR/history.jsonl and direct CLI user messages in projects//.jsonl. Subagent, memory, tool-result, and SDK delegation records are skipped.
opencode: reads the SQLite opencode.db under ~/.opencode, ~/.config/opencode, or OPENCODEDATADIR.
openclaw: reads ~/.openclaw/agents/*/agent/openclaw-agent.sqlite and legacy session JSONL, or OPENCLAWSTATEDIR.
hermes: reads ~/.hermes/state.db, or HERMES_HOME.
custom: scans files/directories passed with --path, including raw OpenCode/OpenClaw/Hermes SQLite fixtures.
The scan is local-only and does not call any network service.
Output Modes
The default output is a promotional bordered image with the agent label, time range, message count, and session count. Add --plain to render only the cloud. Use --frame-label "My Agent" to override the label.
Weighting
The default scoring is conversation-relative and non-linear:
- Clean the raw input by removing fenced code, inline code, URLs/paths, pasted-text markers, and slash commands.
- Compute
raw = 1 / (1 + (effective_length / 120) ** 1.5), so short inputs keep high weight and long inputs decay sharply.
- Normalize raw weights within each conversation, then scale that conversation by
sqrt(numberofuser_messages).
- Multiply paste-heavy messages by
0.35.
- Give each message a fixed term budget; words inside it share that budget by token share.
This stops long pasted code, error logs, and generated delegation prompts from dominating the cloud. See [references/scoring.md](references/scoring.md) for the formula, examples, and tuning knobs.
Useful Options
--days N / --since YYYY-MM-DD: restrict the time range.
--until YYYY-MM-DD (alias --to): set an upper time bound.
--project SUBSTRING: keep only projects whose path contains the substring; repeatable.
--exclude-project SUBSTRING: remove matching projects; repeatable.
--list-projects: list discovered projects and message counts, then exit. It honors --project, --exclude-project, and time filters.
--max-words N: control cloud density.
--length-scale, --exponent, --paste-penalty: adjust the non-linear decay.
--font PATH: use a specific CJK-capable font.
--stopwords-file PATH: add user-specific stopwords, one per line.
--report-json PATH: write a reproducible JSON report with scan stats and top terms.
--verbose: print source counts and top terms.
--plain: render only the word cloud, without the promotional border.
--frame-label TEXT: override the agent label shown in the default border.