Skip to content
chaybitsPublic

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

4 stars

Watchers

0 watching

Forks

Repository files navigation

AI Agent Ectype (ectype)

English | Türkçe

Ectype, AI Agent Ectype

A CLI, web UI and MCP server that reads, exports and converts saved sessions, for anyone who uses several AI coding agents or chat apps.

Thirteen AI agents and chat apps, thirteen undocumented session formats, and no shared way to take a conversation out of one and use it somewhere else. ectype reads all of them through a single reader, so a finished session can be picked up again: copied back into its own 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. Copying back works for Claude Code, Codex CLI, Gemini CLI and the Cline CLI.

Carrying the context forward is the point. The export formats and the token budget exist to make that affordable: the 989-message session below is 348,215 tokens whole and 13,110 with thinking off and every tool call reduced to its name, and you can see the difference before you spend it.

The web UI on the 989-message session: tool output set to names only, 13,110 of 348,215 tokens selected, the table of what goes in, and the transcript with every tool call shown by its name

Install

pipx install ectype-cli                             # or: pip install ectype-cli
uv tool install ectype-cli                          # the same, through uv
pip install "ectype-cli[tokens]"                    # plus tiktoken, for exact token counts
pip install git+https://github.com/chaybits/ectype  # the tip of main instead of a release
ectype agents                                       # which stores exist on this machine

ectype needs Python 3.10+ and nothing beyond the standard library. The distribution is ectype-cli; the command and the import package are both ectype. Without the tokens extra, token counts are estimated at one token per four characters.

Each GitHub release also includes two download options:

  • ectype-<version>-windows-x64.zip, for Windows with no Python and no terminal. Unzip it anywhere and double-click ectype-gui.bat. It brings its own copy of Python, keeps its settings inside its own folder, and is uninstalled by deleting that folder: nothing is written to PATH or the registry. About 10 MB.
  • ectype.pyz, the whole program in one file for anyone who has Python but would rather not install anything: python ectype.pyz gui.

Each attached file comes with a .sha256 beside it (sha256sum -c ectype.pyz.sha256 checks it) and a build-provenance attestation: gh attestation verify ectype.pyz --owner chaybits confirms that the file was built by this repository's release workflow.

For each agent, ectype resolves the store in this order: $ECTYPE_<AGENT>_HOME (Codex uses its own $CODEX_HOME), then the path saved in Settings (in the web UI, or in the settings file that ectype settings prints), 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.

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

Some agents keep files beside the transcript: the full text of a tool result too large for it (the transcript keeps a short preview that points to the file), subagent runs, a title you set by hand, a store-wide index. ectype follows the pointer and puts the full text back into the render, and a native copy (same agent in, same agent out) 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; the transcript keeps a 40 KB head read back into the result block, like Claude's
Codex session_index.jsonl store-level thread index read for titles; written when installing a session

Use

Find a session

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

Commands that act on one session take its id, and any unambiguous prefix of it 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.

Know what happened in it

ectype summarize a1b2c3d4        # asks, tools, files, commands, errors, keywords
ectype summarize --all           # keep a summary of every session that is new or changed since last time
ectype search "wireguard|vpn"    # have I dealt with this before? A regex over every session's summary

Without a model or an API key, summarize extracts what was asked, which tools ran and how often, which files were touched, which commands ran, what failed, and a lowercase keyword line meant for grep rather than for reading. On a 989-message session that is a few hundred tokens against 348,215 for the transcript, which is often enough to decide whether to open it at all.

summarize --all keeps one such summary per session beside the settings file and remembers which version of each file it saw, so a second run only touches what changed (--force redoes all of them; summarize <id> --save keeps one). It covers the agents switched on in Settings → Agents. Coding agents are on by default and chat apps are not, because reading personal conversations into summaries is a choice, not a default. -a lmstudio names one explicitly. search first summarises what is new or changed since the last search; every other session is only fingerprinted, so a repeat search reads no transcript. It then matches a regex against every kept summary and says how many sessions it covered, so an empty result is never mistaken for "never happened". summarize and search never write into an agent's store.

When the agent itself wrote a summary of the session, between a pair of markers in one of its own turns, summarize quotes it first (every such block, in order), so the kept summary carries the agent's own account of what mattered and search finds it. The marker is literal text, set in Settings → Summary: %%SUMMARY%% by default, which Markdown shows exactly as written. The summary goes between two of them, and you can set more than one marker. An agent writes one when its instructions ask, and ectype summary-rule adds that request to the instruction files you pick, inside a block it owns, after backing up each file:

ectype summary-rule print                  # the paragraph, to paste by hand
ectype summary-rule install -a codex       # into Codex's AGENTS.md (or claude-code, gemini-cli, --file PATH)
ectype summary-rule remove -a codex        # and out again

