Skip to main content

harness-convert (hc)

Relocate a coding-agent session across harnesses and resume it natively.

The escape hatch: you're 80% through a fix, your harness hits a rate limit / outage mid-task, and you can't even ask it for a handoff. hc reads the session transcript off disk (the dead harness doesn't need to be running or your quota intact), rewrites it into the target harness's format, and you keep going there.

hc                                          # interactive wizard (TTY): pick from/session/to
hc --from claude --to codex                 # dry-run latest; TTY asks before write
hc --from claude --to codex -y              # write without prompting
hc --from codex  --to claude <session-id>   # a specific session
hc --from claude --to codex --dest-cwd DIR  # land it in a different folder
hc list --from claude -n 5                  # newest 5; TTY: pick one and convert
hc list --from claude --no-interactive      # plain table (also when piped)
hc truncate 20 --from claude                # new session, 20% lighter
hc truncate 20 --from claude <session-id>   # a specific one

By default it's a dry run. Pass --write or -y to create the file (or confirm when prompted on a TTY). It then prints the exact resume command. Flags always win; missing pieces prompt only on an interactive TTY. Stdlib only; set HC_NO_INTERACTIVE=1 to force non-interactive mode.

How it works

A session is (a) a model-context stream, (b) a UI-render stream, and (c) identity metadata. Conversion maps all three.

  • Common interface (hconv/common.py): every harness maps to four records: UserMessage, AssistantMessage, ToolCall, ToolResult. This universal floor guarantees any pair converts and resumes. Private reasoning is dropped (each harness encrypts/owns its own; unrecoverable).
  • N² enrichment (hconv/enrich.py): surplus the floor can't hold (session titles, ...) rides a sparse (source, dest) map, layered on top. A pair with no entry is simply common-only. The map never re-encodes the common records.
  • Adapters (hconv/adapters/): one per harness, locate / read / dest_path / write. Codex's writer emits BOTH streams (response_item for the model, event_msg for scrollback incl. exec_command_end / patch_apply_end tool cards); Claude's single row set serves both. OpenCode is SQLite, not JSONL: it reads the session/message/part tables read-only, and writes the canonical {info, messages} file that opencode import validates and ingests (safer than poking a live WAL DB), so opencode -s <id> resumes it. Grok Build stores a session directory (summary.json + chat_history.jsonl + updates.jsonl under ~/.grok/sessions/); write emits all three so grok --resume <id> loads history. Cursor is a content-addressed protobuf blob tree inside SQLite; the adapter walks it from the current root, and is read-only (writable = False, enforced at the CLI).
  • Ragged-tail close (synthesize_missing_results): the source usually died mid-tool-call, so every orphan ToolCall gets a synthetic result, else the resumed API call rejects the history.

Freeing context (hc truncate)

A long session is mostly dead tool payload. hc truncate 20 clips the heaviest payloads until 20% of the session is gone and writes a new session in the same harness; the original is never touched, so a bad trim costs you nothing.

hc truncate 20 --from claude       # dry run, shows the cap and what it frees
hc truncate 20 --from claude -y    # write it, then resume the new id

What it clips, and why that shape: measuring the 40 largest sessions per harness showed payload concentration is extreme, so it clips the biggest payloads, not the oldest. On Codex, 41 records over 200KB are 45.9% of all payload, and the newest decile holds the most tool output, so an oldest-first rule would free almost nothing. It pools tool inputs alongside outputs (Bash.command, Write.content, Edit.new_string) because inputs are 37% of a Claude session; outputs alone cannot pass ~44% freed. Conversation text is never clipped. view_image payloads are dropped outright rather than head-clipped, since 4KB of base64 is bounded junk rather than information.

The new id is uuid5("harness-convert:truncate:<orig>:<pct>"): deterministic, so re-running the same trim upserts one session instead of piling up copies. Cursor is read-only and cannot be truncated.

Install

pipx install harness-convert                            # PyPI
npm i -g @theharshitsingh/hc                            # npm (needs python3 on PATH)
brew install harshitsinghbhandari/tap/harness-convert   # Homebrew

Stdlib only, no dependencies. From a checkout, pipx install . or plain python3 hc.py ... also work.

Supported

Codex (~/.codex), Claude Code (~/.claude), OpenCode (~/.local/share/opencode), and Grok Build (~/.grok, or $GROK_HOME): any direction between the writable ones. Converting into OpenCode writes an import file; resume with opencode import <file> && opencode -s <id> (the command hc prints). Converting into Grok writes a session directory; resume with grok --resume <id>. Within a harness, sessions are also freely relocatable across working directories (pure metadata rewrite, lossless, title included).

Cursor (~/.cursor/chats) is a source only: --from cursor works, --to cursor is rejected. cursor-agent has no import command, so writing a session would mean authoring its undocumented protobuf blob tree with nothing to validate the result against. Reading is full fidelity, tool outputs included. See docs/cursor-format.md. Grok on-disk shapes: docs/grok-format.md.

Test

python3 tests/test_hconv.py

Metadata

Release files for harness-convert 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for harness-convert 0.6.0
File Size Uploaded
harness_convert-0.6.0.tar.gz 77.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for harness-convert 0.6.0
File Interpreter ABI Platform
harness_convert-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 119.9 kB

Release files / harness_convert-0.6.0.tar.gz

Download URL harness_convert-0.6.0.tar.gz
Size 77.3 kB
Tags Source
SHA-256 checksum
How to use checksums
448fdd3abe13bbfbaed09c68a6ad196e7dd6031eaa57ee82b4f1507f66c4cdfd
BLAKE2b-256 checksum
How to use checksums
56dc1be127f67f65790052229ad28bd9e9f21e756cc587479640daae7b1803bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release files / harness_convert-0.6.0-py3-none-any.whl

Download URL harness_convert-0.6.0-py3-none-any.whl
Size 42.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
580292709abdc73b9bb3876a08797a20d928a8c617d0e9b275b53e8d275bf6ba
BLAKE2b-256 checksum
How to use checksums
c5137cf99863e61227bb724d3e716470f190682a708fb98c546f66639efe579c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page