Skip to main content

trajectoriz

Library and CLI to search, browse, and analyze past agent trajectory files. Supports Claude Code, Codex, OpenCode, Copilot, Hermes and more.

Installation

pip install trajectoriz

Features

  • Unified record API — iterate and parse sessions from Claude Code, Codex, Copilot, OpenCode, Hermes and more through a single iter_records() / parse_record() interface
  • Search — metadata by default (no parsing), --content for full-content search across messages, tool calls and results with three backends (sqlite / grep / recoll); space-separated words are AND, \| is OR
  • HTML export — trajectoriz-cli show <id> --html renders a trajectory as a self-contained HTML page
  • ATIF export — trajectoriz.atif translates parsed trajectories to ATIF v1.7 (Claude Code, Codex, Copilot, agentknit, or any iter_records()/parse_record() result)
  • Memory filesystem — trajectoriz-cli memory <mountpoint> mounts a read-only FUSE view where every local trajectory is one ATIF JSON file
  • Leaked-secret scan — trajectoriz-cli secrets searches every trajectory for the verbatim value of every OS keyring secret, and reports hits redacted, by fingerprint

trajectoriz-cli search lets you find past agent sessions — by what started them, or with --content, by everything that was discussed, run and edited inside them.

By default it searches first messages, IDs and agent names, which needs no trajectory parsing and answers the common question ("which session was that?") immediately. --content searches every step instead: slower, exhaustive.

# Locate a session (default: first messages and metadata)
trajectoriz-cli search "refactor auth"

# Search inside every step: tool calls, their results, all messages
trajectoriz-cli search "salary KTH overhead" --content

# AND semantics: all words must appear
trajectoriz-cli search "telegram send_message bot_token" --content

# OR semantics: use \| between alternatives
trajectoriz-cli search "pytest\|unittest" --content

# Restrict to the current project
trajectoriz-cli search "fix login bug" --local

With --content, results are a paginated Markdown table with trajectory ID, agent, date, step number, and a context snippet:

## Search: `salary KTH overhead` — 8 match(es)

| ID           | Agent  | Date       | Step | Snippet                                              |
|---|---|---|---|---|
| `cl-4d72f7b5`| claude | 2026-05-15 | 73   | …kth_salary = ws["E8"].value  # KTH  Direkt lön…   |
| `cl-4ef313e6`| claude | 2026-05-04 | 93   | …Organization: KTH Royal Institute of Technology…  |

Then inspect any result:

trajectoriz-cli show cl-4d72f7b5 --step 73

Search backends:

Backend Setup Semantics
sqlite (default) builds itself; trajectoriz-cli refresh --no-recoll to rebuild whole-word FTS5
grep none substring, in-process, always fresh
recoll trajectoriz-cli refresh --no-sqlite full Xapian index
trajectoriz-cli search "openssl handshake" --content --backend sqlite
trajectoriz-cli search "openssl handshake" --content --backend recoll

CLI

# List trajectories in the current directory
trajectoriz-cli list

# Show a trajectory (markdown, paginated)
trajectoriz-cli show cl-1234abcd
trajectoriz-cli show cl-1234abcd --last         # jump to the last page
trajectoriz-cli show cl-1234abcd --step 42      # jump to the page containing step 42
trajectoriz-cli show cl-1234abcd --html > out.html   # self-contained HTML export

# Trajectory metadata (JSON)
trajectoriz-cli info cl-1234abcd

# Blame a file — every agent edit in chronological order with line deltas
trajectoriz-cli blame src/main.py

# Aggregate statistics across all trajectories
trajectoriz-cli stats --all

# Aggregate shell-invoked programs across a repo
trajectoriz-cli advanced tools --dir /path/to/repo

# Check whether any keyring secret leaked into a trajectory
trajectoriz-cli secrets

Leaked secrets

