Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Codex Rollout Shrinker

codex-rollout-shrinker is a local CLI and .NET 10 library for safely creating a compacted Codex child, shrinking its cold rollout, and restoring that child from an explicit verified backup.

The original V0 workflow remains available when a Codex frontend exposes the required controls:

  1. Fork the source thread.
  2. Switch to the fork and run context compaction.
  3. Wait for compaction to finish.
  4. Close the frontend so its Codex backend releases the rollout writer.
  5. Run inspect, then the explicitly confirmed shrink command with the fork thread ID.
  6. Reopen the same fork thread in Codex.

The V1 command automates the missing frontend operations while every ordinary Codex process is closed:

codex-rollout-shrinker fork-compact-shrink <source-thread-id> \
  [--codex <absolute-path>] [--codex-home <path>] \
  [--sqlite-home <absolute-path>] [--skip-history-cache-reset] [--yes]

The selected Codex app-server creates and registers one persistent fork, compacts it, and exits gracefully. The production command currently sends an eligible legacy child through the existing V0 transaction. The approved paginated extension instead detaches an eligible reference-backed child and requires a second same-binary app-server reconciliation, final source/child fences, and by default a verified opaque global thread-history cache backup/removal before success. Default paginated reset requires an explicit --sqlite-home, which both app-server instances must independently resolve. --skip-history-cache-reset omits only the final cache transaction and allows the target to be omitted; both instances still resolve and compare the actual SQLite home. Skip does not promise a fresh GUI projection or a rebuild merely from restarting Codex. The extension supports standalone paginated sources with absent/null history_base and exact zero-based local ordinals. In either branch the source may be a root or ordinary fork, remains byte-identical, and is never shrunk in place.

The V0 transformation preserves the child's first canonical session_meta record and the smallest raw JSONL suffix containing both the newest usable compacted checkpoint and Codex's required user-turn TurnContext replay anchor.

Legacy thread_rolled_back history is supported only when an EOF-to-rollback reverse-segment barrier proves that the physically newest usable checkpoint survives, and the ordinary minimal retained suffix excludes every rollback marker. The tool does not apply rollback counts or rewrite dead history.

Legacy rollouts from Codex 0.153.x may contain token_usage_record accounting metadata. These records are recognized and retained byte-for-byte when inside the selected suffix. The checkpoint's usage snapshot and model-invisible guardian_history are also preserved; the latter can legitimately retain old text inside the checkpoint. Unknown top-level item types still cause refusal. Standalone-paginated sources also accept this accounting metadata without letting it advance or repair turn readiness; canonical ordinals and all other source checks remain mandatory. Linked children also accept the observed 0.153 usage-before-checkpoint and settings-after-checkpoint positions, without relaxing compaction completion. See the 0.153 compatibility evidence and WSL follow-up.

Status

WP1 implements a read-only, fail-closed inspector. It discovers one active legacy fork rollout, validates every JSONL record, selects the newest usable compaction checkpoint, and reports the exact raw byte ranges a later writer would retain. The safe suffix may begin before the checkpoint when that is required to preserve resume settings.

WP2 implements an internal, non-publishing image builder. It streams the entire inspected source, rechecks its length and SHA-256, copies the selected raw byte ranges into an empty caller-owned stream, and independently parses the result through the same semantic analysis used by inspect. It does not create a discoverable rollout or claim public Codex resume equivalence.

WP3 implements an internal immutable backup bundle. A unique directory outside both Codex session trees receives an exact source copy and a strict V1 manifest binding the source digest to the already verified WP2 replacement digest. Unix bundles are owner-private; Windows bundles inherit the Codex-home ACL. The source backup is reread and hash-checked before the bundle is published. Verification remains independently reusable by the transaction services.

WP4 implements the internal Codex-compatible per-thread writer lock. It uses the same coordination and target paths as Codex, native flock on Linux, and native LockFileEx on Windows. Two-way disposable-home canaries passed against the public Codex 0.147.0 Linux x64 and Windows x64 binaries. This does not add a mutating command.

