P0 parity block + agent capabilities: providers, MCP, subagents, input UX — review-hardened#6
Merged
Conversation
The bordered prompt box no longer disappears during a running turn — it stays below the status line (Claude-Code style) so steering is always visible and inviting. Steer hint moved beneath the box. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ask_user now accepts optional `options` (2-4 short choices). The TUI renders them Claude-Code style: ↑/↓ + Enter or 1-9 to pick, a final "✎ type my own answer…" row, and typing any character drops straight into free-text (Esc returns to the options). Options flow through question.asked → protocol → UI; mock model gains a MOCK_ASK=1 stage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A distinctive glyph per activity, paired with the existing verb pools — the timeline is legible at a glance (design principle + frames from Hux's lynx-agent-spinners, MIT): study scan reading head sweeping the line edit fillsweep cells filling up shell cascade output tumbling out general sparkle the Mist signature (unchanged) Frames normalized to a fixed 4-cell width so the status line never shifts; each spinner animates at its native interval (60-150ms). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- /rename <name> renames the current session; persisted in the store meta so /resume and /sessions show it (works even before first turn) - New sessions auto-name themselves: after the first turn a tiny background model call turns the first question into a 3-6 word title (falls back to the raw prompt; never overwrites a user-chosen name) - session.renamed event → transcript line (✎ named/renamed) - SessionStore.rename rewrites the meta line in place; store test added - Mock model answers title-generation calls with a canned name Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third theme, from the Demon Slayer VS Code spec: Tanjiro's checkered green-black (borders/sage), Yoriichi's crimson + gold sun crest (error/accent), flame-arc ramp (deep red → crimson → orange → gold → yellow-gold) on warm parchment text — firelight, not a stock dark theme. Themes can now carry their own spinner vocabulary (Theme.verbs): while hinokami is active the status line announces the twelve Sun Breathing / Hinokami Kagura forms (Dance, Raging Sun, Fire Wheel, Setting Sun Transformation, …) instead of the standard verb pools; switching themes restores them. Context glyphs (scan/fillsweep/cascade/sparkle) still follow the work. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flagship palette moves from generic pastels to the Mist Breathing spec: fog lifting into clarity — ramp pale fog → deeper haze → distant fog → mint hair tips → sudden clarity; brand #2E8C7C (sudden clarity), dim #93A6A4 (distant fog), warning/path #C9A227 (the gold eye), error #B5555A (muted, not alarming), border #45646E (calm slate). Spinner announces the seven Mist Breathing forms while active (Low Clouds Distant Haze … Obscuring Clouds), via the same Theme.verbs override hinokami uses. Verb tests now pin standard pools under cinnamon (the remaining no-override theme). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fourth theme, from the Moon VS Code spec: moonrise ramp (deep purple → kimono pattern → living blade → flame markings → gold irises), brand #9C2F52 (the living blade), error #E0435A (red sclera, unsubtle), path/warning #D4AF5A (gold irises), moss-green success, moonlit lavender text on the moonless-night palette. Spinner announces the sixteen Moon Breathing forms while active (Dark Moon Evening Palace … Moonbow, Half Moon) via Theme.verbs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Interactive launches open with a bordered banner: ◆ Mist vX · centered "Welcome back, <user>!" · Misty the ghost rendered as truecolor pixel art (half-block ▀/▄ cells, two pixels per row — 20×16 grid from the character sheet: blue-gray cloud body, mint crown arc, navy eyes, highlight, trailing tail dots) · model/engine/session/cwd facts. Right rail (≥92 cols): getting-started tips + most recent session with a /resume pointer. Long cwds middle-truncate; the rail is fixed-width. One-shot argv runs keep the compact one-line brand so scripted and tmux output stays clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implementation detail, not user-facing info — the info line now reads just model (+ session id when resuming). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Inventory of the deprecated Python app vs the shipped TS app: what's already at parity, P0-P2 workstreams with task checklists (provider matrix, MCP, headless surfaces, input UX, config, subagents, safety, plugins, DBOS, images, browser), and cross-cutting gotchas (sealed- binary dynamic import, test asymmetry, Windows, packaging, config/ registry compat). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Second axis alongside parity priority: capability/autonomy impact. Provider matrix and MCP top both lists; input UX drops to last; goal loops, skills, and memory jump from P2 long-tail to agent top-8. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per owner decision the Python specialized-agent roster (code-puppy, planning-agent, qa-kitten, helios, agent-creator) is NOT ported. Subagents are generic, Claude-Code-style: - invoke_subagent engine tool: fresh child MistEngine per task; only the final report returns to the parent (context isolation) - Several calls in one model response run CONCURRENTLY (fan-out), also concurrent with the batch's sequential tools - One delegation level: children don't get invoke_subagent; child system prompt forbids user questions and mandates a final report - Model override propagates to children; child diffs still render - subagent.started/step/done/error envelopes → transcript blocks (◇ subagent “label” … ◇ label done + report preview) and live [label] step rows - Mock model MOCK_SUB=1 stage (two-child fan-out + canned child reports); engine test asserts parallel starts, isolated reports in parent history, and the turn completing after Also removes a dead stray 'case toolblock' JSX block that had slipped into handleEnvelope (unreachable; Bun doesn't typecheck). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lors - Narration blocks: pin the text column width — inside <Static> the flexGrow child next to the ● bullet could overflow the terminal and hard-wrap at column 0 (the 'need to replicate' artifact) - Input box now carries the session name right-aligned in its top border, Claude-Code style (updates on /rename, auto-title, resume; clears on /new); same frame while busy - Theme.verb: spinner-verb text gets a per-theme color — mist sudden-clarity green, hinokami flame orange, moon living-blade crimson, cinnamon pumpkin — stats stay dim Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…view
Provider matrix (P0 §1, written by the parallel Mist session):
ModelClient interface + createModelClient dispatch; OpenAI-protocol and
Gemini streaming clients with Anthropic-shaped-history translation;
RoundRobinClient; per-provider env keys and default bases; parity mock
servers (mock_openai, mock_gemini) + client unit tests. MCP manager
groundwork (mcp.ts, unwired). Also lands the engine anti-stall fix
(auto-continue when a turn ends with open plan items + prompt rule).
Review fixes applied (all 10 findings from the adversarial review):
1. round_robin reachable: configFromDef no longer demands an endpoint
for distributor types (+ factory-path regression test)
2. Gemini functionDeclarations strictly name/description/parameters —
spread-in input_schema was a 400 on every tool request
3. Gemini functionResponse.name now echoes the originating call via an
id→name map (was hardcoded 'tool', breaking multi-turn tool use)
4. OpenAI reasoning models get max_completion_tokens (max_tokens is a
400 on o-series/gpt-5); early o1 previews skip reasoning_effort
5. Mid-stream {"error":{…}} frames now throw in OpenAI+Gemini clients
instead of ending as a silent blank turn (the 429 lesson)
6. MCP liveness wired (client.onclose/onerror → status) so
restart-on-crash can actually fire and dead tools stop advertising
7. minimax gets MINIMAX_API_KEY (was falling through to Anthropic's);
anthropic.ts docstring no longer claims the bare minimax type
8. Missing-key preflight restored for public endpoints (clear config
error instead of a wire 401); keyless custom endpoints still allowed
9. round_robin cycle guard in the engine resolver
10. Engine-level parity test: full runTurn loop through OpenAIClient
Cleanup from the same review: dead DEFAULT_BASE table and dead
thinkingStart removed (openai.ts), MIST_DEBUG_STREAM capture added to
Gemini, env lookup hoisted out of stream hot loops, static rename
import + @modelcontextprotocol/sdk declared in @mist/core, honest
comments (partialArgs claim dropped, thoughtSignature typed).
41 tests green; binary rebuilds clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resuming (-c, -r, /resume picker) now paints the tail of the stored conversation above the ↺ resumed line: '— earlier in this session —', then the last 3 exchanges — user prompts and assistant text verbatim (text-with-tools renders as ● narration), tool activity collapsed to one dim '⋯ ran N tool calls' line per gap. Steer prefixes stripped; auto-continue nudges and compaction summaries stay hidden. Both resume paths share one historyTailItems helper (unit-tested; replaces the old last-user+last-assistant-only replay that showed nothing when a turn ended in tool calls). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Root cause of the P0 session's repeated mid-implementation stops, confirmed from its session file: the last turn contained EXACTLY 25 assistant requests (MAX_REQUESTS_PER_TURN), ended on a tool_use whose result was recorded, then the loop exhausted its budget and exited silently — no final text, no event, and the anti-stall nudge never ran because the cap exit bypasses that branch. - Cap raised: default 100 (subagents 50), MIST_MAX_REQUESTS env - Cap exit is now loud: '⏸ request cap hit (N model calls this turn)' step + a final message telling the user progress is saved and to send 'continue' to resume - Regression test: capped run surfaces the pause and the resume path Also snapshots the parallel P0 session's in-progress work at a green checkpoint (65 tests): MCP wired into the engine tool belt (§2) and headless-surface groundwork (headless.ts/headless_run.ts, §3). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The trigger previously used the chars/2.5 estimate at a 60k default — compacting a 200k-window model 3x too eagerly, and only checking at turn start. Now: - Every API response's input_tokens (the actual context size) is tracked; the estimate is only the cold-start fallback - Threshold: MIST_COMPACT_AT, default 200,000 real tokens, clamped to 80% of the model's registry context_length when declared - Mid-turn check after each tool round — a 500-request turn can outgrow the window between turn starts (one failed attempt stops retries) - compact() resets the reading (history changed → size unknown until the next request) and reports the real before-count in the ⇣ line - /status context figure now shows the real reading too Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Input stack (§4) rebuilt on a single owner: - useReadline state now lives in REFS with a render tick — input() mutates synchronously, so multi-key batches never hit stale closures; all readline tests pass (were 9/9 failing, omitted from the P0 session's '0 fail' report) - TDZ crash fixed: recordHistory declared before submit's dep array (typing @path completions crashed the app with a ReferenceError) - rl.reset() TypeError on every submit → rl.handle.reset() - readline now owns ALL modes: busy/steer and question free-text use the same buffer (full editing everywhere); the old input state, historyNav, and applyCompletion duplicates are deleted — idle ↑/↓ history works again (was writing an invisible buffer) - Emoji/CJK/paste chunks insert wholesale; cursor motion + backspace are surrogate-pair aware - Tab cycling rebuilt: anchor+tail captured at first Tab, candidates cycle in place; /cmd completions drop the trailing space that emptied the token - Ctrl+R search: Esc now cancels (was advertised, swallowed); Ctrl+T transpose dropped — the plan toggle owns the key (doc + test agree) MCP (§2) actually wired at runtime: - EngineSession attaches McpManager + auto-starts servers on construct (mcp_servers.json was silently ignored outside unit tests), exposes .mcp for the /mcp command (which read a nonexistent property), emits mcp.status (⚡ started / failures in transcript), stopAll on /quit History surgery (§5) on genuine turn boundaries: - turnStarts() skips tool_results/steers/auto-continue riding in user-role messages — /pop no longer orphans tool_use pairs (API 400), /prune keeps whole turns atomically, /truncate drops whole turns and never cuts inside one; /prune 0 refused (silently wiped everything) - Regression tests for tool-traffic boundaries + orphan prevention 98 tests, 0 fail. Live-verified in tmux: @completion (no crash), Tab cycle, ↑ history recall, Ctrl+R + Esc, /prune 0 refusal, submit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Misty the ghost retires; the welcome banner now perches the Owlgebra owl — 22×18 pixel grid, same half-block truecolor renderer: blue tufts and wings, light face/belly with dots, big amber eyes with white glints, yellow beak + talons on a brown branch, sparkles. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The owl hands the perch to a witchy crow, per the new character sheet: side profile facing left on a 24×20 grid — charcoal witch hat with green band, gold buckle and crooked tip, gray-blue head, green eye, big orange beak, slate wing behind a lighter chest. Same half-block truecolor renderer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The profile crow read as mush at half-block resolution. Redrawn with the discipline that makes Clawd clean: front-facing, every row a strict mirror (asserted at design time), 8 flat colors, big features (3px eyes with pupils, center beak, buckled hat band), solid silhouette with zero stray pixels. 20×18 grid. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Birds retired. The character is now the brand itself: a small round mist cloud with dot eyes, rosy cheeks, a tiny mouth, and cloud-puff base. Clawd-grade minimalism — 3 colors, 16×12, strictly symmetric. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fresh-system experience was broken: the default model was minimax-m3 (dead quota) and any model name not in a registry file hard-failed — a new user with just an API key couldn't start. - scripts/install.sh: clone → ./scripts/install.sh gets a working `mist` — installs Bun if missing, builds ts/dist/mist, links onto PATH (~/.local/bin or /opt/homebrew/bin; MIST_BIN_DIR overrides), prints first-run model setup - Zero-config models: default is now claude-opus-4-8; well-known names (claude-*, gpt-*, o*, gemini-*) resolve without a registry entry, keyed by the provider env var (ANTHROPIC/OPENAI/GEMINI_API_KEY); registry entries still win - getConfiguredModelName now respects $HOME (was hardwired to real homedir — untestable) - README: install-on-a-new-system section with the one-command path, first-run model options, and the custom-endpoint registry example - Tests for the defaults + builtin resolution (env stashed/restored — sibling test files share the process env) 100 tests, 0 fail; script verified end-to-end on this machine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The tests relied on env leaked from agent.test.ts (MIST_MODEL, MIST_MODELS_JSON, MOCK_FAST) and reused its mock port (9871) — passing locally by file-order luck, failing on CI. Now self-sufficient: own registry + dedicated ports (9931/9932), env stashed and restored, MOCK_FAST set in-file. Verified passing in isolation AND in the full suite (100 tests, 0 fail). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Everything since the cutover PR (#4): the full P0 parity block from docs/PARITY_BACKLOG.md, the top agent-capability features, a wave of UX polish — and two adversarial review rounds (10 verified findings each) with every finding fixed. 98 tests, 0 fail.
Agent capabilities
ModelClient+createModelClientdispatch: OpenAI-protocol and Gemini streaming clients (Anthropic-shaped history translated per provider), round-robin wrapper, per-provider env keys/default bases, protocol-faithful mock servers + engine-level parity testsmcp_servers.json, auto-start on session boot, tools merged into the engine belt,/mcpstatus/start/stop/restart, liveness wiring for restart-on-crashinvoke_subagentwith isolated child context, parallel fan-out of batched calls, one delegation level; the Python specialized-agent roster is deliberately dropped (owner decision, recorded in the backlog)headless.ts/headless_run.ts+ testsinput_tokens(default 200k, clamped to 80% of registrycontext_length), checked mid-turn too; estimate is cold-start fallback onlyInput & UX (§4/§5)
useReadline: cursor editing (Ctrl+A/E/K/U/W, word jumps), multiline, Ctrl+R reverse search (Esc cancels), surrogate-pair-safe motion, paste/emoji wholesale insert — one buffer owns idle, steering, and question modes@path+/cmdTab completion with working candidate cycling;!cmdshell passthrough/set(+SETTING_DEFStable),/show,/cd,/reasoning,/verbosity; history surgery/pop/prune/truncateon genuine turn boundaries (tool-traffic-safe,/prune 0refused)/rename+ auto-generated titles, resume replays the last 3 exchanges, arrow-key option menus for agent questions, input box visible while busyReview hardening
Two structured review rounds (multi-angle finders + verification) produced 10 confirmed findings each — all 20 fixed in-branch, including: round-robin factory reachability, Gemini strict-schema + functionResponse name mapping, o-series
max_completion_tokens, mid-stream error surfacing, MCP runtime wiring (was test-only), a TDZ crash in @-completion, dead idle history, and history surgery that could orphan tool_use pairs (API 400s). Regression tests pin each class.Verification
cd ts && bun test: 98 pass / 0 fail (507 assertions, 22 files)/prune 0refusal, resume replay, real-token compaction line🤖 Generated with Claude Code