Metadata-Version: 2.4
Name: codex-cissor
Version: 0.3.0
Summary: cissor — edit your Codex CLI session context: trim tool outputs, summarize or evict spans, then resume a lean session
Author: Kevin Ng'eno
License: MIT
Project-URL: Repository, https://github.com/Ngenome/codex-cissor
Keywords: codex,cli,context,tokens,sessions
Classifier: License :: OSI Approved :: MIT License
Classifier: Environment :: Console
Classifier: Topic :: Software Development
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: tiktoken>=0.8
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# codex-cissor — edit your Codex session context

`cissor` edits the context of Codex CLI sessions: trim bloated tool outputs,
summarize stale turns in place, evict spans to files with recovery pointers,
transplant or inject content — then resume the leaner session with
`codex resume <id>`. It also inspects what is eating the window, exports
markdown archives, and answers questions about oversized material without
loading it into your context.

Edits happen on fork drafts; publishing (gated on offline validation) is how a
finished fork returns to the canonical sessions tree.

Sessions live in `~/.codex/sessions/YYYY/MM/DD/rollout-<ts>-<uuid>.jsonl`. cissor
parses that format directly, including `compacted` records.

## Install

```
uv tool install codex-cissor        # from PyPI (or: pipx install codex-cissor)
```

Requires `OPENROUTER_API_KEY` in the environment for LLM-backed commands
(summarize / index / export chronicle / ask / replace / evict --with-summary).
Inspection, forking, editing, validation, and transcript export work offline.
Token estimates use tiktoken (`o200k_base` by default).

## Config

```
cissor config path                 # where config/manifest/logs live (~/.codex/cxcm/)
cissor config show
cissor config set model z-ai/glm-5.3-flash          # summarizer
cissor config set ask_max_input_tokens 120000        # above this, ask() switches to map-reduce
cissor config set encoding o200k_base
```

Any OpenRouter model id works; env overrides via `CISSOR_MODEL`, `CISSOR_ASK_MAX_INPUT_TOKENS`, etc.

- `ask_max_input_tokens` (120k): the switch-point where `ask` stops sending the
  whole material in one call and switches to question-keyed map-reduce.
- `context_window_tokens` (0 = unknown): the model's context limit, purely advisory —
  `inspect` reports % of window. Codex defaults to 272k (expandable to 1M);
  auto-compaction triggers around the ~682k hard max.

## Compaction-aware scope

A `compacted` record contains `{message, replacement_history}`. On resume, Codex
replays **only** the last compaction's `replacement_history` + everything after it.
cissor therefore:

- numbers turns/items over the **effective context** (post-last-compaction) by default,
- warns when you touch pre-compaction items (they are not in the live window),
- supports `--scope full` to address the **entire file** including pre-compaction
  history, and `--scope post-compact|auto|full` everywhere selection applies,
- `edit uncompact` removes the compacted record to restore the full pre-compaction
  history (all of it is still in the file),
- items inside `replacement_history` are addressable and editable like any other item,
- `history` lists every compaction point with what it hides.

## Commands

### Inspection

```
cissor list [--limit N] [--json]                    # sessions, newest first (fork names shown)
cissor inspect <session> [--scope full] [--json]    # per-turn + per-type token breakdown
cissor inspect <session> --turns 3-7                # breakdown of a selection
cissor show <session> --turns 3-4 [--max-chars N]   # actual content of a selection
cissor history <session> [--json]                   # compaction points: line, summary, hidden tokens
cissor validate <session> [--json]                  # structural check (pairs, reasoning, meta)
cissor forks [--channel X] [--json]                 # registered forks: channels, lineage, op counts
cissor log [--session X] [--channel C] [--project P] [--stats] [--path]  # activity trail
```

Address a session by: full/prefix id, manifest name, `latest`, or file path.

**Two kinds of placeholders:** `<session>` = any of the above, for read-only
commands. `<fork-id>` = the draft id returned by `cissor fork` — required by every
mutating command (`edit`, `transplant`, `inject`, `extract --evict`); `latest` is
refused there and non-fork originals are always refused.

### Selection (shared by inspect/show/summarize/index/export/extract/ask/edit ops)

```
--scope auto|post-compact|full
--turns "2-10"          turn ranges/lists
--items "12,15-20"      item numbers
--from-text "needle"    from first item containing text to end (inclusive)
--to-text "needle"      from start to last item containing text (inclusive)
--turn-from-text / --turn-to-text
--all                   everything in scope
```

