Documentation
¶
Overview ¶
Package bundle creates and (later) reads .codexbundle archives: a ZIP containing a manifest, a checksum map, and the copied Codex rollout files.
A .codexbundle is a portable, hosting-free way to move local Codex sessions between devices. It never includes or modifies Codex's SQLite state DB.
Index ¶
Constants ¶
const ( ManifestName = "manifest.json" ChecksumsName = "checksums.json" )
Bundle file names.
const FormatVersion = "codex-sync-bundle-v1"
FormatVersion identifies the bundle layout. Bump this on breaking changes.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Action ¶
type Action string
Action describes what import decided to do with one bundle entry.
const ( ActionImport Action = "import" // new file; copied (unless dry-run) ActionSkipIdentical Action = "skip-identical" // target exists with same checksum ActionConflict Action = "conflict" // target exists with different checksum; not overwritten ActionReplace Action = "replace" // conflict, overwritten after backing up the local file ActionImportCopy Action = "import-copy" // conflict, imported as a brand-new session (fresh id + filename) ActionSkipArchived Action = "skip-archived" // archived_sessions entry; not imported in v0.1 ActionSkipNonSession Action = "skip-non-session" // unexpected non-session file ActionSkipDeselected Action = "skip-deselected" // not among the --session ids requested for import )
type CWDInfo ¶
type CWDInfo struct {
// Path is the first-seen original spelling of the cwd (for display).
Path string
// Count is how many sessions recorded this cwd.
Count int
// ExistsLocal reports whether the directory exists on this machine. A
// session whose cwd does not exist locally is hidden in Codex's project
// sidebar until the folder is created or the cwd is remapped on import.
ExistsLocal bool
}
CWDInfo describes one distinct recorded working directory across a bundle's sessions and whether that directory exists on the local machine.
type CWDMapping ¶
CWDMapping rewrites a session's recorded working directory from Old to New during import. It is the only feature that mutates session content, and it touches nothing except the canonical "cwd" field of the session_meta line.
func ParseCWDMappings ¶
func ParseCWDMappings(specs []string) ([]CWDMapping, error)
ParseCWDMappings parses and validates a list of "OLD=NEW" mapping specs.
Rules:
- syntax must be OLD=NEW (split on the first '='),
- OLD must not be empty,
- NEW must not be empty and must be absolute/plausible for the target OS,
- OLD and NEW must differ after normalization,
- duplicate OLD paths (case-insensitive on Windows) are rejected.
type CWDSummary ¶
type CWDSummary struct {
// Dirs are the distinct non-empty recorded cwds, sorted by path.
Dirs []CWDInfo
// UnknownCWD counts sessions with no recorded cwd (e.g. compressed
// sessions, whose cwd is unknown in v0.1).
UnknownCWD int
// MissingCount is how many entries in Dirs do not exist locally.
MissingCount int
}
CWDSummary groups a bundle's sessions by their recorded working directory and reports which directories are missing on the local machine. It is the data behind the "project folders" view that helps users find the #1 portability gotcha (imported sessions hidden because their cwd does not exist here).
func SummarizeCWDs ¶
func SummarizeCWDs(sessions []ManifestSession, exists func(string) bool) CWDSummary
SummarizeCWDs groups sessions by recorded cwd and, for each distinct directory, reports the session count and whether it exists locally. Grouping is case-insensitive on Windows (via normalizeCWD), matching how cwd is compared elsewhere; the first-seen spelling is preserved for display. The exists function is injected so the logic is testable without touching the filesystem; production callers pass DirExists.
type Checksums ¶
Checksums maps each bundle-relative file path (forward slashes) to its SHA-256 hex digest. It is written as checksums.json at the root of the ZIP and covers every file in the bundle except checksums.json itself.
type ExportOptions ¶
type ExportOptions struct {
// ProjectPath, when non-empty, restricts the export to sessions whose
// SessionMeta cwd matches this (already absolute) path. Leave empty to
// export every session regardless of cwd (the `--all` behavior).
ProjectPath string
// OutputPath is the .codexbundle file to write.
OutputPath string
// IncludeArchived also considers archived sessions.
IncludeArchived bool
// Since, when non-zero, restricts the export to sessions whose file
// modification time is at or after this instant.
Since time.Time
// SessionID, when non-empty, exports exactly the single session whose
// thread id equals (or uniquely begins with) this value, regardless of
// cwd. It is mutually exclusive with project/all filtering.
SessionID string
// WithGit forces capture of the project's git metadata (remote, branch,
// commit, dirty/unpushed) into the manifest even when ProjectPath is empty
// (e.g. with --all or --session). When ProjectPath is set, git metadata is
// always captured regardless of this flag.
WithGit bool
}
ExportOptions configures an export.
type ExportResult ¶
type ExportResult struct {
BundlePath string
Manifest Manifest
IncludedCount int
TotalScanned int
CompressedSkipped int // compressed sessions skipped by cwd filter (cwd unknown)
Warnings []string
}
ExportResult summarizes what was exported.
func Export ¶
func Export(home codexhome.Home, opts ExportOptions) (ExportResult, error)
Export scans the Codex home, selects sessions (optionally filtered to a project's cwd), and writes a .codexbundle ZIP containing the rollout files, a manifest, and a checksum map. It never reads or writes Codex's SQLite.
type ImportItem ¶
type ImportItem struct {
BundlePath string
DestPath string
Action Action
OriginalCWD string
CWDMismatch bool
// Mapped reports whether --map-cwd rewrote this session's cwd.
Mapped bool
// Copied reports whether this entry was imported as a brand-new session
// (ActionImportCopy, --import-as-copy) with NewThreadID as its fresh id.
Copied bool
// NewThreadID is the freshly assigned session id when Copied is true.
NewThreadID string
// BackupPath, when non-empty, is where the pre-existing local file was
// backed up before being replaced (ActionReplace, --replace-with-backup).
BackupPath string
// contains filtered or unexported fields
}
ImportItem is the plan/outcome for a single bundle entry.
type ImportOptions ¶
type ImportOptions struct {
BundlePath string
DryRun bool
// ProjectPath, when non-empty, enables per-session cwd-mismatch checks
// against this (already absolute) path.
ProjectPath string
// MapCWD, when set, rewrites matching sessions' recorded cwd on import.
// Only plain .jsonl files are rewritten; .jsonl.zst files that match a
// mapping are copied byte-for-byte and reported as unmappable.
MapCWD []CWDMapping
// ReplaceWithBackup turns conflicts (a local file with different content
// for the same session) into a replace: the local file is backed up next
// to itself and then overwritten with the bundle's version. Without it,
// conflicts are reported and skipped (the default, never-overwrite behavior).
ReplaceWithBackup bool
// SessionIDs, when non-empty, restricts the import to the bundle sessions
// whose thread id equals (or uniquely begins with) one of these values; every
// other session in the bundle is skipped (ActionSkipDeselected). An id that
// matches no session in the bundle is an error (nothing is written).
SessionIDs []string
// ImportAsCopy turns conflicts into a brand-new session: the bundle's
// version is assigned a fresh session id and written under a new rollout
// filename, so it coexists with the diverged local session rather than being
// skipped or replacing it. Only plain .jsonl files can be copied; a
// compressed (.jsonl.zst) conflict, or one without a session_meta id, stays a
// skipped conflict. Mutually exclusive with ReplaceWithBackup at the CLI.
ImportAsCopy bool
}
ImportOptions configures an import.
type ImportResult ¶
type ImportResult struct {
Manifest Manifest
Items []ImportItem
Imported int
SkippedIdentical int
Conflicts int
SkippedOther int
// SkippedDeselected counts bundle sessions excluded by a --session filter.
SkippedDeselected int
CWDMismatchCount int
// Replaced counts conflicting sessions that were overwritten after the local
// file was backed up (--replace-with-backup).
Replaced int
// ImportedCopies counts conflicting sessions imported as brand-new sessions
// (--import-as-copy).
ImportedCopies int
// Mapped counts imported sessions whose cwd was rewritten by --map-cwd.
Mapped int
// MappedCompressedSkipped counts compressed sessions that matched a
// mapping but could not be rewritten in v0.1 (copied byte-for-byte).
MappedCompressedSkipped int
ProjectProvided bool
DryRun bool
Warnings []string
}
ImportResult summarizes an import.
func Import ¶
func Import(home codexhome.Home, opts ImportOptions) (ImportResult, error)
Import validates a bundle end-to-end and, unless DryRun is set, copies its rollout files into the Codex home, preserving the sessions/YYYY/MM/DD layout.
Safety guarantees:
- The whole bundle's checksums are verified BEFORE anything is written.
- Unsafe entry paths (absolute, drive-letter, zip-slip) abort the import.
- Only sessions/YYYY/MM/DD rollout files are imported.
- Existing files are never overwritten: identical files are skipped, differing files are reported as conflicts and skipped.
- Writes are atomic (temp file + rename). SQLite is never touched.
- .jsonl.zst files are copied byte-for-byte; never parsed or decompressed.
type InspectResult ¶
InspectResult is the read-only view of a bundle: its manifest, its checksum map, and the names of the files it contains. Inspecting never extracts or writes anything.
func Inspect ¶
func Inspect(bundlePath string) (InspectResult, error)
Inspect opens a .codexbundle and reads manifest.json and checksums.json without extracting any session files. It validates that the bundle has the expected format version.
type Manifest ¶
type Manifest struct {
FormatVersion string `json:"format_version"`
CreatedAt string `json:"created_at"`
CreatedByDevice string `json:"created_by_device,omitempty"`
SourceOS string `json:"source_os"`
SourceCodexHome string `json:"source_codex_home"`
SourceProjectPath string `json:"source_project_path,omitempty"`
Git *git.Info `json:"git,omitempty"`
CodexVersion string `json:"codex_version,omitempty"`
Sessions []ManifestSession `json:"sessions"`
}
Manifest describes a bundle and everything inside it. It is written as manifest.json at the root of the ZIP.
type ManifestSession ¶
type ManifestSession struct {
ThreadID string `json:"thread_id,omitempty"`
OriginalPath string `json:"original_path"`
BundlePath string `json:"bundle_path"`
OriginalCWD string `json:"original_cwd,omitempty"`
Preview string `json:"preview,omitempty"`
FirstUserMessage string `json:"first_user_message,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
Source string `json:"source,omitempty"`
ModelProvider string `json:"model_provider,omitempty"`
GitBranch string `json:"git_branch,omitempty"`
GitSHA string `json:"git_sha,omitempty"`
Archived bool `json:"archived"`
Compressed bool `json:"compressed"`
SizeBytes int64 `json:"size_bytes"`
SHA256 string `json:"sha256"`
}
ManifestSession is one rollout file recorded in the manifest.