Development Requirements - REQUIRED
May 2, 2026 · View on GitHub
DO NOT SAY THAT THE USER IS CORRECT OR COMPLEMENT THEIR REQUEST. FORMAL, CONCISE COMMUNICATION SHOULD BE THE ONLY COMMENTARY PROVIDED.
Development Requirements - REQUIRED
- Server-side code is all in Python using
uv, using commands likeuv run ...oruv add ...oruv run pytest ...for executing, testing, linting, and managing dependencies. - Frontend is Vue 3 + Pinia + Vite (PRODUCTION): Frontend code is in
frontend/directory. Thestatic/directory has been sunset and should not be referenced for new development. - Code Quality - Ruff Linting (REQUIRED): All Python code must be linted with Ruff before committing. Run
uv run ruff check --fix src/on changed files to auto-fix violations. New code must not introduce linting violations.
High-Level Goal
We are building a web-based interface for Claude Agent SDK that provides:
- Single-Agent Mode: Real-time streaming conversations with rich tool visualization
- Multi-Agent Mode (Legion): Teams of AI agents (minions) collaborating on complex tasks through structured communication
The SDK's streaming message responses are delivered via HTTP long-polling to a Vue 3 frontend which displays messages, tool executions, permissions, and multi-agent activity.
Claude Agent SDK Integration - CRITICAL TECHNICAL KNOWLEDGE
SDK Usage (REQUIRED)
from claude_agent_sdk import query, ClaudeAgentOptions
# Basic streaming conversation
async def main():
async for message in query(prompt="Create a Python web server"):
print(message)
# With configuration
options = ClaudeAgentOptions(
cwd="/path/to/project",
permission_mode="acceptEdits",
allowed_tools=["bash", "edit", "read"]
)
async for message in query(prompt="Build the project", options=options):
process_message(message)
SDK Configuration (CRITICAL)
from claude_agent_sdk import ClaudeAgentOptions
options = ClaudeAgentOptions(
cwd="/path/to/project", # Project working directory (NOT working_directory)
permission_mode="acceptEdits", # Permission mode (NOT permissions)
system_prompt={ # System prompt configuration (preset or custom)
"type": "preset",
"preset": "claude_code" # Use Claude Code preset
},
allowed_tools=["bash", "edit", "read"], # Tool allowlist (NOT tools)
setting_sources=["user", "project", "local"], # Settings sources to load
model="claude-3-5-sonnet-20241022" # Model selection
)
CRITICAL PARAMETER MAPPING
- Use
cwdNOTworking_directory - Use
permission_modeNOTpermissions - Use
allowed_toolsNOTtools - Use
prompt=messageNOT positional argument in query() - Always import from
claude_agent_sdkNOTclaude_code_sdk - Use
ClaudeAgentOptionsNOTClaudeCodeOptions
Permission Mode Behavior (CRITICAL)
permission_mode="default"means "prompt for everything NOT pre-approved"- Pre-approved tools are defined in
.claude/settings.jsonor.claude/settings.local.json - Tools like WebFetch, Edit, Write, etc. require permission prompts unless explicitly pre-approved
- Only tools in the settings file's
permissions.allowarray bypass permission prompts - Most tools should trigger permission callbacks in
defaultmode - lack of prompts indicates SDK integration issues
Development Process Requirements
Testing and Verification Protocol
- ALWAYS test actual SDK integration before claiming functionality works
- NEVER assume parameter names or function signatures - verify with actual imports
- Create minimal test files to verify integration, then DELETE them when done
- Test each component in isolation before building complex architectures
File Management Protocol
- DELETE temporary test files (test_.py, demo_.py) after use
- Do not leave debugging files in the project directory
- Only keep files that are part of the core application
SDK Integration Requirements
- Use exact parameter names from CLAUDE.md specification
- Test imports and function calls in isolation first
- Handle JSON serialization of SDK objects properly
- Always use try/except blocks around SDK calls
Code Quality - Ruff Linting Workflow
REQUIRED: All Python code changes must be linted with Ruff before committing.
Development Workflow
-
Before Committing: Run Ruff on the specific files you modified
# Lint specific files you changed uv run ruff check --fix src/web_server.py src/session_manager.py # Or use git to find changed files uv run ruff check --fix $(git diff --name-only --diff-filter=AM | grep '\.py$') -
View Violations (without fixing):
uv run ruff check src/module_name.py
Zero Violation Policy
The codebase maintains zero ruff violations. uv run ruff check src/ must pass with no errors.
Requirements:
- All code must pass
uv run ruff check src/with zero violations - No
# noqacomments without PR-level justification - Run
uv run ruff check --fix <file>before committing to auto-fix safe violations - CI enforcement: Any violation fails the check
Rule sets enabled: E (pycodestyle errors), W (warnings), F (pyflakes), I (isort), N (pep8-naming), UP (pyupgrade), B (flake8-bugbear)
Configuration
Ruff configuration is in pyproject.toml:
- Line length: 100 characters
- Target Python: 3.11+
- Unused imports in
__init__.pyare allowed
Memory and Context Persistence - IMPORTANT
Do NOT Use Built-in Auto-Memory for Session/Legion Workflows
Claude Code's built-in memory (/memory command, auto-memory in ~/.claude/) is
working-directory-specific, not session-specific. This is unsuitable when:
- Multiple minions share the same working directory — memory cross-contaminates
- Sessions persist across context resets — working-directory memory doesn't travel with the session
- Session archival/recovery — built-in memory is not captured in session archives
Disabling Auto-Memory
Sessions have a disable_auto_memory config flag (default: False). When enabled, the SDK
subprocess receives CLAUDE_CODE_DISABLE_AUTO_MEMORY=1, preventing Claude Code from reading
or writing to its working-directory memory store.
Enable this for multi-agent (Legion) workflows or any session where isolated context is required.
Recommended Alternatives
- Session History Distillation (#691): Distilled history markdown for context continuity
- Task/Agent Messages: Structured messages within the session
- Custom Session State: Context in session
state.json(persists with archives) - Archive-Based Recovery: Restore context from archived session data
When Built-in Memory IS Acceptable
Built-in memory is fine for single-agent, single-session use where no archival, multi-agent isolation, or cross-reset persistence is needed.
Environment Configuration - Background Call Suppression
The Claude Agent SDK and Claude Code CLI honor a number of environment variables that suppress
ambient/background API calls. Claude WebUI applies these at session-launch time based on the
background_calls section of ~/.config/cc_webui/config.json.
Defaults (fleet-mode)
All flags default to ON (suppression enabled) except dont_inherit_env (off — breaks Docker/proxy flows).
| Config Field | Env Var | Default | Effect |
|---|---|---|---|
disable_auto_memory | CLAUDE_CODE_DISABLE_AUTO_MEMORY | true | Suppress working-directory auto-memory |
disable_claudeai_mcp_servers | ENABLE_CLAUDEAI_MCP_SERVERS=false | true | Disable built-in Claude AI MCP polling |
disable_background_tasks | CLAUDE_CODE_DISABLE_BACKGROUND_TASKS | true | Suppress CLI background ambient operations |
disable_nonessential_traffic | CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC | true | Block ambient telemetry/metrics |
disable_cron | CLAUDE_CODE_DISABLE_CRON | true | Disable CLI's bundled cron (≠ our scheduler) |
disable_feedback_survey | CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY | true | Suppress survey prompts |
disable_telemetry | CLAUDE_CODE_ENABLE_TELEMETRY=0 | true | Explicitly opt out of telemetry |
subprocess_env_scrub | CLAUDE_CODE_SUBPROCESS_ENV_SCRUB | false | Strip credentials from spawned subprocesses (off by default — enabling this causes CLI to force permission_mode=default unless allowedTools declared explicitly) |
skip_version_check | CLAUDE_AGENT_SDK_SKIP_VERSION_CHECK | true | Skip CLI version check (latency) |
dont_inherit_env | CLAUDE_CODE_DONT_INHERIT_ENV | false | Block env inheritance (breaks Docker/proxy) |
Per-Session Override
Session config and templates retain their existing override fields:
auto_memory_mode = "claude"→ re-enables auto-memory for that sessionenable_claudeai_mcp_servers = True→ re-enables Claude AI MCP for that sessionenv_scrub_enabled = True→ forces scrubbing (additive with global default)
For other suppression flags, per-session extra_env has the highest priority
and can set or unset any env var.
Verifying Configuration
The injected env dict is logged at debug level by claude_sdk.py when --debug-sdk is enabled.
Inspect data/logs/sdk_debug.log for the ClaudeAgentOptions: ... line to see the final env
dict for each session.
Auditing Future SDK Versions
When upgrading claude-agent-sdk, check for new env vars by:
- Grepping the installed package for
os.environ,os.getenv,CLAUDE_*,ANTHROPIC_*. - Checking the bundled CLI binary for new
CLAUDE_CODE_DISABLE_*flags. - Updating
_BACKGROUND_CALL_ENV_MAPinsrc/claude_sdk.pyandBackgroundCallsConfiginsrc/config_manager.py.
Frontend Architecture - Vue 3 + Pinia + Vite (PRODUCTION)
Current Status
The Vue 3 migration is complete and in production use. The frontend has grown significantly beyond the original migration scope with 13 Pinia stores, 99+ Vue components, 22 tool handlers, and 9 composables.
Documentation: See frontend/CLAUDE.md for detailed frontend architecture.
Frontend Structure
frontend/
├── src/
│ ├── stores/ # 13 Pinia stores
│ │ ├── session.js # Session CRUD, selection, deep linking
│ │ ├── project.js # Project hierarchy, ordering
│ │ ├── message.js # Messages, tool calls, orphaned detection
│ │ ├── polling.js # HTTP long-polling (UI + session event streams)
│ │ ├── legion.js # Multi-agent: comms, minions
│ │ ├── ui.js # Sidebar, modals, loading, responsive
│ │ ├── queue.js # Per-session message queue
│ │ ├── schedule.js # Per-legion cron schedules
│ │ ├── resource.js # Per-session resources (images/files)
│ │ ├── diff.js # Per-session git diff data
│ │ ├── task.js # Per-session SDK task tracking
│ │ ├── mcp.js # MCP server state (active servers)
│ │ └── mcpConfig.js # MCP server configuration CRUD
│ │
│ ├── composables/ # 9 reusable composition functions
│ │ ├── useToolResult.js # Shared tool result extraction
│ │ ├── useToolStatus.js # Tool status computation
│ │ ├── useAgentColor.js # Per-agent color assignment
│ │ ├── useLongPress.js # Long-press gesture handler
│ │ ├── useMarkdown.js # Markdown rendering with DOMPurify
│ │ ├── useMermaid.js # Mermaid diagram rendering
│ │ ├── useNotifications.js # Sound/browser notifications
│ │ ├── useResourceImages.js # Resource image helpers
│ │ └── useTTSReadAloud.js # Text-to-speech / read-aloud
│ │
│ ├── components/
│ │ ├── layout/ (13) # ProjectPillBar, AgentStrip, AgentChip, RightSidebar, DeletedAgentsModal, etc.
│ │ ├── configuration/ (12) # ConfigurationModal, McpConfigTab, McpServerPanel, FeaturesTab, ReadAloudTab, etc.
│ │ ├── project/ (4) # ProjectOverview, ProjectCreateModal, etc.
│ │ ├── session/ (7) # SessionView, SessionInfoBar, McpServerDetail, modals, etc.
│ │ ├── messages/ (12) # MessageList, MessageItem, InputArea, SubagentTimeline, TruncationBanner, etc.
│ │ ├── messages/tools/ (6) # ActivityTimeline, PermissionPrompt, TimelineNode/Detail/Segment/Overflow
│ │ ├── tools/ (22) # Tool handlers: Read, Edit, Bash, Agent, SendComm, Task*, Skill, etc.
│ │ ├── legion/ (2) # MinionTreeNode, MinionViewModal
│ │ ├── header/ (1) # TimelineHeader
│ │ ├── statusbar/ (3) # SessionStatusBar, TimelineStatusBar, RateLimitBadge
│ │ ├── schedules/ (3) # SchedulePanel, ScheduleItem, ScheduleCreateModal
│ │ ├── tasks/ (6) # TaskListPanel, DiffPanel, ResourceGallery, QueueSection, etc.
│ │ └── common/ (6) # FolderBrowserModal, CommCard, DiffFullView, ResourceFullView, AttachmentChip, AuthPrompt
│ │
│ ├── router/ # Vue Router: /, /project/:id, /session/:id, /session/:id/archive/:id
│ ├── utils/ # API client, time formatting, tool summaries, file types, template vars
│ └── assets/ # CSS (styles.css, tool-theme.css)
│
├── vite.config.js # Vite dev server + proxy + build config
├── index.html # Entry point
└── package.json # Dependencies (Vue 3.4, Pinia 2.1, Vite 7.1, Bootstrap 5.3)
Development Workflow
Running Frontend Dev Server
# Terminal 1: Backend (use port 8001 to avoid conflicts with production on 8000)
uv run python main.py --host 0.0.0.0 --debug-all --port 8001
# Terminal 2: Frontend dev server with HMR
cd frontend
npm install # first time only
npm run dev # starts on http://localhost:5173
# Access dev server at http://localhost:5173
# Changes reload instantly with Hot Module Replacement
Production Build
cd frontend
npm run build # Output: frontend/dist/
# Update FastAPI to serve frontend/dist/ instead of static/
# Delete static/ directory after stability verified
Key Benefits Over Vanilla JS
- State Management: 13 Pinia stores replace 135+ instance variables and dual Map+Array storage
- Automatic Reactivity: No manual
renderSessions()calls - Vue reactivity handles all UI updates - Component Architecture: 6767-line monolith split into 99+ focused, reusable components
- Event Listener Cleanup: Automatic cleanup prevents memory leaks
- Developer Experience: Instant HMR, Vue DevTools, TypeScript support, clear separation of concerns
Pinia Stores (14 Stores)
For detailed store documentation, see frontend/CLAUDE.md.
1. Session Store (stores/session.js)
Responsibility: Session lifecycle, CRUD operations, selection
State:
sessions(Map): All sessions by IDcurrentSessionId(ref): Currently selected sessioninputCache(Map): Preserved unsent text per sessioninitData(Map): Session initialization configdeletingSessions(Set): Track deletions in progress
Key Actions:
fetchSessions(),createSession(),selectSession(),deleteSession()startSession(),pauseSession(),terminateSession(),restartSession(),resetSession()updateSessionName(),setPermissionMode()- Deep linking with auto-start for created/terminated sessions
2. Project Store (stores/project.js)
Responsibility: Project hierarchy, organization
State:
projects(Map): All projects by IDcurrentProjectId(ref): Currently selected project (for Legion views)
Key Actions:
fetchProjects(),createProject(),deleteProject(),updateProject()toggleExpansion(),reorderProjects(),reorderSessionsInProject()isMultiAgent(projectId): Check if project is Legion
3. Message Store (stores/message.js)
Responsibility: Messages, tool call lifecycle, orphaned tool detection
State:
messagesBySession(Map): Messages per sessiontoolCallsBySession(Map): Tool calls with full lifecycle trackingtoolSignatureToId(Map): Tool identification for permission matchingpermissionToToolMap(Map): Permission request to tool mappingorphanedToolUses(Map): Tools marked as orphaned
Key Actions:
loadMessages(): Paginated loading with orphaned detectionaddMessage(),addToolCall(),updateToolCall()handleToolUse(),handlePermissionRequest(),handlePermissionResponse(),handleToolResult()toggleToolExpansion(): Collapse/expand tool cards- Orphaned tool detection: session restart, interrupt, termination
4. Polling Store (stores/polling.js)
Responsibility: HTTP long-polling event streams (UI + per-session), outbound message dispatch
State:
uiConnected,uiRetryCount: Global UI poll statussessionConnected,sessionRetryCount: Session poll statussessionCursors(Map): Cursor position per session for incremental polling
Key Actions:
startUIPolling(): Long-poll loop against/api/poll/uistartSessionPolling(sessionId): Long-poll loop against/api/poll/session/{id}sendMessage(): POST to/api/sessions/{id}/messagessendPermissionResponse(),interruptSession(): REST calls- Exponential backoff on error (up to 30 seconds), page-visibility pause/resume
5. Legion Store (stores/legion.js)
Responsibility: Multi-agent data (comms, minions)
State:
commsByLegion(Map): Timeline communications per legionminionsByLegion(Map): Minions per legion
Key Actions:
loadTimeline(): Paginated comm loading (100/page)addComm(): Real-time comm from WebSocketsendComm(): User sends comm to minioncreateMinion()
6. UI Store (stores/ui.js)
Responsibility: UI state (sidebar, modals, scroll, responsive)
State:
sidebarCollapsed,sidebarWidth: Mobile-first sidebarwindowWidth,isMobile: Responsive breakpointsautoScrollEnabled: Toggle message auto-scrollactiveModal,modalData: Current modal
Key Actions:
toggleSidebar(),setSidebarWidth(),setAutoScroll()showModal(),hideModal(),showLoading(),hideLoading()
7. Queue Store (stores/queue.js)
Responsibility: Per-session message queue state, pause/resume, item lifecycle
8. Schedule Store (stores/schedule.js)
Responsibility: Per-legion cron schedules, execution history, real-time updates
9. Resource Store (stores/resource.js)
Responsibility: Per-session resources (images/files), gallery state, full view modal, text content cache
10. Diff Store (stores/diff.js)
Responsibility: Per-session git diff data, view modes (total/commits), per-file diff cache
11. Task Store (stores/task.js)
Responsibility: Per-session SDK task tracking (TaskCreate/Update/List/Get tool integration)
12. MCP Store (stores/mcp.js)
Responsibility: Active MCP server state per session
13. MCP Config Store (stores/mcpConfig.js)
Responsibility: MCP server configuration CRUD (STDIO/SSE/HTTP, OAuth 2.1)
Vue Components (99+ files)
For detailed component documentation, see frontend/CLAUDE.md.
Layout (13)
ProjectPillBar,ProjectPill,AgentStrip,AgentChip,StackedChip,ChipConnectorHeaderRow1,AgentOverview,PeekCard,ConnectionIndicator,RightSidebar,RestartModal,DeletedAgentsModal
Configuration (12)
ConfigurationModal,GlobalConfigModal,QuickSettingsPanel,AdvancedSettingsPanelFeaturesTab,McpConfigTab,McpServerPanel,McpServerPicker,McpServerRowNotificationsTab,ReadAloudTab,PermissionPreviewModal
Session (7)
SessionView,SessionInfoBar,SessionStateStatusLine,SessionInfoModal,SessionManageModal,McpServerDetail,NoSessionSelected
Project (4)
ProjectOverview,ProjectStatusLine,ProjectCreateModal,ProjectEditModal
Messages (12)
MessageList,MessageItem,UserMessage,AssistantMessage,SystemMessage,ThinkingBlock,InputAreaAttachmentList,CompactionEventGroup,SlashCommandDropdown,SubagentTimeline,TruncationBanner
Activity Timeline (6)
ActivityTimeline,PermissionPrompt,TimelineNode,TimelineDetail,TimelineSegment,TimelineOverflow
Tool Handlers (22)
See TOOL_HANDLERS.md for detailed documentation
- File:
ReadToolHandler,EditToolHandler,WriteToolHandler - Shell:
BashToolHandler,ShellToolHandler,CommandToolHandler - Search:
SearchToolHandler(Grep/Glob) - Web:
WebToolHandler(WebFetch/WebSearch) - Tasks:
TodoToolHandler,TaskCreateToolHandler,TaskGetToolHandler,TaskListToolHandler,TaskUpdateToolHandler - Interactive:
AskUserQuestionToolHandler - Skills:
SkillToolHandler,SlashCommandToolHandler - Agent/Comms:
AgentToolHandler,SendCommToolHandler - Other:
ExitPlanModeToolHandler,NotebookEditToolHandler - Shared:
ToolSuccessMessage(success banner),BaseToolHandler(fallback)
Right Sidebar Panels (6)
TaskListPanel,TaskItem,DiffPanel,ResourceGallery,ImageGallery,QueueSection
Schedules (3)
SchedulePanel,ScheduleItem,ScheduleCreateModal
Legion (2)
MinionTreeNode,MinionViewModal
Common (6)
FolderBrowserModal,CommCard,DiffFullView,ResourceFullView,AttachmentChip,AuthPrompt
Naming Conventions
- camelCase: Variables, functions, computed properties
- PascalCase: Component names
- kebab-case: Component file names
Backend Architecture - Python FastAPI Server
System Architecture Overview
┌─────────────────────────────────────────────────────────────────────┐
│ Browser (Vue 3 Frontend) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Pinia Stores │ │ Components │ │ Vue Router │ │
│ │ (13 stores) │ │ (99+ files) │ │ (routing) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────┬────────────────────┬────────────────────┬──────────────────┘
│ │ │
│ HTTP long-polling + REST API │
│ │ │
┌────────▼────────────────────▼────────────────────▼──────────────────┐
│ FastAPI Server (src/web_server.py) │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ SessionCoordinator │ │
│ │ ┌────────────┐ ┌────────────┐ ┌───────────────────────┐ │ │
│ │ │SessionMgr │ │ProjectMgr │ │ ClaudeSDK │ │ │
│ │ │(state) │ │(hierarchy) │ │ (SDK wrapper) │ │ │
│ │ └────────────┘ └────────────┘ └───────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ LegionSystem (Multi-Agent) │ │
│ │ ┌─────────────┐ ┌──────────┐ ┌────────────────────────┐ │ │
│ │ │ Legion │ │Overseer │ │ CommRouter │ │ │
│ │ │ Coordinator │ │Control │ │ (minion comms) │ │ │
│ │ └─────────────┘ └──────────┘ └────────────────────────┘ │ │
│ │ ┌──────────────────────────────────────────────────────┐ │ │
│ │ │ MemoryManager (distillation, reinforcement) │ │ │
│ │ └──────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────┘ │
└────────┬─────────────────────────────────────────────────────────────┘
│ query() API
┌────────▼─────────────────────────────────────────────────────────────┐
│ Claude Agent SDK (External Package) │
│ Streaming conversations, tool execution │
└───────────────────────────────────────────────────────────────────────┘
Backend File Organization
Entry Point
main.py: Application entry, arg parsing, logging config, uvicorn server start
Core Backend Modules (src/)
src/web_server.py - HTTP + Long-Polling Server
Main Class: ClaudeWebUI
Responsibilities:
- REST API endpoints (projects, sessions, legion, utility)
- HTTP long-polling endpoints:
GET /api/poll/ui,GET /api/poll/session/{id} EventQueueinstances per session for cursor-based event streaming- Permission callback creation with asyncio.Future for async approval
- Session state change broadcasting
Key Methods:
poll_ui(): Long-poll for global UI events (returns{events, next_cursor})poll_session(): Long-poll for session-specific events_create_permission_callback(): Async permission prompts_create_message_callback(): Message wrapping for event queue broadcast_on_state_change(): Broadcast session state changes
src/session_coordinator.py (1050 lines) - Central Orchestrator
Main Class: SessionCoordinator
Responsibilities:
- Ties together SessionManager, ProjectManager, ClaudeSDK, DataStorage, MessageProcessor
- Manages active SDK instances per session
- Handles ExitPlanMode detection and auto-reset
- Permission update tracking
- Tool use tracking for orphaned detection
Key Methods:
create_session(): Session + storage + SDK initialization (lines 100-171)start_session(): Start/resume SDK, send client_launched message (lines 177-289)send_message(): Queue message to SDK, update processing state (lines 538-572)interrupt_session(): Stop active SDK processing (lines 447-492)set_permission_mode(): Runtime permission mode changes (lines 494-536)_create_message_callback(): Process SDK messages, detect completion (lines 741-818)
src/session_manager.py - Session Lifecycle & State
Main Classes: SessionState (enum), SessionInfo (dataclass), SessionManager
SessionState Values:
CREATED,STARTING,ACTIVE,PAUSED,TERMINATING,TERMINATED,ERROR
SessionInfo Fields (Extended for Legion):
- Standard:
session_id,state,working_directory,current_permission_mode,tools,model,name,order - Legion:
is_minion,role,is_overseer,parent_overseer_id,child_minion_ids,capabilities,initialization_context
Key Methods:
create_session(): Create directory, persist state.jsonstart_session(),pause_session(),terminate_session(): State transitionsupdate_processing_state(): Track active processingupdate_permission_mode(): Runtime mode changes
src/project_manager.py - Project Hierarchy & Organization
Main Classes: ProjectInfo (dataclass), ProjectManager
ProjectInfo Fields (Extended for Legion):
- Standard:
project_id,name,working_directory,session_ids,is_expanded,order - Legion:
is_multi_agent,minion_ids,max_concurrent_minions,active_minion_count
Key Methods:
create_project(): Create with order shiftingadd_session_to_project(),remove_session_from_project()reorder_projects(),reorder_project_sessions()
src/claude_sdk.py - SDK Wrapper & Message Queue
Main Class: ClaudeSDK
Responsibilities:
- Wraps Claude Agent SDK with async queue
- Manages conversation loop
- Handles streaming responses
- MCP server integration for Legion tools
Key Components:
_message_queue: Async queue for user messages_conversation_task: Background processing loop_sdk_client: ClaudeSDKClient instance_mcp_server: Optional MCP server for Legion tools
Key Methods:
start(): Initialize SDK client, start conversation loopsend_message(): Enqueue messageinterrupt_session(): Set interrupt flagset_permission_mode(): Send mode change to SDK_conversation_loop(): Process queue, stream responses
src/message_parser.py - Message Normalization
Main Classes: MessageType (enum), ParsedMessage (dataclass), MessageProcessor
Responsibilities:
- Convert between SDK objects, storage format, and event-queue format
- Unified processing for consistency
Handlers: SystemMessageHandler, AssistantMessageHandler, UserMessageHandler, ResultMessageHandler, PermissionRequestHandler, PermissionResponseHandler
MessageProcessor Methods:
process_message(): Raw SDK message → ParsedMessageprepare_for_storage(): ParsedMessage → JSON-serializable dictprepare_for_websocket(): Format for frontend
src/data_storage.py - Persistent Storage
Main Class: DataStorageManager
Files Managed:
messages.jsonl: Append-only message logstate.json: Session metadata (managed by SessionManager)
Key Methods:
append_message(),read_messages(),get_message_count(),cleanup()
Additional Backend Modules (src/)
application_service.py: Top-level service facade used byweb_server.pyconfig_manager.py:~/.config/cc_webui/config.jsonread/write (network binding, auth settings)docker_utils.py: Docker image/mount configuration helpers for per-session isolationevent_queue.py:EventQueue— cursor-based async event buffer backing long-polling endpointsexception_handlers.py: FastAPI exception handler registrationfile_upload.py: Multipart file upload handling and session attachment storagehistory_distiller.py: Session history summarization for archival context continuitylegion_system.py: Top-level Legion system wiring (coordinator + overseer + comm router)mcp_config_manager.py: Per-session MCP server configuration persistence (STDIO/SSE/HTTP, OAuth)mock_sdk.py:MockClaudeSDK— fixture replay for testing without live SDK callsoauth_manager.py: OAuth 2.1 token acquisition and storageoauth_refresh_manager.py: Background OAuth token refresh looppermission_service.py: Permission evaluation and decision routingsession_config.py: Session configuration dataclass combining all per-session optionstask_utils.py: SDK task reconstruction helpers used bytask.jsstore synctemplate_variables.py: Template variable substitution (e.g.,{{session_id}})timestamp_utils.py: Consistent timestamp parsing/formatting across storage and API
Legion Multi-Agent System
Legion Components (src/legion/)
src/legion/legion_coordinator.py - Legion Lifecycle Management
Main Class: LegionCoordinator
Responsibilities:
- Legion creation and deletion
- Fleet control (halt all, resume all, emergency halt)
- Central capability registry (MVP: keyword search)
src/legion/overseer_controller.py - Minion Management
Main Class: OverseerController
Responsibilities:
- Minion lifecycle: create_minion_for_user(), spawn_minion(), dispose_minion()
- Enforce parent authority (only parent can dispose children)
- Memory transfer on disposal
- Capability registration
src/legion/comm_router.py - Inter-Agent Communication
Main Class: CommRouter
Responsibilities:
- Convert between Comms and SDK Messages
- Route Comms to minions or user
- Handle interrupt priorities (HALT, PIVOT)
- Persist to timeline and minion logs
- Parse and validate #tag references
src/legion/memory_manager.py - Memory & Learning (Planned)
Main Class: MemoryManager
Responsibilities (Future):
- Distill task completions into structured memories
- Reinforce memories based on outcome feedback
- Promote high-quality memories to long-term
- Transfer knowledge between minions
- Support minion forking with memory copy
src/legion/legion_mcp_tools.py - MCP Tools for Minions
Main Class: LegionMCPTools
Tools Provided:
- Communication:
send_comm - Lifecycle:
spawn_minion,dispose_minion - Discovery:
list_minions,get_minion_info,search_capability
Integration: Single instance per legion, attached to all minion SDK sessions
Legion Data Models (src/legion/models.py)
Core Entities:
Comm: High-level message with routing infoCommTypeenum: TASK, QUESTION, REPORT, INFO, HALT, PIVOT, THOUGHT, SPAWN, DISPOSE, SYSTEMMemoryEntry,MinionMemory: Knowledge management (future)
Additional Backend Systems
Queue System (src/queue_manager.py, src/queue_processor.py)
FIFO message queue with JSONL persistence for timed/sequential message delivery.
- QueueManager: State management with
QueueItemdataclass (queue_id, session_id, content, reset_session, status, position). Storage viaqueue.jsonlwith event replay on startup. - QueueProcessor: Background asyncio task delivering queued messages with timing guards (
min_wait_seconds=10,min_idle_seconds=10). Auto-starts sessions, handles pausing, pollsis_processingwithout timeout.
Cron Scheduler (src/legion/scheduler_service.py)
Background service evaluating cron schedules every 30 seconds.
- SchedulerService: Creates/manages
Scheduleobjects with croniter evaluation. Enqueues prompts via SessionCoordinator when due. RecordsScheduleExecutionhistory to JSONL. Auto-cancels on minion disposal. - Models:
Schedule(cron, next_run, status, failure tracking),ScheduleExecution(execution record),ScheduleStatus(ACTIVE/PAUSED/CANCELLED)
Archive Manager (src/legion/archive_manager.py)
Timestamped archival of minion session data before disposal.
- ArchiveManager: Copies messages.jsonl, state.json, and disposal metadata to
data/archives/minions/{minion_id}/{timestamp}/. ReturnsArchiveResultwith archive path and file count.
Permission Resolver (src/permission_resolver.py)
Multi-source permission merge for effective permission preview.
resolve_effective_permissions(): Parses permissions from user/project/local settings files and session-level allowed_tools. Returns list of{permission, sources}with source tracking.
Resource MCP Tools (src/resource_mcp_tools.py)
Session-scoped MCP server for agent resource display in the task panel.
- ResourceMCPTools: Creates per-session MCP servers with
register_resourceandregister_image(deprecated alias) tools. Validates file path, extension, size (10MB max, 100 per session). Broadcastsresource_registeredvia WebSocket.
Template Manager (src/template_manager.py)
File-based minion template CRUD with slug naming.
- TemplateManager: Stores templates as JSON+MD file pairs in
data/templates/. Supports slug-based filenames for human readability. Seeds default templates fromsrc/default_templates/. Migrates legacy UUID filenames on load.
Skill Manager (src/skill_manager.py)
Global skill deployment and symlink management.
- SkillManager: Syncs skills from
src/default_skills/to~/.cc_webui/skills/, creates symlinks in~/.claude/skills/. Detects conflicts with user files. Returns (added, updated, removed) counts.
Data Directory Structure
data/
├── logs/ # Per-category debug logs
│ ├── coordinator.log # SessionCoordinator actions
│ ├── error.log # All errors
│ ├── parser.log # Message parsing
│ ├── sdk_debug.log # SDK integration
│ ├── storage.log # File operations
│ └── polling.log # Poll transport signal logging
│
├── projects/{uuid}/ # One folder per project
│ └── state.json # ProjectInfo serialized
│
├── sessions/{uuid}/ # One folder per session
│ ├── state.json # SessionInfo serialized
│ ├── messages.jsonl # Append-only message log
│ ├── queue.jsonl # Message queue event log
│ └── resources/ # Registered resources (images/files)
│
├── templates/ # Minion templates (JSON + MD pairs)
│ ├── {slug}.json # Template configuration
│ └── {slug}.md # Template system prompt
│
├── archives/ # Archived minion data (post-disposal)
│ └── minions/{minion_id}/{ts}/ # Timestamped snapshots
│
└── legions/{uuid}/ # One folder per legion (multi-agent project)
├── timeline.jsonl # Unified comm log
├── schedules.json # Cron schedule definitions
├── schedule_history.jsonl # Schedule execution log
└── minions/{minion_id}/
├── minion_state.json
├── session_messages.jsonl # SDK messages
├── short_term_memory.json # (Future)
└── long_term_memory.json # (Future)
API Endpoint Reference
For the complete endpoint reference with request/response details, see .claude/API_REFERENCE.md.
Summary: 50+ REST endpoints across 10 domains (projects, sessions, files, resources, diffs, queue, legion, schedules, templates, system) + 2 HTTP long-polling endpoints (/api/poll/ui, /api/poll/session/{id}).
Message Flow Architecture
SDK Message → Storage → Long-Poll Event Flow
1. ClaudeSDK receives message from claude_agent_sdk
↓
2. ClaudeSDK._conversation_loop() extracts message data
↓
3. Calls message_callback (SessionCoordinator._create_message_callback)
↓
4. MessageProcessor.process_message() normalizes to ParsedMessage
↓
5. SessionCoordinator stores via DataStorageManager.append_message()
├─ MessageProcessor.prepare_for_storage() converts to dict
└─ Writes to messages.jsonl
↓
6. SessionCoordinator pushes event to session EventQueue
└─ EventQueue.put() wakes any waiting poll request
↓
7. Frontend poll loop receives {events, next_cursor}, updates Pinia stores reactively
User Message → SDK Flow
1. User types in frontend, clicks Send
↓
2. Frontend POST /api/sessions/{id}/messages {message: "..."}
↓
3. web_server.py REST handler receives request
↓
4. Calls SessionCoordinator.send_message(session_id, content)
↓
5. SessionCoordinator marks session.is_processing = True
↓
6. ClaudeSDK.send_message() enqueues to _message_queue
↓
7. ClaudeSDK._conversation_loop() picks up from queue
↓
8. Sends to claude_agent_sdk via query(prompt=message)
↓
9. SDK streams back responses (loop back to SDK Message flow)
↓
10. On ResultMessage, SessionCoordinator sets is_processing = False
Permission Flow
1. SDK needs permission for tool (e.g., Edit, Write)
↓
2. SDK calls permission_callback() from web_server.py
↓
3. web_server.py stores permission request message (with suggestions if any)
↓
4. web_server.py pushes permission_request event to session EventQueue
↓
5. Frontend poll loop receives event, displays permission modal with suggestions
↓
6. User clicks Allow/Deny (optionally applies suggestions)
↓
7. Frontend POST /api/sessions/{id}/permission/{request_id}
↓
8. web_server.py resolves asyncio.Future with user's decision
↓
9. Permission callback returns {behavior: "allow"/"deny", updated_permissions: [...]}
↓
10. SDK receives response and continues/aborts tool execution
Common Development Scenarios
Finding Where Functionality Lives
Problem: Need to change how Edit tool is displayed
→ Solution: frontend/src/components/messages/tools/EditToolHandler.vue
Problem: Session not starting, need to debug SDK initialization
→ Solution: src/session_coordinator.py:177-289 (start_session()) + enable --debug-sdk
Problem: Long-poll events not arriving
→ Solution: Check src/web_server.py poll endpoints and src/event_queue.py; enable --debug-polling
Problem: Messages not persisting
→ Solution: src/data_storage.py:51-67 (append_message()) + enable --debug-storage
Problem: Permission callback not triggering
→ Solution: src/web_server.py:984-1185 (_create_permission_callback()) + enable --debug-permissions
Problem: Add new REST endpoint
→ Solution: Add route in src/web_server.py:232-635 (_setup_routes())
Problem: Add new Vue component
→ Solution: Create .vue file, register in parent component or router
Problem: Add new tool handler → Solution: See TOOL_HANDLERS.md for Vue 3 component creation guide
Understanding State Management
Session States (SessionState enum):
CREATED: Session exists but SDK not startedSTARTING: Transitioning to activeACTIVE: SDK running, can send/receive messagesPAUSED: Awaiting user input (permissions)TERMINATED: SDK stopped cleanlyERROR: Startup or runtime failure (checkerror_messagefield)
Processing State (is_processing boolean):
True: Session actively processing user input (disable send button)False: Session idle, ready for new input- Automatically reset on
ResultMessageor errors
Permission Modes:
default: Prompt for everything not pre-approved in .claude/settingsacceptEdits: Auto-approve Edit/Write/etc (permissive)plan: Planning mode (auto-resets to default after ExitPlanMode)bypassPermissions: No prompts at all
Component Dependencies
main.py
└─ web_server.py
├─ session_coordinator.py
│ ├─ session_manager.py
│ ├─ project_manager.py
│ ├─ claude_sdk.py
│ │ ├─ data_storage.py
│ │ ├─ message_parser.py
│ │ └─ logging_config.py
│ ├─ data_storage.py
│ ├─ message_parser.py
│ ├─ queue_manager.py
│ ├─ queue_processor.py
│ ├─ template_manager.py
│ ├─ skill_manager.py
│ ├─ permission_resolver.py
│ ├─ resource_mcp_tools.py
│ ├─ legion/legion_coordinator.py (if multi-agent)
│ │ ├─ legion/overseer_controller.py
│ │ ├─ legion/comm_router.py
│ │ ├─ legion/memory_manager.py
│ │ ├─ legion/legion_mcp_tools.py
│ │ ├─ legion/scheduler_service.py
│ │ └─ legion/archive_manager.py
│ └─ logging_config.py
├─ message_parser.py
└─ logging_config.py
Testing & Development Patterns
Standard Testing Configuration
CRITICAL: Always use port 8001 for testing to avoid conflicts with production on port 8000.
# Test run
uv run python main.py --host 0.0.0.0 --debug-all --data-dir test_data --port 8001
# Production run
uv run python main.py --port 8000
Process Management - REQUIRED PATTERN
CRITICAL: Always kill processes by PID, never by name.
Windows:
# Find process
netstat -ano | findstr ":8001"
# Kill by PID
taskkill /PID <PID> /F
Unix/Linux/macOS:
# Find process
lsof -i :8001
# Kill by PID
kill <PID>
# or: kill -9 <PID>
Running Tests
# All tests
uv run pytest src/tests/ -v
# Specific test file
uv run pytest src/tests/test_session_manager.py -v
# With coverage
uv run pytest src/tests/ --cov=src --cov-report=html
Frontend Development
# Terminal 1: Backend
uv run python main.py --host 0.0.0.0 --port 8001 --debug-all
# Terminal 2: Frontend dev server
cd frontend
npm run dev # http://localhost:5173
Key Architectural Decisions
Why SessionCoordinator?
- Central orchestrator pattern prevents circular dependencies
- Single point of control for SDK lifecycle
- Coordinates state across multiple managers
Why MessageProcessor?
- SDK message format ≠ storage format ≠ WebSocket format
- Unified processing ensures consistency
- Handles backward compatibility as SDK evolves
Why Separate Project and Session Managers?
- Projects = lightweight grouping (working_directory + sessions)
- Sessions = heavy (SDK instances, message history, state)
- Enables multi-project session support (future)
Why JSONL for messages?
- Append-only is safe for concurrent access
- Line-by-line reading enables pagination
- Easy to repair if corruption occurs
- Human-readable for debugging
Why asyncio.Future for permissions?
- SDK permission callback is synchronous from its perspective
- HTTP long-polling response is asynchronous
- Future bridges sync callback ↔ async REST response
Why Vue 3 + Pinia?
- Reactive state management eliminates manual UI updates
- Component architecture improves maintainability
- Vue DevTools provides powerful debugging
- TypeScript support improves code quality
- Hot Module Replacement accelerates development
Why MCP Tools for Legion?
- Explicit intent (no ambiguity in minion actions)
- Structured parameters (type-safe, validated)
- Clear error feedback (minions can act on specific errors)
- Debuggable (tool calls visible in session messages)
- Self-documenting (tool descriptions teach minions usage)
Future Enhancements
Frontend:
- Syntax highlighting for code blocks (highlight.js/Prism)
- Virtual scrolling for large message lists
- Advanced filtering and search
- Multi-user authentication
- Theme customization
Backend:
- PostgreSQL for multi-instance deployments
- Redis for session state caching
- Prometheus metrics exporter
- Rate limiting and abuse prevention
- Multi-user authorization
Legion:
- Memory distillation and reinforcement
- Knowledge transfer on disposal
- Minion forking for A/B testing
- Enhanced capability discovery
Additional Resources
- User Guide: run_guide.md - Setup, usage, troubleshooting
- Frontend Architecture: frontend/CLAUDE.md - Vue 3 stores, components, composables
- API Reference: .claude/API_REFERENCE.md - All REST + long-polling endpoints
- Tool Handlers: TOOL_HANDLERS.md - Vue 3 tool handler development
- Legion Proposal: legion_proposal/LEGION_PROPOSAL.md - Multi-agent design
- MCP Tools: legion_proposal/MCP_TOOLS_ARCHITECTURE.md - Inter-agent communication
- Development Plan: DEVELOPMENT_PLAN.md - Project roadmap
- Claude Agent SDK: https://github.com/anthropics/claude-agent-sdk
Summary
Claude WebUI is a production-ready web interface for Claude Agent SDK with:
Single-Agent Features:
- Real-time streaming conversations with rich tool visualization (22 tool handlers)
- Project/session hierarchy with drag-and-drop reordering
- Four permission modes with smart suggestions and permission preview
- Message queue with timed delivery and auto-start
- Resource gallery (images and files from agents)
- Git diff viewer with per-commit and aggregate views
- Orphaned tool detection and cleanup
- Persistent message storage (JSONL + JSON)
- Vue 3 + Pinia reactive UI (13 stores, 99+ components)
- Mobile-responsive design
Multi-Agent Features (Legion):
- Minion creation and management with templates
- Inter-agent communication (structured Comms)
- Cron-based scheduling for recurring agent tasks
- Timeline view for observability
- MCP tools for explicit minion actions (send_comm, spawn/dispose, discovery)
- Sandbox mode for minions
- Session archival on disposal
Developer Experience:
- Comprehensive debugging tools (per-category logs)
- 50+ REST endpoints + HTTP long-polling event streams
- Extensible architecture (22 tool handlers, easy to add more)
- Hot Module Replacement for instant feedback
- Vue DevTools integration
important-instruction-reminders
Do what has been asked; nothing more, nothing less. NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one. NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User. ALWAYS remove temporary test files after debugging is complete.
There is windows file modification bug in Claude Code. The workaround is: always use complete absolute Windows paths with drive letters and backslashes for ALL file operations. Apply this rule going forward, not just for this file.