trajectoriz-cli secrets answers one question: has any secret in my OS keyring ever been written in cleartext into an agent trajectory? Agents print environment variables, cat config files and echo tokens into shell commands; all of it is kept forever in the trajectory store. The keyring is the ground truth of what a secret is, so there are no entropy or pattern heuristics here — every keyring value is searched for verbatim.

trajectoriz-cli secrets                     # scan every local trajectory
trajectoriz-cli secrets --dir /path/to/repo # only this repo's trajectories
trajectoriz-cli secrets --group-by trajectory
trajectoriz-cli secrets --json
## Leaked secrets: 2 of 297 keyring secrets appear in cleartext in 4 trajectory(ies)

### Sent to

| Model endpoint          | Distinct secrets |
|---|---|
| claude-sonnet-5         | 2 |
| glm-5.3 (api.z.ai)      | 1 |

### `github token` (fp `a1b2c3d4e5f6`, 40 chars, org.freedesktop.Secret.Generic)

| Agent  | Trajectory    | Date       | Step | Sent to         | Context                               |
|---|---|---|---|---|---|
| claude | `cl-4d72f7b5` | 2026-05-15 | 73   | claude-sonnet-5 | …export GH_TOKEN=«REDACTED:40 chars»… |

A secret in a trajectory step is a secret that was in the context window, so the report names the destination: the model, and the endpoint host when the log records it. That is the question worth answering, since a local file that never left the machine is a smaller problem than a credential handed to a third party.

Secret values never appear in the output: a finding is identified by its keyring label and a SHA-256 fingerprint, and the match context is redacted — a report that quoted the secret would just be the next leak. Exit status is 1 when something leaked, 0 when nothing did, so it works as a cron or pre-commit check.

Coverage is the same store as search: every trajectory file plus the SQLite session stores (OpenCode, Copilot, Hermes, Codex), scanned as text so nothing hides in a DB page. For agentknit sessions the *_messages.json payload written beside the journal is scanned too: that file is the request as it was posted to the endpoint, so it is the direct evidence of what left the machine. Multi-line secrets (PEM keys) are matched on their longest line and flagged as partial.

Two things keep the report honest rather than noisy. Keyring values shorter than --min-length (default 8) are skipped, and a value that turns up in more than --max-files trajectories (default 25) is listed separately as ordinary text — a dictionary-word password matches half the corpus and means nothing. Both are reported as counts, so nothing is dropped silently; --max-files 0 removes the cap. Locked keyring collections are reported as unscanned rather than ignored.

Memory filesystem

trajectoriz-cli memory mounts a read-only FUSE filesystem where every local trajectory shows up as an ATIF v1.7 JSON file — so any tool that reads files (grep, an agent's own file tools, etc.) can browse past sessions directly, without going through this CLI.

The idea behind it: Exposing Past Sessions as Memory for Coding Agents.

pip install trajectoriz[fuse]   # requires libfuse (Linux) or macFUSE (macOS)

trajectoriz-cli memory                          # mounts ./memory (created if missing), daemonizes
trajectoriz-cli memory ~/mnt/traj-memory        # or mount elsewhere
trajectoriz-cli memory --foreground             # or run attached

ls memory
cat memory/README.md                            # what the directory is, in the directory
cat memory/2026-05-15_claude_cl-4d72f7b5.atif.json

trajectoriz-cli memory --unmount                # unmount (or: fusermount -u memory)

Use --dir PATH to expose a different repo's trajectories instead of the current directory's. If the mountpoint sits inside a git repo, it's added to that repo's .gitignore automatically.

The mount is built for tools that walk and read files: one store scan serves the whole directory listing (refreshed every couple of seconds, so new sessions still show up), each trajectory's ATIF payload is rendered once per open and then served from memory, and a file's size is memoized on disk so ls -l, find and git can stat the whole directory without rendering anything. Reading every file in a mount of 30 trajectories takes ~0.1s.

Two rules keep the mount from taking the machine with it if something goes wrong:

  • Store scans never descend into a FUSE mount. They would otherwise: ~/.local/share/agent_probe is commonly a symlink into a repo, and that repo can hold a memory mount of its own — so a daemon would end up sending itself a request from inside a request.
  • No request waits without a deadline. The kernel holds a mount's inode lock while a handler runs, so a handler that blocks forever leaves every process that touches the directory in uninterruptible sleep — D state, which SIGKILL cannot end. A scan runs off the request path and a request waits at most 10s for it, serving the previous listing after that.

If a mount ever stops responding — a killed or wedged daemon leaves the mountpoint attached but unserviced, which hangs anything that walks the tree it sits in — recover it with:

trajectoriz-cli memory --unmount ./memory       # unmounts lazily, and aborts the
                                                # FUSE connection if it is wedged,
                                                # which is what frees processes
                                                # already stuck on it

To clear several at once — or a mount left over from an older version — scripts/fuse-abort.sh lists every FUSE connection with the mount it serves and the number of requests stuck on it, and aborts the bricked ones. It is a dry run until passed --go, and never touches connections matching $KEEP (portals, gvfs, AppImages, sshfs and friends), because aborting a healthy connection breaks whatever uses it.

Python API

from trajectoriz import iter_records, parse_record

# Iterate sessions across all supported agents (Claude, Codex, Copilot, OpenCode, …)
for record in iter_records():
    print(record.agent, record.timestamp[:10], record.first_msg[:60])

# Iterate sessions for the current project only
for record in iter_records(cwd="/path/to/repo"):
    trajectory = parse_record(record)
    if trajectory is not None:
        print(f"{record.agent}: {len(trajectory.steps)} steps, {trajectory.total_tokens} tokens")

License

MIT

Metadata

Release files for trajectoriz 0.10001.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for trajectoriz 0.10001.0
File Interpreter ABI Platform
trajectoriz-0.10001.0-py3-none-any.whl Python 3 none any Details

Release files / trajectoriz-0.10001.0-py3-none-any.whl

Download URL trajectoriz-0.10001.0-py3-none-any.whl
Size 68.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e92e5e2a0d9193f55cb363ab17eb2e4038c44d4cb969b5d3efeaab8fcdc473bd
BLAKE2b-256 checksum
How to use checksums
e3f8c00d06c5e4cb35359e4d98311ae99ab673b8ad84d985561cc13fa4fa9b51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.10001.0 This release

1 release file

0.54.0

1 release file

0.53.0

1 release file

0.52.0

1 release file

0.51.0

1 release file

0.50.0

1 release file

0.49.0

1 release file

0.48.0

1 release file

0.47.0

1 release file

0.46.0

1 release file

0.45.0

1 release file

0.44.0

1 release file

0.43.0

1 release file

0.42.0

1 release file

0.41.0

1 release file

0.40.0

1 release file

0.39.0

1 release file

0.38.0

1 release file

0.37.0

1 release file

0.36.0

1 release file

0.35.0

1 release file

0.34.0

1 release file

0.33.0

1 release file

0.32.0

1 release file

0.31.0

1 release file

0.30.0

1 release file

0.29.0

1 release file

0.28.0

1 release file

0.27.0

1 release file

0.26.0

1 release file

0.25.0

1 release file

0.24.0

1 release file

0.23.0

1 release file

0.22.0

1 release file

0.21.0

1 release file

0.20.0

1 release file

0.19.0

1 release file

0.18.0

1 release file

0.17.0

1 release file

0.16.0

1 release file

0.15.0

1 release file

0.14.0

1 release file

0.13.0

1 release file

0.12.0

1 release file

0.11.0

1 release file

0.10.0

1 release file

0.9.0

1 release file

0.8.0

1 release file

0.7.0

1 release file

0.6.0

1 release file

0.5.0

1 release file

0.4.0

1 release file

0.3.0

1 release file

0.2.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page