ShellPilot
0.4.0-preview0013
GitHub Copilot in your PowerShell terminal: device-flow auth, model listing, chat and agentic tool-calling with usage and cost.
Minimum PowerShell version
7.4
See the version list below for details.
Installation Options
Owners
Copyright
(c) raandree. All rights reserved.
Package Details
Author(s)
- raandree
Tags
GitHubCopilot Copilot AI LLM Chat Agent
Functions
Clear-ShpChat Clear-ShpContext Clear-ShpRedactionPolicy Clear-ShpToolPolicy Clear-ShpUsage Compress-ShpChat ConvertTo-ShpAnnotation ConvertTo-ShpTokenCount Get-ShpChat Get-ShpContext Get-ShpCosineSimilarity Get-ShpCostEstimate Get-ShpDefault Get-ShpMcpServer Get-ShpModel Get-ShpModelName Get-ShpRedactionPolicy Get-ShpTool Get-ShpToolPolicy Get-ShpUsage Initialize-Shp Invoke-Shp Invoke-ShpBatch Register-ShpMcpServer Register-ShpTool Request-ShpEmbedding Resolve-ShpError Select-ShpModel Set-ShpContext Set-ShpRedactionPolicy Set-ShpToolPolicy Start-ShpChat Test-ShpCiReadiness Unregister-ShpMcpServer Unregister-ShpTool
PSEditions
Dependencies
This module has no dependencies.
Release Notes
## [0.4.0-preview0013] - 2026-09-07
### Security
- **Protect Unix `edit_file` staging from creation.** Apply the source file
mode when creating the empty temporary file, before any content is copied,
so a private source is not temporarily exposed through default permissions.
- **Keep `edit_file` on the target approved by the tool policy.** Repointing
the original directory alias after authorization no longer redirects the
edit to a different file. Confirmation names the authorized target. Refuse
special files again after staging so a named-pipe swap cannot block the
final content check. External filesystem races remain outside the tool's
guarantees.
- **Tool policy refuses paths when link resolution fails.** A missing runtime
API or filesystem error no longer leaves an unresolved path eligible for
Read or Write access. This prevents a junction inside an allowed directory
from bypassing rules for its destination on an unsupported runtime.
- **A disabled tool can no longer be executed.** `-DisableTerminal`,
`-DisableFileAccess`, `-DisableBrowsing`, `-DisableUserPrompts` and
`-DisableTodoList` removed a tool from the set offered to the model, but the
dispatch switch matched built-in tool names unconditionally — so a model that
named a disabled tool anyway, from its own priors or from a replayed history,
had it run. `-DisableTerminal` bounded what was advertised and nothing about
what executed.
Dispatch now refuses any built-in that this call did not offer, before the
tool runs. The refusal reuses the existing tool-policy path: the `tool.call`
event carries `policy = denied`, the reason names the disabled tool, the call
appears on `ToolCallsDenied`, and the model receives `{"denied": "..."}` so it
can choose another route instead of failing the turn. The offered set is
derived from the assembled tool list rather than re-tested against each
switch, so a tool added later cannot be offered under one condition and
dispatched under another.
- **`Register-ShpTool` refuses a built-in tool name.** Dispatch matches built-in
names before it consults the user tool table, so registering `run_command`,
`read_file` or any other built-in produced a tool that was advertised to the
model and then silently ignored while the built-in ran instead — with the
caller believing it had replaced it. An attached MCP server has always been
refused a colliding name; a local registration now fails the same way, loudly
and at registration time. Choose a distinct `-ToolName`.
### Added
- **Add explicit estimated budgets for trusted owned requests.** Opt into
`RequestBudgetMode provider-estimate` for non-refundable reservations and
upward reconciliation; default verified counters keep their meaning.
Add the bounded Claude child provider/counting path, pre-generation host
admission, and secret-free reported/partial Usage. No automatic retries,
Model substitution, or invoice guarantee is implied. See
[the transport contract](specs/030-host-request-transport.md).
- **Add conditional admission limits to owned `Invoke-Shp` transport.**
`RequestLimits` and a trusted `RequestTokenCounter` reserve input, maximum
output, and Engine-priced cost before dispatch. Unknown or failed Usage
retains its reservation and stays explicitly unknown in results, events,
and summaries. No verified Copilot counter or complete child runtime is
supplied; ordinary calls are unchanged. See
[the contract and limitations](specs/030-host-request-transport.md).
- **Add optional host transport groundwork to `Invoke-Shp`.** Use
`NoAutomaticRetry` to disable transport and API-shape resends, or
`RequestTransport` for a credentialless Tool-calling loop with a trusted
caller-owned transport. Ordinary calls are unchanged. Hard request admission,
process isolation, and a trusted transport process are not supplied by these
options. See [the contract and limitations](specs/030-host-request-transport.md).
- **Add `edit_file` for targeted changes to existing files.** Replace one
exact, case-sensitive `oldString` with `newString`, refusing zero matches or
multiple matches with recovery guidance. Preserve the BOM, encoding and
unchanged line endings for UTF-8 and BOM-marked UTF-16/UTF-32; refuse
malformed or unsupported text instead of converting it. The tool is disabled
by `-DisableFileAccess`, and reports the intended edit without writing under
`-WhatIf`.
When a tool policy is set, an edit needs both a `Read()` and a `Write()` rule
covering the target, and a deny in either kind refuses it. Match counts
disclose file content even when the replacement is identical, so `Write()`
alone would turn the tool into a way to confirm guesses about a file the
policy never granted read access to. `write_file` and `create_directory` are
unchanged and still need only `Write()`.
Only regular, seekable files are eligible, and input and output are each
capped at 8 MiB including the BOM. Unix file types are checked directly,
avoiding a hang when formatted permissions misidentify a named pipe as a
regular file. The edit is staged in the target's own
directory, flushed, checked against the file's current bytes, and then put in
place with a backup of the original. A native replacement failure that moves
the original away retains the backup and reports `recoveryPath` for manual
recovery instead of deleting the remaining copy. Cleanup is best effort.
Detected concurrent changes are refused; the final check and replacement
are not a compare-and-swap guarantee.
See [README.md](README.md#agent-tools-on-by-default).
- **`glob_files` and `grep_files` let the model search without a shell.**
`glob_files` finds files by name pattern under a directory; `grep_files`
searches their contents and returns only the path, line number and matching
line, leaving `read_file` to read around a hit. Both are offered with the
other file tools and withdrawn by `-DisableFileAccess`.
Both are governed by the existing `Read()` rules of `Set-ShpToolPolicy`, and
that is the point: until now the only way to make the model *find* something
was `run_command`, so a policy tight enough to be worth setting had to grant
`Shell(...)` — far more reach than searching needs. `Set-ShpToolPolicy -Rule
'Read(./**)'` is now enough to let the model locate a file by name or by
content while `run_command` stays denied.
Every returned hit is policy-checked, not just the search root, because a
glob rooted at an allowed directory can still match a path that resolves,
through a link, to somewhere no rule covers. An excluded hit is counted in
`excludedByPolicy` rather than dropped silently. Both results are bounded —
files examined, matches returned, and characters returned — and set
`truncated` when any cap bites, so the model narrows the pattern instead of
overflowing the context window.
- **`ConvertTo-ShpAnnotation` surfaces structured findings in CI.** Pipe a
`ShellPilot.Result` from `Invoke-Shp -JsonSchema`, or any plain finding
object, into the cmdlet to produce GitHub Actions annotations, Azure DevOps
`task.logissue` commands, or readable text. `Level`, `Path`, `Line`,
`Column`, `Title`, and `Message` are matched case-insensitively and can be
redirected with `-PropertyMap`; an unknown or missing level is always a
warning. Vendor-specific escaping keeps newlines and delimiters from
corrupting a workflow command. Output stays on the success stream unless
`-Emit` writes it to the host, and `-Summary` appends a Markdown table to
`$env:GITHUB_STEP_SUMMARY` when available.
See [specs/028-ci-annotations.md](specs/028-ci-annotations.md).
- **`Invoke-Shp -EventStream <path>` writes a headless JSONL event stream.** A
CI log collector reads lines, not prose: everything the module said about a
running turn was aimed at a person, so a nineteen-iteration turn that was
refused twice by the tool policy, retried once on an expired session token
and then stopped on `-MaxBudgetUSD` left one object saying
`BudgetExceeded = $true` and nothing about the shape of the failure. The
stream appends one JSON object per line - `turn.start`, `model.request`,
`usage`, `reasoning` (one per streamed chunk under `-ShowThinking`),
`tool.call`, `tool.result`, `todo`, `retry`, `error`, `final` - each carrying
`schemaVersion`, a monotonic `sequence`, an ISO 8601 UTC `timestamp`, a
`type` and a flat `data` object. Pass `-` to write the records to the
Information stream instead of a file. Every line is appended whole, so a run
killed mid-turn still leaves a file that parses up to its last complete line;
a later call appending to that valid stream continues the sequence. Every
string payload goes through the same redaction seam the request body does, so
a secret a tool printed does not reach the stream verbatim; a `run_command`
tool-call record names the tool and the policy decision but never the command
line. The complete streamed reasoning trace is redacted before it is divided
back into Event records, so an SSE boundary cannot split a secret around the
redaction seam; partial reasoning is retained before a `retry` or `error`.
Transient HTTP and network-outage retries from the shared request wrapper are
recorded with attempt, delay and status data, and an invented `ask_user` call
in a non-interactive turn records its denied Tool call and terminal error
before the call stops. `-DisableProgressEvents` no longer switches this off -
the two sinks are gated independently.
See [specs/027-headless-event-stream.md](specs/027-headless-event-stream.md).
- **`Invoke-Shp -AsJob` and `Invoke-ShpBatch -AsJob` run a call in the
background.** Both return a thread job whose `Receive-Job` resolves to the
same `ShellPilot.Result` / `ShellPilot.BatchResult` objects the synchronous
call returns - the same process, so nothing is serialised into a
`Des
FileList
- ShellPilot.nuspec
- ShellPilot.Format.ps1xml
- ShellPilot.psm1
- data\PriceTable.psd1
- en-US\ShellPilot-help.xml
- ShellPilot.psd1
- en-US\about_ShellPilot.help.txt
Version History
| Version | Downloads | Last updated |
|---|---|---|
| 0.4.0-previe... | 7 | 9/7/2026 |
| 0.4.0-previe... (current version) | 3 | 9/7/2026 |
| 0.4.0-previe... | 3 | 9/6/2026 |
| 0.4.0-previe... | 4 | 9/6/2026 |
| 0.4.0-previe... | 7 | 8/26/2026 |
| 0.4.0-previe... | 4 | 8/24/2026 |
| 0.4.0-previe... | 9 | 8/19/2026 |
| 0.4.0-previe... | 5 | 8/12/2026 |
| 0.4.0-previe... | 7 | 8/12/2026 |
| 0.4.0-previe... | 6 | 8/11/2026 |
| 0.4.0-previe... | 3 | 8/11/2026 |
| 0.4.0-previe... | 10 | 8/6/2026 |
| 0.4.0-previe... | 11 | 7/28/2026 |
| 0.4.0-previe... | 3 | 7/28/2026 |
| 0.3.1 | 87 | 7/23/2026 |
| 0.3.1-previe... | 3 | 7/23/2026 |
| 0.3.0-previe... | 8 | 7/12/2026 |
| 0.3.0-previe... | 7 | 7/9/2026 |
| 0.3.0-previe... | 4 | 7/9/2026 |
| 0.3.0-previe... | 7 | 7/9/2026 |
| 0.2.1-previe... | 8 | 7/8/2026 |
| 0.2.0 | 37 | 7/8/2026 |
| 0.2.0-previe... | 6 | 7/8/2026 |
| 0.2.0-previe... | 4 | 7/8/2026 |
| 0.2.0-previe... | 31 | 6/12/2026 |