Files
archy/CLAUDE.md
T
DorianandClaude Opus 4.6 b71c88f03b feat(app): update PWA icons to ✦ star design and fix chat panel default
Replace chat-bubble PWA icons with the four-pointed star (✦) used in
the interface. Fix panelSide default so chat appears on the left and
content surface on the right. Add CLAUDE.md project guide and
.claude/launch.json dev server config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 23:49:31 +00:00

9.8 KiB

CLAUDE.md — AIUI Project Guide

Project Overview

AIUI is a next-generation AI content surface UI. It's a pnpm monorepo with two packages:

  • @aiui/app — Reference application (Vite + Vue 3 + Tailwind CSS)
  • @aiui/core — Reusable component library

Stack: Vue 3 (Composition API), TypeScript ~5.8 (strict), Vite, Tailwind CSS, Pinia, Vue Router, Turborepo Node: >=20.0.0 | pnpm: >=10.0.0

Quick Reference

pnpm dev            # Run app dev server + Claude proxy
pnpm dev:core       # Watch-build core library
pnpm build          # Build all packages (turbo)
pnpm test           # Run tests (vitest)
pnpm lint           # Lint all packages (eslint)
pnpm typecheck      # Type-check all packages (vue-tsc)
pnpm clean          # Remove dist/ directories

Dev server: http://localhost:5173 | Claude proxy: http://localhost:3141

Core Philosophy

  • Open source only — MIT/Apache-2.0 licensed dependencies only
  • Decentralized-first — Pluggable adapters, no vendor lock-in
  • Bitcoin only — sats/Lightning/Cashu/Fedimint. Never fiat, never altcoins. AIUI is never a wallet — always deep-link to external wallets
  • Privacy-first — E2E encryption (tweetnacl.js), encrypted local storage (AES-256-GCM), no tracking/telemetry
  • Mobile-first, everywhere-perfect — Desktop is an enhancement of the mobile experience
  • Plugin-everything — All integrations go through typed plugin interfaces

Vue 3 Conventions

Always use <script setup lang="ts"> — never Options API.

Script section ordering

Imports → Props (defineProps) → Emits (defineEmits) → Reactive state → Computed → Watchers → Methods → Lifecycle hooks → defineExpose

Naming

Thing Convention Example
Components PascalCase ProjectCard.vue
Composables camelCase, use prefix useTheme.ts
Props (JS) camelCase projectName
Props (template) kebab-case project-name
Boolean props is/has/can/should prefix isVisible, canEdit
Emits (template) kebab-case with colon namespacing project:updated
Stores camelCase, use prefix, Store suffix useSettingsStore

Reactive state rules

  • ref() for primitives, reactive() for objects
  • computed() for derived values — no side effects in computed
  • shallowRef() for large collections/objects not requiring deep reactivity
  • Always use unique IDs for :key — never array index

Props

Always use object-style with type annotations, never array-style:

// Correct
defineProps<{ title: string; count?: number }>()

// Wrong
defineProps(['title', 'count'])

Performance

  • Lazy load with defineAsyncComponent for non-critical components
  • Use onErrorCaptured for error boundaries
  • Always handle loading/error/data states in async operations

File Structure

packages/app/src/
├── components/
│   ├── ui/              # Generic UI components
│   ├── chat/            # Chat interface components
│   ├── content-panel/   # Content panel components
│   ├── renderers/       # Content type renderers
│   └── layout/          # Layout components
├── composables/         # Shared composition functions
├── stores/              # Pinia stores
├── pages/               # Route-level components
├── styles/              # Global CSS, themes, tokens
├── utils/               # Pure utility functions
├── types/               # TypeScript type definitions
├── plugins/             # Plugin system
└── mocks/               # Dev fixtures & mock data

packages/core/src/
├── plugins/             # Plugin system interfaces
└── types/               # Shared TypeScript types

Tailwind & Design System

Glass Morphism (Archy-derived)

This project uses a glass morphism design language. Key utility classes:

Class Purpose
.glass Standard glass: rgba(0,0,0,0.35), blur(18px), white border 0.18 opacity
.glass-strong Stronger blur: blur(24px)
.glass-card Card variant: rgba(0,0,0,0.65), border-radius: 1rem
.glass-button Button: 48px height, rgba(0,0,0,0.6), blur(18px)
.glass-button-sm Compact button variant
.gradient-button Primary action gradient button
.gradient-card Gradient background card

Spacing

4px grid system: 1=4px, 2=8px, 3=12px, 4=16px, etc.

Colors

  • Background: #0a0a0a (near-black)
  • Accent / Bitcoin orange: #F7931A
  • Primary: #606060
  • Text opacity scale: /25 (placeholder) → /40 (muted) → /60 (secondary) → /70 (interactive) → /80 (body) → /90 (emphasis) → /96 (headings) → text-white (active)
  • No separator borders between major sections

Typography

Inter/system-ui for body, Menlo/Monaco for monospace.

Responsive breakpoints (mobile-first)

sm 640px → md 768px → lg 1024px → xl 1280px → 2xl 1536px

Animations

  • animate-fade-up (900ms), animate-fade-up-fast (400ms), animate-fade-in (500ms), animate-scale-in (250ms)
  • Duration: 100ms micro, 200ms fast, 300ms moderate, 500ms normal, 600ms max
  • Easing: ease-out for entrances (90% of animations), ease-in for exits
  • Only animate transform and opacity — avoid animating layout properties
  • Always respect prefers-reduced-motion

Content Surfaces Architecture

Every content renderer supports up to five surfaces:

  1. Chat Preview (~120px max) — inline bubble, identify content at a glance
  2. Chat Play (~200px max) — inline playback with expand button
  3. Panel Preview (unlimited) — full browsing, filtering, sorting
  4. Panel Play — full immersive playback
  5. Panel Edit — full interaction, sends changes back to chat

On mobile, Panel surfaces open as full-screen overlays, not side-by-side.

interface RendererDefinition {
  id: string
  name: string
  contentType: string
  surfaces: SurfaceType[]
  chatPreview?: Component
  chatPlay?: Component
  panelPreview?: Component
  panelPlay?: Component
  panelEdit?: Component
  lazyDependencies?: () => Promise<any>
}

Chat surfaces must have zero lazy dependencies. Panel surfaces may lazy-load heavy libraries.

Plugin System

All integrations are plugins. Plugin types: ai-provider, media-source, messaging, storage, renderer, file-handler, crypto, search, auth, wallet, social-embed, mcp, media.

interface AIUIPlugin {
  id: string
  name: string
  version: string
  type: PluginType
  description?: string
  init(context: PluginContext): Promise<void>
  destroy(): Promise<void>
  isAvailable(): Promise<boolean>
}

Sandboxing: Tier 1 (trusted built-in), Tier 2 (community — sandboxed iframes), Tier 3 (external processes). Community plugins get no direct DOM access.

AI Provider Integration

interface AIProviderAdapter extends AIUIPlugin {
  type: 'ai-provider'
  chat(messages: Message[], options: ChatOptions): AsyncIterable<ChatChunk>
  models(): Promise<Model[]>
  supportsStreaming: boolean
  supportsVision: boolean
  supportsTools: boolean
}

Normalize tool calling across providers (OpenAI tool_calls vs Claude tool_use). Never include API keys in context injection.

Security & Crypto

  • E2E encryption: tweetnacl.js XSalsa20-Poly1305
  • Local storage: Web Crypto API AES-256-GCM + PBKDF2 (100K+ iterations)
  • API keys: encrypted at rest, never in localStorage, never logged, masked in UI (last 4 chars)
  • No eval() or innerHTML with untrusted content
  • Sanitize all user input against XSS
  • HTTPS only, CSP headers in production
  • Dev bypass: VITE_DISABLE_CRYPTO=true (never in production)

Accessibility

WCAG AA minimum compliance:

  • Color contrast: 4.5:1 normal text, 3:1 large/interactive
  • Keyboard: all elements focusable via Tab, visible focus indicators, Escape closes modals
  • Semantic HTML: use <header>, <nav>, <main>, <article>, <aside>, <footer> — not div soup
  • ARIA: aria-label for icon buttons, aria-live="polite" for dynamic updates, sr-only for screen reader text
  • Touch targets: min 44x44px with 8px gaps
  • All images need alt attributes (decorative: alt="")
  • Respect prefers-reduced-motion

Performance Budget

  • Initial load: < 250KB gzipped
  • Core bundle: Vue + Tailwind + Pinia + Router + chat UI (~150KB) + markdown + streaming (~50KB)
  • Everything else: lazy-loaded on demand
  • Virtual scrolling (TanStack Virtual) for chat lists
  • Clean up listeners in onUnmounted, use shallowRef for large data
  • Core Web Vitals: LCP < 2.5s, FID < 100ms, CLS < 0.1
  • Preconnect to API hosts, debounce inputs (100ms)

Mobile UX

  • Primary actions in bottom thumb zone
  • Touch targets: min 44x44px, 8px gap between targets
  • Viewport: height: 100dvh with safe area insets
  • Form inputs: min 16px font (prevents iOS zoom), appropriate inputmode
  • Content panels: full-screen overlay or bottom sheet on mobile
  • Support both portrait and landscape

Environment & Dev Mode

Env vars must be prefixed VITE_. Secrets go in .env.local (gitignored). See .env.example for template.

Feature flags via useFeatureFlags(): isDev, isTauri, isMobile, isCryptoEnabled, isMockData

Dev mode enables: mock data, debug panel, verbose logging, disabled encryption, all renderers without lazy loading.

Git Conventions

Commit format

type(scope): description

Types: feat, fix, refactor, style, docs, test, chore, perf Scope: package or area — core, app, chat, renderer-film, plugin-x

Branches

main (production), dev (integration), feat/description, fix/description

Rules

  • One feature per PR
  • All tests pass, TypeScript strict passes, no lint errors
  • No force push to main/dev
  • Never commit .env.local, secrets, or node_modules
  • Squash merge features, tag releases v1.0.0