Jottrace preserves local AI coding-session transcripts into a private SQLite journal you control.
Today it can ingest Claude CLI / Claude Code, Codex CLI, Factory / Droid-style JSONL session files, Gemini CLI chat JSON files, OpenCode SQLite, and Hermes SQLite SessionDB rows. It also preserves Claude subagent sidechain sessions and reports the local journal status from the command line. Cursor and other readers are tracked in the design docs, but are not implemented as user-facing ingest sources yet.
- Install a standalone
jottracebinary into~/.local/bin. - Keep local state in
~/.jottrace/db.sqlite, or another directory viaJOTTRACE_HOME. - Check the data directory and database with
jottrace doctor. - Ingest Claude, Codex, Factory, Gemini, OpenCode, and Hermes sessions with
jottrace ingest. - Inspect stored session, event, schema, and ingest-error counts with
jottrace status. - Preserve Claude subagent sidechains as distinct child sessions linked to the parent session.
- Resume incremental JSONL imports, defer partial trailing lines, and preserve rewritten or truncated source files as new generations.
- Record corrupt or unreadable source-file errors without blocking unrelated sessions.
- Inspect and compact eligible raw payload rows with
jottrace compact. - Browse preserved sessions, events, and unresolved ingest errors locally with
jottrace web. - Update the installed binary from GitHub Releases with
jottrace update.
curl -fsSL https://raw.githubusercontent.com/season179/jottrace/main/install.sh | bashThe installer detects your OS and CPU architecture, downloads the matching
GitHub Release artifact, and installs jottrace to:
~/.local/bin/jottraceIf ~/.local/bin is not on your PATH, the installer prints a shell snippet
you can paste into your shell rc file. It does not edit shell configuration
files automatically.
The installer needs a published GitHub Release to download from. If no release has been published yet, the script is present but installation will fail at the download step.
After installing, run:
jottrace -h
jottrace --version
jottrace doctor
jottrace ingest
jottrace status
jottrace compact
jottrace pack
jottrace settle <archive>
jottrace webjottrace -h is the fastest CLI discovery path. It prints the top-level
commands and points to jottrace <command> --help for command-specific usage.
High-frequency agent-facing commands use compact stdout by default:
status, doctor, ingest, and compact print the action-relevant counts
and next steps without journal paths or long diagnostics. Add --details to
those commands when you need the database path, schema version, recent
ingest-error fields, or full compaction counters. jottrace events keeps its
explicit --limit / --all bounded-output contract.
jottrace doctor creates or checks the local data directory at ~/.jottrace
and reports whether its permissions are private. On Unix systems, the directory
is expected to use mode 0700; the SQLite database is expected to use mode
0600. It also reports unresolved ingest-error counts; use
jottrace doctor --details to show recent error details.
jottrace ingest scans these Claude install directories under HOME:
~/.claude~/.claude-code~/.claude-local~/.claude-m2~/.claude-zai
For each install directory, Jottrace reads Claude project session files under
projects/ plus UUID-named flat-root JSONL session files. Source files are
read-only inputs: Jottrace does not move, edit, or delete Claude artifacts.
It also scans these Codex install directories under HOME:
~/.codex~/.codex-local
For Codex, Jottrace reads session files under sessions/ and
archived_sessions/, using each file's committed session_meta id as the
stable session id.
For Gemini CLI, Jottrace reads chat JSON files under
~/.gemini/tmp/<project-or-hash>/chats/*.json, using each file's sessionId
as the stable session id and preserving the ordered messages[] entries.
It also scans Factory / Droid-style sessions under:
~/.factory/sessions
For Factory, Jottrace reads nested sessions/<encoded-cwd>/*.jsonl files,
uses the first committed session_start.id as the stable session id, and links
matching sibling .settings.json files through deterministic source metadata.
For OpenCode, Jottrace reads ~/.local/share/opencode/opencode.db, using
session.id as the stable session id. It preserves the session row plus
ordered message, part, and session-entry rows while ignoring non-authoritative
sidecar storage until a fixture proves it is reader-scope.
For Hermes, Jottrace reads ~/.hermes/state.db, using sessions.id as the
stable session id. It preserves each session row plus ordered messages rows,
links sessions.parent_session_id when the parent row exists, and ignores FTS
mirror tables.
The ingest command stores raw source event/message payloads and cheap
deterministic session metadata, then prints discovered file count, total
session/event counts, inserted event count, and unresolved ingest-error count.
Use jottrace ingest --details to include the database path.
jottrace status initializes ~/.jottrace/db.sqlite if needed and reports
session, event, and unresolved ingest-error counts. Use
jottrace status --details to include the database path and schema version.
jottrace compact reports eligible raw payload rows and estimated savings
without mutating the journal. Use jottrace compact --apply to rewrite
eligible rows as zstd and jottrace compact --vacuum to reclaim free SQLite
pages after applying. Use jottrace compact --details to include the database
path, before/after codec counts, skipped-row counters, stored byte totals, and
SQLite reclaimable-page counters.
jottrace web starts a read-only web UI bound to 127.0.0.1, prints the URL
and database path, and serves data from the existing SQLite journal. The UI lets
you filter sessions by source, cwd/path metadata, session id, and visible raw
payload text; selecting a session shows its preserved events and payload
previews. Unresolved ingest errors are shown on the page to help diagnose broken
source files.
The web UI is local-only. It does not mutate source files, delete journal rows, or send transcript data to external services. To request a fixed port instead of an available OS-assigned port:
jottrace web --port 7421For scripted smoke checks, jottrace web --once serves one request and exits.
To use a different journal directory:
JOTTRACE_HOME=/path/to/private/journal jottrace ingest
JOTTRACE_HOME=/path/to/private/journal jottrace status
JOTTRACE_HOME=/path/to/private/journal jottrace webTo move the journal between machines, use pack to bundle ~/.jottrace into
a single archive and settle to unpack it on the new machine:
jottrace pack # writes ./jottrace-pack-<utc>.tar.gz (mode 0600)
# copy the archive to the new machine (scp / AirDrop / USB / ...)
jottrace settle ./jottrace-pack-<utc>.tar.gz # restores ~/.jottrace and re-applies 0700/0600pack checkpoints the SQLite WAL into db.sqlite and holds the same lock as
ingest and compact so a concurrent writer cannot tear the snapshot. It
refuses to overwrite an existing output file. settle refuses to overwrite an
existing non-empty journal unless invoked with --force, and runs pending
schema migrations on the first DB open.
To update the installed binary in place:
jottrace updatejottrace upgrade is supported as an alias. The command downloads the matching
GitHub Release artifact for your OS and CPU, reports the current version,
target version, install path, and final result. When a newer artifact is
available, it replaces only the installed binary. It does not read or mutate
data under ~/.jottrace.
For deterministic release testing, jottrace update honors the same
JOTTRACE_VERSION and JOTTRACE_RELEASE_BASE_URL controls as install.sh.
If the update command is unavailable or fails before replacing the binary, rerun the installer fallback:
curl -fsSL https://raw.githubusercontent.com/season179/jottrace/main/install.sh | bashWhen Jottrace appears to be running from the install.sh location
(~/.local/bin/jottrace), normal commands quietly start a throttled background
update check. The foreground command is not delayed and does not print update
status. If the background check, download, validation, or replacement fails,
the existing binary is left in place.
To disable background auto-update checks for one command or shell session:
JOTTRACE_AUTO_UPDATE=0 jottrace statusTo disable them persistently, create ~/.jottrace/config.json:
{
"auto_update": false
}These opt-outs only affect background auto-updates. You can still run
jottrace update or jottrace upgrade manually.
cargo build
cargo testRun the development binary with:
cargo run -- doctor
cargo run -- ingest
cargo run -- status
cargo run -- compact
cargo run -- webJottrace uses CalVer in YY.M.PATCH form. For example, the first release in
May 2026 is v26.5.0; later releases in the same month increment the patch
segment, such as v26.5.11.
scripts/check-version.sh enforces that Cargo.toml uses this shape and that
release tags match the Cargo package version.
The release workflow runs on version tags and publishes the artifacts consumed
by install.sh.
git checkout main
git pull --ff-only
git tag v26.5.11
git push origin v26.5.11After the Release GitHub Action finishes, the install command above should
work end to end.