Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
29 changes: 28 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,32 @@ All notable changes to Runloop. The format follows [Keep a Changelog](https://ke
## [Unreleased]

### Added
- **The immersive town (DL-014, 2026-10-18).** `/` is a game you stay in rather than a web page with a canvas.
- **Full screen:** the town is the whole viewport, with no sidebar or top bar; the land goes on past the town (outskirts, farms, fields, the Brook and a lake, forest, hills, mountains) into haze and a sky that follows sim time.
- **Camera:** perspective with a narrow field of view (the default still reads isometric); drag to pan with inertia, zoom toward the cursor, free rotation (Q/E, right-drag, two-finger twist), tilt 10°–62° (Z/X), WASD/arrows, soft bounds, follow, fly into a building with the roof lifting. `cam=x,z,zoom[,az,tilt]` links (3-part links still work); `window.__runloopCam` for tests.
- **HUD:** world chip, Find (⌘K), the bell, the clock and speed with the sound toggle, notifications, a minimap (view outline, agents with status glyphs, alerts; click to go), the hotbar (Explore, Agents, Add to World, Intelligence, Lab, Menu), entity cards anchored next to their entity, the guide banner, an Esc menu (Display, Sound, Controls with the Simulated-vs-Real legend, Runtime, Connections, Pages, Help). It fades while you drag and hides with H; a needs-you dot stays.
- **Everything in place:** Add to World picks a lot in 3D (free lots are outlined and their labels are buttons) and collects the name and workspace in a card on the lot; Intelligence is the World Log at the Commons Library with any run's full trace in a sheet; Lab is compare at the Lattice Lab; Sessions and Connections are sheets; inside an agent's building a session strip scrubs its recorded sessions. `/?overlay=trace|compare|log|sessions|connect|list|map|add` opens them by link. The legacy pages stay full pages, each with "Open in the world".
- **Decorative ambient life:** cars on the roads out, bird flocks, drifting clouds and cloud shadows, water shimmer, a windmill. Never pickable or listed, never within 12 cells of an agent lot, still when the world is paused, gone under reduced motion.
- **Sound** (`apps/studio/src/audio`, Web Audio only, no files or dependencies): an ambient bed that follows the camera and the time of day, interface sounds, and four cues for live, real agent events only (goes live, needs approval, incident, task done), rate-limited; no sound before the first gesture, silent in a hidden tab, volumes and "reduce sound" in Esc › Sound, `window.__runloopAudio` for tests.
- **Phones** get a light 3D town with touch gestures (one-finger pan, pinch, twist, two-finger tilt) and bottom-sheet cards; framings keep room for the card or session strip at the bottom, so entering a building shows its diorama; the 2D map stays for WebGL off and as a Display setting.
- **Navigation:** `useStudioNav()` sends every run link to the right place: sheets and buildings on `/`, the pages elsewhere (⌘K included).
- **Compare** shows Claude Code's reported cost for dispatched runs (a Cost tile; "not reported" otherwise), says when a run is still recording ("Same calls so far…", "As of now…"), words the core's caveats (a run that did not finish, different outcomes, different test scope) and marks a run that no longer finishes as a warning; Duration says "excluding time paused".
- **The town (Runloop Commons), now the Studio's home (`/`).** A persistent, deterministic world beside the run log (DL-009, DL-010; plan `docs/architecture/world-simulation.md`).
- **Simulation** (`packages/town`, `packages/sim`, pure): 80 residents with needs, schedules, traits and friendships deciding by integer scoring; 28 buildings with interiors and opening hours; 14 outdoor spots; one tick per sim minute at 0/1/4/16×. `applyEvent` is the only mutator, shared by the runtime, replay and the Studio; `explain` builds a resident's Why only from its recorded decision.
- **World log** with a provenance on every event (`simulation`, `user`, `external-agent`, `system`, `inferred`), 15 event types, commands checked against `ALLOWED_SOURCES`; `WorldHost` commits before publishing, checkpoints, resumes after a restart (`world.resumed_after_offline`); migrations 3 and 4.
- **API:** `/api/world` (info, town, snapshot, events, explain, SSE stream, commands); `RUNLOOP_WORLD=off` turns the town off.
- **Studio:** a 3D town (merged static scene, instanced residents with a shader rig and level of detail, sky and lit windows from sim time (DL-011), cutaway interiors, labels), the clock and speed controls, a mode rail (Explore, Agents, Intelligence, Lab), context panels (resident with Why, building, place, district, agent), the World Log, an attention ticker, a map and a keyboard directory, ⌘K for residents and buildings, deep links (`?mode&focus&cam`) and redirects from old `/?run=` links. Automatic render quality (the new default) steps down when frames run slow.
- **Real agents in the town** (DL-012). **Add to World** gives a Claude Code agent a building in the Agent District for one project folder; sessions bind by dispatch id, then by folder, else wait in **Arrivals** to be claimed (claiming replays earlier runs). Health (`not_connected`, `awaiting_first_event`, `live`, `idle`, `offline`, `unknown`), attention, tool counts, subagents and incidents come only from the hooks, each citing its run events. The building's interior shows the session's robots. API: `/api/agents`, `/api/agents/arrivals`, `/api/agents/:id/claim`.
- **Assign task (dispatch).** Preview the exact `claude -p` command (preset, model, budget, timeout, environment variable names), approve it with a single-use nonce, follow its output, cancel it. `dontAsk` with an allowlist, haiku by default, a budget Claude Code enforces, its own process group, an audit log. `--plugin-dir` is added unless `claude plugin list` reports the tracer installed. `RUNLOOP_DISPATCH=off` turns it off; `RUNLOOP_DISPATCH_ENV` passes extra variable names.
- **Scripts:** `scripts/e2e-world.mjs` (the town renders, residents move, the clock advances, ⌘K opens a resident's Why with linked factors, Follow, the café interior); `scripts/perf-town.mjs` (render budgets under SwiftShader); `pnpm --filter @runloop-world/sim bench`. `pnpm screenshots` now captures the town, its panels, Add to World, an agent, its interior, Assign task and the World Log (`--suffix` for a second pass, e.g. at night).
- **Run compare (Experiments).** Pin a run as a baseline, run the agent again, compare.
- **Experiments page** (`/experiments?a=&b=`): the baseline defaults to the newest pinned run and the candidate to the newest other run of the same task. Six summary tiles (outcome, tests passing, failures, duration, tool calls, tokens), the first divergence, outcome and tests (fixed, newly failing, still failing), files only in A, only in B or in both, tool activity by category, tokens and models per agent, and permissions and delegation. Test runs, failures, files, categories, usage reports and the divergence link to their events in Traces.
- **Honesty rules:** a value a side did not report shows "not reported" and is never compared or shown as 0; executed-vs-traced pairs, runs still recording and token totals that cover different agents are flagged; a target or test name one side did not report is unknown, never a difference.
- **Baselines:** `POST` / `DELETE /api/runs/:id/baseline` (JSON and Origin guards), stored in `runs.pinned_at` (migration 2), `RunSummary.pinnedAt`. A pin toggle with Undo on the run header and the Overview history; a baseline mark in the sidebar, the history and the run switcher; a "Compare" button on runs that have a baseline; command palette entries.
- **Core:** `summarizeRun` and `diffRuns` in `packages/core/src/compare.ts`, pure and unit-tested.
- **`run.started.speed`** (optional, additive): the scripted demo's pacing, so compare does not call a run at speed 0 "faster" than one at speed 1.
- **`tool.call_started.target`** (optional, additive): the file of Read/Edit/Write/NotebookEdit, the directory of Grep/Glob, the first word of a shell command (never its arguments); the workspace path or program for the scripted demo's tools.
- **3D world richness pass (D10):** tighter framing (at 1440×900 the board spans 97% of the stage width and a robot projects to 44 px; at 1920×1080, 81–82%), chibi robots with a dark glass visor and state-coloured eyes, warm key and cool rim light, tinted rooms with shaded floors, paths that light up only while a robot walks them or a recorded message crosses them, and a light-theme "architectural model" look (DL-009).
- **3D world richness pass (D10):** tighter framing (at 1440×900 the board spans 97% of the stage width and a robot projects to 44 px; at 1920×1080, 81–82%), chibi robots with a dark glass visor and state-coloured eyes, warm key and cool rim light, tinted rooms with shaded floors, paths that light up only while a robot walks them or a recorded message crosses them, and a light-theme "architectural model" look (DL-013).
- **Screenshots:** `scripts/screenshots.mjs` also captures Experiments (default pair, each run kind's pair and its lower half, an unknown run, offline) and a pinned baseline's Traces header. It pins a baseline for the capture only when none exists, and unpins it afterwards (`--no-pin` to skip).
- **Claude Code tracer.** The plugin is in `integrations/claude-code-plugin` and the marketplace manifest in `.claude-plugin/marketplace.json`.
- Hooks are observe-only: async, with Stop, StopFailure and SessionEnd synchronous. They always exit 0 and print nothing.
Expand Down Expand Up @@ -48,6 +66,13 @@ All notable changes to Runloop. The format follows [Keep a Changelog](https://ke
- **Docs:** `docs/architecture/overview.md`, `docs/architecture/event-model.md` and `docs/status/verification-report.md`.

### Changed
- **Assign task approval moved to the runtime.** The Studio shows the exact command, then **Approve in Runloop…** opens the runtime's own approval page; it follows the outcome (`GET /api/dispatches/previews/:id`) and never posts a nonce itself.
- **Agent truth labels:** "Real · Claude Code · observed" only for an agent registered in this runtime; a presence the agents API does not list is an "Unregistered building" with no actions, and one not confirmed yet says so. A dispatched task whose hooks have not reported yet reads "Task running · no events yet" beside the health; "Live" now means a session is open and its hooks reported in the last 5 minutes.
- **World clock:** clock frames are anchored at the runtime's `wallMs`, and a speed change re-bases the clock at its event, so pausing at 16× no longer throws walkers back and steady 16× no longer steps backwards; resuming the stream names the world (`?after=&world=`), and a snapshot from another world resets the town's state instead of folding onto it.
- `scripts/screenshots.mjs` captures the immersive states (horizon, tilted street, the café, Add to World's lots and card, the agent and its building, the Intelligence and Lab sheets, the trace sheet, the Esc menu); `scripts/e2e-world.mjs` waits for clicks under software rendering and reads the world clock from `/api/world` (a snapshot's tick stands still at night). Screenshots wait for interiors by frames, restart a crashed browser and skip the first-visit hint.
- **`/` is the town.** Overview, Live World, Traces, Experiments, Integrations and Settings stay; the mode rail replaces the run sidebar except on `/world` and `/traces`, and `/world?run=` shows "Agent District › {building} › Session #n" with **Back to town**. Old `/?run=` links redirect to `/world?run=`.
- The light-theme world decision is now numbered DL-013 (it was DL-009), so the plan of record's DL-009–012 stay valid.
- The tracer's `TraceSessionManager` takes an `onSessionSeen` hook and can close a session Runloop stopped (`closeStopped`, inferred); the recorder has `subscribeAll`.
- Write guards (JSON content type, allowed Origin) apply to `DELETE` as well as `POST`.
- Experiments is in the sidebar; the design system lists it as shipped.
- The Metrics panel shows an executed run's tool calls by category, from Runloop's own tools (the mapping compare uses), instead of "not categorised".
Expand All @@ -57,6 +82,8 @@ All notable changes to Runloop. The format follows [Keep a Changelog](https://ke
- Studio URLs end in a slash (`/overview/`), so the static export works on plain static servers.

### Fixed
- **Immersive town review (2026-10-18), game feel and truth:** Add to World's last step follows the live agent (it hands over to the agent's own card on the first real event and never says "waiting for its first event" after one), and a link to a lot that does not exist or is taken stays in lot picking with the reason; a double click enters a building even when the second press lands on the card the first one opened (the town times double clicks itself); Explore, Agents, Intelligence and Lab, the World Log and compare leave the building the viewer is in instead of moving the camera away from a still-open interior; cards stand beside the screen box of what they describe (a building, an interior, a lot), stay above the minimap, and dock when nothing fits; the session strip and the guide banner centre in the area an open sheet leaves free (the strip rises above the minimap when it would be too narrow), and notifications start below the banner; on phones the card stands above the session strip; the strip says "Open · idle 12m" for a quiet session ("Live" only when the agent is live) and its picker says Open, not Live; a compact agent label keeps "Incident" or "Needs approval" in words; an agent going offline after its session closed is in the bell's list only (no "need you", no popup); a real agent's cue and its notification show together, and a stale "is live" or "started a session" never pops after newer facts; the HQ diorama is in fixed town materials (no longer a black slab in daylight or a white model in the light theme); night stars come out just above the haze line, so the lowest tilt shows them; a loading veil (the town's name and a progress line) covers the stage until the town is drawn, and the first-visit hint starts only then; a pinch that starts on the HUD zooms the town, never the web page; closing a card, the directory or the session strip gives focus back to what opened it.
- **World integration (2026-10-18):** the runtime now wires the agent layer and dispatch (they existed but were not mounted, so `/api/agents` answered 404); a cancelled or timed-out dispatch closes its traced run as interrupted (inferred) instead of reading live for 5 minutes; a dispatched session in a workspace that was traced with `--plugin-dir` is traced again (the plugin is passed unless `claude plugin list` reports it installed); keys typed right after ⌘K reach the palette instead of page shortcuts (focus no longer waits for an animation frame); a deep-linked `?focus=resident:` frames the resident once its position exists; at phone width the compact "Add" button is named "Add to World" for assistive technology; inside an agent's building the interior follows a session that starts while you watch; a grouped dispatch item in the feed shows the provenance of its latest event (the system finishing it, not you approving it).
- `--doctor` now finds the plugin data dirs Claude Code actually uses (`runloop-tracer-inline` for `--plugin-dir`, and any other `runloop-tracer*` directory) when run from a shell.
- The Studio no longer shows "Runtime offline" after a single slow health check. It needs two consecutive failures once it has been online.
- In the 3D world, a selected incident label is no longer covered by the selected agent's label. A second required label shrinks before it may overlap.
Expand Down
Loading
Loading