cc-transcript 0.8.0__tar.gz → 0.9.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.
Files changed (57) hide show
  1. cc_transcript-0.9.0/PKG-INFO +184 -0
  2. cc_transcript-0.9.0/README.md +144 -0
  3. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/__init__.py +3 -1
  4. cc_transcript-0.9.0/cc_transcript/__main__.py +3 -0
  5. cc_transcript-0.9.0/cc_transcript/cli.py +412 -0
  6. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/nav.py +3 -13
  7. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/filterspec.py +12 -2
  8. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/parser.py +4 -2
  9. cc_transcript-0.9.0/cc_transcript/render.py +274 -0
  10. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/pyproject.toml +20 -3
  11. cc_transcript-0.8.0/PKG-INFO +0 -97
  12. cc_transcript-0.8.0/README.md +0 -60
  13. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/Cargo.lock +0 -0
  14. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/Cargo.toml +0 -0
  15. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/LICENSE +0 -0
  16. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/_parser_rs.pyi +0 -0
  17. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/backend.py +0 -0
  18. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/builders.py +0 -0
  19. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/discovery.py +0 -0
  20. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/__init__.py +0 -0
  21. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/__init__.py +0 -0
  22. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/candidates.py +0 -0
  23. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/confidence.py +0 -0
  24. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/context.py +0 -0
  25. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/filterspec.py +0 -0
  26. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/formats.py +0 -0
  27. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/llm.py +0 -0
  28. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/markers.py +0 -0
  29. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/signals.py +0 -0
  30. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/sourcekind.py +0 -0
  31. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/store.py +0 -0
  32. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/mining/verdicts.py +0 -0
  33. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/sentiment/__init__.py +0 -0
  34. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/sentiment/buckets.py +0 -0
  35. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/sentiment/engine.py +0 -0
  36. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/sentiment/lexicon.py +0 -0
  37. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/domains/sentiment/scorespec.py +0 -0
  38. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/filters.py +0 -0
  39. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/messages.py +0 -0
  40. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/models.py +0 -0
  41. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/py.typed +0 -0
  42. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/rust.py +0 -0
  43. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/sentiment/__init__.py +0 -0
  44. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/sentiment/buckets.py +0 -0
  45. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/sentiment/lexicon.py +0 -0
  46. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/sentiment/messages.py +0 -0
  47. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/cc_transcript/store.py +0 -0
  48. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/Cargo.toml +0 -0
  49. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/data/afinn-en-165.tsv +0 -0
  50. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/data/domain_overrides.tsv +0 -0
  51. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/src/event.rs +0 -0
  52. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/src/filter.rs +0 -0
  53. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/src/lexicon.rs +0 -0
  54. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/src/lib.rs +0 -0
  55. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/src/model.rs +0 -0
  56. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/src/score.rs +0 -0
  57. {cc_transcript-0.8.0 → cc_transcript-0.9.0}/rust/src/value.rs +0 -0
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: cc-transcript
3
+ Version: 0.9.0
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Environment :: Console
6
+ Classifier: Intended Audience :: Developers
7
+ Classifier: Operating System :: OS Independent
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3 :: Only
10
+ Classifier: Programming Language :: Rust
11
+ Classifier: Typing :: Typed
12
+ Requires-Dist: aiosqlite>=0.20
13
+ Requires-Dist: anyio>=4.4
14
+ Requires-Dist: click>=8.1
15
+ Requires-Dist: orjson>=3.10
16
+ Requires-Dist: pytest>=8.0 ; extra == 'dev'
17
+ Requires-Dist: ty>=0.0.44 ; extra == 'dev'
18
+ Requires-Dist: ruff>=0.8 ; extra == 'dev'
19
+ Requires-Dist: cc-transcript[sentiment] ; extra == 'lexicon'
20
+ Requires-Dist: spawnllm>=0.1.3 ; extra == 'llm'
21
+ Requires-Dist: spacy>=3.8 ; extra == 'sentiment'
22
+ Requires-Dist: afinn>=0.1 ; extra == 'sentiment'
23
+ Provides-Extra: dev
24
+ Provides-Extra: lexicon
25
+ Provides-Extra: llm
26
+ Provides-Extra: sentiment
27
+ License-File: LICENSE
28
+ Summary: Typed, non-lossy events for Claude Code transcripts: a superset JSONL parser (Rust fast path, Python reference), sentiment and feedback-mining domains, and a transcript-investigation CLI.
29
+ Keywords: claude-code,claude,anthropic,transcripts,jsonl,parser,cli,agents,sentiment,feedback-mining
30
+ Author-email: Yasyf Mohamedali <yasyfm@gmail.com>
31
+ License-Expression: PolyForm-Noncommercial-1.0.0
32
+ Requires-Python: >=3.13
33
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
34
+ Project-URL: Changelog, https://github.com/yasyf/cc-transcript/blob/main/CHANGELOG.md
35
+ Project-URL: Documentation, https://yasyf.github.io/cc-transcript/
36
+ Project-URL: Homepage, https://github.com/yasyf/cc-transcript
37
+ Project-URL: Issues, https://github.com/yasyf/cc-transcript/issues
38
+ Project-URL: Repository, https://github.com/yasyf/cc-transcript
39
+
40
+ # cc-transcript
41
+
42
+ ![cc-transcript banner](https://github.com/yasyf/cc-transcript/raw/main/docs/assets/readme-banner.png)
43
+
44
+ [![PyPI](https://img.shields.io/pypi/v/cc-transcript.svg)](https://pypi.org/project/cc-transcript/)
45
+ [![Python](https://img.shields.io/pypi/pyversions/cc-transcript.svg)](https://pypi.org/project/cc-transcript/)
46
+ [![Docs](https://img.shields.io/github/actions/workflow/status/yasyf/cc-transcript/docs.yml?branch=main&label=docs)](https://yasyf.github.io/cc-transcript/)
47
+ [![License: PolyForm Noncommercial](https://img.shields.io/badge/License-PolyForm--Noncommercial--1.0.0-blue.svg)](https://github.com/yasyf/cc-transcript/blob/main/LICENSE)
48
+
49
+ `cc-transcript` parses Claude Code's on-disk JSONL transcripts into a **typed superset event model** — every entry type preserved, nothing dropped — so you build on one faithful representation and apply your own semantic filtering on top.
50
+
51
+ The one property that makes it worth using: the parser is non-lossy. It never silently discards sidechains, synthetic turns, tool results, or unrecognized entry types; filtering is opt-in and lives in your code, not buried in the parser. It ships as a Python library, a `uvx`-runnable CLI, and a Claude Code plugin.
52
+
53
+ ## Install
54
+
55
+ ```bash
56
+ uv add cc-transcript # or: pip install cc-transcript
57
+ uvx cc-transcript --help # CLI, no install needed
58
+ ```
59
+
60
+ ## Quickstart
61
+
62
+ Discover the transcripts on disk, parse one, and look at the events:
63
+
64
+ ```python
65
+ import anyio
66
+
67
+ from cc_transcript import AssistantEvent, TranscriptDiscovery, UserEvent, parse_events_from_bytes
68
+
69
+ path = anyio.run(TranscriptDiscovery.find_transcripts)[0]
70
+ events = parse_events_from_bytes(path.read_bytes())
71
+
72
+ for event in events:
73
+ match event:
74
+ case UserEvent(text=text):
75
+ print("user:", text[:80])
76
+ case AssistantEvent(model=model, text=text):
77
+ print(f"assistant ({model}):", text[:80])
78
+ ```
79
+
80
+ Compose a filter from small builders and apply it. The builders return clauses,
81
+ `build_spec` assembles them into a spec, and `apply_spec` yields the survivors:
82
+
83
+ ```python
84
+ from cc_transcript import apply_spec, build_spec, keep_only, drop_junk, drop_short
85
+
86
+ spec = build_spec(keep_only("user", "assistant"), drop_junk("structural"), drop_short(2))
87
+ clean = list(apply_spec(events, spec))
88
+ ```
89
+
90
+ `NOISE_SPEC` is a ready-made spec for the universal structural noise (system reminders,
91
+ local-command output, skill banners). For flag-style filtering, `FilterConfig` is also
92
+ available — every rule is off by default, so a bare `FilterConfig()` passes everything through.
93
+
94
+ ## The CLI
95
+
96
+ Four commands — `list`, `show`, `grep`, `stats` — and every one runs as `uvx cc-transcript ...`, no install step. `list` finds transcripts, newest first:
97
+
98
+ ```console
99
+ $ uvx cc-transcript list --limit 3
100
+ 2026-06-11 19:27 1.0MB ~/.claude/projects/-Users-yasyf-Code-captain-hook/d2ca206a-2561-4c2c-9a4c-3ecaac9f8443/subagents/agent-a804d9aea43a110b5.jsonl
101
+ 2026-06-11 19:27 70.6KB ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e/subagents/agent-affd5dbe069a3660d.jsonl
102
+ 2026-06-11 19:27 740.8KB ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
103
+ 3 of 6608 transcripts under ~/.claude/projects
104
+ ```
105
+
106
+ `stats` summarizes a session before you read any of it:
107
+
108
+ ```console
109
+ $ uvx cc-transcript stats ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
110
+ files 1
111
+ events 181
112
+ kinds other 68 · assistant 53 · user 33 · mode 22 · system 5
113
+ models claude-fable-5 53
114
+ tools TaskCreate 10 · Agent 5 · Read 5 · TaskUpdate 5 · Bash 2 · ToolSearch 2 · AskUserQuestion 1 · ExitPlanMode 1
115
+ text 14.8KB
116
+ thinking 8.7KB
117
+ tool io 89.0KB
118
+ sessions 1
119
+ span 2026-06-12 01:07:55 → 2026-06-12 02:28:03
120
+ interrupts 0
121
+ tool errors 0
122
+ sidechain 0
123
+ ```
124
+
125
+ `show` renders one compact line per event; `--signal` keeps the conversational spine, and the index column is the event's position in the raw file:
126
+
127
+ ```console
128
+ $ uvx cc-transcript show ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl --signal --tail 4
129
+ 189 asst 02:30:49 [claude-fable-5] Bash(rg -A3 'name = "great-docs"' /Users/yasyf/Code/cc-transcript/uv.lock | head -6; echo ---; rg -n "cl…)
130
+ 194 asst 02:31:31 [claude-fable-5] "`cli:` support confirmed in the pinned great-docs. Checking the exact config shape before writing:"
131
+ 195 asst 02:31:31 [claude-fable-5] TaskUpdate(8)
132
+ 196 asst 02:31:32 [claude-fable-5] Bash(sed -n '40,60p;1750,1790p' /Users/yasyf/.cache/uv/git-v0/checkouts/a9f52a54772f9b4e/d318527/great_d…)
133
+ ```
134
+
135
+ `grep` searches event content; hit indexes feed straight back into `show --range`:
136
+
137
+ ```console
138
+ $ uvx cc-transcript grep -i "filterspec" --kind user --max-matches 3 ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
139
+ == ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
140
+ 16 user 01:12:00 <-Agent (10161ch) ## Findings Report: cc-transcript Repository Based on a thorough exploration of `/Users/yasyf/Code/…
141
+ 29 user 01:16:29 <-? (1378ch) /Users/yasyf/Code/cc-transcript/cc_transcript/: total 8648 drwxr-xr-x@ 19 yasyf staff 608 Jun 11 17…
142
+ 69 user 01:36:17 <-Read (4247ch) 1 """Composable builder fragments for :class:`~cc_transcript.FilterSpec`. 2 3 Each fragment returns…
143
+ 1 files, 3 matches
144
+ ```
145
+
146
+ The output is compact by design — one line per event, hard truncation — so an agent triages a session in a few hundred tokens instead of paging through megabytes of JSONL.
147
+
148
+ ## Claude Code plugin
149
+
150
+ Install the bundled plugin from inside Claude Code:
151
+
152
+ ```
153
+ /plugin marketplace add yasyf/cc-transcript
154
+ /plugin install cc-transcript@cc-transcript
155
+ ```
156
+
157
+ The plugin's skill teaches Claude to answer questions about its own history — "what did I ask yesterday", "find the session where we fixed the parser" — by funneling through the CLI's `list`, `stats`, `grep`, and `show` commands instead of reading raw JSONL.
158
+
159
+ ## What problems does this solve?
160
+
161
+ - **One faithful parse.** Anything reading Claude Code transcripts re-implements the same JSONL quirks (str-or-list content, tool results nested two ways, envelope-less mode markers). This is that parser, written once and typed strictly.
162
+ - **Non-lossy by design.** The event model is a superset: sidechains, `<synthetic>` turns, thinking blocks, and unrecognized entry types all survive parsing. You decide what to drop, via composable filter specs (`build_spec`) or `FilterConfig`.
163
+ - **Incremental ingestion.** `FileStateStore` tracks per-file mtimes in SQLite (WAL, safe across concurrent tasks) so re-runs only reparse changed files, and you compose your own writes in the same transaction.
164
+ - **Two engines, one contract.** A single `Backend` protocol with two implementations: `RustBackend` (PyO3 + rayon) is the default fast path, and `PythonBackend` is the readable reference — parity-asserted against each other. Filter specs are portable, so a spec built in Python runs Rust-side without giving up the fast path.
165
+ - **Analysis domains.** `domains.sentiment` scores conversational sentiment per time-bucketed conversation window; `domains.mining` mines transcripts for user feedback — detectors, confidence calibration, candidate filtering, and verdicts.
166
+ - **Transcript investigation for agents.** The CLI answers "what happened in that session" in a few hundred tokens, which is what makes the Claude Code plugin viable.
167
+
168
+ ## Docs
169
+
170
+ Each section of [the docs site](https://yasyf.github.io/cc-transcript/) is a focused guide:
171
+
172
+ - [Getting Started](https://yasyf.github.io/cc-transcript/docs/getting-started/index.html) — install, parse, filter, persist.
173
+ - [Filtering events](https://yasyf.github.io/cc-transcript/docs/guide/filtering-events.html) — clauses, specs, and `NOISE_SPEC`.
174
+ - [Scoring sentiment](https://yasyf.github.io/cc-transcript/docs/guide/scoring-sentiment.html) — the lexicon engine and score specs.
175
+ - [Rust/Python backends & parity](https://yasyf.github.io/cc-transcript/docs/guide/backends-and-parity.html) — the `Backend` protocol and parity testing.
176
+ - [Compose your own policy](https://yasyf.github.io/cc-transcript/docs/guide/compose-your-own-policy.html) — building a bespoke filtering policy.
177
+ - [Mining feedback](https://yasyf.github.io/cc-transcript/docs/guide/mining-feedback.html) — detectors, confidence, candidates, and verdicts.
178
+ - [The transcript CLI](https://yasyf.github.io/cc-transcript/docs/guide/transcript-cli.html) — `list`/`show`/`grep`/`stats` end to end.
179
+ - [API reference](https://yasyf.github.io/cc-transcript/reference/index.html) — the complete typed surface.
180
+
181
+ ## License
182
+
183
+ [PolyForm Noncommercial 1.0.0](LICENSE).
184
+
@@ -0,0 +1,144 @@
1
+ # cc-transcript
2
+
3
+ ![cc-transcript banner](https://github.com/yasyf/cc-transcript/raw/main/docs/assets/readme-banner.png)
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/cc-transcript.svg)](https://pypi.org/project/cc-transcript/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/cc-transcript.svg)](https://pypi.org/project/cc-transcript/)
7
+ [![Docs](https://img.shields.io/github/actions/workflow/status/yasyf/cc-transcript/docs.yml?branch=main&label=docs)](https://yasyf.github.io/cc-transcript/)
8
+ [![License: PolyForm Noncommercial](https://img.shields.io/badge/License-PolyForm--Noncommercial--1.0.0-blue.svg)](https://github.com/yasyf/cc-transcript/blob/main/LICENSE)
9
+
10
+ `cc-transcript` parses Claude Code's on-disk JSONL transcripts into a **typed superset event model** — every entry type preserved, nothing dropped — so you build on one faithful representation and apply your own semantic filtering on top.
11
+
12
+ The one property that makes it worth using: the parser is non-lossy. It never silently discards sidechains, synthetic turns, tool results, or unrecognized entry types; filtering is opt-in and lives in your code, not buried in the parser. It ships as a Python library, a `uvx`-runnable CLI, and a Claude Code plugin.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ uv add cc-transcript # or: pip install cc-transcript
18
+ uvx cc-transcript --help # CLI, no install needed
19
+ ```
20
+
21
+ ## Quickstart
22
+
23
+ Discover the transcripts on disk, parse one, and look at the events:
24
+
25
+ ```python
26
+ import anyio
27
+
28
+ from cc_transcript import AssistantEvent, TranscriptDiscovery, UserEvent, parse_events_from_bytes
29
+
30
+ path = anyio.run(TranscriptDiscovery.find_transcripts)[0]
31
+ events = parse_events_from_bytes(path.read_bytes())
32
+
33
+ for event in events:
34
+ match event:
35
+ case UserEvent(text=text):
36
+ print("user:", text[:80])
37
+ case AssistantEvent(model=model, text=text):
38
+ print(f"assistant ({model}):", text[:80])
39
+ ```
40
+
41
+ Compose a filter from small builders and apply it. The builders return clauses,
42
+ `build_spec` assembles them into a spec, and `apply_spec` yields the survivors:
43
+
44
+ ```python
45
+ from cc_transcript import apply_spec, build_spec, keep_only, drop_junk, drop_short
46
+
47
+ spec = build_spec(keep_only("user", "assistant"), drop_junk("structural"), drop_short(2))
48
+ clean = list(apply_spec(events, spec))
49
+ ```
50
+
51
+ `NOISE_SPEC` is a ready-made spec for the universal structural noise (system reminders,
52
+ local-command output, skill banners). For flag-style filtering, `FilterConfig` is also
53
+ available — every rule is off by default, so a bare `FilterConfig()` passes everything through.
54
+
55
+ ## The CLI
56
+
57
+ Four commands — `list`, `show`, `grep`, `stats` — and every one runs as `uvx cc-transcript ...`, no install step. `list` finds transcripts, newest first:
58
+
59
+ ```console
60
+ $ uvx cc-transcript list --limit 3
61
+ 2026-06-11 19:27 1.0MB ~/.claude/projects/-Users-yasyf-Code-captain-hook/d2ca206a-2561-4c2c-9a4c-3ecaac9f8443/subagents/agent-a804d9aea43a110b5.jsonl
62
+ 2026-06-11 19:27 70.6KB ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e/subagents/agent-affd5dbe069a3660d.jsonl
63
+ 2026-06-11 19:27 740.8KB ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
64
+ 3 of 6608 transcripts under ~/.claude/projects
65
+ ```
66
+
67
+ `stats` summarizes a session before you read any of it:
68
+
69
+ ```console
70
+ $ uvx cc-transcript stats ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
71
+ files 1
72
+ events 181
73
+ kinds other 68 · assistant 53 · user 33 · mode 22 · system 5
74
+ models claude-fable-5 53
75
+ tools TaskCreate 10 · Agent 5 · Read 5 · TaskUpdate 5 · Bash 2 · ToolSearch 2 · AskUserQuestion 1 · ExitPlanMode 1
76
+ text 14.8KB
77
+ thinking 8.7KB
78
+ tool io 89.0KB
79
+ sessions 1
80
+ span 2026-06-12 01:07:55 → 2026-06-12 02:28:03
81
+ interrupts 0
82
+ tool errors 0
83
+ sidechain 0
84
+ ```
85
+
86
+ `show` renders one compact line per event; `--signal` keeps the conversational spine, and the index column is the event's position in the raw file:
87
+
88
+ ```console
89
+ $ uvx cc-transcript show ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl --signal --tail 4
90
+ 189 asst 02:30:49 [claude-fable-5] Bash(rg -A3 'name = "great-docs"' /Users/yasyf/Code/cc-transcript/uv.lock | head -6; echo ---; rg -n "cl…)
91
+ 194 asst 02:31:31 [claude-fable-5] "`cli:` support confirmed in the pinned great-docs. Checking the exact config shape before writing:"
92
+ 195 asst 02:31:31 [claude-fable-5] TaskUpdate(8)
93
+ 196 asst 02:31:32 [claude-fable-5] Bash(sed -n '40,60p;1750,1790p' /Users/yasyf/.cache/uv/git-v0/checkouts/a9f52a54772f9b4e/d318527/great_d…)
94
+ ```
95
+
96
+ `grep` searches event content; hit indexes feed straight back into `show --range`:
97
+
98
+ ```console
99
+ $ uvx cc-transcript grep -i "filterspec" --kind user --max-matches 3 ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
100
+ == ~/.claude/projects/-Users-yasyf-Code-cc-transcript/4c77d556-8694-4613-8f50-253d905da68e.jsonl
101
+ 16 user 01:12:00 <-Agent (10161ch) ## Findings Report: cc-transcript Repository Based on a thorough exploration of `/Users/yasyf/Code/…
102
+ 29 user 01:16:29 <-? (1378ch) /Users/yasyf/Code/cc-transcript/cc_transcript/: total 8648 drwxr-xr-x@ 19 yasyf staff 608 Jun 11 17…
103
+ 69 user 01:36:17 <-Read (4247ch) 1 """Composable builder fragments for :class:`~cc_transcript.FilterSpec`. 2 3 Each fragment returns…
104
+ 1 files, 3 matches
105
+ ```
106
+
107
+ The output is compact by design — one line per event, hard truncation — so an agent triages a session in a few hundred tokens instead of paging through megabytes of JSONL.
108
+
109
+ ## Claude Code plugin
110
+
111
+ Install the bundled plugin from inside Claude Code:
112
+
113
+ ```
114
+ /plugin marketplace add yasyf/cc-transcript
115
+ /plugin install cc-transcript@cc-transcript
116
+ ```
117
+
118
+ The plugin's skill teaches Claude to answer questions about its own history — "what did I ask yesterday", "find the session where we fixed the parser" — by funneling through the CLI's `list`, `stats`, `grep`, and `show` commands instead of reading raw JSONL.
119
+
120
+ ## What problems does this solve?
121
+
122
+ - **One faithful parse.** Anything reading Claude Code transcripts re-implements the same JSONL quirks (str-or-list content, tool results nested two ways, envelope-less mode markers). This is that parser, written once and typed strictly.
123
+ - **Non-lossy by design.** The event model is a superset: sidechains, `<synthetic>` turns, thinking blocks, and unrecognized entry types all survive parsing. You decide what to drop, via composable filter specs (`build_spec`) or `FilterConfig`.
124
+ - **Incremental ingestion.** `FileStateStore` tracks per-file mtimes in SQLite (WAL, safe across concurrent tasks) so re-runs only reparse changed files, and you compose your own writes in the same transaction.
125
+ - **Two engines, one contract.** A single `Backend` protocol with two implementations: `RustBackend` (PyO3 + rayon) is the default fast path, and `PythonBackend` is the readable reference — parity-asserted against each other. Filter specs are portable, so a spec built in Python runs Rust-side without giving up the fast path.
126
+ - **Analysis domains.** `domains.sentiment` scores conversational sentiment per time-bucketed conversation window; `domains.mining` mines transcripts for user feedback — detectors, confidence calibration, candidate filtering, and verdicts.
127
+ - **Transcript investigation for agents.** The CLI answers "what happened in that session" in a few hundred tokens, which is what makes the Claude Code plugin viable.
128
+
129
+ ## Docs
130
+
131
+ Each section of [the docs site](https://yasyf.github.io/cc-transcript/) is a focused guide:
132
+
133
+ - [Getting Started](https://yasyf.github.io/cc-transcript/docs/getting-started/index.html) — install, parse, filter, persist.
134
+ - [Filtering events](https://yasyf.github.io/cc-transcript/docs/guide/filtering-events.html) — clauses, specs, and `NOISE_SPEC`.
135
+ - [Scoring sentiment](https://yasyf.github.io/cc-transcript/docs/guide/scoring-sentiment.html) — the lexicon engine and score specs.
136
+ - [Rust/Python backends & parity](https://yasyf.github.io/cc-transcript/docs/guide/backends-and-parity.html) — the `Backend` protocol and parity testing.
137
+ - [Compose your own policy](https://yasyf.github.io/cc-transcript/docs/guide/compose-your-own-policy.html) — building a bespoke filtering policy.
138
+ - [Mining feedback](https://yasyf.github.io/cc-transcript/docs/guide/mining-feedback.html) — detectors, confidence, candidates, and verdicts.
139
+ - [The transcript CLI](https://yasyf.github.io/cc-transcript/docs/guide/transcript-cli.html) — `list`/`show`/`grep`/`stats` end to end.
140
+ - [API reference](https://yasyf.github.io/cc-transcript/reference/index.html) — the complete typed surface.
141
+
142
+ ## License
143
+
144
+ [PolyForm Noncommercial 1.0.0](LICENSE).
@@ -2,7 +2,9 @@
2
2
  # pyright: reportUnusedImport=false
3
3
  """Typed events for Claude Code transcripts.
4
4
 
5
- Discovery, a superset JSONL parser (Python + Rust), and ingestion-state tracking.
5
+ Discovery, a superset JSONL parser a Rust fast path and a Python reference
6
+ behind one ``Backend`` protocol — ingestion-state tracking, and a
7
+ transcript-investigation CLI.
6
8
  """
7
9
 
8
10
  from __future__ import annotations
@@ -0,0 +1,3 @@
1
+ from cc_transcript.cli import cli
2
+
3
+ cli()