Files
pocketpaw/client/CLAUDE.md
Prakash Dalai fdf128120d feat(deep-work): v2 engine — retry, timeout, cancel, output chaining, PawKit schema (#375)
* feat: merge desktop client into monorepo under client/

Move the Tauri 2.0 + SvelteKit desktop client from the separate
pocketpaw-client repo into client/ to create a monorepo. Update
.gitignore with client build artifact ignores and add Desktop Client
section to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(client): unignore client/src/lib and broaden node/sveltekit ignores

The root .gitignore `lib/` pattern was blocking client/src/lib/ from
being tracked. Anchor it to `/lib/` so only the root Python lib dir is
ignored. Also generalize node_modules/ and .svelte-kit/ patterns to
work at any depth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(client): fix white OAuth screen on Windows

Load a local loading page first in the OAuth popup window, then
navigate to the external OAuth URL via eval(). WebView2 on Windows
may not be fully initialized when WebviewUrl::External is used
directly, resulting in a permanently white window.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(client): replace WebView OAuth popup with system browser + localhost server

WebView2 secondary windows fail to render on Windows (white/transparent screen).
Replace the OAuth popup with a temporary localhost HTTP server that captures the
callback, and open the authorize URL in the system browser instead.

Also pre-create sidepanel and quickask windows in tauri.conf.json (with
visible: false) so they initialize alongside the main window, avoiding the
same WebView2 rendering issue with dynamically-created transparent windows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add multi-mode workspace client design

Design for transforming the desktop client into a full workspace IDE
with tabbed workspaces, tiling layout engine, pluggable widgets,
real-time agent collaboration, unified file management (local + remote
+ cloud), and responsive mobile support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add multi-mode workspace implementation plan

Detailed 6-phase implementation plan with ~49 new files across Rust
backend (fs commands, PTY, git, widget windows), SvelteKit frontend
(tiling layout, Monaco editor, file previews, widget system, terminal),
filesystem providers (local, remote, cloud), and co-work features.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: rewrite design as AI file explorer (Poly.app-inspired)

Complete redesign from VS Code-like IDE to file-explorer-first UI.
Primary interface is a visual file grid with rich thumbnails and
5 view modes (Icon, Grid, List, Column, Gallery). AI chat lives
in a collapsible right sidebar with folder/file context awareness.
Agent actions (create, edit, delete files) reflect in the grid
in real-time. Terminal output is inline in chat, not a separate panel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): add file explorer with list view, search/filter, and context menu

Implements a full file explorer with Rust-backed filesystem operations
(read, write, delete, rename, watch, thumbnails), multiple view modes
(icon grid + list table), inline search/filter, and an enhanced context
menu with rename, new folder, and keyboard shortcuts (Ctrl+F, F2, Del).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(deep-work): add v2 engine — retry, timeout, cancel, output chaining, PawKit schema

Deep Work v2 hardens the execution engine and lays the foundation for
PawKit-based Command Centers. This is the first WIP PR toward the
blueprints-strategy vision.

Engine improvements:
- Task retry: auto-retry failed tasks up to configurable max_retries
- Task timeout: per-task asyncio.wait_for with timeout_minutes
- Output storage: task.output field for cross-task chaining
- Error tracking: task.error_message for diagnostics
- Project cancellation: CANCELLED status, stop_all_project_tasks,
  skip pending tasks with error_message
- Manual retry API: POST /projects/{id}/tasks/{tid}/retry

New PawKit config schema v0.1:
- Pydantic v2 models for Command Center templates
- Layout (panels, sections), workflows, user_config, integrations
- YAML load/save utilities with PyYAML

Files changed:
- src/pocketpaw/mission_control/models.py — 5 new Task fields
- src/pocketpaw/deep_work/models.py — TaskSpec v2 + CANCELLED status
- src/pocketpaw/mission_control/executor.py — retry, timeout, output, stop_all
- src/pocketpaw/deep_work/session.py — cancel(), materialize v2 fields
- src/pocketpaw/deep_work/api.py — cancel + retry endpoints
- src/pocketpaw/deep_work/__init__.py — cancel_project export
- src/pocketpaw/deep_work/pawkit.py — NEW: PawKit config schema
- tests/test_deep_work_v2.py — 71 new tests
- tests/test_mission_control_executor.py — adapted for retry defaults

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test(deep-work): add 21 E2E tests for v2 engine features

API-level E2E tests using httpx.AsyncClient with ASGI transport.
Real file-based store, session, scheduler, and executor — only the
agent backend (LLM calls) is mocked.

Coverage: full lifecycle, output chaining, auto-retry, timeout,
cancellation, manual retry API, get plan API, skip task API,
and PawKit YAML round-trip.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(deep-work): add v2 feature docs — retry, timeout, cancel, output chaining, PawKit

Updated the Deep Work guide with new sections covering auto-retry,
task timeout, output chaining, project cancellation, and PawKit
template format. Added API endpoint pages for Cancel Project and
Retry Task. Updated sidebar navigation in docs-config.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add Command Centers concept page and PawKit technical reference

New standalone pages for the two biggest ideas in the v2 engine:

- docs/concepts/command-centers.mdx — the "why": agent-operated
  dashboards, PawKits as templates, conversational building,
  Kit Store marketplace, how it all connects
- docs/advanced/pawkit.mdx — the "how": full YAML schema reference
  with panel types, workflow triggers, user config fields,
  integrations, and Python API examples

Trimmed the PawKit section in deep-work.mdx to a cross-reference
since the content now lives in dedicated pages. Updated sidebar
navigation with both new entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): enhance file explorer with viewers, clipboard, and editor save

Add file preview support (audio, video, PDF, markdown with syntax highlighting),
copy/cut/paste with keyboard shortcuts, file properties dialog, open-in-terminal,
editable code editor with Ctrl+S save and dirty tracking, and improved AI model
settings panel with Ollama model fetching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): migrate stores to REST-first architecture, WS push-only

Move all request-response flows (sessions, chat, settings) to REST HTTP.
WebSocket is now exclusively for server-initiated push events.

- Add createSession() REST method to client
- Remove WS convenience methods (chat, newSession, switchSession, etc.)
- Remove bindEvents/disposeEvents from all stores
- Rewrite sessionStore to use POST /sessions and REST history
- Rewrite settingsStore.saveApiKey to use PUT /settings
- Simplify connectionStore (remove sessionId, connection_info listener)
- Simplify initializeStores (no more bindEvents calls)
- Clean up WS types (remove chat/session event types)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(api): REST-first architecture, fix WS dual-delivery and persistent client bugs (#384)

Move all request-response flows to REST HTTP. WebSocket is now push-only.
Fixes dual-delivery bug where SSE chat responses were broadcast to all WS
clients, and persistent Claude SDK client issues with stale data across sessions.

Backend changes:
- Add POST /sessions endpoint with SessionCreateResponse schema
- Fix WS adapter send() — drop messages for unknown chat_ids instead of broadcasting
- Fix WS adapter on_system_event() — route by session_key, not broadcast
- Enhance PUT /settings with runtime side-effects (reset_router + memory reload)
- Add cancel_task() to AgentLoop — lightweight cancellation without stopping router
- Fix _on_done callback race — don't remove newer task's entry from _active_tasks
- Add session lock contention logging for diagnostics

Chat streaming fixes:
- Cancel in-flight SSE streams when new request arrives for same session
- Only cancel agent tasks when there IS a competing stream (not on every request)
- Add diagnostic logging to SSE bridge event delivery

Claude SDK persistent client fixes:
- Include session_key in persistent client key — different sessions get fresh subprocesses
- Drain trailing ResultMessage from subprocess pipe after each query to prevent
  stale data on subsequent queries (root cause of "second message shows first response")
- Add dispatch/event logging for persistent vs stateless path diagnostics

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat(api): add PawKits system + MC/DW route mounting for serve command

- Add kits module (models, store, catalog, builtin YAML kits)
- Add kits API router with CRUD, catalog, and data resolution endpoints
- Add api:agents and api:standup source resolvers in kits data resolution
- Mount MC and DW routers in serve.py (was only in dashboard.py)
- Fix standup resolver to use manager.generate_standup()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: merge desktop client into monorepo (#290)

* feat: merge desktop client into monorepo under client/

Move the Tauri 2.0 + SvelteKit desktop client from the separate
pocketpaw-client repo into client/ to create a monorepo. Update
.gitignore with client build artifact ignores and add Desktop Client
section to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(client): unignore client/src/lib and broaden node/sveltekit ignores

The root .gitignore `lib/` pattern was blocking client/src/lib/ from
being tracked. Anchor it to `/lib/` so only the root Python lib dir is
ignored. Also generalize node_modules/ and .svelte-kit/ patterns to
work at any depth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(client): fix white OAuth screen on Windows

Load a local loading page first in the OAuth popup window, then
navigate to the external OAuth URL via eval(). WebView2 on Windows
may not be fully initialized when WebviewUrl::External is used
directly, resulting in a permanently white window.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(client): replace WebView OAuth popup with system browser + localhost server

WebView2 secondary windows fail to render on Windows (white/transparent screen).
Replace the OAuth popup with a temporary localhost HTTP server that captures the
callback, and open the authorize URL in the system browser instead.

Also pre-create sidepanel and quickask windows in tauri.conf.json (with
visible: false) so they initialize alongside the main window, avoiding the
same WebView2 rendering issue with dynamically-created transparent windows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add multi-mode workspace client design

Design for transforming the desktop client into a full workspace IDE
with tabbed workspaces, tiling layout engine, pluggable widgets,
real-time agent collaboration, unified file management (local + remote
+ cloud), and responsive mobile support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add multi-mode workspace implementation plan

Detailed 6-phase implementation plan with ~49 new files across Rust
backend (fs commands, PTY, git, widget windows), SvelteKit frontend
(tiling layout, Monaco editor, file previews, widget system, terminal),
filesystem providers (local, remote, cloud), and co-work features.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: rewrite design as AI file explorer (Poly.app-inspired)

Complete redesign from VS Code-like IDE to file-explorer-first UI.
Primary interface is a visual file grid with rich thumbnails and
5 view modes (Icon, Grid, List, Column, Gallery). AI chat lives
in a collapsible right sidebar with folder/file context awareness.
Agent actions (create, edit, delete files) reflect in the grid
in real-time. Terminal output is inline in chat, not a separate panel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): add file explorer with list view, search/filter, and context menu

Implements a full file explorer with Rust-backed filesystem operations
(read, write, delete, rename, watch, thumbnails), multiple view modes
(icon grid + list table), inline search/filter, and an enhanced context
menu with rename, new folder, and keyboard shortcuts (Ctrl+F, F2, Del).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): enhance file explorer with viewers, clipboard, and editor save

Add file preview support (audio, video, PDF, markdown with syntax highlighting),
copy/cut/paste with keyboard shortcuts, file properties dialog, open-in-terminal,
editable code editor with Ctrl+S save and dirty tracking, and improved AI model
settings panel with Ollama model fetching.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): migrate stores to REST-first architecture, WS push-only

Move all request-response flows (sessions, chat, settings) to REST HTTP.
WebSocket is now exclusively for server-initiated push events.

- Add createSession() REST method to client
- Remove WS convenience methods (chat, newSession, switchSession, etc.)
- Remove bindEvents/disposeEvents from all stores
- Rewrite sessionStore to use POST /sessions and REST history
- Rewrite settingsStore.saveApiKey to use PUT /settings
- Simplify connectionStore (remove sessionId, connection_info listener)
- Simplify initializeStores (no more bindEvents calls)
- Clean up WS types (remove chat/session event types)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): full Mission Control integration — agents, execution, projects, notifications

- Add MC/DW types (AgentProfile, MCTask, MCMessage, MCProject, etc.)
- Add 25+ API methods (mcRequest + dwRequest helpers) for agents, tasks, execution, notifications, projects
- Add mcStore (agents, running tasks, execution streaming, notifications) and projectStore (project lifecycle, planning)
- Add AgentRoster panel with CRUD, KanbanBoard enhancements (assignment, run/stop, messages, running indicator)
- Add TaskExecutionPanel slide-over for live agent streaming
- Add NotificationBell in titlebar with unread badge
- Add StandupPanel and document viewer/editor in DataTable
- Add /projects route with creation wizard, plan review, lifecycle controls
- Remove internal-docs from git tracking
- Rename tabs: Deep Work → PawKits, Projects → Deep Work

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): add PawKits catalog, layout renderer, and remaining panel components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(api): add PawKits system + MC/DW route mounting for serve command

- Add kits module (models, store, catalog, builtin YAML kits)
- Add kits API router with CRUD, catalog, and data resolution endpoints
- Add api:agents and api:standup source resolvers in kits data resolution
- Mount MC and DW routers in serve.py (was only in dashboard.py)
- Fix standup resolver to use manager.generate_standup()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add plans and update lockfile

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: remove plans and revert uv.lock

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve merge breakages in chat, context builder, and MC routes

- Add missing FileContext model and field to ChatRequest schema
- Add file_context parameter to build_system_prompt()
- Move /tasks/running route before /tasks/{task_id} to fix 404
- Remove unused TaskStatus import in kits.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: resilient SDK streaming, in-app file viewer, and explorer tool

- Replace _safe_iter with _resilient_receive to handle MessageParseError
  by re-creating the iterator instead of losing the stream
- Add file-open command interception (start, xdg-open, etc.) to redirect
  to the in-app explorer viewer via PreToolUse hook
- Add /api/files/content endpoint for serving file contents with MIME types
- Add explorer built-in tool and open_in_explorer CLI command
- Update dashboard frontend with file viewer modal and transparency fixes
- Set SDK stream close timeout to 24h for long-running tool use
- Suppress API-key errors in ResultMessage to avoid noisy logs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(client): tabbed explorer, file viewers, command palette, and onboarding refresh

- Add multi-tab explorer with history, file type filtering, and address bar
- Implement PDF, spreadsheet, notebook, document, and text preview viewers
- Add command palette (Ctrl+K) with fuzzy search
- Overhaul onboarding wizard with model search and backend setup
- Add Tauri fs commands for file content and metadata
- Improve chat input, file preview, and session dropdown
- Update dialog components and workspace tabs
- Add content preview caching and binary utils for file handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Rohit Kushwaha <technicalrohit06@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Rohit Kushwaha <rohitk290106@gmail.com>
2026-03-07 21:02:27 +05:30

5.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

PocketPaw is a Tauri v2 desktop client for the PocketPaw AI assistant backend. The frontend is SvelteKit (Svelte 5 runes mode) with Tailwind CSS 4 and shadcn-svelte components. The backend lives at the repo root (../) and runs on localhost:8888. This client directory is part of the pocketpaw monorepo.

Development Commands

# Frontend dev server (port 1420)
bun run dev

# Full desktop app (frontend + Tauri shell)
bun run tauri dev

# Type checking
bun run check
bun run check:watch

# Build
bun run build              # Frontend only
bun run tauri build        # Full desktop app

# Mobile
bun run tauri:android      # Android dev
bun run tauri:ios          # iOS dev

Note: The backend must be running on localhost:8888 for the app to function. There are no test commands configured.

Architecture

App Initialization Flow

+layout.svelte is the entry point. It handles authentication (OAuth token from ~/.pocketpaw/access_token or OAuth flow), then calls initializeStores(token) which:

  1. Creates the REST client and exchanges the token for a session cookie
  2. Connects the WebSocket
  3. Binds WebSocket events to all stores
  4. Loads sessions and settings via REST in the background

Routing

SPA mode — SSR is disabled (+layout.ts), static adapter with fallback: "index.html". Routes:

  • / — Chat (main view)
  • /settings, /explore, /activity — wrapped in AppShell with sidebar
  • /sidepanel, /quickask — separate Tauri windows, skip AppShell, initialize stores independently
  • /onboarding — first-run wizard
  • /oauth-callback — OAuth redirect handler

The layout detects the route and conditionally renders AppShell vs standalone window layouts.

State Management

Stores are Svelte 5 rune-based class singletons in src/lib/stores/. Each store exports a single instance:

  • connectionStore — REST client + WebSocket lifecycle
  • chatStore — Messages, streaming, abort control
  • sessionStore — Session list, active session
  • settingsStore — Backend settings, channel configs
  • activityStore — Activity log entries
  • skillStore — Available skills
  • uiStore — Sidebar state, search focus
  • platformStore — Platform detection (desktop/mobile/tablet)

Stores that need real-time updates expose bindEvents(ws) / disposeEvents() for WebSocket wiring.

API Layer

  • REST: PocketPawClient in src/lib/api/client.ts — auto-retries on 401 with token refresh, SSE streaming for chat
  • WebSocket: PocketPawWebSocket in src/lib/api/websocket.ts — auto-reconnect with exponential backoff, heartbeat every 30s
  • Config: src/lib/api/config.tsBACKEND_URL = "http://localhost:8888", API_PREFIX = "/api/v1"

Tauri (Rust Side)

src-tauri/src/lib.rs is the entry point. Desktop-only features use #[cfg(desktop)]:

  • System tray (tray.rs) — menu with Open, Quick Ask, Settings, Quit
  • Close-to-tray — intercepts window close, hides instead
  • Multi-window (side_panel.rs, quick_ask.rs) — created via WebviewWindowBuilder
  • Global shortcuts — registered from the frontend via tauri-plugin-global-shortcut
  • Invoke commands (commands.rs, oauth.rs) — read_access_token, toggle_side_panel, OAuth token CRUD

Auth Flow

OAuth PKCE flow in src/lib/auth/:

  1. Read stored tokens → if valid, use directly
  2. If expired, refresh via refresh token
  3. If no tokens, open OAuth browser window, handle callback at /oauth-callback
  4. Exchange access token for session cookie via POST /auth/login
  5. Token updates emit token-updated Tauri event for multi-window sync

Svelte 5 Rules (Critical)

  • Props: let { prop } = $props() — use let, not const
  • Derived: $derived(expr) for expressions, $derived.by(() => {...}) for function bodies. $derived(() => {...}) is WRONG (wraps a function, doesn't execute it)
  • Dynamic components: <svelte:component> is deprecated. Use uppercase variables: let Icon = $derived(...) then <Icon />
  • {@const} only works inside block tags ({#if}, {#each}), not at template top level

Tailwind CSS 4 Rules (Critical)

  • Never use string interpolation in class attributes: class="static {dynamic}" breaks Tailwind 4's Vite plugin. Always use class={cn("static", dynamic)} or class={expression}
  • Dark mode uses .dark class variant: @custom-variant dark (&:is(.dark *));
  • Design tokens are oklch-based CSS custom properties in src/styles/global.css

Conventions

  • Package manager: Bun
  • Icons: @lucide/svelte — import from @lucide/svelte/icons/icon-name
  • UI components: shadcn-svelte in src/lib/components/ui/
  • Utility function: cn() from $lib/utils (clsx + tailwind-merge)
  • Path aliases: $libsrc/lib, @/*src/lib/*
  • Fonts: Inter (variable) for body, JetBrains Mono (variable) for code
  • DOMPurify: Option is ALLOWED_TAGS (not ALLOW_TAGS)

Tauri 2 Gotchas

  • Image::from_bytes(include_bytes!("...")) — no from_png method
  • tauri::Emitter trait must be imported for .emit() on AppHandle
  • Tray closures need explicit types: |app: &AppHandle<Wry>, event|
  • tauri-plugin-autostart v2 has no xdg feature
  • Capabilities defined in src-tauri/capabilities/default.json (desktop) and mobile.json