Only the assistant's turns are read, so a summary you paste into a prompt is not mistaken for the new session's summary. summarize --marker TEXT uses a different marker for one run. The web UI shows the quoted summary under Summary; Settings → Summary shows the paragraph and each agent's instruction file.

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            # redacted: still read it before you share it
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. In custom mode the text-based formats (text, markdown, html, csv) also cut a call's arguments at 200 characters; json and jsonl carry them whole, because a structured export is data rather than a view. 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 that names the session, its project and model, and counts the turns it shows. It does not list what the options left out. Where a view shortens something, the output says so at that point: a capped result carries …[+n tokens cut], a names-only call prints no output, and the web UI shows "847 of 989 messages" beside the budget. Every export and conversion ends with a short message telling the receiving model that the session was imported and that paths, dates and tools should be re-checked; --no-notice leaves it out of one export, and Settings → Import notice turns it off for all of them.

--redact applies rules computed from the running machine: your home directory, removable-media paths, 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.

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 in the session is lost. The file is already in 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 some of it is lost. ectype does not translate tool records between agents, and no agent accepts another's reasoning. 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.

The conversion table from Claude Code to Codex CLI: each element carried, folded into a note, dropped or added

ectype can write into the stores of Claude Code, Codex CLI, Gemini CLI and the Cline CLI, 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; 2026-09-18 against Cline 3.0.62, whose store is two JSON files plus a row in its own index, and which resumes only in its terminal UI). The other nine are read-only: Antigravity and Cursor keep resumable state in a database an outside writer cannot safely forge; Copilot Chat keeps it 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 Roo Code and Continue are plausible targets for which no live resume has been proven. 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.

Two convert flags run the target agent once, on your own login and at its normal cost, to replace a guess with a fact, so neither is ever the default. --mint-template runs the target once on its cheapest model and uses the session it writes as the template, so the envelope matches the release you actually have installed. --verify, after an --install, resumes the installed session in the target agent and reports whether it answered.

Keep a copy

ectype backup a1b2c3d4                  # the transcript and every sidecar file it owns
ectype backup --list                    # what has been saved, newest first
ectype backup --restore NAME --dry-run  # names every destination, writes nothing

Each backup is one timestamped folder with a manifest recording where every file came from, which is what lets --restore put them back without guessing. A restore first saves what it is about to overwrite as a backup of its own (before-restore-<name>), so it can be undone the same way. An install takes a backup by itself whenever it would modify a file the store already owns, and --no-backup opts out. Installs into Claude Code and Gemini CLI only add a file, so they need no backup; installs into Codex and Cline do, because Codex appends to the store's own session index and its migration rewrites the thread history, and Cline's index gets a row. By default every backup is kept; Settings → Backups sets how many to keep or for how many days (backup.keep_last, backup.keep_days, 0 = no limit), applied each time a new backup is taken or on demand with ectype backup --prune.

Browse it

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

Let the agent read it

claude mcp add ectype -- ectype mcp     # any MCP client: ectype mcp speaks JSON-RPC on stdio

Six read-only tools: list_sessions, search_sessions (the regex over kept summaries), session_budget (what a session costs before you read it), show_session (at a depth the agent picks; the cap from Settings applies unless it says otherwise), summarize_session and list_agents. So an agent can answer "what did we decide about X last week" by searching, finding the session, checking what it costs in tokens, and pulling in the names-only view instead of 348,215 tokens of transcript.

A seventh tool, install_session, writes into an agent's store and therefore is not offered unless you start the server with ectype mcp --allow-write: a tool an agent cannot see is a tool it cannot be talked into calling.

ectype can also install a slash command, /ectype by default, for Claude Code, Gemini CLI and Codex:

ectype skill install                          # /ectype in all three (one file each, in the agent's command folder)
ectype skill install --name bringmedasummary  # call it what you like; the name is remembered in Settings
ectype skill status                           # what is installed, where

A file ectype wrote records a hash of its own text, so status can tell three cases apart: a file nobody touched, which a plain install updates (also after an ectype update); a file you edited, which is kept unless you run install --force, which saves it as .bak first; and a command of your own, which is never touched.

The files go into each agent's command folder (~/.claude/commands, ~/.gemini/commands, ~/.codex/prompts), or under CLAUDE_CONFIG_DIR, GEMINI_CLI_HOME and CODEX_HOME when those are set, because that is where the agents look.

All three are built on one command:

ectype recall a1b2c3d4                       # the session the way the skill wants it, then its summary is kept
ectype recall a1b2c3d4 --tools --mode custom --cap 300 --thinking   # options typed after the id win

