Important
This is a testing-stage release — back up first. Cleanup deletes permanently, and correct behaviour cannot be guaranteed for every Codex version on every machine. Take a backup before your first cleanup.
Before cleaning, quit ChatGPT/Codex and make a recoverable copy of the Codex data directory (normally ~/.codex) and ~/Library/Application Support/Codex. Keep the backup until you have reopened Codex and verified the result. A current Time Machine backup is also suitable.
Pull requests are welcome. See CONTRIBUTING.md before starting a change.
Codex accumulates: a rollout file for every conversation you have ever had, plugin versions it never got around to deleting, staging folders abandoned by an interrupted update, and whatever your sessions wrote to disk. Clean My Codex scans all of it and lists each item by category with the space it takes.
- Six scan areas. The Codex data directory, sessions, session assets, plugins, worktrees and workspace — each has its own page and its own rules.
- Honest numbers. A SQLite database contributes what it really occupies; its reusable free pages are never presented as space you can reclaim.
- Conservative by default. Nothing is recommended without positive evidence that it is disposable, so a scan that recommends nothing is a normal result rather than a failure. Everything that is only counted is labelled that way in the interface.
- Whole conversations. A session that spans several rollout segments and several layers of subagents is one row in the list and one deletion, with every derived database and every desktop-side copy cleaned up alongside it.
- Worktrees, taken down by git. Codex checks a repository out under
~/.codex/worktreesfor each conversation that needs one, and a checkout with its dependencies installed runs to hundreds of megabytes. They are listed with their repository state, how much of them is build output, and how many conversations ran there. Removing one goes throughgit worktree remove, so the repository they came from stops listing a worktree that is no longer on disk. - Scheduled cleanup. Runs on an interval over stale temporary folders, confirmed old plugin versions and aged-out conversations only. It skips pinned conversations, unfinished goals and queued work, and never touches caches, configuration, standalone session assets, worktrees or the workspace.
A worktree is only ever offered when git's administrative directory for it still carries the marker file Codex writes there. One you created yourself — even sitting in the same folder — is counted and shown, never offered. So is one whose repository has been deleted or moved: the marker went with the repository, and nothing is left to say who made the checkout.
Configuration and credentials — config.toml, auth.json, the age-encrypted secret store under secrets/, the MCP OAuth fallback .credentials.json and .env — along with all six of Codex's runtime SQLite databases and the crash-recovery copies it keeps in db-backups/, the managed proxy CA in proxy/, the Windows sandbox identity files, the data plugins persist under plugins/data, the plugin version Codex is currently using and its runtimes, the Chromium profile data your desktop sign-in lives in, the desktop application's own logs, and every cache — both Codex's own operational metadata cache and the desktop application's runtime caches. Worktrees and the workspace are additionally out of scope for scheduled runs. All of it is counted so the totals add up, and shown as protected.
Download the latest build directly — macOS (Apple Silicon) · macOS (Intel) · Windows (x64) — or pick an installer from Releases. The direct links always serve the newest release, so they are safe to bookmark and share; each release also keeps the versioned files (CleanMyCodex-<version>-<arch>) alongside them.
The macOS bundle is ad-hoc signed but not notarized, so the first launch goes through System Settings → Privacy & Security → Open Anyway. The Windows installer is currently unsigned, so Microsoft Defender SmartScreen may ask for confirmation before it runs.
| Platform | Distribution | Verification | Status |
|---|---|---|---|
| macOS, Apple Silicon | .dmg release |
CI and packaging | Supported |
| macOS, Intel | .dmg release |
CI and packaging | Supported |
| Windows, x64 | .exe NSIS release |
CI and packaging | Experimental; scheduled cleanup is available |
Clean My Codex follows the current Codex Desktop storage layout. The latest Clean My Codex and Codex releases are recommended; because parts of the desktop storage format are private and may change, no fixed range of Codex versions is guaranteed during the testing stage.
Scanning and cleanup run locally. Clean My Codex has no analytics or telemetry and does not upload credentials, session contents or file metadata. A packaged build makes one request to GitHub Releases on startup to check whether a newer version exists; downloads and upgrades remain manual. Calls to codex app-server use the local Codex process.
Scanning is scheduled by the Electron main process, and the expensive traversal runs in a worker so the interface never blocks. The result comes back in six parts:
- Codex data directory — caches, logs and temporary files. A SQLite database only contributes its actual footprint; reusable free pages are never listed as cleanable.
- Sessions — rollouts are read as a stream rather than loaded whole, session information is collected, and session assets are linked back to the conversation that produced them.
- Session assets — ImageGen, Visualization and Plan results are scanned for file count, usage, modification time and source conversation; a Visualization source and its Viewer are grouped as one item, and a Plan is named by the H1 of its newest revision.
- Plugins — the directories on disk are combined with what
codex app-serverreports, separating the current version from older versions and uninstall leftovers. - Worktrees — the checkout Codex creates under
~/.codex/worktreesfor a conversation that needs one. Each is listed with its repository state, how much of it is build output, and how many conversations ran there. - Workspace — scanned only once you open that page. Each output is matched with the source session title recorded in SQLite, and flagged when git has uncommitted or unpushed work.
A scan result is only a read-only snapshot. When cleanup runs, the main process rebuilds its task list from that snapshot and re-validates every path; caches, configuration, credentials, the state database, the current plugins, worktrees and the workspace never enter scheduled cleanup.
Three of the six areas are things sessions leave on disk. They relate to sessions differently, so they are deleted differently.
| Area | Where it lives | Relation to a session | How the link is built | How it is removed |
|---|---|---|---|---|
| Session assets | ~/.codex/generated_images, visualizations, visualization-viewers, plans |
1 session ↔ 1 directory | The directory name is the thread ID | rm -rf |
| Workspace | ~/Documents/Codex |
N sessions ↔ 1 directory | sourceThreads[], reverse-looked-up from the SQLite working directory |
rm -rf + git safety check |
| Worktree | the checkout under ~/.codex/worktrees |
N sessions ↔ 1 worktree | Same sourceThreads[] reverse lookup |
git worktree remove |
- Session assets are deleted with their session; the workspace is not.
generated_images/<thread-id>belongs to one session alone, so once that session is gone the directory is garbage and removing it with the session is safe — there is no point keeping the child once the parent is gone.~/Documents/Codex/xxxmay be shared by several sessions (sourceThreadsis an array) and sits in your documents folder as real work, so it is not deleted with any one session. The rule in one line: session assets follow their session; the workspace does not. - Cascade forward, not backward. Deleting a worktree or a workspace folder can optionally also delete the conversations that ran there — parent deletes child. Session assets cannot delete the session they belong to — child does not delete parent: an asset is a session's product, not something that should decide the session's fate.
- The app removes these itself, not
thread/delete. None of these directories is managed by thethread/deleteprotocol; the app deletes them directly. The protocol only handles the session's own rollouts, database rows and index lines.
Every path under ~/.codex below is checked against the Codex sources, which is the harness the desktop application is built on, rather than inferred from one machine's directory listing. The desktop's own storage is not open source — the Application Support tree, the Chromium profile, ~/.codex/sqlite and .codex-global-state.json are read from observed data instead, and are treated more cautiously for it: counted, never deleted as files.
Each source is scanned as what it actually is:
codex app-server—plugin/listconfirms which plugins and versions are installed. On versions that supportthread/delete, Codex deletes the conversation itself; on versions that do not, the app falls back to targeted local cleanup.- Rollout JSONL —
~/.codex/sessionsand~/.codex/archived_sessionsare scanned as a stream. They are the durable record of session events, and the source Codex itself builds its session-history projection from. state_*.sqlite— read-only for titles, working directories, archive state and subagent parent/child links. A title prefers the concisenameCodex generates, falling back totitleand thenpreview, both of which usually hold the whole first user message. Parent/child links come fromthread_spawn_edges. Rows are removed only when a session is deleted, and only those of that session and all of its descendants.session_index.jsonl— a supplementary index behind generated titles and the desktop session list. Deleting a session removes the index lines for exactly the same set of threads.thread_history_*.sqlite— the session-history projection Codex derives from the rollouts. The scanner counts it as a session projection database; deleting a session clears the matching rows directly instead of waiting for Codex to rebuild them.~/.codex/sqlite/*.db— the ChatGPT/Codex desktop's own storage.local_thread_catalogis the conversation list in the left sidebar, and the same directory holds session summaries and history snapshots. Rows are deleted by thread ID when a session is deleted; the files themselves never are..codex-global-state.json— the desktop's persisted state, keyed by thread ID: pins, project membership, queued tasks. Only the keys and list items of deleted sessions are removed;electron-persisted-atom-state(drafts, panel layout and other interface state) is left alone as a whole.generated_images/<thread-id>— standalone image directories produced by a conversation and listed on the Session Assets page.visualizations/YYYY/MM/DD/<thread-id>— the rich visual results Codex generates, such as JPG/PNG comparisons or HTML visualization previews. The date levels are walked recursively, listed as session assets and attributed to their source conversation.plans/<thread-id>— the plan documents Codex's plan mode produces, grouped by conversation. A conversation's directory may hold several revisions, which the scan collapses into one item named by the H1 of its newest revision; it is removed along with the conversation that owned it.visualization-viewers/<thread-id>— the rendered viewers Codex materializes from those fragments, which its own code calls the viewer caches. A Viewer is grouped and deleted with the Visualization source for the same thread, avoiding a half-broken result.~/.codex/cache— the remote plugin catalog (remote_plugin_catalog), the Apps server and tool definitions (codex_apps_server_info,codex_apps_tools), the connector directory (codex_app_directory) and the terminal pet packs (tui-pets). Every one of them is rebuildable, but a future release may put live state beside them, so the whole directory is counted as protected data with no way to delete it.~/Library/Logs/com.openai.codex/YYYY/MM/DD— the desktop application's own logs, one file per session per process. The application rotates them itself, keeping only the last few days, so they are counted towards the totals and never offered: cleaning them would reclaim only what is about to be reclaimed anyway, and would take the recent sessions its own diagnostics read with it. Deletion is refused for the whole log tree.~/Library/Caches/Codex,~/Library/Caches/com.openai.codex— the desktop application's runtime caches. The container and every leaf directory inside it are counted as protected data, with no way to delete them.- The Chromium profile data your desktop sign-in lives in —
Cookies,Network/,Local Storage,Session Storage,IndexedDB,Service Worker,Preferences,Web Data,Local State,Partitions/,codex-browser-app/and the like. The root,Default/and the desktop's own partition layout are all locked: counted, never cleaned. Deletion is refused for the whole Application Support tree and for the platform cache containers. ~/.codex/sqlite,.codex-global-state.jsonand its.bak— the desktop's own session database and persisted state. Rows and keys go only when a session is deleted; the files themselves are locked.- User-authored and live-state paths —
rules,skills,hooksandhooks.json,memories,agents,themes,avatars,prompts,shell_snapshots,attachments,session_index.jsonl,installation_id,managed_config.toml,environments.toml, the app-server daemon and control sockets, the Wasm TTS components and the goals/queue/memories/logs databases — counted towards usage, but kept locked. ~/.codex/.tmp— despite the name, live state: the curated plugin checkout, the installed marketplaces, the bundledopenai-bundledsource and Codex's rollout locks all live here. Only the temporary-directory prefixes Codex creates itself are eligible, namely theplugins-clone-*checkouts and theplugins-backup-*directories that Codex's own startup sweep leaves behind because it only removes the clones. Any other unknown.tmpsubdirectory is never inferred to be disposable just because it has sat there a long time.~/.codex/tmp/arg0— a different directory from.tmp, holding one locked directory per running Codex process for theapply_patchand sandbox helper shims. Codex deletes every unlocked sibling on launch, so the ones still there were abandoned by its own definition, and removing them costs the next launch a symlink rebuild.- The staging parents —
.tmp/marketplaces/.staging,plugins/.remote-plugin-install-stagingandplugins/.marketplace-plugin-source-staging. Codex renames a finished tree out of each of these and drops the rest, so every surviving child belongs to a process that died mid-install.
Recommended on the overview holds two kinds of thing, and only these two, because they are the only ones backed by evidence beyond "it looks like a cache": install and update staging leftovers, which have to be more than 24 hours untouched, sit in a directory Codex itself treats as scratch, and not belong to the current source; and old plugin directories, where plugin/list has authoritatively confirmed a current version exists. A plugin directory named local is never one of them, whatever the catalog reports, because Codex resolves the active version from the directory listing alone and local outranks every numbered sibling. When neither kind is present, nothing is recommended, and that is the correct answer rather than a failed scan.
One conversation can be spread across several rollout files, and can recursively spawn several layers of subagents. The interface shows a single top-level conversation, but every total and every action uses the full closure: all continuation segments of the main conversation, the segments of subagents at every level, and the generated images and Visualization directories belonging to each of them.
The current release does not scan, count, deduplicate or rewrite images embedded directly in conversation content; it manages only the ImageGen, Visualization and Plan directories Codex writes to disk, treating each Viewer as part of its Visualization. Session assets can be deleted on their own page, while deleting a conversation still removes every asset linked to that conversation and its subagents.
Deleting a session requires ChatGPT/Codex to have quit. It then runs, in order:
- Resolve every thread ID involved in this deletion: the IDs in the rollout file names, the subagents in
thread_spawn_edges, and the records instate_*.sqlitewhose rollout path points at those files. A desktop conversation has its own thread ID and does not appear in a file name, so it can only be found by looking up the rollout path. - Call the app-server's
thread/deletefor the main conversation, the desktop conversation record and each level of subagent, in preference to anything local. Each request permanently deletes that thread's continuation rollouts, database records andsession_index.jsonllines. - Where the version does not support the protocol, or any request fails, fall back to local compatible cleanup and permanently delete the rollouts the protocol did not handle.
- Permanently delete the
generated_imagesand Visualization directories, which the protocol does not manage. - Whether the protocol or the fallback ran, re-check
thread_history_*.sqlite,state_*.sqliteandsession_index.jsonlagainst the same set of thread IDs, and remove records still pointing at deleted rollouts. - Clean the desktop's own copy last: rows are deleted by thread ID from
~/.codex/sqlite/*.db(local_thread_catalogis the sidebar conversation list, and the summary and history-snapshot databases sit beside it), and the matching mapping keys, list items and…threadIdfields are stripped from~/.codex/.codex-global-state.jsonand its.bak.thread/deletedoes not cover these two — when the protocol reports success and the core data really is gone, but the conversation is still in the sidebar and opening it reportsno rollout found for thread id, this is the step that was missing.
Every step records how many rows it removed in the cleanup log.
Configuration, credentials, the current plugins and the workspace are not removed along with a session; the session_index.jsonl lines tied directly to the target session are.
Automatic session cleanup skips pinned conversations, conversations with an unfinished goal, and conversations that still have a queued item; if any subagent meets one of those conditions, the whole top-level conversation is skipped. Pinning is read both from the is_pinned column in state_*.sqlite and from pinned-thread-ids in .codex-global-state.json — the desktop records pins in the latter, so reading only the column misses them. Manual deletion is not bound by those conditions: a conversation you selected and confirmed is deleted as you asked. The list marks pinned conversations, and the confirmation dialog says how many of the selected conversations are pinned. Before a manual deletion, SQLite integrity, the supported core tables and the write lock are checked first, so a database that cannot be modified is not discovered after the session files are already gone. Plugin deletion re-asks codex app-server for the current version immediately before it runs, so an upgrade between scan and cleanup cannot cause the wrong version to be removed.
One thing worth knowing that this app does not manage: Codex records a checkpoint of every turn as a git ref in your own repository, under refs/codex/turn-diffs/. Those refs keep the objects they point at alive, so git gc cannot reclaim them and a long-running repository's .git keeps growing. They live in your repository rather than in Codex' data directory, so Clean My Codex counts nothing of them and touches nothing of them.
Cleanup is written to a log — cache and leftover removals record the path and byte count of each deletion, including the ones that failed or were skipped: macOS ~/Library/Logs/CleanMyCodex/cleanup.log, Windows %APPDATA%\CleanMyCodex\logs\cleanup.log. Each deletion records the thread IDs that were resolved, whether thread/delete was available, how many rows the local re-check removed, and which desktop table and state file were cleaned of how many entries. Past 1 MB, one generation of history is kept. Scheduled cleanup writes its own autoclean.log. Settings → Diagnostics → Logs opens that folder.
Requires Node.js 24 and pnpm 11.19. Built on Electron 43, which runs on macOS 12+ and Windows 10+.
pnpm install
pnpm devFull check:
pnpm checkPackaging:
pnpm build:mac
pnpm build:win
pnpm build:win-arm64See CONTRIBUTING.md for the development workflow and cleanup-safety expectations. Use GitHub Issues for bugs and feature proposals, and read SUPPORT.md before sharing logs.
Security vulnerabilities must not be reported in a public issue. Follow the private reporting process in SECURITY.md. Participation in the project is governed by the Code of Conduct.
Clean My Codex is an independent community project. It is not affiliated with, endorsed by or sponsored by OpenAI. Codex and OpenAI are trademarks of OpenAI.
