Browse Source

feat(rules): Commit global rules back into repo

Copy five general-purpose rules from ~/.claude/rules/ that were
authored globally and never committed: dev-servers, modern-tools,
public-posts, release-review, shell-preference. ccd-session-tools.md
is deliberately not shipped (internal user-private reference doc).

Machine-specificity review:
- dev-servers.md is the machine-specific one (X:\00_Orchestration
  stack paths, .lab URLs, machine-local pcserve skill). Generalized
  lightly: added a portability note framing it as a template, and
  pointed cross-refs at the shipped process-compose-ops/portless-ops
  skills instead of the unshipped pcserve playbook. The 2026-07-03
  crash-loop incident is kept as documented rationale.
- public-posts.md and release-review.md keep their dated user
  corrections as documented rationale (same pattern as the shipped
  worktree-boundaries.md).
- shell-preference.md is user-preference-voiced ("on this machine")
  but coherent as a personal directive others can adapt.

Also fix a contradiction: agents/git-agent.md listed gh release
create as a T2 safe-write, contradicting release-review.md. Moved to
T3 (preflight + stop), and the Release Workflow now stops before
gh release create pending explicit human approval.

Docs updated to 14 rules: README.md header count + Rules table,
AGENTS.md structure map, docs/PLAN.md inventory table. New rule
files converted LF to CRLF to match the repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0xDarkMatter 6 days ago
parent
commit
38f227fd25
9 changed files with 368 additions and 5 deletions
  1. 1 1
      AGENTS.md
  2. 6 1
      README.md
  3. 4 2
      agents/git-agent.md
  4. 1 1
      docs/PLAN.md
  5. 59 0
      rules/dev-servers.md
  6. 76 0
      rules/modern-tools.md
  7. 74 0
      rules/public-posts.md
  8. 100 0
      rules/release-review.md
  9. 47 0
      rules/shell-preference.md

+ 1 - 1
AGENTS.md

@@ -34,7 +34,7 @@ cd claude-mods && ./scripts/install.sh  # or .\scripts\install.ps1 on Windows
 | `skills/` | Skill definitions with SKILL.md |
 | `skills/` | Skill definitions with SKILL.md |
 | `output-styles/` | Response personalities (13 styles incl. vesper, atlas, noir, roast, scout) |
 | `output-styles/` | Response personalities (13 styles incl. vesper, atlas, noir, roast, scout) |
 | `hooks/` | Working hook scripts (lint, format, safety, pmail) |
 | `hooks/` | Working hook scripts (lint, format, safety, pmail) |
-| `rules/` | Claude Code rules (9 files: agentic-quality, cli-tools, commit-style, loop-engineering, naming-conventions, prompt-injection, skill-agent-updates, supply-chain, worktree-boundaries) |
+| `rules/` | Claude Code rules (14 files: agentic-quality, cli-tools, commit-style, dev-servers, loop-engineering, modern-tools, naming-conventions, prompt-injection, public-posts, release-review, shell-preference, skill-agent-updates, supply-chain, worktree-boundaries) |
 | `tools/` | Modern CLI toolkit documentation |
 | `tools/` | Modern CLI toolkit documentation |
 | `tests/` | Validation scripts + justfile |
 | `tests/` | Validation scripts + justfile |
 | `scripts/` | Install scripts |
 | `scripts/` | Install scripts |

+ 6 - 1
README.md

@@ -18,7 +18,7 @@ Built on the [Agent Skills specification](https://agentskills.io/specification)
 
 
 From Python async patterns to Rust ownership models, from AWS Fargate deployments to Craft CMS development - claude-mods provides the specialized knowledge and tools that transform Claude from a general-purpose assistant into a domain expert who understands your stack, remembers your workflow, and ships production code.
 From Python async patterns to Rust ownership models, from AWS Fargate deployments to Craft CMS development - claude-mods provides the specialized knowledge and tools that transform Claude from a general-purpose assistant into a domain expert who understands your stack, remembers your workflow, and ships production code.
 
 
-**3 agents. 100 skills. 13 styles. 13 hooks. 9 rules. One install.**
+**3 agents. 100 skills. 13 styles. 13 hooks. 14 rules. One install.**
 
 
 ## Recent Updates
 ## Recent Updates
 
 
@@ -413,6 +413,11 @@ See [skill-creator](skills/skill-creator/) for the complete guide.
 | [worktree-boundaries.md](rules/worktree-boundaries.md) | Never touch other sessions' worktrees - no rm -rf, no git add -A sweeping gitlinks |
 | [worktree-boundaries.md](rules/worktree-boundaries.md) | Never touch other sessions' worktrees - no rm -rf, no git add -A sweeping gitlinks |
 | [loop-engineering.md](rules/loop-engineering.md) | Graduated-autonomy discipline for scheduled/autonomous agent loops - L1→L2→L3, scheduler-not-session, escalation gate, kill switch + budget; companion to loop-ops |
 | [loop-engineering.md](rules/loop-engineering.md) | Graduated-autonomy discipline for scheduled/autonomous agent loops - L1→L2→L3, scheduler-not-session, escalation gate, kill switch + budget; companion to loop-ops |
 | [agentic-quality.md](rules/agentic-quality.md) | Code, comments, and structure that survive the session - cold-agent test, comment doctrine (contract blocks, WHY-only, guard comments), entry-doc standard, file-size discipline, docs indexing + pairing; companion to repo-doctor |
 | [agentic-quality.md](rules/agentic-quality.md) | Code, comments, and structure that survive the session - cold-agent test, comment doctrine (contract blocks, WHY-only, guard comments), entry-doc standard, file-size discipline, docs indexing + pairing; companion to repo-doctor |
+| [dev-servers.md](rules/dev-servers.md) | Never start local dev servers ad-hoc - register them under a process-compose + portless stack with a port registry; template rule (adapt paths), companion to process-compose-ops/portless-ops |
+| [modern-tools.md](rules/modern-tools.md) | Which-tool enforcement when generating commands - default modern (uv, fd, rg, sd), footnote legacy; companion to cli-tools.md |
+| [public-posts.md](rules/public-posts.md) | Preview-before-send for public surfaces - quote the verbatim draft and wait for explicit approval before gh comments, PRs, or any external post |
+| [release-review.md](rules/release-review.md) | Never auto-publish GitHub releases - push commit+tag, stop, surface the diff for human review before gh release create |
+| [shell-preference.md](rules/shell-preference.md) | User-facing commands are PowerShell-native by default (WSL is the bash exception) - includes bash-to-PowerShell translation table |
 
 
 ### Tools & Hooks
 ### Tools & Hooks
 
 

+ 4 - 2
agents/git-agent.md

@@ -45,7 +45,6 @@ git branch <new-branch>
 gh pr create, gh issue create
 gh pr create, gh issue create
 gh pr merge --squash (with checks passing)
 gh pr merge --squash (with checks passing)
 gh pr comment, gh issue comment
 gh pr comment, gh issue comment
-gh release create
 ```
 ```
 
 
 **Before T2 writes:**
 **Before T2 writes:**
@@ -69,6 +68,7 @@ git checkout -- <file> (discard changes)
 git stash clear, git stash drop
 git stash clear, git stash drop
 git merge (into main/master)
 git merge (into main/master)
 gh pr merge --rebase
 gh pr merge --rebase
+gh release create (public one-way publish — rules/release-review.md requires explicit human approval)
 ```
 ```
 
 
 **T3 Preflight Report Format:**
 **T3 Preflight Report Format:**
@@ -155,7 +155,9 @@ When asked to create a release or tag:
 2. Determine version bump (from orchestrator context or commit analysis)
 2. Determine version bump (from orchestrator context or commit analysis)
 3. Create tag: `git tag -a v{version} -m "Release v{version}"`
 3. Create tag: `git tag -a v{version} -m "Release v{version}"`
 4. If requested, push tag: `git push origin v{version}`
 4. If requested, push tag: `git push origin v{version}`
-5. If requested, create GitHub release: `gh release create v{version} --generate-notes`
+5. STOP before `gh release create` — it is T3 (rules/release-review.md): surface the tag
+   diff URL, proposed release notes, and the exact command; publish only after the
+   orchestrator relays explicit human approval
 6. Report: version, changelog summary
 6. Report: version, changelog summary
 
 
 ### Changelog Generation
 ### Changelog Generation

+ 1 - 1
docs/PLAN.md

@@ -18,7 +18,7 @@
 | Agents | 3 | Pure context-isolation/worker roles only: git-agent (background commits/PRs), firecrawl-expert (noisy scrapes), project-organizer (bulk restructure) |
 | Agents | 3 | Pure context-isolation/worker roles only: git-agent (background commits/PRs), firecrawl-expert (noisy scrapes), project-organizer (bulk restructure) |
 | Skills | 100 | Operational skills, CLI tools, workflows, diagnostics, security |
 | Skills | 100 | Operational skills, CLI tools, workflows, diagnostics, security |
 | Commands | 3 | Session management + git orchestration (sync, save, git-ops) |
 | Commands | 3 | Session management + git orchestration (sync, save, git-ops) |
-| Rules | 9 | agentic-quality, cli-tools, commit-style, loop-engineering, naming-conventions, prompt-injection, skill-agent-updates, supply-chain, worktree-boundaries |
+| Rules | 14 | agentic-quality, cli-tools, commit-style, dev-servers, loop-engineering, modern-tools, naming-conventions, prompt-injection, public-posts, release-review, shell-preference, skill-agent-updates, supply-chain, worktree-boundaries |
 | Output Styles | 13 | Vesper, Spartan, Mentor, Executive, Pair, Atlas, Coach, Harbour, Meridian, Noir, Roast, Sage, Scout |
 | Output Styles | 13 | Vesper, Spartan, Mentor, Executive, Pair, Atlas, Coach, Harbour, Meridian, Noir, Roast, Sage, Scout |
 | Hooks | 13 | lint, format, safety, uv, install-scan, manifest-scan, pmail, unicode-scan ×2, config-change guard, worktree guard, peer-writer guard, touched-files ledger |
 | Hooks | 13 | lint, format, safety, uv, install-scan, manifest-scan, pmail, unicode-scan ×2, config-change guard, worktree guard, peer-writer guard, touched-files ledger |
 
 

+ 59 - 0
rules/dev-servers.md

@@ -0,0 +1,59 @@
+# Dev Servers — always via the Process Compose stack
+
+Companion to the generic [`process-compose-ops`](../skills/process-compose-ops/SKILL.md)
+and [`portless-ops`](../skills/portless-ops/SKILL.md) skills (shipped with this plugin)
+and a machine-local `pcserve` skill (the author's playbook — not shipped). This file is
+the *directive* — what to do every time a local server is about to be started, in any
+project on this machine.
+
+> **Portability note:** the stack location (`X:\00_Orchestration\compose-portless`),
+> port registry, `.lab` URLs, and the `pcserve` skill are specific to the author's
+> machine. Treat this rule as a template: point it at your own process-compose +
+> portless setup (or equivalent process manager and port registry). The pattern —
+> registered services, one port registry, no ad-hoc servers — is the portable part.
+
+## The rule
+
+**Never start a local dev server, preview server, or daemon ad-hoc.** Every local web
+server on this machine runs under the Process Compose stack at
+`X:\00_Orchestration\compose-portless` (lifecycle) + portless (HTTPS routing,
+`https://<name>.lab`). Before binding ANY port, check the registry at
+`X:\00_Orchestration\shared\ports.yaml`.
+
+When a task needs a server — serving an app, previewing a build, spinning up an API,
+adding an MCP server — **invoke the `pcserve` skill** and register it, don't reach for
+`npm run dev` / `python -m http.server` / `uvicorn` on a made-up port.
+
+## Why this matters
+
+Ad-hoc servers are how this machine gets port clashes and orphaned processes. On
+2026-07-03 an orphaned dev process holding port 8113 put the registered `glyph`
+service into a silent 5-second crash-loop — **3,603 restarts over 5.5 hours**. Every
+unregistered `localhost:<random>` server is a future collision with a pinned-port
+service, an untracked process that survives its session, and a URL the user can't
+find again. Registered services get a stable `.lab` URL, health checks, bounded
+restarts, logs, and show up on the `https://home.lab` dashboard — for free.
+
+## Directives
+
+| Situation | Directive |
+|---|---|
+| Task needs any server the user will open, or that outlives the task | Register it: `pcserve` skill → `add-service.ps1`. Port from `shared/ports.yaml` ranges. |
+| Quick throwaway check (serve → curl → kill, same task) | Bind **8190–8199** only, and kill it before the task ends. Never leave it running. |
+| Service misbehaving / needs restart, pause, logs | PC CLI via `pcserve` — `process restart/stop/start`, read `logs\<name>.log`. Never `pm2 *`. |
+| Done with a service | `remove-service.ps1` — don't let dead entries rot in the stack. |
+| Port already in use | Find the holder (`Get-NetTCPConnection -LocalPort <p> -State Listen`), reap orphans — don't just increment the port number. |
+| Tempted to `process-compose down` or `portless proxy start` | Don't. Individual `process stop`; proxy is the `Portless Proxy` scheduled task. |
+
+## When to bend the rule
+
+- Unit/integration test servers managed by a test runner (pytest, vitest, playwright)
+  — those live and die inside the runner, run them normally.
+- Explicit user instruction to run something outside the stack.
+- Work inside WSL/containers with isolated networking.
+
+## Cross-reference
+
+- `~/.claude/skills/pcserve/SKILL.md` — the workflow playbook (machine-local, not shipped)
+- `X:\00_Orchestration\compose-portless\AGENTS.md` — stack golden rules (machine-local)
+- `process-compose-ops` / `portless-ops` skills — generic tool depth (shipped)

+ 76 - 0
rules/modern-tools.md

@@ -0,0 +1,76 @@
+# Modern Tools — Enforcement
+
+Companion to [cli-tools.md](cli-tools.md). cli-tools.md is the *reference* (what's available). This file is the *directive* (which to pick when drafting commands, scripts, install instructions, or docs).
+
+## The rule
+
+**Default to the most modern, canonical tool. Never drift back to legacy aliases just because they're more common in the wild.**
+
+This applies whenever you're generating user-facing commands — README install steps, Dockerfile RUN lines, CI workflows, AGENTS.md run-commands tables, scratch shell snippets, anything the user will see or copy-paste.
+
+## Why this matters
+
+The user has explicitly built their environment around modern tooling and pre-approved permissions for it. Every legacy fallback you generate is friction the user has to undo. The user notices. They've corrected this drift more than once.
+
+Modern tools are also typically 10–100× faster (uv vs pip, fd vs find, rg vs grep) — defaulting legacy is a measurable cost, not a stylistic preference.
+
+## Translation table (this is what "modern" means here)
+
+| Don't generate | Generate instead | Why |
+|---|---|---|
+| `pip install <pkg>` | `uv tool install <pkg>` (CLI tool) <br/> `uv add <pkg>` (project dep) <br/> `uv pip install <pkg>` (last resort) | uv is 10–100× faster; `uv tool` is the right answer for CLI binaries — isolated env, lands on PATH, supports `uv tool upgrade` / `uninstall` |
+| `pipx install <pkg>` / `pipx run <pkg>` | `uv tool install <pkg>` / `uvx <pkg>` | uvx is the one-shot ephemeral runner; uv tool is persistent |
+| `pip install -e .` | `uv sync` (uv-managed project) <br/> `uv pip install -e ".[dev]"` (last resort) | `uv sync` reads pyproject + lockfile, installs everything, faster |
+| `python -m venv .venv` | `uv venv .venv` | Faster |
+| `python -m pip install` | `uv pip install` | Same |
+| VCS install: `pip install git+https://...` | `uv tool install git+https://...` <br/> or `uvx --from git+https://... <cmd>` | Modern equivalent works identically |
+| `find . -name "*.py"` | `fd -e py` | Faster, respects .gitignore, simpler syntax |
+| `grep -r "pattern"` | `rg "pattern"` | 10× faster, respects .gitignore |
+| `sed -i 's/old/new/g' file` | `sd 'old' 'new' file` | No escaping headaches |
+| `cat file.py` (for display) | `bat file.py` | Syntax highlighting; for editing, use the Read tool |
+| `ls -la --git` | `eza -la --git` | Git status + icons in one command |
+| `man <cmd>` | `tldr <cmd>` | Practical examples, 98% smaller |
+| `du -sh *` | `dust` | Visual tree |
+| `make <target>` | `just <target>` | Simpler syntax, no tab-vs-space pain |
+| `top` / `htop` | `btm` (when shown to user) | Cleaner UI; `ps` is fine for shell scripts |
+
+## Web fetch hierarchy (when fetching URL content)
+
+Never default to `curl <url>` for content extraction. Use this priority:
+
+1. `WebFetch` tool — built-in, instant
+2. `r.jina.ai/<url>` — fastest fallback (~0.5s avg)
+3. `firecrawl <url>` — anti-bot bypass (Cloudflare, heavy JS)
+4. `markitdown <url>` — simple static pages or local files
+
+## Docker base images
+
+When writing Dockerfiles, install uv from the official image rather than `pip install uv`:
+
+```dockerfile
+COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
+```
+
+Then use `uv tool install`, `uv sync`, etc. Avoid plain `pip` in `RUN` lines.
+
+## When to bend the rule
+
+If a downstream user's environment provably doesn't have uv (e.g. constrained CI runner, system without HOME write access), document the legacy fallback as a **footnote**, not the default. Default-modern, footnote-legacy.
+
+If the user explicitly asks for a `pip`/`find`/`grep` invocation (e.g. "show me the pip command for X"), give them what they asked for — but mention the modern equivalent in passing.
+
+## Self-check before writing install/setup docs
+
+Before committing any `README.md`, `QUICKSTART.md`, `DEPLOYMENT.md`, `Dockerfile`, or `.github/workflows/*.yml`:
+
+```
+rg -n 'pip install|pipx |\bfind \.|^grep |sed -i|^cat ' <file>
+```
+
+If anything matches, ask: is this *really* the modern way, or am I drifting?
+
+## Cross-reference
+
+- `cli-tools.md` — reference table (what's installed, syntax cheatsheet)
+- `commit-style.md` — Conventional Commits enforcement
+- This file — picks-which-tool enforcement when *generating* commands

+ 74 - 0
rules/public-posts.md

@@ -0,0 +1,74 @@
+# Public Posts — preview before sending
+
+Companion to [release-review](release-review.md). That rule covers the
+release page; this one covers the rest of the same family: anything that
+posts text to a third-party surface other humans will read.
+
+## The rule
+
+**Quote the draft body in chat and wait for explicit approval before
+invoking any command that posts to a public surface.** The user's
+authorisation to *do the post* ("comment on #4", "open a PR", "draft the
+release") is not authorisation to *send the specific words* you came up
+with — those they still need to see and approve.
+
+Applies to (non-exhaustive):
+
+- `gh issue comment`, `gh issue create`, `gh issue edit`
+- `gh pr comment`, `gh pr create`, `gh pr edit` (title and body)
+- `gh release create`, `gh release edit` (covered also by release-review)
+- Slack / Discord / email sends
+- Any MCP tool that publishes a comment / message / canvas to an external
+  service (Asana, Notion, Apollo, Linear, Tessitura, etc.)
+
+Does **not** apply to:
+
+- Local git operations (`git commit`, `git tag`) — commit messages are
+  reviewable in the diff before push, and the user authorises the push
+  separately.
+- `git push` itself — that's covered by the push-gate skill and per-task
+  authorisation.
+- Reading public surfaces (`gh issue view`, `gh pr checks`, etc.).
+
+## Why
+
+A comment, PR description, or release note is a one-way visibility
+commitment. Once sent it shows up in someone else's notifications, gets
+indexed by search engines, and stays in the project's history. Editing it
+later leaves a visible "edited" marker; deleting it leaves a gap.
+
+The cost of pausing to surface the draft is one extra message. The cost
+of sending the wrong tone, a misattribution, a stale claim, or a typo to
+a third party is real and not fully reversible.
+
+The user (2026-05-29) corrected this on a `gh issue comment` to issue #4
+that they had authorised in concept but had not seen the text of.
+
+## How to apply
+
+1. Compose the post in chat as a quoted block (the exact body that would
+   be sent, verbatim — not paraphrased).
+2. Name the command that would send it (`gh issue comment 4 ...`,
+   `gh pr create ...`, etc.).
+3. Wait for explicit approval ("yes", "send it", "looks good", an edit
+   request, etc.). Silence is not approval.
+4. If the user edits, apply the edit and re-surface — don't ship a
+   guess.
+5. Only then run the send command.
+
+## When to bend the rule
+
+If the user has already pasted the exact body they want sent, or said
+something like "post this verbatim" / "ship it as-is" / "send my words",
+the approval is in-band — proceed.
+
+If the post is a trivial mechanical action with no author voice (e.g.
+`gh pr edit --add-label ready`, `gh issue close`), no preview needed.
+The rule is about *text Claude wrote* hitting a public surface.
+
+## Cross-reference
+
+- `~/.claude/rules/release-review.md` — the release-creation specific
+  half of this pattern
+- `~/.claude/skills/push-gate/SKILL.md` — pre-push gate (different
+  concern: secrets / forbidden files, not message review)

+ 100 - 0
rules/release-review.md

@@ -0,0 +1,100 @@
+# Release Review — never auto-publish
+
+Companion to [github-ops](../skills/github-ops/SKILL.md), the
+release flows in `cli-tools.md`, and [public-posts](public-posts.md)
+(the broader sibling — preview text before sending it to any third-party
+surface, not just the release page).
+
+## The rule
+
+**Never run `gh release create` without explicit user approval.** Push the
+commit + tag if the user has authorised the publish flow, but stop at the
+release step and surface the diff for review.
+
+This applies to:
+
+- `gh release create`
+- `gh release edit --draft=false` (publishing a previously drafted release)
+- Any other action that creates a public, externally-visible release page
+- Force-pushing tags that already have a release
+
+## Why
+
+A GitHub release is a one-way visibility commitment. Once published:
+
+- The release page shows up in the user's profile feed
+- Any `uv tool install <pkg>@<tag>` / `pip install <pkg>==<version>` resolves
+  to the published artefacts
+- People watching the repo get a "new release" notification
+- Search engines index the release notes
+- "Yanking" a release leaves a 410 / "this release was deleted" trace
+
+Pushing a commit + tag is *also* visible, but it's a much smaller signal
+than a release page. The user can review the pushed state on GitHub
+before creating the release.
+
+The user has explicitly corrected this drift (rookery v0.3.0, 2026-04-28):
+
+> "no human review before github release"
+
+— meaning a human review step is required *before* the release is published.
+
+## How to apply — the right release flow
+
+When invoking the github-ops `update` mode (or any equivalent flow):
+
+1. Bump the version, update CHANGELOG / README "Recent Updates"
+2. `git commit` + `git tag` (these stay local until step 4)
+3. Run push-gate preflight on the commit
+4. `git push origin <branch>` + `git push origin <tag>` — OK to do
+   without separate confirmation when the user has authorised the publish
+5. **Stop here.** Surface the pushed state to the user:
+   - Link to the tag's diff: `https://github.com/<org>/<repo>/compare/<prev>...<tag>`
+   - Link to the tag's tree: `https://github.com/<org>/<repo>/tree/<tag>`
+   - The CHANGELOG section that would become the release notes
+6. Wait for explicit user approval before running `gh release create`
+7. If the user wants edits to the release notes, apply them, then ask
+   again
+
+## What to surface for the review
+
+When you stop at step 5, give the user:
+
+- The exact `gh release create` command you'd run, with the `--notes` content
+- The git diff URL for the tag
+- A reminder that the tag + commit are already pushed, so review can
+  happen on GitHub directly
+
+Example:
+
+```
+v0.3.0 commit + tag pushed. Ready to create the GitHub release.
+
+Diff: https://github.com/0xDarkMatter/rookery/compare/v0.2.0...v0.3.0
+Tree: https://github.com/0xDarkMatter/rookery/tree/v0.3.0
+
+Proposed release command:
+  gh release create v0.3.0 \
+    --repo 0xDarkMatter/rookery \
+    --title "v0.3.0 — Parcel reporting refactor" \
+    --notes-file /tmp/v030-notes.md
+
+Want me to run it, or do you want to review on GitHub first?
+```
+
+## When to bend the rule
+
+If the user has already explicitly said "create the release" / "publish
+v0.X.Y" / "ship it" in the same turn that authorises the push, you can
+skip the separate confirmation step. The rule is about *implicit*
+authorisation — the user saying "use github-ops update mode" is not
+the same as saying "publish the release page".
+
+If unsure, ask. The cost of asking is low; the cost of an unwanted
+release is real.
+
+## Cross-reference
+
+- `~/.claude/skills/github-ops/SKILL.md` — release flow modes
+- `~/.claude/skills/push-gate/scripts/preflight.sh` — pre-push secret scan
+- `~/.claude/rules/cli-tools.md` — `gh` CLI usage patterns

+ 47 - 0
rules/shell-preference.md

@@ -0,0 +1,47 @@
+# Shell Preference — PowerShell by default (WSL is the exception)
+
+Companion to [cli-tools.md](cli-tools.md) and [modern-tools.md](modern-tools.md). Those pick *which tool*;
+this picks *which shell syntax* to hand the user.
+
+## The rule
+
+**On this machine the user ALWAYS uses Windows PowerShell. Every command you give the user to run must be
+PowerShell-native — never bash — UNLESS the current work is inside WSL (a Linux shell), where bash is the default.**
+
+The user's PowerShell is **Windows PowerShell 5.1**: no `&&`/`||` chaining, no `export`, no `\` line-continuation,
+no unix coreutils. Generate accordingly.
+
+## Why this matters
+
+The user flagged this emphatically after being handed bash one-liners that errored on paste
+(`The token '&&' is not a valid statement separator in this version`). Bash syntax in their terminal is pure
+friction every time. They use PowerShell for everything except explicit WSL/Linux work.
+
+## How to apply — bash → PowerShell
+
+| Don't give the user | Give instead |
+|---|---|
+| `export NAME=value` | `$env:NAME = "value"` |
+| `cmd1 && cmd2` | two separate lines (PS 5.1 has **no** `&&`). `;` runs sequentially but does **not** stop on failure |
+| `cmd1 \`<newline>` continuation | one line, or backtick `` ` `` continuation |
+| `cd /x/Roam/BlockLab` | `cd X:\Roam\BlockLab` |
+| `grep PAT file` | `Select-String -Path file -Pattern 'PAT'` |
+| `jq '.x' f.json` | `Get-Content f.json \| ConvertFrom-Json \| % { $_.x }` |
+| `cat` / `cut -d= -f2` | `Get-Content` / `.Split('=')[1]` |
+| `$(cmd)` | `(cmd)` (or `$(cmd)` works too, but `(cmd)` is idiomatic) |
+| `VAR=x cmd` (inline env) | `$env:VAR='x'; cmd` |
+
+**Interactive-prompt lines** (e.g. `keeper get` asking for a master password): tell the user to run that line
+**alone**, because a multi-line paste feeds the following lines into the prompt.
+
+## The WSL exception
+
+When the work is explicitly in **WSL** / a Linux shell (the user says so, the cwd is a WSL path like
+`/home/...` or `/mnt/...`, or the task is clearly Linux), **bash is the default there** — give bash commands.
+Default to PowerShell whenever it's the normal Windows terminal.
+
+## Scope
+
+This governs **user-facing commands** — what the user pastes into their terminal. The assistant's own `Bash`
+tool runs Git Bash internally and may keep using bash for its own execution; that's invisible to the user and
+fine. The rule is about what you *hand the user to run*.