`--from-text` + `--to-text` together bound a single inclusive span (both anchor
items included). One-sided use opens a range to the start/end of scope.

### Summarize (read-only)

```
cissor summarize <session> --turns 1-40 --style index
cissor summarize <session> --turns 2-10 --style key-points --out s.md
cissor summarize <session> --turns 2-10 --prompt "focus only on pricing decisions"
```

Styles are editable markdown files (see Styles below): `chronicle`, `index`,
`short`, `key-points`, `export-chronicle`, plus your own — or pass a one-off
`--prompt`/`--prompt-file` inline. Long selections are map-reduced in
~48k-token chunks (`chunk_tokens`).

### Event index

```
cissor index <session>                                  # generate + save to cissor state
cissor index <session> --locate "pricing"               # search existing index, else generate
cissor index <session> --out D:\indexes\voice.md        # custom location
```

Produces `Items A-B (turn T): title — description` entries for fast navigation;
`--locate` answers "where was X discussed" in item/turn ranges.

### Export (archival)

```
cissor export <session>                                  # markdown transcript to stdout
cissor export <session> --turns 3-9 --out archive.md
cissor export <session> --strategy chronicle             # LLM chronicle segment
cissor export <session> --strategy chronicle --chronicle-dir docs\chronicles
cissor export <session> --strategy index-only
cissor export <session> --no-outputs --include-reasoning --max-item-chars 2000
```

Transcripts use `**User** (item 4):` / `**Assistant**` / `**Tool call: name**`
labels under `## Turn N` headings. Developer/system messages and synthetic user
context (`<environment_context>` etc.) are excluded by default — pass
`--include-developer` / `--include-synthetic` to keep them (the header records
what was excluded).

`--chronicle-dir` maintains the conversation-chronicle skill layout: numbered
segments (`NNNN-YYYY-MM-DD-HHMM-title.md`) + master `INDEX.md` with event index.

### Extract / evict to file

```
cissor extract <session> --turns 5-11 --out span.md              # read-only dump (md|json|raw)
cissor extract <fork> --items 17-56 --out span.md --evict        # + pointer message in fork
cissor extract <fork> --from-text A --to-text B --evict --with-summary --out span.md
```

`--evict` removes the span from the fork and leaves a `<context_evicted>` user
message with the archive path (plus an LLM summary with `--with-summary`).
Text anchors are inclusive (both anchor items are part of the span); evictions
covering >60% of scope or >150k tokens are refused without `--force` (over-broad
anchor protection). `--format raw` writes re-importable JSONL lines.

### Ask — query oversized material with another LLM (stateful)

```
cissor ask D:\data\huge.json "What are the top-level keys and their types?"
cissor ask <session> --scope full "What did we decide about X early on?"
cissor ask <ask-id> "follow-up question"              # continues the session
cissor asks list / cissor asks show <ask-id>
```

The target (any text file, or a session slice) is sent WHOLE to the ask model —
your agent's context never holds it. Above `ask_max_input_tokens` it falls back to
**question-keyed map-reduce**: the material is split into ~48k-token chunks, and
each chunk is filtered through the QUESTION ("extract every fact relevant to this
question, with exact values and anchors") — that's the map phase, keyed to the
question rather than generic summarization. A final reduce call merges the
extracts into a grounded answer citing which fragments support each claim. Note:
each new question on an oversized target re-scans the chunks. Answers cite
item/turn anchors when the material provides them. PDFs/binary are rejected with a
conversion hint — convert to text/markdown first, then ask the converted file.

### Fork (draft) → edit → publish

Forks are **drafts stored in `~/.codex/cxcm/forks/`** — invisible to Codex until
published, so the canonical session list stays clean while editing is in progress.

```
cissor fork <session> --name my-fork        # or --suffix trimmed, or neither (auto -fork)
cissor fork <session> --channel diet-auth   # stable work-stream id (default: source session id,
                                          # inherited by fork-of-fork so a chain stays grouped)
cissor edit <fork-id> ...                   # work on the draft
cissor publish <fork-id>                    # offline validation gate, then copies into sessions tree
codex resume <published-id>               # user resumes
cissor forks [--channel diet-auth]          # registered forks: status, lineage, op counts
```

**Fork discipline:** the fork is agent-invoked and returns an id; every editing
action must pass that id explicitly. `latest` is refused for edits. Multiple forks
are fine when each is deliberate; channels group related forks, and a repeat fork
in the same channel within 30 minutes prints a warning pointing at the existing
one. Fork of a fork inherits the parent channel and extends the lineage chain.

**Originals are never edited in place — no override exists.** Editing requires a
registered fork; `--force` only exists for the over-broad eviction guard.

`cissor publish <fork-id>` runs the offline validator first (no Codex invocation, no
tokens) and refuses to publish a structurally broken fork; `--open` then launches
`codex resume <id>` in the fork's project directory. Re-publishing an already
published fork is refused unless `--republish`.

Note: forks keep the source session's cwd (provenance). Codex's resume lookup
filters by cwd, so resume from the same project works directly; from a different
directory use `codex resume --all <id>` / `codex exec resume --all <id>`.

### Edit (fork drafts only — originals are immutable; requires the explicit fork id)

```
cissor edit <fork> drop --turns 3-7
cissor edit <fork> replace --turns 2-40 --style index          # summarize + splice summary
cissor edit <fork> replace --turns 2-40 --summary-file s.md    # splice a hand-written summary
cissor edit <fork> trim-outputs --turns 2-10 --keep-chars 250 --min-tokens 200
cissor edit <fork> trim-outputs --all --keep-chars 400
cissor edit <fork> trim-inputs --all --keep-chars 200
cissor edit <fork> uncompact [--which last|first|all]
cissor edit <fork> transplant --from <other-session> --turns 3-9   # copy a span in (pairs kept intact)
cissor edit <fork> inject --file notes.md --label project_notes    # add a whole document as a turn
```

`inject` appends ONE message at the end — `user` role by default
(`--role developer|assistant` available) — wrapped in `<label>` tags; no fake
assistant turn is added. `transplant` requires complete call/output pairs in the
span and renames colliding call_ids automatically.

Safety model:

- originals are immutable — edits only ever touch fork drafts, never `--force`-able
- never touches `session_meta`, `turn_context`, `event_msg`, `world_state` records
- dropping/replacing a tool call auto-includes its paired output (and vice versa),
  plus any reasoning items directly attached to them — a broken call/output pair or
  a dangling reasoning item makes resume fail
- refuses to remove the last user message
- every save: pre-edit `.cxcm-bak` backup, post-edit validation; pre-existing
  structural errors (some of Codex's own compactions leave orphan calls) are
  reported but don't block edits — only **new** errors do
- all writes are atomic (temp file + rename)
- reports/log lines compress item lists to ranges (`17-56`) to save agent context

## Styles — editable prompts

```
cissor styles list                # builtin | file | custom
cissor styles show index
cissor styles edit index          # materializes the default, prints the path; edit at will
cissor styles reset index         # back to builtin
```

Style files live in `~/.codex/cxcm/styles/<name>.md`; a file overrides the builtin.
Create `<your-style>.md` for custom compaction flavours and use `--style your-style`.

## Traceability

Every mutating or LLM-backed action appends one line to
`~/.codex/cxcm/activity.jsonl` (ts, kind, session, channel, project cwd, op, items,
tokens before/after, model, outputs). Forks additionally keep per-fork op history
in `~/.codex/cxcm/manifest.json`.

```
cissor log                       # last 30 events (item lists range-compressed)
cissor log --stats               # compact aggregate: events by kind, total tokens saved, channels
cissor log --channel diet-auth   # everything for one work stream
cissor log --project ai-landscape  # everything for one project cwd
cissor log --path                # just print the file paths — grep them with bash for deep dives
```

Never dump the whole log into an agent context; use `--path` + shell search, or
`--stats` for a summary.

## Agent self-service workflow

```
cissor fork latest --suffix context-diet
cissor index <fork> --locate "the pricing bug"        # find what matters
cissor extract <fork> --turns 3-8 --out dump.md --evict --with-summary
cissor edit <fork> trim-outputs --all --keep-chars 300 --min-tokens 300
cissor edit <fork> replace --turns 9-40 --style index
cissor validate <fork>
codex resume <new-id>
```

## Notes

- Token estimates cover conversation items only — not the system prompt, developer
  instructions stored in `session_meta`, or tool schemas. Real API usage (from
  `token_count` events) is shown by `inspect` for comparison.
- `.cxcm-bak` files sit next to edited sessions; Codex ignores them.
- Roadmap ideas live in `ROADMAP.md`.
