An interactive terminal in the Web UI — steer your agents mid-run, Claude-Code-style (v0.26 → v0.29) Loomcycle's Web UI v0.26-v0.29 introduces a live agent terminal enabling mid-run steering, persistent interactive runs, inline interruption answers, and a terminal interface. The update includes cross-replica steering, view-switch survival, and polished rendering, allowing operators to drive long-running agents from the browser with features like queued messages and event streaming. loomcycle's Web UI ships a live agent terminal that lets the operator drive a long-running agent Claude-Code-style from the browser. Open /run, pick an agent, type a prompt — the agent streams back into a terminal. Type a new instruction while it's still working and it shows up as the next user turn before the model's next call. Answer its Yes/No questions inline. Close the page, come back two hours later, the run is still alive. Four headline mechanisms shipped at v0.26.0. 1 Mid-run steering: POST /v1/runs/{run id}/input + a new internal/steer per-run buffered registry depth 16, mirroring internal/cancel , with a drainSteer hook in the loop that pulls queued messages at the TOP of each iteration — never between a tool use assistant turn and its tool results user turn that orphans the tool use and 400s the provider; tested in TestRun DrainSteer OrderingWithToolResults which fails-before on the naive placement . A new EventSteer SSE event "steer", not "user input" — that name was taken by the persisted transcript event renders the operator's input as a distinct row. 2 Persistent interactive runs that park at end turn: the loop now emits EventAwaitingInput and parks waiting for operator input rather than terminating, with a heartbeat ticker pulsing OnHeartbeat so the staleness sweeper doesn't reap the idle run. Paired with per-agent unbounded iterations that lifts the 16-iteration soft-cap for LLM agents the same exemption code-js providers already get , keeping the 1<<20 hard ceiling as a runaway backstop; cancel becomes the stop. The flag round-trips through every AgentDef mirror F14/F40 chain so it survives the content-addressed substrate. 3 Inline interruption answers: when an agent raises a question via the Interruption tool, the terminal renders option buttons for fixed-set asks or a free-text answer box right in the live transcript — no need to bounce to a separate /interrupts inbox. The answer goes to the existing resolve endpoint; the parked run wakes on the same open stream. 4 The terminal itself: always-on prompt that routes by state send routes to steer while running, continue between turns ; inline interruption prompt takes precedence; awaiting input renders "idle — waiting for operator input". v0.26.1 added cross-replica steering via a SteerCoordinator that mirrors the existing CancelCoordinator's shape route by runs.replica id to the owning replica, await ack, never re-broadcast — the cancel-storm lesson . v0.27.0 made interactive runs survive a view-switch — pre-fix the loop was bound to the HTTP request context and closing the SSE stream cancelled the request, which cascaded to the loop ctx and terminated the parked run. The fix needed two pieces: detach the loop into a background goroutine under context.WithoutCancel r.Context so it keeps the request's auth principal + tenant values but is not cancelled on client disconnect; and have the handler stream by tailing the persisted event store via a new GetRunEventsSince runID, afterSeq, limit method sqlite + postgres, indexed on events by run seq instead of writing live to a ResponseWriter that has returned. A new GET /v1/runs/{id}/stream endpoint replays from ?from seq then live-tails, re-emitting each persisted event as the same SSE frame the live run produced. v0.27.0 also added Context op=self reporting the resolved provider + model per-iteration so a mid-run provider fallback that swaps opts.Provider/opts.Model in place is reflected truthfully . v0.27.1 + v0.27.2 polished the rendering auto-scroll, collapsed tool call, multi-line input, tool result fold . v0.29.0 today completed the polish layer with four pieces. User-message echo: the operator's typed prompt was invisible because the persisted user input event was filtered from the live SSE tail. Fix is client-side: useRunStream pushes a synthetic user echo transcript entry on its own sends, seeded in start with the initial prompt, appended in send steer and sendMessage continuation , rendered as "❯ {text}" distinct from a drained "» {text}" steer frame. Context-size gauge in the LiveRunPane header: "ctx 47.2k / 200k 24% " with an amber 70% / red 90% color bar, computing the true prompt footprint as input + cache read + cache creation tokens the prompt-caching honest accounting; input tokens alone undercounts . When the provider doesn't report a context window Ollama the gauge shows just the absolute size without a bar. The plumbing: providers.Usage gained an additive optional MaxContextTokens field stamped on per-iteration EventUsage from opts.Provider.Capabilities .MaxContextTokens; @loomcycle/client 0.26.0 picks up the field. Agent editor sampling controls + advanced JSON/YAML overlay: the agent create/fork modal now has dedicated inputs for temperature/top p/top k/frequency penalty/presence penalty/seed/stop blank = unset, "0" = explicit so temperature 0.0 stays distinct from default , and a scoped collapsible JSON/YAML overlay textarea for the long-tail overlay fields without dedicated controls channels, interruption, def scopes, etc. , shallow-merged over the structured overlay at submit. Deliberately differs from the v0.10.4 whole-overlay catch-all we removed in v0.11.6: system prompt stays in its own textarea no newlines-in-JSON , and the box is optional. Soft-reclaim of retired agent names: AgentDefSetRetired is now transactional and clears the agent def active pointer in the same transaction when retiring the currently-active def; lookup.resolveDynamic skips a retired active row as defense-in-depth fixes a latent runtime bug where a retired-but-active def was still served to runs ; LibraryEntry surfaces live version count + active retired, and the create modal's name-collision check loosens so a name with no live active version is reclaimable for a fresh create that's allowed to widen the tool ceiling. Three engineering moments worth keeping: the orphaned-tool use problem provider message ordering is part of the contract — drain steers at iteration boundaries, never between tool use → tool results ; the detach-from-request problem interactive runs need context.WithoutCancel + persistent-store tailing to survive HTTP request lifecycle ; the cross-replica problem already solved for cancel; SteerCoordinator mirrors . What this unlocks: the substrate becomes a development surface, not just a production runtime. The interactive-terminal feature also codifies the "parked run, drained at iteration boundaries, woken by an external event" contract that self-evolving agents exp6.5 v0.30.0 cross-instance mid-run resume and agent ensembles exp5 Channel.await consolidator both build on. One residual deferred: cross-replica re-attach a viewer on replica A re-attaching a run owned by replica B — single-replica re-attach covers the common case.