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
Make revdiff and both Claude Code plugins (revdiff, revdiff-planning) build, run, and integrate cleanly on Windows 10/11 + WezTerm. The work is intentionally narrow: five concrete Go/code touchpoints, two PowerShell sibling scripts per plugin, and a documentation pass. No CI changes, no second binary, no terminal abstraction layer — we sit Windows logic next to existing Unix logic via Go build tags and .ps1 siblings to existing .sh scripts, so the macOS/Linux paths remain untouched and risk-free.
The audit (already in conversation context) confirmed that the heavy lifting — filepath.Join discipline, exec.Command style, modern bubbletea/lipgloss, os.UserHomeDir, os.CreateTemp("") — is already cross-platform. The remaining gaps are five surgical fixes plus PowerShell ports of the launcher scripts.
Architecture Decisions
Build tags over runtime.GOOS branching. Platform-specific Go code (TTY reattach, possibly path defaults if cleaner) lives in _windows.go / _unix.go files behind //go:build constraints. Keeps business logic free of platform conditionals and lets the Go compiler enforce mutual exclusion. Rejected alternative: if runtime.GOOS == "windows" branches inline — works, but pollutes call sites and resists test isolation.
os.UserConfigDir() rather than manual %APPDATA% resolution. The standard library already returns %APPDATA% on Windows, $XDG_CONFIG_HOME (or ~/.config) on Linux, and ~/Library/Application Support on macOS. We currently hardcode ~/.config even on macOS, which is non-idiomatic. To minimize blast radius, we keep the existing ~/.config/revdiff/ layout on Unix (Linux + macOS) and only switch to os.UserConfigDir() semantics on Windows, gated by runtime.GOOS == "windows". This avoids breaking existing macOS users who already have configs at ~/.config/revdiff/.
PowerShell siblings rather than rewriting the bash launcher.launch-revdiff.sh is 290+ lines of terminal-specific overlay code. Rewriting it as a Go binary or unifying it cross-platform was considered and rejected: too much risk to the existing macOS workflow, and a second binary complicates plugin distribution. Instead, launch-revdiff.ps1 is a from-scratch PowerShell file containing only the WezTerm path. Bash and PowerShell scripts are maintained side-by-side and a header comment in each links to its sibling.
wezterm cli spawn --new-tab for plugin hosting. Already locked in via PRD brainstorming. The new tab lives in the user's existing WezTerm window (so Claude stays visible), and the script can wait on the spawned pane id for cleanup. No wezterm start (steals focus, separate window) and no split-pane (less consistent with the existing kitty/wezterm bash overlay flow).
SKILL.md dispatches on $IsWindows. PowerShell defines $IsWindows natively in v6+. The SKILL.md (or the small loader script the harness invokes) checks platform and selects .ps1 on Windows, .sh elsewhere. The bash path stays the documented default so existing users see no change.
No CI Windows runner. Validation is manual on the author's Windows + WezTerm machine via the success criteria checklist. Adding windows-latest to GitHub Actions and shipping signed binaries are explicit follow-ups, not blockers.
Makefile is untouched.build.ps1 and test.ps1 are added in parallel. A Windows contributor uses the .ps1 files; a Unix contributor keeps using make. Two scripts, one source of truth (the same go build / go test flags), maintained by convention.
No new Go dependencies.golang.org/x/term was considered for cross-platform TTY handling but rejected — os.Open("CONIN$") on Windows and os.Open("/dev/tty") on Unix is two lines of code each, doesn't justify pulling a new module. Vendoring stays clean.
Technical Approach
Frontend Components
revdiff is a TUI with no web frontend, but the user-facing surface that needs Windows attention is:
Terminal rendering pipeline (bubbletea + lipgloss): no code changes required. Versions in go.mod (bubbletea v1.3.10, lipgloss v1.1.0, x/ansi v0.11.6) already drive ConPTY correctly on Windows 10 1809+. Validation only.
Plugin launchers (PowerShell): the user-visible entry point for both plugins. New file per plugin, identical UX to the bash flow.
TUI key handling on stdin mode: must reattach the keyboard via CONIN$ after consuming piped stdin. Without this fix, every key press goes nowhere on Windows.
Backend Services
revdiff has no network backend, but it shells out to git. Audit confirmed all exec.Command("git", ...) calls are list-form (not shell strings) and Go's exec package auto-resolves git.exe from PATH on Windows. No changes needed in diff/diff.go, diff/directory.go, diff/blame.go, or cmd/revdiff/main.go:502.
The Go-side changes are concentrated in one file (cmd/revdiff/main.go) plus two new build-tagged sidecars:
cmd/revdiff/main.go: modify defaultConfigPath, defaultKeysPath, defaultThemesDir to consult runtime.GOOS and route Windows callers through os.UserConfigDir(). Replace direct openTTY() body with a call to a build-tagged openInteractiveTTY() helper.
cmd/revdiff/main_test.go gains a small table-driven test that fakes the Windows branch via dependency injection or a build-tagged sibling test file.
Infrastructure
Build tooling: build.ps1 and test.ps1 at repo root. Each is ~20-30 lines of PowerShell wrapping the same go build / go test invocations the Makefile uses.
Vendoring: no changes; no new dependencies.
Plugin distribution: existing .claude-plugin/plugin.json and .claude-plugin/marketplace.json already point to skill paths that don't depend on the file extension, so adding .ps1 files alongside .sh files requires no manifest changes. A version bump to plugin.json/marketplace.json is deferred to the end of implementation per CLAUDE.md.
Implementation Strategy
Phasing
Phase 1 — Go core (parallel-friendly): Land the TTY split and config-path Windows-awareness first. Once revdiff.exe builds and produces the right paths via --dump-config, every other piece of work has something concrete to test against.
Phase 2 — Build scripts and plugin launchers (parallel after Phase 1):build.ps1/test.ps1, the launch-revdiff.ps1 + detect-ref.ps1 pair, and launch-plan-review.ps1 can all proceed in parallel because they touch disjoint files. Each gets validated independently against the revdiff.exe from Phase 1.
Phase 3 — Documentation (parallel with Phase 2): README, site/docs.html, CLAUDE.md, and plugin reference docs can be drafted as soon as Phase 1 design is locked in. They reference paths and commands that are stable from the PRD.
Phase 4 — End-to-end validation (sequential, last): Walk every PRD success criterion on the actual Windows + WezTerm machine. Fix any gaps surfaced. Bump plugin version once.
Risk mitigation
Risk: bubbletea ConPTY rendering anomalies. Mitigation: validate early in Phase 1 with a smoke test (revdiff --help then a real revdiff against the repo). If anomalies appear, the upstream bubbletea GitHub issues are the first stop, not a local fix.
Risk: wezterm cli spawn exit semantics differ from Unix overlay flow. Mitigation: the PowerShell launcher uses the same pane-id-wait pattern as the bash script; if cleanup behavior differs, a try/finally block guarantees we don't leave orphan tabs.
Risk: macOS/Linux regression from SKILL.md dispatch logic. Mitigation: Unix path is unchanged (the dispatch is a simple if ($IsWindows) guard at the top of the loader). A Phase 4 smoke test on macOS confirms zero regression.
Risk: Windows test runs fail due to git config (line endings, autocrlf). Mitigation: validation step verifies core.autocrlf doesn't perturb existing diff parsing. If it does, document the required git config for Windows contributors rather than coding around it.
Test strategy
Unit tests for the new path defaults, gated by build tags so each platform tests its own branch.
Unit test for openInteractiveTTY() is light-touch — we can't actually open CONIN$ in CI without a console, so we test the symbol resolution and gate the smoke test to manual validation.
All existing tests (make test on Unix, .\test.ps1 on Windows) must stay green throughout.
Six tasks total (under the ≤10 cap). Tasks 2/3/4/5 can run in parallel after task 1. Task 6 is the final gate.
001 — Go core: Windows config paths + TTY reattach. Modify cmd/revdiff/main.go (defaultConfigPath, defaultKeysPath, defaultThemesDir, openTTY callers). Add tty_unix.go and tty_windows.go build-tagged sidecars. Update cmd/revdiff/main_test.go for both branches. Single PR; conflicts with nothing.
002 — PowerShell build/test scripts. Add build.ps1 and test.ps1 at repo root mirroring make build / make test. Output to .bin\revdiff.exe. No Makefile changes.
003 — revdiff plugin Windows launcher. Add .claude-plugin/skills/revdiff/scripts/launch-revdiff.ps1 and .claude-plugin/skills/revdiff/scripts/detect-ref.ps1. Update .claude-plugin/skills/revdiff/SKILL.md to dispatch on $IsWindows. WezTerm spawn via wezterm cli spawn --new-tab. Behavior parity with launch-revdiff.sh.
004 — revdiff-planning plugin Windows launcher. Add plugins/revdiff-planning/scripts/launch-plan-review.ps1. Update the planning plugin's SKILL.md dispatch. Same WezTerm pattern as task 003.
005 — Documentation pass. Update README.md (Installation + Config + Plugin sections), site/docs.html (in sync with README), CLAUDE.md (Windows path notes), .claude-plugin/skills/revdiff/references/install.md and .../config.md. No code changes.
006 — End-to-end Windows validation + plugin version bump. Walk all 10 PRD success criteria on Windows 11 + WezTerm. Fix any gaps. Run macOS/Linux smoke test for regressions. Bump plugin.json and marketplace.json to next minor.
Tasks 002/003/004/005 share no files and can be assigned to four parallel agents. Task 006 is sequential and gates the epic.
Dependencies
External
WezTerm with wezterm cli subcommand on the validator's PATH (for tasks 003, 004, 006).
Git for Windows on PATH (for task 006 validation).
Go matching go.mod (for tasks 001, 002, 006).
PowerShell 5.1+ (preinstalled on Windows 10/11) — $IsWindows requires PowerShell 6+, so for Windows PowerShell 5.1 we fall back to [System.Environment]::OSVersion.Platform checks. Confirm during task 003 implementation.
Internal
Audit findings from this conversation — implementing engineer must re-read before starting task 001.
CLAUDE.md site/docs.html sync rule (task 005).
CLAUDE.md plugin version bump rule (task 006).
The PRD's "no regressions on macOS/Linux" requirement governs task 006.
No blocking dependencies
All dependencies are tooling/runtime concerns, not other epics. This work can begin as soon as the epic syncs to GitHub.
Success Criteria (Technical)
Builds clean on Windows.go install github.com/shtirlitsDva/revdiff/cmd/revdiff@latest and .\build.ps1 both produce a runnable revdiff.exe. No //go:build errors. .\test.ps1 exits 0.
Builds clean on Unix.make build && make test on macOS and Linux exits 0 with no behavior change vs. master. The ~/.config/revdiff/ layout still works.
Config paths route correctly. On Windows, revdiff.exe --dump-config shows paths under %APPDATA%\revdiff\. On Unix, revdiff --dump-config shows ~/.config/revdiff/. Both cases auto-create the themes directory with the five bundled themes on first run.
TTY reattach works on Windows.Get-Content README.md | revdiff --stdin reads input, reattaches keyboard via CONIN$, and accepts q / j / k / / interactions.
Plugin launcher works on Windows. Invoking the revdiff skill from a Claude Code session running inside a WezTerm tab spawns revdiff in a new tab in the same WezTerm window. Tab cleans up on revdiff exit.
Plugin works on Unix unchanged.launch-revdiff.sh and launch-plan-review.sh are byte-identical to master. SKILL.md dispatch logic only adds an $IsWindows branch.
Documentation reflects Windows. README, site/docs.html, CLAUDE.md, and plugin reference docs all describe the Windows install + config layout. The site/docs.html ↔ README sync rule is satisfied.
No new Go dependencies.go.mod and vendor/ diff against master shows no additions.
Plugin version bumped once.plugin.json and marketplace.json move to the next minor version exactly once at the end of implementation.
Estimated Effort
Effort is described in scope, not time, per project conventions.
001 (Go core): small. ~50 lines of Go across 3 files + ~30 lines of test. Single contributor, single PR.
002 (PowerShell build/test): small. ~60 lines of PowerShell across 2 files. Single PR.
003 (revdiff launcher): medium. ~150 lines of PowerShell + a 5-line SKILL.md edit. The bash original is 290+ lines but most of that is non-WezTerm terminal handlers we don't need; the WezTerm path is the small slice we're porting.
004 (planning launcher): medium-small. Mirrors 003 but the bash original is shorter (~335 lines, similarly trimmed to just the WezTerm path).
005 (documentation): small. Targeted edits to ~6 markdown/HTML files. No new pages.
006 (validation): small in code, medium in time. Walk all 10 success criteria, fix any gaps, bump version. Validation work is hard to estimate because it depends on whether anything surfaced in the wild.
Total scope: 6 tasks, four of which can parallelize after task 001 lands. The biggest risk is ConPTY rendering surprises in bubbletea — flagged in mitigation above.
Critical path: 001 → (003 ∥ 004) → 006. Tasks 002 and 005 are off the critical path and can land any time after 001.
Tasks Created
001.md - Go core: Windows config paths and TTY reattach (parallel: true)
002.md - PowerShell build and test scripts (parallel: true)
005.md - Documentation pass for Windows support (parallel: true)
006.md - End-to-end Windows validation and plugin version bump (parallel: false)
Total tasks: 6
Parallel tasks: 5 (001, 002, 003, 004, 005)
Sequential tasks: 1 (006 — depends on all five above)
Estimated total scope: 4×S + 2×M (one M is validation, not code)
Epic: windows-support
Overview
Make revdiff and both Claude Code plugins (
revdiff,revdiff-planning) build, run, and integrate cleanly on Windows 10/11 + WezTerm. The work is intentionally narrow: five concrete Go/code touchpoints, two PowerShell sibling scripts per plugin, and a documentation pass. No CI changes, no second binary, no terminal abstraction layer — we sit Windows logic next to existing Unix logic via Go build tags and.ps1siblings to existing.shscripts, so the macOS/Linux paths remain untouched and risk-free.The audit (already in conversation context) confirmed that the heavy lifting —
filepath.Joindiscipline,exec.Commandstyle, modern bubbletea/lipgloss,os.UserHomeDir,os.CreateTemp("")— is already cross-platform. The remaining gaps are five surgical fixes plus PowerShell ports of the launcher scripts.Architecture Decisions
Build tags over
runtime.GOOSbranching. Platform-specific Go code (TTY reattach, possibly path defaults if cleaner) lives in_windows.go/_unix.gofiles behind//go:buildconstraints. Keeps business logic free of platform conditionals and lets the Go compiler enforce mutual exclusion. Rejected alternative:if runtime.GOOS == "windows"branches inline — works, but pollutes call sites and resists test isolation.os.UserConfigDir()rather than manual%APPDATA%resolution. The standard library already returns%APPDATA%on Windows,$XDG_CONFIG_HOME(or~/.config) on Linux, and~/Library/Application Supporton macOS. We currently hardcode~/.configeven on macOS, which is non-idiomatic. To minimize blast radius, we keep the existing~/.config/revdiff/layout on Unix (Linux + macOS) and only switch toos.UserConfigDir()semantics on Windows, gated byruntime.GOOS == "windows". This avoids breaking existing macOS users who already have configs at~/.config/revdiff/.PowerShell siblings rather than rewriting the bash launcher.
launch-revdiff.shis 290+ lines of terminal-specific overlay code. Rewriting it as a Go binary or unifying it cross-platform was considered and rejected: too much risk to the existing macOS workflow, and a second binary complicates plugin distribution. Instead,launch-revdiff.ps1is a from-scratch PowerShell file containing only the WezTerm path. Bash and PowerShell scripts are maintained side-by-side and a header comment in each links to its sibling.wezterm cli spawn --new-tabfor plugin hosting. Already locked in via PRD brainstorming. The new tab lives in the user's existing WezTerm window (so Claude stays visible), and the script can wait on the spawned pane id for cleanup. Nowezterm start(steals focus, separate window) and nosplit-pane(less consistent with the existing kitty/wezterm bash overlay flow).SKILL.md dispatches on
$IsWindows. PowerShell defines$IsWindowsnatively in v6+. The SKILL.md (or the small loader script the harness invokes) checks platform and selects.ps1on Windows,.shelsewhere. The bash path stays the documented default so existing users see no change.No CI Windows runner. Validation is manual on the author's Windows + WezTerm machine via the success criteria checklist. Adding
windows-latestto GitHub Actions and shipping signed binaries are explicit follow-ups, not blockers.Makefile is untouched.
build.ps1andtest.ps1are added in parallel. A Windows contributor uses the.ps1files; a Unix contributor keeps usingmake. Two scripts, one source of truth (the samego build/go testflags), maintained by convention.No new Go dependencies.
golang.org/x/termwas considered for cross-platform TTY handling but rejected —os.Open("CONIN$")on Windows andos.Open("/dev/tty")on Unix is two lines of code each, doesn't justify pulling a new module. Vendoring stays clean.Technical Approach
Frontend Components
revdiff is a TUI with no web frontend, but the user-facing surface that needs Windows attention is:
go.mod(bubbletea v1.3.10,lipgloss v1.1.0,x/ansi v0.11.6) already drive ConPTY correctly on Windows 10 1809+. Validation only.CONIN$after consuming piped stdin. Without this fix, every key press goes nowhere on Windows.Backend Services
revdiff has no network backend, but it shells out to
git. Audit confirmed allexec.Command("git", ...)calls are list-form (not shell strings) and Go's exec package auto-resolvesgit.exefromPATHon Windows. No changes needed indiff/diff.go,diff/directory.go,diff/blame.go, orcmd/revdiff/main.go:502.The Go-side changes are concentrated in one file (
cmd/revdiff/main.go) plus two new build-tagged sidecars:cmd/revdiff/main.go: modifydefaultConfigPath,defaultKeysPath,defaultThemesDirto consultruntime.GOOSand route Windows callers throughos.UserConfigDir(). Replace directopenTTY()body with a call to a build-taggedopenInteractiveTTY()helper.cmd/revdiff/tty_unix.go(//go:build !windows):func openInteractiveTTY() (*os.File, error) { return os.Open("/dev/tty") }cmd/revdiff/tty_windows.go(//go:build windows):func openInteractiveTTY() (*os.File, error) { return os.Open("CONIN$") }cmd/revdiff/main_test.gogains a small table-driven test that fakes the Windows branch via dependency injection or a build-tagged sibling test file.Infrastructure
build.ps1andtest.ps1at repo root. Each is ~20-30 lines of PowerShell wrapping the samego build/go testinvocations the Makefile uses..claude-plugin/plugin.jsonand.claude-plugin/marketplace.jsonalready point to skill paths that don't depend on the file extension, so adding.ps1files alongside.shfiles requires no manifest changes. A version bump to plugin.json/marketplace.json is deferred to the end of implementation per CLAUDE.md.Implementation Strategy
Phasing
Phase 1 — Go core (parallel-friendly): Land the TTY split and config-path Windows-awareness first. Once
revdiff.exebuilds and produces the right paths via--dump-config, every other piece of work has something concrete to test against.Phase 2 — Build scripts and plugin launchers (parallel after Phase 1):
build.ps1/test.ps1, thelaunch-revdiff.ps1+detect-ref.ps1pair, andlaunch-plan-review.ps1can all proceed in parallel because they touch disjoint files. Each gets validated independently against therevdiff.exefrom Phase 1.Phase 3 — Documentation (parallel with Phase 2): README, site/docs.html, CLAUDE.md, and plugin reference docs can be drafted as soon as Phase 1 design is locked in. They reference paths and commands that are stable from the PRD.
Phase 4 — End-to-end validation (sequential, last): Walk every PRD success criterion on the actual Windows + WezTerm machine. Fix any gaps surfaced. Bump plugin version once.
Risk mitigation
revdiff --helpthen a realrevdiffagainst the repo). If anomalies appear, the upstreambubbleteaGitHub issues are the first stop, not a local fix.wezterm cli spawnexit semantics differ from Unix overlay flow. Mitigation: the PowerShell launcher uses the same pane-id-wait pattern as the bash script; if cleanup behavior differs, atry/finallyblock guarantees we don't leave orphan tabs.if ($IsWindows)guard at the top of the loader). A Phase 4 smoke test on macOS confirms zero regression.core.autocrlfdoesn't perturb existing diff parsing. If it does, document the requiredgit configfor Windows contributors rather than coding around it.Test strategy
openInteractiveTTY()is light-touch — we can't actually openCONIN$in CI without a console, so we test the symbol resolution and gate the smoke test to manual validation.make teston Unix,.\test.ps1on Windows) must stay green throughout.Task Breakdown Preview
Six tasks total (under the ≤10 cap). Tasks 2/3/4/5 can run in parallel after task 1. Task 6 is the final gate.
cmd/revdiff/main.go(defaultConfigPath,defaultKeysPath,defaultThemesDir,openTTYcallers). Addtty_unix.goandtty_windows.gobuild-tagged sidecars. Updatecmd/revdiff/main_test.gofor both branches. Single PR; conflicts with nothing.build.ps1andtest.ps1at repo root mirroringmake build/make test. Output to.bin\revdiff.exe. No Makefile changes..claude-plugin/skills/revdiff/scripts/launch-revdiff.ps1and.claude-plugin/skills/revdiff/scripts/detect-ref.ps1. Update.claude-plugin/skills/revdiff/SKILL.mdto dispatch on$IsWindows. WezTerm spawn viawezterm cli spawn --new-tab. Behavior parity withlaunch-revdiff.sh.plugins/revdiff-planning/scripts/launch-plan-review.ps1. Update the planning plugin's SKILL.md dispatch. Same WezTerm pattern as task 003.README.md(Installation + Config + Plugin sections),site/docs.html(in sync with README),CLAUDE.md(Windows path notes),.claude-plugin/skills/revdiff/references/install.mdand.../config.md. No code changes.plugin.jsonandmarketplace.jsonto next minor.Parallelization map
Tasks 002/003/004/005 share no files and can be assigned to four parallel agents. Task 006 is sequential and gates the epic.
Dependencies
External
wezterm clisubcommand on the validator's PATH (for tasks 003, 004, 006).go.mod(for tasks 001, 002, 006).$IsWindowsrequires PowerShell 6+, so for Windows PowerShell 5.1 we fall back to[System.Environment]::OSVersion.Platformchecks. Confirm during task 003 implementation.Internal
site/docs.htmlsync rule (task 005).No blocking dependencies
Success Criteria (Technical)
go install github.com/shtirlitsDva/revdiff/cmd/revdiff@latestand.\build.ps1both produce a runnablerevdiff.exe. No//go:builderrors..\test.ps1exits 0.make build && make teston macOS and Linux exits 0 with no behavior change vs. master. The~/.config/revdiff/layout still works.revdiff.exe --dump-configshows paths under%APPDATA%\revdiff\. On Unix,revdiff --dump-configshows~/.config/revdiff/. Both cases auto-create the themes directory with the five bundled themes on first run.Get-Content README.md | revdiff --stdinreads input, reattaches keyboard viaCONIN$, and acceptsq/j/k//interactions.revdiffskill from a Claude Code session running inside a WezTerm tab spawns revdiff in a new tab in the same WezTerm window. Tab cleans up on revdiff exit.revdiff-planning.launch-revdiff.shandlaunch-plan-review.share byte-identical to master. SKILL.md dispatch logic only adds an$IsWindowsbranch.go.modandvendor/diff against master shows no additions.plugin.jsonandmarketplace.jsonmove to the next minor version exactly once at the end of implementation.Estimated Effort
Effort is described in scope, not time, per project conventions.
Total scope: 6 tasks, four of which can parallelize after task 001 lands. The biggest risk is ConPTY rendering surprises in bubbletea — flagged in mitigation above.
Critical path: 001 → (003 ∥ 004) → 006. Tasks 002 and 005 are off the critical path and can land any time after 001.
Tasks Created
Total tasks: 6
Parallel tasks: 5 (001, 002, 003, 004, 005)
Sequential tasks: 1 (006 — depends on all five above)
Estimated total scope: 4×S + 2×M (one M is validation, not code)