From pwsh-code-review
How to bootstrap a PowerShell project with pwsh-code-review. Use when the user is setting up the reviewer on a new repo, when /pwsh-review-bootstrap runs, or when the existing profile needs refreshing.
How this skill is triggered — by the user, by Claude, or both
Slash command
/pwsh-code-review:pwsh-review-bootstrapThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill is invoked by `/pwsh-review-bootstrap`. It contains the procedure for walking a PowerShell repo, generating the project profile, and producing a usable starting point.
This skill is invoked by /pwsh-review-bootstrap. It contains the procedure for walking a PowerShell repo, generating the project profile, and producing a usable starting point.
The user runs the bootstrap once. They get back a .pwsh-review/ directory with files that:
<!-- TODO --> where unsure)Bad bootstrap looks like: generic boilerplate, made-up architecture descriptions, hallucinated function lists, glossary terms with invented definitions. Avoid this aggressively.
$psFiles = Get-ChildItem -Recurse -File -Include *.ps1, *.psm1, *.psd1
For each file, classify:
.psd1 with RootModule set: module manifest.psd1 without RootModule: data file (like our config files).psm1: module.ps1 in tests/ or matching *.Tests.ps1: Pester test.ps1 in Public/: public function file.ps1 in Private/: private function file.ps1 at root or scripts/: entry scriptBuild a table:
File | Role | Lines | Functions defined | Functions called externally
For each file, parse with [System.Management.Automation.Language.Parser]::ParseFile. Extract:
FunctionDefinitionAstCommandAst (function/cmdlet calls)VariableExpressionAst for $script:, $global:, $env:AssignmentStatementAst writing to those scopesImport-PowerShellDataFileIdentify cross-platform signals by scanning for:
\ in string literals representing pathsGet-CimInstance, Get-WmiObject, Get-ItemProperty 'HKLM:..', New-PSDrive -PSProvider Registry$env:USERPROFILE, $env:APPDATA, $env:LOCALAPPDATA, $env:PROGRAMFILESpowershell.exe references$IsWindows, $IsLinux, $IsMacOS references (good signal: project is platform-aware)New-Object -ComObject, [System.__ComObject]Test-NetConnection, Get-NetAdapter, *-Service, etc.Identify dependencies:
RequiredModulesImport-Module callsusing module statements& <name> where <name> is not a function)Look for the cleanest existing example of each canonical pattern:
pattern-pipeline-cmdlet.ps1: search for FunctionDefinitionAst where:
[CmdletBinding()][OutputType()]ValueFromPipeline = $trueprocess blockScore each candidate by:
[OutputType()] matching what is actually returnedSupportsShouldProcess if state-changing+= in a loop)Pick the highest-scoring candidate. Copy verbatim with a header comment:
# Canonical example from <relative-path>
# Picked because: pipeline-shaped, OutputType honest, CBH complete
If no candidate scores above zero, copy the template version.
pattern-error-handling.ps1: search for the cleanest existing function that uses try/catch with Write-Error -ErrorAction Stop (not bare throw "string"), distinguishes terminating from non-terminating, and has a justifying comment.
pattern-module-init.psm1: search for the cleanest .psm1 that does dot-source loading of Public/ and Private/, calls Export-ModuleMember correctly, and handles errors during load.
Walk all source files and extract identifiers (function names, parameter names, comment words) that:
DOTBOT, Worktree, Whisper, Outpost)Take the top 20. For each, find the first definition or descriptive use in a README or .SYNOPSIS block. Draft a glossary entry:
### Term
<!-- TODO: confirm definition -->
<inferred definition from first descriptive use, or "Domain term used in <count> places, definition not auto-inferable">
Used in: file:line, file:line, file:line
The user fills in or corrects. Never invent definitions.
From the module manifests' FunctionsToExport (if not '*'), build the list of public functions. If FunctionsToExport = '*', fall back to: every function defined in a Public/ directory, or every function whose file matches the function name.
For each public function, capture:
This goes into architecture.md and profile.lock.json.
architecture.mdHonest. Where uncertain, leave a TODO. Do not write paragraphs of generic prose about how "this project follows clean architecture". Stick to facts you can verify from the code:
standards.mdStart from templates/standards.md. Then merge in any rules detected from existing files:
.editorconfig: line endings, indent style, charsetPSScriptAnalyzerSettings.psd1: rule excludes and includesSTYLE.md or CODING_STANDARDS.md if present at repo root: copy relevant sectionsCONTRIBUTING.md: pull in any "code style" sectionIf the project has its own conventions that contradict the template, preserve the project's.
glossary.md20 entries maximum. All marked TODO. If you cannot infer the definition, say so explicitly:
### Widget
<!-- TODO: confirm definition -->
Domain term, appears in 47 places. Not auto-inferable from context.
Used in: src/server.ps1:42, src/Modules/WidgetCore/Public/New-Widget.ps1:1, ...
patterns/Three files minimum (pipeline, error handling, module init). Add more if obvious patterns emerge from the codebase (e.g. a clear "configuration loading" pattern, a clear "logging" pattern).
PSScriptAnalyzerSettings.psd1Copy templates/PSScriptAnalyzerSettings.psd1. Set Rules.PSUseCompatibleSyntax.TargetVersions based on the lowest PowerShellVersion in any manifest, or 7.4 if no manifest. Set Rules.PSUseCompatibleCmdlets.compatibility based on detected platforms.
config.psd1Set Platforms based on detection. Default ConfidenceThreshold to 80, NitCap to 3.
profile.lock.jsonSchema:
{
"version": "1",
"generated": "<ISO timestamp>",
"public_surface": {
"<function-name>": {
"signature_hash": "<sha256>",
"file": "<relative-path>"
}
},
"manifests": {
"<relative-path>": {
"hash": "<sha256>",
"version": "<from manifest>"
}
},
"top_dirs": {
"<dir>": "<sha256 of sorted file list>"
},
"ruleset_version": "1"
}
The freshness check on every review compares this against the current state.
--refresh regenerates intelligently:
.pwsh-review/, compute a structural diff between the new version and the existing.architecture.md, standards.md: show the user a section-by-section diff and ask which to apply. Default: apply factual updates (counts, lists), preserve prose edits.glossary.md, patterns/*.ps1: never overwrite. These are hand-curated. Just print "Skipped, hand-curated."PSScriptAnalyzerSettings.psd1: if the user has not modified it (matches the original generated version), update freely. If modified, show diff and ask.profile.lock.json and cache/: always regenerate.--force overwrites everything except cache. One confirmation prompt: "This will overwrite all hand edits in .pwsh-review/. Type 'overwrite' to confirm:". Anything other than exact match aborts.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub andresharpe/pwsh-code-review-marketplace --plugin pwsh-code-review