{"owner":"21st-dev","repo":"1code","hasSkills":true,"totalSkillsCount":3,"totalTokensCount":6428,"categories":["claude-rule","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md","AGENTS.md","openspec/AGENTS.md"],"skills":{"CLAUDE.md":"<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->\n\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## What is this?\n\n**21st Agents** - A local-first Electron desktop app for AI-powered code assistance. Users create chat sessions linked to local project folders, interact with Claude in Plan or Agent mode, and see real-time tool execution (bash, file edits, web search, etc.).\n\n## Commands\n\n```bash\n# Development\nbun run dev              # Start Electron with hot reload\n\n# Build\nbun run build            # Compile app\nbun run package          # Package for current platform (dir)\nbun run package:mac      # Build macOS (DMG + ZIP)\nbun run package:win      # Build Windows (NSIS + portable)\nbun run package:linux    # Build Linux (AppImage + DEB)\n\n# Database (Drizzle + SQLite)\nbun run db:generate      # Generate migrations from schema\nbun run db:push          # Push schema directly (dev only)\n```\n\n## Architecture\n\n```\nsrc/\n├── main/                    # Electron main process\n│   ├── index.ts             # App entry, window lifecycle\n│   ├── auth-manager.ts      # OAuth flow, token refresh\n│   ├── auth-store.ts        # Encrypted credential storage (safeStorage)\n│   ├── windows/main.ts      # Window creation, IPC handlers\n│   └── lib/\n│       ├── db/              # Drizzle + SQLite\n│       │   ├── index.ts     # DB init, auto-migrate on startup\n│       │   ├── schema/      # Drizzle table definitions\n│       │   └── utils.ts     # ID generation\n│       └── trpc/routers/    # tRPC routers (projects, chats, claude)\n│\n├── preload/                 # IPC bridge (context isolation)\n│   └── index.ts             # Exposes desktopApi + tRPC bridge\n│\n└── renderer/                # React 19 UI\n    ├── App.tsx              # Root with providers\n    ├── features/\n    │   ├── agents/          # Main chat interface\n    │   │   ├── main/        # active-chat.tsx, new-chat-form.tsx\n    │   │   ├── ui/          # Tool renderers, preview, diff view\n    │   │   ├── commands/    # Slash commands (/plan, /agent, /clear)\n    │   │   ├── atoms/       # Jotai atoms for agent state\n    │   │   └── stores/      # Zustand store for sub-chats\n    │   ├── sidebar/         # Chat list, archive, navigation\n    │   ├── sub-chats/       # Tab/sidebar sub-chat management\n    │   └── layout/          # Main layout with resizable panels\n    ├── components/ui/       # Radix UI wrappers (button, dialog, etc.)\n    └── lib/\n        ├── atoms/           # Global Jotai atoms\n        ├── stores/          # Global Zustand stores\n        ├── trpc.ts          # Real tRPC client\n        └── mock-api.ts      # DEPRECATED - being replaced with real tRPC\n```\n\n## Database (Drizzle ORM)\n\n**Location:** `{userData}/data/agents.db` (SQLite)\n\n**Schema:** `src/main/lib/db/schema/index.ts`\n\n```typescript\n// Three main tables:\nprojects    → id, name, path (local folder), timestamps\nchats       → id, name, projectId, worktree fields, timestamps\nsub_chats   → id, name, chatId, sessionId, mode, messages (JSON)\n```\n\n**Auto-migration:** On app start, `initDatabase()` runs migrations from `drizzle/` folder (dev) or `resources/migrations` (packaged).\n\n**Queries:**\n```typescript\nimport { getDatabase, projects, chats } from \"../lib/db\"\nimport { eq } from \"drizzle-orm\"\n\nconst db = getDatabase()\nconst allProjects = db.select().from(projects).all()\nconst projectChats = db.select().from(chats).where(eq(chats.projectId, id)).all()\n```\n\n## Key Patterns\n\n### IPC Communication\n- Uses **tRPC** with `trpc-electron` for type-safe main↔renderer communication\n- All backend calls go through tRPC routers, not raw IPC\n- Preload exposes `window.desktopApi` for native features (window controls, clipboard, notifications)\n\n### State Management\n- **Jotai**: UI state (selected chat, sidebar open, preview settings)\n- **Zustand**: Sub-chat tabs and pinned state (persisted to localStorage)\n- **React Query**: Server state via tRPC (auto-caching, refetch)\n\n### Claude Integration\n- Dynamic import of `@anthropic-ai/claude-code` SDK\n- Two modes: \"plan\" (read-only) and \"agent\" (full permissions)\n- Session resume via `sessionId` stored in SubChat\n- Message streaming via tRPC subscription (`claude.onMessage`)\n\n## Tech Stack\n\n| Layer | Tech |\n|-------|------|\n| Desktop | Electron 33.4.5, electron-vite, electron-builder |\n| UI | React 19, TypeScript 5.4.5, Tailwind CSS |\n| Components | Radix UI, Lucide icons, Motion, Sonner |\n| State | Jotai, Zustand, React Query |\n| Backend | tRPC, Drizzle ORM, better-sqlite3 |\n| AI | @anthropic-ai/claude-code |\n| Package Manager | bun |\n\n## File Naming\n\n- Components: PascalCase (`ActiveChat.tsx`, `AgentsSidebar.tsx`)\n- Utilities/hooks: camelCase (`useFileUpload.ts`, `formatters.ts`)\n- Stores: kebab-case (`sub-chat-store.ts`, `agent-chat-store.ts`)\n- Atoms: camelCase with `Atom` suffix (`selectedAgentChatIdAtom`)\n\n## Important Files\n\n- `electron.vite.config.ts` - Build config (main/preload/renderer entries)\n- `src/main/lib/db/schema/index.ts` - Drizzle schema (source of truth)\n- `src/main/lib/db/index.ts` - DB initialization + auto-migrate\n- `src/renderer/features/agents/atoms/index.ts` - Agent UI state atoms\n- `src/renderer/features/agents/main/active-chat.tsx` - Main chat component\n- `src/main/lib/trpc/routers/claude.ts` - Claude SDK integration\n\n## Debugging First Install Issues\n\nWhen testing auth flows or behavior for new users, you need to simulate a fresh install:\n\n```bash\n# 1. Clear all app data (auth, database, settings)\nrm -rf ~/Library/Application\\ Support/Agents\\ Dev/\n\n# 2. Reset macOS protocol handler registration (if testing deep links)\n/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user\n\n# 3. Clear app preferences\ndefaults delete dev.21st.agents.dev  # Dev mode\ndefaults delete dev.21st.agents      # Production\n\n# 4. Run in dev mode with clean state\ncd apps/desktop\nbun run dev\n```\n\n**Common First-Install Bugs:**\n- **OAuth deep link not working**: macOS Launch Services may not immediately recognize protocol handlers on first app launch. User may need to click \"Sign in\" again after the first attempt.\n- **Folder dialog not appearing**: Window focus timing issues on first launch. Fixed by ensuring window focus before showing `dialog.showOpenDialog()`.\n\n**Dev vs Production App:**\n- Dev mode uses `twentyfirst-agents-dev://` protocol\n- Dev mode uses separate userData path (`~/Library/Application Support/Agents Dev/`)\n- This prevents conflicts between dev and production installs\n\n## Releasing a New Version\n\n### Prerequisites for Notarization\n\n- Keychain profile: `21st-notarize`\n- Create with: `xcrun notarytool store-credentials \"21st-notarize\" --apple-id YOUR_APPLE_ID --team-id YOUR_TEAM_ID`\n\n### Release Commands\n\n```bash\n# Full release (build, sign, submit notarization, upload to CDN)\nbun run release\n\n# Or step by step:\nbun run build              # Compile TypeScript\nbun run package:mac        # Build & sign macOS app\nbun run dist:manifest      # Generate latest-mac.yml manifests\n./scripts/upload-release-wrangler.sh  # Submit notarization & upload to R2 CDN\n```\n\n### Bump Version Before Release\n\n```bash\nnpm version patch --no-git-tag-version  # 0.0.27 → 0.0.28\n```\n\n### After Release Script Completes\n\n1. Wait for notarization (2-5 min): `xcrun notarytool history --keychain-profile \"21st-notarize\"`\n2. Staple DMGs: `cd release && xcrun stapler staple *.dmg`\n3. Re-upload stapled DMGs to R2 and GitHub (see RELEASE.md for commands)\n4. Update changelog: `gh release edit v0.0.X --notes \"...\"`\n5. **Upload manifests (triggers auto-updates!)** — see RELEASE.md\n6. Sync to public: `./scripts/sync-to-public.sh`\n\n### Files Uploaded to CDN\n\n| File | Purpose |\n|------|---------|\n| `latest-mac.yml` | Manifest for arm64 auto-updates |\n| `latest-mac-x64.yml` | Manifest for Intel auto-updates |\n| `1Code-{version}-arm64-mac.zip` | Auto-update payload (arm64) |\n| `1Code-{version}-mac.zip` | Auto-update payload (Intel) |\n| `1Code-{version}-arm64.dmg` | Manual download (arm64) |\n| `1Code-{version}.dmg` | Manual download (Intel) |\n\n### Auto-Update Flow\n\n1. App checks `https://cdn.21st.dev/releases/desktop/latest-mac.yml` on startup and when window regains focus (with 1 min cooldown)\n2. If version in manifest > current version, shows \"Update Available\" banner\n3. User clicks Download → downloads ZIP in background\n4. User clicks \"Restart Now\" → installs update and restarts\n\n## Current Status (WIP)\n\n**Done:**\n- Drizzle ORM setup with schema (projects, chats, sub_chats)\n- Auto-migration on app startup\n- tRPC routers structure\n\n**In Progress:**\n- Replacing `mock-api.ts` with real tRPC calls in renderer\n- ProjectSelector component (local folder picker)\n\n**Planned:**\n- Git worktree per chat (isolation)\n- Claude Code execution in worktree path\n- Full feature parity with web app\n\n## Debug Mode\n\nWhen debugging runtime issues in the renderer or main process, use the structured debug logging system. This avoids asking the user to manually copy-paste console output.\n\n**Start the server:**\n```bash\nbun packages/debug/src/server.ts &\n```\n\n**Instrument renderer code** (no import needed, fails silently):\n```js\nfetch('http://localhost:7799/log',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({tag:'TAG',msg:'MESSAGE',data:{},ts:Date.now()})}).catch(()=>{});\n```\n\n**Read logs:** Read `.debug/logs.ndjson` - each line is a JSON object with `tag`, `msg`, `data`, `ts`.\n\n**Clear logs:** `curl -X DELETE http://localhost:7799/logs`\n\n**Workflow:** Hypothesize → instrument → user reproduces → read logs → fix with evidence → verify → remove instrumentation.\n\nSee `packages/debug/INSTRUCTIONS.md` for the full protocol.\n","AGENTS.md":"<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->","openspec/AGENTS.md":"# OpenSpec Instructions\n\nInstructions for AI coding assistants using OpenSpec for spec-driven development.\n\n## TL;DR Quick Checklist\n\n- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)\n- Decide scope: new capability vs modify existing capability\n- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)\n- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability\n- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement\n- Validate: `openspec validate [change-id] --strict --no-interactive` and fix issues\n- Request approval: Do not start implementation until proposal is approved\n\n## Three-Stage Workflow\n\n### Stage 1: Creating Changes\nCreate proposal when you need to:\n- Add features or functionality\n- Make breaking changes (API, schema)\n- Change architecture or patterns  \n- Optimize performance (changes behavior)\n- Update security patterns\n\nTriggers (examples):\n- \"Help me create a change proposal\"\n- \"Help me plan a change\"\n- \"Help me create a proposal\"\n- \"I want to create a spec proposal\"\n- \"I want to create a spec\"\n\nLoose matching guidance:\n- Contains one of: `proposal`, `change`, `spec`\n- With one of: `create`, `plan`, `make`, `start`, `help`\n\nSkip proposal for:\n- Bug fixes (restore intended behavior)\n- Typos, formatting, comments\n- Dependency updates (non-breaking)\n- Configuration changes\n- Tests for existing behavior\n\n**Workflow**\n1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.\n2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.\n3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.\n4. Run `openspec validate <id> --strict --no-interactive` and resolve any issues before sharing the proposal.\n\n### Stage 2: Implementing Changes\nTrack these steps as TODOs and complete them one by one.\n1. **Read proposal.md** - Understand what's being built\n2. **Read design.md** (if exists) - Review technical decisions\n3. **Read tasks.md** - Get implementation checklist\n4. **Implement tasks sequentially** - Complete in order\n5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses\n6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality\n7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved\n\n### Stage 3: Archiving Changes\nAfter deployment, create separate PR to:\n- Move `changes/[name]/` → `changes/archive/YYYY-MM-DD-[name]/`\n- Update `specs/` if capabilities changed\n- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)\n- Run `openspec validate --strict --no-interactive` to confirm the archived change passes checks\n\n## Before Any Task\n\n**Context Checklist:**\n- [ ] Read relevant specs in `specs/[capability]/spec.md`\n- [ ] Check pending changes in `changes/` for conflicts\n- [ ] Read `openspec/project.md` for conventions\n- [ ] Run `openspec list` to see active changes\n- [ ] Run `openspec list --specs` to see existing capabilities\n\n**Before Creating Specs:**\n- Always check if capability already exists\n- Prefer modifying existing specs over creating duplicates\n- Use `openspec show [spec]` to review current state\n- If request is ambiguous, ask 1–2 clarifying questions before scaffolding\n\n### Search Guidance\n- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)\n- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)\n- Show details:\n  - Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)\n  - Change: `openspec show <change-id> --json --deltas-only`\n- Full-text search (use ripgrep): `rg -n \"Requirement:|Scenario:\" openspec/specs`\n\n## Quick Start\n\n### CLI Commands\n\n```bash\n# Essential commands\nopenspec list                  # List active changes\nopenspec list --specs          # List specifications\nopenspec show [item]           # Display change or spec\nopenspec validate [item]       # Validate changes or specs\nopenspec archive <change-id> [--yes|-y]   # Archive after deployment (add --yes for non-interactive runs)\n\n# Project management\nopenspec init [path]           # Initialize OpenSpec\nopenspec update [path]         # Update instruction files\n\n# Interactive mode\nopenspec show                  # Prompts for selection\nopenspec validate              # Bulk validation mode\n\n# Debugging\nopenspec show [change] --json --deltas-only\nopenspec validate [change] --strict --no-interactive\n```\n\n### Command Flags\n\n- `--json` - Machine-readable output\n- `--type change|spec` - Disambiguate items\n- `--strict` - Comprehensive validation\n- `--no-interactive` - Disable prompts\n- `--skip-specs` - Archive without spec updates\n- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)\n\n## Directory Structure\n\n```\nopenspec/\n├── project.md              # Project conventions\n├── specs/                  # Current truth - what IS built\n│   └── [capability]/       # Single focused capability\n│       ├── spec.md         # Requirements and scenarios\n│       └── design.md       # Technical patterns\n├── changes/                # Proposals - what SHOULD change\n│   ├── [change-name]/\n│   │   ├── proposal.md     # Why, what, impact\n│   │   ├── tasks.md        # Implementation checklist\n│   │   ├── design.md       # Technical decisions (optional; see criteria)\n│   │   └── specs/          # Delta changes\n│   │       └── [capability]/\n│   │           └── spec.md # ADDED/MODIFIED/REMOVED\n│   └── archive/            # Completed changes\n```\n\n## Creating Change Proposals\n\n### Decision Tree\n\n```\nNew request?\n├─ Bug fix restoring spec behavior? → Fix directly\n├─ Typo/format/comment? → Fix directly  \n├─ New feature/capability? → Create proposal\n├─ Breaking change? → Create proposal\n├─ Architecture change? → Create proposal\n└─ Unclear? → Create proposal (safer)\n```\n\n### Proposal Structure\n\n1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)\n\n2. **Write proposal.md:**\n```markdown\n# Change: [Brief description of change]\n\n## Why\n[1-2 sentences on problem/opportunity]\n\n## What Changes\n- [Bullet list of changes]\n- [Mark breaking changes with **BREAKING**]\n\n## Impact\n- Affected specs: [list capabilities]\n- Affected code: [key files/systems]\n```\n\n3. **Create spec deltas:** `specs/[capability]/spec.md`\n```markdown\n## ADDED Requirements\n### Requirement: New Feature\nThe system SHALL provide...\n\n#### Scenario: Success case\n- **WHEN** user performs action\n- **THEN** expected result\n\n## MODIFIED Requirements\n### Requirement: Existing Feature\n[Complete modified requirement]\n\n## REMOVED Requirements\n### Requirement: Old Feature\n**Reason**: [Why removing]\n**Migration**: [How to handle]\n```\nIf multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.\n\n4. **Create tasks.md:**\n```markdown\n## 1. Implementation\n- [ ] 1.1 Create database schema\n- [ ] 1.2 Implement API endpoint\n- [ ] 1.3 Add frontend component\n- [ ] 1.4 Write tests\n```\n\n5. **Create design.md when needed:**\nCreate `design.md` if any of the following apply; otherwise omit it:\n- Cross-cutting change (multiple services/modules) or a new architectural pattern\n- New external dependency or significant data model changes\n- Security, performance, or migration complexity\n- Ambiguity that benefits from technical decisions before coding\n\nMinimal `design.md` skeleton:\n```markdown\n## Context\n[Background, constraints, stakeholders]\n\n## Goals / Non-Goals\n- Goals: [...]\n- Non-Goals: [...]\n\n## Decisions\n- Decision: [What and why]\n- Alternatives considered: [Options + rationale]\n\n## Risks / Trade-offs\n- [Risk] → Mitigation\n\n## Migration Plan\n[Steps, rollback]\n\n## Open Questions\n- [...]\n```\n\n## Spec File Format\n\n### Critical: Scenario Formatting\n\n**CORRECT** (use #### headers):\n```markdown\n#### Scenario: User login success\n- **WHEN** valid credentials provided\n- **THEN** return JWT token\n```\n\n**WRONG** (don't use bullets or bold):\n```markdown\n- **Scenario: User login**  ❌\n**Scenario**: User login     ❌\n### Scenario: User login      ❌\n```\n\nEvery requirement MUST have at least one scenario.\n\n### Requirement Wording\n- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)\n\n### Delta Operations\n\n- `## ADDED Requirements` - New capabilities\n- `## MODIFIED Requirements` - Changed behavior\n- `## REMOVED Requirements` - Deprecated features\n- `## RENAMED Requirements` - Name changes\n\nHeaders matched with `trim(header)` - whitespace ignored.\n\n#### When to use ADDED vs MODIFIED\n- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding \"Slash Command Configuration\") rather than altering the semantics of an existing requirement.\n- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.\n- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.\n\nCommon pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren’t explicitly changing the existing requirement, add a new requirement under ADDED instead.\n\nAuthoring a MODIFIED requirement correctly:\n1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.\n2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).\n3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.\n4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.\n\nExample for RENAMED:\n```markdown\n## RENAMED Requirements\n- FROM: `### Requirement: Login`\n- TO: `### Requirement: User Authentication`\n```\n\n## Troubleshooting\n\n### Common Errors\n\n**\"Change must have at least one delta\"**\n- Check `changes/[name]/specs/` exists with .md files\n- Verify files have operation prefixes (## ADDED Requirements)\n\n**\"Requirement must have at least one scenario\"**\n- Check scenarios use `#### Scenario:` format (4 hashtags)\n- Don't use bullet points or bold for scenario headers\n\n**Silent scenario parsing failures**\n- Exact format required: `#### Scenario: Name`\n- Debug with: `openspec show [change] --json --deltas-only`\n\n### Validation Tips\n\n```bash\n# Always use strict mode for comprehensive checks\nopenspec validate [change] --strict --no-interactive\n\n# Debug delta parsing\nopenspec show [change] --json | jq '.deltas'\n\n# Check specific requirement\nopenspec show [spec] --json -r 1\n```\n\n## Happy Path Script\n\n```bash\n# 1) Explore current state\nopenspec spec list --long\nopenspec list\n# Optional full-text search:\n# rg -n \"Requirement:|Scenario:\" openspec/specs\n# rg -n \"^#|Requirement:\" openspec/changes\n\n# 2) Choose change id and scaffold\nCHANGE=add-two-factor-auth\nmkdir -p openspec/changes/$CHANGE/{specs/auth}\nprintf \"## Why\\n...\\n\\n## What Changes\\n- ...\\n\\n## Impact\\n- ...\\n\" > openspec/changes/$CHANGE/proposal.md\nprintf \"## 1. Implementation\\n- [ ] 1.1 ...\\n\" > openspec/changes/$CHANGE/tasks.md\n\n# 3) Add deltas (example)\ncat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\nUsers MUST provide a second factor during login.\n\n#### Scenario: OTP required\n- **WHEN** valid credentials are provided\n- **THEN** an OTP challenge is required\nEOF\n\n# 4) Validate\nopenspec validate $CHANGE --strict --no-interactive\n```\n\n## Multi-Capability Example\n\n```\nopenspec/changes/add-2fa-notify/\n├── proposal.md\n├── tasks.md\n└── specs/\n    ├── auth/\n    │   └── spec.md   # ADDED: Two-Factor Authentication\n    └── notifications/\n        └── spec.md   # ADDED: OTP email notification\n```\n\nauth/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\n...\n```\n\nnotifications/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: OTP Email Notification\n...\n```\n\n## Best Practices\n\n### Simplicity First\n- Default to <100 lines of new code\n- Single-file implementations until proven insufficient\n- Avoid frameworks without clear justification\n- Choose boring, proven patterns\n\n### Complexity Triggers\nOnly add complexity with:\n- Performance data showing current solution too slow\n- Concrete scale requirements (>1000 users, >100MB data)\n- Multiple proven use cases requiring abstraction\n\n### Clear References\n- Use `file.ts:42` format for code locations\n- Reference specs as `specs/auth/spec.md`\n- Link related changes and PRs\n\n### Capability Naming\n- Use verb-noun: `user-auth`, `payment-capture`\n- Single purpose per capability\n- 10-minute understandability rule\n- Split if description needs \"AND\"\n\n### Change ID Naming\n- Use kebab-case, short and descriptive: `add-two-factor-auth`\n- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`\n- Ensure uniqueness; if taken, append `-2`, `-3`, etc.\n\n## Tool Selection Guide\n\n| Task | Tool | Why |\n|------|------|-----|\n| Find files by pattern | Glob | Fast pattern matching |\n| Search code content | Grep | Optimized regex search |\n| Read specific files | Read | Direct file access |\n| Explore unknown scope | Task | Multi-step investigation |\n\n## Error Recovery\n\n### Change Conflicts\n1. Run `openspec list` to see active changes\n2. Check for overlapping specs\n3. Coordinate with change owners\n4. Consider combining proposals\n\n### Validation Failures\n1. Run with `--strict` flag\n2. Check JSON output for details\n3. Verify spec file format\n4. Ensure scenarios properly formatted\n\n### Missing Context\n1. Read project.md first\n2. Check related specs\n3. Review recent archives\n4. Ask for clarification\n\n## Quick Reference\n\n### Stage Indicators\n- `changes/` - Proposed, not yet built\n- `specs/` - Built and deployed\n- `archive/` - Completed changes\n\n### File Purposes\n- `proposal.md` - Why and what\n- `tasks.md` - Implementation steps\n- `design.md` - Technical decisions\n- `spec.md` - Requirements and behavior\n\n### CLI Essentials\n```bash\nopenspec list              # What's in progress?\nopenspec show [item]       # View details\nopenspec validate --strict --no-interactive  # Is it correct?\nopenspec archive <change-id> [--yes|-y]  # Mark complete (add --yes for automation)\n```\n\nRemember: Specs are truth. Changes are proposals. Keep them in sync.\n"},"files":{"CLAUDE.md":"<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->\n\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## What is this?\n\n**21st Agents** - A local-first Electron desktop app for AI-powered code assistance. Users create chat sessions linked to local project folders, interact with Claude in Plan or Agent mode, and see real-time tool execution (bash, file edits, web search, etc.).\n\n## Commands\n\n```bash\n# Development\nbun run dev              # Start Electron with hot reload\n\n# Build\nbun run build            # Compile app\nbun run package          # Package for current platform (dir)\nbun run package:mac      # Build macOS (DMG + ZIP)\nbun run package:win      # Build Windows (NSIS + portable)\nbun run package:linux    # Build Linux (AppImage + DEB)\n\n# Database (Drizzle + SQLite)\nbun run db:generate      # Generate migrations from schema\nbun run db:push          # Push schema directly (dev only)\n```\n\n## Architecture\n\n```\nsrc/\n├── main/                    # Electron main process\n│   ├── index.ts             # App entry, window lifecycle\n│   ├── auth-manager.ts      # OAuth flow, token refresh\n│   ├── auth-store.ts        # Encrypted credential storage (safeStorage)\n│   ├── windows/main.ts      # Window creation, IPC handlers\n│   └── lib/\n│       ├── db/              # Drizzle + SQLite\n│       │   ├── index.ts     # DB init, auto-migrate on startup\n│       │   ├── schema/      # Drizzle table definitions\n│       │   └── utils.ts     # ID generation\n│       └── trpc/routers/    # tRPC routers (projects, chats, claude)\n│\n├── preload/                 # IPC bridge (context isolation)\n│   └── index.ts             # Exposes desktopApi + tRPC bridge\n│\n└── renderer/                # React 19 UI\n    ├── App.tsx              # Root with providers\n    ├── features/\n    │   ├── agents/          # Main chat interface\n    │   │   ├── main/        # active-chat.tsx, new-chat-form.tsx\n    │   │   ├── ui/          # Tool renderers, preview, diff view\n    │   │   ├── commands/    # Slash commands (/plan, /agent, /clear)\n    │   │   ├── atoms/       # Jotai atoms for agent state\n    │   │   └── stores/      # Zustand store for sub-chats\n    │   ├── sidebar/         # Chat list, archive, navigation\n    │   ├── sub-chats/       # Tab/sidebar sub-chat management\n    │   └── layout/          # Main layout with resizable panels\n    ├── components/ui/       # Radix UI wrappers (button, dialog, etc.)\n    └── lib/\n        ├── atoms/           # Global Jotai atoms\n        ├── stores/          # Global Zustand stores\n        ├── trpc.ts          # Real tRPC client\n        └── mock-api.ts      # DEPRECATED - being replaced with real tRPC\n```\n\n## Database (Drizzle ORM)\n\n**Location:** `{userData}/data/agents.db` (SQLite)\n\n**Schema:** `src/main/lib/db/schema/index.ts`\n\n```typescript\n// Three main tables:\nprojects    → id, name, path (local folder), timestamps\nchats       → id, name, projectId, worktree fields, timestamps\nsub_chats   → id, name, chatId, sessionId, mode, messages (JSON)\n```\n\n**Auto-migration:** On app start, `initDatabase()` runs migrations from `drizzle/` folder (dev) or `resources/migrations` (packaged).\n\n**Queries:**\n```typescript\nimport { getDatabase, projects, chats } from \"../lib/db\"\nimport { eq } from \"drizzle-orm\"\n\nconst db = getDatabase()\nconst allProjects = db.select().from(projects).all()\nconst projectChats = db.select().from(chats).where(eq(chats.projectId, id)).all()\n```\n\n## Key Patterns\n\n### IPC Communication\n- Uses **tRPC** with `trpc-electron` for type-safe main↔renderer communication\n- All backend calls go through tRPC routers, not raw IPC\n- Preload exposes `window.desktopApi` for native features (window controls, clipboard, notifications)\n\n### State Management\n- **Jotai**: UI state (selected chat, sidebar open, preview settings)\n- **Zustand**: Sub-chat tabs and pinned state (persisted to localStorage)\n- **React Query**: Server state via tRPC (auto-caching, refetch)\n\n### Claude Integration\n- Dynamic import of `@anthropic-ai/claude-code` SDK\n- Two modes: \"plan\" (read-only) and \"agent\" (full permissions)\n- Session resume via `sessionId` stored in SubChat\n- Message streaming via tRPC subscription (`claude.onMessage`)\n\n## Tech Stack\n\n| Layer | Tech |\n|-------|------|\n| Desktop | Electron 33.4.5, electron-vite, electron-builder |\n| UI | React 19, TypeScript 5.4.5, Tailwind CSS |\n| Components | Radix UI, Lucide icons, Motion, Sonner |\n| State | Jotai, Zustand, React Query |\n| Backend | tRPC, Drizzle ORM, better-sqlite3 |\n| AI | @anthropic-ai/claude-code |\n| Package Manager | bun |\n\n## File Naming\n\n- Components: PascalCase (`ActiveChat.tsx`, `AgentsSidebar.tsx`)\n- Utilities/hooks: camelCase (`useFileUpload.ts`, `formatters.ts`)\n- Stores: kebab-case (`sub-chat-store.ts`, `agent-chat-store.ts`)\n- Atoms: camelCase with `Atom` suffix (`selectedAgentChatIdAtom`)\n\n## Important Files\n\n- `electron.vite.config.ts` - Build config (main/preload/renderer entries)\n- `src/main/lib/db/schema/index.ts` - Drizzle schema (source of truth)\n- `src/main/lib/db/index.ts` - DB initialization + auto-migrate\n- `src/renderer/features/agents/atoms/index.ts` - Agent UI state atoms\n- `src/renderer/features/agents/main/active-chat.tsx` - Main chat component\n- `src/main/lib/trpc/routers/claude.ts` - Claude SDK integration\n\n## Debugging First Install Issues\n\nWhen testing auth flows or behavior for new users, you need to simulate a fresh install:\n\n```bash\n# 1. Clear all app data (auth, database, settings)\nrm -rf ~/Library/Application\\ Support/Agents\\ Dev/\n\n# 2. Reset macOS protocol handler registration (if testing deep links)\n/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user\n\n# 3. Clear app preferences\ndefaults delete dev.21st.agents.dev  # Dev mode\ndefaults delete dev.21st.agents      # Production\n\n# 4. Run in dev mode with clean state\ncd apps/desktop\nbun run dev\n```\n\n**Common First-Install Bugs:**\n- **OAuth deep link not working**: macOS Launch Services may not immediately recognize protocol handlers on first app launch. User may need to click \"Sign in\" again after the first attempt.\n- **Folder dialog not appearing**: Window focus timing issues on first launch. Fixed by ensuring window focus before showing `dialog.showOpenDialog()`.\n\n**Dev vs Production App:**\n- Dev mode uses `twentyfirst-agents-dev://` protocol\n- Dev mode uses separate userData path (`~/Library/Application Support/Agents Dev/`)\n- This prevents conflicts between dev and production installs\n\n## Releasing a New Version\n\n### Prerequisites for Notarization\n\n- Keychain profile: `21st-notarize`\n- Create with: `xcrun notarytool store-credentials \"21st-notarize\" --apple-id YOUR_APPLE_ID --team-id YOUR_TEAM_ID`\n\n### Release Commands\n\n```bash\n# Full release (build, sign, submit notarization, upload to CDN)\nbun run release\n\n# Or step by step:\nbun run build              # Compile TypeScript\nbun run package:mac        # Build & sign macOS app\nbun run dist:manifest      # Generate latest-mac.yml manifests\n./scripts/upload-release-wrangler.sh  # Submit notarization & upload to R2 CDN\n```\n\n### Bump Version Before Release\n\n```bash\nnpm version patch --no-git-tag-version  # 0.0.27 → 0.0.28\n```\n\n### After Release Script Completes\n\n1. Wait for notarization (2-5 min): `xcrun notarytool history --keychain-profile \"21st-notarize\"`\n2. Staple DMGs: `cd release && xcrun stapler staple *.dmg`\n3. Re-upload stapled DMGs to R2 and GitHub (see RELEASE.md for commands)\n4. Update changelog: `gh release edit v0.0.X --notes \"...\"`\n5. **Upload manifests (triggers auto-updates!)** — see RELEASE.md\n6. Sync to public: `./scripts/sync-to-public.sh`\n\n### Files Uploaded to CDN\n\n| File | Purpose |\n|------|---------|\n| `latest-mac.yml` | Manifest for arm64 auto-updates |\n| `latest-mac-x64.yml` | Manifest for Intel auto-updates |\n| `1Code-{version}-arm64-mac.zip` | Auto-update payload (arm64) |\n| `1Code-{version}-mac.zip` | Auto-update payload (Intel) |\n| `1Code-{version}-arm64.dmg` | Manual download (arm64) |\n| `1Code-{version}.dmg` | Manual download (Intel) |\n\n### Auto-Update Flow\n\n1. App checks `https://cdn.21st.dev/releases/desktop/latest-mac.yml` on startup and when window regains focus (with 1 min cooldown)\n2. If version in manifest > current version, shows \"Update Available\" banner\n3. User clicks Download → downloads ZIP in background\n4. User clicks \"Restart Now\" → installs update and restarts\n\n## Current Status (WIP)\n\n**Done:**\n- Drizzle ORM setup with schema (projects, chats, sub_chats)\n- Auto-migration on app startup\n- tRPC routers structure\n\n**In Progress:**\n- Replacing `mock-api.ts` with real tRPC calls in renderer\n- ProjectSelector component (local folder picker)\n\n**Planned:**\n- Git worktree per chat (isolation)\n- Claude Code execution in worktree path\n- Full feature parity with web app\n\n## Debug Mode\n\nWhen debugging runtime issues in the renderer or main process, use the structured debug logging system. This avoids asking the user to manually copy-paste console output.\n\n**Start the server:**\n```bash\nbun packages/debug/src/server.ts &\n```\n\n**Instrument renderer code** (no import needed, fails silently):\n```js\nfetch('http://localhost:7799/log',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({tag:'TAG',msg:'MESSAGE',data:{},ts:Date.now()})}).catch(()=>{});\n```\n\n**Read logs:** Read `.debug/logs.ndjson` - each line is a JSON object with `tag`, `msg`, `data`, `ts`.\n\n**Clear logs:** `curl -X DELETE http://localhost:7799/logs`\n\n**Workflow:** Hypothesize → instrument → user reproduces → read logs → fix with evidence → verify → remove instrumentation.\n\nSee `packages/debug/INSTRUCTIONS.md` for the full protocol.\n","AGENTS.md":"<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->","openspec/AGENTS.md":"# OpenSpec Instructions\n\nInstructions for AI coding assistants using OpenSpec for spec-driven development.\n\n## TL;DR Quick Checklist\n\n- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)\n- Decide scope: new capability vs modify existing capability\n- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)\n- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability\n- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement\n- Validate: `openspec validate [change-id] --strict --no-interactive` and fix issues\n- Request approval: Do not start implementation until proposal is approved\n\n## Three-Stage Workflow\n\n### Stage 1: Creating Changes\nCreate proposal when you need to:\n- Add features or functionality\n- Make breaking changes (API, schema)\n- Change architecture or patterns  \n- Optimize performance (changes behavior)\n- Update security patterns\n\nTriggers (examples):\n- \"Help me create a change proposal\"\n- \"Help me plan a change\"\n- \"Help me create a proposal\"\n- \"I want to create a spec proposal\"\n- \"I want to create a spec\"\n\nLoose matching guidance:\n- Contains one of: `proposal`, `change`, `spec`\n- With one of: `create`, `plan`, `make`, `start`, `help`\n\nSkip proposal for:\n- Bug fixes (restore intended behavior)\n- Typos, formatting, comments\n- Dependency updates (non-breaking)\n- Configuration changes\n- Tests for existing behavior\n\n**Workflow**\n1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.\n2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.\n3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.\n4. Run `openspec validate <id> --strict --no-interactive` and resolve any issues before sharing the proposal.\n\n### Stage 2: Implementing Changes\nTrack these steps as TODOs and complete them one by one.\n1. **Read proposal.md** - Understand what's being built\n2. **Read design.md** (if exists) - Review technical decisions\n3. **Read tasks.md** - Get implementation checklist\n4. **Implement tasks sequentially** - Complete in order\n5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses\n6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality\n7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved\n\n### Stage 3: Archiving Changes\nAfter deployment, create separate PR to:\n- Move `changes/[name]/` → `changes/archive/YYYY-MM-DD-[name]/`\n- Update `specs/` if capabilities changed\n- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)\n- Run `openspec validate --strict --no-interactive` to confirm the archived change passes checks\n\n## Before Any Task\n\n**Context Checklist:**\n- [ ] Read relevant specs in `specs/[capability]/spec.md`\n- [ ] Check pending changes in `changes/` for conflicts\n- [ ] Read `openspec/project.md` for conventions\n- [ ] Run `openspec list` to see active changes\n- [ ] Run `openspec list --specs` to see existing capabilities\n\n**Before Creating Specs:**\n- Always check if capability already exists\n- Prefer modifying existing specs over creating duplicates\n- Use `openspec show [spec]` to review current state\n- If request is ambiguous, ask 1–2 clarifying questions before scaffolding\n\n### Search Guidance\n- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)\n- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)\n- Show details:\n  - Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)\n  - Change: `openspec show <change-id> --json --deltas-only`\n- Full-text search (use ripgrep): `rg -n \"Requirement:|Scenario:\" openspec/specs`\n\n## Quick Start\n\n### CLI Commands\n\n```bash\n# Essential commands\nopenspec list                  # List active changes\nopenspec list --specs          # List specifications\nopenspec show [item]           # Display change or spec\nopenspec validate [item]       # Validate changes or specs\nopenspec archive <change-id> [--yes|-y]   # Archive after deployment (add --yes for non-interactive runs)\n\n# Project management\nopenspec init [path]           # Initialize OpenSpec\nopenspec update [path]         # Update instruction files\n\n# Interactive mode\nopenspec show                  # Prompts for selection\nopenspec validate              # Bulk validation mode\n\n# Debugging\nopenspec show [change] --json --deltas-only\nopenspec validate [change] --strict --no-interactive\n```\n\n### Command Flags\n\n- `--json` - Machine-readable output\n- `--type change|spec` - Disambiguate items\n- `--strict` - Comprehensive validation\n- `--no-interactive` - Disable prompts\n- `--skip-specs` - Archive without spec updates\n- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)\n\n## Directory Structure\n\n```\nopenspec/\n├── project.md              # Project conventions\n├── specs/                  # Current truth - what IS built\n│   └── [capability]/       # Single focused capability\n│       ├── spec.md         # Requirements and scenarios\n│       └── design.md       # Technical patterns\n├── changes/                # Proposals - what SHOULD change\n│   ├── [change-name]/\n│   │   ├── proposal.md     # Why, what, impact\n│   │   ├── tasks.md        # Implementation checklist\n│   │   ├── design.md       # Technical decisions (optional; see criteria)\n│   │   └── specs/          # Delta changes\n│   │       └── [capability]/\n│   │           └── spec.md # ADDED/MODIFIED/REMOVED\n│   └── archive/            # Completed changes\n```\n\n## Creating Change Proposals\n\n### Decision Tree\n\n```\nNew request?\n├─ Bug fix restoring spec behavior? → Fix directly\n├─ Typo/format/comment? → Fix directly  \n├─ New feature/capability? → Create proposal\n├─ Breaking change? → Create proposal\n├─ Architecture change? → Create proposal\n└─ Unclear? → Create proposal (safer)\n```\n\n### Proposal Structure\n\n1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)\n\n2. **Write proposal.md:**\n```markdown\n# Change: [Brief description of change]\n\n## Why\n[1-2 sentences on problem/opportunity]\n\n## What Changes\n- [Bullet list of changes]\n- [Mark breaking changes with **BREAKING**]\n\n## Impact\n- Affected specs: [list capabilities]\n- Affected code: [key files/systems]\n```\n\n3. **Create spec deltas:** `specs/[capability]/spec.md`\n```markdown\n## ADDED Requirements\n### Requirement: New Feature\nThe system SHALL provide...\n\n#### Scenario: Success case\n- **WHEN** user performs action\n- **THEN** expected result\n\n## MODIFIED Requirements\n### Requirement: Existing Feature\n[Complete modified requirement]\n\n## REMOVED Requirements\n### Requirement: Old Feature\n**Reason**: [Why removing]\n**Migration**: [How to handle]\n```\nIf multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.\n\n4. **Create tasks.md:**\n```markdown\n## 1. Implementation\n- [ ] 1.1 Create database schema\n- [ ] 1.2 Implement API endpoint\n- [ ] 1.3 Add frontend component\n- [ ] 1.4 Write tests\n```\n\n5. **Create design.md when needed:**\nCreate `design.md` if any of the following apply; otherwise omit it:\n- Cross-cutting change (multiple services/modules) or a new architectural pattern\n- New external dependency or significant data model changes\n- Security, performance, or migration complexity\n- Ambiguity that benefits from technical decisions before coding\n\nMinimal `design.md` skeleton:\n```markdown\n## Context\n[Background, constraints, stakeholders]\n\n## Goals / Non-Goals\n- Goals: [...]\n- Non-Goals: [...]\n\n## Decisions\n- Decision: [What and why]\n- Alternatives considered: [Options + rationale]\n\n## Risks / Trade-offs\n- [Risk] → Mitigation\n\n## Migration Plan\n[Steps, rollback]\n\n## Open Questions\n- [...]\n```\n\n## Spec File Format\n\n### Critical: Scenario Formatting\n\n**CORRECT** (use #### headers):\n```markdown\n#### Scenario: User login success\n- **WHEN** valid credentials provided\n- **THEN** return JWT token\n```\n\n**WRONG** (don't use bullets or bold):\n```markdown\n- **Scenario: User login**  ❌\n**Scenario**: User login     ❌\n### Scenario: User login      ❌\n```\n\nEvery requirement MUST have at least one scenario.\n\n### Requirement Wording\n- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)\n\n### Delta Operations\n\n- `## ADDED Requirements` - New capabilities\n- `## MODIFIED Requirements` - Changed behavior\n- `## REMOVED Requirements` - Deprecated features\n- `## RENAMED Requirements` - Name changes\n\nHeaders matched with `trim(header)` - whitespace ignored.\n\n#### When to use ADDED vs MODIFIED\n- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding \"Slash Command Configuration\") rather than altering the semantics of an existing requirement.\n- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.\n- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.\n\nCommon pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren’t explicitly changing the existing requirement, add a new requirement under ADDED instead.\n\nAuthoring a MODIFIED requirement correctly:\n1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.\n2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).\n3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.\n4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.\n\nExample for RENAMED:\n```markdown\n## RENAMED Requirements\n- FROM: `### Requirement: Login`\n- TO: `### Requirement: User Authentication`\n```\n\n## Troubleshooting\n\n### Common Errors\n\n**\"Change must have at least one delta\"**\n- Check `changes/[name]/specs/` exists with .md files\n- Verify files have operation prefixes (## ADDED Requirements)\n\n**\"Requirement must have at least one scenario\"**\n- Check scenarios use `#### Scenario:` format (4 hashtags)\n- Don't use bullet points or bold for scenario headers\n\n**Silent scenario parsing failures**\n- Exact format required: `#### Scenario: Name`\n- Debug with: `openspec show [change] --json --deltas-only`\n\n### Validation Tips\n\n```bash\n# Always use strict mode for comprehensive checks\nopenspec validate [change] --strict --no-interactive\n\n# Debug delta parsing\nopenspec show [change] --json | jq '.deltas'\n\n# Check specific requirement\nopenspec show [spec] --json -r 1\n```\n\n## Happy Path Script\n\n```bash\n# 1) Explore current state\nopenspec spec list --long\nopenspec list\n# Optional full-text search:\n# rg -n \"Requirement:|Scenario:\" openspec/specs\n# rg -n \"^#|Requirement:\" openspec/changes\n\n# 2) Choose change id and scaffold\nCHANGE=add-two-factor-auth\nmkdir -p openspec/changes/$CHANGE/{specs/auth}\nprintf \"## Why\\n...\\n\\n## What Changes\\n- ...\\n\\n## Impact\\n- ...\\n\" > openspec/changes/$CHANGE/proposal.md\nprintf \"## 1. Implementation\\n- [ ] 1.1 ...\\n\" > openspec/changes/$CHANGE/tasks.md\n\n# 3) Add deltas (example)\ncat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\nUsers MUST provide a second factor during login.\n\n#### Scenario: OTP required\n- **WHEN** valid credentials are provided\n- **THEN** an OTP challenge is required\nEOF\n\n# 4) Validate\nopenspec validate $CHANGE --strict --no-interactive\n```\n\n## Multi-Capability Example\n\n```\nopenspec/changes/add-2fa-notify/\n├── proposal.md\n├── tasks.md\n└── specs/\n    ├── auth/\n    │   └── spec.md   # ADDED: Two-Factor Authentication\n    └── notifications/\n        └── spec.md   # ADDED: OTP email notification\n```\n\nauth/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\n...\n```\n\nnotifications/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: OTP Email Notification\n...\n```\n\n## Best Practices\n\n### Simplicity First\n- Default to <100 lines of new code\n- Single-file implementations until proven insufficient\n- Avoid frameworks without clear justification\n- Choose boring, proven patterns\n\n### Complexity Triggers\nOnly add complexity with:\n- Performance data showing current solution too slow\n- Concrete scale requirements (>1000 users, >100MB data)\n- Multiple proven use cases requiring abstraction\n\n### Clear References\n- Use `file.ts:42` format for code locations\n- Reference specs as `specs/auth/spec.md`\n- Link related changes and PRs\n\n### Capability Naming\n- Use verb-noun: `user-auth`, `payment-capture`\n- Single purpose per capability\n- 10-minute understandability rule\n- Split if description needs \"AND\"\n\n### Change ID Naming\n- Use kebab-case, short and descriptive: `add-two-factor-auth`\n- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`\n- Ensure uniqueness; if taken, append `-2`, `-3`, etc.\n\n## Tool Selection Guide\n\n| Task | Tool | Why |\n|------|------|-----|\n| Find files by pattern | Glob | Fast pattern matching |\n| Search code content | Grep | Optimized regex search |\n| Read specific files | Read | Direct file access |\n| Explore unknown scope | Task | Multi-step investigation |\n\n## Error Recovery\n\n### Change Conflicts\n1. Run `openspec list` to see active changes\n2. Check for overlapping specs\n3. Coordinate with change owners\n4. Consider combining proposals\n\n### Validation Failures\n1. Run with `--strict` flag\n2. Check JSON output for details\n3. Verify spec file format\n4. Ensure scenarios properly formatted\n\n### Missing Context\n1. Read project.md first\n2. Check related specs\n3. Review recent archives\n4. Ask for clarification\n\n## Quick Reference\n\n### Stage Indicators\n- `changes/` - Proposed, not yet built\n- `specs/` - Built and deployed\n- `archive/` - Completed changes\n\n### File Purposes\n- `proposal.md` - Why and what\n- `tasks.md` - Implementation steps\n- `design.md` - Technical decisions\n- `spec.md` - Requirements and behavior\n\n### CLI Essentials\n```bash\nopenspec list              # What's in progress?\nopenspec show [item]       # View details\nopenspec validate --strict --no-interactive  # Is it correct?\nopenspec archive <change-id> [--yes|-y]  # Mark complete (add --yes for automation)\n```\n\nRemember: Specs are truth. Changes are proposals. Keep them in sync.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/21st-dev/1code/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->","isInternal":false,"tokens":144,"sizeBytes":660},{"name":"AGENTS.md","path":"openspec/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/21st-dev/1code/HEAD/openspec/AGENTS.md","title":"openspec - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# OpenSpec Instructions\n\nInstructions for AI coding assistants using OpenSpec for spec-driven development.\n\n## TL;DR Quick Checklist\n\n- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)\n- Decide scope: new capability vs modify existing capability\n- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)\n- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability\n- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement\n- Validate: `openspec validate [change-id] --strict --no-interactive` and fix issues\n- Request approval: Do not start implementation until proposal is approved\n\n## Three-Stage Workflow\n\n### Stage 1: Creating Changes\nCreate proposal when you need to:\n- Add features or functionality\n- Make breaking changes (API, schema)\n- Change architecture or patterns  \n- Optimize performance (changes behavior)\n- Update security patterns\n\nTriggers (examples):\n- \"Help me create a change proposal\"\n- \"Help me plan a change\"\n- \"Help me create a proposal\"\n- \"I want to create a spec proposal\"\n- \"I want to create a spec\"\n\nLoose matching guidance:\n- Contains one of: `proposal`, `change`, `spec`\n- With one of: `create`, `plan`, `make`, `start`, `help`\n\nSkip proposal for:\n- Bug fixes (restore intended behavior)\n- Typos, formatting, comments\n- Dependency updates (non-breaking)\n- Configuration changes\n- Tests for existing behavior\n\n**Workflow**\n1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.\n2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.\n3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.\n4. Run `openspec validate <id> --strict --no-interactive` and resolve any issues before sharing the proposal.\n\n### Stage 2: Implementing Changes\nTrack these steps as TODOs and complete them one by one.\n1. **Read proposal.md** - Understand what's being built\n2. **Read design.md** (if exists) - Review technical decisions\n3. **Read tasks.md** - Get implementation checklist\n4. **Implement tasks sequentially** - Complete in order\n5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses\n6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality\n7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved\n\n### Stage 3: Archiving Changes\nAfter deployment, create separate PR to:\n- Move `changes/[name]/` → `changes/archive/YYYY-MM-DD-[name]/`\n- Update `specs/` if capabilities changed\n- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)\n- Run `openspec validate --strict --no-interactive` to confirm the archived change passes checks\n\n## Before Any Task\n\n**Context Checklist:**\n- [ ] Read relevant specs in `specs/[capability]/spec.md`\n- [ ] Check pending changes in `changes/` for conflicts\n- [ ] Read `openspec/project.md` for conventions\n- [ ] Run `openspec list` to see active changes\n- [ ] Run `openspec list --specs` to see existing capabilities\n\n**Before Creating Specs:**\n- Always check if capability already exists\n- Prefer modifying existing specs over creating duplicates\n- Use `openspec show [spec]` to review current state\n- If request is ambiguous, ask 1–2 clarifying questions before scaffolding\n\n### Search Guidance\n- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)\n- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)\n- Show details:\n  - Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)\n  - Change: `openspec show <change-id> --json --deltas-only`\n- Full-text search (use ripgrep): `rg -n \"Requirement:|Scenario:\" openspec/specs`\n\n## Quick Start\n\n### CLI Commands\n\n```bash\n# Essential commands\nopenspec list                  # List active changes\nopenspec list --specs          # List specifications\nopenspec show [item]           # Display change or spec\nopenspec validate [item]       # Validate changes or specs\nopenspec archive <change-id> [--yes|-y]   # Archive after deployment (add --yes for non-interactive runs)\n\n# Project management\nopenspec init [path]           # Initialize OpenSpec\nopenspec update [path]         # Update instruction files\n\n# Interactive mode\nopenspec show                  # Prompts for selection\nopenspec validate              # Bulk validation mode\n\n# Debugging\nopenspec show [change] --json --deltas-only\nopenspec validate [change] --strict --no-interactive\n```\n\n### Command Flags\n\n- `--json` - Machine-readable output\n- `--type change|spec` - Disambiguate items\n- `--strict` - Comprehensive validation\n- `--no-interactive` - Disable prompts\n- `--skip-specs` - Archive without spec updates\n- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)\n\n## Directory Structure\n\n```\nopenspec/\n├── project.md              # Project conventions\n├── specs/                  # Current truth - what IS built\n│   └── [capability]/       # Single focused capability\n│       ├── spec.md         # Requirements and scenarios\n│       └── design.md       # Technical patterns\n├── changes/                # Proposals - what SHOULD change\n│   ├── [change-name]/\n│   │   ├── proposal.md     # Why, what, impact\n│   │   ├── tasks.md        # Implementation checklist\n│   │   ├── design.md       # Technical decisions (optional; see criteria)\n│   │   └── specs/          # Delta changes\n│   │       └── [capability]/\n│   │           └── spec.md # ADDED/MODIFIED/REMOVED\n│   └── archive/            # Completed changes\n```\n\n## Creating Change Proposals\n\n### Decision Tree\n\n```\nNew request?\n├─ Bug fix restoring spec behavior? → Fix directly\n├─ Typo/format/comment? → Fix directly  \n├─ New feature/capability? → Create proposal\n├─ Breaking change? → Create proposal\n├─ Architecture change? → Create proposal\n└─ Unclear? → Create proposal (safer)\n```\n\n### Proposal Structure\n\n1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)\n\n2. **Write proposal.md:**\n```markdown\n# Change: [Brief description of change]\n\n## Why\n[1-2 sentences on problem/opportunity]\n\n## What Changes\n- [Bullet list of changes]\n- [Mark breaking changes with **BREAKING**]\n\n## Impact\n- Affected specs: [list capabilities]\n- Affected code: [key files/systems]\n```\n\n3. **Create spec deltas:** `specs/[capability]/spec.md`\n```markdown\n## ADDED Requirements\n### Requirement: New Feature\nThe system SHALL provide...\n\n#### Scenario: Success case\n- **WHEN** user performs action\n- **THEN** expected result\n\n## MODIFIED Requirements\n### Requirement: Existing Feature\n[Complete modified requirement]\n\n## REMOVED Requirements\n### Requirement: Old Feature\n**Reason**: [Why removing]\n**Migration**: [How to handle]\n```\nIf multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.\n\n4. **Create tasks.md:**\n```markdown\n## 1. Implementation\n- [ ] 1.1 Create database schema\n- [ ] 1.2 Implement API endpoint\n- [ ] 1.3 Add frontend component\n- [ ] 1.4 Write tests\n```\n\n5. **Create design.md when needed:**\nCreate `design.md` if any of the following apply; otherwise omit it:\n- Cross-cutting change (multiple services/modules) or a new architectural pattern\n- New external dependency or significant data model changes\n- Security, performance, or migration complexity\n- Ambiguity that benefits from technical decisions before coding\n\nMinimal `design.md` skeleton:\n```markdown\n## Context\n[Background, constraints, stakeholders]\n\n## Goals / Non-Goals\n- Goals: [...]\n- Non-Goals: [...]\n\n## Decisions\n- Decision: [What and why]\n- Alternatives considered: [Options + rationale]\n\n## Risks / Trade-offs\n- [Risk] → Mitigation\n\n## Migration Plan\n[Steps, rollback]\n\n## Open Questions\n- [...]\n```\n\n## Spec File Format\n\n### Critical: Scenario Formatting\n\n**CORRECT** (use #### headers):\n```markdown\n#### Scenario: User login success\n- **WHEN** valid credentials provided\n- **THEN** return JWT token\n```\n\n**WRONG** (don't use bullets or bold):\n```markdown\n- **Scenario: User login**  ❌\n**Scenario**: User login     ❌\n### Scenario: User login      ❌\n```\n\nEvery requirement MUST have at least one scenario.\n\n### Requirement Wording\n- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)\n\n### Delta Operations\n\n- `## ADDED Requirements` - New capabilities\n- `## MODIFIED Requirements` - Changed behavior\n- `## REMOVED Requirements` - Deprecated features\n- `## RENAMED Requirements` - Name changes\n\nHeaders matched with `trim(header)` - whitespace ignored.\n\n#### When to use ADDED vs MODIFIED\n- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding \"Slash Command Configuration\") rather than altering the semantics of an existing requirement.\n- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.\n- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.\n\nCommon pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren’t explicitly changing the existing requirement, add a new requirement under ADDED instead.\n\nAuthoring a MODIFIED requirement correctly:\n1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.\n2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).\n3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.\n4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.\n\nExample for RENAMED:\n```markdown\n## RENAMED Requirements\n- FROM: `### Requirement: Login`\n- TO: `### Requirement: User Authentication`\n```\n\n## Troubleshooting\n\n### Common Errors\n\n**\"Change must have at least one delta\"**\n- Check `changes/[name]/specs/` exists with .md files\n- Verify files have operation prefixes (## ADDED Requirements)\n\n**\"Requirement must have at least one scenario\"**\n- Check scenarios use `#### Scenario:` format (4 hashtags)\n- Don't use bullet points or bold for scenario headers\n\n**Silent scenario parsing failures**\n- Exact format required: `#### Scenario: Name`\n- Debug with: `openspec show [change] --json --deltas-only`\n\n### Validation Tips\n\n```bash\n# Always use strict mode for comprehensive checks\nopenspec validate [change] --strict --no-interactive\n\n# Debug delta parsing\nopenspec show [change] --json | jq '.deltas'\n\n# Check specific requirement\nopenspec show [spec] --json -r 1\n```\n\n## Happy Path Script\n\n```bash\n# 1) Explore current state\nopenspec spec list --long\nopenspec list\n# Optional full-text search:\n# rg -n \"Requirement:|Scenario:\" openspec/specs\n# rg -n \"^#|Requirement:\" openspec/changes\n\n# 2) Choose change id and scaffold\nCHANGE=add-two-factor-auth\nmkdir -p openspec/changes/$CHANGE/{specs/auth}\nprintf \"## Why\\n...\\n\\n## What Changes\\n- ...\\n\\n## Impact\\n- ...\\n\" > openspec/changes/$CHANGE/proposal.md\nprintf \"## 1. Implementation\\n- [ ] 1.1 ...\\n\" > openspec/changes/$CHANGE/tasks.md\n\n# 3) Add deltas (example)\ncat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\nUsers MUST provide a second factor during login.\n\n#### Scenario: OTP required\n- **WHEN** valid credentials are provided\n- **THEN** an OTP challenge is required\nEOF\n\n# 4) Validate\nopenspec validate $CHANGE --strict --no-interactive\n```\n\n## Multi-Capability Example\n\n```\nopenspec/changes/add-2fa-notify/\n├── proposal.md\n├── tasks.md\n└── specs/\n    ├── auth/\n    │   └── spec.md   # ADDED: Two-Factor Authentication\n    └── notifications/\n        └── spec.md   # ADDED: OTP email notification\n```\n\nauth/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\n...\n```\n\nnotifications/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: OTP Email Notification\n...\n```\n\n## Best Practices\n\n### Simplicity First\n- Default to <100 lines of new code\n- Single-file implementations until proven insufficient\n- Avoid frameworks without clear justification\n- Choose boring, proven patterns\n\n### Complexity Triggers\nOnly add complexity with:\n- Performance data showing current solution too slow\n- Concrete scale requirements (>1000 users, >100MB data)\n- Multiple proven use cases requiring abstraction\n\n### Clear References\n- Use `file.ts:42` format for code locations\n- Reference specs as `specs/auth/spec.md`\n- Link related changes and PRs\n\n### Capability Naming\n- Use verb-noun: `user-auth`, `payment-capture`\n- Single purpose per capability\n- 10-minute understandability rule\n- Split if description needs \"AND\"\n\n### Change ID Naming\n- Use kebab-case, short and descriptive: `add-two-factor-auth`\n- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`\n- Ensure uniqueness; if taken, append `-2`, `-3`, etc.\n\n## Tool Selection Guide\n\n| Task | Tool | Why |\n|------|------|-----|\n| Find files by pattern | Glob | Fast pattern matching |\n| Search code content | Grep | Optimized regex search |\n| Read specific files | Read | Direct file access |\n| Explore unknown scope | Task | Multi-step investigation |\n\n## Error Recovery\n\n### Change Conflicts\n1. Run `openspec list` to see active changes\n2. Check for overlapping specs\n3. Coordinate with change owners\n4. Consider combining proposals\n\n### Validation Failures\n1. Run with `--strict` flag\n2. Check JSON output for details\n3. Verify spec file format\n4. Ensure scenarios properly formatted\n\n### Missing Context\n1. Read project.md first\n2. Check related specs\n3. Review recent archives\n4. Ask for clarification\n\n## Quick Reference\n\n### Stage Indicators\n- `changes/` - Proposed, not yet built\n- `specs/` - Built and deployed\n- `archive/` - Completed changes\n\n### File Purposes\n- `proposal.md` - Why and what\n- `tasks.md` - Implementation steps\n- `design.md` - Technical decisions\n- `spec.md` - Requirements and behavior\n\n### CLI Essentials\n```bash\nopenspec list              # What's in progress?\nopenspec show [item]       # View details\nopenspec validate --strict --no-interactive  # Is it correct?\nopenspec archive <change-id> [--yes|-y]  # Mark complete (add --yes for automation)\n```\n\nRemember: Specs are truth. Changes are proposals. Keep them in sync.\n","isInternal":false,"tokens":3627,"sizeBytes":15087},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/21st-dev/1code/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->\n\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## What is this?\n\n**21st Agents** - A local-first Electron desktop app for AI-powered code assistance. Users create chat sessions linked to local project folders, interact with Claude in Plan or Agent mode, and see real-time tool execution (bash, file edits, web search, etc.).\n\n## Commands\n\n```bash\n# Development\nbun run dev              # Start Electron with hot reload\n\n# Build\nbun run build            # Compile app\nbun run package          # Package for current platform (dir)\nbun run package:mac      # Build macOS (DMG + ZIP)\nbun run package:win      # Build Windows (NSIS + portable)\nbun run package:linux    # Build Linux (AppImage + DEB)\n\n# Database (Drizzle + SQLite)\nbun run db:generate      # Generate migrations from schema\nbun run db:push          # Push schema directly (dev only)\n```\n\n## Architecture\n\n```\nsrc/\n├── main/                    # Electron main process\n│   ├── index.ts             # App entry, window lifecycle\n│   ├── auth-manager.ts      # OAuth flow, token refresh\n│   ├── auth-store.ts        # Encrypted credential storage (safeStorage)\n│   ├── windows/main.ts      # Window creation, IPC handlers\n│   └── lib/\n│       ├── db/              # Drizzle + SQLite\n│       │   ├── index.ts     # DB init, auto-migrate on startup\n│       │   ├── schema/      # Drizzle table definitions\n│       │   └── utils.ts     # ID generation\n│       └── trpc/routers/    # tRPC routers (projects, chats, claude)\n│\n├── preload/                 # IPC bridge (context isolation)\n│   └── index.ts             # Exposes desktopApi + tRPC bridge\n│\n└── renderer/                # React 19 UI\n    ├── App.tsx              # Root with providers\n    ├── features/\n    │   ├── agents/          # Main chat interface\n    │   │   ├── main/        # active-chat.tsx, new-chat-form.tsx\n    │   │   ├── ui/          # Tool renderers, preview, diff view\n    │   │   ├── commands/    # Slash commands (/plan, /agent, /clear)\n    │   │   ├── atoms/       # Jotai atoms for agent state\n    │   │   └── stores/      # Zustand store for sub-chats\n    │   ├── sidebar/         # Chat list, archive, navigation\n    │   ├── sub-chats/       # Tab/sidebar sub-chat management\n    │   └── layout/          # Main layout with resizable panels\n    ├── components/ui/       # Radix UI wrappers (button, dialog, etc.)\n    └── lib/\n        ├── atoms/           # Global Jotai atoms\n        ├── stores/          # Global Zustand stores\n        ├── trpc.ts          # Real tRPC client\n        └── mock-api.ts      # DEPRECATED - being replaced with real tRPC\n```\n\n## Database (Drizzle ORM)\n\n**Location:** `{userData}/data/agents.db` (SQLite)\n\n**Schema:** `src/main/lib/db/schema/index.ts`\n\n```typescript\n// Three main tables:\nprojects    → id, name, path (local folder), timestamps\nchats       → id, name, projectId, worktree fields, timestamps\nsub_chats   → id, name, chatId, sessionId, mode, messages (JSON)\n```\n\n**Auto-migration:** On app start, `initDatabase()` runs migrations from `drizzle/` folder (dev) or `resources/migrations` (packaged).\n\n**Queries:**\n```typescript\nimport { getDatabase, projects, chats } from \"../lib/db\"\nimport { eq } from \"drizzle-orm\"\n\nconst db = getDatabase()\nconst allProjects = db.select().from(projects).all()\nconst projectChats = db.select().from(chats).where(eq(chats.projectId, id)).all()\n```\n\n## Key Patterns\n\n### IPC Communication\n- Uses **tRPC** with `trpc-electron` for type-safe main↔renderer communication\n- All backend calls go through tRPC routers, not raw IPC\n- Preload exposes `window.desktopApi` for native features (window controls, clipboard, notifications)\n\n### State Management\n- **Jotai**: UI state (selected chat, sidebar open, preview settings)\n- **Zustand**: Sub-chat tabs and pinned state (persisted to localStorage)\n- **React Query**: Server state via tRPC (auto-caching, refetch)\n\n### Claude Integration\n- Dynamic import of `@anthropic-ai/claude-code` SDK\n- Two modes: \"plan\" (read-only) and \"agent\" (full permissions)\n- Session resume via `sessionId` stored in SubChat\n- Message streaming via tRPC subscription (`claude.onMessage`)\n\n## Tech Stack\n\n| Layer | Tech |\n|-------|------|\n| Desktop | Electron 33.4.5, electron-vite, electron-builder |\n| UI | React 19, TypeScript 5.4.5, Tailwind CSS |\n| Components | Radix UI, Lucide icons, Motion, Sonner |\n| State | Jotai, Zustand, React Query |\n| Backend | tRPC, Drizzle ORM, better-sqlite3 |\n| AI | @anthropic-ai/claude-code |\n| Package Manager | bun |\n\n## File Naming\n\n- Components: PascalCase (`ActiveChat.tsx`, `AgentsSidebar.tsx`)\n- Utilities/hooks: camelCase (`useFileUpload.ts`, `formatters.ts`)\n- Stores: kebab-case (`sub-chat-store.ts`, `agent-chat-store.ts`)\n- Atoms: camelCase with `Atom` suffix (`selectedAgentChatIdAtom`)\n\n## Important Files\n\n- `electron.vite.config.ts` - Build config (main/preload/renderer entries)\n- `src/main/lib/db/schema/index.ts` - Drizzle schema (source of truth)\n- `src/main/lib/db/index.ts` - DB initialization + auto-migrate\n- `src/renderer/features/agents/atoms/index.ts` - Agent UI state atoms\n- `src/renderer/features/agents/main/active-chat.tsx` - Main chat component\n- `src/main/lib/trpc/routers/claude.ts` - Claude SDK integration\n\n## Debugging First Install Issues\n\nWhen testing auth flows or behavior for new users, you need to simulate a fresh install:\n\n```bash\n# 1. Clear all app data (auth, database, settings)\nrm -rf ~/Library/Application\\ Support/Agents\\ Dev/\n\n# 2. Reset macOS protocol handler registration (if testing deep links)\n/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user\n\n# 3. Clear app preferences\ndefaults delete dev.21st.agents.dev  # Dev mode\ndefaults delete dev.21st.agents      # Production\n\n# 4. Run in dev mode with clean state\ncd apps/desktop\nbun run dev\n```\n\n**Common First-Install Bugs:**\n- **OAuth deep link not working**: macOS Launch Services may not immediately recognize protocol handlers on first app launch. User may need to click \"Sign in\" again after the first attempt.\n- **Folder dialog not appearing**: Window focus timing issues on first launch. Fixed by ensuring window focus before showing `dialog.showOpenDialog()`.\n\n**Dev vs Production App:**\n- Dev mode uses `twentyfirst-agents-dev://` protocol\n- Dev mode uses separate userData path (`~/Library/Application Support/Agents Dev/`)\n- This prevents conflicts between dev and production installs\n\n## Releasing a New Version\n\n### Prerequisites for Notarization\n\n- Keychain profile: `21st-notarize`\n- Create with: `xcrun notarytool store-credentials \"21st-notarize\" --apple-id YOUR_APPLE_ID --team-id YOUR_TEAM_ID`\n\n### Release Commands\n\n```bash\n# Full release (build, sign, submit notarization, upload to CDN)\nbun run release\n\n# Or step by step:\nbun run build              # Compile TypeScript\nbun run package:mac        # Build & sign macOS app\nbun run dist:manifest      # Generate latest-mac.yml manifests\n./scripts/upload-release-wrangler.sh  # Submit notarization & upload to R2 CDN\n```\n\n### Bump Version Before Release\n\n```bash\nnpm version patch --no-git-tag-version  # 0.0.27 → 0.0.28\n```\n\n### After Release Script Completes\n\n1. Wait for notarization (2-5 min): `xcrun notarytool history --keychain-profile \"21st-notarize\"`\n2. Staple DMGs: `cd release && xcrun stapler staple *.dmg`\n3. Re-upload stapled DMGs to R2 and GitHub (see RELEASE.md for commands)\n4. Update changelog: `gh release edit v0.0.X --notes \"...\"`\n5. **Upload manifests (triggers auto-updates!)** — see RELEASE.md\n6. Sync to public: `./scripts/sync-to-public.sh`\n\n### Files Uploaded to CDN\n\n| File | Purpose |\n|------|---------|\n| `latest-mac.yml` | Manifest for arm64 auto-updates |\n| `latest-mac-x64.yml` | Manifest for Intel auto-updates |\n| `1Code-{version}-arm64-mac.zip` | Auto-update payload (arm64) |\n| `1Code-{version}-mac.zip` | Auto-update payload (Intel) |\n| `1Code-{version}-arm64.dmg` | Manual download (arm64) |\n| `1Code-{version}.dmg` | Manual download (Intel) |\n\n### Auto-Update Flow\n\n1. App checks `https://cdn.21st.dev/releases/desktop/latest-mac.yml` on startup and when window regains focus (with 1 min cooldown)\n2. If version in manifest > current version, shows \"Update Available\" banner\n3. User clicks Download → downloads ZIP in background\n4. User clicks \"Restart Now\" → installs update and restarts\n\n## Current Status (WIP)\n\n**Done:**\n- Drizzle ORM setup with schema (projects, chats, sub_chats)\n- Auto-migration on app startup\n- tRPC routers structure\n\n**In Progress:**\n- Replacing `mock-api.ts` with real tRPC calls in renderer\n- ProjectSelector component (local folder picker)\n\n**Planned:**\n- Git worktree per chat (isolation)\n- Claude Code execution in worktree path\n- Full feature parity with web app\n\n## Debug Mode\n\nWhen debugging runtime issues in the renderer or main process, use the structured debug logging system. This avoids asking the user to manually copy-paste console output.\n\n**Start the server:**\n```bash\nbun packages/debug/src/server.ts &\n```\n\n**Instrument renderer code** (no import needed, fails silently):\n```js\nfetch('http://localhost:7799/log',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({tag:'TAG',msg:'MESSAGE',data:{},ts:Date.now()})}).catch(()=>{});\n```\n\n**Read logs:** Read `.debug/logs.ndjson` - each line is a JSON object with `tag`, `msg`, `data`, `ts`.\n\n**Clear logs:** `curl -X DELETE http://localhost:7799/logs`\n\n**Workflow:** Hypothesize → instrument → user reproduces → read logs → fix with evidence → verify → remove instrumentation.\n\nSee `packages/debug/INSTRUCTIONS.md` for the full protocol.\n","isInternal":false,"tokens":2657,"sizeBytes":10680}],"systemPromptSnippet":"<yakaai_skills repo=\"21st-dev/1code\">\n<!-- File: AGENTS.md (Tokens: ~144 | Category: root-instruction) -->\n<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->\n\n<!-- File: openspec/AGENTS.md (Tokens: ~3627 | Category: root-instruction) -->\n# OpenSpec Instructions\n\nInstructions for AI coding assistants using OpenSpec for spec-driven development.\n\n## TL;DR Quick Checklist\n\n- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)\n- Decide scope: new capability vs modify existing capability\n- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)\n- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability\n- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement\n- Validate: `openspec validate [change-id] --strict --no-interactive` and fix issues\n- Request approval: Do not start implementation until proposal is approved\n\n## Three-Stage Workflow\n\n### Stage 1: Creating Changes\nCreate proposal when you need to:\n- Add features or functionality\n- Make breaking changes (API, schema)\n- Change architecture or patterns  \n- Optimize performance (changes behavior)\n- Update security patterns\n\nTriggers (examples):\n- \"Help me create a change proposal\"\n- \"Help me plan a change\"\n- \"Help me create a proposal\"\n- \"I want to create a spec proposal\"\n- \"I want to create a spec\"\n\nLoose matching guidance:\n- Contains one of: `proposal`, `change`, `spec`\n- With one of: `create`, `plan`, `make`, `start`, `help`\n\nSkip proposal for:\n- Bug fixes (restore intended behavior)\n- Typos, formatting, comments\n- Dependency updates (non-breaking)\n- Configuration changes\n- Tests for existing behavior\n\n**Workflow**\n1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.\n2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.\n3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.\n4. Run `openspec validate <id> --strict --no-interactive` and resolve any issues before sharing the proposal.\n\n### Stage 2: Implementing Changes\nTrack these steps as TODOs and complete them one by one.\n1. **Read proposal.md** - Understand what's being built\n2. **Read design.md** (if exists) - Review technical decisions\n3. **Read tasks.md** - Get implementation checklist\n4. **Implement tasks sequentially** - Complete in order\n5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses\n6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality\n7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved\n\n### Stage 3: Archiving Changes\nAfter deployment, create separate PR to:\n- Move `changes/[name]/` → `changes/archive/YYYY-MM-DD-[name]/`\n- Update `specs/` if capabilities changed\n- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)\n- Run `openspec validate --strict --no-interactive` to confirm the archived change passes checks\n\n## Before Any Task\n\n**Context Checklist:**\n- [ ] Read relevant specs in `specs/[capability]/spec.md`\n- [ ] Check pending changes in `changes/` for conflicts\n- [ ] Read `openspec/project.md` for conventions\n- [ ] Run `openspec list` to see active changes\n- [ ] Run `openspec list --specs` to see existing capabilities\n\n**Before Creating Specs:**\n- Always check if capability already exists\n- Prefer modifying existing specs over creating duplicates\n- Use `openspec show [spec]` to review current state\n- If request is ambiguous, ask 1–2 clarifying questions before scaffolding\n\n### Search Guidance\n- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)\n- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)\n- Show details:\n  - Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)\n  - Change: `openspec show <change-id> --json --deltas-only`\n- Full-text search (use ripgrep): `rg -n \"Requirement:|Scenario:\" openspec/specs`\n\n## Quick Start\n\n### CLI Commands\n\n```bash\n# Essential commands\nopenspec list                  # List active changes\nopenspec list --specs          # List specifications\nopenspec show [item]           # Display change or spec\nopenspec validate [item]       # Validate changes or specs\nopenspec archive <change-id> [--yes|-y]   # Archive after deployment (add --yes for non-interactive runs)\n\n# Project management\nopenspec init [path]           # Initialize OpenSpec\nopenspec update [path]         # Update instruction files\n\n# Interactive mode\nopenspec show                  # Prompts for selection\nopenspec validate              # Bulk validation mode\n\n# Debugging\nopenspec show [change] --json --deltas-only\nopenspec validate [change] --strict --no-interactive\n```\n\n### Command Flags\n\n- `--json` - Machine-readable output\n- `--type change|spec` - Disambiguate items\n- `--strict` - Comprehensive validation\n- `--no-interactive` - Disable prompts\n- `--skip-specs` - Archive without spec updates\n- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)\n\n## Directory Structure\n\n```\nopenspec/\n├── project.md              # Project conventions\n├── specs/                  # Current truth - what IS built\n│   └── [capability]/       # Single focused capability\n│       ├── spec.md         # Requirements and scenarios\n│       └── design.md       # Technical patterns\n├── changes/                # Proposals - what SHOULD change\n│   ├── [change-name]/\n│   │   ├── proposal.md     # Why, what, impact\n│   │   ├── tasks.md        # Implementation checklist\n│   │   ├── design.md       # Technical decisions (optional; see criteria)\n│   │   └── specs/          # Delta changes\n│   │       └── [capability]/\n│   │           └── spec.md # ADDED/MODIFIED/REMOVED\n│   └── archive/            # Completed changes\n```\n\n## Creating Change Proposals\n\n### Decision Tree\n\n```\nNew request?\n├─ Bug fix restoring spec behavior? → Fix directly\n├─ Typo/format/comment? → Fix directly  \n├─ New feature/capability? → Create proposal\n├─ Breaking change? → Create proposal\n├─ Architecture change? → Create proposal\n└─ Unclear? → Create proposal (safer)\n```\n\n### Proposal Structure\n\n1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)\n\n2. **Write proposal.md:**\n```markdown\n# Change: [Brief description of change]\n\n## Why\n[1-2 sentences on problem/opportunity]\n\n## What Changes\n- [Bullet list of changes]\n- [Mark breaking changes with **BREAKING**]\n\n## Impact\n- Affected specs: [list capabilities]\n- Affected code: [key files/systems]\n```\n\n3. **Create spec deltas:** `specs/[capability]/spec.md`\n```markdown\n## ADDED Requirements\n### Requirement: New Feature\nThe system SHALL provide...\n\n#### Scenario: Success case\n- **WHEN** user performs action\n- **THEN** expected result\n\n## MODIFIED Requirements\n### Requirement: Existing Feature\n[Complete modified requirement]\n\n## REMOVED Requirements\n### Requirement: Old Feature\n**Reason**: [Why removing]\n**Migration**: [How to handle]\n```\nIf multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.\n\n4. **Create tasks.md:**\n```markdown\n## 1. Implementation\n- [ ] 1.1 Create database schema\n- [ ] 1.2 Implement API endpoint\n- [ ] 1.3 Add frontend component\n- [ ] 1.4 Write tests\n```\n\n5. **Create design.md when needed:**\nCreate `design.md` if any of the following apply; otherwise omit it:\n- Cross-cutting change (multiple services/modules) or a new architectural pattern\n- New external dependency or significant data model changes\n- Security, performance, or migration complexity\n- Ambiguity that benefits from technical decisions before coding\n\nMinimal `design.md` skeleton:\n```markdown\n## Context\n[Background, constraints, stakeholders]\n\n## Goals / Non-Goals\n- Goals: [...]\n- Non-Goals: [...]\n\n## Decisions\n- Decision: [What and why]\n- Alternatives considered: [Options + rationale]\n\n## Risks / Trade-offs\n- [Risk] → Mitigation\n\n## Migration Plan\n[Steps, rollback]\n\n## Open Questions\n- [...]\n```\n\n## Spec File Format\n\n### Critical: Scenario Formatting\n\n**CORRECT** (use #### headers):\n```markdown\n#### Scenario: User login success\n- **WHEN** valid credentials provided\n- **THEN** return JWT token\n```\n\n**WRONG** (don't use bullets or bold):\n```markdown\n- **Scenario: User login**  ❌\n**Scenario**: User login     ❌\n### Scenario: User login      ❌\n```\n\nEvery requirement MUST have at least one scenario.\n\n### Requirement Wording\n- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)\n\n### Delta Operations\n\n- `## ADDED Requirements` - New capabilities\n- `## MODIFIED Requirements` - Changed behavior\n- `## REMOVED Requirements` - Deprecated features\n- `## RENAMED Requirements` - Name changes\n\nHeaders matched with `trim(header)` - whitespace ignored.\n\n#### When to use ADDED vs MODIFIED\n- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding \"Slash Command Configuration\") rather than altering the semantics of an existing requirement.\n- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.\n- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.\n\nCommon pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you aren’t explicitly changing the existing requirement, add a new requirement under ADDED instead.\n\nAuthoring a MODIFIED requirement correctly:\n1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.\n2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).\n3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.\n4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.\n\nExample for RENAMED:\n```markdown\n## RENAMED Requirements\n- FROM: `### Requirement: Login`\n- TO: `### Requirement: User Authentication`\n```\n\n## Troubleshooting\n\n### Common Errors\n\n**\"Change must have at least one delta\"**\n- Check `changes/[name]/specs/` exists with .md files\n- Verify files have operation prefixes (## ADDED Requirements)\n\n**\"Requirement must have at least one scenario\"**\n- Check scenarios use `#### Scenario:` format (4 hashtags)\n- Don't use bullet points or bold for scenario headers\n\n**Silent scenario parsing failures**\n- Exact format required: `#### Scenario: Name`\n- Debug with: `openspec show [change] --json --deltas-only`\n\n### Validation Tips\n\n```bash\n# Always use strict mode for comprehensive checks\nopenspec validate [change] --strict --no-interactive\n\n# Debug delta parsing\nopenspec show [change] --json | jq '.deltas'\n\n# Check specific requirement\nopenspec show [spec] --json -r 1\n```\n\n## Happy Path Script\n\n```bash\n# 1) Explore current state\nopenspec spec list --long\nopenspec list\n# Optional full-text search:\n# rg -n \"Requirement:|Scenario:\" openspec/specs\n# rg -n \"^#|Requirement:\" openspec/changes\n\n# 2) Choose change id and scaffold\nCHANGE=add-two-factor-auth\nmkdir -p openspec/changes/$CHANGE/{specs/auth}\nprintf \"## Why\\n...\\n\\n## What Changes\\n- ...\\n\\n## Impact\\n- ...\\n\" > openspec/changes/$CHANGE/proposal.md\nprintf \"## 1. Implementation\\n- [ ] 1.1 ...\\n\" > openspec/changes/$CHANGE/tasks.md\n\n# 3) Add deltas (example)\ncat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\nUsers MUST provide a second factor during login.\n\n#### Scenario: OTP required\n- **WHEN** valid credentials are provided\n- **THEN** an OTP challenge is required\nEOF\n\n# 4) Validate\nopenspec validate $CHANGE --strict --no-interactive\n```\n\n## Multi-Capability Example\n\n```\nopenspec/changes/add-2fa-notify/\n├── proposal.md\n├── tasks.md\n└── specs/\n    ├── auth/\n    │   └── spec.md   # ADDED: Two-Factor Authentication\n    └── notifications/\n        └── spec.md   # ADDED: OTP email notification\n```\n\nauth/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: Two-Factor Authentication\n...\n```\n\nnotifications/spec.md\n```markdown\n## ADDED Requirements\n### Requirement: OTP Email Notification\n...\n```\n\n## Best Practices\n\n### Simplicity First\n- Default to <100 lines of new code\n- Single-file implementations until proven insufficient\n- Avoid frameworks without clear justification\n- Choose boring, proven patterns\n\n### Complexity Triggers\nOnly add complexity with:\n- Performance data showing current solution too slow\n- Concrete scale requirements (>1000 users, >100MB data)\n- Multiple proven use cases requiring abstraction\n\n### Clear References\n- Use `file.ts:42` format for code locations\n- Reference specs as `specs/auth/spec.md`\n- Link related changes and PRs\n\n### Capability Naming\n- Use verb-noun: `user-auth`, `payment-capture`\n- Single purpose per capability\n- 10-minute understandability rule\n- Split if description needs \"AND\"\n\n### Change ID Naming\n- Use kebab-case, short and descriptive: `add-two-factor-auth`\n- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`\n- Ensure uniqueness; if taken, append `-2`, `-3`, etc.\n\n## Tool Selection Guide\n\n| Task | Tool | Why |\n|------|------|-----|\n| Find files by pattern | Glob | Fast pattern matching |\n| Search code content | Grep | Optimized regex search |\n| Read specific files | Read | Direct file access |\n| Explore unknown scope | Task | Multi-step investigation |\n\n## Error Recovery\n\n### Change Conflicts\n1. Run `openspec list` to see active changes\n2. Check for overlapping specs\n3. Coordinate with change owners\n4. Consider combining proposals\n\n### Validation Failures\n1. Run with `--strict` flag\n2. Check JSON output for details\n3. Verify spec file format\n4. Ensure scenarios properly formatted\n\n### Missing Context\n1. Read project.md first\n2. Check related specs\n3. Review recent archives\n4. Ask for clarification\n\n## Quick Reference\n\n### Stage Indicators\n- `changes/` - Proposed, not yet built\n- `specs/` - Built and deployed\n- `archive/` - Completed changes\n\n### File Purposes\n- `proposal.md` - Why and what\n- `tasks.md` - Implementation steps\n- `design.md` - Technical decisions\n- `spec.md` - Requirements and behavior\n\n### CLI Essentials\n```bash\nopenspec list              # What's in progress?\nopenspec show [item]       # View details\nopenspec validate --strict --no-interactive  # Is it correct?\nopenspec archive <change-id> [--yes|-y]  # Mark complete (add --yes for automation)\n```\n\nRemember: Specs are truth. Changes are proposals. Keep them in sync.\n\n<!-- File: CLAUDE.md (Tokens: ~2657 | Category: claude-rule) -->\n<!-- OPENSPEC:START -->\n# OpenSpec Instructions\n\nThese instructions are for AI assistants working in this project.\n\nAlways open `@/openspec/AGENTS.md` when the request:\n- Mentions planning or proposals (words like proposal, spec, change, plan)\n- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work\n- Sounds ambiguous and you need the authoritative spec before coding\n\nUse `@/openspec/AGENTS.md` to learn:\n- How to create and apply change proposals\n- Spec format and conventions\n- Project structure and guidelines\n\nKeep this managed block so 'openspec update' can refresh the instructions.\n\n<!-- OPENSPEC:END -->\n\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## What is this?\n\n**21st Agents** - A local-first Electron desktop app for AI-powered code assistance. Users create chat sessions linked to local project folders, interact with Claude in Plan or Agent mode, and see real-time tool execution (bash, file edits, web search, etc.).\n\n## Commands\n\n```bash\n# Development\nbun run dev              # Start Electron with hot reload\n\n# Build\nbun run build            # Compile app\nbun run package          # Package for current platform (dir)\nbun run package:mac      # Build macOS (DMG + ZIP)\nbun run package:win      # Build Windows (NSIS + portable)\nbun run package:linux    # Build Linux (AppImage + DEB)\n\n# Database (Drizzle + SQLite)\nbun run db:generate      # Generate migrations from schema\nbun run db:push          # Push schema directly (dev only)\n```\n\n## Architecture\n\n```\nsrc/\n├── main/                    # Electron main process\n│   ├── index.ts             # App entry, window lifecycle\n│   ├── auth-manager.ts      # OAuth flow, token refresh\n│   ├── auth-store.ts        # Encrypted credential storage (safeStorage)\n│   ├── windows/main.ts      # Window creation, IPC handlers\n│   └── lib/\n│       ├── db/              # Drizzle + SQLite\n│       │   ├── index.ts     # DB init, auto-migrate on startup\n│       │   ├── schema/      # Drizzle table definitions\n│       │   └── utils.ts     # ID generation\n│       └── trpc/routers/    # tRPC routers (projects, chats, claude)\n│\n├── preload/                 # IPC bridge (context isolation)\n│   └── index.ts             # Exposes desktopApi + tRPC bridge\n│\n└── renderer/                # React 19 UI\n    ├── App.tsx              # Root with providers\n    ├── features/\n    │   ├── agents/          # Main chat interface\n    │   │   ├── main/        # active-chat.tsx, new-chat-form.tsx\n    │   │   ├── ui/          # Tool renderers, preview, diff view\n    │   │   ├── commands/    # Slash commands (/plan, /agent, /clear)\n    │   │   ├── atoms/       # Jotai atoms for agent state\n    │   │   └── stores/      # Zustand store for sub-chats\n    │   ├── sidebar/         # Chat list, archive, navigation\n    │   ├── sub-chats/       # Tab/sidebar sub-chat management\n    │   └── layout/          # Main layout with resizable panels\n    ├── components/ui/       # Radix UI wrappers (button, dialog, etc.)\n    └── lib/\n        ├── atoms/           # Global Jotai atoms\n        ├── stores/          # Global Zustand stores\n        ├── trpc.ts          # Real tRPC client\n        └── mock-api.ts      # DEPRECATED - being replaced with real tRPC\n```\n\n## Database (Drizzle ORM)\n\n**Location:** `{userData}/data/agents.db` (SQLite)\n\n**Schema:** `src/main/lib/db/schema/index.ts`\n\n```typescript\n// Three main tables:\nprojects    → id, name, path (local folder), timestamps\nchats       → id, name, projectId, worktree fields, timestamps\nsub_chats   → id, name, chatId, sessionId, mode, messages (JSON)\n```\n\n**Auto-migration:** On app start, `initDatabase()` runs migrations from `drizzle/` folder (dev) or `resources/migrations` (packaged).\n\n**Queries:**\n```typescript\nimport { getDatabase, projects, chats } from \"../lib/db\"\nimport { eq } from \"drizzle-orm\"\n\nconst db = getDatabase()\nconst allProjects = db.select().from(projects).all()\nconst projectChats = db.select().from(chats).where(eq(chats.projectId, id)).all()\n```\n\n## Key Patterns\n\n### IPC Communication\n- Uses **tRPC** with `trpc-electron` for type-safe main↔renderer communication\n- All backend calls go through tRPC routers, not raw IPC\n- Preload exposes `window.desktopApi` for native features (window controls, clipboard, notifications)\n\n### State Management\n- **Jotai**: UI state (selected chat, sidebar open, preview settings)\n- **Zustand**: Sub-chat tabs and pinned state (persisted to localStorage)\n- **React Query**: Server state via tRPC (auto-caching, refetch)\n\n### Claude Integration\n- Dynamic import of `@anthropic-ai/claude-code` SDK\n- Two modes: \"plan\" (read-only) and \"agent\" (full permissions)\n- Session resume via `sessionId` stored in SubChat\n- Message streaming via tRPC subscription (`claude.onMessage`)\n\n## Tech Stack\n\n| Layer | Tech |\n|-------|------|\n| Desktop | Electron 33.4.5, electron-vite, electron-builder |\n| UI | React 19, TypeScript 5.4.5, Tailwind CSS |\n| Components | Radix UI, Lucide icons, Motion, Sonner |\n| State | Jotai, Zustand, React Query |\n| Backend | tRPC, Drizzle ORM, better-sqlite3 |\n| AI | @anthropic-ai/claude-code |\n| Package Manager | bun |\n\n## File Naming\n\n- Components: PascalCase (`ActiveChat.tsx`, `AgentsSidebar.tsx`)\n- Utilities/hooks: camelCase (`useFileUpload.ts`, `formatters.ts`)\n- Stores: kebab-case (`sub-chat-store.ts`, `agent-chat-store.ts`)\n- Atoms: camelCase with `Atom` suffix (`selectedAgentChatIdAtom`)\n\n## Important Files\n\n- `electron.vite.config.ts` - Build config (main/preload/renderer entries)\n- `src/main/lib/db/schema/index.ts` - Drizzle schema (source of truth)\n- `src/main/lib/db/index.ts` - DB initialization + auto-migrate\n- `src/renderer/features/agents/atoms/index.ts` - Agent UI state atoms\n- `src/renderer/features/agents/main/active-chat.tsx` - Main chat component\n- `src/main/lib/trpc/routers/claude.ts` - Claude SDK integration\n\n## Debugging First Install Issues\n\nWhen testing auth flows or behavior for new users, you need to simulate a fresh install:\n\n```bash\n# 1. Clear all app data (auth, database, settings)\nrm -rf ~/Library/Application\\ Support/Agents\\ Dev/\n\n# 2. Reset macOS protocol handler registration (if testing deep links)\n/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user\n\n# 3. Clear app preferences\ndefaults delete dev.21st.agents.dev  # Dev mode\ndefaults delete dev.21st.agents      # Production\n\n# 4. Run in dev mode with clean state\ncd apps/desktop\nbun run dev\n```\n\n**Common First-Install Bugs:**\n- **OAuth deep link not working**: macOS Launch Services may not immediately recognize protocol handlers on first app launch. User may need to click \"Sign in\" again after the first attempt.\n- **Folder dialog not appearing**: Window focus timing issues on first launch. Fixed by ensuring window focus before showing `dialog.showOpenDialog()`.\n\n**Dev vs Production App:**\n- Dev mode uses `twentyfirst-agents-dev://` protocol\n- Dev mode uses separate userData path (`~/Library/Application Support/Agents Dev/`)\n- This prevents conflicts between dev and production installs\n\n## Releasing a New Version\n\n### Prerequisites for Notarization\n\n- Keychain profile: `21st-notarize`\n- Create with: `xcrun notarytool store-credentials \"21st-notarize\" --apple-id YOUR_APPLE_ID --team-id YOUR_TEAM_ID`\n\n### Release Commands\n\n```bash\n# Full release (build, sign, submit notarization, upload to CDN)\nbun run release\n\n# Or step by step:\nbun run build              # Compile TypeScript\nbun run package:mac        # Build & sign macOS app\nbun run dist:manifest      # Generate latest-mac.yml manifests\n./scripts/upload-release-wrangler.sh  # Submit notarization & upload to R2 CDN\n```\n\n### Bump Version Before Release\n\n```bash\nnpm version patch --no-git-tag-version  # 0.0.27 → 0.0.28\n```\n\n### After Release Script Completes\n\n1. Wait for notarization (2-5 min): `xcrun notarytool history --keychain-profile \"21st-notarize\"`\n2. Staple DMGs: `cd release && xcrun stapler staple *.dmg`\n3. Re-upload stapled DMGs to R2 and GitHub (see RELEASE.md for commands)\n4. Update changelog: `gh release edit v0.0.X --notes \"...\"`\n5. **Upload manifests (triggers auto-updates!)** — see RELEASE.md\n6. Sync to public: `./scripts/sync-to-public.sh`\n\n### Files Uploaded to CDN\n\n| File | Purpose |\n|------|---------|\n| `latest-mac.yml` | Manifest for arm64 auto-updates |\n| `latest-mac-x64.yml` | Manifest for Intel auto-updates |\n| `1Code-{version}-arm64-mac.zip` | Auto-update payload (arm64) |\n| `1Code-{version}-mac.zip` | Auto-update payload (Intel) |\n| `1Code-{version}-arm64.dmg` | Manual download (arm64) |\n| `1Code-{version}.dmg` | Manual download (Intel) |\n\n### Auto-Update Flow\n\n1. App checks `https://cdn.21st.dev/releases/desktop/latest-mac.yml` on startup and when window regains focus (with 1 min cooldown)\n2. If version in manifest > current version, shows \"Update Available\" banner\n3. User clicks Download → downloads ZIP in background\n4. User clicks \"Restart Now\" → installs update and restarts\n\n## Current Status (WIP)\n\n**Done:**\n- Drizzle ORM setup with schema (projects, chats, sub_chats)\n- Auto-migration on app startup\n- tRPC routers structure\n\n**In Progress:**\n- Replacing `mock-api.ts` with real tRPC calls in renderer\n- ProjectSelector component (local folder picker)\n\n**Planned:**\n- Git worktree per chat (isolation)\n- Claude Code execution in worktree path\n- Full feature parity with web app\n\n## Debug Mode\n\nWhen debugging runtime issues in the renderer or main process, use the structured debug logging system. This avoids asking the user to manually copy-paste console output.\n\n**Start the server:**\n```bash\nbun packages/debug/src/server.ts &\n```\n\n**Instrument renderer code** (no import needed, fails silently):\n```js\nfetch('http://localhost:7799/log',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({tag:'TAG',msg:'MESSAGE',data:{},ts:Date.now()})}).catch(()=>{});\n```\n\n**Read logs:** Read `.debug/logs.ndjson` - each line is a JSON object with `tag`, `msg`, `data`, `ts`.\n\n**Clear logs:** `curl -X DELETE http://localhost:7799/logs`\n\n**Workflow:** Hypothesize → instrument → user reproduces → read logs → fix with evidence → verify → remove instrumentation.\n\nSee `packages/debug/INSTRUCTIONS.md` for the full protocol.\n</yakaai_skills>"}