Backlog
Work agreed but not started, in rough priority order, with what has shipped marked done and dated. Each item becomes an ADR when it is picked up.
Planned for the next releases
The releases planned next, and what each carries, are in roadmap.md. This page keeps the agreed work that is not yet scheduled, and what has shipped, marked done and dated.
Context
- Done 2026-10-01: layered context (ADR 0045, the
proposal phases 1 to 6). Each request is composed from a store
that refers to the audit log: tool output as a reference after its turn, retyped output cut, facts
(2026-09-30), the running summary (2026-09-30), the
memorytool (2026-09-30), and condensing to a token target with headroom and its guard (2026-10-01). The per-request assessment is built and off. Open:memoryon a second scenario (context-management.md, “Not done yet”), and a specialised distiller (roadmap.md, “Not scheduled”). - Done 2026-10-09: context checkpoint 2 (ADR 0057). The
target and headroom tuned on a conversation that condenses at the default budget, the 50% variants re-measured
under the guard, D10’s model switch evaluated, and
memorymeasured on and off.memoryis off by default (context.memoryturns it on),context.targetis 0.6, and the assessment, still off, changes an inferred task only when a request restates one (assessment.taskChanges: restated). - Done 2026-10-03: permanent facts over MCP (ADR 0048). A
wisp mcpcaller asks withset_fact_scopepermanent, and the person keeps or drops the fact withwisp facts keep|dropor inwisp-tui. Settled 2026-10-12: a request has no time limit and outlives its thread and its server (ADR 0048, amended); the terminal-only answers were reviewed and kept (ADR 0046, “Review, 2026-10-12”). - Done 2026-10-12: the tool-output budget (ADR 0050). Every
tool result is bounded by an eighth of the model’s window (4 to 64 KiB); what does not fit is kept whole in the
conversation’s output store (
~/.wisp/output/<session>/, swept by age,context.outputDays) and reached throughmemoryby page, filter, exact summary, or a condensing question;inspectlists a turn’s calls and a repeated call is noted. Done 2026-10-12 too: chat’s/showand/lastandwisp-tui’s expanded view (Ctrl-O) show the stored whole, through a pager on a terminal and a page at a time inwisp-tui(ADR 0050, “The person’s views”).
Policy
- Done 2026-09-19: each simple command in a line is checked and approved separately, remembered by program (ADR 0015).
- Done 2026-10-04: the sandbox’s refusals checked against the writable roots, and a nested wisp agent denied to
the model and to typed
!commands (ADR 0054). - Done 2026-10-12: loops and conditionals judged and remembered by the commands inside them, inline programs
(
python3 -c) at least moderate,find -execjudged, piping into an interpreter dangerous, and a line whose risk only the whole line shows asked once (ADR 0015, amended 2026-10-11); the rules and deny patterns read a search pattern, an awk program, or printed text as data, not as a pipe, a deletion, or a write. - Done 2026-10-12: project approvals whose folder is gone marked in
wisp approvals,/approvals, andwisp://approvals, and removed bywisp approvals clear --gone. - Done 2026-10-14: command time limits:
run_command’stimeoutSecondsandrespond’scommandTimeoutSeconds, clamped to the operator’scommandMaxTimeoutSeconds, with the default raised to 120 s (ADR 0063). - Done 2026-10-14: an approved run outside the sandbox, for the chores it refuses (
brew upgrade,cargo install,rustup update):run_command’soutsideSandbox, asked of the person every time for that exact line and remembered by nothing, behindcommandPolicy.sandbox.allowOutsideSandbox; and the person’s own run outside it, typed after!!(ADR 0064). Done the same day: Homebrew’snot writablelines read as the sandbox’s refusal (ADR 0054, amended 2026-10-14).
Enabling other harnesses (see the objective)
wisp’s offer to another harness is work done locally that the harness would otherwise do with its own tokens on a remote model: reading, condensing, classifying, extracting, and answering over local data, so the caller’s model never ingests the raw material. Other harnesses already run commands locally; that is not the differentiator. Items, in order of leverage:
- Done 2026-09-20: receipts. Every
respondresult carriesstructuredContent.receipt, the turn’s tool calls, commands with exit status, denials, approvals, and errors, folded from the audit events (ADR 0021). Token usage added 2026-10-09: the turn’s input, output, cached, and reasoning tokens, where the runtime reports them (mcp.md). - Done 2026-09-20: structured output.
respondand the CLI (--schema) take a JSON Schema and return JSON of that shape through guided generation (ADR 0022). - Condensing tools. Purpose-built MCP tools that keep raw content on the device and return small
results (ADR 0023). Done 2026-09-20:
triage, build or test output into a failure list. Done 2026-09-21:summarise_diff, a diff into per-file lines and review flags. Done 2026-09-23:scan_secretsandredact(ADR 0031);condense_logandjson_shape, deterministic (ADR 0032). Done 2026-09-26:dependency_audit,flaky_tests, andhot_paths, deterministic, and an exact pre-pass intriagefor known failure formats, which read all four eval fixtures without the model (ADR 0039). Next: summarise a file, answer a question over a set of files, extract fields to a schema. - Done 2026-09-20: a measured task catalogue.
scripts/check evalrecords aMeasurementper task into an embedded resource; the tool catalogue andwisp://measurementspublish them (ADR 0026, measurements.md). - Done 2026-10-12: the verification pass (ADR 0060,
verification.md). Exact readers check the results a reply reports against the turn’s complete
call list from the audit log, on by default; an unsupported claim is shown as
unsupported:and returned asverificationbyrespond. The model step (verification.mode: model) is built and off by default: on the on-device model it flagged 6 of 14 honest replies; open until a more capable model is measured (roadmap.md, “Not scheduled”). - Done 2026-10-12: the eval sets of
edit_file,system_info, anddraft_changeenlarged (110, 54, and 44 cases), with floors set from the suites’ pooled history; the release runs a fixed subset,WISP_EVAL_FULL=1all of them (measurements.md). - Done 2026-10-12: processes named at spawn (ADR 0061):
scripts/wisp-mcpstartswisp mcp (CLIENT)fromWISP_MCP_CLIENT,wisp-tuiits child aswisp chat (tui). - Reverse delegation through MCP sampling. When the on-device model is stuck on a sub-step, ask the calling harness’s model through the protocol, with data leaving the device only for that step and only with approval.
- Roots. Use the client’s declared roots as the sandbox’s writable root. Progress, done
2026-09-29: a caller that sends a
progressTokengets each line chat would show as a progress notification (mcp.md, “Progress”). Open there: per-chunk progress in the condensing tools’ model pass.
Use cases chosen for later
Picked on 2026-09-23 alongside secret scanning, the condensers, watch mode, and system_info, and left
for after them:
- Bulk classification. Label hundreds of commits, issues, or log lines into categories with structured output (ADR 0022): too cheap a job for a remote model, and measurable with the eval harness.
- Done 2026-09-24: git chores.
draft_changeandwisp draft: commit messages, PR descriptions, and changelog lines from a diff (ADR 0035). - Offline work. wisp as the agent when there is no network: on a plane, or on a network that cannot reach a remote model. Mostly a matter of documenting and testing what already works without one.
Tools
- Done 2026-09-24: custom tools, command templates declared in
~/.wisp/config.json, andtools.disabledfor built-ins (ADR 0036). Later, by decision: tools from other MCP servers. - Done 2026-10-09:
edit_file’s line edits forgive a line sent without its indentation and a stale line number besidefind, without guessing, and an emptyfindbesidelinechecks nothing (ADR 0024, refined 2026-10-06). - Done 2026-10-12:
edit_fileon CRLF, CR-only, and mixed-ending files: lines split on bytes asread_filenumbers them, each line keeping its ending, and a guard refusing an edit that would change lines it does not name (ADR 0024, refined 2026-10-12). Before, an edit of line 1 of a CRLF file replaced the whole file. - Done 2026-10-12: the secret scanner’s unquoted
assigned-secretrule no longer reads prose as a credential assigned to a name (“per token: every …th layer”, “per drafted token: 748.125 MiB” in the756b178eval fixture): after a word and a colon, the value must hold letters and digits and not be a measure (ADR 0031, amended 2026-10-12).
Terminal front end
Accepted 2026-09-22 (ADR 0029). Input history shipped 2026-09-23
(Up and Down recall, /history in chat). Line editing shipped 2026-09-24: a cursor, word and line
motions, readline’s deletions, bracketed paste, and Alt-Enter for a newline. The input grows to six rows
for a multi-line message, done 2026-09-25. The turn event and the rendered text on
events, done 2026-09-25 (ADR 0029, amendment), a bordered approval dialog with the reasons inside it,
and Markdown rendering of replies as they are committed, the same day. Done 2026-09-26: /config from
chat with a picker for choices and Tab completion (ADR 0040).
Done 2026-09-26 too: /config as YAML and /config get; /status, /approvals (with revoke), and
/audit in place of /inspect, kept as an alias, with Tab completing them and approval ids; and sent
lines styled in the scrollback like the input box. Done 2026-09-29, in both front ends: the gate’s
decision for each command, each turn’s time and tokens, a live line for what the turn is doing, and
/audit sessions and /audit <id>. Done 2026-09-30: each tool’s output folded in the scrollback with
Ctrl-O for the last one whole, the model’s context in a panel (Ctrl-T), facts in that panel, and the
hello line with notifications posted through the terminal (ADR 0044).
Done 2026-10-04: ! <command> in chat, with wisp-tui’s command mode
(ADR 0049); the input box inactive and holding keys while a turn
runs; and the running summary in a place of its own (/inspect summary, wisp://threads/{id}/summary).
Tables and links in replies are shown as typed.
Done 2026-10-12: Ctrl-C during a model’s turn stops the turn and the command it started, in both front ends, and a
second Ctrl-C quits (ADR 0049 and
ADR 0029, amended 2026-10-11).
Done 2026-10-14: wisp-tui’s outside mode, a muted red input box for a line run outside the sandbox, entered with a
second ! at the start in command mode and left one mode at a time with Backspace
(ADR 0064, amended 2026-10-14); its colours are a first
proposal, open to the operator’s choice from renders.
Documentation
- Done 2026-10-14: the documentation site, https://wisp.pidster.com, an mdBook over
docs/with guides first, the reference, then the internals and every decision record, checked in the gate byscripts/check docs-linksand built byscripts/check docs-site(ADR 0065).
When wisp can be signed
Three things wait on a Developer ID or App Store signature rather than on code.
- A notification helper app.
Wisp Notifier.app, a tiny agent bundle (LSUIElement) in the formula’slibexec, posting throughUserNotificationsinstead ofosascript(ADR 0030). Gains: banners as “Wisp” with its own icon and its own row in Notification settings, and action buttons (“Show” opening the audit). Done 2026-09-30 without signing (ADR 0044): banners come from the terminal (its notification sequence in Ghostty, iTerm2, WezTerm, and kitty, ordisplay notificationsent to the terminal app), so they carry its name and icon and a click returns to it; Script Editor remains only as the last route.wisp notifyand thenotifytool launch the helper when it is installed and authorised, and fall back toosascriptotherwise. The open fact to settle first: whether macOS grants notification authorisation to the bundle as shipped; signing removes that doubt. - A DMG, with the package declaring its layout. An app bundle in a disk image, signed and notarised,
beside the Homebrew formula. Its layout differs from the formula’s:
wispinContents/MacOSorContents/Helpers,mlx.metalliband other resources inContents/Resources. Today wisp finds its parts by searching from its own real path:wisp-tuibeside it or in abinbeside its folder (0.18.1, after 0.17.0’s move ofwispintolibexecsentwisp chatto the plain chat without a word), and the MLX library beside it (ADR 0047). Each new layout would need a code change and a release. Instead, each package declares where its parts are, relative towisp, at build time: the app’sInfo.plist, or a small manifest in the formula’slibexec. The search stays as the fallback for a build directory, and aWISP_TUIvariable, likeWISP_BIN, overrides for an odd set-up.wisp doctorchecks every part the package declares, which would have caught 0.17.0’s regression before release. Not aconfig.jsonsetting: the layout is a fact of the package, not a choice for the person (the operator, 2026-10-04). - Private Cloud Compute. The
com.apple.developer.private-cloud-computeentitlement is granted to signed App Store apps only (backends.md, “Private Cloud Compute”).
Models
-
Done 2026-09-24: routing by input size. A task with measured size bands picks the first model on the configured
routing.laddertrusted with an input that large; piloted ondraft_change(ADR 0037). Next: size bands fortriageand the redaction pass, and more cases per band. -
Done 2026-09-28: a default model per task.
routing.tasksnames the model for a task’s model pass;secretsdefaults tosystem, measured best for it (ADR 0037, amendment). -
Done 2026-09-19:
ollama:<name>models through a wisp-supplied executor (ADR 0016). -
Done 2026-09-20: a backend registry with declared capabilities, and MLX Swift and Core AI as backends (ADR 0019); a Core ML approval-risk classifier behind a versioned contract (ADR 0020).
-
Done 2026-09-20: context estimation from the runtime.
Agentcondenses ahead of a known window from the usage every reply reports; Ollama is asked for an explicitcontextLength(ADR 0025). -
Done 2026-10-04: MLX on a par with Ollama. MLX models run through wisp’s own executor, with the window sized from the model and memory, exact token counts, usage, and each thread’s processed prefix reused; Core AI reports its bundle’s window;
wisp models pullfetchesmlx-communitymodels into the Hugging Face cache, reusing what Hugging Face’s tools already fetched, after asking (ADR 0052). Measured against Ollama forQwen3-1.7B-4bitin 0.20.0; the rest of ADR 0052’s list is not yet scheduled (roadmap.md, “Not scheduled”). -
Done 2026-10-04: a reasoning model’s thinking shown, counted, audited, and never sent back to the model, and
ollama.think(ADR 0053). -
Done 2026-10-04: models enabled and disabled,
wisp modelsas a table, an MLX model’s capabilities checked on the model when it is enabled, and chat falling back tosystemwhen its model is unavailable (ADR 0056). -
Done 2026-10-09: windows sized for models Ollama reports per layer (gemma4) and for hybrid attention and recurrent models (
qwen3.8, Falcon-H1), refining ADR 0043; MLX measured against Ollama on the same weights and the gap closed by leaving thinking to the chat template, with MLX’s thinking shown andmlx.think(ADR 0052, ADR 0053, refined); MLX tool calls as a JSON array and ChatML’s end of turn read; Mistral’s text tool calls read from Ollama replies; and the local-model and Falcon comparisons, which keptgranite4.1:8bas the delegation default (measurements.md). -
Done 2026-10-09: llama.cpp and LM Studio as backends through a shared executor for OpenAI-compatible servers (ADR 0058; see “Model backends, deferred”); a context window for one model (
ollama.models.<name>.contextLength,mlx.models.<name>.contextLength);wisp models pullresuming a file cut off part-way and seeding the Hugging Face cache from a real directory, and Core AI’s listing following links (ADR 0052, refined 2026-10-09); andqwen3.8:27bre-measured, with no slowdown in tool work (measurements.md). -
Done 2026-10-12: one set of model actions for the person and the model (ADR 0059):
ModelActionsbehindwisp models,/models, and/model;/models pull,trust, andcancelin chat andwisp-tui, with the picker’s pull row; and amodelstool for the model, off by default (tools.models), whose every change asks the person. -
Done 2026-10-12: thinking chosen per model (
<runtime>.models.<name>.think) and per call: wisp’s own side calls sendthink: false, and MCPrespondtakesthinkwhen a thread starts (ADR 0053, amended 2026-10-11). -
Done 2026-09-20: agent tests without the model.
ScriptedModeldrivesAgent, the tool loop,WispServerover a real client and in its unit tests (the fake thread is gone), and the wholewisp chatloop, which moved intoWispCoreasChatLoopwith injected input and output.
Classifiers
Accepted 2026-09-25 (ADR 0038): classifiers are
tasks served by fast, specialised models, measured for speed as well as accuracy. Done the same day:
wisp classifier train (Create ML, on device, from the bundled examples), wisp classifier measure,
contract 2, and latency in every classifier measurement. Next, in order:
- Done 2026-09-26:
wisp classifier train --from-audit, the eval set widened to 123 commands, and three rule gaps closed (ADR 0038, amendment). - Done 2026-09-26: classifier versions. Each release ships a fixed default,
risk@X.Y.Z-default, used byapproval.classifier: coremlwhen no model is named;wisp classifier trainaddsrisk@X.Y.Z-local.<n>and never overwrites one;list,use, andremovemanage them. Training is deterministic and never usesheld-out.tsvor an--excludeset (ADR 0038, amendments). - Done 2026-09-26: train, dev, and test sets for risk, secrets, failures, and log severity under
training/, kept apart by family, with frozen test sets of real data; the shipped risk default is trained fromtraining/risk/train.tsv, drafted and real commands. The rules know a short list of read-only commands, which skip the model, and rate printing a credential dangerous (ADR 0038, amendments). A trained classifier good enough to be the default.Done 2026-09-26 (ADR 0041). On the 996 real test commands, the shipped default, trained from drafted and real commands, rates 817 exactly beside the rules (system-model: 664) at under a millisecond a command, and becameapproval.classifier’s default. It rates four of the 25 dangerous commands safe (system-model: one), three of them undecidable from the text.- Done 2026-09-26: dangerous commands measured closely. Instead of a new dangerous-only test slice, five-fold cross-validation over train and dev scores all 403 labelled dangerous commands with the gate’s combination; after closing the rule gaps it found, 6 are rated safe (1.5%, at most 2.9% at 95% confidence), all credential reads a regex cannot tell from safe look-alikes (ADR 0038, amendment). Growing the frozen test set from real use: done 2026-10-12, 13 rows from the audit log confirmed by the operator, 25 dangerous commands to 29 (ADR 0038, amendment). Open: more, as use adds them; 29 still bounds a dangerous command rated safe only loosely.
- Other providers. Embedding nearest-neighbour over labelled examples (
NLEmbeddingor an Ollama embedding model), and an external process speaking JSON Lines, like the binaries intools/. - Other tasks. Secret and personal-data detection for
redact, log-line categories forcondense_log, failure kinds fortriage, and the bulk classification chosen for later. Their training sets exist (above); on test a trained failures classifier beatsKnownFailures, andLogDigest’s keywords beat a trained log-severity classifier. None is wired in yet. For secrets, done 2026-09-27: the rules were measured and widened instead (ADR 0031, amendment). Open there: the gap between train (85% of secrets found) and third-party test data (32%). Personal data, done 2026-09-28: a personal-only classifier beside the rules inscan_secretsfinds 62% of personal test lines, against 12% for the rules alone (ADR 0042). Open: using it inredact, where it would have to point the model at the flagged lines, since it cannot name a value.
Model backends, deferred
Candidates recorded on 2026-09-20 with the MLX and Core AI work, not implemented: ONNX Runtime; PyTorch and
Hugging Face Transformers; vLLM. llama.cpp and LM Studio were built on 2026-10-09 through a shared HTTP executor
with a dialect per runtime (ADR 0058); vLLM serves the same API, so it
is most of the way there. Still to do for those two: a check against a real llama-server and LM Studio, neither
of which was on this Mac when they were built. Embeddings, reranking, and other
non-conversational models are not LanguageModels and need task-specific interfaces (an embed tool, a
rerank tool) rather than a backend; that is a separate design. The MLX packaging chores are done
(2026-10-03, ADR 0047): the release carries mlx.metallib beside
the binary, in the formula’s libexec, and scripts/check mlx-live places it beside the test bundle so
the live test runs.
Upstream
- Report to
modelcontextprotocol/swift-sdk:Client.Capabilities.experimentalis[String: String]?(Sources/MCP/Client/Client.swift:128, still so on main ata0ae212) while the specification allows object values; Codex sends{"codex/auth-change": {}}and the server failsinitializewith-32603. wisp works around it inCompatibilityTransport; drop the workaround when the SDK changes the type.
Open design
- Escalations. Approval and inquiry as distinct verbs, delivered over more channels than MCP
elicitation (the harness’s own question dialog, a terminal, a file, a webhook), so an operator who is
another agent, or absent, still gets a bounded, audited answer. Proposal written 2026-09-20 at
proposals/2026-09-20-escalations.md. Its approval part, approval for clients that do not render elicitation (mobile), paused since ADR 0014, was resolved on 2026-10-02 by ADR 0046: through another face, not through the conversation. The inquiry verb: done 2026-10-12 for 0.24.0 (ADR 0062, tools/ask.md): theasktool, off by default, answered in chat,wisp-tui, and throughwisp questionsunderwisp mcp, where the turn parks. Open: the operator’s hand test of the client’s question form (D8), after whichinquiry.elicitationmay default on (roadmap.md, “Not scheduled”). - Approval banners when the client’s dialog works. Done 2026-10-12 for 0.24.0: the banner is posted only once
the client’s dialog has gone unanswered for
approval.bannerDelaySeconds(default 10), and not at all when it is answered sooner (ADR 0046, amendment of 2026-10-12). - Waiting MCP requests in plain chat. Done 2026-10-12 for 0.24.0: plain
wisp chatnotes commands, facts, and questions waiting inwisp mcpservers before its prompt, and answers them with/approvals approve|deny,/facts keep|drop, and/questions answer|declinewhen its input is a terminal (ADR 0046, note of 2026-10-12).