Version. v0.2
Date. 2026-06-26
Author. Claude.ai (scoping)
For. The Operator. Two decisions are settled (unified open; template framing — branding + language axes, ready-not-active); this note records the build shape and what the first change request will cover.
Repository home. loomworks-record/scoping-notes/
Reading level. Plain English. The change request that follows will carry the file names, component paths, and line-level grounding for the build session.
What changed from v0.1. Added the template framing (new §0): this Companion surface is the reference template from which many custom Companions are created, so it is built to be customizable along two axes — branding (palette, fonts, Companion name, voice register) and language (full string translatability) — ready-not-active (swappable seams, ships with one brand and English; the runtime tenant/locale switcher is not built until a second Companion gives real requirements). A template-cleanliness gate is added to the build discipline (§5) and folded into seed alignment (§4). The wire-then-reskin shape and the unified-open decision are unchanged.
What this is. The Engine now has the full spoken loop — say "open Goosey," your unqualified commands land in Goosey, say "close" to leave. That all works at the Engine and API level (merged, tested, green). But the frontend — the screen you actually look at — uses none of it. This note scopes the work to make the spoken loop visible and usable on the Companion surface, and to move that surface toward the mockups you've already drawn.
The honest finding that shapes everything. You described this as building "a completely new Companion." A read-only inspection of the live frontend found that's not quite the situation: three working conversation surfaces already exist (the in-engagement chat, the engagement picker, and a full-screen chat view), built on a clean, convention-bound foundation that already uses the brand colors and fonts from the mockups. The frontend isn't bare ground — it's a sound frame that's missing the focus layer entirely. So the cheaper, lower-risk path is to wire the focus capability into what's there and re-skin it toward the mockups, with a clean fallback to rebuild if the result comes out wrong. Because the Engine is the thing that matters and it's untouched either way, trying the cheaper path first costs little: if it's genuinely patchwork when done, you rebuild the surface and lose nothing of the substrate.
What decision is needed now. None — the one open product question is settled: unified open (see below). This note records the build shape for your approval; the change request follows.
The one settled decision. Open is unified: when you open an engagement — by clicking it or saying "open Goosey" — it both takes you to that engagement's surface and sets your command-focus there, as one act. "Where I'm looking is where my commands land." Today these are two disconnected things (the screen navigates one way; the Engine's focus is set another way, and the frontend never sets it at all). Unifying them is the heart of this work.
The core commitment. This Companion surface is the reference template from which many custom Companions are created. It is not "the Loomworks Companion" as a one-off; it is the comprehensive template a custom Companion is derived from. That changes how every piece is built: each must be customizable from the start, or it gets built twice.
The two axes of customization (the complete set — confirmed with the Operator).
There is no third axis (layout variation, feature-set-per-Companion, etc.) in scope. The template is designed around branding and language; if a third axis is ever needed, the readiness seams below will not foreclose it, but it is not built for speculatively.
Ready, not active. The template is built so branding and language are parameterized and swappable — but it ships with the one Loomworks brand and English. The runtime tenant/locale switcher (a mechanism to load a different brand and language at runtime) is not built now, because there is one brand and one language today, and the switcher's real requirements only appear when the second Companion does. Building it now would be designing against a state that does not exist. The principle, consistent across this whole arc: build the seams clean so the second Companion is cheap; build the switching machinery when the second Companion gives real requirements.
Why the seams are cheap to build clean (the machinery already exists). The live frontend already carries the indirection both axes need — so template-cleanliness is not new architecture, it is using what is there correctly:
companion_name on the person record), not a literal — so the name axis is already swap-ready.This mirrors the Engine-side commitment the architecture already names (the white-label hooks: brand-free outcomes as structured codes the host translates). The frontend template is the consumer side of the same principle.
The template-cleanliness gate (build discipline, applied at every step — see §5). Every step of the build is checked against: no hardcoded color (tokens only); no inline user-facing string (registry only); Companion name and identity from data (never literal "Companion"/"Goosey"); voice-register strings isolated so tone is swappable. Because the repo already has a vocabulary-wall guard at the wire boundary, the change request can add a lightweight test that fails if the new focus components introduce a raw color or an inline user-facing string — so the template rule is guaranteed in code, not requested in the prompt.
A read-only inspection of the live loomworks frontend and the mockups (full findings: loomworks-companion-surface-scoping-grounding-v0_1.md) established:
The mockups (the design target). The Companion surfaces are drawn as HTML mockups in loomworks-record/brand/. The most relevant: a dual-pane chat surface (conversation on the left, a four-room workspace on the right) with a top-bar focus chip reading "here: 7 · Goosey · E0007" — your current engagement shown by number, name, and E-label, never the hidden UUID. Open and close are spoken (composer chips and voice), though the picker also opens by click. There's an engagement-picker home and a richer three-pane dashboard variant.
The live frontend (the build truth). Next.js with the App Router, TypeScript, and — importantly — the mockup's colors and fonts are already the live design tokens, so a build can match the mockups natively. Three conversation surfaces already work and already talk to the Engine's converse endpoint. There's one clean API client, an established pattern for "me"-style endpoints, a provider pattern for shared state, a voice hook, and a "vocabulary wall" guard that already enforces plain-terms discipline (no engine jargon leaking to the screen).
The gap (verified, not assumed). The frontend calls none of the focus endpoints the Engine just gained. There's no focus chip. And the existing "open" is screen navigation only — clicking an engagement jumps you to its page but never tells the Engine that's where your commands should go. So there are two unconnected "opens": the screen's (live, navigates) and the Engine's (just built, unwired). The build reconciles them into the one unified open.
Reusable, confirmed present. The API client, the conversation components (already wired to converse), the voice hook (for spoken open/close), the design tokens (the mockup palette), the brand-string registry, and the test setup. The build adds a focus layer on top of these — it does not rebuild them.
The work splits into two phases with a deliberate judge-seam between them. The split exists so the moment-of-judgment (is this a sound frame or patchwork?) comes before the expensive cosmetic work, not after.
This phase makes the Engine's focus loop visible and working on the existing surfaces, changing as little of the look as possible. At the end, you look at it and judge the bones.
What it builds:
GET/PUT /me/current-engagement), following the existing pattern for "me"-style endpoints.The judge-seam. At the end of Phase 1, the focus loop works on the existing surfaces and you can use it. You look at it and decide: is this a sound frame worth re-skinning, or is it patchwork that should be rebuilt? Phase 2 only proceeds on a sound frame. This is the cheap-failure point — if wiring the focus reveals the existing surfaces fight it, you learn that here, before investing in the re-skin.
Only if Phase 1's frame is judged sound. This phase moves the surface's look and layout toward the mockups — the dual-pane conversation-plus-four-room-workspace arrangement, the composer with suggested-command chips, the voice surfacing, the picker home. The focus capability from Phase 1 is the foundation it sits on.
This phase is scoped in its own change request after the judge-seam, because its exact shape depends on what Phase 1 reveals and on which mockup surfaces you most want first. It is named here so the arc is visible, not drafted in detail yet.
You raised the real risk: modifying an existing solution can produce a patchwork product. That risk is genuine, and here is the honest reading of it against what the inspection found.
Patchwork happens when new behavior is bolted onto a foundation built on different assumptions — when the old structure fights the new thing. The inspection describes the opposite: a clean foundation missing the focus layer, not a wrong-built one resisting it. The focus work adds an absent layer; it doesn't carve into a mis-built one.
The patchwork risk is actually higher in a from-scratch rebuild, because a new surface still has to talk to the same Engine through the same client, render the same conversation, use the same tokens, obey the same vocabulary wall. Rebuilding means either reusing those (which is "modify what exists" with extra steps) or duplicating them (two conversation views, two API patterns, drifting apart — the patchwork, self-inflicted and doubled).
And the fallback is cheap because it's all about the Engine and the API. The frontend is a consumer of a substrate that's built, merged, and green. If the wired-and-reskinned surface comes out wrong, you rebuild the surface and the Engine is untouched. The cost of trying the cheaper path first is bounded: at worst you fall back to rebuild, having lost a surface, never the substrate. That is why wire-first-judge-then-reskin is the low-risk move, and the rebuild option stays open the whole way.
A Companion surface is the most seed-governed thing in the product. Checked against the canonical seed (v0.12) and the architecture specification (v0.6); the build conforms on every surface-governing commitment:
No conflict with the seed or the architecture specification is visible. The one seed-adjacent surface — Companion addressing vocabulary (number + name + E-label; UUID invisible) — is exactly what the focus chip displays, and it is governed by the engagement-identity record this work follows.
Template-readiness aligns with the white-label commitment. Building branding and language as swappable seams (§0) is the consumer-side expression of the architecture's white-label hooks (brand-free outcomes the host translates; tenant_context + locale). The template does not introduce a commitment the seed lacks — it realizes one the architecture already names, on the frontend.
The change request drafted from this note covers Phase 1 only — wire the focus capability — built in disciplined steps, each its own commit, the test suite green at each, the build halting before any push for Operator authorization. Every step is built template-clean (the §0 gate: tokens not colors, registry not inline strings, name-from-data, voice-register isolated). Its steps, in plain terms:
Phase 2 (the re-skin) is a separate change request drafted after the judge-seam, its shape informed by what Phase 1 reveals and which mockup surfaces you prioritize — and built to the same template-cleanliness gate.
This scoping note rests on a read-only inspection already performed (loomworks-companion-surface-scoping-grounding-v0_1.md), which grounded the framework, the existing surfaces, the API client, the provider pattern, the reusable pieces, and the verified gap. The change request's Step 0 re-confirms the live component paths and the exact endpoint shapes against the loomworks repo at draft time (the frontend may have moved since the inspection), and confirms the focus endpoints' request/response shapes against the merged Engine (GET/PUT /me/current-engagement). Grounding is re-pulled live at CR time, not carried as assumption.
DUNIN7 — Done In Seven LLC — Miami, Florida Companion surface — scoping note — v0.2 — 2026-06-26