codexhop 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ # Changelog
2
+
3
+ All notable changes to codexhop are listed here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [1.0.0] - 2026-11-02
8
+
9
+ The first release.
10
+
11
+ ### Added
12
+
13
+ - Hop the live Codex login between saved ChatGPT accounts with `chop <name>`,
14
+ or pick one from a menu with `chop`. API-key logins hop the same way.
15
+ - `chop add <name>` signs in with `codex login` in a private temporary Codex
16
+ home, so the live login is untouched while you sign in. Options after the name
17
+ go to `codex login`, such as `--device-auth`.
18
+ - `chop run <name>` runs `codex` as one account in one terminal, from a Codex
19
+ home that links to your real one for config, rules, skills, history and
20
+ sessions.
21
+ - `chop usage` reads the 5-hour and weekly usage of every saved account, and
22
+ `chop next` hops to another login in a list you give it that has room in its
23
+ 5-hour window, only when you run it.
24
+ - `chop renew` renews the saved logins whose access token runs out within a
25
+ day, a day ahead of when Codex would renew them.
26
+ - `chop doctor [--fix]` checks the Codex version, where Codex keeps its login,
27
+ file permissions, duplicate logins, logins due for renewal and leftover files,
28
+ and repairs an `auth.json` whose workspace id does not match its tokens.
29
+ - A login is identified by the email, user and workspace in its own ID token, so
30
+ listing, hopping and `whoami` need no network, and the bare `account_id` field
31
+ is never trusted on its own.
32
+ - A hop holds Codex's `auth.lock`, files the outgoing login under its account
33
+ first, and stops while an open session is about to renew the live login.
34
+ - `docs/experiments/session-follows-hop.py` measures what open sessions do after
35
+ a hop against real Codex binaries; the results for 0.160.1 and 0.166.0 are in
36
+ `docs/how-it-works.md`.
@@ -0,0 +1,83 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or advances of any kind
22
+ * Trolling, insulting or derogatory comments, and personal or political attacks
23
+ * Public or private harassment
24
+ * Publishing others' private information, such as a physical or email address, without their explicit permission
25
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
26
+
27
+ ## Enforcement Responsibilities
28
+
29
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
32
+
33
+ ## Scope
34
+
35
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
36
+
37
+ ## Enforcement
38
+
39
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at contact@ebenworks.co. All complaints will be reviewed and investigated promptly and fairly.
40
+
41
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
42
+
43
+ ## Enforcement Guidelines
44
+
45
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
46
+
47
+ ### 1. Correction
48
+
49
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
50
+
51
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
52
+
53
+ ### 2. Warning
54
+
55
+ **Community Impact**: A violation through a single incident or series of actions.
56
+
57
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
58
+
59
+ ### 3. Temporary Ban
60
+
61
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
62
+
63
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
64
+
65
+ ### 4. Permanent Ban
66
+
67
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
68
+
69
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
70
+
71
+ ## Attribution
72
+
73
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
74
+
75
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
76
+
77
+ For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations].
78
+
79
+ [homepage]: https://www.contributor-covenant.org
80
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
81
+ [Mozilla CoC]: https://github.com/mozilla/diversity
82
+ [FAQ]: https://www.contributor-covenant.org/faq
83
+ [translations]: https://www.contributor-covenant.org/translations
@@ -0,0 +1,57 @@
1
+ # Contributing
2
+
3
+ Thanks for looking. codexhop is small on purpose, and a few rules keep it that
4
+ way. A pull request that follows them is usually merged quickly.
5
+
6
+ ## The rules that keep it small
7
+
8
+ 1. **Python 3.9+, standard library only.** No dependencies and no build step.
9
+ `codexhop.py` stays a single file you can read in one sitting and run
10
+ straight from a clone. `pyproject.toml` packages that one module and nothing
11
+ else.
12
+ 2. **Never lose a login.** Any code path that replaces the live login first
13
+ files what was there under the account it belongs to, by its token claims;
14
+ one with no saved account yet is stashed under its email. Codex treats a used
15
+ refresh token as spent, so a renewed login is written to disk before anything
16
+ else happens, and a login that a running Codex holds is renewed only by that
17
+ Codex.
18
+ 3. **Tests use fake logins and no network.** `test/test_codexhop.py` runs the
19
+ real command against a throwaway `CODEX_HOME`, with unsigned made-up tokens,
20
+ a local fake token and usage server, and a stand-in `codex` script. A test
21
+ that needs a real account is not a test we can run.
22
+ 4. **Say what you measured.** A claim about how Codex behaves names the Codex
23
+ version it was checked on and how. The ones in the docs come from
24
+ `docs/experiments/session-follows-hop.py`, which runs a real Codex binary
25
+ against a local fake backend with the network cut off (`unshare -rn` on
26
+ Linux).
27
+ 5. **Tokens never get printed.** Not in `--json`, not in errors, not in a cache
28
+ file, not in a test's failure message.
29
+
30
+ ## Working on it
31
+
32
+ ```bash
33
+ python3 -m unittest discover -s test # the whole suite, about 15 seconds
34
+ TEST_PYTHON=python3.9 python3.9 -m unittest discover -s test # the oldest supported Python
35
+ ruff check codexhop.py test/ docs/experiments/
36
+ shellcheck -S warning install.sh
37
+ ```
38
+
39
+ `./install.sh` links `~/.local/bin/codexhop` to your clone, so your edits take
40
+ effect at once. CI runs the suite on Linux and macOS with Python 3.9 and 3.13,
41
+ builds and installs the package, and checks the installer.
42
+
43
+ ## Things worth doing
44
+
45
+ - macOS on real hardware. CI runs the tests on macOS, where finding running
46
+ `codex` processes falls back to `pgrep`, which cannot see which Codex home
47
+ each one uses. Driving a run session on a Mac and reporting what happens is
48
+ the next step.
49
+ - The keyring store. Codex can keep its login in the system keyring instead of
50
+ `auth.json`; codexhop refuses that today. Supporting it means reading and
51
+ writing the `Codex Auth` item per Codex home.
52
+ - fish shell completion. The shell glue covers bash and zsh.
53
+
54
+ ## Style
55
+
56
+ Match the code around you: plain names, comments that say why, and messages a
57
+ person can act on without reading the source.
codexhop-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ebenworks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ # The wheel is one module. The sdist also carries the repo installer, the docs
2
+ # (with the experiment that measured what open sessions do) and the tests.
3
+ include LICENSE CHANGELOG.md CONTRIBUTING.md SECURITY.md SUPPORT.md CODE_OF_CONDUCT.md install.sh
4
+ recursive-include docs *
5
+ include test/test_codexhop.py
6
+ global-exclude __pycache__ *.py[cod]
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.4
2
+ Name: codexhop
3
+ Version: 1.0.0
4
+ Summary: Use several ChatGPT accounts with OpenAI Codex on one machine: hop the saved login in one command, or run a different account in each terminal. One file, no dependencies.
5
+ Author-email: Ebenworks <contact@ebenworks.co>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/psychofict/codexhop
8
+ Project-URL: Repository, https://github.com/psychofict/codexhop
9
+ Project-URL: Documentation, https://github.com/psychofict/codexhop#readme
10
+ Project-URL: Changelog, https://github.com/psychofict/codexhop/blob/main/CHANGELOG.md
11
+ Project-URL: Security policy, https://github.com/psychofict/codexhop/blob/main/SECURITY.md
12
+ Project-URL: Issues, https://github.com/psychofict/codexhop/issues
13
+ Project-URL: Author, https://ebenworks.co/
14
+ Keywords: codex,openai-codex,codex-cli,chatgpt,account-switcher,multi-account,chatgpt-plus,chatgpt-pro,chatgpt-business,oauth,credentials,cli,developer-tools,productivity,shell,terminal,ai,llm
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Environment :: Console
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Operating System :: MacOS :: MacOS X
19
+ Classifier: Operating System :: POSIX :: Linux
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3 :: Only
22
+ Classifier: Programming Language :: Python :: 3.9
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Topic :: System :: Systems Administration :: Authentication/Directory
28
+ Classifier: Topic :: Terminals
29
+ Classifier: Topic :: Utilities
30
+ Requires-Python: >=3.9
31
+ Description-Content-Type: text/markdown
32
+ License-File: LICENSE
33
+ Dynamic: license-file
34
+
35
+ <p align="center">
36
+ <img src="https://raw.githubusercontent.com/psychofict/codexhop/main/assets/cover.png" alt="codexhop: hop OpenAI Codex between ChatGPT accounts" width="820">
37
+ </p>
38
+
39
+ <p align="center">
40
+ <a href="https://github.com/psychofict/codexhop/actions/workflows/ci.yml"><img src="https://github.com/psychofict/codexhop/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
41
+ <a href="https://github.com/psychofict/codexhop/blob/main/LICENSE"><img src="https://img.shields.io/badge/licence-MIT-FC5F00" alt="MIT licence"></a>
42
+ <img src="https://img.shields.io/badge/python-3.9%2B-FC5F00" alt="Python 3.9 or newer">
43
+ <img src="https://img.shields.io/badge/dependencies-none-FC5F00" alt="No dependencies">
44
+ </p>
45
+
46
+ codexhop lets you use several ChatGPT accounts with OpenAI Codex on one machine,
47
+ such as a personal plan and a seat in your company's workspace. It saves each
48
+ account's Codex login, swaps the live one in one command, and can run a
49
+ different account in each terminal.
50
+
51
+ The whole tool is one Python file with no dependencies. A browser opens only
52
+ when you add an account.
53
+
54
+ ```
55
+ $ chop
56
+ NAME EMAIL PLAN 5H USED
57
+ 1. home me@gmail.com plus 4%
58
+ 2. * work me@company.com business 62%
59
+
60
+ hop to which? [1-2, Enter to stay] 1
61
+ switched to home (me@gmail.com, plus)
62
+ new `codex` sessions start as this account.
63
+ ```
64
+
65
+ `chop` is the short name the shell glue gives `codexhop`. The 5H USED column is
66
+ the last reading `chop usage` saved, so the menu comes up at once.
67
+
68
+ ## Install
69
+
70
+ ```bash
71
+ pipx install codexhop # or: pip install --user codexhop
72
+ eval "$(codexhop shell-init)" # the `chop` alias and tab completion
73
+ ```
74
+
75
+ Put the `eval` line in your `~/.bashrc` or `~/.zshrc` and open a new terminal.
76
+ It needs Python 3.9 or newer and Codex, on Linux or macOS. For the newest code
77
+ from GitHub instead, use `pipx install git+https://github.com/psychofict/codexhop`.
78
+
79
+ To install from a clone instead, run `./install.sh`. It links
80
+ `~/.local/bin/codexhop` to the clone and adds the same line to your shell rc. If
81
+ `chop` is taken on your machine, `codexhop shell-init --alias NAME` picks
82
+ another name.
83
+
84
+ Then save the login you already have, and add the others:
85
+
86
+ ```bash
87
+ chop save home # names whatever is logged in right now
88
+ chop add work # signs in as a second account, aside from the live one
89
+ ```
90
+
91
+ `chop add` runs `codex login` in a private temporary Codex home, so your live
92
+ login is untouched while you sign in. If your browser is signed in to ChatGPT as
93
+ another account, that is the one you get. Open the link in a private window, or
94
+ use `chop add work --device-auth`.
95
+
96
+ ## Commands
97
+
98
+ ```bash
99
+ chop work # new codex sessions start as work
100
+ chop run home # codex as home in this terminal only; arguments after the name go to codex
101
+ chop usage # 5-hour and weekly usage for every account
102
+ chop next home work # hop to whichever of the others has room in its 5-hour window
103
+ ```
104
+
105
+ | Command | What it does |
106
+ |---|---|
107
+ | `chop` | list the accounts and ask which one to hop to |
108
+ | `chop <name>` | hop to that account |
109
+ | `chop add <name>` | sign in as another account and save it |
110
+ | `chop save [name]` | save the login you have now |
111
+ | `chop run <name> [...]` | run `codex` as that account in this terminal only |
112
+ | `chop usage [name]` | 5-hour and weekly usage, with reset times |
113
+ | `chop next [names]` | hop to another login in the list that has 5-hour room ([how it picks](https://github.com/psychofict/codexhop/blob/main/docs/commands.md#chop-next-names)) |
114
+ | `chop whoami` | who the live login is, read from the login itself |
115
+ | `chop list --long` | token expiry, last renewal and save date per account |
116
+ | `chop renew [name]` | renew the saved logins that are due |
117
+ | `chop doctor [--fix]` | check the setup and repair what it can |
118
+ | `chop rm`, `chop rename` | delete or rename a saved account |
119
+
120
+ The [command reference](https://github.com/psychofict/codexhop/blob/main/docs/commands.md)
121
+ covers every command, flag, setting, file and exit status.
122
+
123
+ ### One account per terminal
124
+
125
+ `chop run work` starts `codex` as `work` in this terminal, while every other
126
+ terminal keeps the live login.
127
+
128
+ The session gets its own Codex home. That home holds the account's login and
129
+ links to everything else in yours, so the session has your config, rules,
130
+ skills and history, and `codex resume` sees the same conversations. When the
131
+ session ends, a login it renewed is saved back.
132
+
133
+ ### Usage for every account
134
+
135
+ ```
136
+ $ chop usage
137
+ NAME 5 HOURS WEEK NOTE
138
+ * home 4% resets 3h19m 18% resets 23h59m
139
+ work 62% resets 2h09m 41% resets 23h59m
140
+ ```
141
+
142
+ The figures come from the endpoint Codex reads an account's rate limits from. A
143
+ reading under
144
+ a minute old is shown again without asking, and a server that asks for a pause
145
+ is not asked again until the pause is over.
146
+
147
+ An idle account whose access token has run out is renewed first, so every
148
+ account can be read, not only the live one.
149
+
150
+ ## What happens to sessions that are already open
151
+
152
+ A hop changes the login new `codex` sessions start with. A session that is
153
+ already open keeps the login it started with until that login's access token is
154
+ within 5 minutes of running out, about 10 days after its last renewal. Then it
155
+ stops with "signed in to another account. Please sign in again."
156
+
157
+ The exception is two logins in one workspace: there the open session moves to
158
+ the new login at that point.
159
+
160
+ This was measured with Codex 0.160.1 and 0.166.0, and
161
+ [How it works](https://github.com/psychofict/codexhop/blob/main/docs/how-it-works.md#what-open-sessions-do)
162
+ has the cases and the script. The hop tells you how long the open sessions have.
163
+ Start a new session to move over; `codex resume` reopens the conversation in it.
164
+
165
+ When a session is about to renew the live login, the hop stops and says so. A
166
+ hop that lands during that renewal can cost the account its login, because
167
+ Codex 0.166.0 drops the renewed tokens and 0.160.1 saves them under the new
168
+ account's workspace id. Let the session make its next request first, or pass
169
+ `--yes`.
170
+
171
+ ## How it works
172
+
173
+ Codex keeps its login in `~/.codex/auth.json`. codexhop keeps one copy of that
174
+ file per account in `~/.codex/codexhop/accounts/`, mode 600, and copies the one
175
+ you want into place.
176
+
177
+ Which account a login belongs to is read from the login's own ID token (email,
178
+ ChatGPT user and workspace), so listing, hopping and `whoami` need no network.
179
+ During the swap codexhop holds `auth.lock`, the lock Codex 0.166.0 takes around
180
+ its own writes. The outgoing login is filed under the right account first, so a
181
+ renewal Codex has already saved is never overwritten.
182
+
183
+ [How it works](https://github.com/psychofict/codexhop/blob/main/docs/how-it-works.md)
184
+ goes through it step by step.
185
+
186
+ ## Before you hop
187
+
188
+ - Codex can keep its login in the system keyring instead of `auth.json`. The
189
+ file is the default; if yours is set to `keyring` or `auto`, codexhop says how
190
+ to switch back.
191
+ - Codex before 0.164.0 does not check, when it saves a renewal, that
192
+ `auth.json` still holds the same login (the check first appears in Codex's
193
+ source at rust-v0.164.0). `chop doctor` warns about it, and
194
+ `chop doctor --fix` repairs a file that got mixed up. Upgrading Codex closes
195
+ the gap.
196
+ - `CODEX_ACCESS_TOKEN`, and `CODEX_API_KEY` in `codex exec`, take the place of
197
+ the saved login. `chop whoami` and `chop doctor` warn when either is set.
198
+ - codexhop changes nothing about what each account may do. Use each one within
199
+ OpenAI's terms of use.
200
+
201
+ ## FAQ
202
+
203
+ **Does codexhop send my login anywhere?** Only to OpenAI, and only to renew it
204
+ (`auth.openai.com`) or to read usage (`chatgpt.com`), when a command needs to.
205
+ `CODEXHOP_OFFLINE=1` turns both off.
206
+ [SECURITY.md](https://github.com/psychofict/codexhop/blob/main/SECURITY.md)
207
+ lists what the tool holds and how it protects it.
208
+
209
+ **Can I hop between a ChatGPT login and an API key?** Yes. `chop add work
210
+ --with-api-key` reads the key from standard input, and the result hops like any
211
+ other account.
212
+
213
+ **Does it switch accounts by itself when one runs out?** No. `chop next` hops
214
+ to another login with room in its 5-hour window, but only when you run it.
215
+
216
+ **Two accounts with the same email?** One email in two ChatGPT workspaces is two
217
+ logins, and codexhop keeps them apart. `chop list` adds a WORKSPACE column when
218
+ that happens.
219
+
220
+ **Windows?** Windows is not supported. codexhop runs on Linux and macOS.
221
+
222
+ ## Contributing and licence
223
+
224
+ Issues and pull requests are welcome. Start with
225
+ [CONTRIBUTING.md](https://github.com/psychofict/codexhop/blob/main/CONTRIBUTING.md),
226
+ and report anything that could expose a login through
227
+ [SECURITY.md](https://github.com/psychofict/codexhop/blob/main/SECURITY.md).
228
+
229
+ codexhop is built by [Ebenworks](https://ebenworks.co/), which also makes
230
+ [claudehop](https://github.com/psychofict/claudehop) for Claude Code.
231
+
232
+ MIT licence. Not affiliated with, endorsed by, or sponsored by OpenAI. "OpenAI",
233
+ "Codex" and "ChatGPT" are trademarks of OpenAI, used here only to say what this
234
+ works with.
@@ -0,0 +1,200 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/psychofict/codexhop/main/assets/cover.png" alt="codexhop: hop OpenAI Codex between ChatGPT accounts" width="820">
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://github.com/psychofict/codexhop/actions/workflows/ci.yml"><img src="https://github.com/psychofict/codexhop/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
+ <a href="https://github.com/psychofict/codexhop/blob/main/LICENSE"><img src="https://img.shields.io/badge/licence-MIT-FC5F00" alt="MIT licence"></a>
8
+ <img src="https://img.shields.io/badge/python-3.9%2B-FC5F00" alt="Python 3.9 or newer">
9
+ <img src="https://img.shields.io/badge/dependencies-none-FC5F00" alt="No dependencies">
10
+ </p>
11
+
12
+ codexhop lets you use several ChatGPT accounts with OpenAI Codex on one machine,
13
+ such as a personal plan and a seat in your company's workspace. It saves each
14
+ account's Codex login, swaps the live one in one command, and can run a
15
+ different account in each terminal.
16
+
17
+ The whole tool is one Python file with no dependencies. A browser opens only
18
+ when you add an account.
19
+
20
+ ```
21
+ $ chop
22
+ NAME EMAIL PLAN 5H USED
23
+ 1. home me@gmail.com plus 4%
24
+ 2. * work me@company.com business 62%
25
+
26
+ hop to which? [1-2, Enter to stay] 1
27
+ switched to home (me@gmail.com, plus)
28
+ new `codex` sessions start as this account.
29
+ ```
30
+
31
+ `chop` is the short name the shell glue gives `codexhop`. The 5H USED column is
32
+ the last reading `chop usage` saved, so the menu comes up at once.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pipx install codexhop # or: pip install --user codexhop
38
+ eval "$(codexhop shell-init)" # the `chop` alias and tab completion
39
+ ```
40
+
41
+ Put the `eval` line in your `~/.bashrc` or `~/.zshrc` and open a new terminal.
42
+ It needs Python 3.9 or newer and Codex, on Linux or macOS. For the newest code
43
+ from GitHub instead, use `pipx install git+https://github.com/psychofict/codexhop`.
44
+
45
+ To install from a clone instead, run `./install.sh`. It links
46
+ `~/.local/bin/codexhop` to the clone and adds the same line to your shell rc. If
47
+ `chop` is taken on your machine, `codexhop shell-init --alias NAME` picks
48
+ another name.
49
+
50
+ Then save the login you already have, and add the others:
51
+
52
+ ```bash
53
+ chop save home # names whatever is logged in right now
54
+ chop add work # signs in as a second account, aside from the live one
55
+ ```
56
+
57
+ `chop add` runs `codex login` in a private temporary Codex home, so your live
58
+ login is untouched while you sign in. If your browser is signed in to ChatGPT as
59
+ another account, that is the one you get. Open the link in a private window, or
60
+ use `chop add work --device-auth`.
61
+
62
+ ## Commands
63
+
64
+ ```bash
65
+ chop work # new codex sessions start as work
66
+ chop run home # codex as home in this terminal only; arguments after the name go to codex
67
+ chop usage # 5-hour and weekly usage for every account
68
+ chop next home work # hop to whichever of the others has room in its 5-hour window
69
+ ```
70
+
71
+ | Command | What it does |
72
+ |---|---|
73
+ | `chop` | list the accounts and ask which one to hop to |
74
+ | `chop <name>` | hop to that account |
75
+ | `chop add <name>` | sign in as another account and save it |
76
+ | `chop save [name]` | save the login you have now |
77
+ | `chop run <name> [...]` | run `codex` as that account in this terminal only |
78
+ | `chop usage [name]` | 5-hour and weekly usage, with reset times |
79
+ | `chop next [names]` | hop to another login in the list that has 5-hour room ([how it picks](https://github.com/psychofict/codexhop/blob/main/docs/commands.md#chop-next-names)) |
80
+ | `chop whoami` | who the live login is, read from the login itself |
81
+ | `chop list --long` | token expiry, last renewal and save date per account |
82
+ | `chop renew [name]` | renew the saved logins that are due |
83
+ | `chop doctor [--fix]` | check the setup and repair what it can |
84
+ | `chop rm`, `chop rename` | delete or rename a saved account |
85
+
86
+ The [command reference](https://github.com/psychofict/codexhop/blob/main/docs/commands.md)
87
+ covers every command, flag, setting, file and exit status.
88
+
89
+ ### One account per terminal
90
+
91
+ `chop run work` starts `codex` as `work` in this terminal, while every other
92
+ terminal keeps the live login.
93
+
94
+ The session gets its own Codex home. That home holds the account's login and
95
+ links to everything else in yours, so the session has your config, rules,
96
+ skills and history, and `codex resume` sees the same conversations. When the
97
+ session ends, a login it renewed is saved back.
98
+
99
+ ### Usage for every account
100
+
101
+ ```
102
+ $ chop usage
103
+ NAME 5 HOURS WEEK NOTE
104
+ * home 4% resets 3h19m 18% resets 23h59m
105
+ work 62% resets 2h09m 41% resets 23h59m
106
+ ```
107
+
108
+ The figures come from the endpoint Codex reads an account's rate limits from. A
109
+ reading under
110
+ a minute old is shown again without asking, and a server that asks for a pause
111
+ is not asked again until the pause is over.
112
+
113
+ An idle account whose access token has run out is renewed first, so every
114
+ account can be read, not only the live one.
115
+
116
+ ## What happens to sessions that are already open
117
+
118
+ A hop changes the login new `codex` sessions start with. A session that is
119
+ already open keeps the login it started with until that login's access token is
120
+ within 5 minutes of running out, about 10 days after its last renewal. Then it
121
+ stops with "signed in to another account. Please sign in again."
122
+
123
+ The exception is two logins in one workspace: there the open session moves to
124
+ the new login at that point.
125
+
126
+ This was measured with Codex 0.160.1 and 0.166.0, and
127
+ [How it works](https://github.com/psychofict/codexhop/blob/main/docs/how-it-works.md#what-open-sessions-do)
128
+ has the cases and the script. The hop tells you how long the open sessions have.
129
+ Start a new session to move over; `codex resume` reopens the conversation in it.
130
+
131
+ When a session is about to renew the live login, the hop stops and says so. A
132
+ hop that lands during that renewal can cost the account its login, because
133
+ Codex 0.166.0 drops the renewed tokens and 0.160.1 saves them under the new
134
+ account's workspace id. Let the session make its next request first, or pass
135
+ `--yes`.
136
+
137
+ ## How it works
138
+
139
+ Codex keeps its login in `~/.codex/auth.json`. codexhop keeps one copy of that
140
+ file per account in `~/.codex/codexhop/accounts/`, mode 600, and copies the one
141
+ you want into place.
142
+
143
+ Which account a login belongs to is read from the login's own ID token (email,
144
+ ChatGPT user and workspace), so listing, hopping and `whoami` need no network.
145
+ During the swap codexhop holds `auth.lock`, the lock Codex 0.166.0 takes around
146
+ its own writes. The outgoing login is filed under the right account first, so a
147
+ renewal Codex has already saved is never overwritten.
148
+
149
+ [How it works](https://github.com/psychofict/codexhop/blob/main/docs/how-it-works.md)
150
+ goes through it step by step.
151
+
152
+ ## Before you hop
153
+
154
+ - Codex can keep its login in the system keyring instead of `auth.json`. The
155
+ file is the default; if yours is set to `keyring` or `auto`, codexhop says how
156
+ to switch back.
157
+ - Codex before 0.164.0 does not check, when it saves a renewal, that
158
+ `auth.json` still holds the same login (the check first appears in Codex's
159
+ source at rust-v0.164.0). `chop doctor` warns about it, and
160
+ `chop doctor --fix` repairs a file that got mixed up. Upgrading Codex closes
161
+ the gap.
162
+ - `CODEX_ACCESS_TOKEN`, and `CODEX_API_KEY` in `codex exec`, take the place of
163
+ the saved login. `chop whoami` and `chop doctor` warn when either is set.
164
+ - codexhop changes nothing about what each account may do. Use each one within
165
+ OpenAI's terms of use.
166
+
167
+ ## FAQ
168
+
169
+ **Does codexhop send my login anywhere?** Only to OpenAI, and only to renew it
170
+ (`auth.openai.com`) or to read usage (`chatgpt.com`), when a command needs to.
171
+ `CODEXHOP_OFFLINE=1` turns both off.
172
+ [SECURITY.md](https://github.com/psychofict/codexhop/blob/main/SECURITY.md)
173
+ lists what the tool holds and how it protects it.
174
+
175
+ **Can I hop between a ChatGPT login and an API key?** Yes. `chop add work
176
+ --with-api-key` reads the key from standard input, and the result hops like any
177
+ other account.
178
+
179
+ **Does it switch accounts by itself when one runs out?** No. `chop next` hops
180
+ to another login with room in its 5-hour window, but only when you run it.
181
+
182
+ **Two accounts with the same email?** One email in two ChatGPT workspaces is two
183
+ logins, and codexhop keeps them apart. `chop list` adds a WORKSPACE column when
184
+ that happens.
185
+
186
+ **Windows?** Windows is not supported. codexhop runs on Linux and macOS.
187
+
188
+ ## Contributing and licence
189
+
190
+ Issues and pull requests are welcome. Start with
191
+ [CONTRIBUTING.md](https://github.com/psychofict/codexhop/blob/main/CONTRIBUTING.md),
192
+ and report anything that could expose a login through
193
+ [SECURITY.md](https://github.com/psychofict/codexhop/blob/main/SECURITY.md).
194
+
195
+ codexhop is built by [Ebenworks](https://ebenworks.co/), which also makes
196
+ [claudehop](https://github.com/psychofict/claudehop) for Claude Code.
197
+
198
+ MIT licence. Not affiliated with, endorsed by, or sponsored by OpenAI. "OpenAI",
199
+ "Codex" and "ChatGPT" are trademarks of OpenAI, used here only to say what this
200
+ works with.