Claude Code skill for converting chat JSONL files into professional HTML visualizations with an interactive dashboard. Handles setup, configuration, batch generation, and organization of Claude Code conversation logs. Fully automated — Claude Code configures, generates, and manages everything.
Resources
8Install
npx skillscat add oskar-gm/code-chat-viewer Install via the SkillsCat registry.
Code Chat Viewer — Skill Instructions
This file contains operational instructions for Claude Code. When this skill is loaded, follow the workflows below to help the user configure, generate, and manage their Claude Code chat visualizations.
Overview
This skill provides two scripts:
| Script | Purpose |
|---|---|
scripts/visualizer.py |
Core converter: single JSONL file to single HTML |
scripts/manager.py |
Orchestrator: batch scan, generate, organize, and create dashboard |
The manager reads config.json for all paths and settings. If it does not exist, guide the user through interactive setup.
Workflow: First-Time Setup
When the user wants to use this skill and config.json does not exist:
Step 1: Detect source path
Look for Claude Code chat files automatically:
- Windows:
%USERPROFILE%\.claude\projects\ - Linux/Mac:
~/.claude/projects/
Verify the path exists and contains project subdirectories with .jsonl files. If not found, ask the user for the correct path.
Step 2: Ask configuration questions
Ask these questions interactively (suggest defaults in parentheses):
Output folder: "Where should the generated HTML files be saved?"
- Default:
~/Code Chat Viewer - Dashboard is saved at the root; chats go into a
Chats/subfolder
- Default:
Dashboard filename: "What name for the dashboard file?"
- Default:
CCV-Dashboard.html
- Default:
Agent chats: "Include agent sub-chats? (yes/no)"
- Default: yes
- If yes: "Minimum agent file size in KB?" (default: 3)
Inactive days: "Days of inactivity before organizing?"
- Default: 5
Shorts management: "Automatically separate small inactive chats into a subfolder? (yes/no)"
- Default: yes
- If yes: "Maximum size in KB to classify as short?" (default: 40)
Archive management: "Automatically archive large inactive chats? (yes/no)"
- Default: yes
Step 3: Create config.json
Generate config.json from the user's answers. Use the structure in config.example.json as template. Place it in the skill's root folder.
Step 4: Run first generation
Execute: python scripts/manager.py
Report the results to the user.
Workflow: Regular Usage
When config.json already exists:
- Execute:
python scripts/manager.py - Report results (new, updated, unchanged, organized, dashboard stats)
- Inform the user where the dashboard file is located
Workflow: Update Configuration
When the user wants to change settings:
- Read current
config.json - Show current configuration
- Ask what they want to change
- Update
config.json - Re-run the manager if needed
Workflow: Single Chat Conversion
When the user wants to convert a single JSONL file:
python scripts/visualizer.py <input.jsonl> [output.html]If no output filename is provided, the script generates one automatically with format Chat YYYY-MM-DD HH-MM hash.html.
Workflow: Open Specific Chat
The manager supports CLI flags to open a specific chat instead of the dashboard:
| Flag | Usage | Description |
|---|---|---|
--name "terms" |
python scripts/manager.py --name "my chat" |
Find and open a chat by name (flexible: all words match, any order, case-insensitive) |
--current <path> |
python scripts/manager.py --current /path/to/session.jsonl |
Open the chat for a specific JSONL file |
--current |
python scripts/manager.py --current |
Auto-detect current session from CWD |
--force |
python scripts/manager.py --force |
Regenerate ALL chats (ignores modification time check) |
--btw |
python scripts/manager.py --btw |
Generate btw.html aggregating all /btw queries (skips chat generation) |
Flags can be combined: python scripts/manager.py --force --name "my chat"
Interactive mode
When running manually (double-click or terminal without flags), the script prompts for mode selection:
- Normal — Only updates chats whose JSONL source has changed (fast)
- Force — Regenerates all chats from scratch (slow, useful after template changes)
File Locations
Claude Code stores chat logs at:
- Windows:
%USERPROFILE%\.claude\projects\and%USERPROFILE%\.claude\chats\ - Linux/Mac:
~/.claude/projects/and~/.claude/chats/
Each project subdirectory contains:
*.jsonl— Main chat files (UUID-named)agent-*.jsonl— Agent sub-chat filessessions-index.json— Rich metadata (name, summary, message count, git branch)
Configuration Reference
config.json fields:
| Field | Type | Default | Description |
|---|---|---|---|
source.projects_path |
string | ~/.claude/projects |
Directory with Claude Code JSONL files |
output.folder |
string | ~/Code Chat Viewer |
Root folder for output (dashboard + Chats/ subfolder) |
output.index_filename |
string | CCV-Dashboard.html |
Dashboard filename |
time_format |
string | 12h |
Timestamp clock: 12h (AM/PM) or 24h |
agents.include |
bool | true |
Include agent sub-chat files |
agents.min_size_kb |
int | 3 |
Minimum agent file size to include (KB) |
inactive_days |
int | 5 |
Days without activity before organizing |
shorts.enabled |
bool | true |
Separate small inactive chats |
shorts.folder |
string | Shorts |
Subfolder name for short chats |
shorts.max_size_kb |
int | 40 |
Max HTML size to classify as short (KB) |
archive.enabled |
bool | true |
Separate old inactive chats |
archive.folder |
string | Archived |
Subfolder name for archived chats |
Environment variables (take precedence over config.json):
| Variable | Overrides | Description |
|---|---|---|
CODE_CHAT_VIEWER_DIR |
output.folder |
Alternative output directory for the dashboard and HTML files |
Dashboard Features
The generated dashboard (CCV-Dashboard.html by default) is a self-contained HTML file with:
- Sortable table: Click column headers to sort (default: last used, descending); every column is sortable except the link icon
- Full-text search: Filter and exclude search across complete chat names and UUIDs (not just visible truncated text)
- Exclude filter: Hide rows containing specific text (complementary to the search filter)
- Category filters: Checkboxes for Active/Shorts/Archived (only shown if enabled)
- Permanent UUID column: full session UUID with a one-click copy button (was an optional column in earlier versions)
- Optional columns: Branch, Size, and
BTW(per-chat/btwcount) — toggle with checkboxes - Recap / First prompt sub-rows: optional collapsible rows under each chat (toggles in Columns) showing the chat's last obtainable summary and the full first user message; searchable, sort-aware, persisted in localStorage
- Select & delete: a Select button enables per-row checkboxes (with a select-all-visible master) and a Delete button that opens a confirmation modal listing the affected chats; it generates a ready-to-copy command (PowerShell / macOS / Linux tabs) that removes each chat's HTML and original
.jsonl— to trash by default, permanent via toggle. The dashboard cannot delete files itself (static HTML): the user runs the command in their terminal and regenerates - Name tooltips: Hover to see full chat name when truncated in the table
- UUID copy: Click the copy button in the UUID column to copy the full session ID to clipboard
- Direct links: Icon to open each chat HTML file
- Enriched data: Uses
sessions-index.jsonand direct JSONL parsing for name, summary, message count, git branch - State persistence: Remembers sort order, filters, search text, exclude text, and visible columns via localStorage (5h TTL)
- Snapshot filtering: Automatically excludes file-history-snapshot entries (Claude Code's undo system)
- Header buttons: Feedback (opens GitHub Issues) and Latest release (links to the newest release to check for updates); Feedback also in footer
- BTW Queries view:
[3]in the interactive menu or the--btwflag generates a standalonebtw.htmlaggregating every/btwquery from~/.claude/history.jsonl, grouped by chat, with Expand/Collapse all and a real-time filter
Chat Page Features
Each generated chat HTML includes:
- Chat title in header: Displays the chat name next to "Code Chat Viewer" (resolved from custom title, session index, or first prompt)
- Chat UUID in header: Full session UUID shown on the right side of the header. Selectable text plus a one-click SVG copy button (visual confirmation on copy)
- Dashboard link: "Back to Dashboard" button in header (links adjust automatically for subfolder location)
- Conversation filter: Filter messages by text content
- Edit diff view:
Tool: EditandTool: MultiEditblocks renderold_stringvsnew_stringside-by-side inside the tool-use box, with red/green color coding (Dark theme by default, Light theme toggle available) - Expand/collapse all Edits & Writes: One-click button in the search bar to open or close every Edit and Write block at once
- Write tool view: Full-width collapsible block with blue accent, consistent with Edit's
new_stringside; the sharedEdits/Writestoggle expands/collapses both at once /btwqueries inline:/btwquestions from~/.claude/history.jsonlmatching the session are injected inline as user-style messages (Claude cream styling), with a counter in the stats bar- Full date in timestamps: messages show the full
YYYY-MM-DDdate with configurable 12h (AM/PM, default) or 24h time (time_formatin config) - Multi-mode message navigation: All/User/Assistant modes with prev/next buttons, position counter, and keyboard shortcuts (N/P)
- Collapsible thinking blocks: Collapsed by default with first-line preview; expand for full content
- Collapsible tool-use blocks: Collapsed by default; expand for full untruncated content
- Smart message rendering: Commands (
[COMMAND]), compact blocks (collapsible, purple), task notifications (color by status), user responses (amber Q&A with markdown previews), user rejections ([REJECTED]with feedback, coral/red), inline user comments ([USER COMMENT], amber) - Color-coded highlights: Blue for user, green for assistant, purple for compact, amber for user responses/comments, red for rejections
- Smart scroll: Centers short messages; pins long messages to top for readability
- Header buttons: Feedback (opens GitHub Issues) and Latest release (check for updates), plus Back to Dashboard; Feedback also in footer
- Collapsible tool results: Click to expand/collapse
Chat Categories
| Category | Criteria | Location |
|---|---|---|
| Active | Used within inactive_days |
Chats/ folder |
| Short | HTML < shorts.max_size_kb + inactive |
Chats/Shorts/ subfolder |
| Archived | Inactive for inactive_days+ |
Chats/Archived/ subfolder |
Troubleshooting
"config.json not found"
Run the setup workflow (Step 1-4 above) to create the configuration.
"Source path does not exist"
The configured source.projects_path is wrong. Update it in config.json or re-run setup.
Empty dashboard
The source directory may not contain any JSONL files, or the output folder has no generated HTMLs yet. Run the manager first.
Missing enriched data (? icon in Msgs column)
Some chats lack metadata in sessions-index.json. This is normal for old chats, agent chats, or recently active sessions not yet indexed by Claude Code.
Requirements
- Python: 3.6 or higher
- Dependencies: None (Python standard library only)
- OS: Windows, Linux, macOS
Technical Notes
- The manager imports functions from
visualizer.py(same directory):parse_chat_json,generate_html,get_chat_timestamp,generate_output_filename,ICON_BASE64,ICON_FAVICON_BASE64 - HTML generation is deterministic: same JSONL input produces same HTML output
- The manager only regenerates an HTML if the source JSONL is newer than the existing HTML (unless
--forceis used) - Timestamps are always verified against JSONL file mtime (sessions-index.json can be stale)
- Message counts and metadata are extracted directly from JSONL files for accuracy
- File-history-snapshot entries (Claude Code's undo system) are automatically filtered out
- Organization (shorts/archive) uses the JSONL modification time as "last used" indicator, not the HTML generation time
- Dashboard links in chat pages are automatically adjusted for subfolder depth (
../or../../) - Favicon uses a dark icon (visible on white browser tabs); header uses a light icon (visible on dark header)
- Both icons are embedded as base64 — no external files needed
- The manager auto-opens the dashboard in the browser after generation (interactive mode only)
- With
--nameor--current, the manager opens the matching chat HTML instead of the dashboard - Chat title resolution chain: JSONL
custom_title→ sessions-indexcustomTitle→ sessions-indexsummary→ first prompt (60 chars) → "Untitled" - "(no content)" placeholder messages from Claude Code internals are automatically filtered out
- Scripts can be run manually without Claude Code — they pause before closing on Windows (double-click compatible)
- In interactive mode (manual execution), the user can choose between normal and force mode before scanning
Attribution
Author: Óscar González Martín
Repository: https://github.com/oskar-gm/code-chat-viewer
License: MIT
Version: 2.4.0