One-line script outcomes for Cursor agents — `-AgentSummary` and the PowerShell probe contract

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 --agent mode for machine-pure output
  • TAP ok / not ok lines (multi-line test streams)
  • GitHub Actions ::error / ::notice workflow commands
  • pytest -q short summary (.....F... + 1 failed, 8 passed) — dot stream ending in one totals line
  • pre-commit run --all-files per-hook Passed / Failed lines — one line per gate, human-skimmable
  • Cursor official cli-for-agent skill — 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]$AgentSummary on your agent-runnable helper naming pattern (for example scripts/Invoke-*.ps1), or
  • An explicit # AgentSummary: skip — <rationale> marker in .NOTES for 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

  1. Prefer one allowlisted pwsh -NoProfile -File … -AgentSummary over ; if ($LASTEXITCODE …) compounds.
  2. Treat the summary line as an exit twin — emit *-FAIL on process failure; keep *-OK for successful probe reports (including empty / missing targets).
  3. Prefer optional *-MISS* on exit 2 when agents need distinct bootstrap remediations without parsing JSON; otherwise keep *-FAIL exit=2.
  4. Don’t overload *-FAIL with domain findings that belong in JSON — that erodes branching trust.
  5. Catch throws so FAIL/MISS is always printed before exit; never leave agents with stderr only.
  6. Pair with -Json envelopes when agents need structure; document ordering (JSON then summary line) when both switches are set.
  7. Prefer summary/JSON probes over dumping verbose CLI transcripts into chat when the IDE lacks terminal-output compression for agents.
  8. Thread into nested exit helpers only the switches those helpers use (-Json and/or -AgentSummary) so the contract stays explicit at every call site.
  9. Enforce with lint + a documented skip marker (# AgentSummary: skip — <rationale>) so exceptions stay intentional.
  10. Pair -AgentSummary with a **Safety tier: N** line in comment-based help and a runtime gate so untiered scripts are held as unsafe until reviewed.

Installable bits that implement this convention (plugin + PowerShell module/templates) are in the Showcase: Built for Cursor — spine-agent-probes and Spine.Automation.