You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-install no longer bounds the -cli-url download at 5 minutes by default, so a slow-but-honest download the reference completes now succeeds rather than failing with cliError "download failed: context deadline exceeded (Client.Timeout or context cancellation while reading body)"; opt-in via -cli-download-timeout or the cli-download-timeout key in claustrum.conf. (#246)
-install no longer bounds the <cli> --version runnability probe at 15 seconds by default, so a slow-but-working CLI installs instead of failing with cliError "installed cli at <path> is not runnable" and having its staged binary deleted; opt-in via -cli-probe-timeout or the cli-probe-timeout key in claustrum.conf. (#245)
-install no longer caps the decompressed CLI or the download body at 512 MiB by default, so a large CLI installs instead of failing with a cliError the reference daemon never produces; opt-in via -max-cli-bytes or the max-cli-bytes key in claustrum.conf. (#238)
files.extract_tar no longer caps extraction at 512 MiB by default, so a large tree extracts instead of failing with an error the reference daemon never produces; the cap is now opt-in via -max-extract-bytes or the max-extract-bytes key in claustrum.conf. (#236)
files.read no longer refuses a non-regular path by default, so reading a character device such as /dev/null returns {"content":"","exists":true} as the reference daemon does instead of a claustrum-only -32602 "files.read: not a regular file"; the guard is now opt-in via -files-read-regular-only or the files-read-regular-only key in claustrum.conf, which restores the bound on a writerless FIFO and on unbounded device reads. (#250)
The daemon no longer bounds every git invocation at 60 seconds by default, so a slow-but-honest git on a large or cold repository completes instead of being SIGKILLed into a claustrum-only -32603 "signal: killed" (or a git worktree remove timed out after …) where the reference showed no such deadline at the durations probed; now opt-in via -git-timeout or the git-timeout key in claustrum.conf. (#248)
-install no longer bounds the linux ldd --version libc probe at 5 seconds by default, so a slow ldd's answer stands instead of being killed into a fallback classification — the reference daemon showed no such deadline against a stalled ldd at the durations probed; the deadline is now opt-in via -libc-probe-timeout or the libc-probe-timeout key in claustrum.conf. (#251)
Fixes
The exit stream frame now arrives at most 5 seconds after a spawned process exits, instead of waiting forever when the command left a background grandchild holding its stdout. (#186)
A reply's id is now the request's id decoded and re-encoded rather than the raw bytes echoed back, so a non-integer id such as 1.0, 1e2 or {"b":1,"a":2} is canonicalized exactly as the reference returns it. (#188)
-install now creates the CLI directory chain owner-only (0700) like the reference, instead of 0755 which left the installed CLI world-traversable. (#191)
A non-200 CLI download now reports download failed with status <code> like the reference, instead of a differently-worded message that also leaked the download URL into the __INSTALL_RESULT__ line. (#197)
A zero-byte -token-file is now a fatal startup error instead of producing a daemon that listens but can never be authenticated to, and the daemon now logs a failed token-file unlink, a child stream read error, and a discarded stdin queue rather than passing over them in silence. (#200)
Report the reference daemon's error text for files.list on a non-directory, files.extract_tar failing to open the archive, and process.spawn with an unusable cwd. (#175)
Expand a leading ~ to the home directory on every path parameter, so files.*, git.* and process.spawn no longer fail or create a literal ~ directory. (#176)
A ~-prefixed path is now cleaned lexically like the reference — ~/link/../x means ~/x even when link is a symlink, ~//f and ~/a/./b and a trailing ~/wt/ collapse, and bare ~ alone stays verbatim — which is wire-visible on eight frames, most sharply on files.stat/files.validate where a trailing separator on a regular file previously answered not a directory and now succeeds. (#205)
files.extract_tar now carries the reference's create <entry>: prefix when an archive entry's target lands on an existing directory, so the error field reads create ../sub: open <dest>: is a directory instead of the bare Go error. (#226)
files.extract_tar now refuses a Windows volume or UNC share root as destDir — previously only the literal / was refused, so C:\ passed the guard and reached the os.RemoveAll that clears the destination before extracting. (#225)
files.read now applies the reference's 256 KiB (262144-byte) default cap when maxBytes is absent, zero, or negative, instead of reading the file without any limit; an explicit positive maxBytes is still honored verbatim. (#189)
Wait for the login-shell PATH extraction before the first process.spawn builds its child environment, so the first command finds binaries in ~/.local/bin and nvm. (#168)
git.list_branches reads git's stdout only and reports a failed for-each-ref as -32603 exit status <n>, so a broken ref no longer lists git's warning: line as a branch and a corrupt refs database no longer returns that failure as branch names. (#213)
git.status and git.list_branches now recognize a bare repository and a .git directory as repositories, and git.worktree_create ignores a sourceBranch that is not a local branch instead of failing the request. (#178)
git.status now trims the whole porcelain output before splitting it, so the first change loses its leading space and every later one keeps it, matching the reference. (#185)
Keep the leading space on git.status porcelain lines so a client can tell a staged change from an unstaged change. (#167)
git.status now reads only git's stdout, so warnings git writes to stderr (an unreadable core.excludesFile, for example) no longer appear as entries in changes and no longer make a clean repo report as dirty. (#193)
The daemon now recovers from a panic in any request handler instead of crashing, replying -32603 "recovered panic: <v>" and staying up for other connections, so a handler bug can no longer orphan managed child processes or leave a stale socket behind. (#243)
-install no longer executes ldd when the musl loader marker already answers the question, and it consumes the local -cli-zst blob once decompression succeeds rather than only on a fully successful install — both matching the reference. (#216)
-install now removes leftover .fetch-* download temporaries, which previously counted against -cli-keep and could delete every real CLI version, and it prunes only after an install that succeeded. (#180)
-install stages the CLI at .fetch-<random> and sweeps stray *.zst blobs so leftovers no longer take a -cli-keep slot; an occupied cliPath is cleared instead of failing with a rename error; a failed cli-dir creation carries the mkdir cli dir: prefix; -cli-version must name a single entry inside -cli-dir, so a version reaching outside via .. or a symlink can no longer delete a directory there, and one the orphan sweep claims (.fetch-* or *.zst) is refused; the new CLI is renamed into place before the old one is cleared, so two installs in one cli-dir cannot leave it empty; if another install reclaims its staging file, it retries once instead of failing. (#196)
process.killAndWait clamps timeoutMs at 30000 ms instead of 600000 ms, so a caller asking for a longer grace against a signal-ignoring child now gets its exit frame at 30 s, matching the reference. (#214)
The login-shell PATH is now applied only to spawned children, not the daemon's own environment, so the daemon no longer resolves its own git through the user's PATH; a non-executable $SHELL falls back to a usable shell instead of failing extraction, and a missing PATH sentinel is logged with the shell's output. (#199)
Login-shell PATH extraction now gives up after 4 seconds instead of 10, matching the reference, so a slow login shell no longer delays the first process.spawn or hands spawned children a PATH the reference would not have applied. (#190)
-install now reports musl when a musl loader of any architecture is present, and reports no libc at all on macOS and Windows, matching the reference daemon. (#183)
process.kill and process.killAndWait now match signal names case-sensitively and no longer map QUIT to SIGQUIT, so a request naming quit sends SIGTERM like the reference instead of a SIGQUIT that dumps core. (#203)
Reject a negative offset on process.stdin and a negative fromSeq on process.reattach, which before silently dropped the first bytes of the child's stdin. (#173)
files.stat, files.read and files.validate now report a stat failure other than "does not exist" instead of the missing-path result — e.g. a path component that is a file. (#177)
Exited processes are now dropped from the process table 15 minutes after they finish, freeing their replay buffers, so process.reattach on a long-finished id reports found:false as the reference does. (#187)
process.killAndWait now waits 7 seconds for a SIGKILL'd process to be reaped instead of 5, matching the reference daemon, so a child that is reaped between those two points is reported as dead rather than still running. (#242)
process.reattach now transfers the frame stream to the reattaching connection like the reference, so a previously attached connection stops receiving instead of both getting every frame after a resume. (#202)
files.extract_tar now refuses a destDir that is or contains the home directory, so a tilde or relative path can no longer reach the recursive delete it performs before unpacking — paths under home, such as ~/.claude/…, are unaffected. (#231)
git.worktree_remove now refuses a worktreePath that is or contains the home directory, so a tilde or relative path can no longer reach the recursive delete it performs when git fails — the method previously had no path guard of any kind. (#232)
-serve now writes its output to remote-server.log beside the socket (mode 0600) instead of the launcher's stdout and stderr, and the file survives a graceful shutdown. (#181)
The per-process replay buffer counts its 16 MiB cap in serialized frame bytes, not base64 payload alone, so process.reattach's firstSeq matches the reference on small-frame workloads instead of retaining ~9% too many frames. (#215)
Cap the per-process replay buffer at 16 MiB instead of 50 MiB, so process.reattach reports the same firstSeq floor as the reference daemon. (#174)
git.info emits repoSlug only for a canonical github.com remote whose owner and repo pass the reference's charset rules, not for any remote URL with two path segments, so GitLab, Bitbucket, self-hosted, and www.github.com remotes report "". (#192)
claustrum -serve with neither -token-file nor -token-fd now daemonizes and refuses to start in the detached child, so the launcher reports its ~10s accept timeout as the reference does, instead of exiting immediately with the specific reason. (#217)
-serve now creates a missing socket directory (mode 0700) instead of refusing to start, and waits until the daemon is accepting before returning, so a client connecting immediately after launch no longer races an unopened socket. (#195)
claustrum now prefers zsh over bash when $SHELL is unusable and discards a login PATH whose extraction timed out, both matching the reference. (#212)
server.shutdown is no longer authenticated, matching the reference, so claustrum --stop --socket <sock> works with no CLAUDE_RPC_TOKEN; every other method still requires auth. (#206)
process.kill and process.killAndWait now deliver a non-KILL signal to the spawned process alone, not its whole process group, so a graceful stop no longer kills the background jobs the command started, while escalate:true still sweeps the group with SIGKILL as the reference does. (#194)
Pipelined process.stdin requests on one connection now reach the child in the order they were sent, instead of racing and scrambling the byte stream. (#201)
-stop now gives up waiting for the daemon's reply after 2 seconds like the reference instead of blocking forever, and no longer echoes that reply frame to stdout. (#198)
claustrum -stop now unlinks the socket path on every exit path — including when the dial fails and no daemon was ever reached — matching the reference, so a stale socket no longer blocks the next -serve from binding. (#217)
git.worktree_create now copies .claude/ and the files named by .worktreeinclude into the new worktree, which previously came up with tracked files only. (#182)
git.worktree_remove now deletes the branch given in branchName, including a branch that is not merged, in place of leaving it in the repository. (#179)
git.worktree_remove now removes the worktree directory itself when git refuses (e.g. a locked worktree) and reports success:false with an error when that cleanup also fails, instead of answering success:true while leaving the directory in place; a git worktree remove that hits claustrum's opt-in git deadline is reported rather than treated as a refusal, so a wedged git no longer triggers that cleanup. (#204)
Performance
-install streams the download to a temporary file and hashes it as it arrives, and hashes and decompresses the local -cli-zst blob straight from disk, so peak memory is flat in the blob size (measured 886 MB to 10 MB on a 400 MiB download) with no change to any cliError or install outcome. (#238)