← Bob-Wire · c21

technical-plan.md

c21 Technical Plan — Inventory + Users / Devices

Audience: AI agents executing this cycle in bob-wire Source of truth for content: design-brief.md — settled decisions in §2 are constraints; open questions in §6 may be explored but must be annotated on the wireframe, not silently decided.

Venue change (2026-09-01): execution moved hi-fi-first into ../design app/pages/pages/ (Mark's call). Three pages — inventory-companies-v1, users-devices-v1, user-detail-v1 — on shared fixtures ../design/app/data/c21-inventory-fixtures.ts, registered in design's app/data/page-registry.ts (groups inventory / teams). The Fleet Overview page is dropped: design c78's fleet-overview-v3 owns the landing thread; c21 widget ideas feed it. The bob-wire wf1 plan below stands as reference if a lo-fi pass is ever wanted, but is not the active path.

Scope

wf1 wireframe iteration: a clickable prototype of the restructured qcontrol inventory area — Fleet Overview entry widgets, the Inventory page (technology view), the Users / Devices page (people view), and one user-detail drill. Lo-fi, Wire* components, layout: 'wireframe'.

Out of scope for wf1: enforcement UI (account blocking is shown as visibility + an annotated "next step" affordance only), governance/compliance pages, the gamified adoption checklist (parked idea — at most a placeholder widget slot on Fleet Overview), mockups (m1 comes after Thursday-call feedback).

Pages

All under app/pages/c21/wireframes/wf1/inventory-v1/:

PageFileContent
Fleet Overviewfleet-overview.vueEntry-story widgets: agent visibility (unique agents, monitored %), team deployment status (coverage % vs identity source of truth), token usage per model per period, accounts posture (enterprise vs personal count). Each widget click-navigates to its page.
Inventoryinventory.vueCompany→technology→instance rollup (Anthropic → Claude Code/Claude Desktop → instances), monitored vs detected-only, models directory w/ usage trends (tokens/$ toggle), accounts & licensing panel (enterprise/personal/unknown flagged), surface directories (MCP servers, tools, plugins, skills, repos, external services). User filter chip appears when arriving via drill-through. No machines, no sessions, no per-user rows, no risk posturing.
Users / Devicesusers-devices.vueCoverage header: sensor deployment status vs definitive source of truth (identity/MDM integration state shown, e.g. "Okta connected · Jamf connected · 47 known workstations"), actionable uncovered list ("Alexis — no sensor — investigate"). User/team table: agents used, provider mix, account type (corporate/personal), tokens/$ (toggle), intensity, one-line LLM summary. Rows drill to user detail. Agent-attribute filters mirror Inventory's user filter.
User Detailuser-detail.vueOne user: devices → agents on each (relationship chain workstation ↔ identity ↔ agent kept visible), account usage incl. any personal accounts, usage trend, LLM-derived work summary + concrete tool-calling surface (MCP servers, repos), and sessions list (sessions live here, not in Inventory). Links back to Inventory pre-filtered ("View in Inventory").

Cross-links to implement (the call's drill paths):

  • Users / Devices → user → click an agent (e.g. Claude) → Inventory with ?user=tyler&agent=claude filter chips shown.
  • Inventory → account panel "used by 3 people" → Users / Devices filtered.
  • Fleet Overview widgets → respective pages.
  • Include an unknown/unattributed identity row somewhere (brief §6, identity attribution edge case).

Data

Shared sample-data module: app/data/c21-inventory.ts. Shapes:

  • Company → technologies[] → instances[] (instance: user, device, monitored: boolean, account ref)
  • Account { provider, accountId, licensing: 'enterprise' | 'personal' | 'unknown', users[] }
  • Person { name, team, devices[], sensorInstalled per device, source: 'okta' | 'manual', tokens, dollars, intensity, summary, surface: { mcpServers[], repos[] }, sessions[] }
  • UsageTrendPoint { period, model, tokens, dollars } — enough periods to show the Anthropic→OpenAI→Grok drift story from the call

Realistic names/numbers; include at least: one unmonitored-but-detected agent (Hermes — the call's example of a surprise), one personal ChatGPT account on a named user, several people with no sensor installed, one unattributed agent instance.

Conventions checklist

  1. Wire* components only; grey borders, dashed placeholders, no shadows; .wire-* classes ok. WireViewToggle for tokens/$ and monitored/all toggles; wire-annotation for open-question callouts.
  2. definePageMeta({ layout: 'wireframe' }) on every page.
  3. Register all four pages in app/data/wireframe-registry.ts: type: 'wireframe', iteration: 'wf1', feature inventory-v1.
  4. Create app/pages/c21/index.vue cycle gallery (copy c16/c20 pattern) and add c21 to the root TOC in app/pages/index.vue.
  5. Copy design-brief.md into the feature dir for /api/specs/ colocation (per brief-colocation convention).
  6. Annotate, don't decide: where the brief lists open questions (agent vs harness label, page name, fleet definition), pick a working label and mark it with a wire-annotation (e.g. "label TBD: agents vs harnesses").

Execution phases

  • Phase 0 (done): cycle records, design brief, this plan.
  • Phase 1 — wf1 build: /wireframe (wireframe-builder) against design-brief.md, four pages above. Builders write .vue files; batch registry entries after parallel runs complete (established parallel-run convention).
  • Phase 2 — flow: /flow to wire the drill paths and filter-chip navigation.
  • Phase 3 — review: /review inventory-v1 against the brief; fix conformance gaps.
  • Phase 4 — feedback loop: present at the Thursday follow-up (Mark Peterson product-spec session); capture deltas as an update brief via /write-brief, then /iterate → wf2, or promote to m1 mockups if structure holds.

Product-side notes (not bob-wire work — for the humans)

Captured from the call so they aren't lost; none block the wireframes:

  • Windows installer/tapping (Kamal) blocks Mark Peterson self-testing; macOS-only today.
  • Centralize the control plane (Docker + Postgres) vs current local-only mode; wireframes assume centralized mode, with local mode noted in brief §2.10.
  • OpenFlow's provider mapping should be corrected to OpenAI in the real data.
  • Identity attachment is "one of the simplest things we do" per Tyler once an identity integration exists — wireframes can assume identity data is available when integration is connected.
  • Data model already holds provider; confirm it represents the company→technology→instance hierarchy the UI now needs.
  • Summarizer model required for per-user work summaries (customer supplies an LLM endpoint).

Qpoint Brand Style Guide