Repository navigation
Releases: stricttools/claudewheel
Release list
v0.34.1
The release archives for Linux, which 0.34.0 failed to publish: claudewheel runs only on Linux, and its macOS builds failed.
Fixes
- Each GitHub Release carries
claudewheelarchives for Linux on amd64 and arm64. 0.34.0 published none: its macOS builds failed, and claudewheel runs only on Linux (it starts sessions in systemd user scopes), so no macOS archive is built.
v0.34.0
claudewheel rewritten in Go: one binary installed with go install or from the release archives, a workspace converted once with upgrade-workspace, segments preset with -s, patch-profiles with an explicit --profile or --all-profiles, and the probe runner run by probe run-service. The Python and npm packages are no longer published; PyPI and npm keep 0.33.0.
Context
The stricttools projects are moving to Go; the Python and npm releases stop at 0.33.0.
Breaking
- Claude Code is no longer memory-capped; a session's Bash commands share a 6G cap instead. Each launched session runs in its own slice: Claude Code in an uncapped scope, and every Bash command, with everything it starts, in a scope of its own inside the session's tools slice, capped together at
tool_memory_max(6G) andtool_memory_swap_max(1G) fromconfig.json. A runaway command is killed while the session goes on, and the command's output ends with a line naming what was killed and the cap. The commands reach the slice throughCLAUDE_CODE_SHELL_PREFIX, pointed at the newclaudewheel-tool-scopescript, which a launch deploys when it is missing; hooks, the status line, and MCP servers run outside the cap.session_memory_maxandsession_memory_swap_maxare removed fromconfig.jsonand not carried over. Probe reports, probe commands, andheavyattribute a Bash command's scope to its session. Sessions already running keep the scope they were launched with. - The command names itself
claudewheel. Help headers,--helpfooters, parse errors, and--versionnow printclaudewheelinstead ofc(claudewheel --versionprintsclaudewheel <version>), and the--jsonoutput'sappfield is"claudewheel". Scripts that matched the oldctext must match the new one. Theclauncher script at the repository root, which was meant to be symlinked as~/.local/bin/c, is gone; run the installedclaudewheelcommand instead. The README's install instruction now names the command that exists,claudewheel install <version>. claudewheel --dump-schemais replaced byclaudewheel help --json.--dump-schemais now refused with an error namingclaudewheel help --json, which prints the help document on stdout instead of writing a file. Also: an integer value accepts only plain decimal digits with an optional leading minus sign (+30and030are refused), and a flag that takes one value is refused when given twice.- claudewheel is now a single Go binary; the PyPI and npm packages are no longer published. Install it with
go install github.com/stricttools/claudewheel/cmd/claudewheel@v0or from the Linux archives on each GitHub Release (claudewheel runs only on Linux); PyPI and npm keep 0.33.0. To move from the Python: uninstall it (uv tool uninstall claudewheel,pipx uninstall claudewheel, ornpm uninstall -g claudewheel), runclaudewheel upgrade-workspace, thenclaudewheel deploy-hooks claudewheel-probe-runner.service --force-overwriteso the probe runner's service runs the Go binary. The deprecated namesnew-profile,delete-profile, andshow-profileare gone. - A workspace an older claudewheel wrote is converted once with the new
claudewheel upgrade-workspace. It removes the retired keys (_schema_version,scratchpad_snooze_until) and adds the keys the defaults declare, never changing a value; every other command refuses an unconverted workspace and names it, and--dry-runpreviews it. The workspace is always$HOME/.claudewheel(CLAUDEWHEEL_CONFIG_DIRis no longer read), read-only commands such asshowandhealthno longer create missing files,statsno longer deletes anything,reset-optionswrites the defaultoptions.jsoninstead of deleting it, andconfigopens$EDITORonly, refusing when it is unset. reconcile-permissionsis gone;patch-profilestakes a required--profile <name>or--all-profiles. Only--all-profilesalso reconcilesshared-settings.json.permission addandpermission removeedit theallowlist only and drop the category argument (every launch resetsdenyandaskto the canonical lists), and adding an allow rule that conflicts with a guardrail rule is refused.healthexits 1 when any check is not OK.launchpresets segments only with-s KEY=VALUE. The per-segment flags (--profile,--github,--model,--directory,--mcp,--permissions) are gone. A value a fixed-choice segment does not offer is refused, naming the values it offers; print mode with a required segment unset is an error instead of a warning; arguments after--go to the client; and Ctrl-C at the launch bar exits 130.migratetakes--session <uuid>(the full lowercase id) or--all-sessions, with no substring matching, and refuses before moving anything when any destination already exists, listing every collision.importrefuses a source holding a broken symlink it would read, listing every one, before copying anything.- The permissions segment no longer offers plan mode, and
-s permissions=planor a pinnedplanis refused: accepting a plan wipes the session's history. The segment offersbypass,default, andauto. - Every confirmation takes the same keys:
yaccepts,ndeclines, Escape skips, and Enter does nothing. The scratchpad cleanup asks once per stale directory, andnkeeps that directory and never offers it again (the seven-day snooze is gone). A launch with the miniclaude client hides the version segment and refusesmcp=strict, and a reconcile that fails during a launch stops the launch instead of being ignored.
Features
claudewheel deploy-hooksships theheavywrapper.heavyruns a memory-heavy command alone on the machine and under a memory cap: one machine-wide lock queues heavy commands from every session, and each runs in its own systemd scope with a 5G limit (--memchanges it) and no swap, so a runaway job is killed alone instead of the whole terminal session.deploy-hooks heavy(or--all) writes it to~/.claudewheel/scripts/heavyand makes~/.local/bin/heavya symlink to it; anything else already at that path is refused unless--force-overwriteis passed.heavyruns jobs side by side within a memory budget, replacing the one machine-wide lock. Every heavy command declares its cap (--mem, 5G unless given), and starts once that cap, plus what the running heavy commands have not yet used of theirs, fits in the machine's available memory less a 2G margin; at most 8 run at once. A job that needs less, such as a single test or a small build, starts sooner with a smaller cap (heavy --mem 2G -- <command>), and a cap larger than the machine's memory less the margin is a usage error. A command whoseheavywas killed keeps its cap reserved while it runs on, and the waiting message names thesystemctl --user stopcommand that ends it. When the command returns,heavystops whatever it left running. The command's arguments now reach it unchanged:systemd-runused to rewrite$VARand$$in them, soheavy -- bash -c 'echo $$'printed$.- Each session claudewheel launches runs in its own memory-capped systemd scope. A memory-heavy command that runs outside
heavyinside a session (a test suite insidebash -c, say) can now take down only its own session, not the whole terminal. The ceiling issession_memory_maxinconfig.json(4G unless set) withsession_memory_swap_maxof swap (1G unless set, or0); claudewheel prints both at every launch, and a malformed value fails the launch naming the key. When the scope reaches its ceiling, the largest process in it is killed and the session carries on.heavyjobs started from a session are limited only by their own caps.systemd-runmust be on the launchPATH. Sessions already running keep their old setup until they are relaunched. - Claude Code sessions are told when the OOM killer kills their commands, and probes watch other sessions. Every OOM kill of a command a session started (in its own session scope, or in a
heavyjob it launched) is reported to that session: the report wakes its main conversation even when it sits idle, and a session that ended gets it when it resumes. A Bash call that dies with status 137 during such a kill is labeled for the conversation that made it, the main one or a subagent, naming any other Bash call that was running at the kill.claudewheel probe create oom-kill --session <uuid>or--all-sessionswatches other sessions' kills until a required--deadline(or--count,--until-watched-ends,--until-file, orprobe stop);probe subscribeandprobe unsubscribeadd and remove sessions, and a subscription made by a subagent reaches that subagent.probe listshows every probe, every undelivered or expired report, and every kill no session took, and the sessions overview counts each session's undelivered reports. The kills are read from the user journal byclaudewheel-probe-runner.service, whichclaudewheel deploy-hooks --all(ordeploy-hooks claudewheel-probe-runner.service) installs, enables, and starts, andclaudewheel healthchecks;systemctl --user stop claudewheel-probe-runner.servicestops it.heavynames the session that started a job in the job's scope description. Profiles get the two new hooks at their next launch orclaudewheel patch-profiles; redeploy the hook scripts and the service withclaudewheel deploy-hooks --all --force-overwrite. claudewheel move-session <session> <directory>moves one Claude Code session to another project directory. It takes the session's full lowercase id and an existing directory, renames the session's transcript and folder into that directory's session store (in the sameprojectsdirectory the session was found in, so a session of thedefaultprofile stays in~/.claude/projects), appends therelocatedrecord C...
v0.33.0
A guardrail rule that refuses a shell sleep in every managed profile.
Context
An agent that runs sleep to wait for something is spending a turn on
nothing: the harness reports background work when it finishes, and the
state being waited on can simply be read. The new hard-deny rule refuses
sleep wherever it begins a shell command and answers with that steering,
while a word that merely contains "sleep" -- nosleep, ./sleepwalker,
echo sleep, grep sleep file -- still runs.
Features
- Every managed profile now refuses a shell
sleep. The guardrail hook deniessleepwherever it begins a shell command -- at the start, after a separator, or opening a subshell -- and tells the agent to read the state it is waiting on instead of padding the turn; a word that merely contains "sleep" still runs.
Fixes
- The package metadata names the repository where it actually lives. The repository moved to the stricttools organisation, so the npm page's repository and issue links pointed at the old owner, and a publish whose build attestation named the new one was rejected.
v0.32.2
The tool describes itself with one sentence everywhere including --help, and its documentation moved onto selfdoc's .stricttools/ layout.
Fixes
- The tool describes itself with one sentence everywhere, including
--help. The--helpheader, package metadata, README and docs site now carry the same description.
v0.32.1
v0.32.0
A machine-wide sessions table and per-session lifecycle store, launch facts in the child environment, hook-script fixes, and the project now describes itself consistently on PyPI, npm and in its README with its docs at the unified site.
Features
- New feature. Launched sessions now record their own start and end in claudewheel's per-session lifecycle store, through two new Claude Code hooks (
hook-session-start,hook-session-end).claudewheel patch-profilesdeploys and wires them;claudewheel healthreports a profile that is missing either. - New feature. A launched session's environment now carries what claudewheel chose for it --
CLAUDEWHEEL_LAUNCH_PROFILE,_VERSION,_MODEL,_PERMISSIONSandCLAUDEWHEEL_LIFECYCLE_DIR-- so the session lifecycle record names the profile, version, model and permissions mode behind every session. A selection you did not make sets no variable. - Machine-wide sessions table. The
Sscreen now lists every Claude Code session on the machine -- across all profiles, plus the sessions recorded in the lifecycle store -- as a framed, scrolling table with state, kind, directory, version, model, age and memory columns. Enter expands a row into its details,mmarks a session on hold, blocked or done,areveals the finished ones, andpprunes the registry files of the crashed ones.
Fixes
- Session lifecycle hooks record names faithfully. A session display name containing a tab, newline, carriage return or backslash is now recorded byte-for-byte; the hooks print their own diagnostic instead of a bash
HOME: unbound variableabort when no HOME,CLAUDEWHEEL_LIFECYCLE_DIR,CLAUDEWHEEL_CONFIG_DIRorCLAUDE_CONFIG_DIRis set; and a compaction or an unrecognized SessionStart source no longer creates the lifecycle directory. - Sessions table. The
Startedcolumn no longer truncates a long age: a session up for23h 59mor100d 0hreads in full instead of23h 59m a…. - Sessions table. Refreshing no longer moves an expanded row's details onto another session: the open row is followed by its own session, and collapses when that session stops being listed.
- The project describes itself consistently on PyPI, npm and in its README. The three registry surfaces carried three different one-line descriptions, PyPI had no Documentation, Issues or Changelog links, and the README opened with a fragment instead of a definition.
- Documentation links point at the unified site. The declared docs base was the retired per-project host; it is
https://smmh.dev/claudewheel/now, so generated sitemaps, feeds and llms.txt name the address that serves the pages.
v0.31.0
Every managed profile now disables Claude Code's agent view and its on-demand daemon, and every profile session launches without auto-generated session titles.
Context
A single left-arrow press on an empty prompt in Claude Code 2.1.263 moves a
running interactive session into a daemon-managed background session, opens
the agents view and forces the fullscreen renderer, with no confirmation once
the prompt has been idle. The canonical settings model now carries
disableAgentView so patch-profiles and the launch health check keep it off
everywhere. The auto-generated session title, which the same path promoted
into a name shown on the prompt bar with no display switch, is turned off at
launch through CLAUDE_CODE_DISABLE_TERMINAL_TITLE.
Features
- Agent view disabled in every profile. The canonical settings model now sets
disableAgentView: true, sopatch-profilesturns off Claude Code's agent view,--bg,/background, the left-arrow background gesture and the on-demand daemon in every managed profile, and the launch health check reports a profile that drifts from it. - No auto-generated session titles. Every profile session claudewheel launches now carries
CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1, which stops Claude Code from generating a session title and from rewriting the terminal title; names set with--nameor/renamestill apply.
v0.30.1
The git stash guardrail no longer tells agents to park work in progress on a temporary branch.
Fixes
- Stashed work no longer gets steered onto a temporary branch. The
git stashguardrail's deny message told agents to commit on a temporary branch; it now says to commit the work in progress on the current branch withsafegit commit.
v0.30.0
Quieter Claude Code sessions: launches disable the client self-updater and feature-flag evaluation, Remote Control auto-connect and spinner tips are off in every managed profile, the post-update summary is suppressed, and the launcher no longer offers plan mode.
Context
Claude Code 2.1.263 shows several startup notices that a claudewheel user
never wants: an auto-updater that installs over claudewheel's managed
versions, a server-delivered model-upsell tip, Remote Control connection
status, and a post-update changelog summary after every version switch.
Each was traced to its actual switch in the client. The updater and the
feature-flag system are only reachable through environment variables, so
the launch injects them; Remote Control auto-connect and spinner tips are
settings.json keys, so they joined the canonical model that the exact
reconcile enforces; the post-update summary has no switch at all and is
prevented by marking the launched version as already seen before exec.
Plan mode cannot be removed from the client's own Shift+Tab cycle, so the
launcher stops offering it instead, and a stale saved plan selection is
reset to default so it can never fall through to a bypass launch.
Breaking
planis no longer offered in the permissions segment. The launcher offersbypassanddefault; an existing options.json is migrated.planandautoremain accepted when pinned or passed with--set.
Features
- Quieter launches. Every claudewheel launch now sets
DISABLE_AUTOUPDATER=1andDISABLE_GROWTHBOOK=1, so Claude Code no longer self-updates over claudewheel's managed versions and no longer shows the server-delivered model-upsell tip (Remote Control is disabled as a side effect). - Remote Control and spinner tips off by default.
remoteControlAtStartupandspinnerTipsEnabledare now canonical settings keys: new profiles get both set to false,patch-profiles/reconcile-permissionsmake them exact in every managed profile, andhealthreports drift. - No more post-update summary. Before launching, claudewheel marks the launched Claude Code version as seen in the profile's
.claude.json, so the 'Updated to latest. Got N features...' banner no longer appears after a version switch.
Fixes
- A stale
planlaunch selection now resets todefault. Previously it restored unselected and the launch fell through to the default bypass flags.
v0.29.0
The model picker now discovers newly available Claude models from the Anthropic API on its own and orders them by release date.
Context
Previously every new Claude model had to be hand-added to the launcher's
hardcoded list, so new releases (most recently Fable 5.1) were invisible
until someone edited defaults. The picker's list is now the accumulated
values list in options.json -- append-only, seeded from the built-in
defaults, extended by a background fetch of the Anthropic models endpoint
using stored profile tokens, and never shrunk. Release dates from the API
drive a newest-first display order. Alongside the feature, the
minimum-CLI-version facts were unified onto a single built-in table that
feeds both the picker's dimming and the pre-launch guard through one
shared version resolution, so the two can no longer disagree.
Features
- Model auto-discovery. The model picker asks the Anthropic API which models your account may use, adds any it has not seen before to your option list, and orders the list by release date, newest first. The list only grows: a model that stops being served stays selectable, and an offline launch offers everything a previous one discovered.
- Models needing a newer Claude Code are dimmed in the picker. A model whose minimum CLI version is above the one you have selected or installed now renders unavailable in the model segment, the same table that already blocked such a launch at the pre-launch check.