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

283 lines
9.8 KiB
Markdown

# 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
```bash
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:
```ts
// 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.
```ts
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`.
```ts
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
```ts
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`