transcripto 0.1.5__tar.gz → 0.2.1__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.
@@ -0,0 +1,315 @@
1
+ Metadata-Version: 2.4
2
+ Name: transcripto
3
+ Version: 0.2.1
4
+ Summary: Instant replay for coding agents. Inspect requests, tool calls, and recorded results across Claude Code, Codex, and Cursor. Local, stdlib-only.
5
+ Author: Oscar Morke
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Morkeeth/transcripto
8
+ Project-URL: Source, https://github.com/Morkeeth/transcripto
9
+ Keywords: claude-code,coding-agents,transcripts,local-first,analytics
10
+ Classifier: Environment :: Console
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Topic :: Utilities
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Dynamic: license-file
18
+
19
+ # Transcripto
20
+
21
+ **You might already be keeping a journal. Read your side of it.**
22
+
23
+ Your agent transcripts contain what you asked for, what you changed your mind
24
+ about, and what you kept coming back to. Transcripto helps you find those words
25
+ and read the recorded work around them.
26
+
27
+ Claude Code · Codex · Cursor. Local files. No account. No runtime dependencies.
28
+
29
+ ## Start with something you remember saying
30
+
31
+ ```sh
32
+ uvx --from transcripto==0.2.1 transcripto ask "retry"
33
+ ```
34
+
35
+ Replace `retry` with a word you remember using. `ask` searches messages identified
36
+ as yours and shows dated snippets, newest first. It refreshes the local index
37
+ automatically. The first search indexes the selected history; a large archive
38
+ can take minutes. Add `--harness claude`, `--harness codex`, or `--harness cursor`
39
+ to limit that scan. It does not generate a diary or interpret your personality.
40
+
41
+ Each hit prints an `Open:` command. Run that command to open the exact request
42
+ and its recorded work. This also works when search matches a word variant
43
+ (such as `retry` matching `retried`) or several requests share the same words.
44
+
45
+ You can also search replay directly:
46
+
47
+ ```sh
48
+ uvx --from transcripto==0.2.1 transcripto replay "retry"
49
+
50
+ # Or open your latest human session:
51
+ uvx --from transcripto==0.2.1 transcripto
52
+ ```
53
+
54
+ Replay puts your request, tool calls and recorded results in order. Failed edits
55
+ stay failed. Missing results stay unknown. Status describes tool execution,
56
+ not whether the task was done correctly.
57
+
58
+ Or install with `python3 -m pip install transcripto==0.2.1`, then run
59
+ `transcripto ask "retry"`. Requires Python 3.9 or newer.
60
+
61
+ ## Try the stranger flow without your transcripts
62
+
63
+ The bundled public example is synthetic. It works in an isolated home and does
64
+ not depend on agent dotfiles:
65
+
66
+ ```sh
67
+ INSTALL="$(mktemp -d)"
68
+ python3 -m pip install --no-deps --no-build-isolation --target "$INSTALL" .
69
+ export HOME="$(mktemp -d)"
70
+ transcripto() { PYTHONPATH="$INSTALL" python3 -m transcripto "$@"; }
71
+
72
+ transcripto import-example
73
+ transcripto ask "What changed about the forecast cache?"
74
+ transcripto changes
75
+ ```
76
+
77
+ `ask` cites the imported JSONL line for every hit. `changes` is a focused view
78
+ of the request that was revised, the correction, and its recorded follow-up.
79
+ It labels missing results rather than turning a change of mind into a score.
80
+
81
+ To carry that correction to a different receiver:
82
+
83
+ ```sh
84
+ transcripto handoff "30 seconds" \
85
+ --to-harness codex --output "$HOME/codex-inbox/correction.json"
86
+ transcripto receive-handoff \
87
+ "$HOME/codex-inbox/correction.json" --as-harness codex \
88
+ --output "$HOME/codex-work/receiver-brief.md"
89
+ cat "$HOME/codex-work/receiver-brief.md"
90
+ ```
91
+
92
+ The brief includes the cited correction, recorded follow-up statuses
93
+ (failed / succeeded / unknown), and an `Open:` command for the exact request.
94
+ If the source moved, disappeared, or no longer holds the cited request, the brief
95
+ marks evidence uncertain and shows only the packet's own statuses as provisional. It does not invoke a receiver agent or prove
96
+ adoption. Synthetic provenance stays visible in search, changes, and handoffs.
97
+ Handoff files are local and mode `0600`; they can contain transcript text and
98
+ paths, so review them before sharing.
99
+
100
+ ### Cross-harness lab (failed / succeeded / unknown)
101
+
102
+ For a receiving agent that needs to find a prior episode and reopen exact
103
+ evidence without private history:
104
+
105
+ ```sh
106
+ transcripto import-lab
107
+ transcripto ask "retry"
108
+ # run each printed Open: command
109
+ ```
110
+
111
+ All lab records are labelled synthetic. Claude shows a failed edit, Codex a
112
+ succeeded check, Cursor an unknown missing result.
113
+
114
+ ### Offline flight card
115
+
116
+ ```sh
117
+ transcripto quickstart --wheel /absolute/path/to/transcripto-0.2.1-py3-none-any.whl
118
+ ```
119
+
120
+ Prints install, `import-lab`, search, and reopen commands for a built wheel
121
+ without PyPI. See also `docs/OFFLINE-QUICKSTART.md`.
122
+
123
+ **Your files remain yours.** Transcripto does not upload transcript content or
124
+ execute commands found in it. Search output, replay and JSON can contain private
125
+ words and paths; review anything you choose to share. It reads existing files,
126
+ not deleted history. Check your agent's retention settings and keep your own
127
+ backup if you want a lasting record. Authorship detection differs by harness;
128
+ [see the limits below](#what-each-harness-supports).
129
+
130
+ ## Find the thing you remember
131
+
132
+ Search automatically refreshes a local index. No setup command is required.
133
+
134
+ ```sh
135
+ transcripto ask "retry" # your submitted words
136
+ transcripto search "retry" # prompts, replies, and tool text
137
+ transcripto find parser.py # recorded file operations and attempts
138
+ transcripto trace "retry" # an alias into result-aware replay
139
+ transcripto sessions # sessions with submitted prompts
140
+ transcripto stats # activity counts
141
+ ```
142
+
143
+ A failed or unconfirmed file change is labelled an **attempt**, never `WROTE`.
144
+ Queries with `--harness` or `--root` are scoped to that selection even if the
145
+ index already contains another corpus. `index` and `watch` remain available for
146
+ explicit refresh and background polling.
147
+
148
+ ## The replay
149
+
150
+ This is output from `replay --demo`. **All prompts and results in this example
151
+ are invented.** The demo goes through the same parser as a real transcript.
152
+
153
+ ```text
154
+ THE COMEBACK · claude · request 1
155
+ You asked: "Fix the login redirect and run its tests."
156
+
157
+ 1 FAIL edit src/login.py
158
+ Tool error: Error: text not found [call L2 → result L3]
159
+ 2 OK edit src/login.py
160
+ Tool reported success. [call L4 → result L5]
161
+ 3 FAIL check pytest tests/test_login.py
162
+ Tool error: Process exited with code 1 [call L6 → result L7]
163
+ 4 OK edit src/login.py
164
+ Tool reported success. [call L8 → result L9]
165
+ 5 OK check pytest tests/test_login.py
166
+ Tool reported success. [call L10 → result L11]
167
+
168
+ Agent said: "The redirect is fixed and the tests pass."
169
+
170
+ Recorded: 3 succeeded · 2 failed · 0 unknown
171
+ Status describes a tool result, not task correctness. Missing results stay unknown.
172
+ ```
173
+
174
+ The headings have rules. **The comeback** means a recorded failure was followed
175
+ by success for the same operation and target, without a later failed or unknown
176
+ attempt on that target. **The snag** means a failure is
177
+ present. **The missing receipt** means a result is unknown. **The answer** means
178
+ there were no recorded tool calls; an explanation may have been the whole task.
179
+ These are descriptions of the sequence, not grades for you or your agent.
180
+
181
+ On your own history, each replay names its source file and line numbers, plus a
182
+ command that reopens that exact request. Long sequences open around the first
183
+ failure or change and tell you what was omitted. `--all` shows the full sequence.
184
+
185
+ ```sh
186
+ transcripto # latest session you submitted a request in
187
+ transcripto replay --failures # most recent request with a recorded failure
188
+ transcripto replay "login redirect" # find requests containing these words
189
+ transcripto replay path/to/session.jsonl # inspect one transcript
190
+ transcripto replay --session 3f9c1a2b # explicitly select a session prefix
191
+ transcripto replay path/to/session.jsonl --episode 3 --all
192
+ transcripto replay path/to/session.jsonl --line 42 # exact request from an ask hit
193
+ transcripto replay latest --json # structured events, evidence, source lines
194
+ transcripto replay latest --share # counts + caveat; no prompts or paths
195
+ ```
196
+
197
+ `--share` is intentionally small. Full replay output and JSON contain your own
198
+ words and local paths. The tool does not upload either.
199
+
200
+ ## What each harness supports
201
+
202
+ | Feature | Claude Code | Codex | Cursor |
203
+ |---|---|---|---|
204
+ | Replay, search, ask, find, trace, sessions, stats | Yes | Yes | Yes |
205
+ | Tool attempts | Native tool calls | Direct calls and supported static wrappers | `StrReplace`, `Shell`, `Write`, and other calls |
206
+ | Execution status | Matched results | Matched results; ambiguous wrappers stay unknown | Unknown when the export omits results or call IDs |
207
+ | Authorship | `promptSource` typed/queued, excluding injected/tool records | User messages with known injected context excluded | `<user_query>` wrapper; a weaker signal |
208
+ | Coach, export-run | Yes | Yes | Yes, with missing evidence preserved |
209
+ | API-equivalent cost | Yes | Not supported | Not supported |
210
+
211
+ ```sh
212
+ transcripto replay --harness claude
213
+ transcripto replay --harness codex
214
+ transcripto replay --harness cursor
215
+ transcripto search "retry" --harness codex
216
+ transcripto replay --root /path/to/transcripts
217
+ ```
218
+
219
+ Default roots are `~/.claude/projects`, `~/.codex`, and `~/.cursor`.
220
+ Codex reads sessions and archived sessions. Cursor reads the per-session files
221
+ under `projects/*/agent-transcripts/*/`. Latest-session replay skips subagents
222
+ and files without a submitted human request.
223
+
224
+ Cursor exports often contain calls without results. That is useful evidence
225
+ of an attempt, but not enough to claim success. Transcripto does not substitute
226
+ an assistant's closing message or a `turn_ended` record for the missing result.
227
+
228
+ ## The evidence contract
229
+
230
+ 1. A tool call is an **attempt**.
231
+ 2. A matching result may establish **succeeded** or **failed** execution.
232
+ 3. A missing result, a running command, or an ambiguous result is **unknown**.
233
+ 4. An exit code of zero is not proof that the requested task is correct.
234
+ 5. A later human request opens a new episode. Its work is never absorbed into
235
+ the previous request because the words happen to overlap.
236
+ 6. A command mentioning `git commit` is not necessarily a commit. Quoted text,
237
+ dry runs, and compound shell commands are not promoted to commit evidence.
238
+
239
+ The tool never executes transcript commands. It parses a limited set of static
240
+ Codex wrapper forms; arbitrary JavaScript and multiple nested child calls are
241
+ not reconstructed. A long-running call can remain unknown when completion is
242
+ only present in a later polling call. Cross-session durability, semantic task
243
+ completion, and live repository state are not inferred from transcript text.
244
+
245
+ ## Coach without invented grades
246
+
247
+ `transcripto coach` shows descriptive request history. It no longer recommends
248
+ prompt habits, labels a no-edit answer a bad prompt, or applies one person's
249
+ correction-rate calibration to someone else's data.
250
+
251
+ Habit proportions include **change attempts with known outcomes**. Unknown
252
+ outcomes and read-only tasks are excluded. The groups overlap and the requests
253
+ can be correlated, so these proportions are not significance tests or causal
254
+ advice. No best/worst ranking is printed. Correction markers are a lexical
255
+ estimate with false positives and misses, not a guaranteed lower bound.
256
+
257
+ Coach JSON is marked `transcripto.coach/2`. Legacy `durable`/`survived` fields
258
+ refer only to observed successful change results, not lasting work. Unknown
259
+ request outcomes have `survived: null`. `durable_rate` uses only known change
260
+ requests as its denominator and is null when there are none. `best_prompt` and `worst_prompt` are
261
+ retained as null compatibility fields. Use `successful_request`,
262
+ `failed_request`, and replay's event status to inspect evidence.
263
+
264
+ `export-run latest` always prints JSON. Its
265
+ existing `transcripto.export-run/1` keys remain available. `records` counts
266
+ normalized message records. `files_touched` lists attempted file targets,
267
+ including reads; it is not a successful-change count. Reflog commits are local
268
+ working-tree events inside the available timestamp window, not proof that this
269
+ agent caused them. Without a usable window, the commit fields are null.
270
+
271
+ ## Privacy and limits
272
+
273
+ The three runtime modules contain no network client, telemetry, account flow,
274
+ or process execution. Package installation (`pip` or `uvx`) is a separate
275
+ operation that may contact a package registry and write a package cache.
276
+
277
+ Replay and coach read transcripts without making an index. Search writes text
278
+ and file metadata to `~/.trace/trace.db`. A new index directory is private;
279
+ database and WAL files use mode `0600`. The index stays after the command exits.
280
+ Schema upgrades rebuild it locally. `replay --demo` briefly writes an invented
281
+ transcript to a temporary directory and removes it afterward.
282
+
283
+ Malformed records and unreadable files produce diagnostics. Search indexes the
284
+ valid records of partially malformed files and repeats the warning on later
285
+ queries until the source is repaired. A wholly unreadable file keeps any prior
286
+ indexed copy, with an explicit warning; replay always reads the source. Files larger than
287
+ 128 MiB are skipped before parsing; lines larger than 8 MiB are discarded as
288
+ whole records. Split larger files into smaller JSONL files to inspect them.
289
+ Individual displayed text fields are bounded at 16,000 characters. Replay's
290
+ source references let you inspect the original. Terminal control sequences are
291
+ removed from rendered transcript content.
292
+
293
+ ## Development
294
+
295
+ Python 3.9+, standard library only. The CLI remains in `transcripto.py`;
296
+ `transcripto_core.py` owns normalization and evidence; `transcripto_replay.py`
297
+ owns replay selection and presentation. All fixtures committed here are synthetic.
298
+
299
+ ```sh
300
+ python3 -m unittest discover -s tests -v
301
+ for test in test_*.sh; do bash "$test" || exit; done
302
+ ```
303
+
304
+ `test_distribution.sh` requires the development-only `build` package. It builds
305
+ an sdist, builds the wheel from that archive, installs without dependencies in a
306
+ fresh virtual environment, and exercises discovery, search and exact replay
307
+ across all three harnesses in an isolated synthetic HOME.
308
+
309
+ The regression cases include failed edits and commits, missing/mismatched
310
+ results, Cursor call shapes, Codex wrappers, result attribution across prompts,
311
+ rollback order, malformed JSON, a sparse 2 GiB file, terminal controls, private
312
+ index permissions, incremental search, and cross-harness retrieval.
313
+
314
+ MIT. Open an issue with the **record shape** that fails, or a synthetic
315
+ reproduction. Your real prompt text is not needed.
@@ -0,0 +1,297 @@
1
+ # Transcripto
2
+
3
+ **You might already be keeping a journal. Read your side of it.**
4
+
5
+ Your agent transcripts contain what you asked for, what you changed your mind
6
+ about, and what you kept coming back to. Transcripto helps you find those words
7
+ and read the recorded work around them.
8
+
9
+ Claude Code · Codex · Cursor. Local files. No account. No runtime dependencies.
10
+
11
+ ## Start with something you remember saying
12
+
13
+ ```sh
14
+ uvx --from transcripto==0.2.1 transcripto ask "retry"
15
+ ```
16
+
17
+ Replace `retry` with a word you remember using. `ask` searches messages identified
18
+ as yours and shows dated snippets, newest first. It refreshes the local index
19
+ automatically. The first search indexes the selected history; a large archive
20
+ can take minutes. Add `--harness claude`, `--harness codex`, or `--harness cursor`
21
+ to limit that scan. It does not generate a diary or interpret your personality.
22
+
23
+ Each hit prints an `Open:` command. Run that command to open the exact request
24
+ and its recorded work. This also works when search matches a word variant
25
+ (such as `retry` matching `retried`) or several requests share the same words.
26
+
27
+ You can also search replay directly:
28
+
29
+ ```sh
30
+ uvx --from transcripto==0.2.1 transcripto replay "retry"
31
+
32
+ # Or open your latest human session:
33
+ uvx --from transcripto==0.2.1 transcripto
34
+ ```
35
+
36
+ Replay puts your request, tool calls and recorded results in order. Failed edits
37
+ stay failed. Missing results stay unknown. Status describes tool execution,
38
+ not whether the task was done correctly.
39
+
40
+ Or install with `python3 -m pip install transcripto==0.2.1`, then run
41
+ `transcripto ask "retry"`. Requires Python 3.9 or newer.
42
+
43
+ ## Try the stranger flow without your transcripts
44
+
45
+ The bundled public example is synthetic. It works in an isolated home and does
46
+ not depend on agent dotfiles:
47
+
48
+ ```sh
49
+ INSTALL="$(mktemp -d)"
50
+ python3 -m pip install --no-deps --no-build-isolation --target "$INSTALL" .
51
+ export HOME="$(mktemp -d)"
52
+ transcripto() { PYTHONPATH="$INSTALL" python3 -m transcripto "$@"; }
53
+
54
+ transcripto import-example
55
+ transcripto ask "What changed about the forecast cache?"
56
+ transcripto changes
57
+ ```
58
+
59
+ `ask` cites the imported JSONL line for every hit. `changes` is a focused view
60
+ of the request that was revised, the correction, and its recorded follow-up.
61
+ It labels missing results rather than turning a change of mind into a score.
62
+
63
+ To carry that correction to a different receiver:
64
+
65
+ ```sh
66
+ transcripto handoff "30 seconds" \
67
+ --to-harness codex --output "$HOME/codex-inbox/correction.json"
68
+ transcripto receive-handoff \
69
+ "$HOME/codex-inbox/correction.json" --as-harness codex \
70
+ --output "$HOME/codex-work/receiver-brief.md"
71
+ cat "$HOME/codex-work/receiver-brief.md"
72
+ ```
73
+
74
+ The brief includes the cited correction, recorded follow-up statuses
75
+ (failed / succeeded / unknown), and an `Open:` command for the exact request.
76
+ If the source moved, disappeared, or no longer holds the cited request, the brief
77
+ marks evidence uncertain and shows only the packet's own statuses as provisional. It does not invoke a receiver agent or prove
78
+ adoption. Synthetic provenance stays visible in search, changes, and handoffs.
79
+ Handoff files are local and mode `0600`; they can contain transcript text and
80
+ paths, so review them before sharing.
81
+
82
+ ### Cross-harness lab (failed / succeeded / unknown)
83
+
84
+ For a receiving agent that needs to find a prior episode and reopen exact
85
+ evidence without private history:
86
+
87
+ ```sh
88
+ transcripto import-lab
89
+ transcripto ask "retry"
90
+ # run each printed Open: command
91
+ ```
92
+
93
+ All lab records are labelled synthetic. Claude shows a failed edit, Codex a
94
+ succeeded check, Cursor an unknown missing result.
95
+
96
+ ### Offline flight card
97
+
98
+ ```sh
99
+ transcripto quickstart --wheel /absolute/path/to/transcripto-0.2.1-py3-none-any.whl
100
+ ```
101
+
102
+ Prints install, `import-lab`, search, and reopen commands for a built wheel
103
+ without PyPI. See also `docs/OFFLINE-QUICKSTART.md`.
104
+
105
+ **Your files remain yours.** Transcripto does not upload transcript content or
106
+ execute commands found in it. Search output, replay and JSON can contain private
107
+ words and paths; review anything you choose to share. It reads existing files,
108
+ not deleted history. Check your agent's retention settings and keep your own
109
+ backup if you want a lasting record. Authorship detection differs by harness;
110
+ [see the limits below](#what-each-harness-supports).
111
+
112
+ ## Find the thing you remember
113
+
114
+ Search automatically refreshes a local index. No setup command is required.
115
+
116
+ ```sh
117
+ transcripto ask "retry" # your submitted words
118
+ transcripto search "retry" # prompts, replies, and tool text
119
+ transcripto find parser.py # recorded file operations and attempts
120
+ transcripto trace "retry" # an alias into result-aware replay
121
+ transcripto sessions # sessions with submitted prompts
122
+ transcripto stats # activity counts
123
+ ```
124
+
125
+ A failed or unconfirmed file change is labelled an **attempt**, never `WROTE`.
126
+ Queries with `--harness` or `--root` are scoped to that selection even if the
127
+ index already contains another corpus. `index` and `watch` remain available for
128
+ explicit refresh and background polling.
129
+
130
+ ## The replay
131
+
132
+ This is output from `replay --demo`. **All prompts and results in this example
133
+ are invented.** The demo goes through the same parser as a real transcript.
134
+
135
+ ```text
136
+ THE COMEBACK · claude · request 1
137
+ You asked: "Fix the login redirect and run its tests."
138
+
139
+ 1 FAIL edit src/login.py
140
+ Tool error: Error: text not found [call L2 → result L3]
141
+ 2 OK edit src/login.py
142
+ Tool reported success. [call L4 → result L5]
143
+ 3 FAIL check pytest tests/test_login.py
144
+ Tool error: Process exited with code 1 [call L6 → result L7]
145
+ 4 OK edit src/login.py
146
+ Tool reported success. [call L8 → result L9]
147
+ 5 OK check pytest tests/test_login.py
148
+ Tool reported success. [call L10 → result L11]
149
+
150
+ Agent said: "The redirect is fixed and the tests pass."
151
+
152
+ Recorded: 3 succeeded · 2 failed · 0 unknown
153
+ Status describes a tool result, not task correctness. Missing results stay unknown.
154
+ ```
155
+
156
+ The headings have rules. **The comeback** means a recorded failure was followed
157
+ by success for the same operation and target, without a later failed or unknown
158
+ attempt on that target. **The snag** means a failure is
159
+ present. **The missing receipt** means a result is unknown. **The answer** means
160
+ there were no recorded tool calls; an explanation may have been the whole task.
161
+ These are descriptions of the sequence, not grades for you or your agent.
162
+
163
+ On your own history, each replay names its source file and line numbers, plus a
164
+ command that reopens that exact request. Long sequences open around the first
165
+ failure or change and tell you what was omitted. `--all` shows the full sequence.
166
+
167
+ ```sh
168
+ transcripto # latest session you submitted a request in
169
+ transcripto replay --failures # most recent request with a recorded failure
170
+ transcripto replay "login redirect" # find requests containing these words
171
+ transcripto replay path/to/session.jsonl # inspect one transcript
172
+ transcripto replay --session 3f9c1a2b # explicitly select a session prefix
173
+ transcripto replay path/to/session.jsonl --episode 3 --all
174
+ transcripto replay path/to/session.jsonl --line 42 # exact request from an ask hit
175
+ transcripto replay latest --json # structured events, evidence, source lines
176
+ transcripto replay latest --share # counts + caveat; no prompts or paths
177
+ ```
178
+
179
+ `--share` is intentionally small. Full replay output and JSON contain your own
180
+ words and local paths. The tool does not upload either.
181
+
182
+ ## What each harness supports
183
+
184
+ | Feature | Claude Code | Codex | Cursor |
185
+ |---|---|---|---|
186
+ | Replay, search, ask, find, trace, sessions, stats | Yes | Yes | Yes |
187
+ | Tool attempts | Native tool calls | Direct calls and supported static wrappers | `StrReplace`, `Shell`, `Write`, and other calls |
188
+ | Execution status | Matched results | Matched results; ambiguous wrappers stay unknown | Unknown when the export omits results or call IDs |
189
+ | Authorship | `promptSource` typed/queued, excluding injected/tool records | User messages with known injected context excluded | `<user_query>` wrapper; a weaker signal |
190
+ | Coach, export-run | Yes | Yes | Yes, with missing evidence preserved |
191
+ | API-equivalent cost | Yes | Not supported | Not supported |
192
+
193
+ ```sh
194
+ transcripto replay --harness claude
195
+ transcripto replay --harness codex
196
+ transcripto replay --harness cursor
197
+ transcripto search "retry" --harness codex
198
+ transcripto replay --root /path/to/transcripts
199
+ ```
200
+
201
+ Default roots are `~/.claude/projects`, `~/.codex`, and `~/.cursor`.
202
+ Codex reads sessions and archived sessions. Cursor reads the per-session files
203
+ under `projects/*/agent-transcripts/*/`. Latest-session replay skips subagents
204
+ and files without a submitted human request.
205
+
206
+ Cursor exports often contain calls without results. That is useful evidence
207
+ of an attempt, but not enough to claim success. Transcripto does not substitute
208
+ an assistant's closing message or a `turn_ended` record for the missing result.
209
+
210
+ ## The evidence contract
211
+
212
+ 1. A tool call is an **attempt**.
213
+ 2. A matching result may establish **succeeded** or **failed** execution.
214
+ 3. A missing result, a running command, or an ambiguous result is **unknown**.
215
+ 4. An exit code of zero is not proof that the requested task is correct.
216
+ 5. A later human request opens a new episode. Its work is never absorbed into
217
+ the previous request because the words happen to overlap.
218
+ 6. A command mentioning `git commit` is not necessarily a commit. Quoted text,
219
+ dry runs, and compound shell commands are not promoted to commit evidence.
220
+
221
+ The tool never executes transcript commands. It parses a limited set of static
222
+ Codex wrapper forms; arbitrary JavaScript and multiple nested child calls are
223
+ not reconstructed. A long-running call can remain unknown when completion is
224
+ only present in a later polling call. Cross-session durability, semantic task
225
+ completion, and live repository state are not inferred from transcript text.
226
+
227
+ ## Coach without invented grades
228
+
229
+ `transcripto coach` shows descriptive request history. It no longer recommends
230
+ prompt habits, labels a no-edit answer a bad prompt, or applies one person's
231
+ correction-rate calibration to someone else's data.
232
+
233
+ Habit proportions include **change attempts with known outcomes**. Unknown
234
+ outcomes and read-only tasks are excluded. The groups overlap and the requests
235
+ can be correlated, so these proportions are not significance tests or causal
236
+ advice. No best/worst ranking is printed. Correction markers are a lexical
237
+ estimate with false positives and misses, not a guaranteed lower bound.
238
+
239
+ Coach JSON is marked `transcripto.coach/2`. Legacy `durable`/`survived` fields
240
+ refer only to observed successful change results, not lasting work. Unknown
241
+ request outcomes have `survived: null`. `durable_rate` uses only known change
242
+ requests as its denominator and is null when there are none. `best_prompt` and `worst_prompt` are
243
+ retained as null compatibility fields. Use `successful_request`,
244
+ `failed_request`, and replay's event status to inspect evidence.
245
+
246
+ `export-run latest` always prints JSON. Its
247
+ existing `transcripto.export-run/1` keys remain available. `records` counts
248
+ normalized message records. `files_touched` lists attempted file targets,
249
+ including reads; it is not a successful-change count. Reflog commits are local
250
+ working-tree events inside the available timestamp window, not proof that this
251
+ agent caused them. Without a usable window, the commit fields are null.
252
+
253
+ ## Privacy and limits
254
+
255
+ The three runtime modules contain no network client, telemetry, account flow,
256
+ or process execution. Package installation (`pip` or `uvx`) is a separate
257
+ operation that may contact a package registry and write a package cache.
258
+
259
+ Replay and coach read transcripts without making an index. Search writes text
260
+ and file metadata to `~/.trace/trace.db`. A new index directory is private;
261
+ database and WAL files use mode `0600`. The index stays after the command exits.
262
+ Schema upgrades rebuild it locally. `replay --demo` briefly writes an invented
263
+ transcript to a temporary directory and removes it afterward.
264
+
265
+ Malformed records and unreadable files produce diagnostics. Search indexes the
266
+ valid records of partially malformed files and repeats the warning on later
267
+ queries until the source is repaired. A wholly unreadable file keeps any prior
268
+ indexed copy, with an explicit warning; replay always reads the source. Files larger than
269
+ 128 MiB are skipped before parsing; lines larger than 8 MiB are discarded as
270
+ whole records. Split larger files into smaller JSONL files to inspect them.
271
+ Individual displayed text fields are bounded at 16,000 characters. Replay's
272
+ source references let you inspect the original. Terminal control sequences are
273
+ removed from rendered transcript content.
274
+
275
+ ## Development
276
+
277
+ Python 3.9+, standard library only. The CLI remains in `transcripto.py`;
278
+ `transcripto_core.py` owns normalization and evidence; `transcripto_replay.py`
279
+ owns replay selection and presentation. All fixtures committed here are synthetic.
280
+
281
+ ```sh
282
+ python3 -m unittest discover -s tests -v
283
+ for test in test_*.sh; do bash "$test" || exit; done
284
+ ```
285
+
286
+ `test_distribution.sh` requires the development-only `build` package. It builds
287
+ an sdist, builds the wheel from that archive, installs without dependencies in a
288
+ fresh virtual environment, and exercises discovery, search and exact replay
289
+ across all three harnesses in an isolated synthetic HOME.
290
+
291
+ The regression cases include failed edits and commits, missing/mismatched
292
+ results, Cursor call shapes, Codex wrappers, result attribution across prompts,
293
+ rollback order, malformed JSON, a sparse 2 GiB file, terminal controls, private
294
+ index permissions, incremental search, and cross-harness retrieval.
295
+
296
+ MIT. Open an issue with the **record shape** that fails, or a synthetic
297
+ reproduction. Your real prompt text is not needed.
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "transcripto"
7
- version = "0.1.5"
8
- description = "Search everything your coding agents ever did, grade your own prompts, and price your decisions. Local, stdlib-only, your data never leaves the machine."
7
+ version = "0.2.1"
8
+ description = "Instant replay for coding agents. Inspect requests, tool calls, and recorded results across Claude Code, Codex, and Cursor. Local, stdlib-only."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
11
  license = { text = "MIT" }
@@ -28,4 +28,4 @@ Source = "https://github.com/Morkeeth/transcripto"
28
28
  transcripto = "transcripto:main"
29
29
 
30
30
  [tool.setuptools]
31
- py-modules = ["transcripto"]
31
+ py-modules = ["transcripto", "transcripto_core", "transcripto_replay"]