Claude-Guardian
Claude Guardian is an all-in-one Claude account safety and risk prevention skill. It intelligently assesses your device, account history, network environment, and payment options, then provides person
翻譯準備中
Claude Code 技能,用於 GitHub 問題管理、PR 工作流程與開發實用工具
AI 翻譯
Claude Code skills for GitHub issue management, PR workflows, and development utilities
技能Shell · PythonGitHub @ImperialAutomation自行安裝營運者未確認
試用過了嗎? 點一下就好,不需要登入。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
安裝型專案無需部署網域也可驗證。個人儲存庫可透過 GitHub 登入驗證,組織儲存庫可使用上方的儲存庫驗證檔案。
正在載入完整 README。 以下為已儲存的摘錄。
A collection of Claude Code skills, a global CLAUDE.md, and a project template for GitHub issue management, PR workflows, and development utilities.
This toolkit separates concerns into four layers:檢視完整 README ↗A collection of Claude Code skills, a global CLAUDE.md, and a project template for GitHub issue management, PR workflows, and development utilities.
This toolkit separates concerns into four layers:
Rules keep the global CLAUDE.md lean by moving context-specific instructions out of the always-loaded file. Skills and agents reference policies from CLAUDE.md and rules rather than duplicating them.
git clone https://github.com/JanKeijzer/claude-code-toolkit.git ~/Projects/claude-code-toolkit
cd ~/Projects/claude-code-toolkit
./install.sh
This creates five symlinks and copies one file:
~/.claude/skills → skills/ (all skills auto-discovered)~/.claude/agents → agents/ (sub-agents auto-discovered)~/.claude/bin → bin/ (helper scripts)~/.claude/rules → rules/ (contextual rules, loaded based on file patterns)~/.claude/CLAUDE.md → claude-md/global.md (global policies)~/.claude/settings.json ← copied from claude-md/settings-global.jsonc (global permissions)The settings file is copied (not symlinked) because Claude Code writes to it when you approve permissions during a session. Restart Claude Code after installation.
Running install.sh again never overwrites an existing ~/.claude/settings.json. It does run settings-sync-hooks.sh, which adds hooks the template gained since your first install (see Global Settings).
This repo is public, so it also ships a pre-commit hook that scans staged changes for secrets with gitleaks before every commit. Install it once per clone:
pip install --user pre-commit
pre-commit install
Without running pre-commit install, the hook is present in the repo but never fires — it must be installed per clone.
Skills are auto-discovered from ~/.claude/skills/*/SKILL.md. Agents are auto-discovered from ~/.claude/agents/*.md.
To set up a new project with a CLAUDE.md and settings:
# Project-specific policies
cp ~/Projects/claude-code-toolkit/claude-md/project-template.md /path/to/your/project/CLAUDE.md
# Project-specific permissions (remove comments and keep what applies)
mkdir -p /path/to/your/project/.claude
cp ~/Projects/claude-code-toolkit/claude-md/settings-template.jsonc /path/to/your/project/.claude/settings.json
Then fill in the sections relevant to your project. The settings template includes commented-out permissions for common tools (Docker, Python, Node, etc.) — uncomment what you need.
The toolkit includes specialized sub-agents for issue creation, infrastructure management, and deployment. They work together with a clear separation of concerns:
Rough idea → issue-crafter → Well-defined issues → /decompose (if large) → /implement or /implement-epic
↑ ↓
/refine (existing issues) devops-automator (deploy)
↑
infra-maintainer (advises) → GitHub issue → /implement (code) ───────────────┘
↑
or: human creates issue directly
| Agent | Role | Tools | Model |
|---|---|---|---|
issue-crafter | Translates rough ideas into well-structured GitHub issues. Asks clarifying questions, proposes issues for approval, then creates them. | Read, Grep, Glob, Bash, Write | Sonnet |
infra-maintainer | Read-only infrastructure advisor. Analyzes, diagnoses, and recommends — never makes direct changes. | Read, Grep, Glob, Bash (diagnostics only) | Sonnet |
devops-automator | Deployment engineer. The only path to production — always through the pipeline. | Read, Write, Edit, Grep, Glob, Bash | Sonnet |
Translates rough ideas and descriptions into well-structured GitHub issues. Explores the codebase for context, asks clarifying questions about scope and acceptance criteria, and presents structured proposals for approval before creating anything. Recommends /decompose for issues that are too large for a single PR.
Workflow (create): rough idea → codebase exploration → clarifying questions → issue proposal → human approval → gh issue create
Workflow (refine): existing issue → read & assess → interactive Q&A → updated proposal → human approval → gh issue edit
The /refine skill provides a shortcut to invoke the refine workflow for a specific issue.
Infrastructure advisor for self-managed VPS servers. Operates in read-only mode (no Write/Edit tools). Runs diagnostic commands, assesses risks, and proposes improvements as GitHub issues (with proposal + infra labels) — but only after human confirmation.
Analysis domains: server hardening, reverse proxy & SSL, backup & disaster recovery, monitoring & uptime, Docker management, security updates & vulnerability management.
Deployment engineer responsible for CI/CD pipelines and the path to production. Every change follows the same path: branch → test → PR → review → merge → deploy. No exceptions.
Scope: GitHub Actions workflows, deployment strategies (lightweight restart vs. full rebuild), Docker image management, environment & secret management, branch protection rules.
Agents are valuable because of their constraints: infra-maintainer is read-only, devops-automator is deployment-scoped. A "software engineer" agent would need all tools with no specific restrictions — that's just Claude Code itself. The /implement skill already encapsulates the full workflow: issue → branch → code + tests → PR.
The bin/ directory contains reusable shell scripts that skills call instead of using inline for loops.
Why? Claude Code permissions match on the first word of a Bash command. An inline loop like for issue in 15 16 17; do gh issue view $issue ...; done gets blocked because the first word is for, not gh. By wrapping batch operations in scripts, permissions can match on the script path (~/.claude/bin/*).
Global CLAUDE.md names each wrapper in one line and leaves the details to the script: cmd-save.sh, strip-ansi.sh, repeat-cmd.sh, http-status.sh, wait-for-pattern.sh, docker-scratch.sh, venv-run.sh and doc-budget-check.sh answer --help with their header comment (usage, exit codes, rules of use). bin/tests/test-script-help.sh pins that the help still carries what CLAUDE.md no longer says.
| Script | Usage | Description |
|---|---|---|
batch-issue-view.sh | batch-issue-view.sh [--output FILE] <repo> <issues...> | Fetch full issue details as JSON array |
batch-issue-status.sh | batch-issue-status.sh <repo> <issues...> | Fetch issue number/state/closed as JSON array |
batch-issue-edit.sh | batch-issue-edit.sh [--dry-run] <repo> <plan.tsv> | Apply label/milestone changes from a TSV plan (<issue>\t<add>\t<remove>\t<milestone>, - = no change) |
batch-pr-for-issues.sh | batch-pr-for-issues.sh <repo> <issues...> | Find merged/open PRs linked to issues |
find-tracking-pr.sh | find-tracking-pr.sh <repo> <issue> | Find the tracking PR for a parent issue |
gh-issues-export.sh | gh-issues-export.sh [--repo R] [--state S] [--output F] | Export GitHub issues to JSON file with search/filter |
gh-save.sh | gh-save.sh <output-file> <gh-args...> | Save gh command output to file (avoids redirect prompts) |
cmd-save.sh | cmd-save.sh [--stderr separate|merge] [--strip-ansi] <output-file> <command> [args...] | Save any command's output to a file. Options go before <output-file>; everything after it is the command. Reports the command's own exit status and the byte count written. The auto-approve hook approves it only when <command> is approvable on its own, and otherwise denies it with a hint to run <command> bare |
strip-ansi.sh | strip-ansi.sh <file> [<outfile>] | Write a copy of a file without ANSI colour/cursor codes (default <file>.clean), so captured test output can be grepped without a sed chain |
cmd-save.sh is the general case; gh-save.sh is the gh-shaped shorthand and delegates to it. Reach for it whenever output belongs on disk: to diff two captures, to feed one command's output into another, or because the output is too long to be worth putting through the model's context.
cmd-save.sh /tmp/pods.json kubectl get pods -o json
cmd-save.sh /tmp/inspect.json docker inspect my-container
cmd-save.sh /tmp/schema.sql docker exec db psql -U postgres -d app -t -A -c "SELECT ..."
cmd-save.sh --stderr merge /tmp/build.log npm run build
Three details it gets right that a bare redirect does not:
cmd ... > file reports whether the redirect worked, so a failed command still writes a file and looks like a success, and the caller reads an error message as data.--stderr merge when the capture exists to diagnose a failure rather than to carry data.Flag parsing stops at the output file, so everything after it belongs to the command and a command's own flags are never eaten as the wrapper's.
Coloured test-runner output (vitest, pytest with colour) is full of ANSI escapes, and grepping it otherwise means a grep ... | sed 's/\x1b\[[0-9;]*m//g' chain whose sed segment prompts every time. Capture it clean with cmd-save.sh --strip-ansi, or clean an existing capture with strip-ansi.sh and read the copy with Read/Grep. Both remove cursor codes and terminal hyperlinks too, which that colour-only regex leaves in place.
cmd-save.sh --strip-ansi /tmp/vitest.txt npx vitest run
strip-ansi.sh /tmp/vitest.txt # -> /tmp/vitest.txt.clean
| Script | Usage | Description |
|---|---|---|
git-find-base-branch | git-find-base-branch [--repo DIR | repo-dir] | Detect the base branch of the current branch, or of the given worktree |
git-resolve-worktree.sh | git-resolve-worktree.sh [--issue N] [hint] | Resolve a worktree hint to one absolute path. Refuses to guess: zero or several matches exit non-zero and list the candidates with their branches |
git-cleanup-merged-branch.sh | git-cleanup-merged-branch.sh [feature] [base] | Checkout base, fast-forward it to its upstream, delete merged feature branch |
extract-issue-from-branch.sh | extract-issue-from-branch.sh | Extract issue number from current branch name |
git-commit.sh | git-commit.sh [--repo DIR] [--allow-protected] <message> | Commit via temp file (avoids heredoc issues in sub-agents). Refuses to commit on a branch the repo marks protected (see below). Can print ok N files changed without committing — see failure modes |
git-verify.sh | git-verify.sh [--repo DIR | repo-dir] [--base B] [--alembic] | Read-only status snapshot (branch, uncommitted, recent commits, vs upstream, stashes, worktrees) in one call |
git-push-pr-merge.sh | git-push-pr-merge.sh [--repo DIR] [options] | Push, create PR, gate on CI checks (fail closed, matched to the pushed commit so a lagging PR head cannot be read as a verdict), merge, return to base (for /implement-epic). --repo targets a worktree instead of the current directory. Repos without CI need --no-ci-wait. A check that is red repo-wide for a cause unrelated to the diff (e.g. a dependency audit after a new advisory) is --allow-failing-check <name>, which keeps the rest of the gate on and records the bypass on the PASS line. --allow-failing-check <name>=<regex> narrows that bypass to one cause: the check's failed job log must match <regex>, so a different failure of the same check still blocks (it blocks too when the log cannot be read, or when the check is an external status with no job log). Creates the PR itself, so hooks do not fire; the gate also cannot prove a check set is complete — see |
git-commit.sh refuses to commit on a protected branch. In repos where every
change reaches the base branch through a PR, a commit on develop/master/main
is always a mistake. The instruction to check the branch first was already
written down twice and it still went wrong: a worktree was switched back to the
base branch after a merge, a later session wrote a follow-up commit there, and
only the push would have exposed it. Per the code-review rule, a convention
violated more than once belongs in a script rather than a doc, and the commit
wrapper is the one choke point every agent commit passes through, so a check
here runs whether or not an agent remembered the rule.
Which branches are protected is per repo, read from the first source that exists:
<repo>/.claude/protected-branches: one branch name per line; blank lines
and # comments ignored, so a branch name containing # has to go in git
config insteadgit config --get-all toolkit.protectedBranchThe file is the single source when it exists; git config is a fallback, not a
second contributor, so "why is this branch protected" has one answer. Neither
present protects nothing, which is the default; repos that commit straight to
main never notice the guard exists. Names match exactly, no globbing.
Commit the file. Left untracked it exists only in the tree where it was
created, so a linked worktree sees no config and the guard never fires there,
which is the one place the mistake is most likely. Tracking it puts the same
protection in every checkout. git config --get-all toolkit.protectedBranch does
not have this problem: worktrees share .git/config, so a value set once covers
all of them, at the cost of living outside version control.
A refusal costs one switch -c; a commit on a base branch costs a manual
untangle. --allow-protected overrides it where a direct commit is intended.
Detached HEAD is always allowed: rebases and bisects commit there routinely and
no base branch is at risk. The guard reads the branch of the tree named by
--repo, not the caller's. Those differ exactly when a session works in a
linked worktree, which is when the mistake happens.
git-resolve-worktree.sh exists because an agent's working directory resets
between every Bash call, and so do exported variables. In a repository with
linked worktrees nothing carries "work in that tree" from one command to the
next, so a bare git or a repo-relative path quietly acts on whichever directory
the session started in. The failure is silent: a commit can land on another
session's branch, carrying that session's staged files, and exit 0.
The script turns a short hint into the one absolute path that every following
command must carry (git -C <path>, git-commit.sh --repo <path>, absolute
Read/Edit paths). A hint is an exact worktree name, a unique case-insensitive
substring of its path, or an absolute path.
An exact name beats a substring. Worktree siblings are conventionally named
by suffixing the main tree (<repo>, <repo>-dev1, <repo>-dev2), so the main
tree's name appears inside every sibling's. Under a plain substring rule, typing
the exact name of the main tree matches all of them and resolves to nothing,
making the most common target the one tree you cannot name without an absolute
path. Exact-beats-partial is how tab-completion already behaves.
--issue N is the fallback when no hint resolves it: it finds the worktree on
branch issue-N-*, so resumed work needs no argument at all. When no tree is on
that branch — new work, before the branch exists — it reports the current
worktree rather than failing, the same answer as no arguments at all. Detection
that finds nothing is not an error; only a hint the user typed can be wrong.
Ambiguity is the interesting case: a hint matching several trees, or none, exits
non-zero with the candidates and their branches on stderr and nothing on
stdout, so a $(...) capture cannot silently become a guess. Single-worktree
projects never notice any of this.
--repo is the convention for every script that selects a git worktree:
git-commit.sh, git-diff-base.sh, git-push-pr-merge.sh, git-verify.sh and
git-find-base-branch all take that same path, for the same reason — without it
they read the start directory and act on the wrong tree. git-push-pr-merge.sh
is the one with real teeth: it pushes, opens a PR, and on merge runs checkout
and branch -D, so a wrong target is destructive to a tree nobody is watching.
It validates the path itself and refuses before pushing; the others fail loudly
through git. None of them fall back to the caller's directory.
Deliberately not -C, despite the resemblance to git -C. That flag means
"run as if git was started in <path>" — a chdir, which is why git -C "" is a
no-op and why multiple -Cs stack relative to each other. These scripts do
something narrower: select a worktree, and refuse a path that is not one.
Reusing the letter for different semantics is the wrong kind of consistency, and
a single letter buys nothing when the caller is an agent rather than a typist.
git-verify.sh and git-find-base-branch also still accept the path
positionally, so existing calls keep working. Naming the same tree twice is fine;
naming two different ones is an error rather than a silent pick, because the
loser is a tree the caller believed they were asking about.
Scripts that take a scan path rather than a worktree keep their positional
argument: deps-audit.sh, secret-scan.sh, env-audit.sh, docker-audit.sh,
docker-health-check.sh and epic-prepare-context.sh. secret-scan.sh ~/Downloads is a meaningful thing to ask for, and calling that --repo would
misdescribe the argument.
| Script | Usage | Description |
|---|---|---|
i18n-audit.py | i18n-audit.py [project-dir] | Audit i18n translation keys (missing, unused, undeterminable, cross-locale) |
env-audit.sh | env-audit.sh [project-dir] | Audit .env vs .env.example sync, empty values, secrets in git |
deps-audit.sh | deps-audit.sh [project-dir] | Audit npm/pip dependencies for known vulnerabilities |
docker-audit.sh | docker-audit.sh [project-dir] | Audit Docker config (unpinned images, health checks, secrets) |
| Script | Usage | Description |
|---|---|---|
secret-scan.sh | secret-scan.sh [project-dir] | Scan codebase for hardcoded secrets, API keys, tokens |
security-headers-check.sh | security-headers-check.sh <url> | Check HTTP security headers (CSP, HSTS, X-Frame-Options, etc.) |
owasp-zap-scan.sh | owasp-zap-scan.sh <url> | OWASP ZAP baseline scan via Docker (requires running target) |
secret-scan.sh and the gitleaks pre-commit hook (see Installation) are intentionally separate tools, not a pattern list to keep in sync: secret-scan.sh is an on-demand audit invoked manually or via /security-audit, while gitleaks is a commit-time gate that blocks git commit outright when it finds a match.
| Script | Usage | Description |
|---|---|---|
docker-health-check.sh | docker-health-check.sh [project-dir] [--timeout S] [--filter PREFIX] [--project NAME] | Runtime Docker container health verification (status, restarts, error logs). --filter names the container set directly and needs no compose file; without it the set comes from a compose file in the project root, queried under the project named by --project, by COMPOSE_PROJECT_NAME, or discovered from container labels. Exit 3 means the Docker daemon could not be reached |
smoke-test.sh | smoke-test.sh [base-url] [--health-token TOKEN] | API endpoint smoke testing with auto-discovery |
http-status.sh | http-status.sh [--body] [--max-time SECS] <url> [url...] | HTTP status per URL as a single command. One URL prints the bare code; several print <status> <url>. 4xx/5xx exit 0 (a valid answer); transport failures print ERR and exit 1 |
wait-for-pattern.sh | wait-for-pattern.sh [--newer-than EPOCH] <file> <extended-regex> [timeout] [poll] | Block until a regex appears in a file. Exit 0 prints the matching line(s); exit 1 dumps the file's current contents for diagnosis. A missing file is a normal starting state, not an error. --newer-than ignores the file until its mtime passes the given epoch |
wait-for-healthy.sh | wait-for-healthy.sh <container> [--timeout SECS] [--interval SECS] | Block until a Docker container reports healthy. Exit 1 on timeout |
repeat-cmd.sh | repeat-cmd.sh <count> <command> [args...] | Run a command N times for warm/cold timing, replacing for i in ...; do <cmd>; done. Output is discarded; stops at the first failing run and reports its number, exit status and stderr. Prints runs, total and per-run time. The auto-approve hook approves it only when <command> is approvable on its own, and otherwise denies it with a hint to run <command> bare |
docker-health-check.sh has to decide which containers belong to the project, and the compose file alone does not always say. docker compose -f <file> ps derives the project name from that file's directory, so a stack started under its own name (docker compose -p mystack -f a.yml -f b.yml up) or from an include: set lives in a project this query never asks about. The query then succeeds and returns nothing, which is the worst available failure: a running, healthy stack reads exactly like a stopped one.
The project name is therefore looked for in several places, in this order: --project <name>, then COMPOSE_PROJECT_NAME in the .env beside the compose file, then the containers' own com.docker.compose.project label, matched by finding the resolved compose file in their com.docker.compose.project.config_files. The label route is what makes the common case need no arguments at all. Only when none of those yields a name does it fall back to letting Compose guess from the directory.
--filter <prefix> skips that question entirely: the prefix names the container set directly, no compose file is consulted, and the containers come from docker ps -a (including stopped ones, which are findings rather than absences). It remains the right answer when the containers share a prefix but no compose project, and the only one when there is no compose file to point at. Record the prefix as Container prefix: in the project CLAUDE.md's Integration Verification section, where /verify and /pre-merge both read it.
Exit codes separate the three outcomes that used to look alike: 1 for container issues or a project with no containers, 2 for a usage error or a missing compose file, and 3 for a Docker daemon that could not be reached. Docker's own message comes through on exit 3, so a permission problem on the socket no longer presents itself as a stack you forgot to start.
wait-for-pattern.sh --newer-than <epoch> exists because a progress file whose
name is fixed per task is reused by every run of that task, and nothing clears it
in between. The second run's wait then matches the first run's PHASE: DONE
within a second, and the caller reports the previous run's result as the new
one — a complete, plausible, wrong answer, with nothing in the file saying which
run wrote it. Exit 0 carries no such information; the mtime does. Capture
SPAWNED_AT=$(date +%s) before starting the watched process and pass it, and
only a write made after that moment can satisfy the pattern. A file that stays
stale times out instead, and says so, naming the cutoff rather than leaving a
dump in which the pattern is visibly present. The /implement-epic skill pairs
this with resetting each progress file before its spawn: belt and braces for the
same mistake, since the reset is an instruction an agent can skip and the flag is
not.
http-status.sh exists for permission matching, not for curl features. curl -s -o /dev/null -w "%{http_code}\n" <url> is rarely wanted just once, and two on a line make a compound command — every segment after the ; or && goes unmatched and prompts, even with a broad Bash(curl *) rule allowlisted. Auth headers, retries and JSON parsing are deliberately absent: past that point it is not a smoke test and calling curl directly is clearer. For waiting until a service comes up, use wait-for-pattern.sh or wait-for-healthy.sh.
| Script | Usage | Description |
|---|---|---|
project-test.sh | project-test.sh [pytest-args...] | Run pytest with automatic venv detection (guardrailed to ~/Projects/). The venv follows the test path's project root, so a path in another worktree uses that worktree's interpreter |
venv-run.sh | venv-run.sh [--repo <dir>] <cmd> [args...] | Run any venv binary (python, alembic, ruff) with auto-detection, falling back to PATH. --repo picks the project root when it is not the current directory. The auto-approve hook approves it only when <cmd> is approvable on its own, and otherwise denies it with a hint to run <cmd> bare, so pip gets the same permission flow as it does bare |
docker-scratch.sh | docker-scratch.sh dir|worktree|clean [--repo D] <purpose> [<ref>] | Scratch location a Docker container can mount: ~/.cache/claude-scratch/<project>/<purpose>/. dir creates and prints it, worktree checks a ref out there as a detached base checkout, clean <purpose>|--all removes it (worktrees through git) without a prompt |
sync-toolkit.sh | sync-toolkit.sh <pull|status|drift> | Sync toolkit from git sources (used by /sync-toolkit skill) |
settings-sync-hooks.sh | settings-sync-hooks.sh [--dry-run] [--settings PATH] [--template PATH] | Add hooks from settings-global.jsonc that are missing in ~/.claude/settings.json; backs up to a new settings.json.<timestamp>.bak; run by install.sh |
json-find-key.sh | json-find-key.sh <key> <file> [--values] | Search for a key in nested JSON files |
odt2txt.sh | odt2txt.sh <input.odt> <output.txt> | Convert ODT to plain text via pandoc |
release.sh | release.sh [major|minor|patch] | Create a GitHub release for a WordPress plugin |
docker-scratch.sh exists because Docker Desktop shares $HOME with its VM but not /tmp, so a tree in the scratchpad or /tmp cannot be bind-mounted (mounts denied: ... is not shared from the host). Without a fixed alternative an agent improvises one, and whole base checkouts end up in ~/Downloads. The location sits under $HOME so Docker shares it, and outside every project tree so test discovery, linters and docker build . never pick up a second checkout. clean is the reason it is a script rather than a documented path: it validates <purpose> as one path component, so its rm -rf cannot reach outside the scratch root, and it unregisters a worktree through git worktree remove instead of leaving it in git worktree list. On native Linux Docker a container running as root leaves root-owned files in the mount; clean then exits 1 naming the directory rather than reporting success.
| Script | Usage | Description |
|---|---|---|
hook-auto-approve-bash.sh | PreToolUse hook in settings.json | Thin wrapper — exec's hook-auto-approve-bash.py |
hook-auto-approve-bash.py | invoked by the .sh wrapper above | Auto-approve safe compound commands via real shlex tokenization (cd-prefix, ;/&&/|/|| chains, env-var prefixes, a model-typed rtk/rtk proxy prefix); rejects command substitution and heredocs; denies sed/inline-Python file reads and until+sleep file wait loops with a hint naming the right tool; denies a command-running wrapper (cmd-save.sh, repeat-cmd.sh, venv-run.sh) whose inner command is not approvable, with a hint to run that command bare (<wrapper> --help alone runs nothing and is approved) |
hook-block-destructive.sh | PreToolUse hook in settings.json | Block destructive Bash commands (force push, rm -rf, destructive SQL, etc.) |
hook-block-foreign-worktree-git.sh | PreToolUse hook in settings.json | Block git -C <other-worktree> checkout/restore/reset/clean/stash that would discard another worktree's uncommitted work |
hook-post-edit-lint.sh | PostToolUse hook in settings.json | Run ruff on Python files after Write/Edit (advisory, non-blocking) |
hook-post-prune-branch-config.sh | PostToolUse hook in settings.json | After a branch deletion, remove [branch "<name>"] config sections whose branch no longer exists. A sandboxed git branch -d cannot write .git/config and leaves them behind; the hook runs outside the sandbox and touches nothing else |
All scripts are already allowed in the global settings (~/.claude/settings.json) installed by the toolkit.
| Script | Usage | Description |
|---|---|---|
permission-friction.py | permission-friction.py [project-dir] [--days N] [--json] [--rewrite-prefix CMD] | Scan session transcripts for permission friction: estimated prompted calls, explicit denials, and top prompt-causing patterns. Chain friction is attributed to the segment that defeats matching, not the first token. Hook denies (including cd <dir> && <cmd> chains) are reported separately and excluded from the estimate. Used by /retro's Permission Friction phase |
doc-budget-check.sh | doc-budget-check.sh [--warn SIZE] [--fail SIZE] [--repo DIR] <doc-root>... | Per-file byte budget for markdown docs: lists files over the warn size (default 15K), exits 1 for any over the fail size (default 25K). Skips archive/ dirs; deliberate exceptions go in <repo>/.claude/doc-budget-exceptions, and an exception that is back under budget is reported as stale. Used by /retro before and after writing; works as a pre-commit or CI step (see --help) |
claude-code-toolkit/
├── agents/ ← sub-agent definitions
│ ├── issue-crafter.md ← idea → well-defined GitHub issues
│ ├── infra-maintainer.md ← read-only infrastructure advisor
│ └── devops-automator.md ← deployment engineer
├── bin/ ← helper scripts (batch operations, git utilities)
│ ├── batch-issue-view.sh ← fetch multiple issues as JSON array
│ ├── batch-issue-status.sh ← fetch issue status as JSON array
│ ├── batch-issue-edit.sh ← apply label/milestone changes from a TSV plan
│ ├── git-find-base-branch ← detect base branch (of a given worktree)
│ ├── git-verify.sh ← read-only git status snapshot in one call
│ ├── git-resolve-worktree.sh ← resolve a worktree hint to one absolute path
│ ├── git-cleanup-merged-branch.sh ← cleanup after PR merge
│ ├── git-commit.sh ← commit via temp file (sub-agent safe)
│ ├── git-push-pr-merge.sh ← push, PR, merge, return to base
│ ├── batch-pr-for-issues.sh ← find merged/open PRs linked to issues
│ ├── find-tracking-pr.sh ← find tracking PR for a parent issue
│ ├── extract-issue-from-branch.sh ← extract issue number from branch name
│ ├── i18n-audit.py ← audit i18n translation keys across a project
│ ├── env-audit.sh ← audit .env vs .env.example sync
│ ├── deps-audit.sh ← audit npm/pip dependencies for vulnerabilities
│ ├── docker-audit.sh ← audit Docker config for common issues
│ ├── docker-health-check.sh ← runtime Docker container health verification
│ ├── smoke-test.sh ← API endpoint smoke testing with auto-discovery
│ ├── http-status.sh ← HTTP status for one or more URLs (single command)
│ ├── project-test.sh ← run pytest with automatic venv detection
│ ├── venv-run.sh ← run any venv binary (python, alembic, ruff)
│ ├── secret-scan.sh ← scan for hardcoded secrets and API keys
│ ├── security-headers-check.sh ← check HTTP security headers
│ ├── owasp-zap-scan.sh ← OWASP ZAP baseline security scan
│ ├── gh-issues-export.sh ← export GitHub issues to JSON file
│ ├── gh-save.sh ← save gh command output to file
│ ├── cmd-save.sh ← save any command's output to file
│ ├── strip-ansi.sh ← copy a file without ANSI escape codes
│ ├── sync-toolkit.sh ← sync toolkit from configured git sources
│ ├── settings-sync-hooks.sh ← add missing template hooks to settings.json
│ ├── json-find-key.sh ← search for keys in nested JSON files
│ ├── odt2txt.sh ← convert ODT to plain text via pandoc
│ ├── release.sh ← create GitHub release for WordPress plugin
│ ├── hook-auto-approve-bash.sh ← PreToolUse hook: thin wrapper, exec's the .py below
│ ├── hook-auto-approve-bash.py ← real implementation: shlex-tokenized compound-command approval
│ ├── test-hook-auto-approve-bash.py ← standalone tests for the above
│ ├── hook-block-destructive.sh ← PreToolUse hook: block destructive commands
│ ├── test-hook-block-destructive.sh ← standalone tests for the above
│ ├── hook-block-foreign-worktree-git.sh ← PreToolUse hook: block cross-worktree git destruction
│ ├── test-hook-block-foreign-worktree-git.sh ← standalone tests for the above
│ ├── hook-post-edit-lint.sh ← PostToolUse hook: ruff lint after Write/Edit
│ ├── hook-post-prune-branch-config.sh ← PostToolUse hook: drop config of deleted branches
│ ├── doc-budget-check.sh ← per-file byte budget for docs (used by /retro)
│ ├── permission-friction.py ← scan transcripts for permission friction (used by /retro)
│ └── test-permission-friction.py ← standalone tests for the above
├── skills/ ← skill definitions (procedures)
│ ├── refine/
│ ├── implement/
│ ├── implement-epic/
│ ├── decompose/
│ ├── bug/
│ ├── cleanup/
│ ├── extend/
│ ├── finish/
│ ├── help-issues/
│ ├── audit/
│ ├── security-audit/
│ ├── debug/
│ ├── ss/
│ ├── sync-closes/
│ ├── update-tracking/
│ ├── verify/
│ ├── review/
│ ├── test/
│ ├── pre-merge/
│ ├── retro/
│ └── sync-toolkit/
├── rules/ ← contextual rules → ~/.claude/rules/
│ ├── error-handling.md ← error propagation, RFC 9457, boundary translation
│ ├── api-design.md ← HTTP status codes, Problem Details, pagination
│ ├── data-integrity.md ← transactions, constraints, idempotency, migrations
│ ├── structured-logging.md ← structured fields, severity levels, no secrets
│ ├── testing.md ← test quality policy (loads for test files and fakes/mocks)
│ ├── code-review.md ← code review conduct
│ └── documentation.md ← documentation standards (loads for .md files only)
├── claude-md/ ← CLAUDE.md files (policies) and settings
│ ├── global.md ← global policies → ~/.claude/CLAUDE.md
│ ├── settings-global.jsonc ← global permissions → ~/.claude/settings.json
│ ├── project-template.md ← template for project-specific CLAUDE.md
│ ├── settings-template.jsonc ← template for project-specific settings
│ └── procedures/ ← shared procedure snippets (added through a toolkit issue)
├── install.sh ← creates symlinks + copies settings
└── README.md
claude-md/settings-global.jsonc)Copied to ~/.claude/settings.json by install.sh. Pre-configures permissions so Claude Code can work without constant approval prompts:
~/.claude/bin/This is a copy (not symlink) because Claude Code writes to it when you approve permissions during a session.
Because it is a copy, later changes to the template do not reach it by themselves. For hooks, settings-sync-hooks.sh (also run by install.sh when the file exists) closes that gap:
settings.json.<YYYYmmdd-HHMMSS>.bak (an existing backup is never overwritten), then replaces the file atomically (2-space JSON, key order kept). --dry-run shows what it would add.settings-global.jsonc → ~/.claude/settings.json)The global settings include three PreToolUse hooks that run in all permission modes, including bypass-permissions:
hook-auto-approve-bash.sh (thin wrapper for hook-auto-approve-bash.py) — Auto-approves safe compound commands that permission matching would otherwise block. The .py implementation tokenizes the full command with shlex (not regex) and splits it into segments on &&, ||, ;, |. It strips a leading cd <dir> when <dir> resolves inside ~/Projects/, leading VAR=value env prefixes (except variables that make a command load or run code, such as PATH, PAGER, PYTHONPATH and the LD_*/GIT_*/npm_config_* families: those are never stripped, so the command prompts), and a model-typed rtk or rtk proxy prefix (so rtk grep ... is judged as grep ...), then approves only if every segment's first token is on a conservative allowlist (the safe commands already allowed in settings.json, plus echo/sleep/test/true). Command substitution ($(...), backticks) and heredocs/here-strings (<<, <<<) are never auto-approved, except git commit in any form. Unparseable input (unbalanced quotes, etc.) always falls through to the normal prompt — the hook fails open to the prompt, never to approval.
The same hook also denies four shapes that already have a better tool, each with a hint naming it. A deny wins over the allow path, so it fires even when every segment is otherwise allowlisted:
| Denied | Use instead |
|---|---|
sed -n 'X,Yp' <file> | the Read tool with offset/limit |
inline Python (-c or a heredoc) that opens a file for reading | Read, Grep, or Edit |
until <file-condition>; do sleep N; done | wait-for-pattern.sh [--newer-than <epoch>] <file> <extended-regex> [timeout] [poll] |
cd <dir> && <cmd> | git -C, npm --prefix, or env -C <dir> <cmd> (approved when <dir> is inside ~/Projects and <cmd> is approvable on its own) |
To use bypass-permissions mode with these safety nets:
claude --dangerously-skip-permissions -p "your task here"
claude-md/global.md)Symlinked to ~/.claude/CLAUDE.md, applies to all projects. Contains only what's needed in every conversation:
Contextual rules live in rules/ and load based on their frontmatter: some always (error handling, API design, data integrity, structured logging, code review), others only when relevant files are edited (testing, documentation, stripe-testing).
rules/)Rules provide contextual policies that load based on frontmatter configuration. Always-loaded rules apply to every conversation; path-triggered rules load only when matching files are being edited.
| Rule | Loads | What it enforces |
|---|---|---|
error-handling.md | Always | Never swallow errors, add context when propagating, translate at boundaries, RFC 9457 Problem Details |
api-design.md | Always | Standard HTTP status codes, RFC 9457 errors, cursor-based pagination, rate limiting headers |
data-integrity.md | Always | Transactions, DB constraints, idempotency, race condition prevention, expand-contract migrations |
structured-logging.md | Always | Structured key-value pairs, consistent field names, severity levels, never log secrets |
code-review.md | Always | No performative agreement, verify before implementing, push back when feedback is wrong |
testing.md | Test files, fakes and mocks | Real behavior over mocks, fakes validate like the real API, 5 test scenarios per feature, realistic fixtures |
documentation.md | .md files | Current purpose over history, usage guidance, no changelogs |
stripe-testing.md | Stripe-named files and stripe/ dirs (generic payment/billing files load payments.md only) | Never real cards, no raw PANs in code, assert on decline codes, prove webhook idempotency |
claude-md/project-template.md)Copy to a project root as CLAUDE.md and fill in:
claude-md/settings-template.jsonc)Copy to .claude/settings.json in your project. Contains commented-out permissions for common tools (Docker, Python, Node, project scripts) and safe deny-defaults for destructive git operations. Uncomment what applies to your project.
Global permissions (git, gh, edit, file operations) are in ~/.claude/settings.json — don't repeat them in project settings.
| Skill | Syntax | Description |
|---|---|---|
/refine | /refine <issue> | Refine a GitHub issue through interactive Q&A to sharpen scope and criteria |
/decompose | /decompose <issue> | Break down a large issue into sub-issues with a tracking PR |
/extend | /extend [issue] or /extend add #issue [to #parent] | Add more sub-issues or link existing issues to a tracking PR |
/implement | /implement <issue> | Implement a GitHub issue with automated PR creation |
/implement-epic | /implement-epic <parent-issue> | Implement all sub-issues of an epic in dependency order |
/finish | /finish [issue] [base] | Commit, close issue, merge to base branch, cleanup |
/bug | /bug ["<title>"] or /bug add #issue [to #parent] | Create a bug interactively or with a title, or add existing issues to tracking PR |
/update-tracking | /update-tracking <pr> | Update tracking PR with current sub-issue status |
/sync-closes | /sync-closes <pr> | Sync all Closes statements in tracking PR |
/cleanup | /cleanup | Clean up after merging a PR (checkout base, delete branch) |
/help-issues | /help-issues | Show quick reference for issue management |
/audit | /audit [i18n|env|deps|docker|all] | Run project audits (i18n, env, deps, docker) |
/security-audit | /security-audit [domain|issue] | OWASP-guided security code review per domain |
/debug | /debug <description> | Systematic debugging — find root cause before fixes |
/ss |
| Skill | Syntax | When to Use |
|---|---|---|
/refine | /refine <issue> | Sharpen scope & acceptance criteria (run on parent AND each sub-issue) |
/decompose | /decompose <issue> | Start: break down large issue |
/implement-epic | /implement-epic <parent-issue> | Auto-implement all sub-issues |
/extend | /extend [issue] or /extend add #issue | Later: add more sub-issues or link existing |
/bug | /bug ["<title>"] or /bug add #issue | Bug found during work, or add existing issue |
/update-tracking | /update-tracking <pr> | Update status table |
/sync-closes | /sync-closes <pr> | Sync Closes statements |
flowchart TD
subgraph phase0 [Phase 0: Refinement]
R[Rough Issue] -->|refine| A[Well-defined Issue]
end
subgraph phase1 [Phase 1: Decomposition]
A -->|decompose| B[Draft PR]
B --> C[Sub-issues]
C -->|refine each| C2[Refined sub-issues]
end
subgraph phase2 [Phase 2: Implementation]
C2 -->|manual| D{Work on sub-issue}
C2 -->|automated| AUTO[implement-epic]
AUTO --> J
D -->|Bug found| E[bug command]
E --> F[Bug issue]
F --> G[Added to PR]
D -->|Done| H[Sub-issue complete]
H --> I[update-tracking]
I --> J[Progress 33%]
end
subgraph phase2b [Phase 2b: Verification]
J -->|verify| V1[Container Health]
J -->|verify| V2[API Smoke Test]
J -->|verify| V3[Migration Check]
J -->|verify| V4[Browser Test]
V1 --> VR[Verification Report]
V2 --> VR
V3 --> VR
V4 --> VR
end
subgraph phase3 [Phase 3: Extension]
VR -->|More work needed| K[extend command]
K --> L[New sub-issues]
L --> D
end
subgraph phase4 [Phase 4: Completion]
VR -->|All done| M[sync-closes]
M --> N[All Closes statements]
N --> O[Merge PR]
O --> P[Auto-close issues]
end
style R fill:#f3e5f5
style A fill:#e1f5fe
style B fill:#fff3e0
style VR fill:#e8f5e9
style P fill:#c8e6c9
Knowledge moves from a working session into the shared toolkit in three steps:
/retro captures knowledge from any working session (debug, implementation, configuration, deployment) as project-local artefacts: scripts, CLAUDE.md procedures, design decisions, auto-memory entries./implement <issue> in this repo builds the generalised version with a branch, tests and a PR. After the merge, the source project acts on its note: the local script becomes a thin wrapper around the toolkit version (or goes), and its CLAUDE.md points at the toolkit.The rule: capture locally first, file a toolkit issue when you have seen the pattern twice.
For use across multiple devices (laptop, servers, cloud sandboxes):
install.sh on the first device (creates symlinks + toolkit.yaml)/sync-toolkit pull to install from configured sources/sync-toolkit drift to check for local modificationsConfiguration lives in ~/.claude/toolkit.yaml. Add private repos there for proprietary skills.
/refine - Refine IssueWhen: You have a rough issue that needs sharper scope and acceptance criteria. Use on the parent issue before /decompose, then on each sub-issue after. Every refine pass makes the issue more concrete and catches gaps early.
What it does:
Syntax:
/refine 42
Example output:
Reading issue #42: Add invoice attachment storage...
Current issue is missing:
- Specific acceptance criteria
- Scope boundaries (which file types? size limits?)
- Storage strategy
Questions:
1. Should attachments be stored on local disk or S3?
2. What file types need to be supported?
3. Is there a maximum file size?
[... Q&A rounds until sharp ...]
Proposed updated issue: [full body with Context, Scope, Acceptance Criteria]
Update issue #42 with this? (y/n)
/decompose - Break Down IssueWhen: You have a large issue that's too complex for a single PR.
What it does:
Closes #XXX statementsSyntax:
/decompose 723
Example output:
Analyzing issue #723: Stripe Payment Provider
Proposed breakdown:
| # | Sub-Issue | Scope |
|---|-----------|-------|
| 1 | Phase 1: Abstraction Layer | Backend |
| 2 | Phase 2: Stripe Integration | Backend |
| 3 | Phase 3: Frontend Updates | Frontend |
Create draft PR and sub-issues? (A/B/C)
/implement-epic - Implement All Sub-IssuesWhen: You've decomposed an epic into sub-issues and want to implement them all automatically.
What it does:
Syntax:
/implement-epic 723
Workflow position:
/refine → /decompose → /refine (per sub-issue) → /implement-epic → tracking PR (manual merge to develop)
Difference from /implement:
| Aspect | /implement | /implement-epic |
|---|---|---|
| Scope | Single issue | All sub-issues of an epic |
| Confirmation | Stops for plan approval | Runs autonomously |
| PRs | One PR against base branch | One PR per sub-issue against feature branch |
| Failure | Stops on failure | Creates bug issue, skips dependents, continues |
| Verification | CLAUDE.md pattern-based (only when Docker files changed) | Always runs full verification |
/extend - Add More Sub-IssuesWhen: You've completed the first batch of sub-issues and want to tackle the next phase.
What it does:
Syntax:
/extend 723 # Decompose new sub-issues for remaining tasks
/extend # Detect parent from branch
/extend add #1042 to #723 # Add existing issue to tracking PR
/extend add #1042 #1043 # Add multiple issues (parent from branch)
Difference from /decompose:
| Aspect | /decompose | /extend |
|---|---|---|
| Creates PR | Yes (new) | No (updates existing) |
| Focus | Everything | Only remaining tasks |
/bug - Create Bug IssueWhen: You find a bug while working on a sub-issue, or want to add an existing issue to a tracking PR.
What it does:
Closes #XXX statementsSyntax:
/bug # Interactive mode — gathers context first
/bug "Webhook signature fails" # Create with title, parent from branch
/bug 724 "Webhook signature fails" # Create with explicit parent #724
/bug add #1042 # Add existing issue to tracking PR
/bug add #1042 to #723 # Add with explicit parent
Example:
$ git branch
issue-724-stripe-webhook
$ /bug "Signature verification fails in test mode"
✅ Created: #730 - 🐛 [Parent #724] Bug: Signature verification fails
✅ Added to tracking PR #727
✅ Will auto-close on merge
/update-tracking - Update StatusWhen: You want to update the progress in the tracking PR.
What it does:
Syntax:
/update-tracking 727
Status indicators:
| Emoji | Meaning |
|---|---|
| ⏳ | Pending - not started |
| 🔄 | In Progress - has open PR |
| ✅ | Complete - issue closed |
| ❌ | Blocked |
| 🎉 | 100% done |
/sync-closes - Sync Closes StatementsWhen: Before merging, to ensure all issues will auto-close.
What it does:
Closes #XXX statementsSyntax:
/sync-closes 727
Example:
Current Closes: #723, #724, #725
Found in table: #723, #724, #725, #730 (bug)
Missing: #730
Add "Closes #730" to PR? (y/n)
/verify - Runtime VerificationWhen: After implementation, after Docker changes, or whenever you want to check if the application is actually running correctly.
What it does:
Syntax:
/verify # quick mode (layers 1-3)
/verify quick # same as above
/verify full # all 4 layers including browser
/verify browser # browser smoke test only
Project configuration: Add an Integration Verification section to your project's CLAUDE.md to configure URLs, container prefixes, health tokens, and trigger patterns. See the project template for the format.
Example output:
## Verification Report
| Check | Status | Details |
|-------|--------|---------|
| Containers | PASS | 5/5 healthy |
| API Health | PASS | 200 OK, all components healthy |
| Migrations | PASS | Current matches head |
| Browser | WARN | 2 console warnings (non-critical) |
Overall: PASS
# Issue #723 exists but is vague: "Add Stripe payments"
/refine 723
# Output:
# Reading issue #723...
# Questions about scope, payment methods, error handling...
# [Q&A rounds]
# ✅ Updated issue #723 with clear scope and acceptance criteria
# Issue #723: Stripe Payment Provider (now well-defined, 5 phases)
/decompose 723
# Output:
# ✅ Created draft PR #727
# ✅ Created sub-issues: #724, #725, #726
# ✅ Progress: 0/3 (0%)
# Each sub-issue benefits from a refine pass — sharpens scope and catches gaps
/refine 724
/refine 725
/refine 726
# Output per issue:
# Questions about edge cases, error handling, specific acceptance criteria...
# [Q&A rounds]
# ✅ Updated issue with concrete scope and testable criteria
# Option A: Implement all sub-issues automatically
/implement-epic 723
# Output:
# Wave 1: #724 (no deps)
# Wave 2: #725 (depends on #724), #726 (depends on #724)
#
# Implementing #724... ✅ PR #731 merged
# Implementing #725... ✅ PR #732 merged
# Implementing #726... ❌ Failed → bug #730 created
#
# Results: 2/3 complete, 1 bug created
# Option B: Implement sub-issues manually one by one
/implement 724
/implement 725
# On branch issue-724-abstraction-layer
/bug "Factory pattern doesn't work with async"
# Output:
# ✅ Created #730 - 🐛 Bug: Factory pattern doesn't work
# ✅ Added to PR #727
/update-tracking 727
# Output:
# #724 - Abstraction: ⏳ → ✅ (PR #731 merged)
# #725 - Stripe: ⏳ → 🔄 (PR #732 open)
# #730 - Bug: ⏳ → ✅ (fixed in #731)
# Progress: 2/4 (50%)
/extend 723
# Output:
# Existing: #724 ✅, #725 🔄, #726 ⏳, #730 ✅
# Remaining tasks: Phase 4 (Frontend), Phase 5 (Testing)
#
# Create #733, #734? (y/n)
/sync-closes 727
# Output:
# All 7 issues have Closes statements ✅
# Ready to merge!
# Merge PR #727 → develop
# Auto-closes: #723, #724, #725, #726, #730, #733, #734
#723 (Parent Issue)
│
├── PR #727 (Tracking PR)
│ ├── Closes #723
│ ├── Closes #724
│ ├── Closes #725
│ └── ...
│
├── #724 (Sub-issue: Phase 1)
│ └── #730 (Bug found in #724)
│
├── #725 (Sub-issue: Phase 2)
│
├── #726 (Sub-issue: Phase 3)
│
└── #733, #734 (Added later via /extend)
/refine on the parent issue before decomposing, then on each sub-issue after. Every pass sharpens scope and catches gaps/update-tracking after each merge/sync-closes before final mergeissue-XXX-description for auto-detectionEach skill is a directory containing a SKILL.md file with YAML frontmatter:
---
name: my-skill
description: What this skill does
argument-hint: <required-arg> [optional-arg]
user-invocable: true
---
Instructions for Claude Code when the skill is invoked...
MIT
gh pr createEach deny is deliberately narrow, so that work with no wrapper to point at keeps falling through to a normal prompt rather than being blocked: a real sed stream edit, Python doing calculation or writing a file, and wait loops polling anything other than a file (an HTTP status, a container state, a command's exit status) are all left alone. while loops are not matched either: while [ -f X ] waits for a file to disappear, which wait-for-pattern.sh cannot express.
hook-block-destructive.sh — Blocks destructive patterns: rm -rf /, git push --force, git reset --hard, git clean -f, dd if=... of=/dev/, and more. When blocked, Claude sees the reason and adjusts its approach.
Destructive SQL is checked as a group rather than as a list of substrings, so the statements that drop a table, a database or a schema, the role-level drop, the truncate and an unqualified DELETE all get the same answer. That consistency is the point: when only the obvious phrasing was refused, the equivalent one became the workaround. A DELETE with a WHERE clause stays allowed, and a statement that merely appears as an argument to a read-only command (searching a file for one, or naming one in a commit message) is not treated as running it.
hook-block-foreign-worktree-git.sh — Blocks a destructive git command (checkout --, checkout -f, restore, reset, clean, stash) that targets a different worktree via -C/--git-dir. Linked worktrees share one repository but hold independent uncommitted work, so restoring a sibling tree to HEAD silently destroys whatever another session was editing there. Only cross-worktree operations are blocked: inside your own tree these commands stay untouched, and unrelated checkouts (a different .git) are left alone. Read-only git stash list/show pass through. Set WORKTREE_GUARD_HINT from a small project wrapper to append a repo-specific alternative (e.g. an isolated test runner) to the block message.
/ss [number] |
| Find recent screenshots |
/retro | /retro [focus-area] | End-of-session retrospective — capture knowledge as scripts, procedures, decisions, or skill proposals |
/verify | /verify [quick|full|browser] | Runtime verification — containers, API health, migrations, browser smoke test |
/review | /review [--staged|--branch|--file PATH] | On-demand code review of current changes with automated checks |
/test | /test [--all|--affected] | Smart test runner that scopes tests based on changed files |
/pre-merge | /pre-merge | Combined quality gate — orchestrates review, tests, verification, AC checks |
/sync-toolkit | /sync-toolkit <pull|status|drift> | Sync toolkit across devices from configured git sources |
/stripe-testing | /stripe-testing | Stripe test values — cards, declines, 3DS, disputes, refunds, SEPA/ACH, webhooks |