recall is show with its defaults taken from Settings → Agent skill. That panel holds every option a view has: tool calls and their output, thinking, injected context, the agent's questions and other sessions' messages, timestamps, merging, redaction, the import notice, and whether to keep the summary. So how a session is brought into an agent is decided once, in one place, and overridden per call. recall starts with the conversation alone, and --tools adds the tool calls. The Settings dialog shows the exact command those defaults produce.

Add an agent yourself

An adapter for an agent ectype does not know can live in its own package: it registers itself under the ectype.adapters entry-point group and ectype loads it at start. A complete working example and the contract it has to meet are in integrations/adapter-plugin/.

What a session costs

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

What fills it, with every option on and nothing capped, 348,215 tokens:

element tokens share
tool results 157,958 45.4%
tool call arguments 138,847 39.9%
thinking 39,126 11.2%
assistant text 9,541 2.7%
your messages 1,108 0.3%
the agent's own notices 489 0.1%
injected context 301 0.1%
headers and timestamps 845 0.2%

The conversation itself is 3% of that. Most of the rest 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,960 +239,071
results capped at 150 (the default) 68,889 0
results capped at 50 56,696 -12,193
names only 13,110 -55,779
no tool calls or results at all 11,064 -57,825

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 weigh nearly as much as the output: a single Bash command or file patch runs to hundreds of tokens, and 377 of them are 138,847 tokens before a byte of output is counted.

Web UI

The screenshot above Install is the web UI (ectype gui). Its parts, in screen order:

  • 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. Settings → Agents decides which agents are listed: coding agents by default, chat apps (LM Studio, Open WebUI, SillyTavern) only when you switch one on. Clicking an id copies it. Double-click a name to rename it. For Claude Code this writes the same custom-title.json the agent writes itself, so the new name shows up there too. For a store with no place for a name, ectype keeps the name in its own records rather than inventing a field in someone else's database. An empty name restores the generated one. 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. The Started column, off by default, is when the first message you typed was sent, so a session resumed days later still sorts by the day it began; Modified is the file's last write.
  • What goes in. Tool output (names only, capped, everything), thinking, tool calls and results, injected context, the agent's own notices (API errors, refusals, away summaries, where the store keeps them), the questions the agent put to you with your answers (shown as the turns they are, even with tool calls off), messages other sessions sent in (each under [PEER]), timestamps, merge, hiding your turns or the assistant's, and a message range. Every control has a tooltip, and ? Help explains all of them and every number.
  • 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.
  • 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.
  • 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.
  • 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.
  • The preview. Exactly what the export will contain, coloured by role.
  • Help, the conversion table for any pair of agents, and Settings: which agents are listed, the interface's language, each agent's store path and resume format, view defaults, redaction rules, export behaviour, the port the web UI listens on, how the agent skill (ectype recall) brings a session in and under what command name (with Install and Remove for the three agents' command files), how many backups to keep, and the wording of the import notice. Help ends with an About section: version, the GitHub and PyPI pages, the licence.

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

Languages. The web UI speaks English and Turkish. Settings → Language picks one or follows the browser's, and how numbers and dates are written is a separate choice there. What an agent reads stays English in every language: transcripts, every export format, the role markers, the fidelity report. Only the import notice can be written in the interface language, as an option. A language is one JSON file: copy ectype/i18n/locales/en.json, translate the values, check the result with ectype i18n check <file>, and put it in the locales folder beside the settings file to try it with no rebuild. The language menu lists it by its own name with how much of it is translated, and a string that is not translated shows in English.

Known limitations

  • Cross-agent conversion carries the conversation, not the tool records. 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"].
  • Four writable targets. ectype writes only into the stores of Claude Code, Codex CLI, Gemini CLI and the Cline CLI; the other nine are read-only, for the reasons under Continue it somewhere. Cline resumes only in its terminal UI, so --verify drives that UI through a pseudo-terminal.
  • 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 command line speaks English only. Its help and its messages are not translated, and neither is the error text the web UI passes on from it. The web UI itself is.
  • 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.

Disclaimer

ectype reads, and on request writes, the private files of other programs, whose formats are undocumented and can change with any release of those programs.

  • Before an install modifies a file the store already owns, it takes a backup, unless you pass --no-backup. ectype backup <id> saves a session and every sidecar file that belongs to it, --list shows what has been saved, and --restore NAME puts it back (--dry-run first, which names every destination and writes nothing).
  • Redaction is best effort, not a guarantee. It replaces what its rules match, and no set of rules can know every secret a transcript happens to contain. Read an export before you share it; that is what the list of matched values is for.
  • --install and the "put it in the agent's store" location write into a live agent's store. Close the agent first.
  • A conversion is not a restoration. A converted session gives another agent the conversation, not the state the original ran with: paths, files, versions and tools may all differ. The import notice exists to say so to the model that receives it.

License

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

Questions and bug reports: the repository's Issues page.

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

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages