Skip to content

Next Release - #4576

Open
rtk-release-bot[bot] wants to merge 60 commits into
masterfrom
develop
Open

rtk-release-bot[bot] wants to merge 60 commits into
masterfrom
develop

Conversation

@rtk-release-bot

@rtk-release-bot rtk-release-bot Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Feats

Fix

Other

rhishi99 and others added 30 commits August 20, 2026 22:41
The Windows stack-size reservation had two problems that only surface off
the MSVC toolchain.

`#[cfg(windows)]` in a build script describes the machine running the
build, not the machine the binary is for, so cross-compiling to Windows
from Linux silently skipped the flag while a Linux-targeted build on a
Windows host wrongly emitted it. Key the check off CARGO_CFG_TARGET_OS
instead, which is the target.

The flag itself is also toolchain-specific. `link.exe` understands
`/STACK:`, but the MinGW `ld` behind `x86_64-pc-windows-gnu` does not --
it reads the argument as a filename and fails the link with:

    ld.exe: cannot find /STACK:8388608: No such file or directory

Select `-Wl,--stack,<bytes>` when CARGO_CFG_TARGET_ENV is `gnu` and keep
`/STACK:` otherwise. CI never caught this because windows-latest defaults
to MSVC.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Agents gate on exit status, and hooks replace a command with whatever
`rtk rewrite` returns, so the rewrite must exit with the raw command's code.
Run a matrix of rewritten commands (git, ls, grep, wc, cat/head -> read,
find, plus `&&`/`;` chains and python3 one-liners when available) raw and
rewritten in a sandboxed repo and require identical exit codes. A second
test fails if the cases stop exercising the rewrite path, so the check
cannot silently degrade into comparing `sh` with itself.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WcTsSr2cKxstnvgXk2bP88
Clap adds -h/--help and a help subcommand to every subcommand it builds. On a
subcommand that exists only to compress another tool's output those tokens are
not RTK's to answer: grep -h is --no-filename, ls -h and tree -h are
--human-readable, and git help log is a real subcommand. RTK replied with its
own usage on stdout at exit 0, so an agent that only ever typed grep -h (the
hook adds the prefix) read RTK's help as grep's matches. Only psql and ctest
had opted out, one bug report at a time.

release_meta_flags now walks the clap tree and releases those flags on every
subcommand that forwards to a native tool, detected structurally rather than
from a list. RTK's own commands keep their help, and rtk help <cmd> still
reaches RTK's usage for a wrapper.

Forwarding the flag exposed a second half: filters that summarise found no
diagnostics in a help page and printed their empty summary instead, so
cargo test --help returned nothing at all. args_utils::asks_tool_for_help
guards those entry points and defers to runner::run_passthrough.

Fixes #4198
Drops the docs and awareness-text changes: rewording the "always safe" claim in
the agent instructions is a separate concern from the flag collision, and the
README and TECHNICAL edits were not needed to ship the fix.

release_meta_flags no longer recurses. disable_help_flag, disable_version_flag
and disable_help_subcommand are all global settings in clap, so one call already
covers the whole subtree.

asks_tool_for_help now reads -h as a help request. It only read the long
spellings before, so cargo build -h still reached the build filter and came back
as "cargo build (0 crates compiled)". ls and tree use the long-only form, since
their -h is --human-readable.
The guard was repeated at 41 filter entry points. 38 of those modules already
run their child through runner::run, which holds the built Command and so can
answer the question itself: requests_help reads the program name and the argv
before the boundary, and swaps the mode to Passthrough.

That leaves explicit guards only where the filter runs the child itself rather
than through the runner: git, find, pip, uv and dotnet. requests_help_args is
the same rule for those callers, so there is one definition of what a help
request is.

-h is a request everywhere except psql, ls, tree and grep, which spell
something else with it. RTK's own package-runner prefix (pnpm exec --,
npx --) is skipped so the -- it ends with is not read as the caller's
boundary.
Two layers, mirroring the two halves of the bug.

