Releases: lavindeep/ShellPilot
Release list
v0.11.1 — dynamic tool guide and memory store caps
A focused patch release: the system prompt now carries a self-consistent tool guide, and persistent memory is capped so it stays selective.
Dynamic tool guide
The system prompt gains a compact Tool guide block rendered directly from the session's registered tool definitions, so it can never drift from the actual toolset:
- Optional tools (
memory_*,web_*,skill_read) are listed only when they are registered for the session. update_planappears only while a plan is active or blocked, preserving the proposal-vs-execution split.- Roughly 82 tokens for the default toolset; the block shows up in
/contextlike any other.
This bumps PROMPT_VERSION to 6.
Memory store caps
memory.json(global and project, each separately) is now capped at 1800 serialized characters. Writes that would exceed the cap are rejected with a clear instruction to forget or compact existing entries — stored memory stays selective instead of relying on prompt truncation.- The cap ratchets: stores that predate the cap and exceed it can always shrink (
/memory forgetkeeps working, including for minified legacy files), while growth stays rejected until the store complies. /memory compactis now atomic across stores — every replacement is validated before any file is written, so a rejected optimization can no longer partially apply./memory add,/memory forget, and/memory compactreport cap rejections with a friendly message instead of failing opaquely.
Scoped memory
- The injected memory block now groups global and project preferences into distinct sections.
memory_propose_updatedocuments the global-vs-project scope policy (what belongs where, what should never be stored) in its tool description.
Quality
- 1625 tests (up from 1610), ruff + mypy --strict green, CI green on Python 3.11 and 3.14.
- New coverage for legacy over-cap stores, ratchet semantics, atomic compact rejection, grouped rendering, and tool-guide composition.
- Validated in a live session before merge.
Full Changelog: v0.11.0...v0.11.1
v0.11.0 — the full-screen app
ShellPilot v0.11.0 — the full-screen app
ShellPilot now opens as a persistent full-screen terminal app on an interactive TTY: a scrolling transcript pane, a framed modal input dock, and a pinned status bar. The classic line-based REPL remains available via --legacy-ui (or SHELLPILOT_UI=legacy) and shares the same renderers.
The app
- Modal input dock — the border says what it is asking: faint while idle, amber
╭─ approve? ─╮for a pending approval, red╭─ type "run" to execute ─╮for high-risk actions. - Type-ahead queue — keep typing while a turn runs; the staged message fires at turn end, and Up-arrow recalls it.
- Worker-thread turns — streaming, scrolling, and Ctrl-C stay live mid-generation.
- Clean cancellation — Ctrl-C aborts a generation mid-stream, kills a running command's process group immediately, or declines the pending approval; conversation history and the on-disk session roll back consistently.
- Thinking trails — reasoning models stream their thinking into a live, collapsible trail (display-only, never fed back).
- Slash menu and completion — a filtered command menu above the dock, Tab path completion for
/cwd set,/attach, and/export, and background-cached model-name completion for/model use. - Diffs and tool calls — approval previews show the entire diff (click or
Ctrl-Oto expand/collapse); tool calls render by subject;!<cmd>output is captured into the transcript. - Status bar — workspace, model, profile, git branch, locality, and context usage, always visible.
Correctness and hardening
- Session transcripts now carry reconciliation records: a mid-batch approval decline and a mid-tool cancel both repair the on-disk transcript, so
--resumenever replays lost or half-finished work. - A plain approval decline ends the turn (and pauses an active plan) instead of letting the model immediately retry; steering via
[e]ditcontinues as before. - Worker-action failures map through the leak-free error path — raw upstream response bodies never reach the terminal.
- User paths in
/cwdand/modelerror messages are markup-escaped; tilde completion degrades gracefully when no home directory can be resolved. - The test suite (1,610 tests) is hermetic against ambient terminal/color environment and machine-specific home directories; CI runs the full gate on Python 3.11 and 3.14.
Docs
- README rewritten from the ground up for v0.11.0.
- DESIGN.md updated throughout §31 (app shell, threading, approvals, cancellation, dock, menu, trails) plus the decline/reconciliation semantics.
Validated live on local and cloud models during development; the line-based REPL remains the supported path for non-TTY and SSH use.
v0.10.1 — post-v0.10.0 hardening and cleanup
v0.10.1 — post-v0.10.0 hardening and cleanup
A patch release on top of v0.10.0. Resolves a wave of external-review logic and security findings, adds robustness fixes, and lands behavior-preserving internal cleanups. No model-facing behavior change — a default localhost session is unchanged.
External-review logic & security fixes
- Classifier — escalate git mutating verbs and option-encoded paths off auto-run.
- Command output — hard-bounded per read (chunked readline; the final chunk is sliced to the remaining budget so total capture never exceeds the cap).
- HTTP egress —
trust_env=Falseon every httpx client (ollama / fetch / search) so an ambient proxy env var can't reroute traffic. - Secret redaction — broadened to key-named, JSON-shaped, and prefixed keys (
OPENAI_API_KEY,DB_PASSWORD,MY_API_KEY). - Planner — finalize on a skipped final step; pin the artifact path to the plan workspace.
- Ollama — reject truncated streams (no
donesentinel); typedOllamaResponseErrors on malformed or wrong-shaped responses, including streaming chunk shapes (non-dict chunk / message /tool_calls); a non-dict element inside a validtool_callslist is skipped, not raised. - Session
--resume— reject any session id whose resolved parent escapes the sessions directory (path-traversal guard). - CLI — guard slash / manual-shell Ctrl+C turns; validate
--resumebefore preload. - Misc — memory rebuild on
/cwd; image-token gate; write-preview placeholder; reserved-name union; uddg redirect-scheme validation;max_resultsclamp; web fetch no longer flags exact-byte-limit bodies as truncated.
Cleanups (behavior-preserving)
- Dead-code removal,
/api/showprobe + skill-decision dedup, loader path/traversable dedup, and import/constant hygiene. No behavior change.
Verification
- Phase gate green:
ruff check,ruff format --check,mypy shellpilot --strict,pytest— 1255 passing. - TDD red-first per fix; each fix cluster independently reviewed.
- Docs updated in step:
__version__→ 0.10.1, README roadmap, DESIGN status line.
v0.10.0 — Security hardening + opt-in cloud models
v0.10.0 is a security-critical release: repo-wide hardening, opt-in cloud models behind an explicit consent boundary, richer workflow skills, and UI polish. Local-first by default — nothing leaves your machine unless you opt into a cloud model and consent per session.
Security hardening
- Command-classifier read-path tightened: path-qualified executables, non-benign
gitglobals, andpytestnow require approval; reader execs honor the workspace boundary and sensitive-read gates. - Terminal output sanitized for control/ANSI sequences at every sink; model-controlled fields (plan goal/steps) sanitized.
- Two-tier egress/safety config invariant: structural keys (
model.options,skills.enabled) are config-file-only; egress/safety keys (tools.web,model.base_url,runtime.security_profile,model.allow_cloud) are high-stakes — settable viaconfig.tomlor a confirm-gated/config set, never via an env var. - Project
AGENTS.mdgated behind trust-on-first-use (re-prompts on content change). - DNS-rebinding SSRF defence in
web_fetch(resolve-and-validate every address, every redirect hop). - Model + web egress redaction and audit at the chokepoints; session and audit-log files created at mode
0600.
Opt-in cloud models
- Off by default behind
[model] allow_cloud. A per-session consent gate states plainly what leaves the device; fail-closed on non-TTY and whenallow_cloudis off — no egress without explicit consent. - An unmistakable active-cloud indicator (amber
☁ CLOUDstatus bar + amber model name +/statuslocality), harness-rendered and unspoofable;cloud_consent_grantedandmodel_requestaudit events.
Approvals & control
- Reject-and-steer: approval prompts are
[y]es / [e]dit / [n]o.[e]drops the proposed action without running it and feeds your instruction back to the model, which re-proposes a corrected action through the full classify→decide→approve gate. High-risk commands still require typing the literalrun. - The path shown at the approval gate is the resolved action path, so a model can't spoof an approval with a misleading argument.
Workflow skills
Four opt-in builtins via progressive disclosure (skill_read): debugging, verification, code-review, git-workflow.
UI / UX
- Redesigned boot banner (sectioned layout, commands + tips + workflow-skills + recent-sessions); streamlined one-key model picker.
- Persistent status bar pinned at the input:
dir · model · profile · locality + ctx%. - Approval diffs reveal with a bounded scrolling animation; changed lines render as full-width red/green bars; long diffs window with a
… (+N more)footer. !<cmd>one-shot manual-shell escape;/config editwrites a commented starterconfig.tomlwhen none exists.
Validation
Phase gate green (ruff + ruff format + mypy --strict + 1157 tests); CI green on Python 3.11 and 3.14.
Next: v0.10.1 — a full-screen TUI input dock (framed input box, queueable input, completion-menu integration).
ShellPilot v0.9.0 — skill progressive disclosure
Skill progressive disclosure
ShellPilot v0.9.0 lets the local model read a skill's deeper documentation on demand rather than force-injecting it into every prompt or leaving it unreachable. The change is additive and opt-in-gated — a default session behaves exactly as it did in v0.8.2.
Highlights
skill_read(skill, resource)tool — opens an in-memory skill document by name, scoped to a skill. It never interprets a filesystem path, and invalid or reserved skills are unreadable. Read-only, no approval gate.- On-demand resources — any skill resource without a trigger (every template, and every reference outside the planning skill) is now discoverable and readable without being injected. No data-model or loader change was needed.
Readable docsmenu — when at least one skill is enabled, active skills advertise their on-demand document names in a single compact line, so the model knows what it can open.- Opt-in gating — both
skill_readand the menu appear only when[skills] enabledis non-empty, mirroring how the web tools register only when web is enabled. A default session gains no new tool surface and no menu. - Showcase — the built-in
skill-authoringskill's references are now real authoring docs (anatomy, trigger choice, resource routing), and itsSKILL.mddemonstrates the pattern: a lean injected body that routes to named on-demand docs. - README — rewritten from the ground up for the milestone, with an architecture diagram, capability tables, an annotated session, and platform support notes.
Validation
- Full check suite green (
ruff,ruff format --check,mypy --strict,pytest) — 908 tests, on Python 3.11 and 3.14. - Live acceptance on
gemma4:e4b: the model autonomously read the relevant on-demand docs when the task called for them, and ignored the menu for unrelated work. Cross-model validation onqwen3.5:4b-mlxis deferred.
Notes
- Planning references remain injected; nothing previously injected moved to on-demand.
docs/DESIGN.md(sections 23.1 and 23.4) documents the mechanism.
Full changelog: v0.8.2...v0.9.0
v0.8.2 — Planner hardening (single end-of-plan summary)
v0.8.2 — Planner hardening (single end-of-plan summary)
A multi-step plan could emit its end-of-plan summary 2–3 times. This release fixes that deterministically, plus related plan-execution hardening.
Fixed
- Single end-of-plan summary. Once the model explicitly completes the last step (via
update_plan) and its reply already contains a substantive summary, the harness ends the turn instead of re-prompting — a finished plan emits one summary, not a repeat. Completion is always explicit (never inferred from prose), so no work is ever skipped. Reproduced on a large cloud model too, so the cause was harness-structural, not small-model flakiness. - Idempotent
propose_plan. A duplicate identical proposal is now a no-op that continues execution, instead of cancelling the just-approved plan and re-prompting for approval.
Changed
- Action-only planning guidance — concrete, checkable steps and no dedicated "summarize" step (the summary is automatic), making execution more predictable across models. The stall-recovery nudge is kept and narrowed.
- Dynamic summary length — scales to the task (brief for simple work, fuller for substantive findings).
Validated live on gemma4:e4b and qwen3.5:4b-mlx: one summary per finished plan, every tool step executed, and the idempotent-propose fix fired under a real double-propose.
v0.8.1 — Web-grounding hardening
ShellPilot v0.8.1 — Web-grounding hardening
Two standing rules added to the built-in web-grounding skill, motivated by live measurement on small local models:
- Fetch-recovery. Fetch only URLs that appeared in search results, and on a blocked or failed fetch (e.g. 403/404) re-search for another authoritative source instead of guessing a URL.
- Current-generation verification. Don't trust the version or product name in the question as current — confirm the current generation from the fetched source.
No backend or provider change (DuckDuckGo remains the zero-config default; SearXNG support is planned for v0.8.5). No runtime, config, or context-window change.
The gemma4:e4b baseline was already robust on the URL-invention / no-recovery axes — this release reinforces that behavior (and hardens weaker models) and nudges against the one residual: going stale when blocked off the official source. Validated live on gemma4:e4b; CI green on Python 3.11 and 3.14 (876 tests).
v0.8.0 — Web-grounding quality
ShellPilot v0.8.0 — Web-grounding quality for small local models
This release helps a small local model (default gemma4:e4b) verify web claims from sources instead of guessing from search snippets — entirely through deterministic harness guidance, with no backend change.
What changed
web-groundingskill — standing grounding guidance. Treat search snippets as leads, not evidence: fetch the official source withweb_fetchbefore asserting a factual, current, or numeric claim. Decompose multi-entity or comparison questions into separate searches. Discover-first query shaping (lead with authority terms like official / documentation / latest release; prefer a specific page over a homepage). Cite sources.- Provider-neutral
web_searchdescription with aweb_fetchbridge. The tool no longer names a specific search engine; it frames results as leads and points the model toweb_fetchon the most authoritative result to ground an answer. - Actionable
web_fetchtruncation marker. When a page is capped, the marker now suggests fetching a more specific source instead of guessing from a partial page. The fetch character limit is unchanged.
Not in this release
No provider/backend change — DuckDuckGo remains the keyless, zero-config default. A configurable privacy-first search provider (self-hosted SearXNG behind a seam) is planned for v0.8.5.
Validation
Verified live on gemma4:e4b: bare prompts now search, fetch the official source, and cite it unprompted, and decompose multi-entity comparisons into per-entity searches. 876 tests; CI green on Python 3.11 and 3.14.
v0.7.1 — Instant high-risk approvals
v0.7.1 — Instant high-risk approvals
High-risk command approvals now appear instantly. The risk-purpose explanation shown before a dangerous command is generated deterministically from the policy classifier's reasons, instead of via a separate blocking model call. That removed a per-command LLM round-trip — and its context-window reconfigure — that could stall the approval prompt for minutes on small local models (the rm was always instant; the wait was the model narrating).
No change to safety behavior — risk classification, the approval decision, and the typed-run gate are untouched. Only how the explanation text is produced changed. Sensitive-file reads still show no purpose line, exactly as before.
- New deterministic
explain_riskin the policy layer, with a sentence for every classifier reason (kept honest by a drift-guard test). - Removed the LLM explainer plumbing (
EXPLAINER_PROMPT, the_explain_purposeround-trip, and the injection seam) — the last blocking per-command model call. - 874 tests; CI green on Python 3.11 and 3.14.
v0.7.0 — Skills v2
Skills v2 — trigger-driven skill assembly tuned for small local models. Instead of exposing skills as model-facing tools, ShellPilot's harness deterministically injects only the guidance relevant to the current runtime state, keeping a 4B model focused.
Highlights
- Crisp deterministic triggers —
ALWAYS_ON,ENABLED,PLAN_PROPOSED,PLAN_ACTIVE,PLAN_BLOCKED,WEB_ENABLED. No intent inference; every trigger has an exact predicate. - Four builtin skills:
planning— proposal/active/blocked mode references; the harness shows only the rule for the current plan phase.context-management— always-on, tiny operating rules for file triage and context budgeting.web-grounding— active only when web tools are actually registered.skill-authoring— opt-in via[skills] enabled.
- Read-only resources — skills may bundle
references/andtemplates/; the relevant reference is selected by the harness. - Script discovery (not execution) —
scripts/manifest.jsonis discovered and validated for visibility, but execution is deferred to v0.8.0 with its own safety design. No skill code runs in this release. - Enriched inspection —
/skillsshows triggers, resources, status, active state, and reasons;/contextshows per-block token estimates, injection state, and skip reasons. - Slimmer base prompt (
PROMPT_VERSION4) — proposal-time discipline stays in the base prompt; execution and blocker discipline live in theplanningskill.
Notes
[skills] enabledis config-file only (no env var, no/config set, no overrides).- Skill resource discovery is path-safety hardened (rejects traversal/absolute/symlink escapes) and bounded (per-file and per-folder caps) so a stray skill folder can't read outside its root or stall startup.
- Reserved builtin names cannot be shadowed by user skills.
Deferred (on record)
- Skill script execution → v0.8.0 (controlled runner + approval/precheck integration).
- Intent-inference triggers (debugging/verification/brainstorming) and richer workflow skills → v0.9.0 candidates.
Validated live on gemma4:e4b. Full test suite (832) and CI green on Python 3.11 and 3.14.