WP5a implements internal durable atomic rollout publication. It creates one same-directory, non-JSONL staging file, durably flushes and independently verifies it, revalidates the source plan and immutable backup binding, and then uses one File.Replace operation. Linux synchronizes the parent directory; Windows flushes a native directory handle and reports best-effort directory metadata durability. Linux additionally requires the source owner to match the effective UID and preserves exact UID/GID identity plus the allowed POSIX mode; ACLs and extended attributes are not yet part of the proof. Once publication begins, every ambiguous failure is reported as outcome unknown without rollback. Native synthetic suites passed on Linux ext4 and Windows NTFS.

WP5b implements the internal shrink transaction coordinator. It holds the WP4 writer lock across fresh plan equality, file-backed candidate construction and durable verification, immutable backup creation, WP5a publication and final verification, and transaction scratch cleanup. It never removes a published backup or retries/rolls back an outcome-unknown publication. The integrated synthetic suite passed on Linux ext4 and native Windows NTFS.

WP6 implements internal hash-guarded restore. It verifies an explicit immutable backup before classifying state, rediscovers the active rollout rather than trusting the manifest as write authority, treats an exact source hash as an already-restored no-op, and restores only over the exact manifest replacement hash. Restoration uses one durably flushed same-directory non-JSONL staging file and one atomic publisher call under the existing writer lock. Once that call begins, ambiguous failures are outcome unknown without retry or rollback. Backup reads also reject Linux FIFOs without blocking. The WP6 synthetic suite and extended native paths passed on Windows NTFS, including 262- and 386-character rollout paths; in this WP6 validation, the public-Codex canary remained an explicitly opt-in skip.

WP7 adds a test-only public Codex cold-resume and next-request canary. The official Codex 0.147.0 Linux x64 and Windows x64 binaries both cold-resumed a synthetic legacy fork after the real shrink transaction, completed a model turn against a bounded IPv4-loopback Responses mock, and listed the unchanged thread ID/path. The captured request contained the checkpoint replacement, retained suffix, and new turn exactly once in order, and contained no discarded-prefix marker. The existing public writer-lock canary also passed through the shared notification-preserving app-server helper. This completes WP7 on both primary platforms.

WP8 exposes the complete mutating surface. shrink prints the exact inspector plan before accepting either an exact interactive phrase or --yes, then passes that same plan to the lock-bound transaction. restore requires an explicit manifest and never searches for a latest backup. Stable content-free results, typed outcome-unknown backup evidence, cancellation, and exit-code contracts passed with disposable synthetic homes on Linux ext4 and native Windows NTFS. The first real live trial subsequently passed on a manually created fork: the active rollout fell from 14,869,588 to 228,680 bytes, the same ID/path resumed in the VS Code frontend, and ordinary turns continued to append without any shrinker-written SQLite state. Aggregate timings and evidence limits are recorded separately from the synthetic interoperability proof.

The rollback extension preserves every existing mutation and restore contract. Its synthetic suite covers typed rollback payloads, reverse-segment edge cases, minimal candidate reanalysis, and an exact shrink/backup/restore round trip. A rollback-specific opt-in public Codex canary is committed; sanitized real rollback-rollout validation remains a separate pending evidence gate. The new canary passed against the local public Codex 0.147.0 Linux binary.

V1 implements fork-compact-shrink as a fail-closed orchestration layer. It confirms before the first persistent fork, structurally probes the selected binary's generated app-server schema for excludeTurns, sends a persistent fork with turn hydration excluded, requires one coherent context-compaction turn, then uses a metadata-only child readback to prove idle status and stable lineage/path. Only a sticky clean shutdown—stdin closed, process exit zero, and both output streams settled before the deadline—permits V0. The app-server is the only SQLite writer; the C# process never opens SQLite or edits database bytes. Paginated mode has one later opaque-file exception that backs up and removes the derived cache only after both app-servers and all final fences. The full chain is intentionally non-atomic: a failure after fork submission retains the possible child, reports content-free phase evidence, and never retries or automatically deletes it. Codex 0.147.0 remains valid V0 evidence but lacks the required V1 fork schema. The first V1 release target is 0.2.0-rc.1. The selected public Codex 0.151.0-alpha.7.2 passed the opt-in production full-chain canary on Linux ext4: a rollback-bearing root source was forked, compacted, cleanly shut down, shrunk with a verified backup, cold-resumed, continued for one model turn, and resolved through thread/list, while the source remained byte-identical. The two captured model requests proved that rolled-back content stayed absent. The separate 0.147.0 negative capability canary passed by refusing that binary before fork. On native Windows/NTFS, npm-installed public Codex 0.151.0 passed npm PATH resolution, schema probing, and the same production full-chain canary. Sanitized real-rollout validation remains pending.

A production contract is now approved for a distinct standalone-paginated branch. It preserves the legacy V0 path, but requires exact source/frontier and ordinal proofs, a raw-span detach/rebase transaction with manifest V2, atomic publication, and same-binary resume/list reconciliation plus final hash fences. The implementation and sanitized synthetic success/failure matrix are complete. The selected executable is bound by canonical path plus complete-file SHA-256 across both app-server lifetimes. The public Codex 0.151.0 Linux command chain passed in a disposable home against a private real-shape standalone paginated source, including fork, compact, V2 backup, atomic detach/rebase, reused-home resume/summary-list reconciliation, and final fences. The 2026-09-11 follow-up also passed Linux 0.153.4 cold Skip through the public library, including a separate real-model continued turn. Native-Windows/NTFS paginated execution and GUI freshness remain separate unverified gates; cross-published packages do not establish them. The final 2026-08-31 ordinary suite passed 598 tests with 17 opt-in canaries skipped. The pinned public Codex schema checks passed 3/3: 0.151.0 exposed both the legacy fork/compact and paginated reconciliation subsets, while 0.147.0 was refused before fork as expected.

Codex 0.151 may retain a stale thread_history_1.sqlite projection after the paginated child rollout is detached and rebased. The paginated mainline now finishes with the same verified opaque global cache transaction used by the standalone experiment: after the second app-server exits cleanly and every final fence passes, it backs up and removes main/WAL/SHM without opening SQLite. Success prints both the detach and cache manifests, reports gui-history-visibility: pending-cache-rebuild-on-next-codex-start, and asks the operator to start the GUI or exactly one Codex instance so Codex can rebuild the cache. It never fabricates a model turn or starts a third app-server.

Codex 0.151 can list the same empty-preview row inside an explicitly assigned thread section. Such an assignment may provide immediate content-free GUI surfacing in clients that render sections, but it is a user-visible organization mutation outside fork-compact-shrink authorization. An explicitly experimental cold-home command is available for operator testing:

codex-rollout-shrinker experimental-section-surface <thread-id> \
  [--codex <absolute-path>] [--codex-home <path>] [--yes]

It creates or reuses the exact Shrunk sessions section through the selected app-server and assigns one standalone paginated user fork without a model turn. Close every Codex process using that home first. Success proves persistent section assignment and unchanged rollout bytes; restart the GUI to determine whether that client build renders the section. The command never claims global recent-list eligibility and never moves a thread already assigned to a different section. Its non-atomic create/move safety contract is design/experimental-section-surface-v0.md.

For the separate Codex 0.151 stale paginated-projection problem, an experimental global cold-cache command is also available:

codex-rollout-shrinker experimental-reset-thread-history-cache \
  --sqlite-home <absolute-path> [--yes]

