I wanted a way to share Claude Code sessions in blog posts. Not screenshots. Not copy-pasted text. The actual terminal experience - dark background, tool calls, the whole thing.
This post is about building that. And it uses the component it describes.
The idea
I was setting up this blog with Claude Code when the thought hit: what if I could embed these sessions directly?
> my end goal is to be able to render chat like snapshots of this exact environment, so it should look like a terminal, lets brainstorm, any lib for that? should we just implement a component?
⏺ Good idea for an AI/agents blog. A few options:
Existing libs:
- termynal - lightweight, animated typing effect, but more for commands than chat
- asciinema - full terminal recordings, but overkill for static snapshots
- xterm.js - actual terminal emulator, way too heavy
Custom component (my recommendation):
- Build a simple Astro component that mimics the Claude Code look
- Dark bg, monospace, styled user/assistant turns
- Maybe tool calls get a different treatment
- Full control over styling to match your blog aesthetic
Custom component it is.
Claude Code stores sessions locally. I didn’t know the format, so we went looking.
> id like to be able to input real chat sessions (as they are stored locally, or parts of them
⏺ That changes things - we'd parse the actual session format rather than authoring manually.
Let me find where Claude Code stores sessions and what the format looks like:
⏺ This is great. The session format is clear:
Location: ~/.claude/projects/{project-path}/{session-id}.jsonl
Format: JSONL (one JSON object per line) with these types:
- type: "user" - User messages
- type: "assistant" - Assistant responses containing:
- type: "text" - The actual response text
- type: "thinking" - Extended thinking blocks
- type: "tool_use" - Tool calls with name and input
JSONL. One JSON object per line. Each message has a type (user/assistant), content blocks for text, tool calls, and thinking. Clean enough to parse.
Building it
Two files:
- parseSession.ts - Reads the JSONL, filters out metadata, deduplicates streamed messages
- ChatSession.astro - Renders the parsed messages with terminal styling
The component accepts a session prop in three formats: typed arrays (cleanest), imported JSONL files, or inline strings.
The result
⏺ Hell yes.
What we built:
- src/utils/parseSession.ts - Parses Claude Code JSONL sessions
- src/components/ChatSession.astro - Renders them as terminal UI
Usage with typed arrays (recommended):
<ChatSession session={[
{ role: "user", content: "hello" },
{ role: "assistant", content: "Hi there!", tools: [{ name: "Read", input: { file_path: "foo.ts" } }] }
]} />
What’s next
The component is basic. Could add:
- Actual tool output (file contents, command results)
- Collapsible long outputs
- Syntax highlighting in code blocks
But it works. I can now embed real sessions, not reconstructions.