The session's first executor request pays for the prefix every later one
reuses, so the session-wide hit rate mixes "did the cache work once warm"
with "how much a cold start could reuse". usagereport already records the
cold start, but nothing a live session reads projected it.
The live figures come from the serve ledger, which restarts on /new,
/resume and /fork; usageTally does not, so its ColdStart can belong to an
earlier conversation in the same process. The broadcaster therefore takes
the cold start from the ledger's own population: the first request the
ledger files under the executor (pricing.LedgerSource, the rule Add
already used), split by the same CacheSplit the ledger applies, and reset
with it. SessionUsage carries it as coldStart.
- /status (TUI): "warm cache" row, ledger hit rate with the cold start
taken out of hit, miss and unknown; "out/in" row, output ÷ input.
- Desktop session overview behind the cache meter: the same two figures,
computed in state/overview beside cacheRate.
- wire-parity: ColdStartUsage mirrored in port/session.ts.
A fourth kind of tab opens a real shell (ConPTY on Windows, a pty elsewhere) in
the project folder, outside the model's permissions and sandbox and with the
host's provider keys left out of its environment. The kernel keeps each shell's
output, so a tab left or a window reloaded comes back as it was; a tab is named
for the command submitted while the shell is busy and carries a blue dot, and
closing a busy one asks first.
Also: the composer's note stack no longer clips to a few pixels when it holds
two notes, which left the second one overlapping the input.
The sheet already fills the window, so enlarging only took it over the title bar and added three window buttons beside its own two. The control, the stored preference, the window buttons it summoned and the drag-region rules that went with it are removed; the board draws no buttons in that corner besides closing.
Compaction moves the folded span into <session>.outputs/fold-<hash>.md and leaves a pointer the model reads back with read_file. The summarizer path, its retries, bounds and tests are removed.
Answering an ask with no selection ends the turn normally instead of reporting a failure.
Find bar, overview and context cards, compact dialog, image preview, root-missing banner, toasts, side panel and prompt refine are aligned to the Chat-Tools board; the agent preset picker follows the Agent-Picker board.
Marks sit at each message's place in the whole conversation (a mounted
message by its own box, an unmounted one by its block), filling the column
instead of a compact cluster in the middle. A grey band follows the viewport
and the marks inside it draw darker; a message that changed files draws
longer; stars are orange. Hovering grows the pointed line and two neighbours
each side (22/16/12px) and opens a card: "你的第n条 · 改了n个文件", two lines of
the message, and the click/right-click hint. Marks closer than 5px join into
segments of at most 56px; hovering one lists its messages with their numbers
and stars, and a press on bare track lands on the mark at that height.
Unloaded earlier messages show as a count pill at the top with a tooltip.
Ctrl+Up/Down rings the mark it walks to and shows its card. A landing on a
mounted message glides over 300ms and the message flashes. The rail needs
three of your messages, is hidden in the folded narrow layout, and reduced
motion switches without animating.
The test for BackgroundJob imported Tool from the port, which does not
export it; it comes from the wire module.
Workbench (WB-Frame, WB-Parts): a raised panel with the float shadow; a 42px tab strip on the page tone with the file-tree tab first, the active tab a raised folder tab of 35px that sits into the panel, others 34px and quiet; a 40px path bar whose segments are faint 12px mono with the file name in semibold text; the read/edit/diff choice as a 24px segmented control; Save as the 32px primary button, outlined while there is nothing to save. The editor sits on the raised surface. Its default width is 520 and the drag starts at 360 with a 900 ordinary limit, as the board's width rule states.
Command palette (Cmd-Palette): 14px corners, a 52px search row at 15px with an Esc key, 11.5px section labels, 36px rows that light with the float highlight, and a 36px footer on the page tone.
A delivered file is one row in a single column: 16px file icon, 13px semibold name, 12px faint description, an Open pill and a 28px more button, 10px/12px padding in a 10px bordered card; the one open in the workbench takes the accent border. The two-column grid and the 22px badged icons are gone, and the more button keeps its "More actions: name" label.
The empty conversation drops the grid and glow it painted under the hero and sits on the plain surface, as both editor boards draw it.
Your message is a 15px overlay bubble at 14px/1.6 and at most 78% of the column; the reply head is a 20px accent R tile beside the 13px semibold name. The execution process is one card with a hair border and 10px radius: a 30px header carrying the running pill and the step count, then 28px rows of kind glyph, the board's verb (读取, 编辑, 运行命令…), the target in 12px mono, the reading, and the status mark at the right end. The raw tool id stays on the verb's title, where it is still one hover away.
The legacy !important rules on .activity-body, .activity-group and .call[data-call] > .c are deleted so the design layer can draw them; src/design/turn.css holds the replacements.
One 15px box with the composer's only shadow; a top row that exists only while a turn runs or files have changed, holding the run pill and the changed-files pill; 14px/1.6 input with 10px/16px padding; a toolbar of 28px borderless pills in the 12px meta size; the model name in 13px semibold text beside its effort; 32px round send and stop, stop drawn as a danger ring. Under 590px of conversation the pickers tighten and under 420px the effort reading folds into the model button, as the narrow-window state shows. The status line keeps 11px faint labels with muted semibold values.
The legacy !important rules on .compose, the pickers and the attach buttons are deleted, since an important declaration in the legacy layer outranks every design-layer rule; the replacements live in src/design/composer.css.
The window bar is 48 high on the surface with a hair line under it; the breadcrumb is 13px and the four icon buttons are 28px, ordered find, device access, theme, workbench. The sidebar foot is the Rail-Foot board's single toolbar row: usage, files, tools, extensions, memory and remote as 28px icons whose names carry their reading, settings at the right end, and feedback as its own 30px row with the unread count. The account entry leaves the rail for settings, as the board says. The empty state's mark sits in a 44px accent tile above a 22px title.
The legacy .chrome, .railfoot, quick-nav, wallet, user-foot and hero rules are deleted rather than overridden; the replacements live in src/design/shell.css in the design layer.
Rewrite internal/runtime/delegation around one Runner and one tool.
spawn_agents runs 1 to 8 independent tasks in parallel, each in its own
session with three base tools (read_file, write_file, bash); plan mode and
read-only skills keep a read-only child. A child's full answer is archived;
the caller gets the opening, a reference, and the files the child read and
wrote, and pages the rest through read_subagent_result.
Removed with it: task, read_only_task, parallel_tasks, fleet,
list_subagents, background sub-tasks, steering and its limits and settings
UI, continue_from, write_paths claims, isolated worktrees, best-of-n, the
run graph and the runtime-resume benchmark. Stale writes by children stay
refused through the per-agent file views.
The use_capability description no longer names task:fleet, so the stable
prefix and its golden files change once.
complete_subtask, the host adjudication of its criteria and the 'lowered by the
host' note are gone, with the handoff audit channel and its metrics, trajectory
field and benchmark columns. A delegated child ends the way any turn does and
the parent reads its last reply.
The host's own receipts appended to a child's reply and the write-scope check
stay: they need a record of what the child changed, which is replaced with the
evidence ledger later.
complete_step now only says a step is done: it names the step and what is now
true, and the host advances the task list as before. It no longer asks for
commands, files or criteria to cite and no longer checks them against the
session's receipts.
conclude_blocked existed to let the readiness gate through and goes with it;
the prompts that pointed at it now ask for a sentence in the reply. Plan steps
lose their acceptance and verification fields: the submit_plan schema, the
planner and executor prompts, the rendering and the re-approval rule all
stop mentioning them, and plans saved with them still load.
The executor's no-action nudge now keys on a plan naming files only.
With the final-readiness gate gone, FinalReadinessError, the readiness audit
and the structured readiness on TurnDone have no producer, and neither do the
contract-shadow, completion-report, evidence-bundle, outcome-progress,
protocol-recovery, verification-drift and project-check-probe audits. Removes
the types, the sink capabilities and their forwarding in every wrapper, the
trajectory and metrics fields, the final_readiness outcome and notice code,
and the delivery-recovery submit port.
The ACP status shape and the desktop reader of old sessions keep their
readiness fields: external editors and recorded sessions still carry them.
Both only steered the final-readiness gate, which no longer exists: the flag
chose exit 3 for an unmet readiness verdict and the setting chose whether a
changed turn was held for a check, a review and a sign-off. Neither can do
anything now.
`run` still exits 4 when an untrusted folder refused its edits. A user config
that still carries host_verification loads unchanged; the key is ignored.
Removes the HoldOwedChecks and WaiveOwedChecks plumbing behind them.
A turn that ends with its answer is done. The agent no longer asks, at the
point of stopping, whether a check ran after the last write, whether a
high-risk change was reviewed, or whether captured test criteria still hold;
it no longer ends a run with a readiness error, and the controller no longer
re-runs the turn to satisfy one.
Goal keeps its update_goal report and the evaluator, and still holds a
complete claim while the task list is unfinished; it no longer reads a
readiness result or freezes a verification contract. Review sub-agents are
ordinary sub-agents: nothing requires them to file a typed report.
Removes the readiness, owed-review, baseline-criteria, carried-proof and
review-report code, the delivery checkpoint, the readiness continuation, the
orphaned helpers they left in evidence, and the tests that asserted the removed
behaviour.
A session method refused because another runtime owns the transcript answered
-32600 and prose, the code a malformed frame gets; an ownership probe that could
not decide answered -32603, the same as a disk that would not write. A client
could not tell "held" from "unreadable" from "your request was broken", so it
could not decide whether to ask the person to close a window or retry.
session/new, session/load and session/resume now answer -32022 with data.code
busy.session_in_use for a held lease and -32023 with data.code
session.lease_unprovable when the store's probe cannot prove ownership either
way; -32600 is left to a genuinely malformed request. The human message stays.
The HTTP frontend, the kernel, the lease and the inbox are untouched.
docs/ACP.md states the table and what a client does with each answer. repolint's
family-vs-writer check is now parameterised by family; it reads the lease
sentinels beside the inbox ones, so a lease sentinel added without a coded case
fails by name against the ACP writer.
A turn no longer builds a shadow task contract, a completion report or a
sealed evidence bundle, takes a workspace snapshot, or hands the host a
completion receipt. Removes the agent-side producers and their wiring in boot,
the observation and verdict packages that only they used, and the
write-protection and unconfined-launch probes that only boot read.
The receipt and audit shapes on the event wire, the terminal and the desktop
settings stay for a later cleanup; nothing sends them now.
The loop no longer classifies a tool-call turn that arrived without
reasoning, retries it, or keeps a file-backed cooldown for it. Removes the
watch and the cooldown state, the deferred stream sink they needed, the
provider policy interfaces and their implementations, the descriptor field on
the extension wire (schema and SDK regenerated), the state-dir path, the
run-metrics counters and the protocol-recovery kinds.
The protocol-recovery audit channel itself stays for now.
Problem: upstream studio changes made the model-health UI PR conflict in Composer.
Root cause: studio added WorkspaceInfo while the health hook removed the former
inline ModelEntry loading state in the same import declaration.
Fix: retain studio's workspace information, running-message intent and composer
hint behavior alongside the consent-gated health hook. Remove the unused
ModelEntry import. The grouped picker, default-off setting and old-server hints
remain unchanged; the feature diff remains 514 additions across 22 files.
Verification: production frontend build, frontend tests and census; go vet,
pinned lint and repository checks; HTTP health authorization/settings tests,
builtin tests and inventory-reconciled boot partitions.
The registry declares 324 pairs now: the 202 it already had and 122 page
copies that agree field for field with the struct their handler writes. The
table moved to a second file, wireparity_table.go, rather than taking
wireparity.go past the 800-line ceiling; the checker still reads one list.
Left out on purpose, because the writer is not a named struct and a guard
over the lookalike struct would not see the response drift:
account.DeviceGrant (/account/login assembles a map), market.Page
(/market/packages assembles a map) and control's McpDraft (/mcp/parse
assembles a map). host.ts's Refusal and ViewRect are the Electron preload's
bridge, not kernel wire; workspace.ts's WorkspaceEntry has no writer.
Tests: the added half resolves, is exact today and is unique per reader; a
dropped field on createBackupRequest -> BackupCreateRequest names the field.
The terminal's hand-written HistoryMessage dropped images, via and modelRef.
A turn that was only an image has empty text, so Restore saw nothing to draw
and dropped it from the transcript, and every reload lost the device and the
model of turns it did keep. Carry the fields that decide that a turn exists
and what it was, restore the image-only row with an honest line, and register
the pair in repolint so a dropped field fails make check.
Problem: Saved connections lack health evidence when selecting a model, while
automatic credential-bearing checks require an explicit user opt-in.
Root cause: The previous UI slice also redesigned the disabled picker, hiding
account endpoint headings and reducing density outside the requested scope.
Fix: Preserve the original grouped rows, hosts, ordering and modelLabel behavior.
Add only short accessible health chips after reading backend consent. Put the
global switch outside the service editor, and explain unsupported older servers
and settings-read failures without enabling probes. Rebase onto current studio.
Verification: 640 frontend tests, production build, census fixtures, vet, pinned
lint, repository checks, HTTP authorization/route tests and builtin tests pass.
All 849 boot cases accounted for: 846 pass, 3 skip. Negative controls fail the
group-layout and old-server regressions. Native Electron light/dark wide/narrow
captures and 390px browser inspection verify retained row density and hosts.
Native disable/reopen issues no new requests; no generation requests occur.
Every inbox handler answered a store refusal with -32600 and prose, so a client
could not tell "gone" from "wrong state" from "may already have run" — and one
that retried on any error re-sent work the kernel refuses precisely because the
turn may already have run. The HTTP frontend already names 14 conditions; ACP
now answers the same names, with -32020 for "the queue refused this call" and
-32021 for "the work may already have run", and leaves -32600 to a malformed
frame alone.
docs/ACP.md states the table and each refusal's class (terminal,
retry-after-repair, do not retry). repolint's family-vs-writer check now reads
both writers, so a sentinel added to the store cannot reach ACP unnamed.
NewStreamDialer is how SSH reaches a remote host under the user's proxy
(remote/attach), and none of dialer.go was exercised: netclient sat at
47% against a 47.2% floor on a declared-sensitive path.
Four tests drive it against fake proxies on loopback:
- an http proxy gets CONNECT to the target with Proxy-Authorization, and
the credentials never also travel as Authorization;
- a proxy that answers 407 yields an error, not an open stream;
- an https proxy sees a TLS handshake first, so CONNECT and credentials
never cross in cleartext;
- a SOCKS5 proxy gets username/password auth and the target by name.
Each fails when the matching guard in dialer.go is removed. The
netclient floor rises from 47.2 to 65.8.
The terminal's copy of /history's tool call had no argumentNormalization
field, so a restored transcript rebuilt the card from Arguments alone —
the proxy's effective text — and drew it as what the model wrote. The
original was not merely hidden; it never left the decoder.
Carry the host's normalization through HistoryToolCall into the
eventwire.Tool the restored transcript draws and inspects, following the
serve payload and the desktop copy that already do. The card still draws
only the effective arguments: showing the original is a UI decision for a
later change, and changing the card would also change a live call.
Register the pair as a declared subset of the serve historyToolCall in
wireparity, naming the six fields the terminal decides from. The exact
table is the desktop's and is read as a TypeScript interface, so a Go
reader belongs in the partial table, which compares both ways over the
declared names.
Problem: full transcript projection and transfer scale with conversation length. The session store now owns stable page snapshots and cross-page context, exposed through optional controller reads and an additive HTTP route. Existing full-history clients are unchanged. Validate through real Boot/resume, full-projection equivalence, cursor invalidation and append stability, request authority and foreground preemption. Focused history tests, race checks, Go lint and release-note tests pass; broad suites are recorded in the PR.
The terminal counted and drew a host-authored inbox entry as the person's
own pending line, so `d d` on it reached DELETE /inbox/items/<id> and the
kernel dropped the runtime's continuation. The desktop has always filtered
these out; the terminal never decoded the field it filters on.
The mirror now carries origin, readonly and capacity, and a declared-subset
wire-parity check holds it (and the page's copy) to the fields a decision
reads, so dropping one is a `make check` failure instead of a silent zero.
A host continuation is out of the pending rows and out of the count, except
where it is blocked or uncertain and needs a decision only the person can
make; there it is drawn marked as the runtime's. A read-only snapshot offers
no mutation key and says why.