ctools
Try it now
uvx --from ctxttools cdir
uvx --from ctxttools ctools-web
Then install it
uv tool install ctxttools
ctools is a suite of simple tools for navigating through the sessions of the most popular LLM agents and coding tools. It allows you to search your history, transfer conversations, filter them, and even share them among machines and users.
It supports Claude Desktop, Claude Code, Codex, Pi, Hermes, Goose, Kilo, FreeBuff, Cline, omp, and OpenClaw.
You can use it from the terminal, from a small web dashboard, or from any AI coding agent (via an MCP server).
Here's an example:
I look for mentions of snake game in opencode using cgrep
$ cgrep "snake game" opencode opencode/ses_a1d1a5a4df984ee698cab4a7:1:user: make a simple snake game in python opencode/ses_a1d1a5a4df984ee698cab4a7:2:assistant: I'll make a terminal-based snake game using `curses` (standard library, no dependencies). opencode/ses_a1d1a5a4df984ee698cab4a7:3:assistant: Done — `snake.py` is a terminal snake game using Python's built-in `curses` module (no dependencies).
cool let's look at the status of that session using cdir
$ cdir -l opencode/ses_a1d1a5a4df984ee698cab4a7 ID NAME MODIFIED SIZE MSGS PATH ses_a1d1a5a4df984ee698cab4a7 make a simple snake game in python 2026-10-07 16:56 2.7 KB 3 /home/chris/.local/share/opencode 1 session(s)
Alright let's copy that session from opencode into pi!
$ ccopy opencode/ses_a1d1a5a4df984ee698cab4a7 pi Copied 3 message(s) from opencode/ses_a1d1a5a4df984ee698cab4a7 to a new pi session: e357f435-f813-463a-b313-f97f1051f3cb Resume it with: pi --session e357f435-f813-463a-b313-f97f1051f3cb
As you can see, these are unix-friendly tools using simple paradigms that you are already familiar with.
What it can do
| Capability | What you get |
|---|---|
| Discover | See every agent installed on your machine and how many sessions each holds. |
| Find | Search every session at once with grep-style regex, narrowed by agent, session glob, or role. |
| Read | Print a conversation as JSON (pipe it anywhere) or as a readable transcript. |
| Continue | Get the exact command to resume a session in its own tool, or open it in the web UI. |
| Copy | Copy a conversation into a new session in another tool, or the same tool on another machine. |
| Measure | See token usage per agent, per session, and per role. |
| Concepts | Pull out the intent of a session: its goal, its constraints, and what was decided. |
| Recover | List and restore the storage backups ctools takes before every local write. |
A quick tour
The overview: every tool ctools can see, with session counts and token totals, plus quick links into the most common actions:
Sessions: browse every conversation from any tool, sorted by recency. Click one to open it.
A conversation: the full message stream, with the original tool's resume command and copy-to-another-tool options.
Search: type a phrase and see every matching message across all tools.
Concepts: ask a session what it's about. ctools extracts the intent, constraints, and decisions so you can pick up where you left off without re-reading everything.
Install
Python 3.10+ is required.
uv tool install ctxttools # or: pip install ctxttools
That gives you the ctools command, a short command for each of its verbs,
and the dashboard and MCP server:
| Command | Purpose |
|---|---|
ctools |
The front door: ctools <verb> [args...]. Run ctools --help for the list. |
cdir, cgrep, ccat, cdu, ccopy, cextract, cconnect, crm, crecover |
Shortcuts for the verbs (cgrep is ctools grep). |
ctools-web |
The dashboard, same as ctools web. |
ctools-mcp |
The MCP server, same as ctools mcp. Needs the mcp extra. |
The MCP server's dependency is optional:
uv tool install "ctxttools[mcp]" # or: pip install "ctxttools[mcp]"
From a local checkout, uv keeps it editable:
uv tool install --editable ".[mcp]"
Heads up:
ctools-mcpneedsmcp<2(see mcp dependency below).
The CLI
ctools has one verb per job. Each verb is also installed as its own short
command, named c plus the verb, so ctools grep and cgrep are the same
program with the same flags. Use whichever you prefer: the long form is easier
to discover, and the short form is quicker to type.
$ ctools --help
usage: ctools <command> [args...]
query:
dir list agents and sessions (cdir)
grep search session content (cgrep)
cat print a session (ccat)
du context usage per session (cdu)
transform:
copy copy a session to another agent (ccopy)
extract extract concepts from a session (cextract)
connect pipe concepts between sessions (cconnect)
rm cut sections out of a session (crm)
recover restore from a backup (crecover)
long-running:
web run the web dashboard (ctools-web)
mcp run the MCP server (ctools-mcp)
Run 'ctools <command> --help' for a command's options.
Each verb has its own page in docs/: dir,
grep, cat, du,
copy, extract,
connect, rm, and
recover. Sessions are addressed as agent/session_id
throughout.
Discover your agents and sessions
ctools dir # every known agent, and whether it's installed
ctools dir opencode # that agent's sessions, and the command that resumes one
ctools dir -l opencode # with modified time, size, message count, path
ctools dir . # sessions that ran in this directory, across all agents
ctools dir opencode/ses_abc # one session's row
Find a session
grep works the way grep does, over conversation content instead of files.
ctools grep "bug report" # every installed agent
ctools grep -i "deploy" claude-code # one agent
ctools grep -C 2 "flaky test" opencode # with context
ctools grep -l "parser" pi # just the session ids
ctools grep --user "refactor" # only what you typed
ctools grep --hosts "mcp config" # also the hosts in ctools.toml
Read a session
ctools cat opencode/ses_abc # JSON list of {role, content}
ctools cat --text opencode/ses_abc # a readable transcript
ctools cat ssh://me@box/pi/<id> # a session on another machine
Copy a session to another tool
copy creates a new session in the destination. The source is never
touched, and ctools prints the command that resumes the copy.
ctools copy opencode/ses_abc claude-code # into another tool
ctools copy opencode/ses_abc codex --dry-run # preview first
ctools copy opencode/ses_abc ssh://me@box/codex # into a tool on another machine
ctools copy opencode/ses_abc ssh://me@box/ # into opencode on that machine
ctools copy ssh://me@box/pi/<id> claude-code # pull one in from another machine
The remote side doesn't need ctools installed; plain ssh and tar will do.
See docs/ccopy.md for how that works and where the new
session lands.
Token usage
ctools du # total across all agents
ctools du opencode # sessions by token count
ctools du opencode/ses_abc # breakdown by role
The web dashboard
ctools web # opens at http://127.0.0.1:8765
ctools web --port 9000 # a different port
ctools-web is the same command. The dashboard is a read-mostly surface over
the same data the CLI uses. You can:
- Browse and search sessions (the "Conversation" view mirrors the CLI).
- Copy a session to another tool right from the UI.
- Export/download a session.
- Run concept extraction on a session (with optional LLM-backed strategies and filters).
It binds to 127.0.0.1 only by default, so it's not exposed to your
network. Use --host to change that deliberately.
Concepts: extract the intent of a session
A raw session is thousands of tokens. Concepts distills it into the few things that matter for picking it back up: the goal, the constraints, and what was decided.
ctools extract @<agent>/<session-id> # or: cextract @<agent>/<session-id>
Concepts are extracted one of three ways. Regex is the default; -s and -F
select the others:
- Regex (default): built-in patterns for goal, decision, constraint, and preference. No setup.
- LLM strategy: you define a chunking strategy that an LLM applies to the session. Best for richer, contextual extraction.
- Filter: narrow the regex/LLM output with a rule (drop boilerplate, keep only certain types, etc.).
Strategies and filters are stored as JSON config files that ctools reads at runtime, in the config dir (see below). Create them in the dashboard (the Concepts tab) or by hand.
Where ctools keeps its config. Config and data live in a per-user
directory resolved via platformdirs (no hand-rolled platform checks):
- Linux:
~/.config/ctools/(config),~/.local/share/ctools/(data) - macOS:
~/Library/Application Support/ctools/(the macOS convention) - Windows:
%APPDATA%\ctools\(config),%LOCALAPPDATA%\ctools\(data)
Set $CTOOLS_CONFIG (and $CTOOLS_DATA) to relocate. This holds
resume-commands.json, strategies/, filters/, and the general
ctools.toml config — one file, multiple sections. The first section,
[hosts], lists the machines ctools grep --hosts searches too:
# ~/.config/ctools/ctools.toml
[hosts]
fatty = "ssh://bobby@fatty.local"
workie = "ssh://10.0.0.4"
Each value is an ssh://[user@]host[:port] reference (the same form ccat
and ccopy use for a remote side), so the host may be a ~/.ssh/config
alias. A missing/malformed config never breaks a search — it just means
"local only".
The dashboard shows the full extraction pipeline (conversation → extraction → filter → concepts) so you can see exactly what was kept and why.
MCP server
The MCP server exposes the same capabilities to any MCP-capable coding agent
(Pi, Claude, OpenCode, etc.). It needs the mcp extra (see Install).
ctools mcp # run the server on stdio (same as ctools-mcp)
Install and register with Pi
ctools-mcp install
If no working ctxttools[mcp] install is found, this installs one with
uv tool. It then registers the server in ~/.pi/agent/mcp.json. Verify with:
pi mcp list # "ctools-mcp … connected"
ctools-mcp uninstall removes the entry again (--all also removes it from
Claude Code's and opencode's configs).
Manual registration (any host)
If you'd rather wire it up yourself, print-config emits the mcpServers JSON
snippet:
ctools-mcp print-config
Add that to your host's MCP config. The server is started with
python -m ctools.ctools_mcp from the install environment.
Tools exposed
| Tool | What it does |
|---|---|
list_agents |
Agents available and whether they're installed. |
list_sessions |
Recent sessions for one agent. |
search_sessions |
Find sessions by pattern or phrase. |
export_session |
Get the messages of a session. |
extract_concepts |
Extract concepts from a session. |
get_session_concepts |
Get a session's concepts, optionally of one type. |
copy_concepts |
Copy extracted concepts into a destination session. |
MCP dependency
ctools-mcp pins mcp>=1.2,<2.0. The mcp package 2.x renamed
FastMCP to MCPServer, which breaks the v1 API ctools uses. If a fresh
install pulls mcp>=2 and ctools-mcp won't start, pin the major version
(pip install "mcp<2"); the released package already does this.
The agents ctools knows about
| Name | Tool | Storage |
|---|---|---|
claude |
Claude Desktop | JSON |
claude-code |
Claude Code CLI | JSONL |
codex |
OpenAI Codex CLI | JSONL |
pi |
Pi coding agent | JSONL |
omp |
omp (oh-my-pi) | JSONL |
opencode |
OpenCode CLI | SQLite |
kilo |
Kilo CLI | SQLite |
goose |
Goose AI agent | SQLite |
hermes |
Hermes agent | SQLite |
openclaw |
OpenClaw | SQLite |
cline |
Cline | JSON |
freebuff |
Freebuff | JSON |
An agent is "installed" if ctools can find its session directory (or DB
file); ctools dir shows which are found and where. Only claude-code,
opencode, kilo, codex, and pi can be a copy destination.
How the data is handled
- Read-only by default.
dir,grep,cat,du, the MCP read tools, and the dashboard's read paths never modify your session files. - Writes are explicit.
copywrites a new session and never touches the source.extractandconnectwrite only when you name a session as the destination, andrmonly to the session you name. - Backed up first. Before a local
copywrites, it snapshots the destination agent's storage and restores it automatically if the write goes wrong.ctools recoverlists and restores those snapshots. - Local unless you say otherwise. The dashboard binds to
127.0.0.1, and the MCP server reads your local storage. Data only crosses the network when you name anssh://host or passgrep --hosts, and then only over your own ssh.
Development
git clone https://github.com/day50-dev/ctools
cd ctools
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
python -m pytest
The code is deliberately simple: each agent adapter is a class in
ctools/agents.py, each verb is one module (ctools/cgrep.py, …), and
ctools/dispatch.py routes ctools <verb> to them. The CLI, dashboard, and
MCP layers are thin over the shared ctools.agents registry.
License
Metadata
Release files for ctxttools 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ctxttools-0.4.0.tar.gz | 159.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ctxttools-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 327.0 kB
Release files / ctxttools-0.4.0.tar.gz
| Download URL | ctxttools-0.4.0.tar.gz |
|---|---|
| Size | 159.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
956cfc5f1ea7a58f3f9b41a15b03fa573ca4f7597dd73f3cfaa9dbd55d302995
|
|
BLAKE2b-256 checksum How to use checksums |
654b2c32310eb51f26673d4de0403be8ec15b78d16a836dfd5e10d52a972c516
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.15
|
Release files / ctxttools-0.4.0-py3-none-any.whl
| Download URL | ctxttools-0.4.0-py3-none-any.whl |
|---|---|
| Size | 167.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2eab24af2e755a9c0b7a58671c5a110303db3b80709c699efdd4df3409f1c26f
|
|
BLAKE2b-256 checksum How to use checksums |
fa08b88a8edb2272cc6968dbc8dfc1aaeae0b5f634f2f9cd64fd9e3fcbdfb2d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.15
|
Security for ctxttools 0.4.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.