codex-cissor 0.2.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 (30) hide show
  1. codex_cissor-0.2.0/LICENSE +21 -0
  2. codex_cissor-0.2.0/PKG-INFO +309 -0
  3. codex_cissor-0.2.0/README.md +289 -0
  4. codex_cissor-0.2.0/codex_cissor/__init__.py +0 -0
  5. codex_cissor-0.2.0/codex_cissor/__main__.py +5 -0
  6. codex_cissor-0.2.0/codex_cissor/activity.py +68 -0
  7. codex_cissor-0.2.0/codex_cissor/asks.py +228 -0
  8. codex_cissor-0.2.0/codex_cissor/cli.py +1074 -0
  9. codex_cissor-0.2.0/codex_cissor/config.py +106 -0
  10. codex_cissor-0.2.0/codex_cissor/edits.py +543 -0
  11. codex_cissor-0.2.0/codex_cissor/export.py +186 -0
  12. codex_cissor-0.2.0/codex_cissor/rollout.py +273 -0
  13. codex_cissor-0.2.0/codex_cissor/selection.py +101 -0
  14. codex_cissor-0.2.0/codex_cissor/sessions.py +288 -0
  15. codex_cissor-0.2.0/codex_cissor/styles.py +116 -0
  16. codex_cissor-0.2.0/codex_cissor/summarize.py +171 -0
  17. codex_cissor-0.2.0/codex_cissor/tokens.py +49 -0
  18. codex_cissor-0.2.0/codex_cissor/validate.py +72 -0
  19. codex_cissor-0.2.0/codex_cissor.egg-info/PKG-INFO +309 -0
  20. codex_cissor-0.2.0/codex_cissor.egg-info/SOURCES.txt +28 -0
  21. codex_cissor-0.2.0/codex_cissor.egg-info/dependency_links.txt +1 -0
  22. codex_cissor-0.2.0/codex_cissor.egg-info/entry_points.txt +2 -0
  23. codex_cissor-0.2.0/codex_cissor.egg-info/requires.txt +5 -0
  24. codex_cissor-0.2.0/codex_cissor.egg-info/top_level.txt +1 -0
  25. codex_cissor-0.2.0/pyproject.toml +34 -0
  26. codex_cissor-0.2.0/setup.cfg +4 -0
  27. codex_cissor-0.2.0/tests/test_edits.py +232 -0
  28. codex_cissor-0.2.0/tests/test_new_features.py +430 -0
  29. codex_cissor-0.2.0/tests/test_rollout.py +96 -0
  30. codex_cissor-0.2.0/tests/test_selection.py +75 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kelvin Ng'eno Ndumia
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.4
2
+ Name: codex-cissor
3
+ Version: 0.2.0
4
+ Summary: cissor — edit your Codex CLI session context: trim tool outputs, summarize or evict spans, then resume a lean session
5
+ Author: Kevin Ng'eno
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/Ngenome/codex-cissor
8
+ Keywords: codex,cli,context,tokens,sessions
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Environment :: Console
11
+ Classifier: Topic :: Software Development
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: tiktoken>=0.8
16
+ Requires-Dist: requests>=2.31
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest>=8; extra == "dev"
19
+ Dynamic: license-file
20
+
21
+ # codex-cissor — edit your Codex session context
22
+
23
+ `cissor` edits the context of Codex CLI sessions: trim bloated tool outputs,
24
+ summarize stale turns in place, evict spans to files with recovery pointers,
25
+ transplant or inject content — then resume the leaner session with
26
+ `codex resume <id>`. It also inspects what is eating the window, exports
27
+ markdown archives, and answers questions about oversized material without
28
+ loading it into your context.
29
+
30
+ Edits happen on fork drafts; publishing (gated on offline validation) is how a
31
+ finished fork returns to the canonical sessions tree.
32
+
33
+ Sessions live in `~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl`. cissor
34
+ parses that format directly, including `compacted` records.
35
+
36
+ ## Install
37
+
38
+ ```
39
+ uv tool install codex-cissor # from PyPI (or: pipx install codex-cissor)
40
+ ```
41
+
42
+ Requires `OPENROUTER_API_KEY` in the environment for LLM-backed commands
43
+ (summarize / index / export chronicle / ask / replace / evict --with-summary).
44
+ Inspection, forking, editing, validation, and transcript export work offline.
45
+ Token estimates use tiktoken (`o200k_base` by default).
46
+
47
+ ## Config
48
+
49
+ ```
50
+ cissor config path # where config/manifest/logs live (~/.codex/cxcm/)
51
+ cissor config show
52
+ cissor config set model z-ai/glm-5.3-flash # summarizer
53
+ cissor config set ask_max_input_tokens 120000 # above this, ask() switches to map-reduce
54
+ cissor config set encoding o200k_base
55
+ ```
56
+
57
+ Any OpenRouter model id works; env overrides via `CISSOR_MODEL`, `CISSOR_ASK_MAX_INPUT_TOKENS`, etc.
58
+
59
+ - `ask_max_input_tokens` (120k): the switch-point where `ask` stops sending the
60
+ whole material in one call and switches to question-keyed map-reduce.
61
+ - `context_window_tokens` (0 = unknown): the model's context limit, purely advisory —
62
+ `inspect` reports % of window. Codex defaults to 272k (expandable to 1M);
63
+ auto-compaction triggers around the ~682k hard max.
64
+
65
+ ## Compaction-aware scope
66
+
67
+ A `compacted` record contains `{message, replacement_history}`. On resume, Codex
68
+ replays **only** the last compaction's `replacement_history` + everything after it.
69
+ cissor therefore:
70
+
71
+ - numbers turns/items over the **effective context** (post-last-compaction) by default,
72
+ - warns when you touch pre-compaction items (they are not in the live window),
73
+ - supports `--scope full` to address the **entire file** including pre-compaction
74
+ history, and `--scope post-compact|auto|full` everywhere selection applies,
75
+ - `edit uncompact` removes the compacted record to restore the full pre-compaction
76
+ history (all of it is still in the file),
77
+ - items inside `replacement_history` are addressable and editable like any other item,
78
+ - `history` lists every compaction point with what it hides.
79
+
80
+ ## Commands
81
+
82
+ ### Inspection
83
+
84
+ ```
85
+ cissor list [--limit N] [--json] # sessions, newest first (fork names shown)
86
+ cissor inspect <session> [--scope full] [--json] # per-turn + per-type token breakdown
87
+ cissor inspect <session> --turns 3-7 # breakdown of a selection
88
+ cissor show <session> --turns 3-4 [--max-chars N] # actual content of a selection
89
+ cissor history <session> [--json] # compaction points: line, summary, hidden tokens
90
+ cissor validate <session> [--json] # structural check (pairs, reasoning, meta)
91
+ cissor forks [--channel X] [--json] # registered forks: channels, lineage, op counts
92
+ cissor log [--session X] [--channel C] [--project P] [--stats] [--path] # activity trail
93
+ ```
94
+
95
+ Address a session by: full/prefix id, manifest name, `latest`, or file path.
96
+
97
+ **Two kinds of placeholders:** `<session>` = any of the above, for read-only
98
+ commands. `<fork-id>` = the draft id returned by `cissor fork` — required by every
99
+ mutating command (`edit`, `transplant`, `inject`, `extract --evict`); `latest` is
100
+ refused there and non-fork originals are always refused.
101
+
102
+ ### Selection (shared by inspect/show/summarize/index/export/extract/ask/edit ops)
103
+
104
+ ```
105
+ --scope auto|post-compact|full
106
+ --turns "2-10" turn ranges/lists
107
+ --items "12,15-20" item numbers
108
+ --from-text "needle" from first item containing text to end (inclusive)
109
+ --to-text "needle" from start to last item containing text (inclusive)
110
+ --turn-from-text / --turn-to-text
111
+ --all everything in scope
112
+ ```
113
+
114
+ `--from-text` + `--to-text` together bound a single inclusive span (both anchor
115
+ items included). One-sided use opens a range to the start/end of scope.
116
+
117
+ ### Summarize (read-only)
118
+
119
+ ```
120
+ cissor summarize <session> --turns 1-40 --style index
121
+ cissor summarize <session> --turns 2-10 --style key-points --out s.md
122
+ cissor summarize <session> --turns 2-10 --prompt "focus only on pricing decisions"
123
+ ```
124
+
125
+ Styles are editable markdown files (see Styles below): `chronicle`, `index`,
126
+ `short`, `key-points`, `export-chronicle`, plus your own — or pass a one-off
127
+ `--prompt`/`--prompt-file` inline. Long selections are map-reduced in
128
+ ~48k-token chunks (`chunk_tokens`).
129
+
130
+ ### Event index
131
+
132
+ ```
133
+ cissor index <session> # generate + save to cissor state
134
+ cissor index <session> --locate "pricing" # search existing index, else generate
135
+ cissor index <session> --out D:\indexes\voice.md # custom location
136
+ ```
137
+
138
+ Produces `Items A-B (turn T): title — description` entries for fast navigation;
139
+ `--locate` answers "where was X discussed" in item/turn ranges.
140
+
141
+ ### Export (archival)
142
+
143
+ ```
144
+ cissor export <session> # markdown transcript to stdout
145
+ cissor export <session> --turns 3-9 --out archive.md
146
+ cissor export <session> --strategy chronicle # LLM chronicle segment
147
+ cissor export <session> --strategy chronicle --chronicle-dir docs\chronicles
148
+ cissor export <session> --strategy index-only
149
+ cissor export <session> --no-outputs --include-reasoning --max-item-chars 2000
150
+ ```
151
+
152
+ Transcripts use `**User** (item 4):` / `**Assistant**` / `**Tool call: name**`
153
+ labels under `## Turn N` headings. Developer/system messages and synthetic user
154
+ context (`<environment_context>` etc.) are excluded by default — pass
155
+ `--include-developer` / `--include-synthetic` to keep them (the header records
156
+ what was excluded).
157
+
158
+ `--chronicle-dir` maintains the conversation-chronicle skill layout: numbered
159
+ segments (`NNNN-YYYY-MM-DD-HHMM-title.md`) + master `INDEX.md` with event index.
160
+
161
+ ### Extract / evict to file
162
+
163
+ ```
164
+ cissor extract <session> --turns 5-11 --out span.md # read-only dump (md|json|raw)
165
+ cissor extract <fork> --items 17-56 --out span.md --evict # + pointer message in fork
166
+ cissor extract <fork> --from-text A --to-text B --evict --with-summary --out span.md
167
+ ```
168
+
169
+ `--evict` removes the span from the fork and leaves a `<context_evicted>` user
170
+ message with the archive path (plus an LLM summary with `--with-summary`).
171
+ Text anchors are inclusive (both anchor items are part of the span); evictions
172
+ covering >60% of scope or >150k tokens are refused without `--force` (over-broad
173
+ anchor protection). `--format raw` writes re-importable JSONL lines.
174
+
175
+ ### Ask — query oversized material with another LLM (stateful)
176
+
177
+ ```
178
+ cissor ask D:\data\huge.json "What are the top-level keys and their types?"
179
+ cissor ask <session> --scope full "What did we decide about X early on?"
180
+ cissor ask <ask-id> "follow-up question" # continues the session
181
+ cissor asks list / cissor asks show <ask-id>
182
+ ```
183
+
184
+ The target (any text file, or a session slice) is sent WHOLE to the ask model —
185
+ your agent's context never holds it. Above `ask_max_input_tokens` it falls back to
186
+ **question-keyed map-reduce**: the material is split into ~48k-token chunks, and
187
+ each chunk is filtered through the QUESTION ("extract every fact relevant to this
188
+ question, with exact values and anchors") — that's the map phase, keyed to the
189
+ question rather than generic summarization. A final reduce call merges the
190
+ extracts into a grounded answer citing which fragments support each claim. Note:
191
+ each new question on an oversized target re-scans the chunks. Answers cite
192
+ item/turn anchors when the material provides them. PDFs/binary are rejected with a
193
+ conversion hint — convert to text/markdown first, then ask the converted file.
194
+
195
+ ### Fork (draft) → edit → publish
196
+
197
+ Forks are **drafts stored in `~/.codex/cxcm/forks/`** — invisible to Codex until
198
+ published, so the canonical session list stays clean while editing is in progress.
199
+
200
+ ```
201
+ cissor fork <session> --name my-fork # or --suffix trimmed, or neither (auto -fork)
202
+ cissor fork <session> --channel diet-auth # stable work-stream id (default: source session id,
203
+ # inherited by fork-of-fork so a chain stays grouped)
204
+ cissor edit <fork-id> ... # work on the draft
205
+ cissor publish <fork-id> # offline validation gate, then copies into sessions tree
206
+ codex resume <published-id> # user resumes
207
+ cissor forks [--channel diet-auth] # registered forks: status, lineage, op counts
208
+ ```
209
+
210
+ **Fork discipline:** the fork is agent-invoked and returns an id; every editing
211
+ action must pass that id explicitly. `latest` is refused for edits. Multiple forks
212
+ are fine when each is deliberate; channels group related forks, and a repeat fork
213
+ in the same channel within 30 minutes prints a warning pointing at the existing
214
+ one. Fork of a fork inherits the parent channel and extends the lineage chain.
215
+
216
+ **Originals are never edited in place — no override exists.** Editing requires a
217
+ registered fork; `--force` only exists for the over-broad eviction guard.
218
+
219
+ `cissor publish <fork-id>` runs the offline validator first (no Codex invocation, no
220
+ tokens) and refuses to publish a structurally broken fork; `--open` then launches
221
+ `codex resume <id>` in the fork's project directory. Re-publishing an already
222
+ published fork is refused unless `--republish`.
223
+
224
+ Note: forks keep the source session's cwd (provenance). Codex's resume lookup
225
+ filters by cwd, so resume from the same project works directly; from a different
226
+ directory use `codex resume --all <id>` / `codex exec resume --all <id>`.
227
+
228
+ ### Edit (fork drafts only — originals are immutable; requires the explicit fork id)
229
+
230
+ ```
231
+ cissor edit <fork> drop --turns 3-7
232
+ cissor edit <fork> replace --turns 2-40 --style index # summarize + splice summary
233
+ cissor edit <fork> replace --turns 2-40 --summary-file s.md # splice a hand-written summary
234
+ cissor edit <fork> trim-outputs --turns 2-10 --keep-chars 250 --min-tokens 200
235
+ cissor edit <fork> trim-outputs --all --keep-chars 400
236
+ cissor edit <fork> trim-inputs --all --keep-chars 200
237
+ cissor edit <fork> uncompact [--which last|first|all]
238
+ cissor edit <fork> transplant --from <other-session> --turns 3-9 # copy a span in (pairs kept intact)
239
+ cissor edit <fork> inject --file notes.md --label project_notes # add a whole document as a turn
240
+ ```
241
+
242
+ `inject` appends ONE message at the end — `user` role by default
243
+ (`--role developer|assistant` available) — wrapped in `<label>` tags; no fake
244
+ assistant turn is added. `transplant` requires complete call/output pairs in the
245
+ span and renames colliding call_ids automatically.
246
+
247
+ Safety model:
248
+
249
+ - originals are immutable — edits only ever touch fork drafts, never `--force`-able
250
+ - never touches `session_meta`, `turn_context`, `event_msg`, `world_state` records
251
+ - dropping/replacing a tool call auto-includes its paired output (and vice versa),
252
+ plus any reasoning items directly attached to them — a broken call/output pair or
253
+ a dangling reasoning item makes resume fail
254
+ - refuses to remove the last user message
255
+ - every save: pre-edit `.cxcm-bak` backup, post-edit validation; pre-existing
256
+ structural errors (some of Codex's own compactions leave orphan calls) are
257
+ reported but don't block edits — only **new** errors do
258
+ - all writes are atomic (temp file + rename)
259
+ - reports/log lines compress item lists to ranges (`17-56`) to save agent context
260
+
261
+ ## Styles — editable prompts
262
+
263
+ ```
264
+ cissor styles list # builtin | file | custom
265
+ cissor styles show index
266
+ cissor styles edit index # materializes the default, prints the path; edit at will
267
+ cissor styles reset index # back to builtin
268
+ ```
269
+
270
+ Style files live in `~/.codex/cxcm/styles/<name>.md`; a file overrides the builtin.
271
+ Create `<your-style>.md` for custom compaction flavours and use `--style your-style`.
272
+
273
+ ## Traceability
274
+
275
+ Every mutating or LLM-backed action appends one line to
276
+ `~/.codex/cxcm/activity.jsonl` (ts, kind, session, channel, project cwd, op, items,
277
+ tokens before/after, model, outputs). Forks additionally keep per-fork op history
278
+ in `~/.codex/cxcm/manifest.json`.
279
+
280
+ ```
281
+ cissor log # last 30 events (item lists range-compressed)
282
+ cissor log --stats # compact aggregate: events by kind, total tokens saved, channels
283
+ cissor log --channel diet-auth # everything for one work stream
284
+ cissor log --project ai-landscape # everything for one project cwd
285
+ cissor log --path # just print the file paths — grep them with bash for deep dives
286
+ ```
287
+
288
+ Never dump the whole log into an agent context; use `--path` + shell search, or
289
+ `--stats` for a summary.
290
+
291
+ ## Agent self-service workflow
292
+
293
+ ```
294
+ cissor fork latest --suffix context-diet
295
+ cissor index <fork> --locate "the pricing bug" # find what matters
296
+ cissor extract <fork> --turns 3-8 --out dump.md --evict --with-summary
297
+ cissor edit <fork> trim-outputs --all --keep-chars 300 --min-tokens 300
298
+ cissor edit <fork> replace --turns 9-40 --style index
299
+ cissor validate <fork>
300
+ codex resume <new-id>
301
+ ```
302
+
303
+ ## Notes
304
+
305
+ - Token estimates cover conversation items only — not the system prompt, developer
306
+ instructions stored in `session_meta`, or tool schemas. Real API usage (from
307
+ `token_count` events) is shown by `inspect` for comparison.
308
+ - `.cxcm-bak` files sit next to edited sessions; Codex ignores them.
309
+ - Roadmap ideas live in `ROADMAP.md`.
@@ -0,0 +1,289 @@
1
+ # codex-cissor — edit your Codex session context
2
+
3
+ `cissor` edits the context of Codex CLI sessions: trim bloated tool outputs,
4
+ summarize stale turns in place, evict spans to files with recovery pointers,
5
+ transplant or inject content — then resume the leaner session with
6
+ `codex resume <id>`. It also inspects what is eating the window, exports
7
+ markdown archives, and answers questions about oversized material without
8
+ loading it into your context.
9
+
10
+ Edits happen on fork drafts; publishing (gated on offline validation) is how a
11
+ finished fork returns to the canonical sessions tree.
12
+
13
+ Sessions live in `~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl`. cissor
14
+ parses that format directly, including `compacted` records.
15
+
16
+ ## Install
17
+
18
+ ```
19
+ uv tool install codex-cissor # from PyPI (or: pipx install codex-cissor)
20
+ ```
21
+
22
+ Requires `OPENROUTER_API_KEY` in the environment for LLM-backed commands
23
+ (summarize / index / export chronicle / ask / replace / evict --with-summary).
24
+ Inspection, forking, editing, validation, and transcript export work offline.
25
+ Token estimates use tiktoken (`o200k_base` by default).
26
+
27
+ ## Config
28
+
29
+ ```
30
+ cissor config path # where config/manifest/logs live (~/.codex/cxcm/)
31
+ cissor config show
32
+ cissor config set model z-ai/glm-5.3-flash # summarizer
33
+ cissor config set ask_max_input_tokens 120000 # above this, ask() switches to map-reduce
34
+ cissor config set encoding o200k_base
35
+ ```
36
+
37
+ Any OpenRouter model id works; env overrides via `CISSOR_MODEL`, `CISSOR_ASK_MAX_INPUT_TOKENS`, etc.
38
+
39
+ - `ask_max_input_tokens` (120k): the switch-point where `ask` stops sending the
40
+ whole material in one call and switches to question-keyed map-reduce.
41
+ - `context_window_tokens` (0 = unknown): the model's context limit, purely advisory —
42
+ `inspect` reports % of window. Codex defaults to 272k (expandable to 1M);
43
+ auto-compaction triggers around the ~682k hard max.
44
+
45
+ ## Compaction-aware scope
46
+
47
+ A `compacted` record contains `{message, replacement_history}`. On resume, Codex
48
+ replays **only** the last compaction's `replacement_history` + everything after it.
49
+ cissor therefore:
50
+
51
+ - numbers turns/items over the **effective context** (post-last-compaction) by default,
52
+ - warns when you touch pre-compaction items (they are not in the live window),
53
+ - supports `--scope full` to address the **entire file** including pre-compaction
54
+ history, and `--scope post-compact|auto|full` everywhere selection applies,
55
+ - `edit uncompact` removes the compacted record to restore the full pre-compaction
56
+ history (all of it is still in the file),
57
+ - items inside `replacement_history` are addressable and editable like any other item,
58
+ - `history` lists every compaction point with what it hides.
59
+
60
+ ## Commands
61
+
62
+ ### Inspection
63
+
64
+ ```
65
+ cissor list [--limit N] [--json] # sessions, newest first (fork names shown)
66
+ cissor inspect <session> [--scope full] [--json] # per-turn + per-type token breakdown
67
+ cissor inspect <session> --turns 3-7 # breakdown of a selection
68
+ cissor show <session> --turns 3-4 [--max-chars N] # actual content of a selection
69
+ cissor history <session> [--json] # compaction points: line, summary, hidden tokens
70
+ cissor validate <session> [--json] # structural check (pairs, reasoning, meta)
71
+ cissor forks [--channel X] [--json] # registered forks: channels, lineage, op counts
72
+ cissor log [--session X] [--channel C] [--project P] [--stats] [--path] # activity trail
73
+ ```
74
+
75
+ Address a session by: full/prefix id, manifest name, `latest`, or file path.
76
+
77
+ **Two kinds of placeholders:** `<session>` = any of the above, for read-only
78
+ commands. `<fork-id>` = the draft id returned by `cissor fork` — required by every
79
+ mutating command (`edit`, `transplant`, `inject`, `extract --evict`); `latest` is
80
+ refused there and non-fork originals are always refused.
81
+
82
+ ### Selection (shared by inspect/show/summarize/index/export/extract/ask/edit ops)
83
+
84
+ ```
85
+ --scope auto|post-compact|full
86
+ --turns "2-10" turn ranges/lists
87
+ --items "12,15-20" item numbers
88
+ --from-text "needle" from first item containing text to end (inclusive)
89
+ --to-text "needle" from start to last item containing text (inclusive)
90
+ --turn-from-text / --turn-to-text
91
+ --all everything in scope
92
+ ```
93
+
94
+ `--from-text` + `--to-text` together bound a single inclusive span (both anchor
95
+ items included). One-sided use opens a range to the start/end of scope.
96
+
97
+ ### Summarize (read-only)
98
+
99
+ ```
100
+ cissor summarize <session> --turns 1-40 --style index
101
+ cissor summarize <session> --turns 2-10 --style key-points --out s.md
102
+ cissor summarize <session> --turns 2-10 --prompt "focus only on pricing decisions"
103
+ ```
104
+
105
+ Styles are editable markdown files (see Styles below): `chronicle`, `index`,
106
+ `short`, `key-points`, `export-chronicle`, plus your own — or pass a one-off
107
+ `--prompt`/`--prompt-file` inline. Long selections are map-reduced in
108
+ ~48k-token chunks (`chunk_tokens`).
109
+
110
+ ### Event index
111
+
112
+ ```
113
+ cissor index <session> # generate + save to cissor state
114
+ cissor index <session> --locate "pricing" # search existing index, else generate
115
+ cissor index <session> --out D:\indexes\voice.md # custom location
116
+ ```
117
+
118
+ Produces `Items A-B (turn T): title — description` entries for fast navigation;
119
+ `--locate` answers "where was X discussed" in item/turn ranges.
120
+
121
+ ### Export (archival)
122
+
123
+ ```
124
+ cissor export <session> # markdown transcript to stdout
125
+ cissor export <session> --turns 3-9 --out archive.md
126
+ cissor export <session> --strategy chronicle # LLM chronicle segment
127
+ cissor export <session> --strategy chronicle --chronicle-dir docs\chronicles
128
+ cissor export <session> --strategy index-only
129
+ cissor export <session> --no-outputs --include-reasoning --max-item-chars 2000
130
+ ```
131
+
132
+ Transcripts use `**User** (item 4):` / `**Assistant**` / `**Tool call: name**`
133
+ labels under `## Turn N` headings. Developer/system messages and synthetic user
134
+ context (`<environment_context>` etc.) are excluded by default — pass
135
+ `--include-developer` / `--include-synthetic` to keep them (the header records
136
+ what was excluded).
137
+
138
+ `--chronicle-dir` maintains the conversation-chronicle skill layout: numbered
139
+ segments (`NNNN-YYYY-MM-DD-HHMM-title.md`) + master `INDEX.md` with event index.
140
+
141
+ ### Extract / evict to file
142
+
143
+ ```
144
+ cissor extract <session> --turns 5-11 --out span.md # read-only dump (md|json|raw)
145
+ cissor extract <fork> --items 17-56 --out span.md --evict # + pointer message in fork
146
+ cissor extract <fork> --from-text A --to-text B --evict --with-summary --out span.md
147
+ ```
148
+
149
+ `--evict` removes the span from the fork and leaves a `<context_evicted>` user
150
+ message with the archive path (plus an LLM summary with `--with-summary`).
151
+ Text anchors are inclusive (both anchor items are part of the span); evictions
152
+ covering >60% of scope or >150k tokens are refused without `--force` (over-broad
153
+ anchor protection). `--format raw` writes re-importable JSONL lines.
154
+
155
+ ### Ask — query oversized material with another LLM (stateful)
156
+
157
+ ```
158
+ cissor ask D:\data\huge.json "What are the top-level keys and their types?"
159
+ cissor ask <session> --scope full "What did we decide about X early on?"
160
+ cissor ask <ask-id> "follow-up question" # continues the session
161
+ cissor asks list / cissor asks show <ask-id>
162
+ ```
163
+
164
+ The target (any text file, or a session slice) is sent WHOLE to the ask model —
165
+ your agent's context never holds it. Above `ask_max_input_tokens` it falls back to
166
+ **question-keyed map-reduce**: the material is split into ~48k-token chunks, and
167
+ each chunk is filtered through the QUESTION ("extract every fact relevant to this
168
+ question, with exact values and anchors") — that's the map phase, keyed to the
169
+ question rather than generic summarization. A final reduce call merges the
170
+ extracts into a grounded answer citing which fragments support each claim. Note:
171
+ each new question on an oversized target re-scans the chunks. Answers cite
172
+ item/turn anchors when the material provides them. PDFs/binary are rejected with a
173
+ conversion hint — convert to text/markdown first, then ask the converted file.
174
+
175
+ ### Fork (draft) → edit → publish
176
+
177
+ Forks are **drafts stored in `~/.codex/cxcm/forks/`** — invisible to Codex until
178
+ published, so the canonical session list stays clean while editing is in progress.
179
+
180
+ ```
181
+ cissor fork <session> --name my-fork # or --suffix trimmed, or neither (auto -fork)
182
+ cissor fork <session> --channel diet-auth # stable work-stream id (default: source session id,
183
+ # inherited by fork-of-fork so a chain stays grouped)
184
+ cissor edit <fork-id> ... # work on the draft
185
+ cissor publish <fork-id> # offline validation gate, then copies into sessions tree
186
+ codex resume <published-id> # user resumes
187
+ cissor forks [--channel diet-auth] # registered forks: status, lineage, op counts
188
+ ```
189
+
190
+ **Fork discipline:** the fork is agent-invoked and returns an id; every editing
191
+ action must pass that id explicitly. `latest` is refused for edits. Multiple forks
192
+ are fine when each is deliberate; channels group related forks, and a repeat fork
193
+ in the same channel within 30 minutes prints a warning pointing at the existing
194
+ one. Fork of a fork inherits the parent channel and extends the lineage chain.
195
+
196
+ **Originals are never edited in place — no override exists.** Editing requires a
197
+ registered fork; `--force` only exists for the over-broad eviction guard.
198
+
199
+ `cissor publish <fork-id>` runs the offline validator first (no Codex invocation, no
200
+ tokens) and refuses to publish a structurally broken fork; `--open` then launches
201
+ `codex resume <id>` in the fork's project directory. Re-publishing an already
202
+ published fork is refused unless `--republish`.
203
+
204
+ Note: forks keep the source session's cwd (provenance). Codex's resume lookup
205
+ filters by cwd, so resume from the same project works directly; from a different
206
+ directory use `codex resume --all <id>` / `codex exec resume --all <id>`.
207
+
208
+ ### Edit (fork drafts only — originals are immutable; requires the explicit fork id)
209
+
210
+ ```
211
+ cissor edit <fork> drop --turns 3-7
212
+ cissor edit <fork> replace --turns 2-40 --style index # summarize + splice summary
213
+ cissor edit <fork> replace --turns 2-40 --summary-file s.md # splice a hand-written summary
214
+ cissor edit <fork> trim-outputs --turns 2-10 --keep-chars 250 --min-tokens 200
215
+ cissor edit <fork> trim-outputs --all --keep-chars 400
216
+ cissor edit <fork> trim-inputs --all --keep-chars 200
217
+ cissor edit <fork> uncompact [--which last|first|all]
218
+ cissor edit <fork> transplant --from <other-session> --turns 3-9 # copy a span in (pairs kept intact)
219
+ cissor edit <fork> inject --file notes.md --label project_notes # add a whole document as a turn
220
+ ```
221
+
222
+ `inject` appends ONE message at the end — `user` role by default
223
+ (`--role developer|assistant` available) — wrapped in `<label>` tags; no fake
224
+ assistant turn is added. `transplant` requires complete call/output pairs in the
225
+ span and renames colliding call_ids automatically.
226
+
227
+ Safety model:
228
+
229
+ - originals are immutable — edits only ever touch fork drafts, never `--force`-able
230
+ - never touches `session_meta`, `turn_context`, `event_msg`, `world_state` records
231
+ - dropping/replacing a tool call auto-includes its paired output (and vice versa),
232
+ plus any reasoning items directly attached to them — a broken call/output pair or
233
+ a dangling reasoning item makes resume fail
234
+ - refuses to remove the last user message
235
+ - every save: pre-edit `.cxcm-bak` backup, post-edit validation; pre-existing
236
+ structural errors (some of Codex's own compactions leave orphan calls) are
237
+ reported but don't block edits — only **new** errors do
238
+ - all writes are atomic (temp file + rename)
239
+ - reports/log lines compress item lists to ranges (`17-56`) to save agent context
240
+
241
+ ## Styles — editable prompts
242
+
243
+ ```
244
+ cissor styles list # builtin | file | custom
245
+ cissor styles show index
246
+ cissor styles edit index # materializes the default, prints the path; edit at will
247
+ cissor styles reset index # back to builtin
248
+ ```
249
+
250
+ Style files live in `~/.codex/cxcm/styles/<name>.md`; a file overrides the builtin.
251
+ Create `<your-style>.md` for custom compaction flavours and use `--style your-style`.
252
+
253
+ ## Traceability
254
+
255
+ Every mutating or LLM-backed action appends one line to
256
+ `~/.codex/cxcm/activity.jsonl` (ts, kind, session, channel, project cwd, op, items,
257
+ tokens before/after, model, outputs). Forks additionally keep per-fork op history
258
+ in `~/.codex/cxcm/manifest.json`.
259
+
260
+ ```
261
+ cissor log # last 30 events (item lists range-compressed)
262
+ cissor log --stats # compact aggregate: events by kind, total tokens saved, channels
263
+ cissor log --channel diet-auth # everything for one work stream
264
+ cissor log --project ai-landscape # everything for one project cwd
265
+ cissor log --path # just print the file paths — grep them with bash for deep dives
266
+ ```
267
+
268
+ Never dump the whole log into an agent context; use `--path` + shell search, or
269
+ `--stats` for a summary.
270
+
271
+ ## Agent self-service workflow
272
+
273
+ ```
274
+ cissor fork latest --suffix context-diet
275
+ cissor index <fork> --locate "the pricing bug" # find what matters
276
+ cissor extract <fork> --turns 3-8 --out dump.md --evict --with-summary
277
+ cissor edit <fork> trim-outputs --all --keep-chars 300 --min-tokens 300
278
+ cissor edit <fork> replace --turns 9-40 --style index
279
+ cissor validate <fork>
280
+ codex resume <new-id>
281
+ ```
282
+
283
+ ## Notes
284
+
285
+ - Token estimates cover conversation items only — not the system prompt, developer
286
+ instructions stored in `session_meta`, or tool schemas. Real API usage (from
287
+ `token_count` events) is shown by `inspect` for comparison.
288
+ - `.cxcm-bak` files sit next to edited sessions; Codex ignores them.
289
+ - Roadmap ideas live in `ROADMAP.md`.
File without changes
@@ -0,0 +1,5 @@
1
+ import sys
2
+ from .cli import main
3
+
4
+ if __name__ == "__main__":
5
+ sys.exit(main())