Closes 3/3 acceptance of [install-ps1]: - (a) install.ps1 existed - (b) --prune flag shipped in 6cf0e98 - (c) concept page now written .wiki/concepts/install-cross-platform.md captures: - why two scripts (PS for native-Win, sh for Linux/Mac) - parity contract (shared invariants, flag-naming convention) - --prune design choices and rejected alternatives - scope boundary (install-side only; dist/.skill prune is separate) Index + log updated per .wiki/CLAUDE.md schema. STATUS.md: [install-ps1] ⚪ → 🟢, new ⚪ task [install-ps1-build-prune-followup] filed for the analogous flag on build.{sh,ps1}.
4.3 KiB
title, type, updated
| title | type | updated |
|---|---|---|
| Install Cross-Platform Parity (PS + Bash) | concept | 2026-05-25 |
Install Cross-Platform Parity (PS + Bash)
Sibling concept to install-portability.md (POSIX-shell compat). This one is about the paired-script parity contract between scripts/install.ps1 (PowerShell) and scripts/install.sh (bash).
Why two scripts
Windows hosts running CC outside a git-bash terminal have no reliable bash. Native PowerShell call (pwsh ./scripts/install.ps1) is the friction-free path. Linux / macOS users get bash. Both audiences are first-class — claude-skills is multi-machine by design (see project_deployment_goal memory).
Single-script "use bash everywhere" was rejected: forces every Windows user to install git-bash before bootstrap, contradicts "tool-light install path".
Parity contract
Both scripts MUST:
- Read sources from
<repo>/skills/<name>/. - Install to
$CLAUDE_SKILLS_DIRif set, else~/.claude/skills/. - Accept a name-list (positional in bash,
-Namesin PS); no args = all. - Skip with a warning when
skills/<name>/is missing or has noSKILL.md. - Idempotent:
rm -rf(orRemove-Item -Recurse -Force) the destination, then copy fresh. - Print one
installed: <name> -> <path>line per successfully installed skill.
Flag naming follows the host shell's convention — POSIX --prune in bash, PascalCase -Prune switch in PowerShell. Behaviour identical.
The --prune / -Prune flag
Added 2026-05-25 (commit 6cf0e98). Motivating case: after retiring using-synology-ops the installed dir ~/.claude/skills/using-synology-ops/ lingered until manual rm — the install scripts had no notion of stale-cleanup.
Behaviour: after the install loop, walk $target/* and remove any dir whose name is not in skills/*.
Design choices and their rejected alternatives:
-
Combined flag, not standalone mode. Single invocation does both. Alternative (
install --prune-only) was rejected — adds a mode that nobody asked for; users wanting "just cleanup" can pass an empty name list (install.sh --prunewith no positional args still walks the prune step at the end, no-op'ing the install loop because all source skills resolve to no-op overwrites of fresh installs). -
Global scan, ignores name filter. Even when called as
install.sh foo --prune, the prune step scans the full target against the full source. Rationale: stale-cleanup is a global concern. A user who explicitly opts into prune wants the cleanup to be useful — a names-filtered prune ("only prune dirs that match the name list AND are missing from source") rarely matches anyone's mental model. -
Print-and-delete, no confirmation prompt. Each removal prints
pruning: <name> (not in skills/) -> <path>. Confirmation prompts would block automation (CI, batch reinstalls). Visibility comes from the printed line; users wanting a dry-run pass-WhatIfin PowerShell (the cmdlet already supports it) or pipe toechoin bash (trivial to grep^pruning:before running for real). -
Default off. Must be passed explicitly. Idempotent re-installs (the common case) don't suddenly delete anything.
What --prune does NOT do
- It does not remove
dist/<name>.skillartefacts. That's a build concern, not install. The matching--pruneflag onbuild.sh/build.ps1is a separate task ([install-ps1]acceptance was scoped to install scripts;dist/is a build artefact directory). - It does not touch plugin-installed skills under
~/.claude/plugins/<plugin>/skills/<name>/. Those are managed by the plugin system, not this repo. - It does not warn if the about-to-be-deleted dir contains user-edited content. The contract is that
~/.claude/skills/<name>/is a managed copy ofskills/<name>/— anything else is user-error.
Test evidence
Both scripts smoke-tested 2026-05-25 on disposable target dirs (env-overridden CLAUDE_SKILLS_DIR). Pre-populated with 2 fake stale dirs, ran full install + prune, verified: stale dirs removed, all real skills installed, retired using-synology-ops absent. No automated test fixture in the repo — install scripts are wrapper-style, smoke-test evidence in the 6cf0e98 commit body suffices under the [skip-tdd: wrapper] carve-out.
[archive-roundtrip-test] (still ⚪ on the board) is a candidate place to add a real fixture once it lands.