Close every Codex CLI, GUI, extension host, and app-server using that SQLite home before preview and keep them closed until completion. The command treats thread_history_1.sqlite plus optional -wal/-shm peers as opaque files. It rejects unknown sidecars and non-regular paths, holds the complete previewed set through removal, and publishes a length/SHA-256 verified backup before deleting SHM, WAL, and main in that order. Linux backups are owner-private; Windows backups inherit the SQLite-home ACL. It never runs SQL or edits database bytes. On success, start exactly one Codex instance and verify the target thread before returning to normal use; recreation remains Codex's work.

This is a global cache action: unrelated paginated threads may be lazily reprojected. The exact-process scan and whole-file guards are strong cold-state preflights, not SQLite-compatible coordination proof, and a Codex startup race remains. The standalone command remains useful for recovery and testing; the paginated mainline reuses the same transaction only after reconciliation and all final fences. Its backup-only, partial-removal, and outcome-unknown contracts are specified in design/experimental-thread-history-cache-reset-v0.md. If this final cache stage fails, the new child remains detached and reconciled; the tool never retries or deletes it. Pre-removal and backup-only cases exit 6, partial removal exits 6 with exact removed/remaining names, and an unknown main removal exits 4. Both manifests are reported whenever the cache backup exists.

Mutating success receipts are rendered before stdout publication. If stdout then fails, exit 5 and a best-effort content-free stderr receipt preserve the successful status and exact thread, rollout, and verified manifest evidence. Both shrink and restore outcome-unknown results carry that same complete absolute evidence. If stdout fails, the same pre-rendered outcome-unknown block falls back to stderr; failure of both channels still returns exit 4 without a retry. The tool does not use session_meta.cli_version as a false future-binary gate; operators must rerun the public compatibility canaries for new Codex versions.

codex-rollout-shrinker inspect <thread-id> [--codex-home <path>]
codex-rollout-shrinker shrink <thread-id> [--codex-home <path>] [--yes]
codex-rollout-shrinker restore <thread-id> --backup <manifest-path> [--codex-home <path>]
codex-rollout-shrinker fork-compact-shrink <source-thread-id> [--codex <absolute-path>] [--codex-home <path>] [--sqlite-home <absolute-path>] [--skip-history-cache-reset] [--yes]
codex-rollout-shrinker experimental-section-surface <thread-id> [--codex <absolute-path>] [--codex-home <path>] [--yes]
codex-rollout-shrinker experimental-reset-thread-history-cache --sqlite-home <absolute-path> [--yes]

Build and run the focused synthetic suite with .NET 10:

dotnet build CodexRolloutShrinker.slnx
dotnet test CodexRolloutShrinker.slnx --no-build

Pin the public Linux x64 Codex versions used by the release gates beneath the ignored artifacts/codex-canaries/ directory:

./eng/provision-codex-canaries.sh
source artifacts/codex-canaries/env.sh

The provisioner installs exact npm versions 0.151.0 and 0.147.0, validates their native executable versions, reuses complete existing installs, and refuses incomplete or symlinked destinations. The generated env.sh selects the compatible full-chain binary and the legacy pre-fork rejection binary for eng/release.sh; neither binary is tracked by Git.

Local development releases

Library consumption

Reference src/CodexRolloutShrinker.Core/CodexRolloutShrinker.Core.csproj from a sibling .NET 10 project, or create a local NuGet package:

dotnet pack src/CodexRolloutShrinker.Core/CodexRolloutShrinker.Core.csproj -o artifacts/library

The package ID is CodexRolloutShrinker.Core; its version follows Directory.Build.props. Add that local feed when restoring your consumer. There are no production dependencies beyond the .NET base class library, and consumers do not reference the CLI executable.

The following call is the same one executed by the independent package consumer. The three required program arguments are source session ID, Codex home, and selected Codex binary path. An optional fourth argument is the absolute SQLite target: supplying it requests default cache reset; omitting it selects Skip.

var result = await ForkCompactShrinker.RunAsync(
    Guid.Parse(args[0]),
    new ForkCompactShrinkOptions
    {
        CodexHome = args[1],
        CodexPath = args[2],
        SqliteHome = args.Length == 4 ? args[3] : null,
        SkipHistoryCacheReset = args.Length == 3,
    });

Use CodexRolloutShrinker.Core.Automation. A non-null result.NewSessionId means the requested workflow completed; select that ID when the host next starts Codex. On failure, retain result.Status, CacheReset, and Evidence; an absent success ID never authorizes retrying a possible persistent fork. Evidence preserves an observed child ID, verified backup manifest, surviving publication staging, and classified cache/shutdown facts without transcript contents. The public call itself is the explicit apply action; it does not read Console or ask for a second confirmation.

The host must keep the selected Codex home cold and serialize calls. Skip does not enable use alongside a still-running app-server for that home. Default cache reset is global: an existing exact Codex process now causes refusal before the first owned app-server or fork. Its final process/file guards still run; a failure in that final stage retains the detached child and reports no success ID. Source rollouts and recovery backups remain, so child byte savings are not net disk savings across the entire home.

Final verification evidence distinguishes reconciliation_final_fence from reconciliation_storage_fence and preserves the inspection failure code. An additional rollout path does not imply that source or child bytes changed; either failure still returns PublishedUnverified without a success ID.

The library contract defines all result states, cancellation behavior, and input defaults. The runnable consumer is built outside the repository from a real local PackageReference, without test friend access, and exercised against synthetic homes by:

dotnet test CodexRolloutShrinker.slnx --filter FullyQualifiedName~PackageConsumerProbeTests

CLI development packages

After committing the implementation and recording the Linux test result, build commit-pinned development packages from the repository root:

./eng/dev-release.sh --linux-test-evidence "dotnet test: <result>"

The script does not publish to GitHub or run the test suite. It requires a clean non-ignored worktree, rechecks the commit and worktree after the build, and writes framework-dependent linux-x64 and win-x64 archives beneath artifacts/dev/v<version>-<short-commit>/, together with the runtime requirements, checksums, and a BUILDINFO.txt containing the full commit and supplied Linux evidence. It runs the extracted Linux launcher's usage smoke test and checks the cross-published Windows launcher's PE magic, but does not claim native Windows validation.

GitHub releases

eng/release.sh is the fail-closed release entry point for the currently validated linux-x64 and win-x64 targets. It requires a clean main, an explicit semantic version equal to the project version, and any existing local or remote tag to point to HEAD. Formatting, the complete ordinary test suite, both framework-dependent single-file publishes, archives, and SHA-256 checksums are completed before it pushes main or the tag. A published release also requires absolute executable paths in CODEX_LOCK_INTEROP_BINARY and CODEX_LEGACY_CAPABILITY_BINARY: it reruns the compatible V1 full-chain/schema gates and the legacy pre-fork rejection gate before publishing. Published executables require the x64 .NET 10 Runtime (Microsoft.NETCore.App 10.0), but not the SDK. Those target statements describe packaging and do not substitute for platform interoperability evidence. The V1 public-Codex full chain has passed on Linux and native Windows/NTFS for the exact recorded artifacts.

Build and inspect the release assets without touching GitHub:

./eng/release.sh 0.2.0-rc.2 --build-only

After authenticating GitHub CLI with an account that can write origin, create the tag when absent, push main and the tag, and publish the release:

gh auth login
export CODEX_LOCK_INTEROP_BINARY=/absolute/path/to/compatible/codex
export CODEX_LEGACY_CAPABILITY_BINARY=/absolute/path/to/legacy/codex
./eng/release.sh 0.2.0-rc.2

