2026 03 23 Proactive Visual Intelligence Design

Documentation for Plans

Proactive Visual Intelligence (PVI) — Design Specification

Date: 2026-03-23 Status: Approved Sub-project: 1 of 3 (PVI → Generation Pipeline Quality → Platform Editability) Session: 257


1. Vision

GoGrab Space is an AI-first platform builder. When a user generates a platform, Vitto doesn't just build it and walk away — Vitto proactively analyzes every component, identifies enhancement opportunities, and presents them as one-click improvements. Users click anywhere in the live preview to see what Vitto suggests. Over time, Vitto learns each user's preferences and gets smarter.

This is not a web builder with AI features bolted on. This is an AI co-pilot that understands design systems, code architecture, and user intent — and acts on all three simultaneously.


2. Core User Flow

  1. Generate — User describes a platform, Vitto generates it
  2. Analyze — Vitto scans every generated component against the SDK manifest, then runs parallel LLM analysis. Ambient pulsing dots appear on elements with suggestions. A chat summary shows the top 3 ranked improvements with "Apply All."
  3. Click — User clicks any element in the live preview. A floating toolbar appears with category icons (Style, Layout, Component, UX, Data, Accessibility). Toolbar ordering is personalized based on what the user applies most.
  4. Suggest — User clicks a category icon. Instant rule-based suggestions appear. Background LLM enrichment streams in within 1-2 seconds with smarter, context-aware suggestions.
  5. Apply — Style changes inject CSS instantly into the iframe, then persist to SCSS. Structural changes generate code via LLM, write to VFS, and compile with a shimmer indicator. Auto-rollback on compilation failure.
  6. Undo — Every apply creates a VFS snapshot (local-first, async Hetzner git push). Timeline shows change history. Click any point to restore.
  7. Learn — Every interaction is tracked. Vitto adjusts toolbar ordering, suggestion ranking, and eventually the generation pipeline itself based on what users actually apply.

3. Architecture

3.1 System Layers

┌─────────────────────────────────────────────────────────────┐
│  LAYER 0: PREREQUISITES                                     │
│  ComponentTaggingPlugin (data-studio-id injection)          │
│  SDK Manifest Pipeline (.intelligence.ts → sdk-manifest.json)│
├─────────────────────────────────────────────────────────────┤
│  LAYER 1: ELEMENT INTELLIGENCE (preview iframe)             │
│  Enhanced preview-bridge-client.ts                          │
│  Rich ElementSelectionPayload via postMessage               │
│  Ambient dot rendering + CSS injection handlers             │
├─────────────────────────────────────────────────────────────┤
│  LAYER 2: SUGGESTION ENGINE (studio services)               │
│  SuggestionRuleEngine (instant, <10ms, from manifest)       │
│  SuggestionEnrichmentService (LLM, Haiku/Sonnet routing)    │
│  SuggestionMergeEngine (rule + LLM → ranked results)        │
├─────────────────────────────────────────────────────────────┤
│  LAYER 3: PROACTIVE ANALYSIS (studio + vitto-api)           │
│  Post-gen rule scan (<100ms) → ambient dots + prelim summary│
│  Parallel Haiku deep scan (2-4s) → merged results           │
│  Chat summary with ranked top-3 + "Apply All"               │
├─────────────────────────────────────────────────────────────┤
│  LAYER 4: APPLY ENGINE (studio + preview)                   │
│  StyleInjectionService (CSS inject → SCSS persist)          │
│  StructuralApplyService (LLM code gen → VFS → compile)      │
│  Auto-rollback on compilation failure                       │
│  Apply All with conflict detection                          │
├─────────────────────────────────────────────────────────────┤
│  LAYER 5: SNAPSHOT & UNDO (studio + Hetzner)                │
│  Local-first VFS snapshots (instant undo)                   │
│  Async Hetzner git push (durable history)                   │
│  Timeline UI with restore-to-point                          │
├─────────────────────────────────────────────────────────────┤
│  LAYER 6: LEARNING (vitto-api + MongoDB)                    │
│  UserSuggestionTracker (view/apply/dismiss events)          │
│  SuggestionWeightService (personalized ordering)            │
│  Feedback quality loop (success/undo tracking)              │
│  Generation pipeline feedback (V3)                          │
└─────────────────────────────────────────────────────────────┘

