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.
- codexhop-1.0.0/CHANGELOG.md +36 -0
- codexhop-1.0.0/CODE_OF_CONDUCT.md +83 -0
- codexhop-1.0.0/CONTRIBUTING.md +57 -0
- codexhop-1.0.0/LICENSE +21 -0
- codexhop-1.0.0/MANIFEST.in +6 -0
- codexhop-1.0.0/PKG-INFO +234 -0
- codexhop-1.0.0/README.md +200 -0
- codexhop-1.0.0/SECURITY.md +71 -0
- codexhop-1.0.0/SUPPORT.md +10 -0
- codexhop-1.0.0/codexhop.egg-info/PKG-INFO +234 -0
- codexhop-1.0.0/codexhop.egg-info/SOURCES.txt +21 -0
- codexhop-1.0.0/codexhop.egg-info/dependency_links.txt +1 -0
- codexhop-1.0.0/codexhop.egg-info/entry_points.txt +2 -0
- codexhop-1.0.0/codexhop.egg-info/top_level.txt +1 -0
- codexhop-1.0.0/codexhop.py +2484 -0
- codexhop-1.0.0/docs/commands.md +230 -0
- codexhop-1.0.0/docs/experiments/results-2026-11-02.txt +145 -0
- codexhop-1.0.0/docs/experiments/session-follows-hop.py +351 -0
- codexhop-1.0.0/docs/how-it-works.md +178 -0
- codexhop-1.0.0/install.sh +106 -0
- codexhop-1.0.0/pyproject.toml +61 -0
- codexhop-1.0.0/setup.cfg +4 -0
- codexhop-1.0.0/test/test_codexhop.py +878 -0
|
@@ -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]
|
codexhop-1.0.0/PKG-INFO
ADDED
|
@@ -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.
|
codexhop-1.0.0/README.md
ADDED
|
@@ -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.
|