The release assets do not bundle Codex. fork-compact-shrink requires a separately installed compatible Codex executable; inspect, shrink, and restore do not. Without --codex, the tool resolves codex from PATH. On Windows it recognizes both a native codex.exe and the standard npm codex.cmd entrypoint. On Linux it recognizes the standard npm codex symlink to @openai/codex/bin/codex.js. The npm launcher itself is not executed: the tool selects the architecture-matched native executable from the bounded adjacent npm package layouts, then binds that regular file by path and SHA-256. Unknown symlink or script launcher shapes remain refused; for an unsupported package-manager layout, pass the absolute packaged native path with --codex. Windows app-server metadata may report a canonical rollout with the \\?\ extended drive/UNC spelling; the tool normalizes those exact forms for comparison while continuing to reject device namespaces, aliases, and paths outside the selected active sessions tree. --codex remains available for an explicit absolute path. A hyphenated version such as 0.2.0-rc.2 is published as a GitHub prerelease.

Assets are written beneath ignored artifacts/release/v0.2.0-rc.2/. Each archive contains one platform launcher and RUNTIME_REQUIREMENTS.txt. The release script rejects a launcher above 5 MiB so an accidental return to bundled-runtime output cannot silently pass. A rerun is safe after failures before release creation; a pre-existing published release is reported without replacing any remote asset. The script does not move an existing tag, overwrite a release, sign binaries, publish NuGet packages, or claim support for unvalidated runtime identifiers.

The historical v0.1.0 assets were self-contained. Starting with v0.1.1, GitHub Release assets are framework-dependent to avoid duplicating roughly 70 MiB of .NET runtime in each platform executable.

The accepted V0 limitations are intentional:

  • only cold, local, legacy-history fork rollouts;
  • no SQLite writes;
  • no conversion into an independent session-tree root;
  • no attempt to render the compaction recap as a visible transcript message;
  • no full rollback replay, non-contiguous dead-turn deletion, or checkpoint rewrite beyond the proven legacy safe subset;
  • fail closed on unfamiliar storage shapes.

The V1 legacy path keeps that byte-transformation boundary. Its implemented paginated extension is a separate raw-span transformation for strict standalone paginated user sources, not a relaxation of V0. Neither branch makes the external app-server/model/hook/SQLite chain atomic, mutates the source rollout, accepts Codex 0.147.0 for the new command, or cleans up partial children.

See the V0 design for the complete contract. The fork/compact orchestration, schema and source-readiness gates, state machine, partial-child semantics, and validation matrix are specified in the V1 design. The library API, optional history-cache reset, result contract, and consumer validation are described in the library V1 contract. Implementation and platform evidence are recorded in the library acceptance note. The mode-specific standalone paginated transformation, manifest V2, publication, reconciliation, and failure contract is specified in the paginated detachment V1 design. The exact Linux and native Windows public-binary full-chain evidence is recorded in the V1 public Codex canary note. The initial real-shape investigation of a paginated reference child and a detached-copy prototype is recorded in the paginated detachment research note. The legacy rollback subset and its reverse-segment proof are specified in the rollback note. The exact WP4 protocol, evidence, and rerun command are recorded in the writer-lock interoperability note. WP5a platform semantics and evidence are recorded in the atomic replacement note. WP5b lock-bound transaction semantics and failure evidence are recorded in the shrink transaction note. WP6 hash-guarded recovery semantics and evidence are recorded in the restore transaction note. WP7 public cold-resume and next-request evidence is recorded in the public Codex resume canary note. WP8 CLI confirmation, result, and recovery semantics are recorded in the mutating CLI note. The first real-rollout result and sanitized upstream issue data are recorded in the live rollout evidence note. The global opaque-file cache reset experiment is specified in the experimental cache reset note.

Technology decision

The recommended implementation is C# targeting .NET 10. The production CLI uses only the .NET base class library. GitHub Releases publish compact, framework-dependent single-file binaries for Windows and Linux and require the x64 .NET 10 Runtime on the target system. A self-contained publish remains possible for an operator who explicitly needs one.

Python would make the first parser shorter, but .NET is a better fit for this tool's hard parts: distributing one executable, handling Windows paths and file replacement, expressing explicit data contracts, and testing native lock compatibility on both Windows and Unix.

Private research material

Real rollout snapshots live under research/private/, which is ignored by Git. See research/README.md before handling those files.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages