The problem
Cursor agents often run helper scripts with a single allowlisted Shell call such as:
pwsh -NoProfile -File scripts/Invoke-SomeGate.ps1
If the agent then needs to branch on success vs failure, a common instinct is:
pwsh -NoProfile -File scripts/Invoke-SomeGate.ps1; if ($LASTEXITCODE -ne 0) { … }
On current Cursor builds that compound form is fragile: the command allowlist tokenizer can treat if as a separate command and prompt for approval even when the pwsh prefix is allowlisted. Exit-code tails are also easy for humans watching the run to miss in a wall of JSON.
A second pressure is context budget: verbose terminal dumps (full lint JSON, install progress, test runners) burn tokens before the model can act. VS Code has optional terminal-output compression for agents; when that filter is unavailable in your IDE, prefer agent-side structured probes — one summary line and/or a small JSON envelope — over pasting interactive CLI transcripts into chat.
The pattern: -AgentSummary
Add an opt-in switch ([switch]$AgentSummary) on agent-runnable gates and probes:
[CmdletBinding()]
param(
[switch]$Json,
[switch]$AgentSummary
)
When -AgentSummary is set, emit exactly one success-stream line after the primary work (summary-only, or after envelope JSON when -Json is also set):
VALIDATOR-OK
LINT-OK findings=0
LINT-FAIL exit=1 findings=12
LINT-MISS
MDLINT-MISS
YAMLLINT-MISS
JSONSCHEMA-MISS
MDLINT-FAIL exit=1 findings=3
ASSET-HASH-OK count=0
VALE-MISS
VALE-MISS-STYLES
Conventions that worked well in practice:
| Part | Rule |
|---|---|
| Prefix | SCREAMING-KEBAB from the script’s role |
| Success | <PREFIX>-OK plus optional key=value metrics |
| Failure | <PREFIX>-FAIL exit=<code> plus optional metrics |
| Missing (optional) | <PREFIX>-MISS / <PREFIX>-MISS-<DETAIL> on exit 2 for distinct bootstrap remediations; else *-FAIL exit=2 |
| Stream | Write-Output (not Write-Host) |
| Exit twin | The summary line mirrors exit code, not “happy path only” |
| Timing | After primary JSON/CSV when both are used; or summary-only when that’s the mode |
Agents can then call:
pwsh -NoProfile -File scripts/Invoke-SomeGate.ps1 -AgentSummary
and branch on the single visible line without a $LASTEXITCODE compound.
Exit twin: When to emit success vs failure
-AgentSummary is a visible twin of the process exit code. It does not replace findings inside JSON, and it’s not “only print when the script finished its happy path.”
| Situation | Exit | AgentSummary |
|---|---|---|
Probe ran; payload is the answer (empty tree, exists: false, count=0) |
0 |
*-OK (+ metrics) |
| Script couldn’t do its job (bad roots, I/O, missing dependency) | 1 / 2 |
*-FAIL exit=N |
| Missing tool / pack with distinct agent remediations (install vs sync) | 2 |
*-MISS or *-MISS-<DETAIL> (optional; else *-FAIL exit=2) |
| Gate found policy violations (lint, validator) | 1 |
*-FAIL with finding counts |
Probes vs gates: inventory helpers (hash audit, path metadata, line stats) should stay *-OK when they successfully report a missing folder or missing file. Treating those domain results as *-FAIL trains agents to think the probe broke when it worked. Use *-FAIL for process failure — and wrap throws so a summary line is always emitted before exit (never leave the agent with stderr only and no PREFIX-FAIL / PREFIX-MISS line).
Gates (validators, linters, safety checks) correctly use *-FAIL when findings violate policy; metrics like findings=12 stay on the FAIL line (or in JSON when not using -AgentSummary).
Optional *-MISS*: when exit 2 needs distinct bootstrap remediations (install CLI vs sync styles; module missing vs config missing; npx / Node absent vs findings), emit PREFIX-MISS / PREFIX-MISS-<DETAIL> instead of a single PREFIX-FAIL exit=2. Default remains *-FAIL exit=2 when one remediation covers all missing-dependency cases.
Probe contract (companion switches)
For probes that also return structured data, keep a small reserved switch set:
| Switch | Role |
|---|---|
-Json |
Envelope JSON on stdout (alone or before summary) |
-AgentSummary |
One summary line (alone or trailing after JSON) |
-RepoRoot / -Path |
Target roots |
-WhatIf / -Confirm |
Mutating scripts only |
A useful JSON envelope shape:
{
"ok": true,
"exitCode": 0,
"safetyTier": 1,
"summary": "VALIDATOR-OK",
"data": {}
}
Dual stdout: -Json and -AgentSummary may combine. Emit the envelope first, then the summary line. Parsers should tolerate JSON followed by one non-JSON trailing line. -AgentSummary alone remains summary-only.
Exit taxonomy for this convention: 0 clean, 1 failed, 2 missing dependency / environment. Safety tier documentation in comment-based help (**Safety tier: N**) pairs with a runtime gate before pwsh -File so untiered scripts are treated as unsafe until reviewed.
Nested exit helpers: if a nested function writes the envelope or summary, declare on that helper only the switches it actually uses, and pass them at every call site. Envelope writers typically take both (-Json:$Json -AgentSummary:$AgentSummary). Helpers that only emit the summary line after the caller already wrote JSON should take -AgentSummary alone — do not add an unused -Json just to mirror the script param() block. Explicit parameters keep the contract readable and quiet unused-parameter lint.
Related public patterns (cousins, not clones)
This is a local convention, not a Microsoft PowerShell standard. Closest ideas elsewhere:
- One JSON object on stdout, logs on stderr (agent-friendly CLIs)
- Global
--agentmode for machine-pure output - TAP
ok/not oklines (multi-line test streams) - GitHub Actions
::error/::noticeworkflow commands pytest -qshort summary (.....F...+1 failed, 8 passed) — dot stream ending in one totals linepre-commit run --all-filesper-hookPassed/Failedlines — one line per gate, human-skimmable- Cursor official
cli-for-agentskill — Success output: on success return machine-useful data (IDs, URLs, durations; plain text fine). Same family as one-line gate summaries; language-agnostic checklist, not a PowerShell switch
What’s distinctive here is the opt-in PowerShell switch ([switch]$AgentSummary) that produces a human-skimmable PREFIX-OK / PREFIX-FAIL / optional PREFIX-MISS* line aimed specifically at Cursor’s command allowlist and agent chat UX — useful when you are watching the agent run, not only when another process scrapes JSON.
Lint it so it sticks
Document the rule, then enforce it in your catalog lint:
- Require
[switch]$AgentSummaryon your agent-runnable helper naming pattern (for examplescripts/Invoke-*.ps1), or - An explicit
# AgentSummary: skip — <rationale>marker in.NOTESfor human-only PDF pipelines, mutators, and long analytical reports
That keeps the convention from rotting as the catalog grows. In this catalog, a PSScriptAnalyzer custom rule (AgentSummaryDocumentation) emits Error when both the switch and the skip marker are missing.
Reference
| Repo | Role |
|---|---|
| spine-cursor | Framework docs + Marketplace plugins; probe contract in spine-agent-probes |
| spine-automation | PowerShell module (Write-SpineProbeResult / envelope helpers) + dual-host / product ShellGuard templates that implement the contract |
Maintained by github.com/villepispa.
Related forum threads
No existing Guide covers this PowerShell switch. These threads share motivation (allowlist / Shell discipline / short agent-visible outcomes) without replacing the contract above:
| Thread | Why it relates |
|---|---|
| Agents should detect shell type and prefer editor tools over terminal | Prefer Read/StrReplace over Shell; when Shell is needed, one allowlisted pwsh -NoProfile -File (and avoid bare $x = … compounds) |
Agent stuck after PowerShell truncation pipeline / $LASTEXITCODE = -1 |
Why agents should not pipe native commands into Select-Object -First N for “short” output — prefer a controlled summary line (or log-then-head) instead |
| How Powershell becomes more pleasant for the agent | Different layer (VS Code shell-integration / OSC noise) — useful Windows PS terminal hygiene, not a probe-contract Guide |
Takeaways
- Prefer one allowlisted
pwsh -NoProfile -File … -AgentSummaryover; if ($LASTEXITCODE …)compounds. - Treat the summary line as an exit twin — emit
*-FAILon process failure; keep*-OKfor successful probe reports (including empty / missing targets). - Prefer optional
*-MISS*on exit 2 when agents need distinct bootstrap remediations without parsing JSON; otherwise keep*-FAIL exit=2. - Don’t overload
*-FAILwith domain findings that belong in JSON — that erodes branching trust. - Catch throws so FAIL/MISS is always printed before
exit; never leave agents with stderr only. - Pair with
-Jsonenvelopes when agents need structure; document ordering (JSON then summary line) when both switches are set. - Prefer summary/JSON probes over dumping verbose CLI transcripts into chat when the IDE lacks terminal-output compression for agents.
- Thread into nested exit helpers only the switches those helpers use (
-Jsonand/or-AgentSummary) so the contract stays explicit at every call site. - Enforce with lint + a documented skip marker (
# AgentSummary: skip — <rationale>) so exceptions stay intentional. - Pair
-AgentSummarywith a**Safety tier: N**line in comment-based help and a runtime gate so untiered scripts are held as unsafe until reviewed.