3.2 Builds on Existing Infrastructure

Existing System How PVI Extends It
preview-bridge-client.ts (click-to-select) Enhanced payload, CSS injection, ambient dots
VisualEditorService (reads VFS sources) Feeds component sources to suggestion engine
StudioInterconnectionService (focus tracking) PVI subscribes to focus updates
BundlerFilesystemService (VFS enrichment) SCSS patching, VFS snapshots
PreviewServerService (blob iframe) CSS injection via postMessage
BundlerService (incremental compile) Structural apply triggers compile (auto-selects PATCH path for ≤6 changed files)
StudioVittoBridgeService (Vitto comms) Chat summary, LLM enrichment calls
UniverseGitService (Hetzner git) Snapshot commits
BaseLLMProvider + ProviderFactory PVI task routes for model selection
ComponentTaggingPlugin (data-studio-id) Must be completed — V1 prerequisite
Prompt partials (ui-framework-components) Auto-generated from sdk-manifest.json
Vitto Memory (MongoDB vector search) Learning layer storage

3.3 New Libraries and Services

New NX library: @libs-ai/proactive-visual-intelligence

New services in existing libraries:

Service Library Purpose
StyleInjectionService @libs-structural/platform-preview CSS injection into blob iframe
ProactiveAnalysisService @libs-structural/vitto-studio Post-generation scan orchestration
SnapshotService @libs-structural/vitto-studio Local VFS snapshots + Hetzner push
UserSuggestionTracker backend-vitto-api MongoDB event recording
PviModelRouterService backend-vitto-api Smart model selection for PVI tasks

New components in vitto-studio:

Component Purpose
PviToolbarComponent Floating category icon toolbar
PviSuggestionPanelComponent Expandable suggestion list per category
PviTimelineComponent Horizontal snapshot history strip
PviChatSummaryComponent Ranked top-3 card in Vitto chat

4. Unified Component Intelligence Manifest

4.1 Problem

The generation pipeline, preview stubs, and prompt partials are maintained separately. This causes drift:

4.2 Solution: SDK Manifest Pipeline

Each SDK component gets a .intelligence.ts file alongside its source:

libs/core/ui-framework/src/lib/components/ggs-table/
  ├── ggs-table.component.ts
  ├── ggs-table.component.html
  ├── ggs-table.component.scss
  └── ggs-table.intelligence.ts     ← NEW

An NX target (generate-sdk-manifest) aggregates all intelligence files into sdk-manifest.json:

*.intelligence.ts (47 files) → generate-sdk-manifest → sdk-manifest.json

4.3 ComponentIntelligence Interface

interface ComponentIntelligence {
  selector: string;
  category: 'button' | 'form' | 'data' | 'layout' | 'overlay' | 'state' | 'navigation' | 'upload' | 'chart';
  purpose: string;
  whenToUse: string[];
  whenNotToUse: string[];
  inputs: Record<string, {
    type: string;
    required: boolean;
    default?: unknown;
    description: string;
    options?: string[];
  }>;
  outputs: Record<string, {
    payload: string;
    description: string;
  }>;
  variants: Record<string, string[]>;
  suggestions: Record<SuggestionCategory, string[]>;
  upgradesFrom: string[];
  composedWith: string[];
  themeTokens: string[];
  examples: Array<{
    label: string;
    html: string;
    ts?: string;
  }>;
}

type SuggestionCategory = 'style' | 'layout' | 'component' | 'ux' | 'data' | 'accessibility';

4.4 SDK Manifest JSON Structure

{
  "version": "1.0.0",
  "generatedAt": "2026-03-23T...",
  "components": {
    "ggs-table": { "...ComponentIntelligence..." }
  },
  "composables": {
    "useCrudList": {
      "purpose": "...",
      "provides": ["items", "loading", "..."],
      "methods": ["loadData", "onSearch", "..."],
      "pairsWith": ["ggs-crud-list-shell", "ggs-table"]
    }
  },
  "patterns": {
    "crud-list": {
      "description": "Standard entity list page",
      "requires": ["ggs-crud-list-shell", "ggs-table", "useCrudList"],
      "optional": ["ggs-filter-panel", "ggs-search-toolbar"],
      "template": "..."
    }
  },
  "themeSystem": {
    "tokens": {
      "--color-primary": { "fallback": "#2563eb", "category": "color", "usage": "..." }
    }
  }
}

4.5 Consumers

Consumer What It Reads Benefit
Generation prompts components, composables, patterns LLM knows exactly what to use (all 47, not 10)
Proactive analysis suggestions, upgradesFrom Rule-based instant suggestions
LLM enrichment Full manifest subset per component Context-aware AI suggestions
Preview stubs inputs, outputs Auto-alignment with real components
Learning layer Writes back suggestion weights Manifest evolves from usage data
External agents Full JSON Any agent can build/edit platforms

4.6 Drift Elimination

The prompt partial ui-framework-components.partial.md is auto-generated from the manifest. The NX target outputs both sdk-manifest.json and the markdown partial. Hand-maintained partials are deleted. Change a component → update .intelligence.ts → run build → prompts, stubs, and suggestions all update.


5. Layer 1: Element Intelligence (Preview Iframe)

5.1 Enhanced Element Selection Payload

The preview bridge client (preview-bridge-client.ts) runs inside the blob iframe. On click, it gathers rich context about the clicked element:

interface ElementSelectionPayload {
  studioId: string;                    // data-studio-id attribute value
  componentName: string;               // Parsed from studioId
  tagName: string;                     // DOM tag name
  childGgsComponents: string[];        // ggs-* elements inside this component
  missingGgsComponents: string[];      // Raw HTML that could be SDK components
  hasNgFor: boolean;                   // Template uses *ngFor pattern
  hasFormControls: boolean;            // Contains input/select/textarea elements
  computedStyles: Record<string, string>; // Key CSS properties
  boundingRect: { x: number; y: number; width: number; height: number }; // Serialized (DOMRect not cloneable via postMessage)
}

Compatibility note: This is a new message type PVI_ELEMENT_CONTEXT sent alongside the existing STUDIO_ELEMENT_SELECTED. The existing StudioElementPayload type and PreviewSelectionEvent in StudioInterconnectionService remain unchanged — PVI subscribes to the new message type via PreviewBridgeService. This avoids breaking the current click-to-select flow. Types to create: ElementSelectionPayload (in PVI library), handler in PreviewBridgeService.handleMessage() for PVI_ELEMENT_CONTEXT.

How it gathers this: On click, walk the DOM subtree scoped to the same data-studio-id. Identify child elements with ggs- tag prefix. Identify raw HTML elements that match upgrade patterns (<button>, <table>, <span> with status-like text). Read computed styles for layout/color/shadow detection. All synchronous DOM inspection, <5ms.

5.2 New Inbound Message Handlers

Message Type Payload Behavior
PVI_INJECT_CSS { studioId, properties: Record<string, string> } Apply CSS properties to target element via style.setProperty()
PVI_REMOVE_CSS { studioId, properties: string[] } Remove CSS properties, restore original values from stored snapshot
PVI_INJECT_DOTS Array<{ studioId, dotType, suggestions }> Render pulsing indicator dots on target elements
PVI_CLEAR_DOTS void Remove all dots

5.3 Ambient Dot Rendering

Dots are absolutely-positioned <div> elements anchored to elements with matching data-studio-id. On iframe load event (after recompile), all dots are re-queried and repositioned. If the target element no longer exists, the dot is silently removed.

Granularity limitation: data-studio-id is injected on component root elements only (by studioTaggingLoader). Dots anchor to components, not individual child elements. If a user clicks a child <button> inside a ggs-table, the dot appears on the table's root element. Per-element granularity is a V3 consideration.

Two visual tiers:

5.4 CSS Injection for Style Apply

The bridge client stores original inline style values before injection. On PVI_REMOVE_CSS, originals are restored. On iframe reload (recompile), injected styles are naturally cleared (the compiled SCSS now includes the change).


