Skip to content
曾亮懿 ZengLiangYi Blog

Importing Claude Code history: paths, parsing, and verification

Check history paths, JSONL filtering, incremental import, and watcher limitations against the current ChatCrystal adapter.

曾亮懿

曾亮懿

4 min read
Table of contents Show Hide

Before importing history, identify the machine and directory being read, then inspect what parsing retains. A session appearing in the list establishes that the application created a record. It does not prove that every original event was preserved.

This article covers the Claude Code adapter in ChatCrystal at commit 7642768. It describes the data shapes this application supports, not a guarantee that Claude Code’s file format will remain unchanged.

Which files the adapter scans

The adapter defaults to ~/.claude/projects. Its scan() visits immediate subdirectories, finds .jsonl files directly within them, and skips files smaller than 100 bytes.

~/.claude/projects/
└── encoded-project-directory/
    ├── session-a.jsonl
    └── session-b.jsonl

This is not an arbitrary-depth recursive scan: do not assume deeper subagent histories are included automatically. Session IDs come from filenames. Project display names are inferred from directory segments, preferring Project or projects and otherwise taking the final one or two segments. This is a heuristic, not a reliable decoder for every original path.

Set custom paths before server startup

The server process loads CLAUDE_PROJECTS_DIR. For a new local service that has not started, a POSIX shell example is:

CLAUDE_PROJECTS_DIR=/absolute/path/to/claude/projects crystal serve -d

In PowerShell, set $env:CLAUDE_PROJECTS_DIR = 'C:\path\to\projects' before starting the service. An existing server does not reload its path because you later set an environment variable before crystal import. Identify the target service and startup configuration, then arrange a restart if changing the path.

This guide assumes the default local connection. Remote cloud import scans at the CLI client and uploads parsed results, changing both the path location and transmission boundary. Check the connection target in status before proceeding.

Scan manually and inspect the results

crystal import
crystal --json conversations --source claude-code --limit 20

The first command scans enabled sources in the current local workflow. The second uses --json to select the non-interactive branch and filters stored sessions by claude-code. Inspect projects, message counts, and status in the returned object’s items array. The current import command registers --source, but its local interactive and streaming branches do not forward that option. Consequently, crystal import --source claude-code cannot be promised to scan only that source.

Startup with an empty database can insert demo data. A demo- record in the list does not prove a real file was imported. Check the original test file’s session ID rather than relying on source labels or total counts.

Repeated import does not always add records. The import service first checks file size and modification time, then compares normalized content hashes when reparsing. Unchanged content is skipped or receives metadata updates; changed content follows the replacement path. After editing an original file, inspect the conversation and associated note status rather than treating an old summary as a conclusion about new content.

Parsing retains filtered messages

JSONL is read line by line. Lines that cannot be parsed as JSON are skipped. Relevant-message processing requires a uuid and a top-level user or assistant type. System records, progress events, and streaming deltas are not retained as ordinary conversation messages.

Within content arrays, the adapter collects text blocks. It saves thinking blocks separately, marks tool_use, and excludes tool_result from body extraction. A message with no body can still survive if it contains thinking or tool use. Filtering top-level thinking noise therefore does not mean every nested thinking block is discarded.

Some command echoes and system-reminder tags are cleaned according to existing rules; messages are then sorted by timestamps. This is neither general redaction nor a complete event archive. Back up original files separately and inspect sensitive material independently.

A skip is not necessarily a failure

Result Causes to investigate
No files scanned Missing path, unsupported directory depth, small files, read permissions
Scanned but skipped Unchanged size and modification time, unchanged parsed content, fewer than two meaningful messages
Content appears incomplete Noise filters, block extraction rules, invalid JSON lines, unfinished history writes
Error count increases Inspect the affected file and import logs, beyond the overall conversation count

Two messages meet the current import threshold; they do not establish completeness, importance, or suitability for notes. Import and summarization are separate stages. After summarizing one chosen record, inspect note content and vector processing status as well.

Verify automatic watching separately

The watcher starts by default in local mode, debouncing add and change events; cloud mode disables local watching. However, it currently passes a Claude Code **/*.jsonl glob to Chokidar 5, which no longer supports globs; see the official upgrade guidance. This version therefore cannot guarantee automatic import of new conversations; verify watching separately.

First import a known file manually. Then create or update another history containing non-sensitive test content and inspect watcher logs and the session list. If nothing changes, manual crystal import provides an explicit check. Debouncing does not prove that the watched target works; preserve the actual path, dependency version, and logs when investigating.

See the getting-started workflow for installation and both model checks, and AI conversation formats for differences across sources.

Share:

Related Posts

Filtering Claude Code JSONL: Events, Blocks, and Omissions

Follow ChatCrystal relevance checks, content extraction, and tag cleanup to distinguish top-level filtering from nested thinking and tool flags.

曾亮懿 曾亮懿
4 min read
#ChatCrystal #Claude Code #JSONL #Data parsing

Set up ChatCrystal MCP: make Claude Code calls reviewable

Connect ChatCrystal to Claude Code with a project-scoped stdio server, then verify its seven tools, HTTP backend, approvals, and request path.

曾亮懿 曾亮懿
3 min read
#ChatCrystal #MCP #Claude Code

Claude Code memory workflow: recall, verify, then write back

Use recall_for_task, validate_task_memory, and write_task_memory as an auditable workflow without treating MCP configuration as an automatic-memory guarantee.

曾亮懿 曾亮懿
4 min read
#ChatCrystal #MCP #Claude Code

From writing to code

Explore ChatCrystal, developer tools and daily learning notes on my GitHub. Questions about the implementation are welcome.