hatcheck 0.2.0__py3-none-win_amd64.whl

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,841 @@
1
+ Metadata-Version: 2.4
2
+ Name: hatcheck
3
+ Version: 0.2.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Environment :: Console
6
+ Classifier: Intended Audience :: Developers
7
+ Classifier: Operating System :: MacOS
8
+ Classifier: Operating System :: Microsoft :: Windows
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Classifier: Programming Language :: Rust
11
+ Classifier: Topic :: Software Development
12
+ Classifier: Topic :: Utilities
13
+ License-File: LICENSE
14
+ Summary: Claude Code and Codex accounts on one computer, each kept apart: recent sessions, plan usage, resume commands and moves across all of them.
15
+ Keywords: claude,claude-code,codex,cli,profiles,sessions
16
+ Home-Page: https://hatcheck.dev
17
+ Author: Yi Wang
18
+ License-Expression: MIT
19
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
20
+ Project-URL: Homepage, https://github.com/hatcheck/hatcheck
21
+ Project-URL: Issues, https://github.com/hatcheck/hatcheck/issues
22
+
23
+ <p align="center">
24
+ <picture>
25
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/hatcheck/hatcheck/main/site/logo-wordmark-dark.svg">
26
+ <img src="https://raw.githubusercontent.com/hatcheck/hatcheck/main/site/logo-wordmark.svg" alt="Hatcheck" width="360">
27
+ </picture>
28
+ </p>
29
+
30
+ # Hatcheck
31
+
32
+ Several Claude accounts on one computer, each kept apart: isolated Claude Desktop instances on
33
+ macOS, and Claude Code CLI profiles, with recent sessions, plan usage and resume commands across all
34
+ of them. OpenAI's Codex CLI gets the same treatment, and sessions can be carried between the two.
35
+
36
+ *Unofficial: not made by, affiliated with or endorsed by Anthropic or OpenAI. Claude, Claude Code and
37
+ Claude Desktop are trademarks of Anthropic; Codex and ChatGPT are trademarks of OpenAI.*
38
+
39
+ Run **two (or more) fully isolated Claude Desktop instances** side by side on macOS — e.g. one
40
+ signed into your **personal** account and one into your **work** account — each with its own
41
+ **color-coded Dock launcher** that **focuses the existing window instead of spawning duplicates**.
42
+
43
+ This builds on Philipp Stracker's excellent
44
+ [`--user-data-dir` approach](https://gist.github.com/stracker-phil/9f84927a556632c7f9cc06663b534f14)
45
+ ([write-up](https://philippstracker.com/multiple-claude-instances/)) and adds two things:
46
+
47
+ 1. **Recolored icons** so you can tell the launchers apart at a glance (blue work / red personal / etc.).
48
+ 2. A **smart, self-contained launcher** that fixes the "every click opens another window" problem.
49
+
50
+ It also has **command-line tools for Claude Code and [Codex](https://github.com/openai/codex)**, for
51
+ keeping one profile per account: `cl` and `cx` run Claude Code and Codex with a profile, and
52
+ `hatcheck` lists the recent sessions in all of them, with the command that resumes each one and
53
+ what's left of each plan. `hatcheck usage` shows the plans, `hatcheck best` says which account to use
54
+ now, `hatcheck where` finds a session, `hatcheck open` resumes one in a new terminal, and
55
+ `hatcheck move` carries one over to another profile, or converts it between Claude Code and Codex.
56
+ `hatcheck bind` ties a folder to a profile, so `cl` and `cx` pick it there, and `--json` gives the
57
+ sessions and plans to scripts and status bars. `claude-z` and `claude-k` run Claude Code on Z.ai's
58
+ GLM or Kimi's models instead, in any profile. See
59
+ [Claude Code and Codex CLI profiles](#claude-code-and-codex-cli-profiles).
60
+
61
+ | | macOS | Linux | Windows |
62
+ |---------------------------------|:-----:|:-----:|:-------:|
63
+ | Claude Desktop instances | yes | no official Desktop app | [planned](#roadmap) |
64
+ | Claude Code and Codex CLI tools | yes | yes | yes |
65
+
66
+ > ## ⭐ Recommended: give *every* account its own isolated instance
67
+ >
68
+ > The most reliable setup is to create a **separate, dedicated instance for each account —
69
+ > including your "personal" one — and stop using Claude's built-in default profile for day-to-day
70
+ > use.** Don't try to make one launcher target the shared default profile.
71
+ >
72
+ > Why: Claude has **no per-profile single-instance lock**, so two processes can run on one profile
73
+ > at once — and **only the *first* instance on a profile can use its login database. Every
74
+ > additional instance on that same profile shows up logged out.** If a "personal" launcher points
75
+ > at the default profile (which the stock Claude icon also uses), you end up with duplicate,
76
+ > logged-out windows. Giving each account its own dir guarantees **one profile → one instance →
77
+ > always logged in**, and makes the focus-don't-duplicate logic rock-solid.
78
+ >
79
+ > Already logged into the default profile and don't want to re-auth? See
80
+ > [Copying an existing login into an instance](docs/desktop-instances.md#copying-an-existing-login-into-an-instance) — you can copy your current
81
+ > profile into the new dedicated dir.
82
+
83
+ ---
84
+
85
+ ## How it works
86
+
87
+ Claude Desktop is an Electron app. Electron's `--user-data-dir` flag points the app at a
88
+ completely separate profile folder (config, sessions, **auth tokens**, MCP servers, Cowork data):
89
+
90
+ ```bash
91
+ open -n -a "/Applications/Claude.app" --args --user-data-dir="$HOME/.claude-instances/work"
92
+ ```
93
+
94
+ A tiny macOS `.app` "wrapper" just runs that command, so it shows up in Launchpad/Dock like a
95
+ normal app. Each wrapper stores its instance name in `Contents/MacOS/config.sh` and runs
96
+ `Contents/MacOS/claude-launcher`.
97
+
98
+ ### The duplicate problem (and the fix)
99
+
100
+ The naive launcher uses `open -n` — the `-n` flag means *"open a NEW instance, even if one is
101
+ already running."* Claude has **no per-profile single-instance lock**, so **every click spawns
102
+ another process** against the same profile dir. That stacks up duplicate windows and risks
103
+ corrupting the shared profile.
104
+
105
+ The **smart launcher** in this repo fixes it. On click it inspects *that specific instance*
106
+ (matched by `--user-data-dir`; for the default instance, the main process that has *no*
107
+ `--user-data-dir`) and does one of three things:
108
+
109
+ - **Running with a window** → focuses that process's window by PID via System Events. No duplicate.
110
+ - **Running but windowless** → opens a fresh window. Claude keeps its main process alive after you
111
+ close the window, and a windowless instance *cannot* be re-shown per-instance (all instances share
112
+ one bundle id, so `open -a` / "activate" can't target it). We deliberately **do not kill** the
113
+ windowless process: it is often windowless precisely because it's still doing background work
114
+ (e.g. a chat that's "thinking"), and killing it would lose that work. The leftover windowless
115
+ process is harmless and goes away when you fully **Quit (⌘Q)** Claude.
116
+ - **Not running** → launches fresh with `open -n`.
117
+
118
+ How "has a window?" is detected: a live window shows up as one or more `--type=renderer` processes
119
+ for that profile; closing the window drops that count to 0.
120
+
121
+ So "always click the launcher you want" reliably **focuses-or-launches** the right instance, even
122
+ after you've closed its window.
123
+
124
+ > **Tip:** to keep the focus-don't-relaunch behavior working, **close Claude with ⌘W** (close
125
+ > window, app keeps running) when you want it to stay live, and **⌘Q** when you truly want it gone.
126
+
127
+ ### What the colors do (and don't do)
128
+
129
+ The recolored icon lives on the **launcher you click**. Because all instances share the one
130
+ `/Applications/Claude.app` binary, **while running they all show the same stock Dock icon and the
131
+ name "Claude"** — the color only marks the launcher. The reliable in-app tell is the signed-in
132
+ account. (Truly distinct *running* Dock icons would require a full standalone copy of Claude.app.)
133
+
134
+ ---
135
+
136
+ ## Claude Desktop instances (macOS)
137
+
138
+ `hatcheck desktop` makes them: each instance gets its own data folder, `~/.claude-instances/<name>`,
139
+ and a launcher in `/Applications` with Claude's icon in a colour you pick. The launcher brings a
140
+ running instance's window forward instead of starting a second one on the same folder.
141
+
142
+ ```bash
143
+ hatcheck desktop new work Work --hue 190 # Claude Work.app, blue
144
+ hatcheck desktop new personal Personal --hue -10 # Claude Personal.app, red-orange
145
+ hatcheck desktop open work # or open it from Launchpad or the Dock
146
+ hatcheck desktop # the instances, and which are running
147
+ hatcheck desktop remove work # its launcher; --data deletes its data folder too
148
+ ```
149
+
150
+ Sign each one in to its account the first time it opens. The first time a launcher brings a window
151
+ forward, macOS asks whether it may control System Events; allow it, once per launcher. `--hue`
152
+ turns the icon's colours by that many degrees (about 110 is green, 190 blue, 240 purple) and
153
+ `--saturation` scales them. hatcheck recolours the icon itself, with macOS's `iconutil`, and a
154
+ launcher it can't recolour keeps Claude's own icon. The name `default` makes a launcher for
155
+ Claude's built-in data folder, which is only safe while nothing else runs on that folder, the stock
156
+ Claude icon included. [docs/desktop-instances.md](docs/desktop-instances.md) has the rest: what
157
+ the launcher does, and how to copy a login you already have into an instance.
158
+
159
+ ---
160
+
161
+ ## Claude Code and Codex CLI profiles
162
+
163
+ Claude Code (the `claude` CLI) keeps its settings, history and session transcripts in `~/.claude`
164
+ (plus `~/.claude.json`), and its login in the macOS Keychain, or on Linux and Windows in
165
+ `~/.claude/.credentials.json`. Point `CLAUDE_CONFIG_DIR` at another folder and you get a separate
166
+ profile with its own login, so you can keep one per account:
167
+ `~/.claude-work`, `~/.claude-personal`, and so on. These are separate from the Desktop instances
168
+ above, though sessions from Desktop's Code tab can be filed in them too (the session list below
169
+ hides those unless you pass `--all`). Codex works the same way with `CODEX_HOME`: see
170
+ [`cx`](#cx-run-codex-with-a-home-per-account).
171
+
172
+ ### Install
173
+
174
+ One binary per platform, with no Python needed. Each of these installs `hatcheck`, `hat`, `cl`,
175
+ `cx`, `claude-z` and `claude-k`:
176
+
177
+ ```bash
178
+ curl -LsSf https://github.com/hatcheck/hatcheck/releases/latest/download/hatcheck-installer.sh | sh
179
+ brew install hatcheck/tap/hatcheck # Homebrew, on macOS and Linux
180
+ uv tool install hatcheck # or: pipx install hatcheck
181
+ ```
182
+
183
+ On Windows, in PowerShell:
184
+
185
+ ```powershell
186
+ powershell -ExecutionPolicy Bypass -c "irm https://github.com/hatcheck/hatcheck/releases/latest/download/hatcheck-installer.ps1 | iex"
187
+ ```
188
+
189
+ The installer scripts put the commands in `~/.local/bin` and add that folder to your `PATH`; set
190
+ `HATCHECK_NO_MODIFY_PATH=1` first to keep your shell's startup files as they are. Each release, made
191
+ from a tag such as `v0.2.0`, has them and the binaries for each platform, and PyPI gets the same
192
+ binaries as wheels. The release builds start after 0.1.0, which is the Python version.
193
+
194
+ From a clone, on macOS and Linux, with Rust 1.90 or newer ([rustup.rs](https://rustup.rs)):
195
+
196
+ ```bash
197
+ ./install.sh # build the commands and link them into ~/.local/bin
198
+ ./install.sh --bin ~/bin # or into another folder on your PATH
199
+ ./install.sh --uninstall # remove the links again
200
+ ```
201
+
202
+ The links point at the build in `target/release`, so after a `git pull`, run `./install.sh` again
203
+ to rebuild them. The installer doesn't edit your shell startup files: if the folder isn't on your
204
+ `PATH`, it prints the line to add. A file that already has one of these names is left alone unless
205
+ you pass `--force`, except the links it made before, to the Python `hatcheck` and the `sh` launchers,
206
+ and the copies of `claude-z` and `claude-k` that the [claude-z](https://github.com/yiwang/claude-z)
207
+ installers made, which these replace. `hat` is installed as its short name too, unless another
208
+ command on your `PATH` already has that name.
209
+
210
+ Before the rename to Hatcheck these were separate commands: `claude-recent-sessions` (now
211
+ `hatcheck`), `claude-usage`, `claude-where`, `claude-move-session` and `claude-provider` (now
212
+ `hatcheck usage`, `where`, `move` and `provider`). The installers remove the links to them.
213
+
214
+ On Windows, in PowerShell:
215
+
216
+ ```powershell
217
+ .\install.ps1 # build the commands and add .cmd launchers for them to ~\.local\bin
218
+ .\install.ps1 -Bin D:\bin # or to another folder on your PATH
219
+ .\install.ps1 -Uninstall # remove them again
220
+ ```
221
+
222
+ The launchers run the build, so after a `git pull`, run it again. They work from PowerShell and
223
+ `cmd` alike, whatever the script execution policy. If PowerShell won't run `install.ps1`, start it
224
+ with `powershell -ExecutionPolicy Bypass -File install.ps1`. On Windows, `hatcheck` prints `cd` and
225
+ resume commands for PowerShell. Paste them into PowerShell, not `cmd`, because `cmd` doesn't treat
226
+ the trailing `# usage` as a comment. Inside a Visual Studio developer prompt, the MSVC compiler is
227
+ also called `cl`, and whichever comes first on `PATH` wins.
228
+
229
+ #### Or as shell functions
230
+
231
+ `cl` and `cx` are small enough to keep as shell functions instead. Add this to `~/.zshrc` (or
232
+ `~/.bashrc`):
233
+
234
+ ```bash
235
+ # cl work --resume <id> == CLAUDE_CONFIG_DIR=~/.claude-work claude --resume <id>
236
+ # cl -k work ... runs the installed claude-k instead (-z: claude-z)
237
+ cl() {
238
+ local run=claude
239
+ case $1 in -z|-k) run=claude$1; shift ;; esac
240
+ [ -n "$1" ] || { echo "usage: cl [-z|-k] <profile> [claude args...] (uses ~/.claude-<profile>)" >&2; return 2; }
241
+ CLAUDE_CONFIG_DIR="$HOME/.claude-$1" "$run" "${@:2}"
242
+ }
243
+
244
+ # cx work resume <id> == CODEX_HOME=~/.codex-work codex resume <id>
245
+ cx() {
246
+ [ -n "$1" ] || { echo "usage: cx <profile> [codex args...] (uses ~/.codex-<profile>)" >&2; return 2; }
247
+ mkdir -p "$HOME/.codex-$1" && CODEX_HOME="$HOME/.codex-$1" codex "${@:2}"
248
+ }
249
+
250
+ ```
251
+
252
+ A shell function takes precedence over an installed command with the same name, and both do the
253
+ same thing. `hatcheck` needs the install; without it, `find ~/.claude* ~/.codex* -name "*3f1c2a9e*"`
254
+ finds a session's files.
255
+
256
+ ### `cl`: run Claude Code with a profile
257
+
258
+ ```bash
259
+ cl work # Claude Code with ~/.claude-work (sign in on first run)
260
+ cl work --resume <session-id> # resume one of that profile's sessions
261
+ cl personal --continue # any claude option works
262
+ cl -k work --resume <session-id> # that session on Kimi; -z for Z.ai (see below)
263
+ ```
264
+
265
+ Plain `claude` keeps using `~/.claude`. Claude Code names each profile's Keychain entry after its
266
+ `CLAUDE_CONFIG_DIR` value, so keep one spelling of each path; `cl` always uses `~/.claude-<name>`.
267
+ In a folder tied to a profile with [`hatcheck bind`](#hatcheck-bind-tie-a-folder-to-a-profile), the
268
+ name can be left out: `cl --resume <session-id>` there uses that profile.
269
+
270
+ ### `cx`: run Codex with a home per account
271
+
272
+ [Codex](https://github.com/openai/codex) keeps its login, config and sessions in `~/.codex`, and
273
+ `CODEX_HOME` points it at another folder, so you can keep one home per ChatGPT account the same way:
274
+ `~/.codex-work`, `~/.codex-personal`, and so on.
275
+
276
+ ```bash
277
+ cx work login # sign in once, with the work account
278
+ cx work # Codex with ~/.codex-work
279
+ cx work resume <session-id> # resume one of that home's sessions
280
+ cx personal exec "run the tests" # any codex command works
281
+ ```
282
+
283
+ - `cx` makes the folder on first use, since Codex won't start with a `CODEX_HOME` that doesn't exist.
284
+ - A new home starts without your `~/.codex/config.toml` (model, trusted folders, MCP servers); copy
285
+ it over if you want the same settings.
286
+ - Plain `codex` keeps using `~/.codex`.
287
+ - In a folder tied to a home with [`hatcheck bind`](#hatcheck-bind-tie-a-folder-to-a-profile), the name
288
+ can be left out: `cx resume <session-id>` there uses that home. A Codex command such as `resume`
289
+ counts as a home's name only when `~/.codex-resume` exists; anywhere else, `cx resume …` says it
290
+ needs a home rather than making `~/.codex-resume`.
291
+
292
+ ### `claude-z`, `claude-k`: Claude Code on Z.ai or Kimi
293
+
294
+ `claude-z` and `claude-k` start Claude Code on [Z.ai](https://z.ai)'s GLM models or
295
+ [Kimi](https://www.kimi.com/code)'s, with your plan there, instead of on Anthropic's. `cl -z <name>` and
296
+ `cl -k <name>` do the same in a profile, so a session can switch between Claude and those models and
297
+ stay in its profile:
298
+
299
+ ```bash
300
+ claude-k reconfig # once: your Kimi API key and model (claude-z reconfig for Z.ai)
301
+ claude-k # Claude Code on Kimi, with ~/.claude
302
+ cl -k work --resume <session-id> # carry on a work-profile session on Kimi…
303
+ cl work --resume <session-id> # …and later back on the work account's Claude plan
304
+ ```
305
+
306
+ - Setup asks for the API key (from [z.ai](https://z.ai/manage-apikey/apikey-list) or the
307
+ [Kimi Code Console](https://www.kimi.com/code)), the model, and an optional cap on output tokens.
308
+ It saves them in `~/.config/claude-z/config` or `~/.config/claude-k/config` (`%APPDATA%\claude-z\config`
309
+ on Windows), the files the [claude-z](https://github.com/yiwang/claude-z) launchers use, so a setup
310
+ made with those works as is. `hatcheck provider` shows what's set up.
311
+ - Models: on Z.ai `glm-5.3[1m]` (the default, with `glm-5.3-flash` for quick tasks), `glm-5.3-flash`
312
+ or `glm-4.7`; on Kimi `k3[1m]` (the default), `k3`, `kimi-for-coding` or
313
+ `kimi-for-coding-highspeed`. `[1m]` turns on the 1M-token context window.
314
+ - The key reaches Claude Code as `ANTHROPIC_AUTH_TOKEN`, which it always uses ahead of the profile's
315
+ claude.ai login and never asks about, and `ANTHROPIC_API_KEY` is cleared. Claude Code asks once per
316
+ profile whether to use an `ANTHROPIC_API_KEY`, with No preselected, and after a No it sends the
317
+ profile's claude.ai login token to the provider instead.
318
+ - The model is pinned with `ANTHROPIC_MODEL`, so a `"model"` in the profile's `settings.json`, such
319
+ as `"fable"`, can't send a Claude model name to Z.ai or Kimi.
320
+ - Resuming a session on another provider sends it the whole conversation so far, so check that's
321
+ allowed before doing it with a work account's sessions.
322
+ - `hatcheck usage` and the comments in `hatcheck` show the Claude and ChatGPT plans, not Z.ai's or
323
+ Kimi's.
324
+
325
+ Coming from the claude-z repo: `./install.sh` replaces the copies its installers put in
326
+ `~/.local/bin`, and your config stays. On Windows, delete `%LOCALAPPDATA%\claude-z` (and `\claude-k`)
327
+ and take it off your `PATH` by hand, but keep `%APPDATA%\claude-z`, which holds your key; that repo's
328
+ uninstallers delete both. The permission mode its installers asked for isn't used (the old launchers
329
+ only ever applied `dangerously-skip-permissions`): set `permissions.defaultMode` in the profile's
330
+ `settings.json`, or pass `--permission-mode`. OpenRouter (`claude-o`) isn't included.
331
+
332
+ ### `hatcheck where`: find a session
333
+
334
+ ```console
335
+ $ hatcheck where 3f1c2a9e
336
+ /Users/me/.claude-work/projects/-Users-me-code-api/3f1c2a9e-8b7d-4c1e-9f2a-6d5e4c3b2a10.jsonl
337
+ $ hatcheck where 019a8c1e
338
+ /Users/me/.codex/sessions/2026/10/14/rollout-2026-10-14T09-12-33-019a8c1e-7d3f-7b21-9c4e-2f1a0b9c8d7e.jsonl
339
+ ```
340
+
341
+ The profile in the path tells you how to resume it (`claude`, or `cl work` here), and the folder
342
+ under `projects/` is the directory the session ran in, with every non-alphanumeric character turned
343
+ into `-`. A session with subagents or large tool results also has a data folder of the same name,
344
+ which is listed too. Codex files its sessions by the date they started, archived ones under
345
+ `archived_sessions/`; resume one with `codex resume <id>`, or `cx <name> resume <id>` for a
346
+ `~/.codex-<name>` home.
347
+
348
+ ### `hatcheck`: what to resume
349
+
350
+ `hat` is the short name: `hat`, `hat usage`, `hat move …` and so on work the same. `hat check` is the name
351
+ in two words, so it's `hat` again: `hat check` lists sessions and `hat check usage` is `hat usage`.
352
+
353
+ Lists the Claude Code sessions from every `~/.claude*` profile, and the Codex sessions from every
354
+ `~/.codex*` home, that were active in the last 24 hours or are still open, grouped by folder and
355
+ newest first. Run from a folder that has sessions, it lists
356
+ just that folder's (`--all-folders` lists them all). Each one comes with the command that resumes it
357
+ and what's left of that profile's plan:
358
+
359
+ ```
360
+ $ hatcheck
361
+ Claude Code and Codex CLI sessions active in the last 24h or open now (by folder, newest first; % = plan left, ↻ = hours/days until reset)
362
+ cd ~/code/api
363
+ 4m Fix flaky login test · main · ● open in pid 48213 (busy)
364
+ cl work --resume 3f1c2a9e-8b7d-4c1e-9f2a-6d5e4c3b2a10 # 5h 100% █████ Fable 48% ███▍░░░ ↻████▎░░ 4d6h
365
+ 40m Add retries to the uploader · codex · main
366
+ cx work resume 019a8c1e-7d3f-7b21-9c4e-2f1a0b9c8d7e # 5h 80% ████░ ↻███▏░ 3h10m week 64% ████▌░░ ↻█▊░░░░░ 1d18h
367
+ 1h Refactor the auth middleware · main · on k3
368
+ cl -k work --resume 2d4f6a8c-1e3b-4d5f-9a7c-0b2d4e6f8a1c
369
+ 3h Add rate limiting to the login endpoint · feat/rate-limit
370
+ claude --resume 9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d # 5h 62% ███▏░ ↻██▋░░ 2h41m week 91% ██████▍ ↻███▏░░░ 3d2h
371
+ cd ~/code/blog
372
+ 20h Draft post on Rust lifetimes · main
373
+ cl personal --resume c47e2b1d-0a9f-4e8d-b7c6-5d4e3f2a1b0c # 5h ? ····· week 97% ██████▊ ↻█████▏░ 5d2h
374
+ cd ~/notes
375
+ 6h Plan next sprint · main
376
+ cl work --resume 5b6c7d8e-9f0a-4b1c-8d2e-3f4a5b6c7d8e # 5h 100% █████ Fable 48% ███▍░░░ ↻████▎░░ 4d6h
377
+ 9h Write release notes · main
378
+ cl work --resume 7e8f9a0b-1c2d-4e3f-8a4b-5c6d7e8f9a0b
379
+ Profiles: ~/.claude (1), ~/.claude-personal (1), ~/.claude-work (4)
380
+ Usage from Claude Code's last snapshot (token expired; run claude in this profile to renew it): ~/.claude-personal 9h ago
381
+ ```
382
+
383
+ - Run the folder's `cd` line, then the session's command. Sessions still open in a terminal are
384
+ marked `● open`, so you don't resume one twice.
385
+ - The comment after each command shows each plan limit: the 5-hour session (`5h`), the weekly limit
386
+ (`week`) and per-model weekly limits such as `Fable`, which are named in violet, with their bar
387
+ drawn in it, so they stand apart from `week`. Each one has the % left and a bar of it, then `↻`, a bar of the time left until
388
+ it resets and that time. Bars have a block per hour of the 5-hour window and per day of a weekly
389
+ one, as in `↻████▎░░ 4d6h`.
390
+ - Time bars are coloured by urgency: blue with most of the window to go, then gold and orange, and
391
+ red as the reset nears.
392
+ - A plan bar shorter than its time bar means that limit is being used up faster than its window runs
393
+ out, like `Fable` above: 48% left with more than half the week to go. `?` means the limit has
394
+ reset since the saved snapshot it came from.
395
+ - A command without the comment, like the second one in `~/notes`, uses the same account as the
396
+ command above it, even through another profile, so its usage is the same.
397
+ - A session whose newest reply came from Z.ai or Kimi shows that model, like `on k3` above, and its
398
+ command resumes it there (`claude-k` for `~/.claude`). Use `cl work` instead to go back to Claude;
399
+ its comment is still the profile's Claude plan.
400
+ - Codex sessions are marked `codex` and resume with `codex resume <id>`, or `cx <name> resume <id>`
401
+ for a `~/.codex-<name>` home. Their comment shows the ChatGPT plan's Codex limits (see
402
+ `hatcheck usage` below). Sessions from the Codex app, its IDE extension and `codex exec` are hidden
403
+ like Desktop ones, and Codex's own approval reviews aren't listed.
404
+ - Since the usage is a shell comment, pasting the whole line runs just the command (zsh needs
405
+ `setopt interactivecomments`).
406
+ - Usage is fetched live, one request per account. When that fails (expired token, rate limit), Claude
407
+ Code's last saved snapshot is used instead and named at the bottom with its age.
408
+ - A session that ran in a folder [bound](#hatcheck-bind-tie-a-folder-to-a-profile) to another
409
+ profile is marked `⚠ folder bound to ~/.claude-work`, so it's easy to spot and `hatcheck move`.
410
+ - What it reads from each session file is cached, in `sessions.json` in `~/Library/Caches/hatcheck`
411
+ on macOS (`%LOCALAPPDATA%\hatcheck\Cache` on Windows, `~/.cache/hatcheck` elsewhere, or
412
+ `$HATCHECK_CACHE_DIR`). A repeat run reads only what was added to a session since, so a session
413
+ that's still being written costs little however long it is. Deleting the folder is always safe.
414
+
415
+ | Option | What it does |
416
+ |--------------|-------------------------------------------------------------------------------|
417
+ | `HOURS` | how far back to look (default 24); takes `36`, `1.5`, `12h` or `3d` |
418
+ | `-n N` | show only the newest N sessions per folder and count the rest |
419
+ | `--all` | also list sessions from Claude Desktop's Code tab, the SDK, the Codex app, its IDE extension and `codex exec` |
420
+ | `--all-folders` | list every folder, even when run from one that has sessions |
421
+ | `--full` | print `CLAUDE_CONFIG_DIR=~/.claude-<name> claude …` instead of `cl`, and `CODEX_HOME=… codex …` instead of `cx` |
422
+ | `--cached` | take usage from Claude Code's and Codex's saved snapshots, without calling the APIs |
423
+ | `--no-usage` | leave plan usage out |
424
+ | `--json` | print the sessions, and the accounts behind them, as JSON ([below](#--json-for-scripts-status-bars-and-apps)) |
425
+ | `-e`, `--email` | with `--json`, include each account's email address |
426
+
427
+ ### `hatcheck usage`: plan usage for every profile
428
+
429
+ ```
430
+ $ hatcheck usage
431
+ Plan usage by profile (% left, then time left until reset)
432
+ Sorted by Fable: those with some left first, the soonest reset on top; then those out of it, the soonest back on top.
433
+ ~/.claude-work team max 5x · live
434
+ session (5h) 100% ██████████
435
+ week (Fable) 48% ████▊░░░░░ ██████▏░░░ resets Sun 8:20pm (in 4d6h)
436
+ ~/.claude pro · live
437
+ session (5h) 62% ██████▎░░░ █████▍░░░░ resets 5:01pm (in 2h41m)
438
+ week (all models) 91% █████████▏ ████▍░░░░░ resets Sat 4:20pm (in 3d2h)
439
+ ~/.claude-personal pro · cached 9h00m ago (token expired; run claude in this profile to renew it)
440
+ session (5h) ? ·········· reset 10:20am, after this snapshot
441
+ week (all models) 97% █████████▊ ███████▎░░ resets Mon 4:20pm (in 5d2h)
442
+ ~/.codex-work ChatGPT plus · live
443
+ session (5h) 80% ████████░░ ██████▍░░░ resets 5:30pm (in 3h10m)
444
+ week (all models) 64% ██████▍░░░ ██▌░░░░░░░ resets Fri 8:20am (in 1d18h)
445
+ ```
446
+
447
+ - Accounts are sorted by their Fable limit. First come those with some Fable left, the soonest
448
+ Fable reset on top: what's left there goes unused once it resets, so that's the one to use first.
449
+ Next come those out of Fable, or out of the weekly limit for all models, which Fable counts against
450
+ too, the soonest back on top. Then come accounts without a Fable limit, such as Pro plans, and
451
+ Codex homes. A snapshot saved before its Fable limit reset counts as full until the reset after.
452
+ - Each limit has two bars: what's left of it, then how much of its window, 5 hours or a week, is
453
+ left before it resets. In a terminal the second goes from blue with most of the window to go,
454
+ through gold and orange, to red as the reset nears. When the first bar is shorter than the
455
+ second, as for `Fable` here, the limit is being used up faster than its window runs out. A limit
456
+ without a reset time, like an unused 5-hour session, has no time bar.
457
+ - It reads each profile's OAuth token from the macOS Keychain, or from the profile's
458
+ `.credentials.json` on Linux and Windows, and asks the same endpoint as Claude Code's `/usage`. The token is only read, never refreshed: a refresh rotates it and would sign Claude Code
459
+ out of that profile.
460
+ - When a token has expired or the endpoint rate-limits the account, Claude Code's last saved snapshot
461
+ is shown with its age. Run `claude` (or `cl <name>`) in that profile to renew the token.
462
+ - Profiles signed in to the same account are shown together. Per-model limits such as
463
+ `week (Fable)` are named in violet, with their bar drawn in it, to tell them from `week (all
464
+ models)`; the % keeps the severity's colour. Quota fields the server
465
+ sends that Claude Code doesn't display are listed dimmed under their raw names.
466
+ - Codex homes show their ChatGPT plan's Codex limits: the 5-hour and weekly windows (a free plan has
467
+ one 30-day window instead), then limits for single models such as `GPT-5.3-Codex-Spark`, named in
468
+ violet like `Fable`. The access token in the home's `auth.json` is sent as it is to the endpoint
469
+ Codex's `/status` uses, and never refreshed. When it has expired, or the request fails, the newest
470
+ limits Codex recorded in that home's session files are shown, with their age. Codex doesn't send a
471
+ severity, so a limit turns yellow from 75% used and red from 90%. Homes signed in to the same
472
+ account are shown together.
473
+ - `--cached` skips the APIs. `-e` / `--email` adds each account's email address, which is hidden by
474
+ default so the output is safe to share. `--json` prints the accounts as data
475
+ ([below](#--json-for-scripts-status-bars-and-apps)).
476
+
477
+ ### `hatcheck move`: carry on a session with another profile
478
+
479
+ When one account runs low, continue a session on another profile, or in the other agent. It copies
480
+ the session by default; `--no-keep` deletes the original once the copy is checked, which moves it.
481
+
482
+ ```
483
+ $ hatcheck move 9a8b7c6d work
484
+ Copied session 9a8b7c6d "Add rate limiting to the login endpoint" from ~/.claude to ~/.claude-work:
485
+ transcript 53.0 KB
486
+ subagents and tool output 3 files
487
+ /rewind file snapshots 4 files
488
+ plan quiet-river-plan.md
489
+ Paths in the conversation to these files now point to the copies.
490
+ Kept the original in ~/.claude; --no-keep deletes it once the copy is checked.
491
+ Resume it with:
492
+ cd ~/code/api
493
+ cl work --resume 9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d
494
+ Resume it now in ~/.claude-work? [y/N]
495
+ ```
496
+
497
+ - It copies the transcript, the folder of subagent transcripts and saved tool output, the `/rewind`
498
+ file snapshots and the plan file, keeping their timestamps, and checks every copied file. Paths in
499
+ the conversation that point at those files are changed to point at the copies, except inside
500
+ Claude's thinking, whose signatures would stop matching.
501
+ - A session that's open in a terminal is refused: quit it first, so it stops changing.
502
+ `hatcheck` marks those `● open`.
503
+ - Resume it with the printed command, from the directory it ran in, or answer `y` when it asks and
504
+ it starts Claude Code there with the new profile. It only asks in a terminal, so scripts never
505
+ wait on it. The conversation comes across whole; the account and its plan limits, settings,
506
+ permissions, MCP servers, plugins and project memory are the new profile's. If the new account
507
+ rejects the signatures on earlier thinking, Claude Code drops those thinking blocks and carries
508
+ on.
509
+ - Plan files stay in the old profile even with `--no-keep`, since sessions can share one.
510
+ - If the session's last reply came from Z.ai or Kimi, it also prints the `cl -z` or `cl -k` command
511
+ that carries on there instead of on the new profile's Claude plan.
512
+
513
+ #### When the profile already has a copy
514
+
515
+ A session copied to another profile and carried on there can be moved back: the copy it left
516
+ behind is an older version of it. The two copies are compared line by line:
517
+
518
+ - **The copy there is older**, because the session went on from it: it's brought up to date, and
519
+ each item shows `(updated an older copy)`. Nothing is lost, since the copy being moved starts with
520
+ all of it.
521
+ - **The copy there is newer**, because the session went on there: nothing is copied. With
522
+ `--no-keep`, the older copy here is deleted.
523
+ - **Both went on** after the copy was made: nothing is copied, since that would lose the prompts
524
+ only the copy there has. It says when they split and how many prompts each has had since.
525
+ `--fork` brings this one in as a new session with its own ID and keeps both, as Claude Code's
526
+ `claude --resume <id> --fork-session` and `codex fork` do. Or delete the copy there first.
527
+
528
+ ```
529
+ $ hatcheck move 9a8b7c6d default
530
+ Session 9a8b7c6d went on in both ~/.claude-work and ~/.claude after Oct 15 01:40: 3 new prompts in ~/.claude-work, 1 in ~/.claude. Copying this one over would lose what's only in ~/.claude, so nothing was copied.
531
+ To keep both, bring this one in as a new session with its own ID:
532
+ hatcheck move 9a8b7c6d default --fork
533
+ Or delete the copy in ~/.claude first, to replace it:
534
+ ~/.claude/projects/-Users-me-code-api/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d.jsonl
535
+ ```
536
+
537
+ A fork changes the session's ID in its records and gives it its own folders for subagents, saved
538
+ tool output and `/rewind` snapshots. Its message IDs stay the same, as in Claude Code's own fork.
539
+ Resuming a fork, a round trip and a copy that went on in both profiles were tested with the real
540
+ `claude` (2.1.301).
541
+
542
+ When more than one profile has the session, you're asked which copy to take. The one used last
543
+ comes first and is the default, and each other one says how it stands to it:
544
+
545
+ ```
546
+ $ hatcheck move 4215508b hp-alan
547
+ Session 4215508b is in 3 profiles:
548
+ 1. ~/.claude-hp-aria Oct 17 14:02 312 prompts used last
549
+ 2. ~/.claude-hp-yi Oct 16 09:11 298 prompts 14 prompts behind 1
550
+ 3. ~/.claude-hp-aiqing Oct 12 18:40 201 prompts went its own way after Oct 11 20:15: 2 prompts of its own
551
+ Which one? [1]
552
+ ```
553
+
554
+ A number, a profile's name or Enter picks one. When the output isn't a terminal, as in a script or
555
+ with `--json`, the copy used last is taken and a line says so; `--from` always decides.
556
+
557
+ #### With Codex
558
+
559
+ `codex` is `~/.codex` and `codex:<name>` is `~/.codex-<name>`, as a place to copy to or `--from`:
560
+
561
+ ```
562
+ $ hatcheck move 019a8c1e work
563
+ Converted Codex session 019a8c1e "Add retries to the uploader" from ~/.codex-work into a Claude Code session in ~/.claude-work:
564
+ conversation 5 of your messages, with the replies
565
+ tool calls 191, as text with their output shortened
566
+ left out Codex's reasoning, images, goals and subagent sessions
567
+ new session 6f6749d7-0f59-4683-997c-a3595421b93f (241.9 KB)
568
+ The original stays in ~/.codex-work.
569
+ Resume it with:
570
+ cd ~/code/api
571
+ cl work --resume 6f6749d7-0f59-4683-997c-a3595421b93f
572
+ Resume it now in ~/.claude-work? [y/N]
573
+ ```
574
+
575
+ - Between Codex homes signed in to the same ChatGPT account, the session file is copied as it is,
576
+ with its ID and its name, and `--no-keep` works as for Claude Code. A copy already there is
577
+ compared the same way, and `--fork` gives the copy a new ID in its file name, its
578
+ `session_meta` and its events.
579
+ - Between Claude Code and Codex (`hatcheck move 3f1c2a9e codex:work` goes the other way), and
580
+ between Codex homes on different accounts, the session is converted into a new one with a new ID,
581
+ and the original is always kept. Codex encrypts its reasoning and its summaries of compacted
582
+ context for the account that wrote them, so a copy can't take them to another account.
583
+ - Your messages and the replies come across as text, and each tool call as a block with its input
584
+ and the start of its output, in the format Codex's own `/import` uses for Claude Code sessions
585
+ (`[external_agent_tool_call: Bash] … [/external_agent_tool_call]`). A note at the start tells the
586
+ model where the session came from. Claude's thinking and Codex's reasoning are left out, and so are
587
+ images, plans, goals, `/rewind` snapshots and subagent transcripts.
588
+ - The whole conversation before a compaction is carried over, not its summary. Past about 100,000
589
+ tokens the oldest turns after the first are left out, so it fits the new agent's context window.
590
+ - Converted sessions were tested by resuming them with the real `claude` (2.1.301) and `codex`
591
+ (0.155.1), which sent the whole converted history to the model and carried on in the same
592
+ session. Codex's resume picker lists them by their Claude Code title.
593
+ - Codex can import Claude Code sessions itself (`/import` in Codex), but only from `~/.claude` and
594
+ the last 30 days. Claude Code's `claude import codex` brings over Codex's instructions, agents and
595
+ hooks, not sessions.
596
+
597
+ | Option | What it does |
598
+ |------------------|------------------------------------------------------------------------------|
599
+ | `SESSION` | the session ID, or the start of it |
600
+ | `PROFILE` | where it goes: `NAME` for `~/.claude-NAME`, `default` for `~/.claude`, `codex` for `~/.codex`, `codex:NAME` for `~/.codex-NAME`, or a path |
601
+ | `--from PROFILE` | the profile or home to take it from, when more than one has it; without it you're asked, with the one used last as the default, and a script or `--json` gets that one |
602
+ | `--no-keep` | delete the original once the copy is checked, which moves it (not when converting) |
603
+ | `--fork` | copy it in as a new session with its own ID, leaving a copy already there as it is (a converted session always gets one) |
604
+ | `--dry-run` | show what would be copied, converted and deleted, and change nothing |
605
+
606
+ ### `hatcheck open`: resume a session in a new terminal
607
+
608
+ ```console
609
+ $ hatcheck open 3f1c2a9e # a new terminal window in ~/code/api, running cl work --resume …
610
+ $ hatcheck open # the newest session started from this folder, in any profile or home
611
+ $ hatcheck open 3f1c2a9e --here # in this terminal instead
612
+ $ hatcheck open 3f1c2a9e --print # the two commands, for scripts
613
+ cd ~/code/api
614
+ cl work --resume 3f1c2a9e-8b7d-4c1e-9f2a-6d5e4c3b2a10
615
+ ```
616
+
617
+ - It finds the session by its ID or the start of it, in every Claude Code profile and Codex home.
618
+ When more than one profile has a copy, it takes the one used last; `--from <profile>` picks one.
619
+ - The command is the one `hatcheck` prints: `cl` or `claude`, `cx` or `codex`, and `cl -z`/`cl -k` for a
620
+ session whose last reply came from Z.ai or Kimi. Without `cl` or `cx` on the `PATH` it's the full
621
+ form (`CLAUDE_CONFIG_DIR=… claude …`), as `--full` gives.
622
+ - A session that's open in a terminal is refused, so it isn't resumed twice.
623
+ - The terminal:
624
+ - **macOS:** Terminal, or the one `hatcheck` runs in when that's iTerm2, Ghostty or WezTerm. Terminal
625
+ and iTerm2 are driven with AppleScript, which macOS asks you to allow once.
626
+ - **Windows:** Windows Terminal (`wt`), otherwise a new PowerShell window.
627
+ - **Linux:** `$TERMINAL`, otherwise `x-terminal-emulator`, GNOME Terminal or Konsole.
628
+ - `--terminal NAME`, or `HATCHECK_TERMINAL`, picks another: `terminal`, `iterm`, `ghostty`,
629
+ `wezterm`, `wt`, `powershell`, `gnome-terminal`, `konsole`, `kitty`, or any terminal that takes
630
+ `-e`. A shell stays open in the folder after the session ends.
631
+ - If the terminal can't be opened, it prints the two commands to run instead.
632
+
633
+ ### `hatcheck best`: which account to use now
634
+
635
+ ```console
636
+ $ hatcheck best
637
+ Claude Code, best first (sorted by Fable, as hatcheck usage sorts)
638
+ 1. ~/.claude-work Fable 31% left, resets Tue 12:00pm · 5h 80% → cl work
639
+ 2. ~/.claude-team Fable 100% left, resets Thu 1:00am · 5h 100% → cl team
640
+ 3. ~/.claude-personal Fable 0% left, back Sat 4:59pm · 5h 100% → cl personal
641
+ 4. ~/.claude week 64% · 5h 100% → claude
642
+ Codex, best first
643
+ 1. ~/.codex month 100% → codex
644
+ Advice only: nothing is started, moved or switched. hatcheck best --for <session> says where to carry a session.
645
+ $ hatcheck best --for 9a8b7c6d
646
+ Session 9a8b7c6d "Add rate limiting to the login endpoint" is in ~/.claude-personal: Fable 0% left, back Sat 4:59pm · 5h 100%.
647
+ Carry it to ~/.claude-work: Fable 31% left, resets Tue 12:00pm · 5h 80%.
648
+ hatcheck move 9a8b7c6d work --from personal
649
+ It prints the command that resumes it there, and offers to run it.
650
+ ```
651
+
652
+ - Claude Code accounts come in the order `hatcheck usage` sorts them: those with Fable left first,
653
+ the soonest Fable reset on top; then those out of Fable, or out of the weekly limit for all models,
654
+ the soonest back on top; then accounts without a Fable limit, by the limit with the least left.
655
+ Codex homes are ranked by the limit with the least left.
656
+ - `--for <session>` picks the best other account of the session's agent that has room now, and
657
+ prints the [`hatcheck move`](#hatcheck-move-carry-on-a-session-with-another-profile) command. If
658
+ the session's own account is the best, it says so and prints the resume command.
659
+ - The numbers are the ones `hatcheck usage` shows, live when it can be, with a snapshot's age
660
+ otherwise; `--cached` skips the APIs.
661
+ - **Advice only.** It runs when you ask, prints commands, and never starts, moves or switches
662
+ anything. Using several accounts to get around one plan's limits may break Anthropic's or OpenAI's
663
+ terms; this is for choosing between accounts you may use for the work at hand, such as your own
664
+ and your company's.
665
+
666
+ ### `hatcheck bind`: tie a folder to a profile
667
+
668
+ With a work and a personal account, it's easy to start `claude` in a work repo out of habit. The
669
+ session then runs on the personal account and is filed in the personal profile. A binding says
670
+ which profile a folder's work belongs to:
671
+
672
+ ```console
673
+ $ cd ~/code/api
674
+ $ hatcheck bind work # this folder and everything under it: ~/.claude-work, ~/.codex-work
675
+ Bound ~/code/api and everything under it: Claude Code ~/.claude-work · Codex ~/.codex-work.
676
+ Here, cl --resume <id> means cl work --resume <id> and cx resume <id> means cx work resume <id>.
677
+ $ hatcheck bind work --codex personal # a different Codex home
678
+ $ hatcheck bind # what this folder is bound to
679
+ $ hatcheck bind --list # every bound folder
680
+ $ hatcheck unbind # untie it
681
+ $ hatcheck bind --hook # warn in Claude Code and Codex (once; hatcheck unbind --hook undoes it)
682
+ ```
683
+
684
+ - Bindings live in your own config, `~/.config/hatcheck/bindings.json`
685
+ (`%APPDATA%\hatcheck\bindings.json` on Windows), not in the repo, so profile names don't end up in
686
+ git. The deepest bound folder wins, and folders are compared once symlinks are resolved.
687
+ - `default` binds `~/.claude` and `~/.codex`. The Codex home is the one named like the profile when
688
+ there is one; `--codex <name>` picks another, and `--codex` alone binds just the Codex home.
689
+ - `cl` and `cx` use the binding when no profile name is given: `cl --resume <id>`, `cl`,
690
+ `cx resume <id>`. A name given still wins, and outside bound folders nothing changes.
691
+ - `hatcheck` marks sessions that ran in a bound folder under another profile:
692
+ `⚠ folder bound to ~/.claude-work`.
693
+ - `--hook` adds a `SessionStart` hook, `hatcheck bind --check`, to every profile's `settings.json`
694
+ and every Codex home's `hooks.json`. When a session starts in a bound folder under another
695
+ profile, it shows a warning and nothing is blocked:
696
+ `hatcheck: ~/code/api is bound to ~/.claude-work, but this session runs in ~/.claude-personal. Quit
697
+ and run cl work here instead.` For a resumed session it gives the `hatcheck move` command instead.
698
+ - **Claude Code:** tested with the real `claude` (2.1.301). It shows the warning in the interactive
699
+ UI; `claude -p` doesn't display it.
700
+ - **Codex:** Codex runs a new hook only once you trust it with `/hooks` in `codex`, once per home.
701
+ Tested with `codex exec` (0.163): it runs the hook from the home's `hooks.json`, with the folder,
702
+ the session and `CODEX_HOME`, but `codex exec` doesn't print hook messages. Codex's docs say its
703
+ interactive UI shows them as a warning; that part wasn't tested here.
704
+
705
+ ### `--json`: for scripts, status bars and apps
706
+
707
+ `hatcheck --json` and `hatcheck usage --json` print what the text shows, as data:
708
+
709
+ ```console
710
+ $ hatcheck --json
711
+ {
712
+ "version": 1,
713
+ "generated_at": "2026-10-15T22:41:07Z",
714
+ "hours": 24,
715
+ "this_folder_only": false,
716
+ "sessions": [
717
+ {
718
+ "agent": "claude",
719
+ "id": "3f1c2a9e-8b7d-4c1e-9f2a-6d5e4c3b2a10",
720
+ "profile": "/Users/me/.claude-work",
721
+ "account": 0,
722
+ "title": "Fix flaky login test",
723
+ "cwd": "/Users/me/code/api",
724
+ "last_active": "2026-10-15T22:37:02Z",
725
+ "entrypoint": "cli",
726
+ "branch": "main",
727
+ "model": "claude-fable-5-1",
728
+ "open": {"pid": 48213, "status": "busy"},
729
+ "continued_in": null,
730
+ "bound_to": null,
731
+ "resume": "cl work --resume 3f1c2a9e-8b7d-4c1e-9f2a-6d5e4c3b2a10"
732
+ }
733
+ ],
734
+ "accounts": [
735
+ {
736
+ "agent": "claude",
737
+ "profiles": ["/Users/me/.claude-work"],
738
+ "plan": "team max 5x",
739
+ "source": "live",
740
+ "saved_at": null,
741
+ "why": null,
742
+ "limits": [
743
+ {"name": "session (5h)", "short": "5h", "kind": "session", "used_percent": 20, "left_percent": 80,
744
+ "resets_at": "2026-10-16T01:30:00Z", "window_seconds": 18000, "severity": "normal", "per_model": false}
745
+ ],
746
+ "extra": null,
747
+ "fable": {"left": true, "resets_at": "2026-10-20T16:00:00Z"}
748
+ }
749
+ ],
750
+ "hidden": {"Desktop": 3},
751
+ "other_folders": 0,
752
+ "older_not_listed": {}
753
+ }
754
+ ```
755
+
756
+ - **The same choices as the text:** the time window, `--all`, `--all-folders` and `-n` pick the same
757
+ sessions in the same order, and `resume` is the command the text prints. `account` is the
758
+ session's place in `accounts`, which holds the accounts behind the listed sessions (none with
759
+ `--no-usage`). `hatcheck usage --json` gives every account, in its Fable order, with `sorted_by`.
760
+ - **Stable:** absolute paths rather than `~`, times in UTC (ISO 8601), no colours. `version` goes up
761
+ only when a field changes meaning or goes away; new fields can appear at any time.
762
+ - `left_percent` is `null` for a snapshot's limit that has reset since it was saved. `fable` is
763
+ `{"left": true, "resets_at": …}`, `{"left": false, "back_at": …}`, or `null` without a Fable limit.
764
+ `source` is `live`, `cached` or `none`, with `why` when it isn't live.
765
+ - Errors go to stderr with a non-zero exit, so stdout is always valid JSON. Email addresses only with
766
+ `--email`.
767
+
768
+ ## The desktop app
769
+
770
+ A menu-bar app (system tray on Windows and Linux) built on the CLI. It shows what's left of every
771
+ plan, sorted by Fable, with bars and reset times, and the last day's sessions with **Resume**,
772
+ which opens a terminal in the session's folder, and **Copy**. It also has buttons for the Claude
773
+ Desktop instances and notifies you when a limit runs low or resets.
774
+
775
+ Its main window browses every session, with search, filters and a read-only preview of the
776
+ conversation. From there you can resume a session, copy its command, or move it to another
777
+ profile after a dry run. The window also lists profiles and homes, signs in to a new one in a
778
+ terminal, and makes Desktop instances.
779
+
780
+ It ships the CLI inside itself, so it needs no Python. It never handles a login, and live usage is
781
+ off until you turn it on. See [desktop/README.md](desktop/README.md) to build it; releases come
782
+ from `.github/workflows/desktop.yml` for macOS, Windows and Linux. The plan behind it is
783
+ [the proposal](docs/proposals/desktop-app.md).
784
+
785
+ ## Files in this repo
786
+
787
+ - **`crates/hatcheck/`**: hatcheck in Rust, the commands and the launchers. Its `src/` has a file per
788
+ subcommand (`sessions.rs`, `usage.rs`, `move_cmd.rs`, `open_cmd.rs`, `desktop.rs` and the rest),
789
+ `launch.rs` for `cl`, `cx`, `claude-z` and `claude-k`, and `src/bin/` for those binaries and `hat`.
790
+ It was ported from a Python version with the same output; see [docs/rust-port.md](docs/rust-port.md).
791
+ - **`install.sh`** / **`install.ps1`**: build the commands from a clone and put them on your `PATH`
792
+ (`~/.local/bin` by default).
793
+ - **`pyproject.toml`**: the PyPI package, the binaries as wheels built with maturin.
794
+ **`dist-workspace.toml`**: the release builds, installers and Homebrew formula, made by cargo-dist.
795
+ **`packaging/`**: the app's Homebrew cask, and the winget manifests for the app and the CLI.
796
+ - **`desktop/`**: the desktop app: Tauri, with the CLI inside it ([its README](desktop/README.md)).
797
+ - **`site/`**: the landing page, one self-contained file, served at [hatcheck.dev](https://hatcheck.dev)
798
+ from Cloudflare as static assets; `site/deploy.sh` ships it. The logo lives there too:
799
+ `logo.svg` and `logo-dark.svg` (the mark), `logo-wordmark.svg` and `logo-wordmark-dark.svg`, `favicon.svg`.
800
+ - **`docs/proposals/`**: the plans these came from: [the CLI features](docs/proposals/cli-features.md)
801
+ and [the desktop app](docs/proposals/desktop-app.md).
802
+ - **`tests/`**: the command tests, which run the binary against throwaway home folders:
803
+ `python3 -m unittest discover -s tests`, which builds it with cargo first, and the crate's own
804
+ tests with `cargo test -p hatcheck`. They never read your real profiles, Keychain or the network.
805
+ GitHub Actions runs both on macOS, Linux and Windows (`.github/workflows/tests.yml`).
806
+
807
+ ## Roadmap
808
+
809
+ - **Claude Desktop instances on Windows.** Claude Desktop is an Electron app there too, so a
810
+ separate `--user-data-dir` per account should work. A Windows version would create a shortcut per
811
+ instance with its own icon, and a launcher that brings a running instance forward instead of
812
+ opening a duplicate. It needs testing on a Windows machine first.
813
+ - **Linux.** There's no official Claude Desktop for Linux, so only the CLI tools apply there.
814
+ - **Releases:** the CLI's 0.1.0 is on PyPI, as Python; the next release ships the Rust binaries to
815
+ PyPI, GitHub, the Homebrew tap and winget, then the app's installers, once the release workflows
816
+ have their accounts and secrets (the workflows list them).
817
+ - **Signing:** a Developer ID for the macOS app, and a certificate for the Windows one.
818
+
819
+ ## Credits
820
+
821
+ - **Claude Desktop instances:** this repo started as a fork of
822
+ [Aaron Oxborrow](https://github.com/aoxborrow)'s
823
+ [gist](https://gist.github.com/aoxborrow/5a3a0ac0aa37819cc19439b70a552221), whose scripts made
824
+ colour-coded launchers for isolated instances. On 16 October 2026 his scripts and his sections of
825
+ this README were replaced by a rewrite, `hatcheck desktop`, so none of his code or text remains.
826
+ The idea both implement, running Claude Desktop with `--user-data-dir`, is from
827
+ [Philipp Stracker's gist](https://gist.github.com/stracker-phil/9f84927a556632c7f9cc06663b534f14)
828
+ ([write-up](https://philippstracker.com/multiple-claude-instances/)), itself a cleaned-up version
829
+ of [weidwonder/claude-desktop-multi-instance](https://github.com/weidwonder/claude-desktop-multi-instance).
830
+ - **Claude Code and Codex CLI tools:** `hatcheck`, `cl`, `cx`, the installers and the tests are by
831
+ [Yi Wang](https://github.com/yiwang).
832
+ - **Z.ai and Kimi:** the provider settings in `crates/hatcheck/src/provider.rs` (endpoints, model slots, context
833
+ windows and the config files) come from [claude-z](https://github.com/sam-fakhreddine/claude-z) by
834
+ Kerim ([lettt325](https://github.com/lettt325)), MIT-licensed, and Yi Wang's
835
+ [fork](https://github.com/yiwang/claude-z) of it, which added Kimi.
836
+
837
+ ## License
838
+
839
+ MIT, see [LICENSE](LICENSE). It covers everything in this repo: the CLI, the desktop app, the site
840
+ and the docs.
841
+