Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AI Agent Ectype (ectype)

Ectype, AI Agent Ectype

Thirteen AI agents, thirteen undocumented session formats, and not one of them hands the conversation back to you. ectype reads all of them through a single reader, so a finished session can be picked up again: copied back into the agent and resumed with its context intact, handed to a different agent, or cut down to the parts that still matter and pasted wherever you need them.

Carrying the context forward is the point. The export formats, the redaction and the token budget exist to make that affordable: the 981-message session below is 347,517 tokens whole and 13,073 with tool output reduced to names, and you can see the difference before you spend it.

The web UI: session list, view options, the two token numbers with their table, and the transcript

Install

pip install git+https://github.com/chaybits/ectype     # pipx and uv tool work the same way
ectype agents                                          # which stores exist on this machine

Python 3.10+ and no dependencies. For exact token counts instead of the 4-characters-per-token estimate, install the tokens extra:

pip install "ectype[tokens] @ git+https://github.com/chaybits/ectype"

Each agent's store is resolved in one order: $ECTYPE_<AGENT>_HOME (Codex uses its own $CODEX_HOME), then the path saved in Settings, then the agent's own default. ectype agents prints the variable, the resolved path and which of the three won, one row per agent. The environment variable stays on top so a one-off run against a fixture never depends on the saved file.

Settings also decide which agents the web UI lists: coding agents are on by default, chat apps (LM Studio, Open WebUI, SillyTavern) are opt-in.

Why

Ten coding agents and three chat apps, each keeping its history in a different, undocumented shape:

Agent Store Shape
Claude Code ~/.claude/projects/<slug>/<uuid>.jsonl append-only message log; tool results ride inside the next user record; a result too big to inline is replaced by a stub and spilled to <uuid>/tool-results/<hash>.txt
Codex CLI $CODEX_HOME/sessions/YYYY/MM/DD/rollout-*.jsonl append-only event log; reasoning encrypted; full tool output in item_completed events, model-visible copy truncated
Gemini CLI ~/.gemini/tmp/<project>/chats/session-*.jsonl mutation log: $set snapshots + re-emitted messages; last record per id wins; big outputs spill to tool-outputs/
Antigravity ~/.gemini/antigravity-cli/brain/<id>/…/transcript_full.jsonl step log; tool results as separate steps or steps/N/output.txt; a failed call leaves no step at all; a working directory is recorded only for conversations opened in a workspace
VS Code Copilot Chat Code/User/**/chatSessions/*.jsonl JSON-path patch log: kind 0 base, kind 1 set-at-path, kind 2 append; state must be replayed
Cursor Cursor/User/globalStorage/state.vscdb SQLite (WAL): composerHeaders index + cursorDiskKV rows composerData: / bubbleId:; one bubble per thinking block, tool call or text segment
Cline ~/.cline/data/sessions/<id>/ metadata json + .messages.json with Anthropic-shaped blocks
Roo Code globalStorage/…roo-cline/tasks/<id>/ three files: api_conversation_history.json (conversation), ui_messages.json (timestamps, errors), history_item.json (metadata)
Continue ~/.continue/sessions/<id>.json history[]; toolCallStates holds the call and its result in one object
Aider .aider.chat.history.md per repo Markdown: #### = user, > = console, plain = assistant; one file, many runs
LM Studio ~/.lmstudio/conversations/<epoch>.conversation.json versions[] + currentlySelected (branching); assistant = steps[]; the tool's output is never stored
Open WebUI <DATA_DIR>/webui.db → table chat SQLite row with the frontend's chat JSON: history.messages is a tree (regenerations are siblings), messages[] the current branch
SillyTavern <data>/<user>/chats/<Character>/<name>.jsonl header line + one message per line; swipes[] keep every regenerated alternative (branching)

Sidecar files

When a tool result is too large for the transcript, some agents write the full text to a file beside it and leave a short preview in its place. ectype follows the pointer and puts the full text back into the render, and a native copy carries those files along and repoints them.

File What it is What ectype does
Claude <uuid>/tool-results/<hash>.txt the full text of a result the transcript truncated read back into the result block; copied with a native export
Claude <uuid>/subagents/agent-*.jsonl Task-tool subagent runs, separate conversations listed in session.meta["subagents"], never folded into the parent
Claude <uuid>/custom-title.json the title you set by hand, written only when you set one used as the session title; otherwise the transcript's own summary or first prompt is used
Gemini tool-outputs/session-<id>/<callId>.txt the same idea, per tool call recorded as spill_path on the result
Codex session_index.jsonl store-level thread index read for titles; written when installing a session

A spill file restored into the transcript

Use

Find a session

ectype list                  # newest sessions across every agent
ectype list -a codex -n 5    # one agent, five rows

Every other command takes an id, and any unambiguous prefix of one will do. If the same id exists under two project folders (a session resumed from another directory), --project <part of the path> picks one.

Read one

ectype show a1b2c3d4                            # the default view
ectype show a1b2c3d4 --thinking --cap 0 -o session.txt
ectype show a1b2c3d4 --no-tools                 # conversation only

The default view keeps the conversation, every tool call, and the first 150 tokens of each tool result; thinking is off. --cap N moves that limit (--cap 0 cuts nothing), --thinking adds the reasoning, --no-tools drops tool activity altogether. Without -o it prints to stdout.

Export it

ectype export a1b2c3d4 --mode brief -o gist.txt                    # tool call names only
ectype export a1b2c3d4 --format markdown --cap 300 -o notes.md     # text · markdown · html · json · jsonl · csv
ectype export a1b2c3d4 --redact --no-tools -o share.txt            # safe to paste somewhere public
ectype export a1b2c3d4 --wrap user --format jsonl -o one.jsonl     # the whole transcript as ONE message

--mode is the one dial that decides most of the bill: brief keeps the tool's name alone, custom keeps the first --cap tokens of each result, full keeps every argument and every byte. Back-to-back turns of the same actor are merged into one turn by default, a tool result riding with the call that produced it (--no-collapse turns that off).

Every export starts with a header naming the session, its project, model and message counts. Where the view leaves something out, the transcript says so at that point: a capped result carries …[+n tokens cut], a names-only call prints no output, and the web UI shows "685 of 924 messages" beside the budget. --notice appends a final message telling the receiving model that the session was imported and that paths, dates and tools should be re-checked.

--redact applies rules computed from the running machine, so nothing personal is hard-coded: your home directory, your username, hostname, e-mail addresses, common API-key shapes, optionally IP addresses, and optionally the timezone offset. Every run reports what matched (home×6, media×62, email×1), and the web UI shows each matched value next to its replacement, so a false positive is visible rather than silent. Add your own with --redact-term TEXT or --redact-term TEXT=REPLACEMENT.

Redaction: what was replaced

Continue it somewhere

ectype convert e5f6a7b8                                   # a copy of the session, same agent
ectype convert e5f6a7b8 --install --workspace ~/code/proj # into the agent's store, ready to resume
ectype convert b2c3d4e5 --to codex --install              # then: codex resume <id>

Same agent in, same agent out is a copy, and nothing is lost. The file already is that format, so ectype rewrites it record for record: tool calls, tool results, thinking, images and injected context all survive, sidecar files travel with it, and the only things that change are the session id (so the copy cannot collide with the original) and the working directory if you re-home it with --workspace. That is what makes "carry on from here" possible.

A different agent is a real conversion, and it costs something. No agent has a place for another's tool records or reasoning, so your messages and the assistant's text carry over verbatim, tool activity folds into short bracketed notes inside the assistant text, and thinking and injected context are dropped. Every conversion writes a *.fidelity.md counting what was kept, folded and dropped, and the web UI shows the same table before you commit to it.

Conversion table: Claude Code to Claude Code is a copy

Conversion table: Claude Code to Codex CLI

Claude Code, Codex CLI and Gemini CLI can be written, because each was proven by installing a converted session and resuming it for real (2026-09-04, against Claude Code 2.1, Gemini CLI 0.58 and Codex CLI 0.153). The other ten are read-only: Antigravity and Cursor keep resumable state in a database an outside writer cannot safely forge, Copilot Chat in a patch log the editor holds open, Aider has one shared Markdown history per repo with no session to resume, the chat apps have no resume at all, and Cline, Roo Code and Continue are plausible targets that no live resume has been proven for yet. They still appear in the menu, greyed out and labelled.

For a cross-agent conversion, --template <a real session file of the target> copies that agent's own envelope (version, cwd, flags), so the output is valid for the release you actually run.

Browse it

ectype gui        # 127.0.0.1:8765, stdlib http.server, no dependencies

What a session costs

One real session: 981 messages, 8 MB of JSONL on disk, 377 tool calls, counted with cl100k_base.

What fills it, with every option on and nothing capped, 347,517 tokens:

element tokens share
tool results 157,932 45.4%
tool call arguments 138,847 40.0%
thinking 39,126 11.3%
assistant text 9,541 2.7%
your messages 1,108 0.3%
injected context 301 0.1%
headers and timestamps 662 0.2%

The conversation itself is 3% of that. Everything else is the agent talking to its tools, which is why one dial decides almost the whole bill.

What each setting of that dial costs, on the same session, thinking off:

view tokens against the default
everything, nothing capped 307,897 +239,048
results capped at 150 (the default) 68,849 0
results capped at 50 56,656 -12,193
names only 13,073 -55,776
no tool calls or results at all 11,034 -57,815

Names only keeps every call, in order, with its name and nothing else, and costs 4% of the whole session. It drops the arguments too, which is most of the saving: a single Bash command or file patch runs to hundreds of characters, and 377 of them are 138,847 tokens before a byte of output is counted.

Names only: the tool's name alone; the table shows what is left out

The same dial on a different shape of session: 55 messages whose tool results alone come to 1.8M tokens. Nothing is capped in the ceiling, and the default view of it is 3,542 tokens.

Everything mode on a 1.8 M-token session

Web UI

The web UI, part by part

  1. The session list. Every session of every enabled agent, as a file manager shows files: sort by any column, drag the edges to resize, chooses which columns appear, and the search box filters by title, id, project or agent. Clicking an id copies it. Ctrl+B hides the whole panel. The size column is the file on disk, which also holds the JSON envelope and usage records, so it is several times the transcript inside it.
  2. What goes in. Tool output (names only, capped, everything), thinking, tool calls and results, injected context, timestamps, merge, hiding either side, and a message range. Every control has a tooltip, and ? Help explains all of them and every number.
  3. Redaction. Switch it on and its rules appear inline, with a box for your own words. After a render the status line lists what matched; clicking it shows every matched value next to its replacement.
  4. Export. The format menu starts with this agent's own resumable format, then text, markdown, html, json, jsonl and csv. convert to lists every agent, source-only ones greyed out, and says what that conversion costs. location is a download, a folder on this machine, or the agent's own store, ready to resume; workspace picks the directory the copy is filed under.
  5. Two numbers. max context is the whole session with everything on and nothing capped, and does not move while you toggle. selected is exactly what the preview shows, which is what the export will cost. The bar measures selected against a reference size you set (the context window you are pasting into), and the dashed mark is where max context would land.
  6. Where they go. One row per element, with a total row that equals selected exactly. A partly included element expands into what is in now and what is left out.
  7. The preview. Exactly what the export will contain, coloured by role.
  8. Help, the conversion table for any pair of agents, and Settings: which agents are listed, each agent's store path and resume format, view defaults, redaction rules, export behaviour and the wording of the import notice.

Times are printed in local time; every store records UTC internally.

Known limitations

  • Cross-agent conversion is messages-only. Tool activity folds into bracketed text and thinking is dropped, even where the target could represent them natively.
  • Branching stores are flattened. SillyTavern swipes, LM Studio versions and the Open WebUI message tree load as the selected path; the alternatives are parked in meta["alternatives"].
  • Three writable targets. Only Claude Code, Codex CLI and Gemini CLI can be written, because each was proven by installing a converted session and resuming it for real.
  • A headless Antigravity run's working directory lives only in cli.log, which is short and rotates; older headless runs have none.
  • Codex full outputs are matched to calls by order, not by id: usually right, not always.
  • The formats parsed here are undocumented internals of each agent and can change with any release. Every adapter records the layout it was written against.

License

GPL-3.0-or-later (see LICENSE).

About

Read, filter, redact and export the on-disk sessions of ten AI coding agents (Claude Code, Codex CLI, Gemini CLI, Antigravity, Copilot Chat, Cursor, Cline, Roo Code, Continue, Aider) and three chat apps (LM Studio, Open WebUI, SillyTavern), or copy one back into its agent and resume it. Command line and a local web UI.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages