Files
claudetools/.claude/standards/powershell/execution-pattern.md
Mike Swanson dd0ef45645 feat: implement agent-os standards system and feature planning tools
- Split CODING_GUIDELINES.md into 19 indexed standards files under .claude/standards/
  - 9 from CODING_GUIDELINES (conventions, powershell, security, api, git, gururmm)
  - 10 from session log tribal knowledge (syncro, ssh, gitea, python, client, gururmm)
- Add .claude/standards/index.yml for cheap relevance-based lookup
- Add /inject-standards command: load targeted standards per task instead of full guidelines
- Add /shape-spec command: pre-implementation spec for GuruRMM features (plan.md,
  shape.md, references.md, standards.md) with mandatory out-of-scope gate
- Add docs/tech-stack.md and docs/mission.md for ClaudeTools API
- Add projects/msp-tools/guru-rmm/docs/tech-stack.md and mission.md for GuruRMM
- Update CLAUDE.md commands table with /inject-standards and /shape-spec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 12:59:49 -07:00

2.5 KiB

name, description, applies-to
name description applies-to
execution-pattern Always write PowerShell to .ps1 files and run with -NoProfile -File, never -Command inline powershell, all

PowerShell Execution Pattern (Windows)

Rule: Always use -NoProfile -File

Never use inline PowerShell commands (-Command or -c). Always write scripts to .ps1 files and execute with -NoProfile -File.

Rationale

  • Prevents font/codepage changes: PowerShell profile scripts often set chcp 65001 or modify [Console]::OutputEncoding, which changes the Claude Code CLI font and breaks rendering. -NoProfile skips all profile scripts.
  • Avoids Git Bash quoting issues: Inline commands have unpredictable quote escaping and variable expansion ($_, $foo) before PowerShell sees them. What you write is not what PowerShell receives.
  • Enforced by hooks: .claude/hooks/pre-bash-pwsh-script.sh blocks inline execution and rejects the command before it runs.

Correct pattern

# Write script to file using the Write tool
# (Write tool creates the file; Bash tool executes it)

# Execute with -NoProfile -File
pwsh -NoProfile -File /tmp/script.ps1

Or using a temp file in the claudetools tmp directory (safe from /tmp path mismatch):

# Write to .claude/tmp/ which both Write tool and Bash agree on
pwsh -NoProfile -File D:/claudetools/.claude/tmp/script.ps1

Incorrect (BLOCKED BY HOOKS)

# These will be rejected by the pre-bash-pwsh-script.sh hook
powershell -Command "Get-Process"
pwsh -c "Get-Date"
powershell.exe -Command '$x = 5; Write-Host $x'
powershell.exe -Command "Get-Service GuruRMMAgent"

Hook enforcement

The hook at .claude/hooks/pre-bash-pwsh-script.sh intercepts any Bash tool call and checks for the patterns powershell.*-Command, powershell.*-c, pwsh.*-c, pwsh.*-Command. If matched, the hook returns a non-zero exit code and the command is rejected.

The hook extracts only the tool_input.command field via jq before grepping — this prevents false positives from grep matching echo arguments or heredoc content.

Note on /tmp path ambiguity on Windows

On Windows, /tmp resolves differently in Git Bash vs. the Write tool. Git Bash maps /tmp to %LOCALAPPDATA%\Temp\, while the Write tool may create files in C:\tmp\. This mismatch has caused wrong-content file reads in past sessions. Use D:/claudetools/.claude/tmp/ as the temp directory for any file that needs to be read back by a Bash command.

Reference

See .claude/hooks/pre-bash-pwsh-script.sh for enforcement details.