zsh_custom
A shell suite that makes moving between sixty-nine projects cost one keystroke — and makes coming back after a reboot cost nothing at all.

What it is
Ten zsh files that load in numeric order, about 3,650 lines, sitting inside the home lab toolkit. The entire thing exists to answer one question faster than you can finish asking it: which project am I in, and what was I doing in it?
A single project_env/projects.json is the manifest of record — sixty-nine projects, each with an id, a display name, a repo, a canonical path, a colour, a category and a sort order. It is committed, so registering a project registers it on every machine. Everything else reads from there.
cs opens the fuzzy menu. Pick a project and the shell becomes that project: the working directory, the environment, its own .aliases, its SSH shortcuts, and the terminal background taking a hint of the project’s colour so a glance at the window tells you where you are. The context survives a shell restart, because the one thing worse than switching is switching and then having to remember.
Right arrow walks a carousel — projects, then hosts, then the client category, then back to projects — so every menu is reachable by counting presses rather than remembering a command.
The part I’d keep
The session registry, which is a fifth of the whole suite and the only part I’d call a design rather than a convenience.
A hook writes one record per Claude Code session, at start and at end. The interesting decision is that a session’s state is never stored — it is worked out at read time, from whether an end was recorded, which boot it happened under, and whether the pid is still a running process:
live | No end recorded, same boot, pid still running |
ended | End fired — closed on purpose |
dead | No end, same boot, pid gone — killed, OOM’d or crashed |
rebooted | No end, recorded under a different boot — the machine went down underneath it |
Only the last of those is a disaster, and it is the one crestore fixes: it reopens everything that was running when the box went down. The distinction matters because a stored flag would have been written by the process that died, which is exactly the process that cannot be trusted to write it.
That design came out of a measurement rather than a theory. The obvious assumption is that closing a terminal kills a session silently — it does not. Closing the terminal sends SIGHUP, which does fire the end hook. Tested, dated, and written into the source as a comment, because the next person to read it will assume otherwise.
The small one
ssh is wrapped. Modern terminals export exotic TERM values — xterm-ghostty, kitty — and a host with an older ncurses answers with unknown terminal type and a dead session. The wrapper downgrades TERM to xterm-256color for the remote side only, local terminal untouched. One environment variable turns it off.
It is four lines of real work and it removed a class of papercut that had been costing a minute at a time for a year. Most of this suite is that: not clever, just finally written down.
Why it exists
I keep circling the cost of crossing between contexts. Tickler is that argument in a browser — every organization on one page, one queue of what needs you. This is the same argument in a terminal, and it came first.
The claim in both is the same: a switcher assumes you already know where you are going, and the expensive part was never the switch. It was the reconstruction on the other side — which window, which host, which session, what was I in the middle of. The long version is the multi-organization problem; the shorter one is a root to stand on.