DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path analyses/loomworks-white-label-multilanguage-analysis-v0_1.md

Loomworks White-Label and Multi-Language Deployment Analysis

Version. 0.1 Date. 2026-05-07 Provenance. Claude.ai analysis session. Operator: Marvin Percival. Status. Analysis document. Assesses current codebase readiness, required changes, and rollout timing for white-label and multi-language deployment.


1. The two capabilities

White-label = a partner runs their own Loomworks-based environment under their own brand. Their users see the partner's name, colors, and identity — not Loomworks, not DUNIN7. The partner's Companion has its own persona. The infrastructure is managed by DUNIN7 through a DevOps engagement.

Multi-language = the environment operates in the user's language. The Companion converses in French. The UI labels are in Japanese. Notifications arrive in Portuguese. Engagement content stays in whatever language the contributors use.

These are separable but compound. A white-label partner in Germany needs German. A white-label partner in Brazil needs Portuguese. DUNIN7's own instances need English now and potentially Spanish (Miami market) later.


2. White-label: what needs to be configurable

2.1 Brand surface inventory

Every place the user sees a brand mark, color, name, or identity must be instance-configurable. Current state assessment:

| Surface | Currently | What white-label needs | Effort | |---------|-----------|----------------------|--------| | Product name ("Loomworks") | Hardcoded in Operator Layer NavBar, landing page, auth page, multiple components | Instance-level config: product_name | Medium — string replacement across many files, but mechanical | | Wordmark / logo | IBM Plex Serif "Loomworks" text rendered in CSS. Stamp mark in brand guide. | Instance-level logo asset (SVG or image URL) + product name | Medium — logo component reads from config | | Color system | CSS custom properties in tokens.css + Tailwind config. Warm paper palette. | Instance-level color override. All 9 core colors configurable. | Low — CSS custom properties are already the right architecture. Override at the :root level from instance config | | Typography | IBM Plex Serif + Inter + IBM Plex Mono via next/font | Instance-level font override (3 slots: serif, sans, mono) | Medium — font loading must be dynamic, not build-time | | Lede / tagline | "Engagement memory for the agentic era" hardcoded | Instance-level tagline | Low — string from config | | Footer | "DUNIN7 — Done In Seven LLC" | Instance-level footer text. DUNIN7 attribution may be required (license terms) or hidden (full white-label) | Low — string from config | | Domain | localhost:3001 (dev) | Partner's domain. Custom domain per instance. | External — DNS + reverse proxy config, not code | | Favicon / PWA icon | Not yet implemented | Instance-level icon assets | Low | | Email templates | Not yet built | Must be branded from inception | Future — design with config slots | | Terms / privacy | Not yet built | Per-instance legal documents | Future |

2.2 Companion identity

| Surface | Currently | What white-label needs | Effort | |---------|-----------|----------------------|--------| | Companion default name | "Companion" (person-level, user-renameable) | Instance-level default. Partner might want "Atlas" or "Guide" or their brand name as default | Low — default value from instance config instead of hardcoded | | Companion persona | English text asset. Lead-expert posture. Warm voice. References {companion_name} and {operator_name} | Instance-level persona template. Partner defines the voice, posture, boundaries. DUNIN7 provides a default. | Medium — persona is already a text asset; making it instance-configurable is extending the template variable system | | Companion avatar | "L" initial in the brand guide mockups | Instance-level avatar (initial, image, or icon) | Low | | NEVER list | No AI disclosure, no engine vocabulary | Instance-level additions possible (partner's own forbidden terms) | Low — extend the list from config |

2.3 The vocabulary wall — per-instance vocabulary

Phase 40 CR §21 explicitly deferred this: "Operator-configurable vocabulary (task vs. project, item vs. note). Future work."

Today the vocabulary wall maps engine terms to a fixed set of Operator terms: engagementproject, assertionnote, shape_eventspecification, render_eventartifact.

A white-label partner might want different Operator terms: projectworkspace, noteinsight, specificationblueprint, artifactdeliverable. This requires the vocabulary wall to be parameterized — the mapping table becomes instance-level config, not a code constant.

Effort: High. The vocabulary wall is currently enforced by a test that scans for hardcoded forbidden terms. Parameterizing it means the Operator Layer frontend, the Orchestration API response schemas, the Companion's system prompt, notification text, and the vocabulary-wall test itself all need to read from instance-level vocabulary config. This is a significant refactor but architecturally clean — the wall already exists as a translation layer. Making it configurable is widening the translation table.

2.4 Instance configuration model

All of the above converges on a single need: an instance configuration object that each deployment reads at startup. This object carries brand, vocabulary, persona, colors, typography, and legal references.


instance_config:
  product_name: "Loomworks"
  tagline: "Engagement memory for the agentic era."
  logo_url: "/assets/logo.svg"
  favicon_url: "/assets/favicon.ico"
  footer_text: "DUNIN7 — Done In Seven LLC — Miami, Florida"
  colors:
    press_ink: "#1A1814"
    cartridge: "#F2EDE0"
    iron_oxide: "#B55537"
    ... (all 9 core colors)
  typography:
    serif: "IBM Plex Serif"
    sans: "Inter"
    mono: "IBM Plex Mono"
  companion:
    default_name: "Companion"
    avatar: "L"
    persona_template: "default"   # or a custom template ID
    never_list_additions: []
  vocabulary:
    project: "project"
    note: "note"
    specification: "specification"
    artifact: "artifact"
    ... (full Operator vocabulary mapping)
  locale:
    default_language: "en"
    supported_languages: ["en"]
  legal:
    terms_url: "/legal/terms"
    privacy_url: "/legal/privacy"

This object is either a JSON file read at startup, an environment variable pointing to a config file, or a table in the instance's database. The Operator Layer frontend reads it on load. The engine reads it for vocabulary and persona configuration.


3. Multi-language: where language lives

3.1 The five language layers

Language appears at five distinct layers in Loomworks, each with different characteristics:

Layer 1 — Companion conversation. The Companion speaks to the user. This is LLM-generated text. The language is controlled by the system prompt. If the persona says "Respond in French," the Companion responds in French. This is the easiest layer to make multilingual — the LLM already knows how to speak every major language.

Current state: English-only persona template. Template variable {companion_name} and {operator_name} already parameterized.

What's needed: A language directive in the persona template. "Respond in {language}." The LLM handles the rest — vocabulary, grammar, idiom. The Companion's voice (warm, direct, authoritative) translates across languages naturally because it's a behavioral instruction, not a linguistic one.

Effort: Low. Add {language} to the persona template. Add default_language to instance config. The LLM does the heavy lifting.

Caveat: The intent classifier also uses language. The classifier prompt must handle multilingual input — a French user's "montre-moi mes projets" needs to classify as ask_about_progress. Claude's multilingual capability handles this naturally, but the classifier prompt's examples are English-only. Adding multilingual examples or a "The user may speak in any language; classify the intent regardless of language" instruction is needed.


Layer 2 — UI chrome. Navigation labels, button text, empty states, error messages, placeholder text. Everything the frontend renders that is not Companion-generated.

Current state: All hardcoded English strings in React components. "Dashboard", "Inbox", "Library", "Companion", "Send", "Sign in", "Message Companion...", empty state messages, greeting text.

What's needed: An i18n system. Every user-visible string in the Operator Layer must be a key that resolves to a translation. Standard approach: a messages/{locale}.json file per language, a React context that provides the current locale, and a t('key') function that resolves strings.

Effort: High. This is the largest single change for multi-language. Every component that renders text needs to use the i18n system instead of hardcoded strings. The Workshop frontend (loomworks-ui) has the same issue but is lower priority (power-user surface, English-acceptable for longer).

Estimated string count: ~100–150 translatable strings in the Operator Layer. Each language requires a complete translation file. Translation quality matters — the Companion's warmth must extend to the UI chrome. Machine translation is a starting point; human review is required for the tone to be right.


Layer 3 — Notification text. Notification titles, bodies, approval card descriptions. These are generated by the engine's trigger evaluator and the Companion's proactive behavior system.

Current state: English. Generated through the vocabulary wall translators and the Companion's response generation.

What's needed: Notification text generation must be language-aware. Two options:

Leaning toward A for user-facing notifications (the Companion's voice matters) and B for system notifications (SSL expiry, deploy status — these are operational, not conversational).


Layer 4 — Engagement content. Assertions, seeds, shapes, renders. What the Operator and contributors produce. This is user-generated content.

What's needed: Nothing. Content is in whatever language the contributors use. A French Operator writes French assertions. A Japanese team writes Japanese seeds. The engine doesn't care about content language — it stores and retrieves text. The Companion reads the content and responds in the same language (because the LLM can read French assertions and discuss them in French).

The one edge case: Mixed-language engagements. Contributor A writes in English, Contributor B writes in French. The Companion needs to be able to discuss both. The LLM handles this naturally — it can read both languages and respond in the Operator's preferred language. No code change needed.


Layer 5 — Vocabulary wall terms. The Operator-vocabulary words: "project", "note", "specification", "artifact", "drafting", "ready", "archived". These appear in API responses, dashboard zone labels, and Companion messages.

Current state: English Literal values in Pydantic schemas. The vocabulary wall test enforces these specific strings.

What's needed: Localized vocabulary. "Project" becomes "Projet" in French, "Projekt" in German, "プロジェクト" in Japanese. This requires the vocabulary mapping to be per-locale, not hardcoded.

Effort: High and entangled with the vocabulary wall architecture. The wall currently enforces specific English strings. Localized vocabulary means the wall must enforce a set of allowed terms per locale, not a single global set. The API response schemas would need to carry locale-appropriate strings — which means either the API returns locale-specific responses (complex) or the frontend maps API vocabulary keys to locale strings (simpler, keeps the API language-neutral).

Recommendation: The API stays in English vocabulary. The frontend maps API values to locale-appropriate display strings. The Companion's LLM responses are already in the user's language. The vocabulary wall stays English (it's an engineering enforcement tool, not a user-facing surface). The frontend's i18n system carries the Operator vocabulary translations alongside UI chrome translations.


3.2 Multi-language summary

| Layer | Current state | What's needed | Effort | When | |-------|-------------|--------------|--------|------| | Companion conversation | English persona | {language} in persona template | Low | Before first non-English instance | | UI chrome | Hardcoded English | i18n system + translation files | High | Before first non-English instance | | Notification text | English | Language-aware generation | Medium | Before first non-English instance | | Engagement content | Language-agnostic | Nothing | Zero | Already works | | Vocabulary terms (display) | Hardcoded English | Frontend locale mapping | Medium | Before first non-English instance |


4. Current codebase implications

4.1 What's already right

The architecture has several properties that make white-label and multi-language feasible without re-architecture:

4.2 What needs work

| Component | File(s) | Issue | Fix category | |-----------|--------|-------|-------------| | Product name in NavBar | src/components/nav/NavBar.tsx | "Loomworks" hardcoded | String → config | | Landing page branding | src/app/page.tsx | Name, tagline hardcoded | String → config | | Auth page | src/app/auth/page.tsx | "Sign in" hardcoded English | i18n | | Chat author labels | src/components/chat/ChatView.tsx | "Companion" fallback, "(Operator)" role label | Config + i18n | | Dashboard greeting | src/app/dashboard/page.tsx | "Welcome back" hardcoded English | i18n | | Empty states | Multiple components | English strings | i18n | | Notification text | Engine: trigger evaluator, notification creation | English generation | Language-aware generation | | Persona template | Engine: orchestration/prompts/ | English-only, no language variable | Template extension | | Classifier prompt | Engine: orchestration/classifier.py | English examples, no multilingual guidance | Prompt extension | | Intent instruction templates | Engine: orchestration/prompts/ | English-only | Template extension | | Vocabulary Literal values | Engine: orchestration/schemas.py | Hardcoded English Literals | API stays English; frontend maps to locale | | Font loading | src/app/layout.tsx or font config | Build-time font import | Dynamic font loading from config | | Color tokens | src/styles/tokens.css | Hardcoded values | Runtime override from instance config | | Tailwind config | tailwind.config.ts | References CSS vars (good), but font families hardcoded | Read from CSS vars (already mostly correct) | | Footer | Layout components | "DUNIN7" hardcoded | String → config |

4.3 RTL language support

Arabic, Hebrew, Persian, and Urdu require right-to-left (RTL) text layout. This affects:

Effort: Medium-High. Tailwind has RTL support via the rtl: variant. Components need auditing for directional assumptions. The chat layout (operator right, companion left) needs to respect locale direction.

When: Not required for initial rollout. Arabic and Hebrew markets are important but not first-wave. Design for RTL readiness (use logical properties start/end instead of left/right) from now to avoid painful retrofitting.


5. Rollout relevance

5.1 What matters when

| Rollout stage | White-label needs | Multi-language needs | |---------------|------------------|---------------------| | Private alpha (now) | Nothing. DUNIN7 brand. English. | Nothing. English users. | | US production (Instance B) | Nothing. Loomworks brand. English. | Nothing. English-primary market. | | EU production (Instance C) | Nothing if DUNIN7-branded. Minimal if partner. | German and French are the priority. EU users expect their language. | | First white-label partner | Full brand config. Product name, colors, typography, logo, persona, footer. | Partner's primary language. Companion conversation + UI chrome. | | APAC expansion | Brand config (already built). | Japanese, Korean, Mandarin. CJK typography considerations. RTL not needed. | | MENA expansion | Brand config (already built). | Arabic. RTL support required. |

5.2 Phased implementation recommendation

Phase A — Instance config foundation (before first non-DUNIN7 instance).

Phase B — i18n system (before EU production or first non-English partner).

Phase C — Full white-label (before first partner instance).

Phase D — RTL and CJK (before MENA/APAC expansion).

5.3 What to do now (zero-effort discipline)

Even before any implementation, three practices prevent future pain:

  1. Use logical CSS properties. padding-inline-start instead of padding-left. margin-inline-end instead of margin-right. This costs nothing now and prevents an RTL retrofit later. New CSS written from today onward should use logical properties.
  1. Don't concatenate user-visible strings. "Welcome back, " + name breaks in languages where word order differs. Use template patterns: t('greeting', { name }) → "Welcome back, {name}" (English) / "{name}さん、おかえりなさい" (Japanese). This is a coding discipline, not a framework installation.
  1. Keep brand strings in one place. If "Loomworks" appears in 15 components, extraction is painful. If it appears in one config constant imported everywhere, extraction is trivial. Same for "Companion", "Dashboard", "Inbox", "Library."

6. Cost implications

6.1 Translation

| Language | Estimated strings | Translation cost (professional) | Ongoing maintenance | |----------|-----------------|-------------------------------|-------------------| | German | ~150 UI + ~30 notifications | ~$500–800 | ~$100 per release with new strings | | French | ~150 UI + ~30 notifications | ~$500–800 | ~$100 per release | | Japanese | ~150 UI + ~30 notifications | ~$600–1,000 | ~$150 per release | | Arabic | ~150 UI + ~30 notifications + RTL audit | ~$800–1,200 | ~$150 per release |

Machine translation (via Claude or DeepL) produces a first draft at near-zero cost. Human review for tone alignment costs the above. The Companion's warmth in the UI chrome is the hard part — "You're all caught up" in German isn't just a translation, it's a voice.

6.2 Development

| Phase | Estimated effort | When needed | |-------|-----------------|-------------| | A (instance config) | 2–3 days | Before first non-DUNIN7 instance | | B (i18n system) | 5–7 days | Before EU production or first partner | | C (full white-label) | 3–5 days | Before first partner instance | | D (RTL + CJK) | 5–7 days | Before MENA/APAC |

These are CC execution estimates, not calendar time. Each is a phase-scale unit of work.

6.3 LLM cost for multilingual Companion

The Companion's conversation in non-English languages costs slightly more in tokens because non-Latin scripts are less token-efficient (Japanese characters use ~2× the tokens of English for equivalent meaning). For German and French (Latin script), the cost difference is negligible. For Japanese, Chinese, and Arabic, expect ~30–50% higher token cost per turn.


7. White-label licensing model

7.1 What the partner gets

7.2 What the partner doesn't get

7.3 Revenue model for white-label

| Component | Revenue to DUNIN7 | |-----------|-------------------| | Platform license | $199–999/month (based on scale) | | Per-seat fees (passed through or marked up) | $19–29/seat/month | | Infrastructure management fee | Included in platform license or billed separately | | LLM cost | Partner provides their own API key or pays DUNIN7 markup | | Setup fee | $1,000–5,000 one-time (branding, config, initial translation) |


8. Companion documents


DUNIN7 — Done In Seven LLC — Miami, Florida White-label and multi-language deployment analysis — v0.1 — 2026-05-07