migrate

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package migrate converts coding-agent sessions between Claude Code and OpenAI Codex so work started with one agent can be resumed with the other.

The two directions are deliberately asymmetric:

  • Codex -> Claude: Claude Code has no import machinery, so zen translates the Codex rollout itself into a Claude-format session file placed where `claude --resume` discovers it (see codex_read.go / claude_write.go).
  • Claude -> Codex: Codex ships its own Claude Code importer, so zen drives it over the `codex app-server` JSON-RPC API and never writes Codex's files itself (see codex_import.go).

Both session formats are undocumented internals of their CLIs. The record shapes handled here were verified against Claude Code 2.1.200 and Codex CLI 0.142.0; unknown record types are skipped rather than failing the migration.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClaudeToCodex

func ClaudeToCodex(ctx context.Context, claudeSessionPath, codexBin string) (string, error)

ClaudeToCodex makes a Claude Code session resumable in Codex and returns the Codex thread id to pass to `codex resume`.

Codex owns this direction: its importer converts Claude sessions into native rollout threads and records them in an import ledger. zen first checks the ledger (the session may already be imported — imports are content-addressed by sha256), and otherwise drives the importer over the `codex app-server` JSON-RPC API. zen never writes to ~/.codex itself.

Known importer limits (Codex 0.142.0): only the ~50 most recent sessions from the last 30 days are detected, and sessions whose recorded cwd no longer exists on disk are skipped.

func CodexToClaude

func CodexToClaude(rolloutPath, worktreePath string) (sessionID string, err error)

CodexToClaude migrates a Codex rollout into a new Claude Code session for the worktree and returns the session id to pass to `claude --resume`.

func WriteClaudeSession

func WriteClaudeSession(t *Transcript, worktreePath string) (string, error)

WriteClaudeSession renders a transcript as a Claude Code session file under ~/.claude/projects/<munged worktree>/<session-id>.jsonl and returns the session id. The worktree must exist: Claude derives the directory name from the symlink-resolved path, and resume only finds files in that exact dir.

Types

type Message

type Message struct {
	Kind MsgKind
	// Text holds the message body for UserText/AssistantText and the output
	// for ToolResult.
	Text string
	// Time is the source record's RFC3339 timestamp, empty if unknown.
	Time string

	// ToolName and ToolInput describe a ToolCall in the source agent's terms
	// (e.g. Codex "exec_command" with {"cmd": ...}).
	ToolName  string
	ToolInput map[string]any
	// CallID pairs a ToolCall with its ToolResult.
	CallID string
}

Message is one conversation step in the agent-neutral transcript.

type MsgKind

type MsgKind int

MsgKind classifies a transcript message.

const (
	// UserText is a plain user message.
	UserText MsgKind = iota
	// AssistantText is a plain assistant message.
	AssistantText
	// ToolCall is an assistant tool invocation. In a well-formed transcript it
	// is immediately followed by its ToolResult (readers guarantee adjacency,
	// synthesizing a placeholder result when the source recorded none).
	ToolCall
	// ToolResult carries the output of the preceding ToolCall.
	ToolResult
)

type Transcript

type Transcript struct {
	// SourceID is the session/thread id in the source agent.
	SourceID string
	// Cwd is the working directory the source session recorded.
	Cwd string
	// GitBranch is the branch the source session recorded, if any.
	GitBranch string
	Messages  []Message
}

Transcript is the neutral intermediate representation of a session.

func ReadCodexRollout

func ReadCodexRollout(path string) (*Transcript, error)

ReadCodexRollout parses a Codex rollout file into a neutral transcript. Records that carry no portable conversation content are skipped: encrypted reasoning, event_msg UI replays, turn_context, and Codex-injected context messages. Every ToolCall in the result is immediately followed by its ToolResult; a placeholder is synthesized when the rollout recorded no output.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL