ctxttools 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ctxttools-0.2.0/ctxttools.egg-info → ctxttools-0.3.0}/PKG-INFO +86 -38
- {ctxttools-0.2.0 → ctxttools-0.3.0}/README.md +85 -36
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/agents.py +791 -43
- ctxttools-0.3.0/ctools/backup.py +454 -0
- ctxttools-0.3.0/ctools/ccat.py +260 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/cconnect.py +55 -32
- ctxttools-0.3.0/ctools/ccopy.py +652 -0
- ctxttools-0.3.0/ctools/cdir.py +708 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/cdu.py +50 -26
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/cextract.py +111 -41
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/cgrep.py +176 -57
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/cli.py +37 -25
- ctxttools-0.3.0/ctools/crecover.py +234 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/crm.py +58 -38
- ctxttools-0.3.0/ctools/filterlib.py +432 -0
- ctxttools-0.3.0/ctools/testing.py +61 -0
- ctxttools-0.3.0/ctools/webui.py +1811 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0/ctxttools.egg-info}/PKG-INFO +86 -38
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctxttools.egg-info/SOURCES.txt +5 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctxttools.egg-info/entry_points.txt +3 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctxttools.egg-info/requires.txt +0 -1
- {ctxttools-0.2.0 → ctxttools-0.3.0}/pyproject.toml +4 -2
- ctxttools-0.2.0/ctools/ccopy.py +0 -317
- ctxttools-0.2.0/ctools/cdir.py +0 -424
- ctxttools-0.2.0/ctools/filterlib.py +0 -116
- {ctxttools-0.2.0 → ctxttools-0.3.0}/LICENSE.MIT +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/__init__.py +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/ctools_mcp.py +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/lib.py +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/log.py +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctools/strategy.py +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctxttools.egg-info/dependency_links.txt +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/ctxttools.egg-info/top_level.txt +0 -0
- {ctxttools-0.2.0 → ctxttools-0.3.0}/setup.cfg +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ctxttools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: CLI tools for LLM conversations
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
7
|
License-File: LICENSE.MIT
|
|
8
|
-
Requires-Dist: typer>=0.9.0
|
|
9
8
|
Requires-Dist: rich>=13.0.0
|
|
10
9
|
Requires-Dist: tiktoken>=0.5.0
|
|
11
10
|
Requires-Dist: structlog>=24.0
|
|
@@ -18,44 +17,45 @@ Dynamic: license-file
|
|
|
18
17
|
<p align="center">
|
|
19
18
|
<img width="500" alt="ctools" src="https://github.com/user-attachments/assets/ee781bbe-6364-44ed-be2d-72114f1e6d8a" /><br/>
|
|
20
19
|
<a href=https://pypi.org/project/ctxttools><img src=https://badge.fury.io/py/ctxttools.svg/></a>
|
|
20
|
+
<br/><br/><b>Try it now</b><br/>
|
|
21
|
+
<code>uvx --from ctxttools cdir</code>
|
|
22
|
+
<br/><br/><b>Then install it</b><br/>
|
|
23
|
+
<code>uv tool install ctxttools</code>
|
|
21
24
|
</p>
|
|
22
25
|
|
|
23
26
|
------
|
|
27
|
+
**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.
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
It supports [Claude Desktop](https://claude.com/download), [Claude Code](https://github.com/anthropics/claude-code), [Codex](https://github.com/openai/codex), [Pi](https://github.com/earendil-works/pi), [Hermes](https://github.com/NousResearch/hermes-agent), [Goose](https://github.com/aaif-goose/goose), [Kilo](https://github.com/Kilo-Org/kilocode), [FreeBuff](https://github.com/CodebuffAI/freebuff), [Cline](https://github.com/cline/cline), [omp](https://github.com/can1357/oh-my-pi), and [OpenClaw](https://openclaw.ai/).
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
Here's an example:
|
|
28
32
|
|
|
33
|
+
> I look for mentions of snake game in opencode using cgrep
|
|
34
|
+
<pre>
|
|
35
|
+
$ <b>cgrep</b> "snake game" opencode
|
|
36
|
+
opencode/ses_a1d1a5a4df984ee698cab4a7:1:user: make a simple snake game in python
|
|
37
|
+
opencode/ses_a1d1a5a4df984ee698cab4a7:2:assistant: I'll make a terminal-based snake game using `curses` (standard library, no dependencies).
|
|
38
|
+
opencode/ses_a1d1a5a4df984ee698cab4a7:3:assistant: Done — `snake.py` is a terminal snake game using Python's built-in `curses` module (no dependencies).
|
|
39
|
+
</pre>
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
> cool let's look at the status of that session using cdir
|
|
42
|
+
<pre>
|
|
43
|
+
$ <b>cdir</b> -l opencode/ses_a1d1a5a4df984ee698cab4a7
|
|
44
|
+
ID NAME MODIFIED SIZE MSGS PATH
|
|
45
|
+
ses_a1d1a5a4df984ee698cab4a7 make a simple snake game in python 2026-10-07 16:56 2.7 KB 3 /home/chris/.local/share/opencode
|
|
31
46
|
|
|
32
|
-
|
|
47
|
+
1 session(s)
|
|
48
|
+
</pre>
|
|
33
49
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
opencode/ses_000d460f:34:assistant: Found it. Root cause: `_check_host` (graflex/__init__.py:128) tries `http`, and …
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
No agent argument? It searches **every installed agent at once** — Claude Code, Opencode, Kilo, Codex, Pi, Goose, Hermes, Cline, omp, and Freebuff, all in one pass. That last line is the root-cause analysis you wrote six months ago and would never have found again.
|
|
42
|
-
|
|
43
|
-
### 2. `ccopy` — move your project from one tool to another
|
|
44
|
-
|
|
45
|
-
Switched from opencode to Claude Code mid-project? You don't have to start from zero. Copy the whole conversation — context, decisions, the lot — into a fresh session in the other tool:
|
|
46
|
-
|
|
47
|
-
```shell
|
|
48
|
-
$ ccopy opencode/ses_abc123 claude-code
|
|
49
|
-
Copied 128 message(s) from opencode/ses_abc123 to a new claude-code session: 1a2b3c
|
|
50
|
+
> Alright let's copy that session from opencode into pi!
|
|
51
|
+
<pre>
|
|
52
|
+
$ <b>ccopy</b> opencode/ses_a1d1a5a4df984ee698cab4a7 pi
|
|
53
|
+
Copied 3 message(s) from opencode/ses_a1d1a5a4df984ee698cab4a7 to a new pi session: e357f435-f813-463a-b313-f97f1051f3cb
|
|
50
54
|
Resume it with:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Your work travels with you. The source is never touched, so it's a true copy. And when the destination is on another machine, it's just `ccopy opencode/ses_abc123 ssh://chris@remote/codex` — it runs over your normal ssh.
|
|
55
|
+
pi --session e357f435-f813-463a-b313-f97f1051f3cb
|
|
56
|
+
</pre>
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
**Works with the agents you already use:** Claude Desktop, Claude Code, Opencode, Kilo, Codex, Pi, Goose, Hermes, Cline, omp (oh-my-pi), and Freebuff (Codebuff).
|
|
58
|
+
As you can see, these are unix-friendly tools using simple paradigms that you are already familiar with.
|
|
59
59
|
|
|
60
60
|
## Tools
|
|
61
61
|
|
|
@@ -63,13 +63,21 @@ ctools is a set of GNU-style tools for the history your coding agents leave behi
|
|
|
63
63
|
|------|--------------|------|
|
|
64
64
|
| `cgrep` | Search conversation content (grep across every agent) | [docs/cgrep.md](docs/cgrep.md) |
|
|
65
65
|
| `cdir` | List sessions (ls for your history) | [docs/cdir.md](docs/cdir.md) |
|
|
66
|
+
| `ccat` | Print one or more conversations (cat for your history) | [docs/ccat.md](docs/ccat.md) |
|
|
66
67
|
| `ccopy` | Copy a whole conversation from one agent to a new session in another | [docs/ccopy.md](docs/ccopy.md) |
|
|
67
68
|
| `cextract` | Extract concepts from a session into files, and inject them back | [docs/cextract.md](docs/cextract.md) |
|
|
68
69
|
| `cconnect` | Live concept pipelines between sessions | [docs/cconnect.md](docs/cconnect.md) |
|
|
69
70
|
| `cdu` | Token usage per session (du for context windows) | [docs/cdu.md](docs/cdu.md) |
|
|
70
71
|
| `crm` | Remove concepts from a session (mdel) | [docs/crm.md](docs/crm.md) |
|
|
72
|
+
| `ctools-web` | Browser dashboard for all of the above | [Web dashboard](#web-dashboard) |
|
|
73
|
+
|
|
74
|
+
Every tool takes `--version`. The session-mover tools (`ccopy`, `cextract`, `cconnect`, `crm`) also take `--verbose` for structured logging. Each tool's full flag reference, output formats, and examples live in its `docs/` page — the table above is just the 30-second version.
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
## The problem
|
|
77
|
+
|
|
78
|
+
You talk to LLMs all day. Over weeks, you build up a set of constraints, preferences, and goals. These live in your conversations as system messages. They are valuable. They are also trapped.
|
|
79
|
+
|
|
80
|
+
Say you have been working with opencode for a month. You have refined your coding style through dozens of sessions. Now you start a new Claude Code project and you want those same preferences. You could copy them by hand. Or you could `cextract` them out and `cextract` them back in, or copy the whole conversation across with `ccopy`. Either way, your memory travels with you.
|
|
73
81
|
|
|
74
82
|
## How it works
|
|
75
83
|
|
|
@@ -80,6 +88,8 @@ Two stages: **extraction** and **filtering**.
|
|
|
80
88
|
- A **strategy** extracts concepts from a conversation. It defines what counts as a concept and how to find it: regex patterns, LLM extraction, whatever. Different strategies produce different ontologies from the same conversation, because context is contestable.
|
|
81
89
|
- A **filter** selects which extracted concepts reach a destination. It's a binary classifier: pass through or filter out. One concept list can fan out to many destinations, each with its own filter. A coding agent gets coding preferences, a security agent gets security constraints, a PM agent gets goals, all from the same source.
|
|
82
90
|
|
|
91
|
+
A filter can be as simple as a type or substring match, or as smart as a **decision model** — a small local classifier that scores each concept and lets it through only when confident. Point a filter at a model and you get *semantic* filtering with no free text to parse: ask "is this concept about security?" and gate on the answer. The model is asked either through Ollama's typed `/v1/systemone` endpoint (calibrated probabilities, the home of decision-dedicated models) or through any OpenAI-compatible `/v1/chat/completions` server (portable, lettered decision-task prompt) — one `endpoint` field decides. See [cextract](docs/cextract.md) for the decision-model and JSON-RPC filter configs.
|
|
92
|
+
|
|
83
93
|
```mermaid
|
|
84
94
|
graph LR
|
|
85
95
|
SRC["source session"] --> STRAT["strategy<br/>(extraction)"]
|
|
@@ -92,13 +102,7 @@ graph LR
|
|
|
92
102
|
FC --> DEST_C["destination C"]
|
|
93
103
|
```
|
|
94
104
|
|
|
95
|
-
Context windows are endpoints: opencode, Claude Code, Codex, Pi. They all speak different protocols, but they all consume the same packets. See [cextract](docs/cextract.md) for the concept packet format, strategies, and the filter (JSON-RPC)
|
|
96
|
-
|
|
97
|
-
## The problem
|
|
98
|
-
|
|
99
|
-
You talk to LLMs all day. Over weeks, you build up a set of constraints, preferences, and goals. These live in your conversations as system messages. They are valuable. They are also trapped.
|
|
100
|
-
|
|
101
|
-
Say you have been working with opencode for a month. You have refined your coding style through dozens of sessions. Now you start a new Claude Code project and you want those same preferences. You could copy them by hand. Or you could `cextract` them out and `cextract` them back in, or copy the whole conversation across with `ccopy`. Either way, your memory travels with you.
|
|
105
|
+
Context windows are endpoints: opencode, Claude Code, Codex, Pi. They all speak different protocols, but they all consume the same packets. See [cextract](docs/cextract.md) for the concept packet format, strategies, and the filter configs (decision model and JSON-RPC).
|
|
102
106
|
|
|
103
107
|
## Supported endpoints
|
|
104
108
|
|
|
@@ -115,6 +119,12 @@ Say you have been working with opencode for a month. You have refined your codin
|
|
|
115
119
|
| cline | JSON (`~/.cline/data/tasks/`) |
|
|
116
120
|
| omp | JSONL (`~/.omp/agent/sessions/`, tree journal) |
|
|
117
121
|
| freebuff | JSON (`~/.config/<codebuff>/projects/`) |
|
|
122
|
+
| openclaw | SQLite (per-agent, `~/.openclaw/agents/`, `OPENCLAW_STATE_DIR`) |
|
|
123
|
+
|
|
124
|
+
OpenClaw is a **personal assistant** rather than a terminal coding agent, so it
|
|
125
|
+
runs in a local Gateway that owns its store; ctools reads and exports its
|
|
126
|
+
sessions but does not seed new ones (the store has canonical-index and integrity
|
|
127
|
+
checks that a raw insert cannot satisfy).
|
|
118
128
|
|
|
119
129
|
Run `cdir` to see which endpoints are found on your system and where they store data.
|
|
120
130
|
|
|
@@ -157,6 +167,37 @@ Add to your MCP config:
|
|
|
157
167
|
}
|
|
158
168
|
```
|
|
159
169
|
|
|
170
|
+
## Web dashboard
|
|
171
|
+
|
|
172
|
+
Prefer a mouse to a man page? ctools ships a browser dashboard — a small local
|
|
173
|
+
web server (Python stdlib only, no web dependencies) with the same library
|
|
174
|
+
underneath. Same on macOS, Windows, and Linux:
|
|
175
|
+
|
|
176
|
+
```sh
|
|
177
|
+
$ ctools-web # or: python -m ctools.webui
|
|
178
|
+
ctools 0.2.1 dashboard: http://127.0.0.1:8765
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Open the URL. You get four views:
|
|
182
|
+
|
|
183
|
+
- **Overview** — every supported agent, installed or not, with session counts
|
|
184
|
+
and total tokens, and a jump into each agent's sessions.
|
|
185
|
+
- **Search** — `cgrep` in the browser: one regex box, per-agent chips, live
|
|
186
|
+
matches; click any match to open that conversation.
|
|
187
|
+
- **Sessions** — `cdir` for one agent: newest, largest, or by token usage.
|
|
188
|
+
- **Conversation** — `ccat` with the source session's messages, token usage,
|
|
189
|
+
the resume command, concept extraction (`cextract`), a markdown export,
|
|
190
|
+
and **Copy** — `ccopy` to any other installed agent, which creates a fresh
|
|
191
|
+
session there (source untouched) and tells you how to resume it.
|
|
192
|
+
|
|
193
|
+
The server binds to `127.0.0.1` by default, so nothing is exposed to your
|
|
194
|
+
network unless you pass `--host 0.0.0.0`. There is one write operation:
|
|
195
|
+
Copy. Everything else is read-only against the agents' storage.
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
ctools-web --port 9000
|
|
199
|
+
```
|
|
200
|
+
|
|
160
201
|
## Installation
|
|
161
202
|
|
|
162
203
|
```sh
|
|
@@ -179,7 +220,7 @@ from ctools.lib import get_formatter
|
|
|
179
220
|
from ctools.cgrep import grep_session
|
|
180
221
|
from ctools.cextract import extract_concepts_from_messages
|
|
181
222
|
from ctools.cdu import count_tokens, get_session_tokens
|
|
182
|
-
from ctools.filterlib import JSONRPCFilter, load_filter
|
|
223
|
+
from ctools.filterlib import JSONRPCFilter, SystemOneFilter, load_filter
|
|
183
224
|
from ctools.log import configure_logging, get_logger
|
|
184
225
|
```
|
|
185
226
|
|
|
@@ -204,6 +245,13 @@ from ctools.agents import OpencodeAgent
|
|
|
204
245
|
agent = OpencodeAgent('/backup/opencode')
|
|
205
246
|
```
|
|
206
247
|
|
|
248
|
+
## Where to go next
|
|
249
|
+
|
|
250
|
+
- **Per-tool reference** — the [Tools](#tools) table above links to a `docs/` page for each command: every flag, output format, and a worked example.
|
|
251
|
+
- **The interchange format** — how a conversation becomes a portable, lossless envelope and back, and why 2N agents compose into N² transfers. See [interchange](docs/interchange.md).
|
|
252
|
+
- **Filtering with decision models** — the full decision-model and JSON-RPC filter configs, with live examples. See [cextract](docs/cextract.md#filters) and [cconnect](docs/cconnect.md#filter-configuration).
|
|
253
|
+
- **Adding an endpoint** — one `Agent` subclass plus a line in `AGENT_CLASSES`. See [Supported endpoints](#supported-endpoints).
|
|
254
|
+
|
|
207
255
|
## Credits
|
|
208
256
|
|
|
209
257
|
ctools was extracted from [Gab n' Go](https://github.com/day50-dev/gabngo). It's named after [GNU mtools](https://www.gnu.org/software/mtools/), which does the same thing for DOS floppies — because your context window is about the size of a DOS-floppy. The flag habits are GNU's too: `--version`, `-1`, `-S`, `-u`, and the rest behave the way you'd expect.
|
|
@@ -1,44 +1,45 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<img width="500" alt="ctools" src="https://github.com/user-attachments/assets/ee781bbe-6364-44ed-be2d-72114f1e6d8a" /><br/>
|
|
3
3
|
<a href=https://pypi.org/project/ctxttools><img src=https://badge.fury.io/py/ctxttools.svg/></a>
|
|
4
|
+
<br/><br/><b>Try it now</b><br/>
|
|
5
|
+
<code>uvx --from ctxttools cdir</code>
|
|
6
|
+
<br/><br/><b>Then install it</b><br/>
|
|
7
|
+
<code>uv tool install ctxttools</code>
|
|
4
8
|
</p>
|
|
5
9
|
|
|
6
10
|
------
|
|
11
|
+
**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.
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
It supports [Claude Desktop](https://claude.com/download), [Claude Code](https://github.com/anthropics/claude-code), [Codex](https://github.com/openai/codex), [Pi](https://github.com/earendil-works/pi), [Hermes](https://github.com/NousResearch/hermes-agent), [Goose](https://github.com/aaif-goose/goose), [Kilo](https://github.com/Kilo-Org/kilocode), [FreeBuff](https://github.com/CodebuffAI/freebuff), [Cline](https://github.com/cline/cline), [omp](https://github.com/can1357/oh-my-pi), and [OpenClaw](https://openclaw.ai/).
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
Here's an example:
|
|
11
16
|
|
|
17
|
+
> I look for mentions of snake game in opencode using cgrep
|
|
18
|
+
<pre>
|
|
19
|
+
$ <b>cgrep</b> "snake game" opencode
|
|
20
|
+
opencode/ses_a1d1a5a4df984ee698cab4a7:1:user: make a simple snake game in python
|
|
21
|
+
opencode/ses_a1d1a5a4df984ee698cab4a7:2:assistant: I'll make a terminal-based snake game using `curses` (standard library, no dependencies).
|
|
22
|
+
opencode/ses_a1d1a5a4df984ee698cab4a7:3:assistant: Done — `snake.py` is a terminal snake game using Python's built-in `curses` module (no dependencies).
|
|
23
|
+
</pre>
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
> cool let's look at the status of that session using cdir
|
|
26
|
+
<pre>
|
|
27
|
+
$ <b>cdir</b> -l opencode/ses_a1d1a5a4df984ee698cab4a7
|
|
28
|
+
ID NAME MODIFIED SIZE MSGS PATH
|
|
29
|
+
ses_a1d1a5a4df984ee698cab4a7 make a simple snake game in python 2026-10-07 16:56 2.7 KB 3 /home/chris/.local/share/opencode
|
|
14
30
|
|
|
15
|
-
|
|
31
|
+
1 session(s)
|
|
32
|
+
</pre>
|
|
16
33
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
opencode/ses_000d460f:34:assistant: Found it. Root cause: `_check_host` (graflex/__init__.py:128) tries `http`, and …
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
No agent argument? It searches **every installed agent at once** — Claude Code, Opencode, Kilo, Codex, Pi, Goose, Hermes, Cline, omp, and Freebuff, all in one pass. That last line is the root-cause analysis you wrote six months ago and would never have found again.
|
|
25
|
-
|
|
26
|
-
### 2. `ccopy` — move your project from one tool to another
|
|
27
|
-
|
|
28
|
-
Switched from opencode to Claude Code mid-project? You don't have to start from zero. Copy the whole conversation — context, decisions, the lot — into a fresh session in the other tool:
|
|
29
|
-
|
|
30
|
-
```shell
|
|
31
|
-
$ ccopy opencode/ses_abc123 claude-code
|
|
32
|
-
Copied 128 message(s) from opencode/ses_abc123 to a new claude-code session: 1a2b3c
|
|
34
|
+
> Alright let's copy that session from opencode into pi!
|
|
35
|
+
<pre>
|
|
36
|
+
$ <b>ccopy</b> opencode/ses_a1d1a5a4df984ee698cab4a7 pi
|
|
37
|
+
Copied 3 message(s) from opencode/ses_a1d1a5a4df984ee698cab4a7 to a new pi session: e357f435-f813-463a-b313-f97f1051f3cb
|
|
33
38
|
Resume it with:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
Your work travels with you. The source is never touched, so it's a true copy. And when the destination is on another machine, it's just `ccopy opencode/ses_abc123 ssh://chris@remote/codex` — it runs over your normal ssh.
|
|
39
|
+
pi --session e357f435-f813-463a-b313-f97f1051f3cb
|
|
40
|
+
</pre>
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
**Works with the agents you already use:** Claude Desktop, Claude Code, Opencode, Kilo, Codex, Pi, Goose, Hermes, Cline, omp (oh-my-pi), and Freebuff (Codebuff).
|
|
42
|
+
As you can see, these are unix-friendly tools using simple paradigms that you are already familiar with.
|
|
42
43
|
|
|
43
44
|
## Tools
|
|
44
45
|
|
|
@@ -46,13 +47,21 @@ ctools is a set of GNU-style tools for the history your coding agents leave behi
|
|
|
46
47
|
|------|--------------|------|
|
|
47
48
|
| `cgrep` | Search conversation content (grep across every agent) | [docs/cgrep.md](docs/cgrep.md) |
|
|
48
49
|
| `cdir` | List sessions (ls for your history) | [docs/cdir.md](docs/cdir.md) |
|
|
50
|
+
| `ccat` | Print one or more conversations (cat for your history) | [docs/ccat.md](docs/ccat.md) |
|
|
49
51
|
| `ccopy` | Copy a whole conversation from one agent to a new session in another | [docs/ccopy.md](docs/ccopy.md) |
|
|
50
52
|
| `cextract` | Extract concepts from a session into files, and inject them back | [docs/cextract.md](docs/cextract.md) |
|
|
51
53
|
| `cconnect` | Live concept pipelines between sessions | [docs/cconnect.md](docs/cconnect.md) |
|
|
52
54
|
| `cdu` | Token usage per session (du for context windows) | [docs/cdu.md](docs/cdu.md) |
|
|
53
55
|
| `crm` | Remove concepts from a session (mdel) | [docs/crm.md](docs/crm.md) |
|
|
56
|
+
| `ctools-web` | Browser dashboard for all of the above | [Web dashboard](#web-dashboard) |
|
|
57
|
+
|
|
58
|
+
Every tool takes `--version`. The session-mover tools (`ccopy`, `cextract`, `cconnect`, `crm`) also take `--verbose` for structured logging. Each tool's full flag reference, output formats, and examples live in its `docs/` page — the table above is just the 30-second version.
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
## The problem
|
|
61
|
+
|
|
62
|
+
You talk to LLMs all day. Over weeks, you build up a set of constraints, preferences, and goals. These live in your conversations as system messages. They are valuable. They are also trapped.
|
|
63
|
+
|
|
64
|
+
Say you have been working with opencode for a month. You have refined your coding style through dozens of sessions. Now you start a new Claude Code project and you want those same preferences. You could copy them by hand. Or you could `cextract` them out and `cextract` them back in, or copy the whole conversation across with `ccopy`. Either way, your memory travels with you.
|
|
56
65
|
|
|
57
66
|
## How it works
|
|
58
67
|
|
|
@@ -63,6 +72,8 @@ Two stages: **extraction** and **filtering**.
|
|
|
63
72
|
- A **strategy** extracts concepts from a conversation. It defines what counts as a concept and how to find it: regex patterns, LLM extraction, whatever. Different strategies produce different ontologies from the same conversation, because context is contestable.
|
|
64
73
|
- A **filter** selects which extracted concepts reach a destination. It's a binary classifier: pass through or filter out. One concept list can fan out to many destinations, each with its own filter. A coding agent gets coding preferences, a security agent gets security constraints, a PM agent gets goals, all from the same source.
|
|
65
74
|
|
|
75
|
+
A filter can be as simple as a type or substring match, or as smart as a **decision model** — a small local classifier that scores each concept and lets it through only when confident. Point a filter at a model and you get *semantic* filtering with no free text to parse: ask "is this concept about security?" and gate on the answer. The model is asked either through Ollama's typed `/v1/systemone` endpoint (calibrated probabilities, the home of decision-dedicated models) or through any OpenAI-compatible `/v1/chat/completions` server (portable, lettered decision-task prompt) — one `endpoint` field decides. See [cextract](docs/cextract.md) for the decision-model and JSON-RPC filter configs.
|
|
76
|
+
|
|
66
77
|
```mermaid
|
|
67
78
|
graph LR
|
|
68
79
|
SRC["source session"] --> STRAT["strategy<br/>(extraction)"]
|
|
@@ -75,13 +86,7 @@ graph LR
|
|
|
75
86
|
FC --> DEST_C["destination C"]
|
|
76
87
|
```
|
|
77
88
|
|
|
78
|
-
Context windows are endpoints: opencode, Claude Code, Codex, Pi. They all speak different protocols, but they all consume the same packets. See [cextract](docs/cextract.md) for the concept packet format, strategies, and the filter (JSON-RPC)
|
|
79
|
-
|
|
80
|
-
## The problem
|
|
81
|
-
|
|
82
|
-
You talk to LLMs all day. Over weeks, you build up a set of constraints, preferences, and goals. These live in your conversations as system messages. They are valuable. They are also trapped.
|
|
83
|
-
|
|
84
|
-
Say you have been working with opencode for a month. You have refined your coding style through dozens of sessions. Now you start a new Claude Code project and you want those same preferences. You could copy them by hand. Or you could `cextract` them out and `cextract` them back in, or copy the whole conversation across with `ccopy`. Either way, your memory travels with you.
|
|
89
|
+
Context windows are endpoints: opencode, Claude Code, Codex, Pi. They all speak different protocols, but they all consume the same packets. See [cextract](docs/cextract.md) for the concept packet format, strategies, and the filter configs (decision model and JSON-RPC).
|
|
85
90
|
|
|
86
91
|
## Supported endpoints
|
|
87
92
|
|
|
@@ -98,6 +103,12 @@ Say you have been working with opencode for a month. You have refined your codin
|
|
|
98
103
|
| cline | JSON (`~/.cline/data/tasks/`) |
|
|
99
104
|
| omp | JSONL (`~/.omp/agent/sessions/`, tree journal) |
|
|
100
105
|
| freebuff | JSON (`~/.config/<codebuff>/projects/`) |
|
|
106
|
+
| openclaw | SQLite (per-agent, `~/.openclaw/agents/`, `OPENCLAW_STATE_DIR`) |
|
|
107
|
+
|
|
108
|
+
OpenClaw is a **personal assistant** rather than a terminal coding agent, so it
|
|
109
|
+
runs in a local Gateway that owns its store; ctools reads and exports its
|
|
110
|
+
sessions but does not seed new ones (the store has canonical-index and integrity
|
|
111
|
+
checks that a raw insert cannot satisfy).
|
|
101
112
|
|
|
102
113
|
Run `cdir` to see which endpoints are found on your system and where they store data.
|
|
103
114
|
|
|
@@ -140,6 +151,37 @@ Add to your MCP config:
|
|
|
140
151
|
}
|
|
141
152
|
```
|
|
142
153
|
|
|
154
|
+
## Web dashboard
|
|
155
|
+
|
|
156
|
+
Prefer a mouse to a man page? ctools ships a browser dashboard — a small local
|
|
157
|
+
web server (Python stdlib only, no web dependencies) with the same library
|
|
158
|
+
underneath. Same on macOS, Windows, and Linux:
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
$ ctools-web # or: python -m ctools.webui
|
|
162
|
+
ctools 0.2.1 dashboard: http://127.0.0.1:8765
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Open the URL. You get four views:
|
|
166
|
+
|
|
167
|
+
- **Overview** — every supported agent, installed or not, with session counts
|
|
168
|
+
and total tokens, and a jump into each agent's sessions.
|
|
169
|
+
- **Search** — `cgrep` in the browser: one regex box, per-agent chips, live
|
|
170
|
+
matches; click any match to open that conversation.
|
|
171
|
+
- **Sessions** — `cdir` for one agent: newest, largest, or by token usage.
|
|
172
|
+
- **Conversation** — `ccat` with the source session's messages, token usage,
|
|
173
|
+
the resume command, concept extraction (`cextract`), a markdown export,
|
|
174
|
+
and **Copy** — `ccopy` to any other installed agent, which creates a fresh
|
|
175
|
+
session there (source untouched) and tells you how to resume it.
|
|
176
|
+
|
|
177
|
+
The server binds to `127.0.0.1` by default, so nothing is exposed to your
|
|
178
|
+
network unless you pass `--host 0.0.0.0`. There is one write operation:
|
|
179
|
+
Copy. Everything else is read-only against the agents' storage.
|
|
180
|
+
|
|
181
|
+
```sh
|
|
182
|
+
ctools-web --port 9000
|
|
183
|
+
```
|
|
184
|
+
|
|
143
185
|
## Installation
|
|
144
186
|
|
|
145
187
|
```sh
|
|
@@ -162,7 +204,7 @@ from ctools.lib import get_formatter
|
|
|
162
204
|
from ctools.cgrep import grep_session
|
|
163
205
|
from ctools.cextract import extract_concepts_from_messages
|
|
164
206
|
from ctools.cdu import count_tokens, get_session_tokens
|
|
165
|
-
from ctools.filterlib import JSONRPCFilter, load_filter
|
|
207
|
+
from ctools.filterlib import JSONRPCFilter, SystemOneFilter, load_filter
|
|
166
208
|
from ctools.log import configure_logging, get_logger
|
|
167
209
|
```
|
|
168
210
|
|
|
@@ -187,6 +229,13 @@ from ctools.agents import OpencodeAgent
|
|
|
187
229
|
agent = OpencodeAgent('/backup/opencode')
|
|
188
230
|
```
|
|
189
231
|
|
|
232
|
+
## Where to go next
|
|
233
|
+
|
|
234
|
+
- **Per-tool reference** — the [Tools](#tools) table above links to a `docs/` page for each command: every flag, output format, and a worked example.
|
|
235
|
+
- **The interchange format** — how a conversation becomes a portable, lossless envelope and back, and why 2N agents compose into N² transfers. See [interchange](docs/interchange.md).
|
|
236
|
+
- **Filtering with decision models** — the full decision-model and JSON-RPC filter configs, with live examples. See [cextract](docs/cextract.md#filters) and [cconnect](docs/cconnect.md#filter-configuration).
|
|
237
|
+
- **Adding an endpoint** — one `Agent` subclass plus a line in `AGENT_CLASSES`. See [Supported endpoints](#supported-endpoints).
|
|
238
|
+
|
|
190
239
|
## Credits
|
|
191
240
|
|
|
192
241
|
ctools was extracted from [Gab n' Go](https://github.com/day50-dev/gabngo). It's named after [GNU mtools](https://www.gnu.org/software/mtools/), which does the same thing for DOS floppies — because your context window is about the size of a DOS-floppy. The flag habits are GNU's too: `--version`, `-1`, `-S`, `-u`, and the rest behave the way you'd expect.
|