Skip to main content

Command Palette

Search for a command to run...

How We Built the OpenClaw Session Viewer

A lightweight, server-side viewer for AI agent session logs — from frustrating JSONL files to a paginated conversation.

Published
3 min read
How We Built the OpenClaw Session Viewer
D

I am a software developer based in Manchester. I primarily work in C#/.Net. I like to play with all things tech, and get involved in new projects, swap ideas and build new things. Particularly in the IoT space.

OpenClaw agent sessions are stored as JSONL files — one JSON object per line, one file per session. This is great for reliability and append-only logging. It's terrible for reading.

A single active session can easily grow to 36MB+. Open that in a browser and your tab crashes. Open it in VS Code and the whole editor stutters. grep works, but it's not great when you want to understand a conversation flow, see what tools were called, or trace a chain of reasoning.

We needed a way to browse session logs like a conversation — not a log file.

The Approach

The obvious solution would be to load the file and render it in the browser. But that defeats the purpose — the browser still has to parse 36MB of JSON. So we went the other way:

Server-side parsing. A Flask app reads the JSONL files on disk, extracts the conversation — user messages, assistant responses, tool calls, tool results — and returns paginated chunks of 100 messages at a time. The browser only ever sees what fits on one screen.

This means even the biggest session files load instantly. No loading spinner, no memory warning, just a conversation.

Architecture

The app is deliberately small — about 400 lines of Python, no database, no build step.

It reads from your OpenClaw agents directory, parses JSONL files, and renders them. That's it. No external API calls, no data leaving your machine.

Key Design Decisions

Why Flask? Because the app is simple enough that a framework would add more complexity than it solves. Flask gives us routing, templating, and a test client. Everything else is just Python.

Why Jinja2 templates instead of a SPA? Two reasons. First, the app works with JavaScript disabled — it's just HTML with pagination links. Second, server-side rendering means the initial page load is instant, no JS bundle to download.

Why no database? The session files already are the database. They're append-only, sorted by time, and each one is self-contained. Adding a database would just duplicate data and add complexity.

Features We're Proud Of

Copy to clipboard. Click the 📋 button on any message to copy its content. Useful for grabbing prompts, debugging tool calls, or sharing snippets.

Expandable tool calls. Long JSON arguments are truncated by default with a "Show full" toggle. Tool results work the same way. Keeps the conversation readable without hiding important details.

Pagination with page numbers. Not just prev/next. You get "1 2 3 … 20 21" so you can jump to any page.

Prometheus metrics. The /metrics endpoint exposes session counts, message totals, and tool call stats per agent. We use this in our Grafana dashboards.

CI/CD and Quality

Every change goes through GitHub Actions:

  • Lint — flake8 catches syntax errors and style issues

  • Tests — 10 pytest tests covering routes, agent stats, metrics, and caching

  • Releases — push a v* tag and GitHub automatically creates a release with changelog

Local development is one command: make check runs lint and tests together.

What's Next

Some ideas we're considering:

  • Search within a session (Ctrl+F but server-side)

  • Side-by-side session comparison

  • Export a session as a readable transcript (PDF or markdown)

  • Docker Compose setup for easy deployment

Try It

If you're an OpenClaw user and this sounds useful, give it a try:

github.com/CoraCodeDev/oc-session-viewer

MIT licensed, runs on any Python 3.10+ host. Pull requests welcome.


Built by CoraCode.