6. Layer 2: Suggestion Engine

6.1 SuggestionRuleEngine

Pure synchronous function. No LLM, no network. Input: ElementSelectionPayload + sdk-manifest.json + UserCategoryWeights. Output: Suggestion[].

~20 rules for V1, expandable:

Rule Match Condition Suggestion
List without table hasNgFor && !childGgsComponents.includes('ggs-table') Layout: Switch to ggs-table
List without cards hasNgFor && !computedStyles.display.includes('grid') Layout: Switch to card grid
Raw button missingGgsComponents.includes('<button>') Component: Replace with ggs-button
Status text without badge missingGgsComponents.includes('<span>') + status-like text Component: Use ggs-badge
No empty state List component without ggs-empty-state child UX: Add empty state
No shadows on cards `!computedStyles.boxShadow
Hardcoded colors Computed style contains hex values not in theme tokens Style: Use theme tokens
No search in list List without ggs-search-input child UX: Add search
No filters in list List without ggs-filter-panel child Data: Add filter panel
Form without error display Form without error message elements UX: Add validation errors
Missing loading state Component without ggs-loading-spinner UX: Add loading indicator
Table without pagination ggs-table without ggs-pagination Data: Add pagination
No hover effects computedStyles show no transition properties Style: Add hover transitions
No responsive breakpoints Fixed widths detected Layout: Add responsive grid
Missing accessibility labels Form inputs without associated labels A11y: Add label associations

Rules return suggestions with source: 'rule'. Suggestions for style changes include pre-built StylePatch with both cssPreview and scssPatch. Structural suggestions include StructuralChange with a pre-built LLM prompt.

6.2 SuggestionEnrichmentService

Async LLM enrichment. Fires conditionally after 500ms debounce measured from when PVI_ELEMENT_CONTEXT arrives at the suggestion engine (note: StudioInterconnectionService applies an additional 150ms debounce on focus updates, so total click-to-enrichment is ~650ms).

Conditions to fire:

Model routing:

Prompt structure:

Analyze this Angular component for {category} improvements.

Component: {componentName}
Template: {html source}
Styles: {scss source}
Available SDK: {relevant manifest entries}
User's platform context: {business domain, entity names}

Return 2-3 specific, actionable suggestions.
JSON: { suggestions: [{ label, description, impact, applyType, codeHint }] }

codeHint is a brief description of the code change — NOT the actual code. Full code generation happens only at apply time.

Cache: Map<string, Suggestion[]> keyed by componentName:category. Invalidated when VFS files for that component change.

6.3 SuggestionMergeEngine

Combines rule-based and LLM suggestions:

  1. LLM suggestions that match a rule suggestion (same category + similar label) → LLM version wins (richer description)
  2. LLM suggestions with no rule match → added as new
  3. Rule suggestions with no LLM match → kept as-is
  4. Sort by: impact (high > medium > low), then user's category weights

7. Layer 3: Proactive Analysis

7.1 Post-Generation Scan

Triggered when generation completes and preview compiles successfully.

Phase A: Rule Scan (instant, <100ms, studio-side)

  1. Iterate all .component.ts and .component.html files in VFS
  2. For each component, run lightweight static analysis:
    • Parse template for raw HTML elements upgradeable to SDK components
    • Check SCSS for hardcoded hex colors
    • Check for missing composable usage (useCrudList, useCrudForm)
    • Check for missing ggs-empty-state in list templates
    • Cross-reference with sdk-manifest.json suggestions
  3. Produce preliminary PviAnalysisResult
  4. Inject ambient dots immediately
  5. Post preliminary chat message: "Analyzing your platform..."

Phase B: LLM Deep Scan (2-4s, parallel Haiku)

  1. For each component: fire Haiku call with template + SCSS + manifest context
  2. All calls in parallel via forkJoin (RxJS — no Promise.all per project conventions)
  3. Each call asks: "What specific improvements would make this component more professional, usable, and polished? Consider all 6 categories."
  4. Merge LLM results with rule results via SuggestionMergeEngine
  5. Update ambient dots (some upgrade from enhancement to high-impact)
  6. Post final chat summary with ranked top-3

7.2 Chat Summary

One message per analysis pass. Structure:

✨ I found {N} enhancements for your platform:

[🎨] Card layout for Animals list — high impact     [Apply]
[🧩] Status badges for Active/Draft — high impact   [Apply]
[✨] Empty state for zero results — medium impact    [Apply]

[Apply All Top 3]

+ {N-3} more — click the ✨ dots in the preview to explore.

7.3 Smart Model Router

interface PviModelRoute {
  task: string;
  model: 'haiku' | 'sonnet' | 'opus';
  maxTokens: number;
  temperature: number;
}

const PVI_ROUTES: Record<string, PviModelRoute> = {
  'pvi:component-scan':        { model: 'haiku',  maxTokens: 2048,  temperature: 0.2 },
  'pvi:enrich-simple':         { model: 'haiku',  maxTokens: 2048,  temperature: 0.3 },
  'pvi:enrich-complex':        { model: 'sonnet', maxTokens: 4096,  temperature: 0.3 },
  'pvi:structural-apply':      { model: 'sonnet', maxTokens: 8192,  temperature: 0.1 },
  'pvi:cross-module-analysis': { model: 'opus',   maxTokens: 16384, temperature: 0.2 },
};

Plugs into existing BaseLLMProvider + ProviderFactory via task key lookup.


8. Layer 4: Apply Engine

8.1 Style Apply (Instant)

User clicks "Apply" on style suggestion
  │
  ├── 1. SnapshotService.createLocalSnapshot(affectedPaths)
  ├── 2. PreviewBridgeService.sendPviMessage('PVI_INJECT_CSS', patch.cssPreview)
  │      → Bridge client applies inline styles instantly (new public method on PreviewBridgeService)
  ├── 3. StyleInjectionService.patchScssFile(patch.scssPath, patch.scssPatch, patch.insertAfterSelector)
  │      → Reads SCSS from VFS, patches string, writes back via VfsService.updateFileContent()
  │      → This is NEW infrastructure — no patchScssFile exists today
  ├── 4. Background: incremental compile (preview doesn't flash — CSS already showing)
  └── 5. Background: SnapshotService.pushToHetzner(commitMessage)

SCSS patching: Not AST manipulation. Generated SCSS files follow predictable BEM structure. Find the target selector block as a string, insert the new property line. If selector doesn't exist, append. This is reliable for generated code which follows strict conventions.

StylePatch interface:

interface StylePatch {
  cssPreview: Record<string, string>;   // Injected into iframe DOM
  scssPatch: string;                     // Written to .scss file in VFS
  scssPath: string;                      // Target .scss file path
  insertAfterSelector: string;           // Where in SCSS to insert
}

8.2 Structural Apply (Compiled)

User clicks "Apply" on structural suggestion
  │
  ├── 1. SnapshotService.createLocalSnapshot(affectedPaths)
  ├── 2. Show shimmer overlay on target element
  ├── 3. LLM call (Sonnet) with:
  │      - Current component files (TS, HTML, SCSS)
  │      - sdk-manifest.json entries for involved components
  │      - suggestion.structuralChange.prompt
  │      - "Return ONLY modified files as JSON. Must compile."
  ├── 4. Write modified files to VFS
  ├── 5. Write to VFS triggers normal compile pipeline (BundlerService auto-selects incremental PATCH path for ≤6 files)
  │
  ├── On SUCCESS:
  │     - Remove shimmer
  │     - Preview refreshes with compiled result
  │     - Background: SnapshotService.pushToHetzner()
  │     - UserSuggestionTracker.record({ applied: true })
  │
  └── On FAILURE (compilation error):
        - Auto-rollback: restore VFS from local snapshot
        - Remove shimmer
        - Show error badge on suggestion: "Couldn't apply"
        - NO Hetzner commit (failed state never persisted)
        - UserSuggestionTracker.record({ applied: false, error: true })

8.3 Apply All with Conflict Detection

Each suggestion declares conflicts: string[] — IDs of incompatible suggestions.

"Apply All" clicked
  │
  ├── 1. Sort top suggestions by impact (high first)
  ├── 2. Create single local snapshot (batch undo point)
  ├── 3. For each suggestion in order:
  │      ├── Check conflicts against already-applied set
  │      ├── If conflict → skip, add to skipped[]
  │      ├── If style → batch into single CSS injection
  │      └── If structural → apply sequentially (each needs compile)
  │             Show progress: "Applying 2 of 3..." between structural applies
  ├── 4. Show result: "Applied {N} of {M}. Skipped: {reasons}"
  └── 5. Single Hetzner commit for the batch

9. Layer 5: Snapshot & Undo

9.1 Local-First Architecture

interface VfsSnapshot {
  id: string;
  timestamp: number;
  label: string;                        // e.g., "Added card shadow"
  affectedPaths: string[];              // Which files were changed
  fileContents: Record<string, string>;  // File content before the change (Record, not Map — must be JSON-serializable)
  hetznerCommitSha?: string;            // Populated async after push
  hetznerPushStatus: 'pending' | 'pushed' | 'failed';
}

Local stack: Max 50 snapshots. FIFO eviction. Undo restores from memory in <1ms.

Hetzner push: Async after successful apply. Commit message: [PVI] {suggestion.label}. 3x retry with exponential backoff. Failure is non-blocking — user can still undo locally.

9.2 Undo Flow

User clicks Undo (or Ctrl+Z)
  │
  ├── 1. Get previous snapshot from local stack
  ├── 2. Restore VFS files from snapshot.fileContents (<1ms)
  ├── 3. If style change was undone: postMessage('PVI_REMOVE_CSS', ...)
  ├── 4. Incremental compile → preview refreshes (~2-4s)
  └── 5. Timeline UI updates current position

9.3 Timeline UI

Horizontal strip below the preview. Each dot = a snapshot. Current position highlighted. Labels on hover. Click any dot to jump to that state (non-linear undo). Shows Hetzner sync status per dot (checkmark = pushed, spinner = pending).


10. Layer 6: Learning

10.1 Event Tracking

Every PVI interaction recorded:

interface UserSuggestionEvent {
  userId: string;
  spaceId: string;
  universeId: string;
  componentType: string;
  category: SuggestionCategory;
  suggestionLabel: string;
  action: 'viewed' | 'applied' | 'dismissed' | 'undone';
  source: 'rule' | 'llm' | 'merged';
  timestamp: Date;
}

Stored in MongoDB pvi_user_preferences collection on vitto-mind database.

10.2 User Preference Weights

Daily cron aggregation:

interface UserCategoryWeights {
  userId: string;
  weights: Record<SuggestionCategory, number>;  // 0.0-1.0, normalized
  topPatterns: Array<{
    componentType: string;
    preferredSuggestions: string[];
  }>;
  updatedAt: Date;
}

Cold start defaults: style=0.30, layout=0.25, component=0.20, ux=0.15, data=0.05, accessibility=0.05.

Weights shift after ~10 interactions. Strongly personalized after ~50.

10.3 How Weights Flow Back

Consumer Effect
Toolbar icon ordering Highest-weight category appears first
Rule engine More suggestion slots for preferred categories
Chat summary User's preferred categories weighted in top-3 ranking
LLM enrichment Skip enrichment for categories user rarely engages with

11. Key Interfaces

// Core suggestion type
interface Suggestion {
  id: string;
  category: SuggestionCategory;
  label: string;
  description: string;
  impact: 'high' | 'medium' | 'low';
  applyType: 'style' | 'structural';
  source: 'rule' | 'llm' | 'merged' | 'learned';
  conflicts: string[];
  patch?: StylePatch;
  structuralChange?: StructuralChange;
}

// Style change — dual format
interface StylePatch {
  cssPreview: Record<string, string>;
  scssPatch: string;
  scssPath: string;
  insertAfterSelector: string;
}

// Structural change — LLM-generated at apply time
interface StructuralChange {
  prompt: string;                        // Pre-built LLM prompt for this change
  affectedFiles: string[];               // Which VFS files will change
}

// Enhanced element payload from preview bridge
interface ElementSelectionPayload {
  studioId: string;
  componentName: string;
  tagName: string;
  childGgsComponents: string[];
  missingGgsComponents: string[];
  hasNgFor: boolean;
  hasFormControls: boolean;
  computedStyles: Record<string, string>;
  boundingRect: { x: number; y: number; width: number; height: number };
}

// Full analysis result
interface PviAnalysisResult {
  components: Array<{
    componentName: string;
    studioId: string;
    suggestions: Suggestion[];
    dotType: 'high-impact' | 'enhancement';
  }>;
  summary: {
    total: number;
    byCategory: Record<SuggestionCategory, number>;
    topThree: Suggestion[];
  };
}

// VFS snapshot
interface VfsSnapshot {
  id: string;
  timestamp: number;
  label: string;
  affectedPaths: string[];
  fileContents: Record<string, string>;
  hetznerCommitSha?: string;
  hetznerPushStatus: 'pending' | 'pushed' | 'failed';
}

// User weights
interface UserCategoryWeights {
  userId: string;
  weights: Record<SuggestionCategory, number>;
  topPatterns: Array<{
    componentType: string;
    preferredSuggestions: string[];
  }>;
  updatedAt: Date;
}

12. Implementation Phases

V1 — Foundation + Core Loop

Goal: User clicks element → sees toolbar → clicks suggestion → it applies. The full loop works.

Prerequisites (P0):

Deliverables:

NOT in V1: Ambient dots, chat summary, LLM enrichment, learning layer, Apply All, Hetzner git, timeline UI.

V2 — Intelligence + Learning

Goal: Vitto proactively analyzes, suggests via chat, learns preferences, persists history.

Deliverables:

V3 — Mastery + Ecosystem

Goal: Self-improving system. Vitto reasons across modules, learns from all users, evolves the generation pipeline.

Deliverables:


13. Critical Dependencies and Risks

Risk Severity Mitigation
ComponentTaggingPlugin incomplete Blocking V1 Verify first. If broken, fix before any PVI work.
Dots lost on preview recompile Medium Re-render from stored map on iframe load event, anchor by data-studio-id
SCSS persistence complexity Medium String-based patching on predictable BEM structure. No AST parser needed for generated code.
Hetzner git latency for undo Medium Local-first snapshots. Hetzner push is async, fire-and-forget.
LLM cost on rapid clicking Low 500ms debounce + cancel in-flight + cache per component:category
Apply All conflicts Low Explicit conflicts[] on each suggestion. Skip and report.
Structural apply compilation failure Medium Auto-rollback from pre-apply snapshot. User never sees broken state.
Learning cold start Low Sensible defaults: style=0.30, layout=0.25, component=0.20, ux=0.15, data=0.05, a11y=0.05
LLM generates broken code on apply Medium Auto-rollback + error badge. Track failure rate per suggestion type.
sdk-manifest.json staleness Low Generated by NX build target. CI validates manifest matches component source.

14. Cost Model

Action Model Frequency Cost per Session
Post-gen scan (15 components) Haiku (parallel) 1x per generation $0.02-0.04
On-click enrichment Haiku or Sonnet ~10 clicks $0.01-0.05
Structural apply Sonnet ~3 applies $0.03-0.09
Chat escalation Opus ~1 per session $0.05-0.10
Total per editing session $0.11-0.28

15. Success Metrics

Metric V1 Target V2 Target V3 Target
Suggestion apply rate ≥20% ≥35% ≥50%
Style apply latency <100ms <100ms <100ms
Structural apply success rate ≥70% ≥85% ≥95%
Post-gen analysis time N/A <5s <3s
User undo rate (quality signal) <30% <20% <15%
Suggestions per platform ≥5 ≥10 (LLM-enriched) ≥15 (personalized)

16. Related Sub-Projects (Future Specs)

This spec is the first of three:

  1. Proactive Visual Intelligence (this spec) — Click → suggest → apply → learn
  2. Generation Pipeline Quality — Prompt engineering, auto-correction, validation, sdk-manifest integration into generation
  3. Platform Editability — Code structure improvements that make generated code easier to modify manually

Sub-projects 2 and 3 will be designed and specced separately, building on the manifest and learning infrastructure established here.