← Cycles
Qnative (provisional) · c2

Expressive Range

archivedcreated 2026-11-10 | **Completed:** 2026-11-11· last activity 2026-11-12· mode: alchemy (how far the kit stretches) inside evolution (a port of pages that exist, on data that exists).

c131 Phase 2. The whole qdash Inventory section in this app: seven listings, nine detail pages and the landing, in the Qpoint skin, on the data the web pages show, cut to one machine. We build our components in Rust (`crates/layer`, with the web layer's names) on top of the kit, and record per component how close it came and what it cost. Stretch: the Tour guide, with Info View and the `qpoint-guide` MCP driving the app. Extra stretch: the table with an expand row at full fidelity.

New in this cycle: GPUI Kit in the Qpoint theme, generated from the layer's tokens

Why

The spike (c1) showed the kit draws a clean window cheaply. It did not show whether the kit can carry the way design builds a page. That way is the web layer's composed vocabulary: Data Machines in aligned bands, ledgers with logos and pills, jump pills that pin, a skill file in an editor frame. This cycle tests that range on one whole section, with the evidence written down per component, so the V1 brand ruling (design c130 D5, c131 R8: tokens only, a kit component before a drawn one) is made on a scorecard rather than a guess.

Objective

Done means:

  • Data: cargo run -p app opens the Inventory landing (20 micros) on the meridian-day90 world (priya-x1's laptop). The data is cut from the Meridian seed through qdash's real ingest and handlers.
  • Pages: every listing and detail opens from it in the Qpoint theme, light and dark, with the fleet → personal translation (the plan's six rules, the harness pages merged).
  • Stories: a story per component and per page state, rendered headless and captured to PNG.
  • Scorecard: how each component was built, fidelity against its design-site demo, the HTML feature it lacked and what stood in, effort.
  • Budget: before and after, with strobe.
  • Stretches: done to the plan, or recorded as not reached.

Scope

  • Here:
    • crates/types (every Inventory shape);
    • crates/nozzle (a repository per resource);
    • crates/fixtures (the worlds);
    • crates/layer (new: our components);
    • crates/app (shell, router, theme, the Inventory context components and pages);
    • crates/stories (new: stories and captures);
    • scripts/ (the world cut);
    • this record.
  • Design:
    • scripts/tokens-to-kit.mjs (the token bridge, c132 deliverable 2 built here);
    • the cycle record in cycles/c131.native-app-v1/;
    • captures under public/cycles/design/.
  • Reads:
    • ../qcontrol/crates/qdash (the handlers, ui/types/api/*, the Inventory pages and components);
    • scripts/qdash-seed (the streams);
    • ../q-nuxt-layer (tokens/, the components).
  • Out:
    • Status, Events, Config, Connect;
    • the messages crate;
    • qmap beyond a link;
    • any change in qcontrol or the layer.

Key Changes

  • kick-off (2026-11-10): cycle created from design's c131 phase2-plan.md after Mark's four answers:
    • our layer in Rust;
    • translate fleet to personal, with the harness pages merged;
    • the Tour stretch with Info View and the MCP guide;
    • three review stops plus one per stretch.

    gpui-kit pinned to =0.9.1 for the cycle.
  • step 1, the world cut to one machine (2026-11-10):
    • scripts/cut-world.py loads qcontrol's seed generator as a module and expands the Meridian streams in memory, without touching qcontrol's tree.
    • It keeps one host's records, ingests them through the qdash binary's real path into a scratch database, serves it, and crawls every request the Inventory pages make. That is the listings for 24h, 7d, 30d and all time, and every detail by its id.
    • The result is one world file per cut in crates/fixtures/world/:
      • meridian-day90: priya-x1. 8,952 of 49,996 run records and 105 of 734 scan records; 128 responses, 533 KB. Four harnesses (Claude Code, Codex and Cursor monitored, Ollama a shadow install), 5 MCP servers, 5 models, 3 providers, 4 skills, 23 tools, 85 sessions, 3 accounts.
      • minimal: chen-mba. 94 responses, 130 KB.
      • fresh: empty, 44 responses, 2 KB.
    • The spike's hand-written world is retired.
  • step 2, types and repositories:
    • scripts/ts-to-rust.py generates crates/types/src/api.rs from qdash's TypeScript contract: 72 interfaces from 15 files, 78 structs. types adds the routes, Period and Request with one key rule shared by the cut script, the synthetic transport, the fixture plane and HTTP.
    • A fixtures test deserialises all 266 responses. With --features types/strict it also denies fields the contract does not name; none were found.
    • It found five places where qdash's handlers serve what the TypeScript does not say. They are recorded as OVERRIDES in the generator, as findings for qdash's contract:
      • HarnessInstall.plugins and .settings are null for a shadow install;
      • AgentRun.run_id and .model and Agent.version can be null;
      • EndpointInstall.plugins can be null;
      • Endpoint.harnesses is served as objects, not names.
    • Detail routes answer null for an id not in the window: the "not found" state, so repositories return Option.
    • The nozzle is now one generic fetch(Request) per transport, with nozzle::Repo on top: one method per resource the pages read, each the request the qdash composable makes. --world / QPOINT_WORLD choose the synthetic world.
    • Nine nozzle tests pass, one of which fetches every listing row's detail in every world. The fixture plane serves any world by the same key.
  • steps 3–4, the skin:
    • Design scripts/tokens-to-kit.mjs (the token bridge, c132 deliverable 2 built here) reads q-nuxt-layer tokens/semantic.mjs, tokens/tokens.json and components/data/palette.js. It writes crates/layer/themes/qpoint.json, "Qpoint Light" and "Qpoint Dark": 140 colour keys each, every kit colour slot covered, every key checked against the kit's schema. It also writes crates/layer/src/tokens.rs: our 21 roles, the palette, the data-viz slots, and the type, weight and radius scales.
    • The new crates/layer owns the skin: layer::install registers the theme and follows the system appearance; qp(role) resolves a role the kit has no slot for. The bundled Inter moved there from app, and the app installs the skin at startup.
    • Body size is 14 (qdash's), card radius 12, base radius 6.
    • Filled signals (success, warning, and danger and info in dark) get dark ink, because white on leaf and amber was too faint.
    • The mono family is left to the platform: the web layer's stack names Geist Mono but does not load it.
  • step 5, captures without Screen Recording:
    • crates/stories opens each story in a window at (-10000, -10000) and calls Window::render_to_image (GPUI's test-support on gpui-pre and gpui-pre-macos only; the kit's whole test-support pulls gpui-fast and a conflicting taffy). It writes target/stories/<story>-<mode>.png at 2×. Both stories render in both modes in 5.6 s.
    • macOS clamps a window to the display's height, so a story must fit in about 900 points.
    • --stock renders the kit's own theme; --family overrides the UI family.
    • scripts/publish-stories.py copies chosen captures into design's public/cycles/qnative/ with surface: native manifest entries (six for review stop 1).
  • Finding, the type: GPUI picks a face by family and weight and does not use a variable font's weight axis, so the bundled InterVariable.ttf drew bold and semibold as regular. Rendered in static Inter faces (the 3.015 install on this Mac), the scale had its weights.
  • The type fixed (2026-11-10, on Mark's word to download):
    • Inter 4.1 fetched from the rsms/inter GitHub release (Inter-4.1.zip, sha256 9883fdd4…6b11e) into a scratch folder.
    • Five static faces from its extras/ttf/ (Regular, Italic, Medium, SemiBold, Bold; 2.09 MB) now replace the variable pair (1.79 MB) in crates/layer/assets/fonts/. They are the same 4.001 build, with the same licence.
    • The family is "Inter" in fonts.rs and in the generated theme.
    • Checked with QPOINT_FONT_CHECK=1 stories: 400, 500, 600 and 700 each resolve to their own bundled face (2048 units per em, Inter 4), not the system's Inter 3.015 (2816).
    • Captures republished.
  • stories --show: the stories open as ordinary windows on screen (--mode dark, --stock and --family apply), for looking rather than capturing.
  • Committed at review stop 1 (12cc30a, 2026-11-10).
  • A drag area (2026-11-10, Mark: "those apps don't appear to have a draggable area").
    • TitleBar::window_options hands the title bar's drag to the app (app_owns_titlebar_drag), so a window opened with it has no drag area unless it draws the kit's TitleBar.
    • stories --show drew none; it now draws one with the story's name. The app's window already had one.
    • Two headless tests prove it: a press and move on the title bar reach start_window_move (the test platform's unimplemented!()), and the same gesture in the body moves nothing.
  • The Dev section and the component docs (2026-11-10, Mark: a dev or admin section to switch dev tools on and off, its first tool a component demo page; then "the equivalent of our component documentation pages … all the components in context working with multiple instances for testing all scenarios at a glance"):
    • layer::demos. The native component docs: one page per component, with a header, an event log of the last interactions, and scenario cards (variants, sizes, states, empty, minimal, typical, overflow), every instance live and stateful.
      • Ten pages. Skin: Tokens and type, Overview. Kit: Button, Switch and Checkbox, Tabs, Tag and Badge, Progress, Alert, Table, Honest states.
      • Our components join as step 3 builds them. Example data, as the web _demos use.
    • The app's Dev group. On in debug builds; --dev or QPOINT_DEV=1 in release.
      • Tools: component demos on or off; appearance (follow the system, light, dark); GPUI's element inspector (⌥⌘I, debug builds); the data source.
      • Components: the docs listed by group, each page built once and keeping its state.
      • The window now follows the system's appearance while it runs.
    • app split into a library and a thin binary, so stories render real app pages: app-harnesses, app-dev-tools, app-dev-components.
    • The stories crate reads the same registry, so every doc page is a capture.
    • Tests. Three headless tests click a switch, a button and a tab on their doc pages and read the page's event log back (GPUI debug_selector bounds). 18 workspace tests pass.
    • Captures. Six in the atlas (thread p2-dev).
    • Not yet: the dev settings are not saved between runs.
  • Committed (d3a87cb, 2026-11-10).
  • The layer in Rust: the plan's step 3, as far as the Harnesses pages need (2026-11-10).
    • The Data Machine family (layer::data): DataMachine, DataMachineGroup with its rows lined up across the band, DataMachineMicro, DataIndexSection with its auto-fill grid measured from its own width; the devices DataRankedBars (every layout), DataSegmentBar, DataDonutChart (canvas arcs), the spark; the web's number formatting ported with its quirks and tested.
      • Subgrid became one flex row per grid row with its tracks stretched; fit-content(45%) became two flex columns with fixed row heights; auto-fill reads a width probe one frame late.
    • Small pieces (layer::ux): UxPill, ProjectedBadge and ProjectedRing, StateEmpty and FilterNoMatches, AgentAvatar (the web's logo registry and name resolution; single-colour logos repainted per appearance), the entity chip.
    • Page furniture (layer::nav): PageHeader, ActorHeader with its metadata grid, NavJumpPills, the sticky band's backing.
    • The ledger (layer::table): DataTable as Qpoint draws it (not the kit's), DataListingBar with its quick filter and column picker.
    • The scorecard (layer::scorecard): one row per web component the section uses (how it was built, fidelity 0–3 against the design site's demo, what GPUI lacked and what stood in), shown on each doc page and as its own page.
    • Eight more doc pages with live scenarios; two more headless tests (a ledger sort, a quick filter).
    • Checked against qdash on :3030 side by side; most rows are at fidelity 3, DataRankedBars at 2 (stacked labels end in an ellipsis where the web breaks words).
    • Captures: seven (thread p2-data).
  • The world, recut: the crawl now follows each harness's agents_detail to /api/agent?id= and /api/surface?agent=, which the merged page needs (meridian-day90: 134 responses, 607 KB). Two more places where the handlers serve what the TypeScript does not say (seven in all) became overrides; all 274 responses pass the strict test.
  • Shell, router and the first pages: the plan's steps 4 and 5 to review stop 2 (2026-11-10, Mark: "continue as we planned").
    • The router (app::router): a Route enum with history (the title bar's back and forward), the shared period (24h, 7d, 30d, All; 30 days by default, c128), and anchors: go_to(route, "surface") lands on a section once it has laid out, as the web's #sec-… does. The spike's one-shot inventory read and its three plain tables are gone.
    • The pages (app::pages): each reads through the repositories on the background executor and draws loading, failed and empty honestly. Built: the overview (twenty micros from the seven listings), Harnesses, and the merged harness page. The six other listings say they are next rather than showing blank.
    • The merged harness page (Harness detail and Harness install detail, ruled in the Q2 answer):
      • The identity header: Status (qdash's Coverage, said as monitored or shadow) and the metadata with the install's long tail behind Show All Metadata.
      • Tiles: Providers, Tokens by model, Spend.
      • Jump pills over three sections. Sessions: 40 on this machine, sortable, ten then Show all. Configured here: the install's MCP servers and skills. Surface.
    • DataSurfaceSection and DataSurfacePanel (layer::data::surface, the plan's step 3e), to a spec measured on qdash's Harness page:
      • Framed panels with label columns as wide as their widest label and flat 15 % primary bars under Intl-compact counts.
      • Row hover and click; Show all, Only show top N, Show more (50 of N), View all N →; the configured chip, the tool kind pill, the folder and GitHub marks.
      • On one machine the Users, Teams and Versions panels leave (one person, one install, one version).
      • A doc page with its scenarios; four scorecard rows at fidelity 3.
    • Beside qdash at 1120 × 720 (the same content width, 844 px), and fixed:
      • Shell: the nav column is 212 px on the subtle sunken tone, and the page canvas is surface-sunken, so cards, panels and table rows sit on it as they do in qdash.
      • Ledgers: the column widths now fit.
      • The harness header: its metadata labels and values line up as two columns, and it keeps only Status, with "last active 132d ago" (qdash's ago(), ported and tested).
      • The overview: "Harnesses here" lists the most-used first, and the MCP servers bar uses the default palette.
      • The jump pills now dock and the scroll-spy follows. GPUI records a scroll container's child bounds before it applies the offset, and the page had subtracted the offset a second time.
    • Tests: 26 workspace tests pass (new: Intl compact, ago).
    • Captures: nine (thread p2-harnesses): the overview, Harnesses light and dark, the harness page at its top, Sessions, Configured here and Surface (light and dark), and the Surface doc page.
    • Not yet: the sticky table header does not pin, and the dev settings are not saved.
  • Committed at review stop 2 (6a919f4, 2026-11-10).
  • Providers, the provider page and the account page: the plan's step 5.3 (2026-11-10, Mark: "Commit, then Providers").
    • A spec first (spec-providers.md, measured on qdash at 1120 × 720): every tile, header cell, metadata pair and ledger column of the three pages, with its formula and verbatim copy, the fleet-only parts flagged, and nine oddities to decide rather than copy.
    • Shared plumbing, so the next listings don't repeat themselves:
      • pages::ledger::Ledger holds a table's sort, quick filter and column picker, and wires the layer's DataTable and DataListingBar back to the page.
      • pages::detail::Detail holds a detail page's scroll, docked band, scroll-spy, jumps and route anchors.
      • Harnesses and the harness page moved onto both with no visible change.
    • The listing:
      • The band: Providers with its concentration line, Tokens excluding cache, Spend with its top three.
      • The ledger: provider, models, harness types, accounts, API requests, tokens · share, spend, last used. The users column leaves.
    • The provider page:
      • The header: Spend and the metadata. Harness instances, users and orgs leave.
      • Tiles: API requests, Tokens, Spend, and Accounts (org-scoped, unscoped, by auth).
      • Ledgers: Models, Harnesses and Accounts. An account is typed company (grey pill) or personal (amber badge), and its row opens it.
    • The account page:
      • The header: what the account is, and its provider.
      • Tiles: Harnesses, Sessions, Tokens and Spend. Tokens takes the place of the fleet's Users (rule 6).
      • Attention: dual use (said of this machine), a personal plan, runs with no identity.
      • The harness-type chips, and Sessions.
      • The Users ledger, the instance ledger and the Shared row leave.
    • Oddities settled rather than copied:
      • Models sorts by tokens; qdash's initial sort matches no label.
      • The accounts ledger's auth column sorts on the method.
      • The account's Sessions tile names providers by label, and its Auth pair names the method.
    • New in the layer:
      • account_type, personal_badge, harness_chip and recency_dot (qdash's active, idle or stopped).
      • DataTable columns take a least width. Past it the grid scrolls sideways, as qdash's Providers ledger does at this width (its declared widths sum to 1020 px in an 844 px box).
    • Found and fixed: the story captures could show a page still loading.
      • An off-screen window gets no display-link frames, and render_to_image reuses the last drawn scene. A read that landed after the second frame was never drawn.
      • The stories now draw a frame at every settle step.
    • Captures: seven (thread p2-providers). 26 tests pass.
    • Committed (cd04f31).
  • Models and the model page: the plan's step 5.4 (2026-11-10, Mark: "Commit, then Models").
    • A spec first (spec-models.md, measured on qdash at 1120 × 720). It found that the model detail never sends a period: the web asks /api/models?model=<id>, all-time, which the world already holds.
    • The listing:
      • The band: Models (top three by tokens and Other), Tokens excluding cache, Spend with its top three.
      • The ledger fits 844 px without scrolling, as qdash's does.
      • The instances column becomes "harness types", the users column leaves, and the provider is one ◈ chip that opens its page.
    • The model page:
      • The header with Spend, and the metadata.
      • Default here: the installs on this machine whose config defaults to the model. It is served, unused on the web, and comes forward under rule 5.
      • Tiles: API requests, Tokens, Spend, saying "all time" as the web's do not.
      • Harnesses: the instances rolled up by type, as qdash's modelHarnessRows. There are no jump pills, as on the web; the title still pins.
    • Oddities settled:
      • The listing subtitle no longer claims all-time for a windowed feed.
      • The provider is shown one way, a ◈ chip that opens its page, where qdash shows it three ways.
      • "Harnesses" means types throughout.
      • Every ledger cell is 13 px.
    • Open: the server keeps one arbitrary provider per model. Sonnet reads Cursor on priya-x1, though Claude Code also calls it through Anthropic. Showing every provider needs the provider pages' models_detail, or a field the plane does not serve.
    • The provider page's model rows and the harness Surface's model rows now open the model page.
    • Captures: five (thread p2-models). 26 tests pass.
    • Committed with the Models commit.
  • MCP Servers and the server page: the plan's step 5.5 (2026-11-10, Mark: "Commit, then MCP Servers").
    • A spec first (spec-mcp.md). The detail asks only ?server=<name> (all-time), and the world holds it.
    • The listing:
      • Every server is typed by which side knows it: observed, configured or both.
      • The band: Count (observed / configured-only), Tool Calls and Tools Used, with their ranked bars below the value, where they have room.
      • The ledger: harness types (not instances) and the number of configs, with tools in the column picker.
      • The Source filter offers the values present in the data; the web's static list can never pick both.
    • The server page:
      • The Source cell, with what the source means.
      • The harnesses here whose config registers it.
      • All-time tiles: Tool Calls, Denied (red above zero, qdash's zero tolerance), Tools Used, In configs.
      • The gap line, keyed on harnesses rather than hosts: configured in, called from, configured but never called, called without config.
      • Tools, then Harnesses rolled up by type. The whole-run tokens and spend the web set beside per-server calls are dropped.
    • Configuration, new: the served per-harness config (transport, command or URL, the env and header key names; values are never collected), which the web computes and has not shown since c102 (rule 5).
    • OAuth: kept in the metadata as served. The spec found it is the latest event across the fleet whose host matches the server name; to verify before it reads as a per-server fact.
    • Shared: pages::rollups::by_harness_type (qdash modelHarnessRows), now used by the model page and the server page.
    • Captures: six (thread p2-mcp). 26 tests pass.
    • Committed with the MCP commit.
  • Tools, the tool page and the expand row: the plan's step 5.6, with the extra stretch (2026-11-10, Mark: "continue with whatever is next").
    • A spec first (spec-tools.md), with the expand row measured open on qdash: the layer API, the geometry, the timings, and what a sort or a poll does to open rows.
    • The expand row (layer::table):
      • Row::details(…) and DataTable::expand(open, on_toggle): a whole-row toggle, many rows open at once.
      • The 4 px primary rules, the open row framed in primary at 40 % with 32 px gutters, the tinted well, the surface card (radius 12, padding 24, shadow) with its X.
      • It grows over 300 ms with qdash's ease-in-out-quint (an animated max height, released at the end); closing is instant, as the web's is.
      • The page holds the open keys on stable ids, so a sort or a refresh keeps rows open. The web keys on the list index, so a new call closes every open row.
      • Not copied: the 200 ms empty strip before the growth, the bold cells, the X over the text, the dead light-mode cream.
      • Not yet: keyboard focus on the row.
      • Its own doc page, a scorecard row at fidelity 3, and two headless tests (open, close).
    • The listing:
      • The band: Tool type by kind, Invocations with its top three below the value, Success Rate with its outcome donut.
      • The ledger: kind pills, a ⇄ server chip that opens the server, outcome tags, harness types.
      • The quick filter: Type and MCP server, with values from the data.
      • A skill row goes to Skills.
    • The tool page:
      • Denied as the headline, red above zero, with its context line "of N invocations" (the web computes it and leaves it out).
      • All-time tiles: Invocations, Success Rate with its donut, Harness types.
      • Harnesses by type.
      • Recent invocations: decision tags, outcomes and durations, and the expand row on the arguments and output as captured.
    • Oddities settled:
      • A Success Rate with nothing judged reads "—" (the web's spins forever).
      • Denied keeps the warning amber in tags and donuts and the error red only as a headline alarm, as on the MCP page.
      • The header dot uses the shared recency.
    • Captures: eight (thread p2-tools). 28 tests pass.
    • Committed (fda7c25).
  • Skills, the skill page and the skill file: the plan's step 5.7, with step 3f (2026-11-10, Mark: "continue with whatever is next").
    • A spec first (spec-skills.md). The detail sends the period, unlike the other details, and the world holds it. Only SKILL.md has text: bundle files are an inventory, never their contents.
    • The skill file in the layer (layer::editor):
      • EditorFrame: the 240 px tray with its label, tree and caption beside the pane, which has one tab and the toolbar.
      • FileTree: folders from paths, files before folders, Lucide glyphs by extension (the kit carries the whole catalog), ⚙ executable, ○ bundled only, folders that close.
      • tab_group: the Preview / Source switch.
      • CodeBlock: a line-number gutter that stays put while the code scrolls sideways, and a marked line. Highlighting is a line tokenizer for the four grammars the web registers (Markdown with YAML front matter and fenced code, YAML, bash, JSON), mapped to the web's highlight.js token table.
      • markdown: the Preview, with headings two levels down, lists, quotes, rules, fenced code, inline code in mono, bold and links.
      • A doc page, five scorecard rows, and two tests (multibyte text, block parsing).
    • The listing:
      • In configs, against this machine's harness installs.
      • Invocations: the honest zero.
      • Skills by harness with Drift beside it, a segmented switch in the card's title where the web has a select. The fleet's Team and People views leave.
    • The skill page:
      • The header: In configs, and Definitions in amber when the copies disagree.
      • Two tiles.
      • Definitions: the segment bar and the delta in words. A pick scrolls to the editor.
      • The editor: Preview decodes the front matter into pills (invocation, invoke as, tools, scope); Source rebuilds the file from its entries and body under the real sha256.
      • The inventory card for bundle files, whose "show in source →" marks the line.
      • Installs: one row per harness install, with its definition.
      • The candidate Sessions, and the honest runtime box.
    • Oddities settled:
      • The Installs ledger sorts by sessions.
      • The scope pill names the picked definition's harnesses.
      • The fold appears whenever it cuts.
      • The prose marks show: tinted, since GPUI text runs carry no outline. The web's outlines don't render either: its CSS feeds RGB triplets as colours.
      • The gutter stays faint in dark.
    • Found and fixed: the inline scanners sliced inside a multibyte "—". Every scanner now steps on character boundaries, with a test.
    • Open, for Mark:
      • A local app could show the real SKILL.md bytes and even the bundle's contents. The product rule today is "contents not captured: scripts can hold secrets", so it is kept.
      • The runtime pair (Harnesses, Recent invocations) is not built: no harness emits skill calls, and the world has none.
    • Captures: nine (thread p2-skills). 30 tests pass.
    • Committed (b25979d).
  • Repos & Workspaces and the workspace page: the plan's step 5.8, the last listing (2026-11-10, Mark: "continue with whatever is next").
    • A spec first (spec-workspaces.md). The detail is all-time, as the web asks (/api/workspaces?workspace=), and says so.
    • The listing:
      • The working directories of this machine's sessions: kind, workspace (name over path), harness types, tokens, spend, last active.
      • The band: Workspaces with its freshness bar, and the tokens and spend top three.
      • The column picker alone in the listing bar. One machine has no teams to filter by, so DataListingBar now draws its filter group only when there are keys.
    • The workspace page:
      • The header: the path, the harness types that work there, and the Git pair, which shows what is served and says "not captured yet" only when nothing is.
      • Tiles: Harness types, Tokens and Spend, all-time.
      • Sessions: harness logo, command, model, exit code in colour, started, duration.
      • Surface: Models, MCP servers, Tools, the skills on the harnesses that work here (joined through this machine's installs), and Harnesses by type.
    • Fleet → personal: the teams column and filter, shared, the Users and Hosts pairs, the Users ledger and the Users and Teams panels leave. Instances read as harness types.
    • Oddities settled:
      • One clock: freshness is measured against the newest session in the data. The web mixes the browser's clock with the data's window and reads "0 active".
      • A folder name shared by two clones is told apart by its parent directory, in the bars and the table.
      • The freshness bar uses the default slots, not the ordinal purples.
      • The Sessions ledger carries the harness logo and the exit code like its siblings. The header dot uses the shared recency.
    • Open, for Mark:
      • Git is not captured. On one machine git -C <cwd> is cheap, and the four places that project git (the provenance count, the kind column, the header pair, the subtitle) would change together. git_text already reads a served value.
      • The last-active cell keeps the app's wall-clock "ago", as every page does, so the frozen synthetic world reads 132 d while the bar counts it active.
    • Captures: six (thread p2-workspaces). 30 tests pass.
    • The section is complete: all seven Inventory listings and their detail pages are native.
    • Committed (044bc32).
  • Review stop 3: the section, the scorecard, the budget: the plan's step 6 (2026-11-10). Written up in review-3.md.
    • The scorecard: 36 rows.
      • 30 drawn with GPUI primitives: 28 at fidelity 3, 2 at fidelity 2 (DataRankedBars' stacked labels, Skill Markdown's outlines).
      • 2 kit as is: Lucide and the segmented tabs.
      • None composed from the kit.
      • 3 not built yet: no page needed them.
      • 1 translated away.
      • The kit carried the shell. Our vocabulary was drawn: about 5,400 lines of components and 2,250 of doc pages.
    • The budget: c1 and c2 release builds, one session, c1's recipe.
      • Binary: 17.9 → 23.2 MB, of which ~1.1 MB is assets.
      • Window idle: 51 → 62 MB private. Tray: 15 → 21 MB.
      • CPU, wakes and startup are unchanged (262 → 254 ms).
      • After every page has been shown once: 116 MB, 46 MB of the growth on the GPU. It levels off over four walks, so it is not a leak.
    • New spike hooks: QPOINT_SPIKE_WALK_AFTER and QPOINT_SPIKE_WALKS.
    • Open, for Mark:
      • the brand ruling (c130 D5, c131 R8);
      • the one-world side-by-side, which restarts the shared :7882 seed;
      • what remains of the extra stretch's full list;
      • five per-page calls;
      • the atlases on close to tray.
  • Stretch: the Tour guide (2026-11-11, Mark: "Start the Tour"). Written up in review-tour.md; 22 captures, thread p2-tour.
    • A spec first (spec-tour.md, measured on the lab at design :3000, 1120 × 720, light and dark). It covers the v5 panel, the four focus modes, the callout and its placement, the glide, open-page's way, the colours, the Inventory part of the app map with the concepts, and 18 oddities to decide.
    • The engine (crates/layer/src/tour.rs):
      • .qp_id(..) with .key(..) and .text(..), a wrapper that adds no layout node and records the child's box in prepaint;
      • the overlay as the last deferred draw, which commits the frame and paints from it;
      • the ring as quads; Dim as an even-odd path with rounded holes; Fade as the same path in the page's background;
      • the callout (TourMarker, lg and sm, measured by the text system) and place() with the obstacle score;
      • the glide, on the scroller each region was drawn inside;
      • a row probe for the kit's sidebar items.
    • Pages name their regions:
      • bands key their cards, and tables key their rows (DataMachineGroup::qp, DataTable::qp, DataIndexSection::qp);
      • detail frames name the header, the pills and each section after its pill;
      • 17 detail tables are named.
    • The runtime (crates/app/src/tour/):
      • tours as serde data, mirroring c123's type;
      • facts worked out from the repositories, which texts, keys and routes name;
      • the v5 panel, docked or floating, minimized to the circle, with the driver pill;
      • follow the page.
    • The native tour, "What's on this machine": 7 stops and 9 steps over the Inventory, including one detail page reached through a fact and three spots.
    • The guide (crates/app/src/guide/):
      • the MCP endpoint in process: tiny_http on loopback, JSON-RPC, sessions, Origin checked, the 16 tools and the web's instructions translated;
      • the app map in JSON (16 pages, 108 regions, 13 concepts) with the web's search ported, its rows coming from the data;
      • Info View in the footer, native first.
    • Checked:
      • scripts/guide-check.py, 117 of 117: every page's regions, every step's targets;
      • a curl walk (mcp.sh): start mid-tour on a fact route, next, end, open-page with the way (1.8 s; the web measured 1.75), point, read-page;
      • 17 unit tests (route paths, facts, the map's search, the glide goal, placement).
    • Not checked: a real harness walking it from one prompt. claude -p failed on the CLI's expired login.
    • Budget: the release binary is 23.2 → 24.2 MB. Interleaved with the review-stop-3 build, the window at idle is unchanged: 63.0 against 62.9 MB, 0.007 % against 0.006 % of a core. A tour open costs nothing at idle.
    • Decided rather than copied:
      • callouts keep off the sidebar;
      • the guide's pointer gets a safe area;
      • Dim darkens in dark;
      • stops are looked up by number;
      • the first route the window shows isn't a move.
    • Open, for Mark:
      • a launcher on the pages;
      • the 488 px page beside the dock (grow the window by 420, or fix the bands' overflow);
      • the one-prompt harness run;
      • the endpoint on by default;
      • keyboard.
    • Waiting at this stop (design c131 D15–D17's hand-on): the worlds recut and renamed (nina-mbp the default laptop, priya's the pilot world) and the settings switch.
  • Hand-on from design: Mark's synthetic-data rulings (2026-11-11; design c131 D15–D17, c132 D6; design commits 37db577c7c, 4a3b885c0c, 5e28e844a5). It arrived as a file (handon-2026-11-11.md) because the cross-session message was held. It is folded in here and the file removed. The record is design's cycles/c131.native-app-v1/synthetic-data.md §Rulings. To act on them, in order:
    1. The default world is a quiet laptop (D15).
      • Recut meridian-day90 to nina-mbp: Frontend; claude-cli, cursor-cli and claude-desktop since day 36; no personal account, no shadow install, nothing in the arc.
      • Keep priya-x1's day-90 cut as its own bundled world, pilot: the violation tour switches to it.
      • scripts/cut-world.py --host nina-mbp --name meridian-day90 and --host priya-x1 --name pilot; BUNDLED grows to four.
      • The spike walk's ids, and the stories and captures that name priya's rows, move to pilot or to nina's rows.
    2. The world is chosen in the app's settings (D16).
      • Shown only while the source is synthetic; --world and QPOINT_WORLD stay for captures.
      • Built as one re-open path that Connect reuses (c131 D13). The RepoHandle global is replaced with a new Repo over the other world, and a generation counter is bumped.
      • Pages observe the global and load again; the footer, the tray and the tour's facts re-read.
      • A read from the old generation is dropped in load's setter.
      • Per-world UI state is reset for synthetic worlds and kept per source for local and plane.
      • The bundled worlds are parsed together into one OnceLock map.
      • No GPUI re-initialisation.
    3. The violation tour, the first native tour, comes with design c137.
      • Switch to pilot; simulate a bad event; watch the notices fire locally and tune what gets through.
      • The simulate step is the drill action (the tour's data keeps its place): the person presses it, and it injects an arc event into this machine's stream. The events are the paste scare (day 38), the secret-file read (day 88) or the incident (day 61); one tour or three.
      • The notices are c137's (rule R4's words: notice, attention, required) and its controls. The tour waits on c137 Phase 3; c0 names it.
    4. The six endpoint-only shapes become qdash routes (D17): typed in qdash's TypeScript and generated like the other 38, never hand-written in types. Until then, Status waits for them or uses a bridge marked as such.
    5. The lab reads the same worlds (c132 D6): keep the world file's shape ({ manifest, responses }, keys route?sorted-query) stable, or tell design when it moves.
  • Mark's rulings on both review stops, built (2026-11-11; design c131 plan.md D18–D20, relayed by design's c130 program session). Both stops are cleared. The work ran on branch c2/rulings in a worktree (../qnative-c2), because c3 Developer Mode had the shell in flight in ../qnative. It was rebased onto c3's 2f66b4b and builds on its extension seam, its settings file and its lean build. 13 captures, thread p2-rulings.
    • D18, the brand: amended to "our layer drawn on GPUI with our tokens; the kit keeps the shell". The scorecard is ratified as built.
    • D19, review stop 3.
      • No seed restart: the measured specs stand.
      • The five per-page calls are accepted as proposed. They're for the local source; nothing to build on synthetic data.
      • The extra stretch's four items, done:
        • A sticky header. StickyGrid paints the body first and the header after it, shifted down to the pin line. The pin line is the top of the scroller the table is drawn in (from the tour registry's stack, since a section may clip its rows), plus the band: 94 with the pills docked, 48 with the title alone, 0 on listings. Nested and quiet tables don't pin.
        • Keyboard and AccessKit. A click puts the cursor on a row and focuses the table. ↑ ↓ Home End move, keeping the row in view; ⏎ and Space open or follow; Esc closes the open row or lets go. Roles: table, row (index, selected, expanded), column header, cell, the X as a button. Two GPUI tests cover it.
        • Content-sized columns. A fixed column grows to its widest cell or label, measured at natural width a frame late, as HTML's auto layout does. The declared width is the floor, the cap twice it or 320.
        • The well and the rows. The well eases to its measured height over 300 ms and eases again whenever that changes, as when nested rows open. The quiet look (Findings): no purple rules, surface, stroke frames. The new-row flash: #FFFEF1 (primary at 5 % in dark) for a second, only for rows born after the first render.
      • The atlases. Measured first, as ruled. GPUI already frees a window's GPU memory with it: IOSurface 26 → 0 MB, IOAccelerator 20 → 2.4 MB. app::memory now lets go of the rest when the last window closes: the recoloured logos, the tour registry, the facts, and the allocator's free pages (malloc_zone_pressure_relief). The tray after a walk and a close went 57 → 48 MB, after a plain close 48 → 43; a tray-only start is 22. What's left is 13 MB of GPU memory the driver still owns but doesn't map, 2.4 MB IOAccelerator and 4–8 MB of heap.
    • D20, the Tour stretch.
      • The panel floats, locked to the window's right edge, never docked. It's 420 wide, full height, over the page, with the dock's side shadows. The page keeps its width, so widening the window reveals what the panel covers. When a step's highlight is mostly under it, the panel says to widen the window.
      • Keys while the panel has focus (given on start and on a click): ← and → move the tour, Esc closes it, and the mouse still works.
      • The endpoint is on by default, with a per-launch token. Every request presents Authorization: Bearer; anything else gets 401 with where to find the token. QPOINT_GUIDE_TOKEN fixes it for scripts. 117 of 117 checks pass with it.
      • Getting started (Help) is a sidebar group with the tours' launcher, the line that connects Claude Code with this launch's token (and Copy), and Info View. The map has the page and three more concepts: Tour, Guide, Info View.
      • The real-harness run is this session's, once Mark refreshes the CLI login.
    • The D15–D17 hand-on, done in this work:
      • D15: meridian-day90 is recut to nina-mbp (119 responses, 324 KB, from 2,280 runs and 37 scan events). priya-x1's cut is bundled as pilot (134 responses, 607 KB). Worlds are parsed per name on first use. Stories, the spike walk and the tests follow.
      • D16: the world is chosen in the tray's "Synthetic world" submenu (shown only while the source is synthetic), remembered in c3's settings.json beside the extensions, and honoured at start unless --world or QPOINT_WORLD says otherwise. Switching goes through router::show_world → router::reopen: the repositories are swapped and a generation moves on. The shell rebuilds the page, so its read runs again and a read in flight lands on a page that's gone; the footer and the tour's facts follow. GPUI is not re-initialised, and Connect can take the same path. QPOINT_SPIKE_WORLD=<s>:<name> drives it without a pointer.
      • Waiting: D17 (the six shapes as qdash routes) with qcontrol engineering; the violation tour with c137.
  • The real-harness run (2026-11-11, evening; Mark refreshed the CLI login). Written up in harness-run.md.
    • Claude Code 2.1.322 (Sonnet 5.5, headless) connected to the app's guide with this launch's token, through --mcp-config so nothing persisted in the user's config.
    • One prompt: "Give me the quick tour of what's on this machine, then show me which model costs the most and where I'd see that."
    • It ran tour-state, list-tours, find-in-app, start-tour, read-step, open-page (Models, by way of the sidebar) and point twice, read the region's text, and answered from the live rows. Ten turns, 18 s, $0.13, no tool errors; nothing pressed.
    • The window afterwards: on Models, Claude Code's callout on the model list, the last move recorded as the agent's.

Outcome

c2 asked how far GPUI Kit stretches toward the way design builds a page. Answer: as far as our own layer, drawn on GPUI. The kit carries the shell; our vocabulary is ours.

  • The section.
    • The whole Inventory section is native, on the web's data cut to one machine: the overview's 20 micros, seven listings, and their detail pages with the provider's account page.
    • Each page was built to a spec measured on qdash at 1120 × 720, fleet translated to personal by six rules, and each web oddity decided rather than copied. The specs are in specs/: ten files, committed by c8 on 2026-11-12 after design c140 found them only in a session scratchpad.
    • Around it: the Qpoint skin (the generated theme, Inter's static faces), a Dev section with native component docs, the stories crate for off-screen captures, generated types under a strict drift test, and the three-source nozzle.
  • The scorecard (review-3.md).
    • 36 components: 30 drawn on GPUI primitives (28 indistinguishable from the web at a glance), 2 from the kit as is, none composed from the kit's components.
    • Mark's D18 ratified it as built and amended the brand ruling (c130 D5, c131 R8): our layer drawn on GPUI with our tokens; the kit keeps the shell.
  • The budget.
    • The release binary grew 17.9 → 24.2 MB over the phase.
    • Idle CPU, wakes and startup (~260 ms) are unchanged from the spike.
    • At rest a window is ~62 MB. Measured beside review stop 3's build, the Tour stretch added nothing at idle (63.0 against 62.9 MB).
    • Every page shown once reaches 116 MB. That is GPUI's atlases, which level off and go with the window.
    • The tray after a window is closed is 48 MB (22 for a tray-only start). The rest is driver-held GPU memory and some heap, now that the app lets go of its own caches (D19).
  • The extra stretch (D19, done in full): the table expand row at fidelity 3, then the sticky header, keyboard and AccessKit roles, content-sized columns, the well's height eased and re-tracked, the quiet nested look and the new-row flash.
  • The Tour stretch (review-tour.md, harness-run.md).
    • The lab's tour layer is native: .qp_id targets recorded in prepaint, and the dim, ring and fade painted from the same frame. Callouts are placed by the web's obstacle score, and the glide is the web's.
    • Tours are serde data. The native tour "What's on this machine" has 7 stops and 9 steps, with live facts.
    • Info View is built here first.
    • The qpoint-guide MCP is served from inside the app on loopback, with a per-launch token, the same 16 tools and the web's search. guide-check.py passes 117 of 117, and Claude Code walked it from one prompt.
    • After D20: the panel floats at the window's right edge, takes ← → Esc, and the tours start from Getting started.
  • The worlds (D15–D16): the default is nina-mbp's quiet laptop, with priya-x1's cut beside it as pilot. The world is chosen in the tray and swapped in place over one reopen path that Connect can reuse.
  • Captures: 122 in design's qnative atlas, across 13 threads.

Hand-ons out of c2:

  • D17, the six endpoint-only shapes as qdash routes, typed and generated like the other 38: engineering's, through design c134 (the plane engineer took the asks in principle, details later).
  • The violation tour (switch to pilot, a drill on the synthetic source, c137's local notices and controls): with qnative c4, the messaging slice (design c137 Phase 3), started in this tree. It runs on this engine; the drill action's place is kept in tour/data.rs.
  • The Status page: from design's c132 session as its Phase 4 worked example (A in the lab first, then the story and the page here).
  • qnative c3, Developer Mode (design c138), is already in the tree; it and c2 shared the shell through small commits and messages.
  • Shared files (router.rs, the shell's navigation, main.rs, Cargo.toml): small commits, pull before editing, and a message to the other session when they change.

Visual record

122 captures — heroes, page slices, and full-page renders. Click to view.

Every story per world (design c132 Phase 3, the native capture mode)

2026-11-11· 18 captureslatest
fresh (day 0, nothing found yet): twenty micros at zero, the overview's honest empty state in the real app.
fresh (day 0, nothing found yet): twenty micros at zero, the overview's honest empty state in the real app.
minimal (chen-mba): one monitored harness and a shadow Windsurf install, a handful of sessions, one provider.
minimal (chen-mba): one monitored harness and a shadow Windsurf install, a handful of sessions, one provider.
meridian-day90 (nina-mbp, the default since c2's recut): the twenty micros on nina's rows.
meridian-day90 (nina-mbp, the default since c2's recut): the twenty micros on nina's rows.
pilot (priya-x1): the twenty micros as c2 first captured them under the name meridian-day90.
pilot (priya-x1): the twenty micros as c2 first captured them under the name meridian-day90.
fresh: no harnesses found on this machine; the band at zero, the ledger's empty state.
fresh: no harnesses found on this machine; the band at zero, the ledger's empty state.
minimal: Claude Code monitored with two sessions, Windsurf a shadow install that never ran under qcontrol.
minimal: Claude Code monitored with two sessions, Windsurf a shadow install that never ran under qcontrol.
meridian-day90 (nina-mbp): three harnesses, all monitored; the ledger with version, status, providers, sessions, spend, last active.
meridian-day90 (nina-mbp): three harnesses, all monitored; the ledger with version, status, providers, sessions, spend, last active.
pilot (priya-x1): four harnesses, three monitored, Ollama a shadow.
pilot (priya-x1): four harnesses, three monitored, Ollama a shadow.
fresh: the page's not-found state, claude-cli is not on this machine.
fresh: the page's not-found state, claude-cli is not on this machine.
minimal: Claude Code on chen-mba, monitored, two sessions all time; one provider, tokens by model, the spend.
minimal: Claude Code on chen-mba, monitored, two sessions all time; one provider, tokens by model, the spend.
meridian-day90 (nina-mbp): Claude Code, Status monitored, the metadata grid, the three tiles, the jump pills.
meridian-day90 (nina-mbp): Claude Code, Status monitored, the metadata grid, the three tiles, the jump pills.
pilot (priya-x1): Claude Code, Status monitored, the metadata grid, the three tiles, the jump pills.
pilot (priya-x1): Claude Code, Status monitored, the metadata grid, the three tiles, the jump pills.
minimal, landed on Sessions: the two sessions on chen-mba.
minimal, landed on Sessions: the two sessions on chen-mba.
meridian-day90 (nina-mbp), landed on Sessions: the band docked, 14 sessions, ten then Show all.
meridian-day90 (nina-mbp), landed on Sessions: the band docked, 14 sessions, ten then Show all.
pilot (priya-x1), landed on Sessions: the band docked, 40 sessions, ten then Show all.
pilot (priya-x1), landed on Sessions: the band docked, 40 sessions, ten then Show all.
minimal, landed on Surface: what Claude Code reaches from chen-mba.
minimal, landed on Surface: what Claude Code reaches from chen-mba.
meridian-day90 (nina-mbp), landed on Surface: Models, MCP Servers, Repos & Workspaces, Tools.
meridian-day90 (nina-mbp), landed on Surface: Models, MCP Servers, Repos & Workspaces, Tools.
pilot (priya-x1), landed on Surface: Models, MCP Servers, Repos & Workspaces, Tools.
pilot (priya-x1), landed on Surface: Models, MCP Servers, Repos & Workspaces, Tools.

Phase 2 · Mark's rulings D18–D20 built: the table at full fidelity, the tour panel at the edge, Help, the token, the quiet default world

2026-11-11· 13 captures
Nested and quiet (Findings): an outer group opens on its own rows, drawn quiet (no purple rules, surface, stroke frames); a row opened inside, and the outer well eased to its new measured height.
Nested and quiet (Findings): an outer group opens on its own rows, drawn quiet (no purple rules, surface, stroke frames); a row opened inside, and the outer well eased to its new measured height.
The same in dark.
The same in dark.
The sticky header: a long ledger scrolled under its pinned header. CSS sticky by hand: the body painted first, the header after it, shifted to the pin line, its clicks moving with it.
The sticky header: a long ledger scrolled under its pinned header. CSS sticky by hand: the body painted first, the header after it, shifted to the pin line, its clicks moving with it.
A row added after the first render flashes #FFFEF1 for a second; the tool column, declared 120, grows to its longest name and the kind column to its own, as HTML's auto table layout does.
A row added after the first render flashes #FFFEF1 for a second; the tool column, declared 120, grows to its longest name and the kind column to its own, as HTML's auto table layout does.
Claude Code's sessions scrolled past their header: it pins under the band (94 with the pills docked), taken from the scroller the table is drawn in, not the section's clip.
Claude Code's sessions scrolled past their header: it pins under the band (94 with the pills docked), taken from the scroller the table is drawn in, not the section's clip.
D20: the panel floats at the window's right edge, never docked; the page keeps its full width under it, so the band has room.
D20: the panel floats at the window's right edge, never docked; the page keeps its full width under it, so the band has room.
When a step's highlight is mostly under the panel at this width, the panel says to widen the window (resizing reveals what it covers).
When a step's highlight is mostly under the panel at this width, the panel says to widen the window (resizing reveals what it covers).
A spot picked with the panel at the edge, on nina's Claude Code.
A spot picked with the panel at the edge, on nina's Claude Code.
Getting started (D20): the tours' launcher, the line that connects Claude Code with this launch's token, and Info View.
Getting started (D20): the tours' launcher, the line that connects Claude Code with this launch's token, and Info View.
Getting started in dark.
Getting started in dark.
D15: the default world is nina-mbp's quiet laptop: claude-cli, cursor-cli and claude-desktop, all monitored, nothing in the arc.
D15: the default world is nina-mbp's quiet laptop: claude-cli, cursor-cli and claude-desktop, all monitored, nothing in the arc.
D16: the same window after the tray's Synthetic world › pilot: priya-x1's four harnesses with the ollama shadow, swapped in place over one reopen path; the footer follows.
D16: the same window after the tray's Synthetic world › pilot: priya-x1's four harnesses with the ollama shadow, swapped in place over one reopen path; the footer follows.
The overview on nina's laptop, with Help › Getting started in the sidebar.
The overview on nina's laptop, with Help › Getting started in the sidebar.

Phase 2 · Stretch: the Tour guide, Info View and the MCP guide, native

2026-11-11· 22 captures
What's on this machine, the native tour, opening on the Inventory overview: the v5 panel docked (Split · Dim), the stop bar at 1 of 7, the live counts worked out from the same repositories the pages read. The opening rings nothing; one callout on the first card.
What's on this machine, the native tour, opening on the Inventory overview: the v5 panel docked (Split · Dim), the stop bar at 1 of 7, the live counts worked out from the same repositories the pages read. The opening rings nothing; one callout on the first card.
The same step in dark: the panel black, the accent #0099FF.
The same step in dark: the panel black, the accent #0099FF.
Providers: the Dim cuts one hole, around the Providers card (the region recorded by .qp_id in prepaint, an even-odd path with 10 px corners), and the callout sits beside it, placed by the obstacle score.
Providers: the Dim cuts one hole, around the Providers card (the region recorded by .qp_id in prepaint, an even-odd path with 10 px corners), and the callout sits beside it, placed by the obstacle score.
Dark: the scrim is black at 0.55, so Dim darkens the page (the lab's #73858F tint lightens a dark one).
Dark: the scrim is black at 0.55, so Dim darkens the page (the lab's #73858F tint lightens a dark one).
Harnesses: the ledger ringed, glided into view under the band, and the busiest harness's row called out by its key.
Harnesses: the ledger ringed, glided into view under the band, and the busiest harness's row called out by its key.
A step whose route names a fact: the busiest harness's own page, opened once the facts were in. Three spots in the panel.
A step whose route names a fact: the busiest harness's own page, opened once the facts were in. Three spots in the panel.
A spot picked: the highlight moves to Configured here, brought into view under the pinned band through the scroller it was drawn inside.
A spot picked: the highlight moves to Configured here, brought into view under the pinned band through the scroller it was drawn inside.
Models: the Spend card ringed, the top model's share of the spend called out.
Models: the Spend card ringed, the top model's share of the spend called out.
MCP servers: the ledger, and the most-called server's row.
MCP servers: the ledger, and the most-called server's row.
Tools: Invocations ringed; the callout on Success rate. Next reads "Next: Skills", the next step's short name within the stop.
Tools: Invocations ringed; the callout on Success rate. Next reads "Next: Skills", the next step's short name within the stop.
Skills: the ledger, and the honest zero (no harness reports skill use at runtime yet).
Skills: the ledger, and the honest zero (no harness reports skill use at runtime yet).
The last step: Workspaces, 7 of 7, End tour.
The last step: Workspaces, 7 of 7, End tour.
Float: the panel over the page (400 wide, radius 14), on the side the web's rule picks, above the scrim; the callout keeps 16 px clear of it.
Float: the panel over the page (400 wide, radius 14), on the side the web's rule picks, above the scrim; the callout keeps 16 px clear of it.
Ring: 2 px of accent with the 6 px glow at 0.3, radius 10, 12 px of room.
Ring: 2 px of accent with the 6 px glow at 0.3, radius 10, 12 px of room.
Ring + Dim: the scrim and the full ring.
Ring + Dim: the scrim and the full ring.
Fade: the same even-odd path in the page's own background at 0.72, which is what opacity 0.28 over that background looks like, with no restyling of the page; the quiet ring.
Fade: the same even-odd path in the page's own background at 0.72, which is what opacity 0.28 over that background looks like, with no restyling of the page; the quiet ring.
Minimized: the dock released, the 48 px circle at the bottom right with the lab's placeholder route mark, drawn as paths.
Minimized: the dock released, the 48 px circle at the bottom right with the lab's placeholder route mark, drawn as paths.
The guide with no tour: an agent's point on the github row (a ring, a small callout with a title and one sentence), and the "Driven by" pill.
The guide with no tour: an agent's point on the github row (a ring, a small callout with a title and one sentence), and the "Driven by" pill.
The point in dark.
The point in dark.
open-page shows the way first: the sidebar item ringed with its path, for 1.6 s, then the page opens. The kit's sidebar item can't be wrapped, so a zero-size probe in its suffix records the row.
open-page shows the way first: the sidebar item ringed with its path, for 1.6 s, then the page opens. The kit's sidebar item can't be wrapped, so a zero-size probe in its suffix records the row.
Info View, native first: the pane over the footer says what the region under the pointer is, from the app map the guide reads; the region takes a quiet ring.
Info View, native first: the pane over the footer says what the region under the pointer is, from the app map the guide reads; the region takes a quiet ring.
Info View on a row: the row's line comes from the data (the map's rows are this machine's records, not a fixture).
Info View on a row: the row's line comes from the data (the map's rows are this machine's records, not a fixture).

Phase 2 · Inventory: Repos & Workspaces and the workspace page

2026-11-10· 6 captures
Repos & Workspaces on one machine: the working directories of this machine's sessions (priya-x1 works in one); freshness against the newest session in the data, one clock; the column picker alone, since one machine has no teams to filter by.
Repos & Workspaces on one machine: the working directories of this machine's sessions (priya-x1 works in one); freshness against the newest session in the data, one clock; the column picker alone, since one machine has no teams to filter by.
The same listing in dark.
The same listing in dark.
payments-migration: the path, the harness types that work there, the Git pair honest about what is captured; all-time tiles Harness types, Tokens, Spend.
payments-migration: the path, the harness types that work there, the Git pair honest about what is captured; all-time tiles Harness types, Tokens, Spend.
The workspace in dark.
The workspace in dark.
Sessions launched from the directory: harness, command, model, exit code, started, duration.
Sessions launched from the directory: harness, command, model, exit code, started, duration.
What runs here: models, MCP servers, tools, the skills on the harnesses working here (joined through this machine's installs), and the harnesses by type.
What runs here: models, MCP servers, tools, the skills on the harnesses working here (joined through this machine's installs), and the harnesses by type.

Phase 2 · Inventory: Skills, the skill page and the skill file

2026-11-10· 9 captures
Skills on one machine: In configs (the register, against this machine's harness installs), Invocations (a real zero: no harness emits skill calls yet), Skills by harness with Drift beside it; the ledger with harness logos and the source.
Skills on one machine: In configs (the register, against this machine's harness installs), Invocations (a real zero: no harness emits skill calls yet), Skills by harness with Drift beside it; the ledger with harness logos and the source.
The same listing in dark.
The same listing in dark.
deploy: registered in two harness configs here, and its two copies disagree (Definitions in amber, 1 of 2 installs drifted); all the tiles say a real zero where it is one.
deploy: registered in two harness configs here, and its two copies disagree (Definitions in amber, 1 of 2 installs drifted); all the tiles say a real zero where it is one.
Definitions: the copies by SKILL.md hash, canonical and drift, the delta in words; picking one opens it in the editor and scrolls there.
Definitions: the copies by SKILL.md hash, canonical and drift, the delta in words; picking one opens it in the editor and scrolls there.
The skill file: the tree (SKILL.md and its scripts, ⚙ executable, ○ bundled only), one tab, Preview with the front matter decoded into pills and the body as the model reads it.
The skill file: the tree (SKILL.md and its scripts, ⚙ executable, ○ bundled only), one tab, Preview with the front matter decoded into pills and the body as the model reads it.
The skill file in dark.
The skill file in dark.
Installs, one row per harness install with the definition it holds (drift in amber, a click reads it), then the candidate Sessions and the honest runtime box.
Installs, one row per harness install with the definition it holds (drift in amber, a click reads it), then the candidate Sessions and the honest runtime box.
EditorFrame, FileTree, CodeBlock documented: Source highlighted by the web's token table with line 12 marked (show in source), bash, JSON.
EditorFrame, FileTree, CodeBlock documented: Source highlighted by the web's token table with line 12 marked (show in source), bash, JSON.
The editor components in dark.
The editor components in dark.

Phase 2 · Inventory: Tools, the tool page and the expand row

2026-11-10· 8 captures
Tools on one machine: Tool type by kind, Invocations with its top three below the value, Success Rate with its outcome donut (— when nothing is judged; the web spins forever); the ledger with kind pills, a ⇄ server chip that opens the server, outcome tags; it scrolls sideways a little, as the web's does at this width.
Tools on one machine: Tool type by kind, Invocations with its top three below the value, Success Rate with its outcome donut (— when nothing is judged; the web spins forever); the ledger with kind pills, a ⇄ server chip that opens the server, outcome tags; it scrolls sideways a little, as the web's does at this width.
The same listing in dark.
The same listing in dark.
Write: Denied as the headline, red above zero, with its context line (the web computes it and leaves it out); all-time tiles Invocations, Success Rate with its donut, Harness types.
Write: Denied as the headline, red above zero, with its context line (the web computes it and leaves it out); all-time tiles Invocations, Success Rate with its donut, Harness types.
The tool in dark.
The tool in dark.
Landed on Recent invocations: when, harness, session, decision and its source, outcome, duration; each row opens on its arguments and output (the expand row).
Landed on Recent invocations: when, harness, session, decision and its source, outcome, duration; each row opens on its arguments and output (the expand row).
query via ⇄ postgres-readonly: an MCP tool, the server a chip that opens its page.
query via ⇄ postgres-readonly: an MCP tool, the server a chip that opens its page.
The expand row, documented: a whole-row toggle, the 4 px primary rules, the framed open row, the tinted well, the surface card with its X; it grows over 300 ms with qdash's ease-in-out-quint; many open at once, held by the page on stable keys.
The expand row, documented: a whole-row toggle, the 4 px primary rules, the framed open row, the tinted well, the surface card with its X; it grows over 300 ms with qdash's ease-in-out-quint; many open at once, held by the page on stable keys.
The expand row in dark.
The expand row in dark.

Phase 2 · Inventory: MCP Servers and the server page

2026-11-10· 6 captures
MCP Servers on one machine: servers seen on the wire merged with those in this machine's harness configs, each typed observed, configured or both. The band's ranked bars sit below their value, where they have room; the Source filter offers the values present (the web's can never pick both).
MCP Servers on one machine: servers seen on the wire merged with those in this machine's harness configs, each typed observed, configured or both. The band's ranked bars sit below their value, where they have room; the Source filter offers the values present (the web's can never pick both).
The same listing in dark.
The same listing in dark.
github: the Source cell (both, and what that means), the harnesses here whose config registers it, all-time tiles Tool Calls, Denied (red above zero), Tools Used, In configs.
github: the Source cell (both, and what that means), the harnesses here whose config registers it, all-time tiles Tool Calls, Denied (red above zero), Tools Used, In configs.
The server in dark.
The server in dark.
Landed on Configuration: how each harness registers the server (transport, URL or command, the env and header key names; values are never collected), which the web computes and no longer shows; then the harnesses that call it, by type.
Landed on Configuration: how each harness registers the server (transport, URL or command, the env and header key names; values are never collected), which the web computes and no longer shows; then the harnesses that call it, by type.
sentry, observed only: in no config here, and the gap line says what one person can act on: 3 harnesses call it without config.
sentry, observed only: in no config here, and the gap line says what one person can act on: 3 harnesses call it without config.

Phase 2 · Inventory: Models and the model page

2026-11-10· 5 captures
Models on one machine: the band (Models with its top three by tokens and Other, Tokens excluding cache, Spend with its top three) and the ledger; the provider is a ◈ chip that opens its page, the instances column reads harness types, the users column is gone.
Models on one machine: the band (Models with its top three by tokens and Other, Tokens excluding cache, Spend with its top three) and the ledger; the provider is a ◈ chip that opens its page, the instances column reads harness types, the users column is gone.
The same listing in dark.
The same listing in dark.
claude-sonnet-4-6, all time (as the web asks, and here said so): the header with Spend, the metadata with Default here (the installs on this machine whose config defaults to the model, served and unused on the web), tiles API requests, Tokens, Spend.
claude-sonnet-4-6, all time (as the web asks, and here said so): the header with Spend, the metadata with Default here (the installs on this machine whose config defaults to the model, served and unused on the web), tiles API requests, Tokens, Spend.
The model in dark.
The model in dark.
Landed on Harnesses: the instances rolled up by harness type (qdash modelHarnessRows), this model's share of each; no jump pills, as on the web, but the title still pins.
Landed on Harnesses: the instances rolled up by harness type (qdash modelHarnessRows), this model's share of each; no jump pills, as on the web, but the title still pins.

Phase 2 · Inventory: Providers, the provider page and the account page

2026-11-10· 7 captures
Providers on one machine: the band (Providers with its concentration, Tokens excluding cache, Spend with its top three) and the ledger without the users column. Like qdash's at this width, the ledger keeps its declared widths and scrolls sideways.
Providers on one machine: the band (Providers with its concentration, Tokens excluding cache, Spend with its top three) and the ledger without the users column. Like qdash's at this width, the ledger keeps its declared widths and scrolls sideways.
The same listing in dark.
The same listing in dark.
Anthropic: the header with its Spend cell and metadata (the metadata wraps under it, as qdash's does at 1120); tiles API requests, Tokens, Spend, Accounts (org-scoped, unscoped, auth).
Anthropic: the header with its Spend cell and metadata (the metadata wraps under it, as qdash's does at 1120); tiles API requests, Tokens, Spend, Accounts (org-scoped, unscoped, auth).
Landed on Accounts: each account typed company or personal, its auth method, the harness types that presented it; a row opens the account.
Landed on Accounts: each account typed company or personal, its auth method, the harness types that presented it; a row opens the account.
One account: what it is (company, oauth), the provider it belongs to, its metadata; tiles Harnesses, Sessions, Tokens (in the place of the fleet's Users), Spend. Attention appears for dual use, a personal plan, or runs with no identity.
One account: what it is (company, oauth), the provider it belongs to, its metadata; tiles Harnesses, Sessions, Tokens (in the place of the fleet's Users), Spend. Attention appears for dual use, a personal plan, or runs with no identity.
The account in dark.
The account in dark.
Landed on Sessions: every run that presented the account, newest first, ten then Show all.
Landed on Sessions: every run that presented the account, newest first, ten then Show all.

Phase 2 · Inventory: the overview, Harnesses and the harness page

2026-11-10· 9 captures
Inventory overview on one machine: twenty micros from the seven listings, four to a row on qdash's grey canvas, the shared period on the right. Personal titles where the fleet's would mislead (Harnesses here, Skills by harness).
Inventory overview on one machine: twenty micros from the seven listings, four to a row on qdash's grey canvas, the shared period on the right. Personal titles where the fleet's would mislead (Harnesses here, Skills by harness).
Harnesses: Installed here (each one monitored or shadow, its bar its share of this machine's sessions) and Work; the ledger without endpoints, with version and last active brought forward; Kind/Provider quick filter, column picker, sort.
Harnesses: Installed here (each one monitored or shadow, its bar its share of this machine's sessions) and Work; the ledger without endpoints, with version and last active brought forward; Kind/Provider quick filter, column picker, sort.
The same listing in dark.
The same listing in dark.
Claude Code, the merged harness page: the identity header with its Status (qdash's Coverage, said as monitored or shadow) and the metadata grid; tiles Providers, Tokens by model, Spend; the jump pills.
Claude Code, the merged harness page: the identity header with its Status (qdash's Coverage, said as monitored or shadow) and the metadata grid; tiles Providers, Tokens by model, Spend; the jump pills.
Landed on Sessions: the band docks with the crumb trail and compact pills, the pill follows the scroll; 40 sessions on this machine, sortable, ten then Show all.
Landed on Sessions: the band docks with the crumb trail and compact pills, the pill follows the scroll; 40 sessions on this machine, sortable, ten then Show all.
Configured here: the MCP servers and skills in this install's config.
Configured here: the MCP servers and skills in this install's config.
Surface: Models, MCP Servers, Repos & Workspaces, Tools as qdash draws them (framed panels, label columns as wide as their widest label, flat 15 % primary bars with Intl-compact counts). Users, Teams and Versions leave on one machine.
Surface: Models, MCP Servers, Repos & Workspaces, Tools as qdash draws them (framed panels, label columns as wide as their widest label, flat 15 % primary bars with Intl-compact counts). Users, Teams and Versions leave on one machine.
The Surface in dark.
The Surface in dark.
The Surface's doc page: the interactive section (columns 1/2/3, row cap 10/2), then Minimal, Empty, Overflow (a long caption, Tools capped at 3) and the hand-off (60 rows: Show more (50 of 60), then View all 60 →).
The Surface's doc page: the interactive section (columns 1/2/3, row cap 10/2), then Minimal, Empty, Overflow (a long caption, Tools capped at 3) and the hand-off (60 rows: Show more (50 of 60), then View all 60 →).

Phase 2 · step 3, the Data Machine family in Rust

2026-11-10· 7 captures
DataIndexSection in Rust: the Inventory section of qdash's Home, twelve micros auto-filling five columns, cards sharing a height with their bodies centred.
DataIndexSection in Rust: the Inventory section of qdash's Home, twelve micros auto-filling five columns, cards sharing a height with their bodies centred.
The same in dark, beside qdash's Home in dark: the card border, light ink bars, the dark categorical slots.
The same in dark, beside qdash's Home in dark: the card border, light ink bars, the dark categorical slots.
DataMachineGroup without subgrid: the band rendered track by track, each a flex row stretching to the tallest, so hairlines and bodies line up.
DataMachineGroup without subgrid: the band rendered track by track, each a flex row stretching to the tallest, so hairlines and bodies line up.
DataMachine: dim units, the delta and its triangle, a donut with its centre, segment legends, italic provenance, the spark; units in bytes, duration, ms, % and $.
DataMachine: dim units, the delta and its triangle, a donut with its centre, segment legends, italic provenance, the spark; units in bytes, duration, ms, % and $.
DataMachineMicro: every device form, the scenarios (an honest zero, device only, a delta, hot) and overflow.
DataMachineMicro: every device form, the scenarios (an honest zero, device only, a delta, hot) and overflow.
DataRankedBars in every layout; the inside value is two copies of the text, one clipped to the fill.
DataRankedBars in every layout; the inside value is two copies of the text, one clipped to the fill.
The scorecard: each web component the Inventory section uses, how its Rust counterpart was built, fidelity, and what HTML feature it lacked and what stood in.
The scorecard: each web component the Inventory section uses, how its Rust counterpart was built, fidelity, and what HTML feature it lacked and what stood in.

Phase 2 · the Dev section and the component docs

2026-11-10· 6 captures
Dev › Tools in the app: component demos on or off, the appearance (follow the system, light, dark), GPUI's element inspector, the data source. On in debug builds; --dev or QPOINT_DEV=1 in release.
Dev › Tools in the app: component demos on or off, the appearance (follow the system, light, dark), GPUI's element inspector, the data source. On in debug builds; --dev or QPOINT_DEV=1 in release.
Dev › Components: the component documentation, one page per component, grouped Skin and Kit; each page keeps its state while you move between them.
Dev › Components: the component documentation, one page per component, grouped Skin and Kit; each page keeps its state while you move between them.
The Button page: every variant, sizes, icons, disabled and loading, a long label in 160 px; every click lands in the page's event log.
The Button page: every variant, sizes, icons, disabled and loading, a long label in 160 px; every click lands in the page's event log.
Switch and Checkbox: on and off, disabled (read-only when connected), sizes, a long label; a checkbox group whose All follows the three.
Switch and Checkbox: on and off, disabled (read-only when connected), sizes, a long label; a checkbox group whose All follows the three.
Tabs: underline, segmented, pill, outline, each selecting; ten tabs in 360 px.
Tabs: underline, segmented, pill, outline, each selecting; ten tabs in 360 px.
Table: typical (sortable), minimal, empty with its honest state, overflow with long values in 480 px.
Table: typical (sortable), minimal, empty with its honest state, overflow with long values in 480 px.

Phase 2 · the Qpoint skin on the kit (review stop 1)

2026-11-10· 6 captures
The kit's own components in the Qpoint skin, light: grape for the one accent, leaf for success, Inter, white surfaces and hairline rules; the table reads priya-x1's harnesses through the real repositories.
The kit's own components in the Qpoint skin, light: grape for the one accent, leaf for success, Inter, white surfaces and hairline rules; the table reads priya-x1's harnesses through the real repositories.
The same gallery in Qpoint Dark, following the layer's light/dark pairs from semantic.mjs.
The same gallery in Qpoint Dark, following the layer's light/dark pairs from semantic.mjs.
Before: the same gallery on the kit's stock theme (shadcn neutral, the system font), for comparison.
Before: the same gallery on the kit's stock theme (shadcn neutral, the system font), for comparison.
Our 21 roles from tokens.rs, honest states (skeleton, empty), and the Inter scale in the bundled Inter 4.1 static faces: regular, medium, semibold and bold each resolve to their own face.
Our 21 roles from tokens.rs, honest states (skeleton, empty), and the Inter scale in the bundled Inter 4.1 static faces: regular, medium, semibold and bold each resolve to their own face.
The roles and the type scale in Qpoint Dark.
The roles and the type scale in Qpoint Dark.
Diagnostic that led to the fix: the bundled variable Inter drew every weight as regular (GPUI picks faces by family and weight, not a variable font's axis); rendered in static Inter faces, the scale had its weights. Inter 4.1's static faces are now bundled.
Diagnostic that led to the fix: the bundled variable Inter drew every weight as regular (GPUI picks faces by family and weight, not a variable font's axis); rendered in static Inter faces, the scale had its weights. Inter 4.1's static faces are now bundled.

Artifacts

/cycles/design/c131/doc/phase2-plan (local dev)/cycles/qnative/c2/doc/review-tour (local dev)/cycles/qnative/c2/doc/CYCLE (local dev)/pages/native/bake-off (local dev)

Qpoint Brand Style Guide