Codex account snapshot manager
Project description
Codex Manager Spec
Goal
Build a codex-manager CLI for OpenAI Codex account snapshots, modeled after geminiai_cli where that design is sound, but adapted to Codex's weekly quota behavior.
The manager should:
- normalize existing Codex account artifacts into a stable machine-readable format
- back up and restore Codex account state safely
- track weekly availability based on session start time, not quota-end time
- recommend the next available account
- keep filename conventions simple and put richer timing details into metadata
Source Context
This repo already contains a working geminiai_cli reference implementation.
Relevant patterns confirmed from that codebase:
backup.pyusestimestamp + emailnamingcooldown.pytracksfirst_usedseparately fromlast_usedcli.pyandargs.pydefine a command-oriented structure we can mirror
Codex sample data lives in .codex_sample/ and includes:
- shared state files such as
auth.json,history.jsonl, sqlite state, sessions, logs - many per-account auth snapshots named like
21apr_drdpsbose023@gmail.com_auth.json
Weekly Quota Model
For Codex, the controlling timestamp is:
session_start_at
Not:
- auth file modified time
- quota-ended time
- availability date encoded in the legacy filename
For new live backups, the manager should obtain exact status from Codex /status.
Preferred live source:
- current
~/.codex/auth.jsonfor the active account identity where available - Codex
/statusoutput for actual account email and actual reset time
Derived fields:
quota_end_detected_at: when the auth snapshot file was last modifiedsession_start_at: inferred start time of the weekly sessionnext_available_at:session_start_at + 7 days
For live status-based backups:
reset_atcomes directly from/statussession_start_at = reset_at - 7 days- no prediction is needed beyond subtracting the fixed weekly window
Example:
- legacy file:
21apr_drdpsbose023@gmail.com_auth.json - mtime:
2026-04-14 17:55:00 - inferred session duration before exhaustion:
2 hours - therefore
session_start_at = 2026-04-14 15:55:00 next_available_at = 2026-04-21 15:55:00
Archive Naming
Recommended archive naming format:
yyyy-mm-dd-hhmmss-email-codex.tar.gz
Example:
2026-04-14-155500-drdpsbose023@gmail.com-codex.tar.gz
For live backups, the filename timestamp should be built from exact session_start_at derived from /status, not from legacy auth-file mtimes.
This is preferred over dd-mm-yyyy-hhmmss-... because:
- it sorts lexically and chronologically
- it matches the existing Gemini philosophy of timestamp-first naming
- it uses the actual quota anchor event: session start
Filename Contract
The archive filename must encode only:
session_start_atemail- product suffix
codex
The filename must not try to encode:
- inferred quota duration
- quota end detection time
- availability date separately
- source legacy filename
Those belong in metadata.
Metadata Contract
Each archive should have a sidecar metadata file with the same base name:
yyyy-mm-dd-hhmmss-email-codex.metadata.json
Example:
2026-04-14-155500-drdpsbose023@gmail.com-codex.metadata.json
Suggested schema:
{
"product": "codex",
"email": "drdpsbose023@gmail.com",
"session_start_at": "2026-04-14T15:55:00+05:30",
"next_available_at": "2026-04-21T15:55:00+05:30",
"reset_at": "2026-04-21T15:55:00+05:30",
"quota_end_detected_at": "2026-04-14T17:55:00+05:30",
"inferred_session_duration_seconds": 7200,
"inference_basis": "legacy filename day-month plus auth file mtime minus configured session duration",
"legacy_auth_filename": "21apr_drdpsbose023@gmail.com_auth.json",
"legacy_quota_day_token": "21apr",
"source_codex_home": "~/.codex",
"captured_files": [
"auth.json",
"history.jsonl",
"state_5.sqlite",
"sessions/"
],
"created_at": "2026-04-19T15:30:00+05:30",
"manager_version": "0.1.0"
}
Legacy Normalization Rules
Legacy auth files follow this rough pattern:
<day><mon>_<email>_auth.json
Example:
21apr_drdpsbose023@gmail.com_auth.json
Interpretation rule:
<day><mon>is the date when quota becomes available again- year is inferred from the current operating year unless explicitly overridden
- file mtime is treated as
quota_end_detected_at session_start_at = quota_end_detected_at - inferred_session_durationnext_available_at = session_start_at + 7 days
That means the legacy day token is a validation signal, not the primary timestamp we preserve.
Validation Rule During Normalization
When normalizing legacy data:
- parse the legacy token, for example
21apr - infer
session_start_at - compute
next_available_at - verify that
next_available_atfalls on the same calendar day as the legacy token
If the day does not match:
- keep the record
- mark it as
validation_status = "mismatch" - do not silently rewrite the evidence
Duration Inference
The 2-hour subtraction in your example should not be hardcoded into the filename logic.
It should be a configurable normalization parameter:
--session-duration-hours
Default for first-pass normalization:
2
Reason:
- old files do not appear to contain enough readable metadata to derive exact session start purely from content
- different accounts or future operating behavior may require a different duration assumption
Timezone Rule
Store full ISO timestamps with timezone in metadata.
For filenames:
- use local wall-clock time rendered as
YYYY-MM-DD-HHMMSS
This keeps filenames readable while metadata stays unambiguous.
What Gets Backed Up
Codex backups should represent account-usable state, not only auth snapshots.
Minimum snapshot set:
auth.json- account-specific auth snapshot copied into the archive manifest
config.tomlhistory.jsonlsessions/state_5.sqlite*logs_2.sqlite*models_cache.jsoninstallation_id- any other files required for a functioning restore after validation
Files or directories that are clearly ephemeral can be made optional:
tmp/.tmp/- transient caches
Backup Source Priority
When creating a new backup:
- query live Codex
/status - parse exact
emailand exactreset_at - derive
session_start_at = reset_at - 7 days - build archive name from that exact session start
- capture current
~/.codexstate
Legacy *_auth.json normalization remains useful for historical inventory and recovery, but should not be the primary source for naming new backups.
Proposed Commands
Mirror geminiai_cli at a high level:
codex-manager backupcodex-manager restorecodex-manager list-backupscodex-manager cooldowncodex-manager recommendcodex-manager normalizecodex-manager profilecodex-manager synccodex-manager prunecodex-manager doctorcodex-manager config
Command Responsibilities
normalize
Consumes legacy auth files and emits a normalized inventory.
Responsibilities:
- scan legacy
*_auth.jsonfiles - parse legacy day tokens and emails
- read file mtimes
- infer
session_start_at - compute
next_available_at - validate against the legacy quota-day token
- optionally create normalized archive names and metadata records
backup
Creates a Codex snapshot archive.
Responsibilities:
- read live status from Codex
/status - extract exact
emailand exactreset_at - derive exact
session_start_at = reset_at - 7 days - build archive base name from
session_start_atandemail - capture the Codex state set
- write
.tar.gz - write sidecar metadata json
- optionally upload to cloud later if desired
restore
Restores a selected archive back into the active Codex home.
Responsibilities:
- choose archive by filename or metadata
- validate archive contents
- restore atomically
- optionally preserve current state as a safety backup
cooldown
Shows current weekly availability.
Responsibilities:
- read normalized metadata records
- compute
next_available_at - show
readyvscooldown - display start time, detected end time, and next available time
recommend
Selects the best account to use next.
Priority:
- available now
- least recently used
- earliest next available if none are ready
Proposed Package Layout
Match the Gemini shape where practical:
src/codex_manager/
├── cli.py
├── args.py
├── config.py
├── backup.py
├── restore.py
├── normalize.py
├── inventory.py
├── cooldown.py
├── recommend.py
├── profile.py
├── sync.py
├── prune.py
├── doctor.py
├── metadata.py
├── utils.py
└── ui.py
Module Mapping From geminiai_cli
Direct parallels:
geminiai_cli.cli->codex_manager.cligeminiai_cli.args->codex_manager.argsgeminiai_cli.config->codex_manager.configgeminiai_cli.backup->codex_manager.backupgeminiai_cli.restore->codex_manager.restoregeminiai_cli.cooldown->codex_manager.cooldowngeminiai_cli.recommend->codex_manager.recommendgeminiai_cli.profile->codex_manager.profilegeminiai_cli.sync->codex_manager.syncgeminiai_cli.prune->codex_manager.prunegeminiai_cli.doctor->codex_manager.doctor
Codex-specific additions:
codex_manager.normalizecodex_manager.inventorycodex_manager.metadata
These are needed because the Codex side starts with a legacy auth-file naming problem that Gemini does not have.
Storage Layout
Suggested manager home:
~/.codexmgr/
Suggested subpaths:
~/.codex-manager/backups/~/.codex-manager/inventory.json~/.codex-manager/cooldown.json~/.codex-manager/profiles/~/.codex-manager/tmp/
Regex Contracts
Normalized archive filename:
^\d{4}-\d{2}-\d{2}-\d{6}-.+-codex\.tar\.gz$
Legacy auth filename:
^(?P<day>\d{1,2})(?P<month>[a-z]{3})_(?P<email>.+)_auth\.json$
Safety Rules
- never infer and overwrite original legacy files in place
- preserve the original filename in metadata
- keep normalization idempotent
- restore atomically where possible
- do not rely only on filenames once metadata exists
First Implementation Slice
Build in this order:
config.pynormalize.pymetadata.pycooldown.pyrecommend.pybackup.pyrestore.py- CLI wiring in
args.pyandcli.py
This order gives a working normalization and scheduling engine before archive creation and restore.
Immediate Next Task
Implement normalize first.
Output for phase 1 should be:
- parsed legacy account records
- inferred
session_start_at - computed
next_available_at - validation status against the legacy quota token
- proposed normalized archive basename
That gives a trustworthy inventory before touching live backup and restore flows.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file codex_manager-2.0.0.tar.gz.
File metadata
- Download URL: codex_manager-2.0.0.tar.gz
- Upload date:
- Size: 33.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22814e23c326443945484329ac85857f34fa5f992c8c7419d75c3fd1698d6993
|
|
| MD5 |
c4b247367cfed8b1ada838d709ae1a5c
|
|
| BLAKE2b-256 |
3d47b272db8c1d299b788b46c1371be67d275b0adcfd4fa9cbf1ffb27044096c
|
Provenance
The following attestation bundles were made for codex_manager-2.0.0.tar.gz:
Publisher:
publish.yml on dhruv13x/codex-manager
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
codex_manager-2.0.0.tar.gz -
Subject digest:
22814e23c326443945484329ac85857f34fa5f992c8c7419d75c3fd1698d6993 - Sigstore transparency entry: 1342317748
- Sigstore integration time:
-
Permalink:
dhruv13x/codex-manager@1b3736ceafd9d225a168e7c7cb91776d7711dd60 -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/dhruv13x
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1b3736ceafd9d225a168e7c7cb91776d7711dd60 -
Trigger Event:
push
-
Statement type:
File details
Details for the file codex_manager-2.0.0-py3-none-any.whl.
File metadata
- Download URL: codex_manager-2.0.0-py3-none-any.whl
- Upload date:
- Size: 26.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c27c566913aea18caa8a9d56cf47d718f5691bf636206d3ca52ba89a4e24328
|
|
| MD5 |
fb0bccc6f08b8ad6d992b71b4b63da05
|
|
| BLAKE2b-256 |
d5f87fc1f10dad804087612f049f83086b204e1de0161c71906fa77948961627
|
Provenance
The following attestation bundles were made for codex_manager-2.0.0-py3-none-any.whl:
Publisher:
publish.yml on dhruv13x/codex-manager
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
codex_manager-2.0.0-py3-none-any.whl -
Subject digest:
7c27c566913aea18caa8a9d56cf47d718f5691bf636206d3ca52ba89a4e24328 - Sigstore transparency entry: 1342317757
- Sigstore integration time:
-
Permalink:
dhruv13x/codex-manager@1b3736ceafd9d225a168e7c7cb91776d7711dd60 -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/dhruv13x
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1b3736ceafd9d225a168e7c7cb91776d7711dd60 -
Trigger Event:
push
-
Statement type: