Move coding-agent sessions between harnesses without flattening them into a prose summary.
HarnessHop currently converts OpenAI Codex rollout history to the official Agent Trajectory Interchange Format (ATIF v1.7) and imports it into Hermes Agent through Hermes's own SessionDB.import_sessions() API. It is local-first: historical tool calls are parsed as data and are never executed.
中文简介:HarnessHop 把 Codex 的本地会话解析为标准 ATIF,或安全导入 Hermes。默认只预检,不写 Hermes;只有显式传入 --apply 才会调用 Hermes 官方 SessionDB。
Coding harnesses persist rich context—user and assistant messages, tool calls and results, reasoning summaries, attachments, timestamps, model metadata, Git state, compaction checkpoints, and branches—in incompatible formats. Copying a final summary loses the structure required for search, inspection, and continuation.
HarnessHop uses a portable intermediate representation:
Codex rollout JSONL
│
▼
ATIF v1.7 trajectory
│
├── portable JSON / JSONL
└── Hermes session import payload
│
▼
SessionDB.import_sessions()
ATIF is an existing public specification maintained by the Harbor project; HarnessHop does not invent a competing interchange format.
| Capability | Status | Notes |
|---|---|---|
| Codex legacy rollout JSONL → ATIF v1.7 | Supported | Verified end to end with Codex 0.142.4; common newer legacy records use explicit loss accounting |
| Codex legacy active-history reconstruction | Supported | Applies replacement_history compactions and thread_rolled_back events |
| Codex audit export | Supported | Keeps every durable response item from every selected rollout |
| Codex current-rollout selection | Supported | Reads state_*.sqlite read-only and honors threads.rollout_path |
| Codex self-contained paginated rollout | Supported | Requires complete contiguous ordinals from zero and preserves source ordering |
Codex paginated history_base / bounded lineage |
Fail-closed | Rejected until recursive lineage reconstruction is implemented |
Zstandard-compressed *.jsonl.zst rollout |
Fail-closed | Detected rather than silently omitted; decompression support is on the roadmap |
| ATIF → Hermes JSON | Supported | Dashboard-compatible { "sessions": [...] } payload |
| Codex → live Hermes import | Supported | Uses the target Hermes installation's own Python and SessionDB |
| Claude Code / OpenCode / Gemini / Aider adapters | Roadmap | Contributions welcome |
See docs/COMPATIBILITY.md for the versioned support boundary. Codex rollout JSONL has no schema-version field and evolves between CLI releases, so HarnessHop distinguishes self-contained paginated files from lineage segments that would be incomplete on their own.
Python 3.11 or newer is required.
# uv tool install from GitHub
uv tool install git+https://github.com/Valdemar-Yu/harnesshop.git
# or develop from source
git clone https://github.com/Valdemar-Yu/harnesshop.git
cd harnesshop
uv sync --extra devPass the Codex home, not only the sessions directory, so HarnessHop can use Codex's current-rollout SQLite index:
harnesshop convert \
--from codex \
--to atif \
~/.codex \
--output codex-current.atif.jsonlFor one rollout, the output is one formatted ATIF JSON document. For multiple rollouts, it is JSONL with one ATIF trajectory per line.
Audit mode does not apply rollback or compaction replacement and includes superseded rollout files:
harnesshop convert \
--from codex \
--to atif \
~/.codex \
--history audit \
--output codex-audit.atif.jsonlAudit history is portable evidence, not the context you should resume from. Hermes output therefore requires the default --history active.
harnesshop convert \
--from codex \
--to hermes \
~/.codex \
--output hermes-sessions.jsonThe resulting object can be submitted to Hermes Dashboard's session import endpoint or inspected before any write.
Dry-run is the default:
harnesshop import \
--from codex \
--to hermes \
~/.codexApply only after reviewing the dry-run summary:
harnesshop import \
--from codex \
--to hermes \
~/.codex \
--applyBy default, imported sessions use the target Hermes profile's current model.
This avoids forcing a Codex-only model onto a different provider. Add
--preserve-source-model only when the target Hermes installation can run the
original Codex model.
Import into a named Hermes profile by targeting its home directly:
harnesshop import \
--from codex \
--to hermes \
~/.codex \
--hermes-home ~/.hermes/profiles/work \
--applyIf Hermes is installed in a non-standard location, add --hermes-install /path/to/hermes-agent.
An explicit path is authoritative: HarnessHop fails instead of falling back to another installation.
- Source files and Codex SQLite databases are opened read-only.
- Export files are atomically replaced with owner-only
0600permissions. - Historical shell commands, patches, web searches, and tool calls are never executed.
- Hermes writes require the explicit
--applyflag. - Hermes writes go through
SessionDB.import_sessions(); HarnessHop never hand-editsstate.db. - Deterministic, bounded
codex_<sanitized-thread-id>-<digest>IDs make repeated imports idempotent without collapsing distinct source identities; Hermes skips existing IDs. - The original Codex model stays in target loss metadata; Hermes uses its current model unless
--preserve-source-modelis explicit. - Parent sessions are ordered before children, and invalid self-parent edges are dropped at the Hermes boundary.
- Imports are split below Hermes's 25 MiB / 50,000-message transaction limits.
- Import batches commit independently through Hermes. If a later batch fails, earlier commits are not rolled back; the JSON result reports each batch plus imported, skipped, verified, and failed session IDs so the operation can be resumed safely.
- Hermes limits one imported session to 5 MiB. ATIF keeps the complete representable content, while the Hermes target truncates oversized message bodies head-and-tail. Every truncation contains a visible marker and
display_metadata.harnesshoploss metadata. - Encrypted Codex content cannot be decrypted by HarnessHop. Its presence is counted in
extra.harnesshop.fidelityrather than misrepresented as plaintext. - Unsupported records are counted; they are not silently claimed as preserved.
- Unsupported paginated lineage, invalid ordinal sequences, and compressed rollouts stop conversion before any output or Hermes write.
See docs/FORMAT.md for the exact mapping and loss-accounting fields.
Converted transcripts can contain credentials, personal information, proprietary source, local paths, remote URLs, prompts, and complete tool output. HarnessHop does not automatically redact them because silent mutation would undermine migration fidelity.
Do not publish generated transcripts without manual review. Do not attach real private rollout files to public bug reports; create a synthetic minimal fixture instead.
uv sync --extra dev
uv run pytest -q
uv run ruff check .
uv buildAll committed fixtures are synthetic. New behavior should be developed test-first, including a failing regression fixture before parser changes.
- ATIF specification
- OpenAI Codex rollout persistence
- OpenAI Codex persisted history types
- Hermes Agent session storage
- Hermes Agent sessions
- Codex paginated lineage reconstruction: ordinals,
history_base, fork/revert bounds, subagent inherited-history cutoff, and*.jsonl.zst. - OpenCode import/export adapter, using its first-party round-trip schema.
- Claude Code JSONL reader with branch/sidechain reconstruction.
- Gemini CLI recording adapter after a field-level compatibility audit.
- Aider Markdown reader, explicitly marked low fidelity.
- Additional native writers only where the target exposes a supported import boundary.
MIT. See LICENSE.