Over the clap tree: every wrapper path crossed with -h, --help, -V, --version
and help, dropped at every position of nine argv shapes, asserting RTK never
answers with its own usage and that the token still reaches the leaf. Roughly
14k parses, read off the built tree so a new subcommand joins on its own. The
inverse is pinned too, or releasing everything would satisfy it.

Over real binaries: rtk <tool> --help spawned against the tool itself for 24
pairs, comparing exit code and asserting the page was not collapsed to a
summary. Tools that are not installed are skipped, and commands are spawned
directly so a grep shell function cannot stand in for the binary.

Both were mutation-checked. Removing release_meta_flags fails the first with
"RTK answered `rtk ls -h` itself"; removing the runner guard fails the second
with "rtk cargo build -h returned 32 bytes of the tool's 3241"; dropping tree
from DASH_H_IS_NOT_HELP fails the filtering check.
Three fixes to the tests added in the previous commit, all found by CI.

semgrep's dynamic-command-execution rule forbids Command::new(<variable>)
anywhere under src/, test modules included. The runner tests built a Command
only to feed requests_help, so they now exercise requests_help_args, which
takes the tool name as a string, and one adapter test keeps a literal program.

Windows names the binary rtk.exe, so the "Usage: rtk " marker never matched.
That failed the positive assertion and, worse, made the negative one pass for
the wrong reason. The marker now stops at the stem.

on_path joined PATH entries with a bare name, which on Windows finds the
extensionless npm script rather than npm.cmd and fails the spawn with error
193. It now walks PATHEXT there. The cases whose Windows namesake is an
unrelated program (find, tree) or needs a Unix toolchain (grep, ls, wc) are
skipped, and the two tests asserting GNU/BSD flag semantics are unix-only.
Signed-off-by: tayfuryldz <yildiztayfur668@gmail.com>
Signed-off-by: tayfuryldz <yildiztayfur668@gmail.com>
Signed-off-by: tayfuryldzz <yildiztayfur668@gmail.com>
Resolves the test-import conflict in src/main.rs by keeping develop's
test_isolation import and dropping clap::Parser, which this branch no longer
needs.

The help fuzz now spawns through common::rtk_command() rather than naming
CARGO_BIN_EXE_rtk, so the child writes to the test's scratch data directory
instead of the contributor's own. core::test_isolation fails the suite on a
spawn that skips it (#3758), which is what turned the merged branch red.
…n capture too

Review round 1 on #4348.

Blocker 1(a): a help request still reached filters that run the child through
exec_capture rather than runner::run, and several answered with a plausible
result: jest returned 2161 bytes of its 26881, pnpm outdated reported "48
outdated packages" parsed out of a help page, wget reported a download. The
guard now also sits in stream::capture, which every exec_capture caller passes
through. exec_capture_probe is the way out for a command RTK issues itself: a
version probe asks --version to read the answer, not to show it, and golangci
runs one.

Blocker 1(b) and 1(c): asks_for_usage goes through arg_tokenizer instead of
comparing raw strings, per rule 6 in rust-patterns.md. A per-tool spelling
picks the dialect, so dotnet's -? and /? and Go's -help are read as the atomic
names they are; a flag carrying a value no longer counts, so
`cargo install x --version 1.2.3` stays filtered; and a tool that forwards past
-- gets that region scanned as the argv it is, so `cargo test -- --help` is
libtest's usage while `grep -- --help` is still a pattern.

git and dotnet keep their own guards rather than relying on capture: by then
RTK has injected its globals, and git's --no-pager turns the man page into a
one-screen usage. pip's guard goes, covered by capture.

kubectl/oc `extra` now carries only a usage request. Anything else runs as the
caller typed it, matching kubectl's own "unknown command" rather than silently
reaching a `get` pinned to -o json.

Blocker 2: pins for what the mutations survived. The forwarded git argv
including globals and the stash subcommand, every git_name arm,
forwarded_dotnet_args, the dotnet spellings, the k8s alias split, RTK's own
help on the commands that wrap nothing (read, diff, log, env), the forwarded
boundary and the value forms. The integration check compares the tool's own
first line rather than a length, so a page from the wrong subcommand fails.
Moving the scan onto the tokenizer brought short-flag clustering with it, and
that read the h inside another flag as a request: `find -maxdepth 2` came back
as raw find output instead of the compressed listing, and `mvn
-Dhttp.proxyHost=…` and `gradlew -Dhttp.x=1` carry one the same way.

A clustered h is almost never the flag, so it counts only when the argument is
exactly `-h`. The cost is `cargo -qh`, which no longer registers; the tools
that spell help with a single-dash long name (`go -help`, `dotnet -?`) are
unaffected, since they are read in the MSBuild dialect where the name is
atomic.
On Windows this harness reaches pip.EXE where rtk reaches pip, so the usage
line the two print differs by that spelling while the page is the same. The
anchor is compared with it removed. The check still fails on a page from the
wrong subcommand, which is what it is for.
…ight

`walk_exceeds_limit` asks git whether `rtk git log`'s ten-commit cap
actually cut anything. It was wrong in both directions: silent on walks
the cap had gutted, and loud on walks it never touched.

Two kinds of walk, two questions. Without a diff-based filter (`-S`,
`-G`, `--diff-filter`, `--find-object`) the probe skips past the limit
and asks whether anything is left. With one it has to count instead,
because git applies `--skip` before such a filter and `--max-count`
after it. Most of what follows is the counting branch getting an honest
count, and the notice being owed at all.

What the probe forwards. It may drop what only decides how git prints,
and must keep what decides which commits come back -- a distinction the
flags do not respect. `--line-prefix` and `--graph` are dropped because
both put something in front of every record, and `--graph` draws its
rail with the characters a patch begins its lines with (`|` before a
diff body, `-` before a removed line), so no trimming rule serves both.
But `--graph` also turns on parent rewriting, which decides which
commits come back: one path here holds a single commit without it and
fifteen with it, so the probe asks for `--parents` instead, which turns
on the same rewriting and prints nothing beside a `%H` record.
`--reverse` is dropped because it moves `--max-count`: git drains the
whole walk before showing anything, so the count bounds the walk rather
than what came through the filter, and eleven records became six
against a selection of 836. `--check` joins `--exit-code`, whose
non-zero exit reports on the diff rather than on the command. And
`-c`/`--cc`/`--remerge-diff` and every `--diff-merges` format but `off`
are kept whenever the walk selects by diff: they give merge commits a
diff, and a diff-based filter selects on the diffs the walk produces.
On a repository whose merges carry content from neither parent, `git
log -S evil` selects nothing where `git log -c -S evil` selects 14. Off
such a walk they are still dropped, which spares a configured
`diff.external` the eleventh run of a ten-commit window.

The user's own `--skip` is now reproduced in the counting branch too.
RTK's has to win, so the user's is stripped and re-applied -- but only
the other branch re-applied it, and the count covered commits they had
already skipped past: `--skip=20 -S NEEDLE` leaves five commits and
announced a cap of ten.

What counts as a commit in the answer. Records are split on NUL as well
as newline, because `-z` terminates them that way and the whole walk
had been read as one line matching nothing. A record is a commit only
at an object name's exact length -- `%H` does not abbreviate, for
neither `--abbrev-commit` nor `core.abbrev` -- which keeps out the
paths `--name-only -z` puts in a record of their own, where a file
called `cafebabe01` had counted as a commit. And only at column 0,
which keeps out the diff context of a probe that kept a merge-diff
flag, in the case where that context is itself full-length hex: a file
of checksums.

Last, the notice is gated on git not having refused. The probe prunes
`--pretty`/`--format`/`--output`, so it can succeed on arguments git
rejected outright, and the notice landed under git's own `fatal:` line.
Failure is not that test: git refuses with 128, 129 or 128 + n and
keeps the small codes for what the diff machinery found in a walk it
ran and printed in full -- 1 for `--exit-code`, 2 for `--check`.

The strip these go through is the one the `diff`/`show` header already
used, lifted behind a predicate so the probe can widen it without
widening that header's own idea of patch shape. Going through it is
what lets `-c` be dropped at all: a short flag shares its argument with
whatever was clustered onto it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review round 2 follow-up, found by differential fuzzing against develop.

git's cap-notice probe appends the caller's args to an argv RTK built, so a
clustered -h reached it and the guard answered for the probe: `git log -hp`
printed git's usage twice and `-ph` returned 129 where git returns 128. The
probe and the cat-file blob probe now capture unguarded.

`--help=x` is a request again. Only a separate value disqualifies one, so
`cargo install x --version 1.2.3` still filters while `jest --help=x` returns
jest's own 1936 bytes instead of 95.

git's -m, --message, -F and --file carry values, so `git commit -m "--help"`
is a message and stays filtered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three conflicts, all additive on both sides:

src/main.rs keeps develop's proxy_label alongside this branch's K8sAlias
version of build_k8s_namespace_args.

go_cmd.rs and golangci_cmd.rs keep develop's shell imports alongside
exec_capture_unguarded.

The help fuzz now builds its native side with develop's common::native_command,
so both sides of every comparison run in the same environment.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The check compared RTK's output against half the size of `df -h`, which is
1627 bytes here and 436 on the CI container, where a 438 byte summary then
read as unfiltered. It now asserts the property instead: the output differs
from df's own and starts with RTK's marker.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The err/summary pin used `df -h`, which is 436 bytes on a CI runner and
1.6 KB on a laptop. RTK rightly returns output raw when summarising it
would be larger, so on ubuntu the assertion read RTK's correct fallback
as a guard failure. Generate a 60 directory tree and probe `du -h` on it
instead: the summary is 258 bytes against 1450 raw with short /tmp paths,
so the marker means the guard held rather than that the input was long.

Mutation checked: making the guard ignore `unguarded_help` fails it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tion

Every Windows target reports target_env `msvc` or `gnu` (gnullvm reports
`gnu`), so msvc is the only one with its own spelling. Matching on it makes any
other environment take the `-Wl,--stack` form the gcc and clang drivers accept.

Read the reservation back from the built rtk.exe's PE header in a Windows-only
test, so a linker that rejects or drops the flag fails a test rather than
shipping a 1 or 2 MiB stack.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The test matrix links windows with link.exe only, so a stack flag that GNU ld
rejects (the failure build.rs used to have) cannot fail CI. Add a windows-latest
leg that tests x86_64-pc-windows-gnu; the runner's host stays msvc, so build.rs
also runs with host and target apart.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…p guard decisions

`cargo install x --version=1.2.3` was read as a usage request and ran unfiltered, while `--version 1.2.3` stayed filtered; cargo reads both as the version to install. An attached value on a flag the value rule names is now a value too.

Pins three decisions no test reached: git's message and file flags carry a value, `rtk test` reads the command it was given without the usage guard, and `rtk git log`'s cap-notice probe leaves a clustered `-h` to git. The help fuzz tests now create their directories under the scratch directory instead of fixed names in the system temp dir, which concurrent runs shared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bumps [encoding_rs](https://github.com/hsivonen/encoding_rs) from 0.8.35 to 0.8.42.
- [Commits](hsivonen/encoding_rs@v0.8.35...v0.8.42)

---
updated-dependencies:
- dependency-name: encoding_rs
  dependency-version: 0.8.42
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [ignore](https://github.com/BurntSushi/ripgrep) from 0.4.25 to 0.4.32.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](BurntSushi/ripgrep@ignore-0.4.25...ignore-0.4.32)

---
updated-dependencies:
- dependency-name: ignore
  dependency-version: 0.4.33
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.228 to 1.0.229.
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](serde-rs/serde@v1.0.228...v1.0.229)

---
updated-dependencies:
- dependency-name: serde
  dependency-version: 1.0.229
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
fix(git): only announce the log cap on a walk git ran, and count it right
KuSh and others added 3 commits October 15, 2026 00:40
…ers (#4281)

Claude Code matches a deny or ask rule past any leading assignment and past a
fixed set of wrappers — `timeout`, `time`, `nice`, `nohup`, `stdbuf`,
`command`, `builtin`, `noglob` and a bare `xargs` — so `Bash(git push *)` stops
`HUSKY=0 git push` and `timeout 30 git push` as well as `git push`. RTK's gate
matched the segment as written and nothing else, so every one of those forms
fell through to Default; under a host that treats Default as its own decision,
as #3909's OpenClaw does, they auto-apply.

The rewrite already looked through the same prefixes: `timeout 30 git push`
became `timeout 30 rtk git push` while the gate did not recognise `git push`
inside it. That was two readings of which command a line runs, and the gap
between them is this bug. The deny and ask loops now also try every reading
`matching_readings` gives: the rewrite's own peels — its env peel, its keyword
prefixes, its wrapper table — applied one prefix at a time, each assignment and
each `env` word a prefix of its own, each intermediate command kept. Where both
look through a prefix, the gate and the rewrite now read the same command
behind it, and a rule may name any layer: `HUSKY=0 git push *` stops
`env HUSKY=0 git push`, and `nohup HUSKY=0 git push` too, where denying is
stricter than the shell, since nohup looks for a program named `HUSKY=0`. The
readings start after the split's leftover grammar is gone, since
`{ HUSKY=0 git push; }` reaches the gate as `{ HUSKY=0 git push`. They are
computed once per segment, not once per rule, and stop after 32 prefixes; past
that the command behind them is unread, so where a deny or ask rule exists the
verdict is at least Ask and an allow rule on the outer wrapper cannot answer for
it. With no deny or ask rule, none of this is read.

Two wrappers the host strips were not in the rewrite's table, for a reason that
still holds: `stdbuf` exists to unbuffer the wrapped command's output, which
routing through rtk would buffer, and `xargs` runs whatever it is handed.
Recognising a command is not the same decision as rewriting it, so they sit in
a match-only table the rewrite never consults. `xargs` is peeled only in its
bare form, as the host does; any option makes the wrapper grammar give up.

The line is drawn at the shell. `env`, `exec` and `nocorrect` are peeled too,
though the host's list stops short of them; each runs the next word as the
command. A program's own arguments are not: `git -C . push` stays `git`, as the
host documents, since reading past it would mean knowing every program's option
grammar.

Allow is deliberately left as it was. The host matches allow past known-safe
variables only, and peeling a wrapper for it would let `timeout 30 <cmd>`
inherit `<cmd>`'s allow rule — so the peel can only make a verdict stricter.

The gate reads prefixes with the rewrite's own peels, so it stops where they
stop; there it reads the command as before, so no verdict is looser than it
was. A line setting more than 32 variables before its command now prompts
where a deny or ask rule exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….0.229

chore(deps): bump serde from 1.0.228 to 1.0.229
…0.4.33

chore(deps): bump ignore from 0.4.25 to 0.4.32
@rtk-wshm-sync-bot rtk-wshm-sync-bot Bot added bug Something isn't working git labels Oct 14, 2026
@rtk-wshm-sync-bot

Copy link
Copy Markdown

wshm · Automated triage by AI

📊 Automated PR Analysis

🐛 Type bug-fix
🟡 Risk medium

Summary

This PR bundles the 'Next Release' changes, primarily a fix to the git log cap announcement logic so RTK only reports a cap when git actually ran the walk, and counts commits correctly by generalizing flag-stripping and handling --graph/--parents rewriting, NUL-separated records, and --skip semantics for diff-filtered walks. It also bumps Cargo.lock dependency versions (ignore, serde, serde_core, serde_derive, syn).

Review Checklist

  • Tests present
  • Breaking change
  • Docs updated

Analyzed automatically by wshm · This is an automated analysis, not a human review.

KuSh and others added 6 commits October 15, 2026 00:53
…g_rs-0.8.42

chore(deps): bump encoding_rs from 0.8.35 to 0.8.42
Bumps [windows-sys](https://github.com/microsoft/windows-rs) from 0.59.0 to 0.61.2.
- [Release notes](https://github.com/microsoft/windows-rs/releases)
- [Commits](https://github.com/microsoft/windows-rs/commits)

---
updated-dependencies:
- dependency-name: windows-sys
  dependency-version: 0.61.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
fix(permissions): match deny and ask rules past assignments and wrappers (#4281)
…-sys-0.61.2

chore(deps): bump windows-sys from 0.59.0 to 0.61.2
Bumps [which](https://github.com/harryfei/which-rs) from 8.0.1 to 8.0.6.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](harryfei/which-rs@8.0.1...8.0.6)

---
updated-dependencies:
- dependency-name: which
  dependency-version: 8.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
fix(cli): hand -h, --help and help to the tool each subcommand wraps
@CLAassistant

CLAassistant commented Oct 14, 2026 •

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
5 out of 6 committers have signed the CLA.

✅ rhishi99
✅ Protocol-zero-0
✅ tayfuryldz
✅ KuSh
✅ b3hz4d
❌ Adrien EPPLING


Adrien EPPLING seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

KuSh and others added 15 commits October 15, 2026 01:44
….0.6

chore(deps): bump which from 8.0.1 to 8.0.6
…p/actions/upload-artifact-7

chore(deps): bump actions/upload-artifact from 4 to 7
…p/actions/checkout-7

chore(deps): bump actions/checkout from 4 to 7
…p/googleapis/release-please-action-5.0.0

chore(deps): bump googleapis/release-please-action from 4.4.1 to 5.0.0
fix(build): send the MinGW linker --stack, not MSVC's /STACK:
…he python probe

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
git 2.56 answers `-h` with its usage and exit 0, where every earlier
release exited 129. `rtk git log` read "git refused the walk" from an
exit code of 128 or more, so on 2.56 `rtk git log -hp` ran the cap
probe after the usage text, the probe got the usage again, read it as
commits left over, and appended "[rtk] capped at 10 commits" under it.
`a_clustered_h_is_answered_by_git_once` fails this way on the macOS and
Windows runners that moved to git 2.56 (2.55 still passes).

A `-h` flag, alone or in a cluster, now counts as a walk that never ran.
Only a flag token does: `--grep -h` and `-- -h` still run the walk and
still get the notice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-regression-test

test(hook): pin exit codes across rtk rewrite (#3492)
fix(git): no log cap notice under git's usage on git 2.56
run_cli moved from src/main.rs to src/lib.rs on develop, which also
skips the hook-status warning for Commands::Hook already; the telemetry
reorder is carried over to its new home.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maybe_ping is inert in any build without RTK_TELEMETRY_URL, test builds
included, so no test could tell whether a hook command pings. The
decision now lives in pings_telemetry, taken on the parse result, with
one call site; the tests cover parsed hook commands and the invocations
clap rejects (help, version, passthrough, a hook with a bad flag).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(hook): skip background checks in hook commands
Claude Code's worktree-isolation guard evaluates the command after the
PreToolUse hook has rewritten it, and it can only verify git when it is
spelled plainly. Every `rtk git …` the hook emitted was therefore refused
as "cannot be shown not to be git", so no git command could run from a
worktree-isolated session.

The payload carries no isolation flag, but managed worktrees always live
at `<repo>/.claude/worktrees/<name>`. When the payload cwd has that shape,
the Claude hook adds `git` to the exclude list so it passes through
untouched while the rest of the chain is still rewritten. Other hosts
pass no cwd and are unchanged.

Fixes #3864

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pin the worktree exclusion: another git verb, a non-worktree .claude
directory, and the user's own exclude_commands kept alongside it. The
doc comment now says a worktree placed outside .claude/worktrees is not
detected, and the path check uses CLAUDE_DIR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(hooks): leave git unrewritten in Claude Code managed worktrees
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working git next-release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants