ai-auth-switch 0.2.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.
- ai_auth_switch-0.2.0/LICENSE +21 -0
- ai_auth_switch-0.2.0/PKG-INFO +299 -0
- ai_auth_switch-0.2.0/README.md +278 -0
- ai_auth_switch-0.2.0/ai_auth_switch/__init__.py +3 -0
- ai_auth_switch-0.2.0/ai_auth_switch/cli.py +908 -0
- ai_auth_switch-0.2.0/ai_auth_switch/errors.py +2 -0
- ai_auth_switch-0.2.0/ai_auth_switch/providers/__init__.py +18 -0
- ai_auth_switch-0.2.0/ai_auth_switch/providers/base.py +25 -0
- ai_auth_switch-0.2.0/ai_auth_switch/providers/codex.py +177 -0
- ai_auth_switch-0.2.0/ai_auth_switch/store.py +686 -0
- ai_auth_switch-0.2.0/ai_auth_switch/sync.py +894 -0
- ai_auth_switch-0.2.0/ai_auth_switch/usage.py +303 -0
- ai_auth_switch-0.2.0/ai_auth_switch/wrapper.py +201 -0
- ai_auth_switch-0.2.0/ai_auth_switch.egg-info/PKG-INFO +299 -0
- ai_auth_switch-0.2.0/ai_auth_switch.egg-info/SOURCES.txt +21 -0
- ai_auth_switch-0.2.0/ai_auth_switch.egg-info/dependency_links.txt +1 -0
- ai_auth_switch-0.2.0/ai_auth_switch.egg-info/entry_points.txt +3 -0
- ai_auth_switch-0.2.0/ai_auth_switch.egg-info/top_level.txt +1 -0
- ai_auth_switch-0.2.0/setup.cfg +38 -0
- ai_auth_switch-0.2.0/setup.py +4 -0
- ai_auth_switch-0.2.0/tests/test_codex_store.py +1438 -0
- ai_auth_switch-0.2.0/tests/test_usage.py +218 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lixtt
|
|
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,299 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ai-auth-switch
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Switch auth profiles for AI coding agents while keeping app config and history shared.
|
|
5
|
+
Home-page: https://github.com/Lixtt/ai-auth-switch
|
|
6
|
+
Author: Lixtt
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Repository, https://github.com/Lixtt/ai-auth-switch.git
|
|
9
|
+
Keywords: codex,auth,cli,ai-agent
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Topic :: Utilities
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# ai-auth-switch
|
|
23
|
+
|
|
24
|
+
Switch auth profiles for AI coding agents while keeping the app's normal
|
|
25
|
+
configuration, history, sessions, and cache layout unchanged.
|
|
26
|
+
|
|
27
|
+
The first provider is Codex. The design keeps Codex itself as the source of
|
|
28
|
+
truth for everything except the active auth file:
|
|
29
|
+
|
|
30
|
+
- `~/.codex/config.toml` is not rewritten.
|
|
31
|
+
- `~/.codex/history.jsonl`, `sessions/`, `skills/`, and other Codex state stay in place.
|
|
32
|
+
- Permanent profile changes switch only `auth.json`.
|
|
33
|
+
- Profile-scoped runs isolate `auth.json` in a temporary `CODEX_HOME` while
|
|
34
|
+
sharing the normal Codex configuration and state.
|
|
35
|
+
- Saved profiles live outside Codex under `~/.local/share/ai-auth-switch/`.
|
|
36
|
+
- Hermes and OpenClaw Codex-dependent auth state is synchronized after Codex
|
|
37
|
+
auth changes.
|
|
38
|
+
|
|
39
|
+
## Install From Checkout
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
python -m pip install -e .
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Python 3.10 or newer is required.
|
|
46
|
+
|
|
47
|
+
You can also run without installation:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
./bin/ai-auth-switch --help
|
|
51
|
+
./bin/ais --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`ais` is the short command name for `ai-auth-switch`; both accept exactly the
|
|
55
|
+
same arguments. Examples below use the long name for clarity.
|
|
56
|
+
|
|
57
|
+
If the checkout and home directory are shared by multiple machines but
|
|
58
|
+
`/usr/local` is machine-local, install the shared launcher on `PATH` instead:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
mkdir -p ~/.local/bin
|
|
62
|
+
ln -sfn "$PWD/bin/ai-auth-switch" ~/.local/bin/ai-auth-switch
|
|
63
|
+
hash -r
|
|
64
|
+
ai-auth-switch alias sync codex
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Codex Usage
|
|
68
|
+
|
|
69
|
+
Save the currently active Codex login:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
ai-auth-switch auth save codex
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The profile name is inferred from the email inside the Codex OAuth token when
|
|
76
|
+
available. If the token does not expose an email, the fallback is
|
|
77
|
+
`chatgpt-<account-id-prefix>`.
|
|
78
|
+
|
|
79
|
+
Login a new Codex account and save it:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
ai-auth-switch auth login codex
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Optionally force a profile name:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ai-auth-switch auth login codex work
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
List and switch profiles:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
ai-auth-switch auth list
|
|
95
|
+
ai-auth-switch auth list codex
|
|
96
|
+
ai-auth-switch auth list codex --usage
|
|
97
|
+
ai-auth-switch auth use codex someone@example.com
|
|
98
|
+
ai-auth-switch auth current codex
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Add `--usage` to query every saved Codex account's current rate-limit windows
|
|
102
|
+
in parallel. Each request uses that profile's own access token and explicit
|
|
103
|
+
ChatGPT account ID, so limits cannot be accidentally attributed to another
|
|
104
|
+
saved account. The normal list remains local and instant; usage lookup is
|
|
105
|
+
opt-in because it requires network access and may report an expired login.
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
* someone@example.com [codex1] (plus, 5h 72% left, 168h 41% left)
|
|
109
|
+
other@example.com [codex2] (team, 5h 18% left, 168h 83% left)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Results are cached for 60 seconds. Use `--refresh-usage` to bypass the cache,
|
|
113
|
+
`--usage-cache-ttl` to tune it, `--usage-timeout` for slow networks, and
|
|
114
|
+
`--usage-workers` to limit concurrency. A failure for one account is shown
|
|
115
|
+
inline without hiding results for the other accounts. The command deliberately
|
|
116
|
+
does not refresh expired OAuth tokens; run that profile through Codex or log in
|
|
117
|
+
again so rotating credentials remain coordinated safely.
|
|
118
|
+
|
|
119
|
+
For status bars, monitoring, or account schedulers, add `--json`. The JSON
|
|
120
|
+
contains profile identity, active/alias state, and structured usage windows
|
|
121
|
+
when `--usage` is also present:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
ai-auth-switch auth list codex --usage --json
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
After Codex auth is saved, logged in, or switched, `ai-auth-switch` also syncs
|
|
128
|
+
Codex-dependent local tools:
|
|
129
|
+
|
|
130
|
+
- Hermes is pointed at `openai-codex` and seeded with a Codex CLI access-token
|
|
131
|
+
pool entry, so it follows the active Codex CLI account without handing turns
|
|
132
|
+
to `codex app-server`. If `hermes-gateway.service` is active, it is restarted
|
|
133
|
+
so Feishu and other messaging channels pick up the new auth immediately.
|
|
134
|
+
- Current OpenClaw installs are synchronized through the SQLite auth store by
|
|
135
|
+
writing `openai:default` from the active Codex CLI OAuth token. Older JSON
|
|
136
|
+
auth-state installs still use the legacy `openai-codex:default` bridge.
|
|
137
|
+
|
|
138
|
+
You can run that step explicitly too:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
ai-auth-switch auth sync codex
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Hermes does not import or share the Codex CLI refresh token. The sync clears
|
|
145
|
+
Hermes's old independent `openai-codex` OAuth state, installs the current Codex
|
|
146
|
+
CLI access token into Hermes's `openai-codex` credential pool, and leaves
|
|
147
|
+
Hermes's `openai_runtime` on `auto`. Current OpenClaw versions no longer import
|
|
148
|
+
Codex CLI auth from `~/.codex` at runtime, so the sync writes the active Codex
|
|
149
|
+
OAuth tokens into OpenClaw's own SQLite auth store as `openai:default` and
|
|
150
|
+
clears any failure cooldown for that profile. Older OpenClaw JSON auth-state
|
|
151
|
+
installs still fall back to the legacy `openai-codex:default` bridge profile.
|
|
152
|
+
|
|
153
|
+
The old Hermes login flag is kept only for command compatibility and is now a
|
|
154
|
+
no-op:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
ai-auth-switch auth sync codex --hermes-login
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Use `ai-auth-switch auth sync codex` normally. Before restarting active gateway
|
|
161
|
+
services, the current process's standard proxy variables (`http_proxy`,
|
|
162
|
+
`https_proxy`, and their uppercase variants) are imported into the systemd user
|
|
163
|
+
manager, so Hermes/OpenClaw do not need a hard-coded proxy env file. To leave a
|
|
164
|
+
running Hermes gateway untouched during an explicit sync, pass
|
|
165
|
+
`--no-hermes-restart`.
|
|
166
|
+
|
|
167
|
+
If Codex reports that a refresh token was already used after switching
|
|
168
|
+
profiles, that profile's stored refresh token has already been invalidated by
|
|
169
|
+
the server. Log in to that Codex account again and save it back into the same
|
|
170
|
+
profile name:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
ai-auth-switch auth login codex <profile>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Recent versions sync Codex's atomically replaced `auth.json` back into the
|
|
177
|
+
managed profile before switching away, which prevents reactivating a stale
|
|
178
|
+
refresh token after Codex refreshes it.
|
|
179
|
+
|
|
180
|
+
On a fresh install, `auth list` can be empty even when Codex is already logged
|
|
181
|
+
in. Import the active Codex auth first:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
ai-auth-switch auth save codex
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
If you run as another Unix user, make sure `CODEX_HOME` points at the Codex
|
|
188
|
+
config directory you actually use, or pass `--codex-home /path/to/.codex`.
|
|
189
|
+
|
|
190
|
+
Run Codex with isolated auth for the lifetime of one process. The default
|
|
191
|
+
active auth is never changed:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
ai-auth-switch run codex someone@example.com -- codex -C ~/workspace/project
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Numbered command aliases are managed automatically for every saved Codex
|
|
198
|
+
account. On the first sync, existing profiles are numbered in saved order;
|
|
199
|
+
later accounts are appended. Removing an account compacts the sequence, and
|
|
200
|
+
renaming an account keeps its number:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
ai-auth-switch auth list codex
|
|
204
|
+
# someone@example.com [codex1]
|
|
205
|
+
# other@example.com [codex2]
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
The profile name is normally the authenticated email. If a credential file's
|
|
209
|
+
actual account differs, `auth list` shows it explicitly as
|
|
210
|
+
`(actual auth: ...)` instead of silently presenting a misleading `codexN`
|
|
211
|
+
mapping.
|
|
212
|
+
|
|
213
|
+
Saving, logging in, switching, renaming, or removing profiles updates the alias
|
|
214
|
+
records. For the default profile store, matching command links are also created
|
|
215
|
+
under `~/.local/bin` and stale links are removed. Run an explicit sync to
|
|
216
|
+
backfill existing accounts or to choose a different command directory:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
ai-auth-switch alias sync codex
|
|
220
|
+
ai-auth-switch alias sync codex --bin-dir /path/on/PATH
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
After installation, `codex1 -C ~/workspace/project` runs the Codex CLI under
|
|
224
|
+
the corresponding profile without changing the account used by `codex2` or by
|
|
225
|
+
the default `codex` command. Numbered aliases can run concurrently, including
|
|
226
|
+
multiple processes using the same saved account. A per-profile lock is held
|
|
227
|
+
only for the wrapper's short credential installation and reconciliation
|
|
228
|
+
steps, not for the lifetime of the Codex process.
|
|
229
|
+
|
|
230
|
+
Each run gets a private temporary `CODEX_HOME` containing only its selected
|
|
231
|
+
`auth.json`. Existing entries from the normal Codex home—including
|
|
232
|
+
`config.toml`, `history.jsonl`, `sessions/`, `skills/`, logs, caches, and
|
|
233
|
+
plugins—are linked into that temporary home. An existing `CODEX_SQLITE_HOME`
|
|
234
|
+
is preserved; when it is unset, SQLite state points back to the normal Codex
|
|
235
|
+
home. If Codex refreshes and atomically replaces its isolated `auth.json`, the
|
|
236
|
+
new credentials are written back to that saved profile when the process exits.
|
|
237
|
+
Same-account processes reference the same saved profile file so they can
|
|
238
|
+
observe a refresh-token rotation performed by another Codex process. If Codex
|
|
239
|
+
atomically replaces a session's auth symlink, wrapper-side reconciliation back
|
|
240
|
+
to the profile is serialized, skips unchanged stale credentials, and refuses a
|
|
241
|
+
write-back whose actual account differs from the saved profile. Rejected
|
|
242
|
+
credentials are preserved under the profile store's `backups/codex/rejected/`
|
|
243
|
+
directory for inspection.
|
|
244
|
+
|
|
245
|
+
Temporary homes use the machine-local per-user runtime directory by default
|
|
246
|
+
(`XDG_RUNTIME_DIR`, with a `/var/tmp` fallback), so workers sharing the profile
|
|
247
|
+
store do not contend on `/mnt` for per-process symlink creation and cleanup.
|
|
248
|
+
Set `AI_AUTH_SWITCH_RUNTIME_DIR` to override the runtime parent when needed.
|
|
249
|
+
|
|
250
|
+
Names matching `codex1`, `codex2`, and so on are reserved for automatic
|
|
251
|
+
management. Other alias names can still be created manually with
|
|
252
|
+
`ai-auth-switch alias set` and `ai-auth-switch alias install`.
|
|
253
|
+
|
|
254
|
+
When `--store-dir` is passed, automatic command-link installation is skipped
|
|
255
|
+
to avoid changing the user's global bin directory. Pass `--bin-dir` to
|
|
256
|
+
`alias sync`, or set `AI_AUTH_SWITCH_ALIAS_BIN_DIR`, to opt into a specific
|
|
257
|
+
directory. Editable installs prefer the checkout's shared `bin/ai-auth-switch`
|
|
258
|
+
launcher, which keeps aliases portable when the home directory is mounted on
|
|
259
|
+
multiple machines. Set `AI_AUTH_SWITCH_ALIAS_TARGET` or pass `--target` to
|
|
260
|
+
choose another launcher explicitly.
|
|
261
|
+
|
|
262
|
+
## Directory Overrides
|
|
263
|
+
|
|
264
|
+
By default Codex auth is read from:
|
|
265
|
+
|
|
266
|
+
```text
|
|
267
|
+
$CODEX_HOME/auth.json
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
or, when `CODEX_HOME` is unset:
|
|
271
|
+
|
|
272
|
+
```text
|
|
273
|
+
~/.codex/auth.json
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Override it explicitly:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
ai-auth-switch --codex-home /path/to/.codex auth list codex
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The profile store can be moved with:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
AI_AUTH_SWITCH_HOME=/secure/path ai-auth-switch auth list codex
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Architecture
|
|
289
|
+
|
|
290
|
+
`ai-auth-switch` has three separate layers:
|
|
291
|
+
|
|
292
|
+
- Auth management: save, list, activate, rename, remove, and inspect profiles.
|
|
293
|
+
- Dependent sync: point Hermes and OpenClaw at the active Codex CLI auth.
|
|
294
|
+
- Wrapper: run a command in a profile-scoped Codex home without changing the
|
|
295
|
+
default active profile or blocking runs of other accounts.
|
|
296
|
+
|
|
297
|
+
Provider support is intentionally small. A provider only needs to define where
|
|
298
|
+
its active auth file lives, how to infer a profile name, and which login command
|
|
299
|
+
should be run for interactive login.
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# ai-auth-switch
|
|
2
|
+
|
|
3
|
+
Switch auth profiles for AI coding agents while keeping the app's normal
|
|
4
|
+
configuration, history, sessions, and cache layout unchanged.
|
|
5
|
+
|
|
6
|
+
The first provider is Codex. The design keeps Codex itself as the source of
|
|
7
|
+
truth for everything except the active auth file:
|
|
8
|
+
|
|
9
|
+
- `~/.codex/config.toml` is not rewritten.
|
|
10
|
+
- `~/.codex/history.jsonl`, `sessions/`, `skills/`, and other Codex state stay in place.
|
|
11
|
+
- Permanent profile changes switch only `auth.json`.
|
|
12
|
+
- Profile-scoped runs isolate `auth.json` in a temporary `CODEX_HOME` while
|
|
13
|
+
sharing the normal Codex configuration and state.
|
|
14
|
+
- Saved profiles live outside Codex under `~/.local/share/ai-auth-switch/`.
|
|
15
|
+
- Hermes and OpenClaw Codex-dependent auth state is synchronized after Codex
|
|
16
|
+
auth changes.
|
|
17
|
+
|
|
18
|
+
## Install From Checkout
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
python -m pip install -e .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Python 3.10 or newer is required.
|
|
25
|
+
|
|
26
|
+
You can also run without installation:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
./bin/ai-auth-switch --help
|
|
30
|
+
./bin/ais --help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`ais` is the short command name for `ai-auth-switch`; both accept exactly the
|
|
34
|
+
same arguments. Examples below use the long name for clarity.
|
|
35
|
+
|
|
36
|
+
If the checkout and home directory are shared by multiple machines but
|
|
37
|
+
`/usr/local` is machine-local, install the shared launcher on `PATH` instead:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
mkdir -p ~/.local/bin
|
|
41
|
+
ln -sfn "$PWD/bin/ai-auth-switch" ~/.local/bin/ai-auth-switch
|
|
42
|
+
hash -r
|
|
43
|
+
ai-auth-switch alias sync codex
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Codex Usage
|
|
47
|
+
|
|
48
|
+
Save the currently active Codex login:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
ai-auth-switch auth save codex
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The profile name is inferred from the email inside the Codex OAuth token when
|
|
55
|
+
available. If the token does not expose an email, the fallback is
|
|
56
|
+
`chatgpt-<account-id-prefix>`.
|
|
57
|
+
|
|
58
|
+
Login a new Codex account and save it:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
ai-auth-switch auth login codex
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Optionally force a profile name:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
ai-auth-switch auth login codex work
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
List and switch profiles:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
ai-auth-switch auth list
|
|
74
|
+
ai-auth-switch auth list codex
|
|
75
|
+
ai-auth-switch auth list codex --usage
|
|
76
|
+
ai-auth-switch auth use codex someone@example.com
|
|
77
|
+
ai-auth-switch auth current codex
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Add `--usage` to query every saved Codex account's current rate-limit windows
|
|
81
|
+
in parallel. Each request uses that profile's own access token and explicit
|
|
82
|
+
ChatGPT account ID, so limits cannot be accidentally attributed to another
|
|
83
|
+
saved account. The normal list remains local and instant; usage lookup is
|
|
84
|
+
opt-in because it requires network access and may report an expired login.
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
* someone@example.com [codex1] (plus, 5h 72% left, 168h 41% left)
|
|
88
|
+
other@example.com [codex2] (team, 5h 18% left, 168h 83% left)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Results are cached for 60 seconds. Use `--refresh-usage` to bypass the cache,
|
|
92
|
+
`--usage-cache-ttl` to tune it, `--usage-timeout` for slow networks, and
|
|
93
|
+
`--usage-workers` to limit concurrency. A failure for one account is shown
|
|
94
|
+
inline without hiding results for the other accounts. The command deliberately
|
|
95
|
+
does not refresh expired OAuth tokens; run that profile through Codex or log in
|
|
96
|
+
again so rotating credentials remain coordinated safely.
|
|
97
|
+
|
|
98
|
+
For status bars, monitoring, or account schedulers, add `--json`. The JSON
|
|
99
|
+
contains profile identity, active/alias state, and structured usage windows
|
|
100
|
+
when `--usage` is also present:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
ai-auth-switch auth list codex --usage --json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
After Codex auth is saved, logged in, or switched, `ai-auth-switch` also syncs
|
|
107
|
+
Codex-dependent local tools:
|
|
108
|
+
|
|
109
|
+
- Hermes is pointed at `openai-codex` and seeded with a Codex CLI access-token
|
|
110
|
+
pool entry, so it follows the active Codex CLI account without handing turns
|
|
111
|
+
to `codex app-server`. If `hermes-gateway.service` is active, it is restarted
|
|
112
|
+
so Feishu and other messaging channels pick up the new auth immediately.
|
|
113
|
+
- Current OpenClaw installs are synchronized through the SQLite auth store by
|
|
114
|
+
writing `openai:default` from the active Codex CLI OAuth token. Older JSON
|
|
115
|
+
auth-state installs still use the legacy `openai-codex:default` bridge.
|
|
116
|
+
|
|
117
|
+
You can run that step explicitly too:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
ai-auth-switch auth sync codex
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Hermes does not import or share the Codex CLI refresh token. The sync clears
|
|
124
|
+
Hermes's old independent `openai-codex` OAuth state, installs the current Codex
|
|
125
|
+
CLI access token into Hermes's `openai-codex` credential pool, and leaves
|
|
126
|
+
Hermes's `openai_runtime` on `auto`. Current OpenClaw versions no longer import
|
|
127
|
+
Codex CLI auth from `~/.codex` at runtime, so the sync writes the active Codex
|
|
128
|
+
OAuth tokens into OpenClaw's own SQLite auth store as `openai:default` and
|
|
129
|
+
clears any failure cooldown for that profile. Older OpenClaw JSON auth-state
|
|
130
|
+
installs still fall back to the legacy `openai-codex:default` bridge profile.
|
|
131
|
+
|
|
132
|
+
The old Hermes login flag is kept only for command compatibility and is now a
|
|
133
|
+
no-op:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
ai-auth-switch auth sync codex --hermes-login
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Use `ai-auth-switch auth sync codex` normally. Before restarting active gateway
|
|
140
|
+
services, the current process's standard proxy variables (`http_proxy`,
|
|
141
|
+
`https_proxy`, and their uppercase variants) are imported into the systemd user
|
|
142
|
+
manager, so Hermes/OpenClaw do not need a hard-coded proxy env file. To leave a
|
|
143
|
+
running Hermes gateway untouched during an explicit sync, pass
|
|
144
|
+
`--no-hermes-restart`.
|
|
145
|
+
|
|
146
|
+
If Codex reports that a refresh token was already used after switching
|
|
147
|
+
profiles, that profile's stored refresh token has already been invalidated by
|
|
148
|
+
the server. Log in to that Codex account again and save it back into the same
|
|
149
|
+
profile name:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
ai-auth-switch auth login codex <profile>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Recent versions sync Codex's atomically replaced `auth.json` back into the
|
|
156
|
+
managed profile before switching away, which prevents reactivating a stale
|
|
157
|
+
refresh token after Codex refreshes it.
|
|
158
|
+
|
|
159
|
+
On a fresh install, `auth list` can be empty even when Codex is already logged
|
|
160
|
+
in. Import the active Codex auth first:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
ai-auth-switch auth save codex
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
If you run as another Unix user, make sure `CODEX_HOME` points at the Codex
|
|
167
|
+
config directory you actually use, or pass `--codex-home /path/to/.codex`.
|
|
168
|
+
|
|
169
|
+
Run Codex with isolated auth for the lifetime of one process. The default
|
|
170
|
+
active auth is never changed:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
ai-auth-switch run codex someone@example.com -- codex -C ~/workspace/project
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Numbered command aliases are managed automatically for every saved Codex
|
|
177
|
+
account. On the first sync, existing profiles are numbered in saved order;
|
|
178
|
+
later accounts are appended. Removing an account compacts the sequence, and
|
|
179
|
+
renaming an account keeps its number:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
ai-auth-switch auth list codex
|
|
183
|
+
# someone@example.com [codex1]
|
|
184
|
+
# other@example.com [codex2]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The profile name is normally the authenticated email. If a credential file's
|
|
188
|
+
actual account differs, `auth list` shows it explicitly as
|
|
189
|
+
`(actual auth: ...)` instead of silently presenting a misleading `codexN`
|
|
190
|
+
mapping.
|
|
191
|
+
|
|
192
|
+
Saving, logging in, switching, renaming, or removing profiles updates the alias
|
|
193
|
+
records. For the default profile store, matching command links are also created
|
|
194
|
+
under `~/.local/bin` and stale links are removed. Run an explicit sync to
|
|
195
|
+
backfill existing accounts or to choose a different command directory:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
ai-auth-switch alias sync codex
|
|
199
|
+
ai-auth-switch alias sync codex --bin-dir /path/on/PATH
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
After installation, `codex1 -C ~/workspace/project` runs the Codex CLI under
|
|
203
|
+
the corresponding profile without changing the account used by `codex2` or by
|
|
204
|
+
the default `codex` command. Numbered aliases can run concurrently, including
|
|
205
|
+
multiple processes using the same saved account. A per-profile lock is held
|
|
206
|
+
only for the wrapper's short credential installation and reconciliation
|
|
207
|
+
steps, not for the lifetime of the Codex process.
|
|
208
|
+
|
|
209
|
+
Each run gets a private temporary `CODEX_HOME` containing only its selected
|
|
210
|
+
`auth.json`. Existing entries from the normal Codex home—including
|
|
211
|
+
`config.toml`, `history.jsonl`, `sessions/`, `skills/`, logs, caches, and
|
|
212
|
+
plugins—are linked into that temporary home. An existing `CODEX_SQLITE_HOME`
|
|
213
|
+
is preserved; when it is unset, SQLite state points back to the normal Codex
|
|
214
|
+
home. If Codex refreshes and atomically replaces its isolated `auth.json`, the
|
|
215
|
+
new credentials are written back to that saved profile when the process exits.
|
|
216
|
+
Same-account processes reference the same saved profile file so they can
|
|
217
|
+
observe a refresh-token rotation performed by another Codex process. If Codex
|
|
218
|
+
atomically replaces a session's auth symlink, wrapper-side reconciliation back
|
|
219
|
+
to the profile is serialized, skips unchanged stale credentials, and refuses a
|
|
220
|
+
write-back whose actual account differs from the saved profile. Rejected
|
|
221
|
+
credentials are preserved under the profile store's `backups/codex/rejected/`
|
|
222
|
+
directory for inspection.
|
|
223
|
+
|
|
224
|
+
Temporary homes use the machine-local per-user runtime directory by default
|
|
225
|
+
(`XDG_RUNTIME_DIR`, with a `/var/tmp` fallback), so workers sharing the profile
|
|
226
|
+
store do not contend on `/mnt` for per-process symlink creation and cleanup.
|
|
227
|
+
Set `AI_AUTH_SWITCH_RUNTIME_DIR` to override the runtime parent when needed.
|
|
228
|
+
|
|
229
|
+
Names matching `codex1`, `codex2`, and so on are reserved for automatic
|
|
230
|
+
management. Other alias names can still be created manually with
|
|
231
|
+
`ai-auth-switch alias set` and `ai-auth-switch alias install`.
|
|
232
|
+
|
|
233
|
+
When `--store-dir` is passed, automatic command-link installation is skipped
|
|
234
|
+
to avoid changing the user's global bin directory. Pass `--bin-dir` to
|
|
235
|
+
`alias sync`, or set `AI_AUTH_SWITCH_ALIAS_BIN_DIR`, to opt into a specific
|
|
236
|
+
directory. Editable installs prefer the checkout's shared `bin/ai-auth-switch`
|
|
237
|
+
launcher, which keeps aliases portable when the home directory is mounted on
|
|
238
|
+
multiple machines. Set `AI_AUTH_SWITCH_ALIAS_TARGET` or pass `--target` to
|
|
239
|
+
choose another launcher explicitly.
|
|
240
|
+
|
|
241
|
+
## Directory Overrides
|
|
242
|
+
|
|
243
|
+
By default Codex auth is read from:
|
|
244
|
+
|
|
245
|
+
```text
|
|
246
|
+
$CODEX_HOME/auth.json
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
or, when `CODEX_HOME` is unset:
|
|
250
|
+
|
|
251
|
+
```text
|
|
252
|
+
~/.codex/auth.json
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Override it explicitly:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
ai-auth-switch --codex-home /path/to/.codex auth list codex
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The profile store can be moved with:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
AI_AUTH_SWITCH_HOME=/secure/path ai-auth-switch auth list codex
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Architecture
|
|
268
|
+
|
|
269
|
+
`ai-auth-switch` has three separate layers:
|
|
270
|
+
|
|
271
|
+
- Auth management: save, list, activate, rename, remove, and inspect profiles.
|
|
272
|
+
- Dependent sync: point Hermes and OpenClaw at the active Codex CLI auth.
|
|
273
|
+
- Wrapper: run a command in a profile-scoped Codex home without changing the
|
|
274
|
+
default active profile or blocking runs of other accounts.
|
|
275
|
+
|
|
276
|
+
Provider support is intentionally small. A provider only needs to define where
|
|
277
|
+
its active auth file lives, how to infer a profile name, and which login command
|
|
278
|
+
should be run for interactive login.
|