chore: remove .planning from tracking and gitignore .planning-archive
These directories contain local planning data that should not be in the repository. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,7 @@ lerna-debug.log*
|
||||
# ===========================
|
||||
.auto-claude/
|
||||
.planning/
|
||||
.planning-archive/
|
||||
.auto-build-security.json
|
||||
.auto-claude-security.json
|
||||
.auto-claude-status
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
# PR Review System Robustness
|
||||
|
||||
## What This Is
|
||||
|
||||
Improvements to Auto Claude's PR review system to make it trustworthy enough to replace human review. The system uses specialist agents (security, logic, quality, codebase-fit) with a finding-validator that re-investigates findings before presenting them. This milestone fixes gaps that cause false positives and missed context.
|
||||
|
||||
## Core Value
|
||||
|
||||
**When the system flags something, it's a real issue.** Trustworthy PR reviews that are faster, more thorough, and more accurate than human review.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Validated
|
||||
|
||||
- ✓ Multi-agent PR review architecture — existing
|
||||
- ✓ Specialist agents (security, logic, quality, codebase-fit) — existing
|
||||
- ✓ Finding-validator for follow-up reviews — existing
|
||||
- ✓ Dismissal tracking with reasons — existing
|
||||
- ✓ CI status enforcement — existing
|
||||
- ✓ Context gathering (diff, comments, related files) — existing
|
||||
|
||||
### Active
|
||||
|
||||
- [ ] **REQ-001**: Finding-validator runs on initial reviews (not just follow-ups)
|
||||
- [ ] **REQ-002**: Fix line 1288 bug — include ai_reviews in follow-up context
|
||||
- [ ] **REQ-003**: Fetch formal PR reviews from `/pulls/{pr}/reviews` API
|
||||
- [ ] **REQ-004**: Add Read/Grep/Glob tool instructions to all specialist prompts
|
||||
- [ ] **REQ-005**: Expand JS/TS import analysis (path aliases, CommonJS, re-exports)
|
||||
- [ ] **REQ-006**: Add Python import analysis (currently skipped)
|
||||
- [ ] **REQ-007**: Increase related files limit from 20 to 50 with prioritization
|
||||
- [ ] **REQ-008**: Add reverse dependency analysis (what imports changed files)
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- Real-time review streaming — complexity, not needed for accuracy goal
|
||||
- Review caching/memoization — premature optimization
|
||||
- Custom specialist agents — current four dimensions sufficient
|
||||
|
||||
## Context
|
||||
|
||||
**Problem**: False positives in PR reviews erode trust. Users have to second-guess every finding, defeating the purpose of automated review.
|
||||
|
||||
**Root cause**: Finding-validator (which catches false positives) only runs during follow-up reviews. Initial reviews present unvalidated findings. Additionally, context gathering has bugs and gaps that cause the AI to make claims without complete information.
|
||||
|
||||
**Existing system**:
|
||||
- `apps/backend/runners/github/` — PR review orchestration
|
||||
- `apps/backend/runners/github/services/parallel_orchestrator_reviewer.py` — initial review
|
||||
- `apps/backend/runners/github/services/parallel_followup_reviewer.py` — follow-up review (has finding-validator)
|
||||
- `apps/backend/runners/github/context_gatherer.py` — gathers PR context
|
||||
- `apps/backend/prompts/github/pr_*.md` — specialist agent prompts
|
||||
|
||||
**Reference**: Full PRD at `docs/PR_REVIEW_SYSTEM_IMPROVEMENTS.md`
|
||||
|
||||
## Constraints
|
||||
|
||||
- **Existing architecture**: Work within current multi-agent PR review structure
|
||||
- **Backward compatibility**: Don't break existing review workflows
|
||||
- **Performance**: Validation step should not significantly slow reviews (run in parallel where possible)
|
||||
|
||||
## Key Decisions
|
||||
|
||||
| Decision | Rationale | Outcome |
|
||||
|----------|-----------|---------|
|
||||
| Add finding-validator to initial reviews | Catches false positives before user sees them | — Pending |
|
||||
| Same validator for initial and follow-up | Consistency, proven approach from follow-up reviews | — Pending |
|
||||
| Expand import analysis incrementally | JS/TS first (REQ-005), Python second (REQ-006) | — Pending |
|
||||
|
||||
---
|
||||
*Last updated: 2026-01-19 after initialization*
|
||||
@@ -1,193 +0,0 @@
|
||||
# Architecture
|
||||
|
||||
**Analysis Date:** 2026-01-19
|
||||
|
||||
## Pattern Overview
|
||||
|
||||
**Overall:** Multi-Agent Orchestration with Electron Desktop UI
|
||||
|
||||
**Key Characteristics:**
|
||||
- Dual-app architecture: Python backend (CLI + agents) + Electron frontend (desktop UI)
|
||||
- Agent-based autonomous coding via Claude Agent SDK
|
||||
- Git worktree isolation for safe parallel development
|
||||
- Phase-based pipeline execution for spec creation and implementation
|
||||
- Event-driven IPC communication between frontend and backend
|
||||
|
||||
## Layers
|
||||
|
||||
**Frontend (Electron Main Process):**
|
||||
- Purpose: Desktop application shell, native OS integration, IPC coordination
|
||||
- Location: `apps/frontend/src/main/`
|
||||
- Contains: Window management, IPC handlers, service managers (terminal, python env, CLI tools)
|
||||
- Depends on: Backend Python CLI, Claude Code CLI
|
||||
- Used by: Renderer process via IPC
|
||||
|
||||
**Frontend (Renderer Process):**
|
||||
- Purpose: React-based user interface
|
||||
- Location: `apps/frontend/src/renderer/`
|
||||
- Contains: Components, Zustand stores, hooks, contexts
|
||||
- Depends on: Main process via preload IPC bridge
|
||||
- Used by: End users
|
||||
|
||||
**Backend Core:**
|
||||
- Purpose: Authentication, SDK client factory, security, workspace management
|
||||
- Location: `apps/backend/core/`
|
||||
- Contains: `client.py` (SDK factory), `auth.py`, `worktree.py`, `workspace.py`, security hooks
|
||||
- Depends on: Claude Agent SDK, project analyzer
|
||||
- Used by: Agents, CLI commands, runners
|
||||
|
||||
**Backend Agents:**
|
||||
- Purpose: AI agent implementations for autonomous coding
|
||||
- Location: `apps/backend/agents/`
|
||||
- Contains: Coder, planner, memory manager, session management
|
||||
- Depends on: Core client, prompts, phase config
|
||||
- Used by: CLI commands, QA loop
|
||||
|
||||
**Backend QA:**
|
||||
- Purpose: Quality assurance validation loop
|
||||
- Location: `apps/backend/qa/`
|
||||
- Contains: QA reviewer, QA fixer, criteria validation, issue tracking
|
||||
- Depends on: Agents, core client
|
||||
- Used by: CLI commands after build completion
|
||||
|
||||
**Backend Spec:**
|
||||
- Purpose: Spec creation pipeline with complexity-based phases
|
||||
- Location: `apps/backend/spec/`
|
||||
- Contains: Pipeline orchestrator, complexity assessment, validation
|
||||
- Depends on: Core client, agents
|
||||
- Used by: CLI spec commands, frontend task creation
|
||||
|
||||
**Backend Security:**
|
||||
- Purpose: Command validation, allowlist management, secrets scanning
|
||||
- Location: `apps/backend/security/`
|
||||
- Contains: Validators, hooks, command parser, secrets scanner
|
||||
- Depends on: Project analyzer
|
||||
- Used by: Core client via pre-tool-use hooks
|
||||
|
||||
**Backend CLI:**
|
||||
- Purpose: Command-line interface and argument routing
|
||||
- Location: `apps/backend/cli/`
|
||||
- Contains: Main entry, build/spec/workspace/QA commands
|
||||
- Depends on: All backend modules
|
||||
- Used by: Entry point (`run.py`), frontend terminal
|
||||
|
||||
## Data Flow
|
||||
|
||||
**Spec Creation Flow:**
|
||||
1. User creates task via frontend or CLI (`--task "description"`)
|
||||
2. `SpecOrchestrator` (`spec/pipeline/orchestrator.py`) initializes
|
||||
3. Complexity assessment determines phase count (3-8 phases)
|
||||
4. `AgentRunner` executes phases: Discovery -> Requirements -> [Research] -> Context -> Spec -> Plan -> Validate
|
||||
5. Each phase uses Claude Agent SDK session with phase-specific prompts
|
||||
6. Output: `spec.md`, `requirements.json`, `context.json`, `implementation_plan.json`
|
||||
|
||||
**Implementation Flow:**
|
||||
1. CLI starts with `python run.py --spec 001`
|
||||
2. `run_autonomous_agent()` in `agents/coder.py` orchestrates
|
||||
3. Planner agent creates subtask-based `implementation_plan.json`
|
||||
4. Coder agent implements subtasks in iteration loop
|
||||
5. Each subtask runs as Claude Agent SDK session
|
||||
6. On completion, QA validation loop runs (`qa/loop.py`)
|
||||
7. QA reviewer validates -> QA fixer fixes issues -> loop until approved
|
||||
|
||||
**Frontend-Backend IPC Flow:**
|
||||
1. Renderer component dispatches action (e.g., start task)
|
||||
2. Zustand store calls `window.api.invoke('ipc-channel', args)`
|
||||
3. Preload script bridges to main process
|
||||
4. IPC handler in `ipc-handlers/` processes request
|
||||
5. Handler spawns Python subprocess or manages terminal
|
||||
6. Events streamed back via IPC to update stores
|
||||
|
||||
**State Management:**
|
||||
- Frontend: Zustand stores per domain (`task-store`, `project-store`, `settings-store`, etc.)
|
||||
- Backend: File-based state (`implementation_plan.json`, `qa_report.md`)
|
||||
- Session recovery: `RecoveryManager` tracks agent sessions for resumption
|
||||
|
||||
## Key Abstractions
|
||||
|
||||
**ClaudeSDKClient:**
|
||||
- Purpose: Configured Claude Agent SDK client with security hooks
|
||||
- Examples: `apps/backend/core/client.py:create_client()`
|
||||
- Pattern: Factory function with multi-layered security (sandbox, permissions, hooks)
|
||||
|
||||
**SpecOrchestrator:**
|
||||
- Purpose: Coordinates spec creation pipeline phases
|
||||
- Examples: `apps/backend/spec/pipeline/orchestrator.py`
|
||||
- Pattern: Orchestrator with dynamic phase selection based on complexity
|
||||
|
||||
**WorktreeManager:**
|
||||
- Purpose: Git worktree isolation for safe parallel builds
|
||||
- Examples: `apps/backend/core/worktree.py`
|
||||
- Pattern: Each spec gets isolated worktree branch (`auto-claude/{spec-name}`)
|
||||
|
||||
**SecurityProfile:**
|
||||
- Purpose: Dynamic command allowlist based on project analysis
|
||||
- Examples: `apps/backend/project_analyzer.py`, `apps/backend/security/`
|
||||
- Pattern: Base + stack-specific + custom commands cached in `.auto-claude-security.json`
|
||||
|
||||
**IPC Handlers:**
|
||||
- Purpose: Bridge between Electron renderer and backend services
|
||||
- Examples: `apps/frontend/src/main/ipc-handlers/`
|
||||
- Pattern: Domain-specific handler modules registered via `ipc-setup.ts`
|
||||
|
||||
## Entry Points
|
||||
|
||||
**Backend CLI:**
|
||||
- Location: `apps/backend/run.py`
|
||||
- Triggers: Terminal, frontend subprocess spawn, direct invocation
|
||||
- Responsibilities: Argument parsing, command routing to `cli/` modules
|
||||
|
||||
**Electron Main:**
|
||||
- Location: `apps/frontend/src/main/index.ts`
|
||||
- Triggers: Application launch
|
||||
- Responsibilities: Window creation, IPC setup, service initialization
|
||||
|
||||
**Renderer Entry:**
|
||||
- Location: `apps/frontend/src/renderer/main.tsx`
|
||||
- Triggers: Window load
|
||||
- Responsibilities: React app mount, store initialization
|
||||
|
||||
**Spec Pipeline:**
|
||||
- Location: `apps/backend/spec/pipeline/orchestrator.py:SpecOrchestrator`
|
||||
- Triggers: CLI `--task`, frontend task creation
|
||||
- Responsibilities: Dynamic phase execution for spec creation
|
||||
|
||||
**Agent Loop:**
|
||||
- Location: `apps/backend/agents/coder.py:run_autonomous_agent()`
|
||||
- Triggers: CLI `--spec 001`, frontend build start
|
||||
- Responsibilities: Subtask iteration, session management, recovery
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Strategy:** Multi-level error handling with recovery support
|
||||
|
||||
**Patterns:**
|
||||
- Agent sessions: `RecoveryManager` tracks state for resumption after interruption
|
||||
- Security validation: Pre-tool-use hooks reject dangerous commands before execution
|
||||
- QA loop: Escalation to human review after max iterations (`MAX_QA_ITERATIONS`)
|
||||
- Git operations: Retry with exponential backoff for network errors
|
||||
- Frontend: Error boundaries with toast notifications
|
||||
|
||||
## Cross-Cutting Concerns
|
||||
|
||||
**Logging:**
|
||||
- Backend: Python `logging` module with task-specific loggers (`task_logger/`)
|
||||
- Frontend: Electron app logger (`app-logger.ts`), Sentry integration
|
||||
|
||||
**Validation:**
|
||||
- Command security: `security/` validators with dynamic allowlists
|
||||
- Spec validation: `spec/validate_pkg/` for implementation plan schema
|
||||
- Tool input: `security/tool_input_validator.py` for Claude tool arguments
|
||||
|
||||
**Authentication:**
|
||||
- OAuth flow: `core/auth.py` manages Claude OAuth tokens
|
||||
- Token storage: Keychain (macOS), Credential Manager (Windows), encrypted file (Linux)
|
||||
- Token validation: Pre-SDK-call validation to prevent encrypted token errors
|
||||
|
||||
**Internationalization:**
|
||||
- Frontend: `react-i18next` with namespace-organized JSON files
|
||||
- Location: `apps/frontend/src/shared/i18n/locales/{en,fr}/`
|
||||
|
||||
---
|
||||
|
||||
*Architecture analysis: 2026-01-19*
|
||||
@@ -1,224 +0,0 @@
|
||||
# Codebase Concerns
|
||||
|
||||
**Analysis Date:** 2026-01-19
|
||||
|
||||
## Tech Debt
|
||||
|
||||
**Large File Complexity:**
|
||||
- Issue: Several core files exceed 1000+ lines, indicating potential need for further modularization
|
||||
- Files:
|
||||
- `apps/backend/core/workspace.py` (2096 lines) - Already refactored but remains large
|
||||
- `apps/backend/runners/github/orchestrator.py` (1607 lines)
|
||||
- `apps/backend/core/worktree.py` (1404 lines)
|
||||
- `apps/backend/runners/github/context_gatherer.py` (1292 lines)
|
||||
- `apps/frontend/src/main/ipc-handlers/task/worktree-handlers.ts` (3149 lines)
|
||||
- `apps/frontend/src/main/ipc-handlers/github/pr-handlers.ts` (2874 lines)
|
||||
- Impact: Difficult to navigate, test, and maintain; increases risk of merge conflicts
|
||||
- Fix approach: Continue modular extraction pattern (workspace.py partially done); extract sub-modules for GitHub orchestrator
|
||||
|
||||
**Deprecated Modules Still in Codebase:**
|
||||
- Issue: Deprecated code remains active and produces warnings
|
||||
- Files:
|
||||
- `apps/backend/runners/github/confidence.py` - Marked deprecated, uses DeprecationWarning
|
||||
- `apps/frontend/src/main/terminal/terminal-manager.ts` - Contains deprecated sync methods
|
||||
- `apps/frontend/src/main/terminal/session-handler.ts` - persistAllSessions deprecated
|
||||
- Impact: Technical confusion, potential runtime warnings, maintenance burden
|
||||
- Fix approach: Remove deprecated modules or complete migration to evidence-based validation
|
||||
|
||||
**Global State / Module-Level Caches:**
|
||||
- Issue: Multiple modules use global variables and module-level caches that are not thread-safe
|
||||
- Files:
|
||||
- `apps/backend/security/profile.py` (5 global variables for caching)
|
||||
- `apps/backend/core/client.py` (_PROJECT_INDEX_CACHE, _CLAUDE_CLI_CACHE)
|
||||
- `apps/backend/core/io_utils.py` (_pipe_broken global)
|
||||
- `apps/backend/core/sentry.py` (_sentry_initialized, _sentry_enabled)
|
||||
- `apps/backend/task_logger/utils.py` (_current_logger global)
|
||||
- Impact: Potential race conditions in multi-threaded scenarios; difficult to test in isolation
|
||||
- Fix approach: Convert to class-based singletons with proper locking; use thread-local storage where appropriate
|
||||
|
||||
**Incomplete TODO Implementation:**
|
||||
- Issue: Critical features have TODO placeholders
|
||||
- Files:
|
||||
- `apps/backend/core/workspace.py:1578` - `_record_merge_completion` not implemented
|
||||
- `apps/backend/merge/conflict_analysis.py:272-283` - Advanced implicit conflict detection not implemented
|
||||
- `apps/frontend/src/renderer/stores/settings-store.ts:214` - i18n keys not implemented
|
||||
- `apps/frontend/src/renderer/components/ideation/EnvConfigModal.tsx:1` - Props interface not defined
|
||||
- Impact: Missing functionality, potential runtime issues
|
||||
- Fix approach: Implement or remove features; document if intentionally deferred
|
||||
|
||||
**Empty Exception Handlers:**
|
||||
- Issue: Many `pass` statements in exception handlers swallow errors silently
|
||||
- Files: 237+ instances of `pass` after exception handling across backend
|
||||
- Locations include:
|
||||
- `apps/backend/core/worktree.py:448`
|
||||
- `apps/backend/services/orchestrator.py:384, 396, 411, 423`
|
||||
- `apps/backend/cli/workspace_commands.py:339-359` (multiple)
|
||||
- `apps/backend/runners/github/memory_integration.py` (multiple)
|
||||
- Impact: Silent failures make debugging difficult; errors may propagate unexpectedly
|
||||
- Fix approach: Add logging to catch blocks; re-raise critical exceptions; document intentional suppressions
|
||||
|
||||
## Known Bugs
|
||||
|
||||
**Status Flip-Flop Bug (Task Store):**
|
||||
- Symptoms: Task status may incorrectly change between terminal states
|
||||
- Files: `apps/frontend/src/renderer/stores/task-store.ts:278, 282, 324, 346`
|
||||
- Trigger: Phase transitions in updateTaskFromPlan
|
||||
- Workaround: Multiple FIX comments added inline; logic guards terminal phases
|
||||
|
||||
**BulkPRDialog Error Detection:**
|
||||
- Symptoms: String-based error detection is fragile
|
||||
- Files: `apps/frontend/src/renderer/components/BulkPRDialog.tsx:32`
|
||||
- Trigger: API error messages changing format
|
||||
- Workaround: None - TODO comment acknowledges the issue
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**Shell=True Usage:**
|
||||
- Risk: Command injection if inputs not properly sanitized
|
||||
- Files:
|
||||
- `apps/backend/core/git_executable.py:134` - Windows 'where' command
|
||||
- `apps/backend/core/gh_executable.py:61` - Windows 'where' command
|
||||
- Current mitigation: Limited to Windows platform detection, not user-controlled input
|
||||
- Recommendations: Document why shell=True is required; ensure no user input reaches these calls
|
||||
|
||||
**Subprocess Execution Spread Across Codebase:**
|
||||
- Risk: Inconsistent security validation; command injection if not properly controlled
|
||||
- Files: 50+ files with subprocess.run/Popen calls
|
||||
- Current mitigation: Security hooks in `apps/backend/security/hooks.py`; allowlist in project_analyzer
|
||||
- Recommendations: Consolidate subprocess calls through centralized wrappers; audit all subprocess calls
|
||||
|
||||
**Environment Variable Handling:**
|
||||
- Risk: Sensitive data exposure through env vars
|
||||
- Files: 100+ os.environ references across backend
|
||||
- Current mitigation: Token validation in `apps/backend/core/auth.py`; encrypted token detection
|
||||
- Recommendations: Audit all env var usage; ensure secrets are not logged; use secure storage APIs
|
||||
|
||||
**Token Decryption Not Implemented:**
|
||||
- Risk: Encrypted tokens fail silently, requiring manual workarounds
|
||||
- Files: `apps/backend/core/auth.py:103-228`
|
||||
- Current mitigation: Clear error messages directing users to alternatives
|
||||
- Recommendations: Implement cross-platform token decryption or improve error UX
|
||||
|
||||
## Performance Bottlenecks
|
||||
|
||||
**Blocking Sleep Calls:**
|
||||
- Problem: time.sleep() calls block threads
|
||||
- Files:
|
||||
- `apps/backend/core/workspace/models.py:129, 218`
|
||||
- `apps/backend/core/worktree.py:95, 106`
|
||||
- `apps/backend/services/orchestrator.py:451`
|
||||
- `apps/backend/runners/github/file_lock.py:172`
|
||||
- `apps/backend/runners/gitlab/glab_client.py:168`
|
||||
- Cause: Synchronous retry logic with exponential backoff
|
||||
- Improvement path: Convert to async operations where possible; use asyncio.sleep for async code
|
||||
|
||||
**Project Index Cache TTL:**
|
||||
- Problem: 5-minute TTL may cause stale data or unnecessary reloads
|
||||
- Files: `apps/backend/core/client.py:43` (_CACHE_TTL_SECONDS = 300)
|
||||
- Cause: Fixed TTL doesn't adapt to project activity
|
||||
- Improvement path: Implement file-watcher invalidation; make TTL configurable
|
||||
|
||||
**Security Profile Cache:**
|
||||
- Problem: Module-level cache with no size limits
|
||||
- Files: `apps/backend/security/profile.py:23-27`
|
||||
- Cause: Global state without eviction policy
|
||||
- Improvement path: Add LRU eviction; consider bounded cache
|
||||
|
||||
## Fragile Areas
|
||||
|
||||
**Merge System:**
|
||||
- Files:
|
||||
- `apps/backend/core/workspace.py` (complex merge orchestration)
|
||||
- `apps/backend/merge/` directory (conflict detection, resolution)
|
||||
- Why fragile: Complex state machine for parallel merges; many edge cases in git operations
|
||||
- Safe modification: Always test with multiple concurrent specs; use DEBUG=true for verbose logging
|
||||
- Test coverage: Tests exist but may not cover all race conditions
|
||||
|
||||
**GitHub Integration:**
|
||||
- Files:
|
||||
- `apps/backend/runners/github/orchestrator.py`
|
||||
- `apps/backend/runners/github/rate_limiter.py`
|
||||
- `apps/backend/runners/github/gh_client.py`
|
||||
- Why fragile: External API dependencies; rate limiting complexity; async/await patterns
|
||||
- Safe modification: Mock external calls in tests; test rate limit scenarios explicitly
|
||||
- Test coverage: Good coverage in `tests/test_github_*.py`
|
||||
|
||||
**Terminal Integration (Frontend):**
|
||||
- Files:
|
||||
- `apps/frontend/src/renderer/stores/terminal-store.ts`
|
||||
- `apps/frontend/src/main/terminal/claude-integration-handler.ts`
|
||||
- Why fragile: Complex state management; IPC communication; PTY lifecycle
|
||||
- Safe modification: Test terminal creation/destruction cycles; watch for memory leaks
|
||||
- Test coverage: Tests exist in `__tests__/` directories
|
||||
|
||||
**Auth/Token Handling:**
|
||||
- Files: `apps/backend/core/auth.py` (898 lines)
|
||||
- Why fragile: Platform-specific code paths; external dependency on Claude CLI; keyring integration
|
||||
- Safe modification: Test on all platforms; verify OAuth flow end-to-end
|
||||
- Test coverage: `tests/test_auth.py` exists
|
||||
|
||||
## Scaling Limits
|
||||
|
||||
**Concurrent Agent Sessions:**
|
||||
- Current capacity: Limited by Claude SDK rate limits and system resources
|
||||
- Limit: No explicit session pooling or queuing
|
||||
- Scaling path: Implement session pool; add retry queues for rate limits
|
||||
|
||||
**Graphiti Memory Database:**
|
||||
- Current capacity: LadybugDB (embedded Kuzu) - single-process access
|
||||
- Limit: No concurrent write support across multiple processes
|
||||
- Scaling path: Consider distributed graph database for multi-user scenarios
|
||||
|
||||
## Dependencies at Risk
|
||||
|
||||
**Deprecated Python Packages:**
|
||||
- Risk: `secretstorage` on Linux has complex DBus dependencies
|
||||
- Impact: Installation failures on minimal Linux systems
|
||||
- Migration plan: Document fallback to .env storage; improve error messages
|
||||
|
||||
**Platform-Specific Code:**
|
||||
- Risk: Windows/macOS/Linux code paths diverge
|
||||
- Impact: Platform-specific bugs (documented in CLAUDE.md)
|
||||
- Migration plan: Centralized platform abstraction in `apps/backend/core/platform/`
|
||||
|
||||
## Missing Critical Features
|
||||
|
||||
**Implicit Conflict Detection:**
|
||||
- Problem: Function rename + usage conflicts not detected
|
||||
- Blocks: Accurate parallel merge conflict resolution
|
||||
- Files: `apps/backend/merge/conflict_analysis.py:272-283`
|
||||
|
||||
**_record_merge_completion:**
|
||||
- Problem: Merge completion not recorded for timeline tracking
|
||||
- Blocks: Full merge history audit trail
|
||||
- Files: `apps/backend/core/workspace.py:1578`
|
||||
|
||||
## Test Coverage Gaps
|
||||
|
||||
**Async Code Testing:**
|
||||
- What's not tested: Many async functions have limited coverage
|
||||
- Files: 70+ files with async functions, 92+ with await statements
|
||||
- Risk: Race conditions in async code may go unnoticed
|
||||
- Priority: High - async bugs are hard to reproduce
|
||||
|
||||
**Platform-Specific Paths:**
|
||||
- What's not tested: Windows-specific code paths on Linux CI
|
||||
- Files: Platform detection in `apps/backend/core/platform/__init__.py`
|
||||
- Risk: Windows-only bugs not caught until user reports
|
||||
- Priority: Medium - CI now runs on all platforms per CLAUDE.md
|
||||
|
||||
**Global State Reset:**
|
||||
- What's not tested: Cache invalidation edge cases
|
||||
- Files: All files with module-level caches
|
||||
- Risk: State leakage between tests
|
||||
- Priority: Medium - add cache reset fixtures
|
||||
|
||||
**Exception Handler Behavior:**
|
||||
- What's not tested: Error paths through empty except blocks
|
||||
- Files: 237+ `pass` statements in exception handlers
|
||||
- Risk: Silent failures in production
|
||||
- Priority: High - add tests that trigger exception paths
|
||||
|
||||
---
|
||||
|
||||
*Concerns audit: 2026-01-19*
|
||||
@@ -1,283 +0,0 @@
|
||||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** 2026-01-19
|
||||
|
||||
## Naming Patterns
|
||||
|
||||
**Files:**
|
||||
- Python: `snake_case.py` (e.g., `project_analyzer.py`, `qa_report.py`)
|
||||
- TypeScript: `kebab-case.ts` or `PascalCase.tsx` for React components
|
||||
- Test files: `test_*.py` (Python), `*.test.ts` (TypeScript)
|
||||
- Config files: lowercase with extension (e.g., `ruff.toml`, `tsconfig.json`)
|
||||
|
||||
**Functions:**
|
||||
- Python: `snake_case` (e.g., `validate_command()`, `get_security_profile()`)
|
||||
- TypeScript: `camelCase` (e.g., `detectRateLimit()`, `parsePhaseEvent()`)
|
||||
|
||||
**Variables:**
|
||||
- Python: `snake_case` for locals, `UPPER_SNAKE_CASE` for constants
|
||||
- TypeScript: `camelCase` for locals, `UPPER_SNAKE_CASE` for constants
|
||||
|
||||
**Classes/Types:**
|
||||
- Python: `PascalCase` (e.g., `SecurityProfile`, `ClaudeSDKClient`)
|
||||
- TypeScript: `PascalCase` for types/interfaces (e.g., `ExecutionParserContext`)
|
||||
|
||||
**Constants:**
|
||||
- Module-level: `UPPER_SNAKE_CASE` (e.g., `DEFAULT_UTILITY_MODEL`, `SAFE_COMMANDS`)
|
||||
- Private cache variables: `_UPPER_SNAKE_CASE` (e.g., `_PROJECT_INDEX_CACHE`)
|
||||
|
||||
## Code Style
|
||||
|
||||
**Formatting - Python (Backend):**
|
||||
- Tool: Ruff (v0.14.10 via pre-commit)
|
||||
- Quote style: Double quotes
|
||||
- Indent style: Spaces (4 spaces per PEP 8)
|
||||
- Line endings: Auto
|
||||
- Key rules enabled:
|
||||
- `E`, `W` (pycodestyle)
|
||||
- `F` (Pyflakes)
|
||||
- `I` (isort)
|
||||
- `B` (flake8-bugbear)
|
||||
- `C4` (flake8-comprehensions)
|
||||
- `UP` (pyupgrade)
|
||||
|
||||
**Formatting - TypeScript (Frontend):**
|
||||
- Tool: Biome (v2.3.11)
|
||||
- Commands:
|
||||
```bash
|
||||
cd apps/frontend && npx biome check --write . # Lint + format
|
||||
```
|
||||
- TypeScript compiler: `tsc --noEmit` for type checking
|
||||
- Strict mode enabled in `tsconfig.json`
|
||||
|
||||
**Linting:**
|
||||
- Python: Ruff handles both linting and formatting
|
||||
- TypeScript: Biome handles both (replaced ESLint for 15-25x faster performance)
|
||||
|
||||
## Import Organization
|
||||
|
||||
**Python Order (enforced by isort via Ruff):**
|
||||
1. Standard library imports (`import os`, `import json`)
|
||||
2. Third-party imports (`from claude_agent_sdk import ...`)
|
||||
3. Local imports (`from core.client import create_client`)
|
||||
|
||||
**TypeScript Order:**
|
||||
1. React/external library imports
|
||||
2. Local component imports
|
||||
3. Type imports
|
||||
|
||||
**Path Aliases (TypeScript):**
|
||||
```typescript
|
||||
// tsconfig.json paths
|
||||
"@/*": ["src/renderer/*"]
|
||||
"@shared/*": ["src/shared/*"]
|
||||
"@preload/*": ["src/preload/*"]
|
||||
"@features/*": ["src/renderer/features/*"]
|
||||
"@components/*": ["src/renderer/shared/components/*"]
|
||||
"@hooks/*": ["src/renderer/shared/hooks/*"]
|
||||
"@lib/*": ["src/renderer/shared/lib/*"]
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Python Patterns:**
|
||||
```python
|
||||
# Try-except with specific exceptions
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=5)
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as e:
|
||||
logger.debug(f"Operation failed: {e}")
|
||||
return None
|
||||
|
||||
# Validation with early return
|
||||
def validate_something(value: str) -> tuple[bool, str]:
|
||||
if not value:
|
||||
return False, "Value is required"
|
||||
if invalid_condition:
|
||||
return False, "Value is invalid because..."
|
||||
return True, ""
|
||||
```
|
||||
|
||||
**TypeScript Patterns:**
|
||||
```typescript
|
||||
// Result object pattern for detection functions
|
||||
interface DetectionResult {
|
||||
isDetected: boolean;
|
||||
message?: string;
|
||||
details?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
function detectSomething(input: string): DetectionResult {
|
||||
if (!input) {
|
||||
return { isDetected: false };
|
||||
}
|
||||
// Detection logic...
|
||||
return { isDetected: true, message: "Detected condition X" };
|
||||
}
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
||||
**Python Framework:** Standard library `logging`
|
||||
|
||||
**Patterns:**
|
||||
```python
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Debug for verbose/diagnostic info
|
||||
logger.debug(f"Cache HIT for {key}")
|
||||
|
||||
# Info for significant operations
|
||||
logger.info(f"Found Claude CLI: {path} (v{version})")
|
||||
|
||||
# Warning for recoverable issues
|
||||
logger.warning(f"Invalid configuration: {value}, using default")
|
||||
|
||||
# Error with context
|
||||
logger.error(f"Failed to process {file}: {error}")
|
||||
```
|
||||
|
||||
**TypeScript Logging:** Console-based in development, suppressed in tests.
|
||||
|
||||
## Comments
|
||||
|
||||
**When to Comment:**
|
||||
- Public functions: Always document with docstrings/JSDoc
|
||||
- Complex algorithms: Explain the "why" not the "what"
|
||||
- Security-related code: Explain security implications
|
||||
- Workarounds: Reference issue numbers
|
||||
|
||||
**Python Docstrings:**
|
||||
```python
|
||||
def create_client(
|
||||
project_dir: Path,
|
||||
spec_dir: Path,
|
||||
model: str,
|
||||
agent_type: str = "coder",
|
||||
) -> ClaudeSDKClient:
|
||||
"""
|
||||
Create a Claude Agent SDK client with multi-layered security.
|
||||
|
||||
Uses AGENT_CONFIGS for phase-aware tool and MCP server configuration.
|
||||
|
||||
Args:
|
||||
project_dir: Root directory for the project (working directory)
|
||||
spec_dir: Directory containing the spec (for settings file)
|
||||
model: Claude model to use
|
||||
agent_type: Agent type identifier from AGENT_CONFIGS
|
||||
|
||||
Returns:
|
||||
Configured ClaudeSDKClient
|
||||
|
||||
Raises:
|
||||
ValueError: If agent_type is not found in AGENT_CONFIGS
|
||||
"""
|
||||
```
|
||||
|
||||
**TypeScript JSDoc:**
|
||||
```typescript
|
||||
/**
|
||||
* Detect rate limit from CLI output.
|
||||
*
|
||||
* @param output - Raw CLI output string
|
||||
* @returns Detection result with isRateLimited flag and optional resetTime
|
||||
*/
|
||||
function detectRateLimit(output: string): RateLimitResult {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Function Design
|
||||
|
||||
**Size:** Keep functions focused on a single responsibility. Functions over 50 lines should be considered for splitting.
|
||||
|
||||
**Parameters:**
|
||||
- Python: Use type hints for all parameters
|
||||
- TypeScript: Use explicit types, avoid `any`
|
||||
- Default values for optional parameters
|
||||
- Keyword arguments for functions with 3+ parameters
|
||||
|
||||
**Return Values:**
|
||||
- Python: Use tuple for multiple returns `-> tuple[bool, str]`
|
||||
- TypeScript: Use result objects for complex returns
|
||||
- Always annotate return types
|
||||
|
||||
## Module Design
|
||||
|
||||
**Python Exports:**
|
||||
- Use `__all__` in `__init__.py` to control public API
|
||||
- Prefix internal functions/classes with underscore
|
||||
|
||||
**TypeScript Barrel Files:**
|
||||
```typescript
|
||||
// index.ts barrel export pattern
|
||||
export { ExecutionPhaseParser } from './execution-phase-parser';
|
||||
export { IdeationPhaseParser } from './ideation-phase-parser';
|
||||
export type { ExecutionParserContext } from './types';
|
||||
```
|
||||
|
||||
## Security Conventions
|
||||
|
||||
**Validation First:**
|
||||
```python
|
||||
# Always validate input before processing
|
||||
def _validate_custom_mcp_server(server: dict) -> bool:
|
||||
"""Validate a custom MCP server configuration for security."""
|
||||
if not isinstance(server, dict):
|
||||
return False
|
||||
|
||||
# Required fields
|
||||
required_fields = {"id", "name", "type"}
|
||||
if not all(field in server for field in required_fields):
|
||||
return False
|
||||
|
||||
# Blocklist dangerous commands
|
||||
DANGEROUS_COMMANDS = {"bash", "sh", "cmd", "powershell"}
|
||||
if command in DANGEROUS_COMMANDS:
|
||||
logger.warning(f"Rejected dangerous command: {command}")
|
||||
return False
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
**Sensitive Commands:** Always use allowlist approach, never blocklist alone.
|
||||
|
||||
## Internationalization (Frontend)
|
||||
|
||||
**Always use i18n for user-facing text:**
|
||||
```tsx
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const { t } = useTranslation(['navigation', 'common']);
|
||||
|
||||
// Correct
|
||||
<span>{t('navigation:items.githubPRs')}</span>
|
||||
|
||||
// Wrong - hardcoded string
|
||||
<span>GitHub PRs</span>
|
||||
```
|
||||
|
||||
**Translation file structure:**
|
||||
- `apps/frontend/src/shared/i18n/locales/en/*.json`
|
||||
- `apps/frontend/src/shared/i18n/locales/fr/*.json`
|
||||
|
||||
## Platform-Specific Code
|
||||
|
||||
**Use platform abstraction module:**
|
||||
```typescript
|
||||
// Correct - use abstraction
|
||||
import { isWindows, getPathDelimiter } from './platform';
|
||||
|
||||
// Wrong - direct check
|
||||
if (process.platform === 'win32') { ... }
|
||||
```
|
||||
|
||||
**Platform modules:**
|
||||
- Frontend: `apps/frontend/src/main/platform/`
|
||||
- Backend: `apps/backend/core/platform/`
|
||||
|
||||
---
|
||||
|
||||
*Convention analysis: 2026-01-19*
|
||||
@@ -1,204 +0,0 @@
|
||||
# External Integrations
|
||||
|
||||
**Analysis Date:** 2026-01-19
|
||||
|
||||
## APIs & External Services
|
||||
|
||||
**Claude AI (Primary):**
|
||||
- Service: Anthropic Claude API via Claude Agent SDK
|
||||
- SDK: `claude-agent-sdk` >= 0.1.19 (Python backend)
|
||||
- Auth: OAuth tokens via system keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service)
|
||||
- Env: `CLAUDE_CODE_OAUTH_TOKEN` or auto-detected from system credential store
|
||||
- Implementation: `apps/backend/core/client.py`, `apps/backend/core/auth.py`
|
||||
|
||||
**CRITICAL: Never use `anthropic.Anthropic()` directly. Always use `create_client()` from `core.client`.**
|
||||
|
||||
**Context7 MCP (Documentation Lookup):**
|
||||
- Service: Upstash Context7 documentation retrieval
|
||||
- SDK: `@upstash/context7-mcp` (spawned via npx)
|
||||
- Auth: None (public MCP server)
|
||||
- Implementation: Configured in `apps/backend/core/client.py` MCP servers
|
||||
- Usage: Automatically available to agents for documentation queries
|
||||
|
||||
**Linear (Optional Project Management):**
|
||||
- Service: Linear issue tracking and project management
|
||||
- SDK: Linear MCP server (HTTP-based)
|
||||
- Auth: `LINEAR_API_KEY` (Bearer token)
|
||||
- Env: `LINEAR_API_KEY`, `LINEAR_TEAM_ID`, `LINEAR_PROJECT_ID`
|
||||
- Implementation: `apps/backend/integrations/linear/integration.py`
|
||||
- Features: Subtask-to-issue sync, progress tracking, stuck task escalation
|
||||
|
||||
**GitHub:**
|
||||
- Service: GitHub API for issues, PRs, releases
|
||||
- SDK: `gh` CLI (subprocess calls)
|
||||
- Auth: GitHub CLI auth (`gh auth login`)
|
||||
- Implementation: `apps/frontend/src/main/ipc-handlers/github/`
|
||||
- Features: Import issues, create PRs, manage releases, triage automation
|
||||
|
||||
**GitLab (Optional):**
|
||||
- Service: GitLab API for issues and merge requests
|
||||
- SDK: `glab` CLI or Personal Access Token
|
||||
- Auth: `glab auth login` or `GITLAB_TOKEN`
|
||||
- Env: `GITLAB_INSTANCE_URL`, `GITLAB_TOKEN`, `GITLAB_PROJECT`
|
||||
- Implementation: `apps/frontend/src/main/ipc-handlers/gitlab/`
|
||||
|
||||
## Data Storage
|
||||
|
||||
**Databases:**
|
||||
- LadybugDB (embedded graph database)
|
||||
- Connection: Local file at `~/.auto-claude/memories/{database_name}`
|
||||
- Client: `real_ladybug` Python package (requires Python 3.12+)
|
||||
- No Docker required - fully embedded
|
||||
- Provider-specific database naming to prevent embedding dimension mismatches
|
||||
|
||||
**File Storage:**
|
||||
- Local filesystem only
|
||||
- Project data: `.auto-claude/` directory per project
|
||||
- Specs: `.auto-claude/specs/{id}-{name}/`
|
||||
- Worktrees: `.auto-claude/worktrees/` (git worktree isolation)
|
||||
|
||||
**Caching:**
|
||||
- Project index cache (5 minute TTL, thread-safe)
|
||||
- CLI path cache (per-session)
|
||||
- Implementation: `apps/backend/core/client.py` (`_PROJECT_INDEX_CACHE`)
|
||||
|
||||
## Memory System (Graphiti)
|
||||
|
||||
**Graph Memory:**
|
||||
- Engine: Graphiti-core + LadybugDB
|
||||
- Purpose: Cross-session context retention, pattern learning
|
||||
- Data: Episodes (insights, discoveries, patterns, gotchas, outcomes)
|
||||
- Config: `apps/backend/integrations/graphiti/config.py`
|
||||
- Memory: `apps/backend/integrations/graphiti/memory.py`
|
||||
|
||||
**Multi-Provider Support:**
|
||||
|
||||
| Provider | LLM | Embedder | Env Vars |
|
||||
|----------|-----|----------|----------|
|
||||
| OpenAI | Yes | Yes | `OPENAI_API_KEY`, `OPENAI_MODEL` |
|
||||
| Anthropic | Yes | No | `ANTHROPIC_API_KEY`, `GRAPHITI_ANTHROPIC_MODEL` |
|
||||
| Azure OpenAI | Yes | Yes | `AZURE_OPENAI_*` (API_KEY, BASE_URL, deployments) |
|
||||
| Voyage AI | No | Yes | `VOYAGE_API_KEY`, `VOYAGE_EMBEDDING_MODEL` |
|
||||
| Google AI | Yes | Yes | `GOOGLE_API_KEY`, `GOOGLE_LLM_MODEL` |
|
||||
| Ollama | Yes | Yes | `OLLAMA_*` (BASE_URL, models, embedding dim) |
|
||||
| OpenRouter | Yes | Yes | `OPENROUTER_API_KEY`, `OPENROUTER_*_MODEL` |
|
||||
|
||||
**Provider Implementation:** `apps/backend/integrations/graphiti/providers_pkg/`
|
||||
|
||||
## Authentication & Identity
|
||||
|
||||
**Claude OAuth:**
|
||||
- Provider: Anthropic Claude Code OAuth
|
||||
- Implementation: `apps/backend/core/auth.py`
|
||||
- Storage:
|
||||
- macOS: Keychain (`/usr/bin/security find-generic-password`)
|
||||
- Windows: `~/.claude/.credentials.json` or Credential Manager
|
||||
- Linux: Secret Service API via DBus (`secretstorage` package)
|
||||
- Token format: `sk-ant-oat01-*` (OAuth access token)
|
||||
- Login flow: `claude` CLI with `/login` command (opens browser)
|
||||
|
||||
**GitHub Auth:**
|
||||
- Provider: GitHub CLI OAuth
|
||||
- Implementation: IPC handlers in frontend
|
||||
- Storage: Managed by `gh` CLI
|
||||
|
||||
**GitLab Auth:**
|
||||
- Provider: GitLab Personal Access Token or glab CLI OAuth
|
||||
- Implementation: `apps/frontend/src/main/ipc-handlers/gitlab/`
|
||||
- Storage: Managed by `glab` CLI or `.env` file
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
**Error Tracking:**
|
||||
- Service: Sentry (optional)
|
||||
- SDK: `@sentry/electron` 7.5.0
|
||||
- Auth: `SENTRY_DSN` (set in CI for official builds)
|
||||
- Env: `SENTRY_DSN`, `SENTRY_TRACES_SAMPLE_RATE`, `SENTRY_PROFILES_SAMPLE_RATE`
|
||||
- Implementation: `apps/frontend/src/main/sentry.ts`
|
||||
- Note: Disabled in forks unless SENTRY_DSN is explicitly set
|
||||
|
||||
**Logs:**
|
||||
- Backend: Python `logging` module (structured JSON in debug mode)
|
||||
- Frontend: `electron-log` (file + console)
|
||||
- Location: Platform-specific logs directory
|
||||
- Debug: Set `DEBUG=true` for verbose output
|
||||
|
||||
## CI/CD & Deployment
|
||||
|
||||
**Hosting:**
|
||||
- Distribution: GitHub Releases (electron-updater compatible)
|
||||
- Auto-update: electron-updater checks GitHub releases
|
||||
|
||||
**CI Pipeline:**
|
||||
- Service: GitHub Actions
|
||||
- Workflow: `.github/workflows/ci.yml`
|
||||
- Matrix: Linux, Windows, macOS
|
||||
- Jobs: test-python, test-frontend, ci-complete (gate job)
|
||||
|
||||
**Release Pipeline:**
|
||||
- Workflow: `.github/workflows/release.yml` (triggered on tag)
|
||||
- Artifacts: DMG, ZIP (macOS), NSIS/ZIP (Windows), AppImage/DEB/Flatpak (Linux)
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
**Required env vars (backend):**
|
||||
```
|
||||
CLAUDE_CODE_OAUTH_TOKEN # Or use system keychain
|
||||
GRAPHITI_ENABLED=true # Enable memory system
|
||||
```
|
||||
|
||||
**Optional env vars (backend):**
|
||||
```
|
||||
ANTHROPIC_BASE_URL # Custom API endpoint
|
||||
LINEAR_API_KEY # Linear integration
|
||||
ELECTRON_MCP_ENABLED # E2E testing
|
||||
DEBUG=true # Verbose logging
|
||||
```
|
||||
|
||||
**Required env vars (frontend):**
|
||||
```
|
||||
# None required - optional debug/Sentry settings
|
||||
```
|
||||
|
||||
**Secrets location:**
|
||||
- Development: `.env` files (gitignored)
|
||||
- CI/CD: GitHub Secrets
|
||||
- Production: System credential stores (no secrets in app bundle)
|
||||
|
||||
## MCP (Model Context Protocol) Servers
|
||||
|
||||
**Built-in MCP Servers:**
|
||||
|
||||
| Server | Purpose | Agent Access | Configuration |
|
||||
|--------|---------|--------------|---------------|
|
||||
| context7 | Documentation lookup | All agents | Auto-enabled |
|
||||
| linear | Project management | All agents | `LINEAR_API_KEY` |
|
||||
| electron | Desktop app automation | QA agents only | `ELECTRON_MCP_ENABLED` |
|
||||
| puppeteer | Web browser automation | QA agents only | Project capability detection |
|
||||
| graphiti-memory | Knowledge graph | All agents | `GRAPHITI_MCP_URL` |
|
||||
| auto-claude | Custom tools | Phase-specific | Auto-enabled |
|
||||
|
||||
**Custom MCP Servers:**
|
||||
- Config: `.auto-claude/.env` (`CUSTOM_MCP_SERVERS` JSON array)
|
||||
- Validation: `apps/backend/core/client.py` (`_validate_custom_mcp_server`)
|
||||
- Allowed commands: `npx`, `npm`, `node`, `python`, `python3`, `uv`, `uvx`
|
||||
|
||||
**Per-Agent MCP Overrides:**
|
||||
- Add servers: `AGENT_MCP_{agent}_ADD=server1,server2`
|
||||
- Remove servers: `AGENT_MCP_{agent}_REMOVE=server1,server2`
|
||||
|
||||
## Webhooks & Callbacks
|
||||
|
||||
**Incoming:**
|
||||
- None (desktop application, no server)
|
||||
|
||||
**Outgoing:**
|
||||
- GitHub API calls (via `gh` CLI)
|
||||
- GitLab API calls (via `glab` CLI or REST)
|
||||
- Linear MCP server (HTTP)
|
||||
- Sentry error reports (if configured)
|
||||
- Auto-update checks (GitHub Releases API)
|
||||
|
||||
---
|
||||
|
||||
*Integration audit: 2026-01-19*
|
||||
@@ -1,140 +0,0 @@
|
||||
# Technology Stack
|
||||
|
||||
**Analysis Date:** 2026-01-19
|
||||
|
||||
## Languages
|
||||
|
||||
**Primary:**
|
||||
- TypeScript 5.9.3 - Electron frontend (desktop UI, IPC handlers, state management)
|
||||
- Python 3.12+ - Backend agents, CLI, integrations, security
|
||||
|
||||
**Secondary:**
|
||||
- JavaScript (ES modules) - Build scripts, configuration
|
||||
- JSON - Configuration, data storage, IPC communication
|
||||
|
||||
## Runtime
|
||||
|
||||
**Environment:**
|
||||
- Node.js >= 24.0.0 (Electron main/renderer processes)
|
||||
- Python 3.12+ (required for LadybugDB/Graphiti memory system)
|
||||
|
||||
**Package Manager:**
|
||||
- npm 10.0.0+ (root monorepo, frontend)
|
||||
- uv (Python backend - fast pip alternative)
|
||||
- Lockfiles: `package-lock.json` (present), Python deps in `requirements.txt`
|
||||
|
||||
## Frameworks
|
||||
|
||||
**Core:**
|
||||
- Electron 39.2.7 - Cross-platform desktop application shell
|
||||
- React 19.2.3 - UI components and state management
|
||||
- Claude Agent SDK >= 0.1.19 - AI agent orchestration (CRITICAL: NOT raw Anthropic API)
|
||||
|
||||
**Testing:**
|
||||
- Vitest 4.0.16 - Frontend unit tests
|
||||
- Playwright 1.52.0 - E2E testing for Electron
|
||||
- pytest 7.0.0+ - Backend Python tests
|
||||
- pytest-asyncio 0.21.0+ - Async test support
|
||||
|
||||
**Build/Dev:**
|
||||
- electron-vite 5.0.0 - Electron build toolchain
|
||||
- Vite 7.2.7 - Frontend bundler
|
||||
- electron-builder 26.4.0 - Cross-platform packaging (dmg, exe, AppImage, deb, flatpak)
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
**Critical (AI/Agent):**
|
||||
- `claude-agent-sdk` >= 0.1.19 - Core AI agent SDK (replaces direct Anthropic API)
|
||||
- `@anthropic-ai/sdk` 0.71.2 - Anthropic client (used by Graphiti providers)
|
||||
|
||||
**Infrastructure:**
|
||||
- `@lydell/node-pty` 1.1.0 - Terminal emulation (native module)
|
||||
- `@xterm/xterm` 6.0.0 - Terminal rendering
|
||||
- `electron-updater` 6.6.2 - Auto-update mechanism
|
||||
- `chokidar` 5.0.0 - File system watching
|
||||
- `zustand` 5.0.9 - React state management
|
||||
|
||||
**UI Components:**
|
||||
- `@radix-ui/*` - Accessible UI primitives (dialogs, dropdowns, tabs, etc.)
|
||||
- `tailwindcss` 4.1.17 - Utility-first CSS
|
||||
- `lucide-react` 0.562.0 - Icons
|
||||
- `motion` 12.23.26 - Animations
|
||||
|
||||
**Memory/Database:**
|
||||
- `real_ladybug` >= 0.13.0 - Embedded graph database (Python 3.12+, no Docker)
|
||||
- `graphiti-core` >= 0.5.0 - Knowledge graph memory layer
|
||||
|
||||
**Observability:**
|
||||
- `@sentry/electron` 7.5.0 - Error tracking (optional, requires SENTRY_DSN)
|
||||
- `electron-log` 5.4.3 - Structured logging
|
||||
|
||||
**Internationalization:**
|
||||
- `i18next` 25.7.3 + `react-i18next` 16.5.0 - Multi-language support (en, fr)
|
||||
|
||||
## Configuration
|
||||
|
||||
**Environment:**
|
||||
- Backend: `apps/backend/.env` (OAuth tokens, integrations, memory config)
|
||||
- Frontend: `apps/frontend/.env` (debug settings, Sentry DSN)
|
||||
- Example files: `.env.example` in both directories
|
||||
|
||||
**Key Backend Env Vars:**
|
||||
```
|
||||
CLAUDE_CODE_OAUTH_TOKEN # Required: OAuth token (or use system keychain)
|
||||
ANTHROPIC_BASE_URL # Optional: Custom API endpoint
|
||||
GRAPHITI_ENABLED # Required: true to enable memory
|
||||
GRAPHITI_LLM_PROVIDER # openai|anthropic|azure_openai|ollama|google|openrouter
|
||||
GRAPHITI_EMBEDDER_PROVIDER # openai|voyage|azure_openai|ollama|google|openrouter
|
||||
LINEAR_API_KEY # Optional: Linear integration
|
||||
ELECTRON_MCP_ENABLED # Optional: E2E testing via Electron MCP
|
||||
```
|
||||
|
||||
**Build:**
|
||||
- `apps/frontend/electron.vite.config.ts` - Electron/Vite build config
|
||||
- `apps/frontend/vitest.config.ts` - Test configuration
|
||||
- `apps/frontend/package.json` (build section) - electron-builder config
|
||||
- `ruff.toml` - Python linting/formatting
|
||||
|
||||
## Platform Requirements
|
||||
|
||||
**Development:**
|
||||
- macOS, Windows, or Linux
|
||||
- Node.js 24+, Python 3.12+
|
||||
- Git (required for worktree isolation)
|
||||
- Git Bash (Windows only, for Claude Code CLI)
|
||||
|
||||
**Production:**
|
||||
- macOS: DMG/ZIP (arm64 + x64)
|
||||
- Windows: NSIS installer/ZIP
|
||||
- Linux: AppImage, DEB, Flatpak
|
||||
- Bundled Python runtime (downloaded via `scripts/download-python.cjs`)
|
||||
|
||||
**CI/CD:**
|
||||
- GitHub Actions (`.github/workflows/ci.yml`)
|
||||
- Matrix testing: Linux, Windows, macOS
|
||||
- Python 3.12 + 3.13 (Linux only)
|
||||
|
||||
## Monorepo Structure
|
||||
|
||||
```
|
||||
autonomous-coding/
|
||||
├── apps/
|
||||
│ ├── backend/ # Python (uv, requirements.txt)
|
||||
│ └── frontend/ # Electron/React (npm, package.json)
|
||||
├── tests/ # Shared test suite
|
||||
├── scripts/ # Build/release scripts
|
||||
└── package.json # Root workspace config
|
||||
```
|
||||
|
||||
**Workspace Commands:**
|
||||
```bash
|
||||
npm run install:all # Install both frontend and backend
|
||||
npm run dev # Start Electron in dev mode
|
||||
npm run build # Build frontend
|
||||
npm run package # Package for current platform
|
||||
npm run test:backend # Run Python tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Stack analysis: 2026-01-19*
|
||||
@@ -1,219 +0,0 @@
|
||||
# Codebase Structure
|
||||
|
||||
**Analysis Date:** 2026-01-19
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
autonomous-coding/
|
||||
├── apps/
|
||||
│ ├── backend/ # Python backend - CLI, agents, core logic
|
||||
│ │ ├── agents/ # Agent implementations (coder, planner, memory)
|
||||
│ │ ├── cli/ # Command-line interface modules
|
||||
│ │ ├── core/ # Client factory, auth, worktree, security
|
||||
│ │ ├── integrations/ # External integrations (Graphiti, Linear)
|
||||
│ │ ├── memory/ # Memory system (sessions, patterns)
|
||||
│ │ ├── merge/ # Git merge conflict resolution
|
||||
│ │ ├── prompts/ # Agent system prompts (.md files)
|
||||
│ │ ├── qa/ # QA validation loop
|
||||
│ │ ├── runners/ # Feature runners (GitHub, GitLab, roadmap, spec)
|
||||
│ │ ├── security/ # Command validators, secrets scanning
|
||||
│ │ ├── spec/ # Spec creation pipeline
|
||||
│ │ └── ui/ # CLI output formatting
|
||||
│ └── frontend/ # Electron desktop app
|
||||
│ ├── src/
|
||||
│ │ ├── main/ # Electron main process
|
||||
│ │ ├── renderer/ # React renderer (components, stores)
|
||||
│ │ ├── preload/ # IPC bridge scripts
|
||||
│ │ └── shared/ # Shared types, constants, i18n
|
||||
│ └── resources/ # App icons, assets
|
||||
├── tests/ # Python test suite
|
||||
├── scripts/ # Build and utility scripts
|
||||
├── docs/ # Documentation
|
||||
└── guides/ # User guides
|
||||
```
|
||||
|
||||
## Directory Purposes
|
||||
|
||||
**`apps/backend/`:**
|
||||
- Purpose: All Python backend code (CLI, agents, core infrastructure)
|
||||
- Contains: Agent implementations, CLI modules, security, integrations
|
||||
- Key files: `run.py` (entry point), `core/client.py` (SDK factory)
|
||||
|
||||
**`apps/backend/agents/`:**
|
||||
- Purpose: AI agent implementations for autonomous coding
|
||||
- Contains: Coder agent loop, planner, memory manager, session utilities
|
||||
- Key files: `coder.py`, `planner.py`, `memory_manager.py`, `session.py`
|
||||
|
||||
**`apps/backend/cli/`:**
|
||||
- Purpose: CLI command implementations
|
||||
- Contains: Build, spec, workspace, QA, batch commands
|
||||
- Key files: `main.py`, `build_commands.py`, `workspace_commands.py`
|
||||
|
||||
**`apps/backend/core/`:**
|
||||
- Purpose: Core infrastructure (client, auth, workspace, platform)
|
||||
- Contains: SDK client factory, OAuth, worktree manager, platform abstraction
|
||||
- Key files: `client.py`, `auth.py`, `worktree.py`, `workspace.py`
|
||||
|
||||
**`apps/backend/qa/`:**
|
||||
- Purpose: QA validation after build completion
|
||||
- Contains: QA loop, reviewer, fixer, criteria validation, issue tracking
|
||||
- Key files: `loop.py`, `reviewer.py`, `fixer.py`, `criteria.py`
|
||||
|
||||
**`apps/backend/spec/`:**
|
||||
- Purpose: Spec creation pipeline
|
||||
- Contains: Pipeline orchestrator, complexity assessment, validation
|
||||
- Key files: `pipeline/orchestrator.py`, `complexity.py`, `validate_pkg/`
|
||||
|
||||
**`apps/backend/security/`:**
|
||||
- Purpose: Bash command validation and security
|
||||
- Contains: Validators, hooks, command parser, secrets scanner
|
||||
- Key files: `hooks.py`, `validator.py`, `parser.py`, `scan_secrets.py`
|
||||
|
||||
**`apps/backend/prompts/`:**
|
||||
- Purpose: Agent system prompts (Markdown files)
|
||||
- Contains: Prompts for coder, planner, QA, spec agents
|
||||
- Key files: `coder.md`, `planner.md`, `qa_reviewer.md`, `spec_gatherer.md`
|
||||
|
||||
**`apps/backend/runners/`:**
|
||||
- Purpose: Feature-specific execution runners
|
||||
- Contains: GitHub PR review, roadmap generation, spec creation
|
||||
- Key files: `github/orchestrator.py`, `spec_runner.py`, `roadmap_runner.py`
|
||||
|
||||
**`apps/frontend/src/main/`:**
|
||||
- Purpose: Electron main process
|
||||
- Contains: Window management, IPC handlers, service managers
|
||||
- Key files: `index.ts`, `ipc-setup.ts`, `cli-tool-manager.ts`
|
||||
|
||||
**`apps/frontend/src/renderer/`:**
|
||||
- Purpose: React UI
|
||||
- Contains: Components, stores, hooks, contexts
|
||||
- Key files: `App.tsx`, `components/`, `stores/`
|
||||
|
||||
**`apps/frontend/src/shared/`:**
|
||||
- Purpose: Shared code between main and renderer
|
||||
- Contains: Types, constants, i18n, utilities
|
||||
- Key files: `types/`, `constants/`, `i18n/`
|
||||
|
||||
## Key File Locations
|
||||
|
||||
**Entry Points:**
|
||||
- `apps/backend/run.py`: Backend CLI entry point
|
||||
- `apps/frontend/src/main/index.ts`: Electron main entry
|
||||
- `apps/frontend/src/renderer/main.tsx`: React app entry
|
||||
|
||||
**Configuration:**
|
||||
- `apps/backend/.env`: Backend environment variables
|
||||
- `apps/backend/.env.example`: Backend env template
|
||||
- `apps/frontend/.env`: Frontend environment variables
|
||||
- `apps/backend/requirements.txt`: Python dependencies
|
||||
- `apps/frontend/package.json`: Frontend dependencies
|
||||
|
||||
**Core Logic:**
|
||||
- `apps/backend/core/client.py`: Claude SDK client factory
|
||||
- `apps/backend/core/auth.py`: OAuth token management
|
||||
- `apps/backend/core/worktree.py`: Git worktree isolation
|
||||
- `apps/backend/agents/coder.py`: Main agent loop
|
||||
- `apps/backend/spec/pipeline/orchestrator.py`: Spec creation pipeline
|
||||
|
||||
**Testing:**
|
||||
- `tests/`: All Python tests (pytest)
|
||||
- `tests/conftest.py`: Pytest fixtures and configuration
|
||||
- `apps/frontend/src/main/__tests__/`: Main process tests
|
||||
- `apps/frontend/src/renderer/__tests__/`: Renderer tests
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
**Files:**
|
||||
- Python modules: `snake_case.py` (e.g., `workspace_commands.py`)
|
||||
- TypeScript modules: `kebab-case.ts` (e.g., `cli-tool-manager.ts`)
|
||||
- React components: `PascalCase.tsx` (e.g., `KanbanBoard.tsx`)
|
||||
- Prompts: `snake_case.md` (e.g., `qa_reviewer.md`)
|
||||
- Tests: `test_*.py` (Python), `*.test.ts/tsx` (TypeScript)
|
||||
|
||||
**Directories:**
|
||||
- Python packages: `snake_case/` with `__init__.py`
|
||||
- TypeScript modules: `kebab-case/`
|
||||
- Package submodules: `*_pkg/` suffix (e.g., `tools_pkg/`, `queries_pkg/`)
|
||||
|
||||
**Classes and Functions:**
|
||||
- Python classes: `PascalCase` (e.g., `SpecOrchestrator`)
|
||||
- Python functions: `snake_case` (e.g., `run_autonomous_agent`)
|
||||
- TypeScript/React: `camelCase` functions, `PascalCase` components
|
||||
|
||||
## Where to Add New Code
|
||||
|
||||
**New Agent Feature:**
|
||||
- Primary code: `apps/backend/agents/`
|
||||
- Prompt: `apps/backend/prompts/{agent_name}.md`
|
||||
- Tests: `tests/test_agent_*.py`
|
||||
|
||||
**New CLI Command:**
|
||||
- Implementation: `apps/backend/cli/{domain}_commands.py`
|
||||
- Registration: `apps/backend/cli/main.py` (argument parsing)
|
||||
- Tests: `tests/test_{command}.py`
|
||||
|
||||
**New Frontend Component:**
|
||||
- Implementation: `apps/frontend/src/renderer/components/{ComponentName}.tsx`
|
||||
- Translations: `apps/frontend/src/shared/i18n/locales/en/{namespace}.json`
|
||||
- Tests: `apps/frontend/src/renderer/components/__tests__/`
|
||||
|
||||
**New Frontend Store:**
|
||||
- Implementation: `apps/frontend/src/renderer/stores/{domain}-store.ts`
|
||||
- Pattern: Use Zustand with typed state and actions
|
||||
|
||||
**New IPC Handler:**
|
||||
- Handler module: `apps/frontend/src/main/ipc-handlers/{domain}-handlers.ts`
|
||||
- Registration: `apps/frontend/src/main/ipc-handlers/index.ts`
|
||||
- Types: `apps/frontend/src/shared/types/`
|
||||
|
||||
**New Security Validator:**
|
||||
- Implementation: `apps/backend/security/validator.py`
|
||||
- Registration: Add to `VALIDATORS` dict in same file
|
||||
- Tests: `tests/test_security.py`
|
||||
|
||||
**New Integration:**
|
||||
- Implementation: `apps/backend/integrations/{service}/`
|
||||
- Configuration: Add env vars to `.env.example`
|
||||
- Documentation: Update `CLAUDE.md`
|
||||
|
||||
**Utilities:**
|
||||
- Backend shared helpers: `apps/backend/core/` or domain-specific module
|
||||
- Frontend shared helpers: `apps/frontend/src/shared/utils/`
|
||||
|
||||
## Special Directories
|
||||
|
||||
**`.auto-claude/`:**
|
||||
- Purpose: Per-project spec storage and build state
|
||||
- Generated: Yes (by backend during spec creation)
|
||||
- Committed: No (gitignored)
|
||||
- Contents: `specs/`, `worktrees/tasks/`, `insights/`
|
||||
|
||||
**`.worktrees/`:**
|
||||
- Purpose: Legacy worktree location (deprecated)
|
||||
- Generated: Yes (by worktree manager)
|
||||
- Committed: No (gitignored)
|
||||
|
||||
**`node_modules/`:**
|
||||
- Purpose: Frontend npm dependencies
|
||||
- Generated: Yes (by npm install)
|
||||
- Committed: No (gitignored)
|
||||
|
||||
**`.venv/`:**
|
||||
- Purpose: Python virtual environment
|
||||
- Generated: Yes (by uv venv)
|
||||
- Committed: No (gitignored)
|
||||
|
||||
**`dist/` and `out/`:**
|
||||
- Purpose: Build outputs
|
||||
- Generated: Yes (by build scripts)
|
||||
- Committed: No (gitignored)
|
||||
|
||||
**`.planning/`:**
|
||||
- Purpose: GSD planning documents
|
||||
- Generated: Yes (by GSD commands)
|
||||
- Committed: Optional (project choice)
|
||||
|
||||
---
|
||||
|
||||
*Structure analysis: 2026-01-19*
|
||||
@@ -1,485 +0,0 @@
|
||||
# Testing Patterns
|
||||
|
||||
**Analysis Date:** 2026-01-19
|
||||
|
||||
## Test Framework
|
||||
|
||||
**Backend (Python):**
|
||||
- Runner: pytest (>=7.0.0)
|
||||
- Config: `tests/pytest.ini`
|
||||
- Async support: pytest-asyncio (>=0.21.0)
|
||||
- Coverage: pytest-cov (>=4.0.0)
|
||||
- Mocking: pytest-mock (>=3.0.0)
|
||||
|
||||
**Frontend (TypeScript):**
|
||||
- Runner: Vitest (v4.0.16)
|
||||
- Config: `apps/frontend/vitest.config.ts`
|
||||
- DOM testing: @testing-library/react, @testing-library/dom
|
||||
- Mocking: Vitest built-in `vi`
|
||||
|
||||
**Run Commands:**
|
||||
```bash
|
||||
# Backend - all tests
|
||||
apps/backend/.venv/bin/pytest tests/ -v
|
||||
|
||||
# Backend - skip slow tests (recommended for development)
|
||||
apps/backend/.venv/bin/pytest tests/ -m "not slow" -v
|
||||
|
||||
# Backend - single test file
|
||||
apps/backend/.venv/bin/pytest tests/test_security.py -v
|
||||
|
||||
# Backend - specific test
|
||||
apps/backend/.venv/bin/pytest tests/test_security.py::test_bash_command_validation -v
|
||||
|
||||
# Frontend - all tests
|
||||
cd apps/frontend && npm test
|
||||
|
||||
# Frontend - watch mode
|
||||
cd apps/frontend && npm run test:watch
|
||||
|
||||
# Frontend - coverage
|
||||
cd apps/frontend && npm run test:coverage
|
||||
|
||||
# From root (convenience)
|
||||
npm run test:backend
|
||||
npm run test (frontend)
|
||||
```
|
||||
|
||||
## Test File Organization
|
||||
|
||||
**Backend Location:** Co-located at root `tests/` directory
|
||||
```
|
||||
tests/
|
||||
├── pytest.ini # Pytest configuration
|
||||
├── conftest.py # Shared fixtures
|
||||
├── test_fixtures.py # Sample data constants
|
||||
├── review_fixtures.py # Review system fixtures
|
||||
├── qa_report_helpers.py # QA test helpers
|
||||
├── requirements-test.txt # Test dependencies
|
||||
├── test_security.py # Security module tests
|
||||
├── test_client.py # SDK client tests
|
||||
├── test_qa_loop.py # QA system tests
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Frontend Location:** Co-located with source, in `__tests__/` directories
|
||||
```
|
||||
apps/frontend/src/
|
||||
├── __tests__/
|
||||
│ ├── setup.ts # Test setup (mocks, globals)
|
||||
│ └── integration/ # Integration tests
|
||||
├── main/__tests__/ # Main process tests
|
||||
│ ├── parsers.test.ts
|
||||
│ ├── rate-limit-detector.test.ts
|
||||
│ └── ...
|
||||
├── renderer/__tests__/ # Renderer tests
|
||||
│ ├── task-store.test.ts
|
||||
│ └── ...
|
||||
└── renderer/components/__tests__/ # Component tests
|
||||
```
|
||||
|
||||
**Naming:**
|
||||
- Python: `test_*.py` (e.g., `test_security.py`)
|
||||
- TypeScript: `*.test.ts` or `*.test.tsx` (e.g., `parsers.test.ts`)
|
||||
|
||||
## Test Structure
|
||||
|
||||
**Python - pytest Pattern:**
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests for Security System
|
||||
=========================
|
||||
|
||||
Tests the security.py module functionality including:
|
||||
- Command extraction and parsing
|
||||
- Command allowlist validation
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from security import validate_command, extract_commands
|
||||
|
||||
|
||||
class TestCommandExtraction:
|
||||
"""Tests for command extraction from shell strings."""
|
||||
|
||||
def test_simple_command(self):
|
||||
"""Extracts single command correctly."""
|
||||
commands = extract_commands("ls -la")
|
||||
assert commands == ["ls"]
|
||||
|
||||
def test_piped_commands(self):
|
||||
"""Extracts all commands from pipeline."""
|
||||
commands = extract_commands("cat file.txt | grep pattern | wc -l")
|
||||
assert commands == ["cat", "grep", "wc"]
|
||||
|
||||
|
||||
class TestValidateCommand:
|
||||
"""Tests for full command validation."""
|
||||
|
||||
def test_base_commands_allowed(self, temp_dir):
|
||||
"""Base commands are always allowed."""
|
||||
for cmd in ["ls", "cat", "grep"]:
|
||||
allowed, reason = validate_command(cmd, temp_dir)
|
||||
assert allowed is True, f"{cmd} should be allowed"
|
||||
```
|
||||
|
||||
**TypeScript - Vitest Pattern:**
|
||||
```typescript
|
||||
/**
|
||||
* Phase Parsers Tests
|
||||
* ====================
|
||||
* Unit tests for the specialized phase parsers.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { ExecutionPhaseParser } from '../agent/parsers';
|
||||
|
||||
describe('ExecutionPhaseParser', () => {
|
||||
const parser = new ExecutionPhaseParser();
|
||||
|
||||
const makeContext = (currentPhase: string): ExecutionParserContext => ({
|
||||
currentPhase,
|
||||
isTerminal: currentPhase === 'complete'
|
||||
});
|
||||
|
||||
describe('structured event parsing', () => {
|
||||
it('should parse structured phase events', () => {
|
||||
const log = '__EXEC_PHASE__:{"phase":"coding","message":"Starting"}';
|
||||
const result = parser.parse(log, makeContext('planning'));
|
||||
|
||||
expect(result).toEqual({
|
||||
phase: 'coding',
|
||||
message: 'Starting',
|
||||
currentSubtask: undefined
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('terminal state handling', () => {
|
||||
it('should not change phase when current phase is complete', () => {
|
||||
const log = 'Starting coder agent...';
|
||||
const result = parser.parse(log, makeContext('complete'));
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Mocking
|
||||
|
||||
**Python - pytest fixtures and unittest.mock:**
|
||||
```python
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
@pytest.fixture
|
||||
def mock_task_logger():
|
||||
"""Mock TaskLogger for testing PhaseExecutor."""
|
||||
logger = MagicMock()
|
||||
logger.log = MagicMock()
|
||||
logger.start_phase = MagicMock()
|
||||
logger.end_phase = MagicMock()
|
||||
return logger
|
||||
|
||||
# Using patch decorator
|
||||
@patch('core.client.find_claude_cli')
|
||||
def test_client_creation(mock_find_cli):
|
||||
mock_find_cli.return_value = '/usr/local/bin/claude'
|
||||
# Test code...
|
||||
|
||||
# Using monkeypatch fixture
|
||||
def test_with_env_var(monkeypatch):
|
||||
monkeypatch.setenv("CLAUDE_CLI_PATH", "/custom/path")
|
||||
# Test code...
|
||||
```
|
||||
|
||||
**TypeScript - Vitest vi.mock:**
|
||||
```typescript
|
||||
// Mock at module level (hoisted)
|
||||
vi.mock('../claude-profile-manager', () => ({
|
||||
getClaudeProfileManager: vi.fn(() => ({
|
||||
getActiveProfile: vi.fn(() => ({
|
||||
id: 'test-profile-id',
|
||||
name: 'Test Profile'
|
||||
})),
|
||||
recordRateLimitEvent: vi.fn()
|
||||
}))
|
||||
}));
|
||||
|
||||
describe('Rate Limit Detector', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should detect rate limit', async () => {
|
||||
const { detectRateLimit } = await import('../rate-limit-detector');
|
||||
const result = detectRateLimit('Limit reached · resets Dec 17');
|
||||
expect(result.isRateLimited).toBe(true);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**What to Mock:**
|
||||
- External APIs (Claude SDK, GitHub API)
|
||||
- File system operations in unit tests
|
||||
- Network requests
|
||||
- System time (for time-sensitive tests)
|
||||
- Heavy dependencies (databases, MCP servers)
|
||||
|
||||
**What NOT to Mock:**
|
||||
- Pure functions under test
|
||||
- Simple data transformations
|
||||
- Validation logic
|
||||
|
||||
## Fixtures and Factories
|
||||
|
||||
**Python Fixtures (conftest.py):**
|
||||
```python
|
||||
@pytest.fixture
|
||||
def temp_dir() -> Generator[Path, None, None]:
|
||||
"""Create a temporary directory that's cleaned up after the test."""
|
||||
temp_path = Path(tempfile.mkdtemp())
|
||||
yield temp_path
|
||||
shutil.rmtree(temp_path, ignore_errors=True)
|
||||
|
||||
@pytest.fixture
|
||||
def temp_git_repo(temp_dir: Path) -> Generator[Path, None, None]:
|
||||
"""Create a temporary git repository with initial commit."""
|
||||
# Clear git environment variables to isolate from parent repo
|
||||
orig_env = {}
|
||||
git_vars_to_clear = ["GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE"]
|
||||
for key in git_vars_to_clear:
|
||||
orig_env[key] = os.environ.get(key)
|
||||
if key in os.environ:
|
||||
del os.environ[key]
|
||||
|
||||
try:
|
||||
subprocess.run(["git", "init"], cwd=temp_dir, capture_output=True)
|
||||
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=temp_dir)
|
||||
# ...
|
||||
yield temp_dir
|
||||
finally:
|
||||
# Restore environment
|
||||
for key, value in orig_env.items():
|
||||
if value is None:
|
||||
os.environ.pop(key, None)
|
||||
else:
|
||||
os.environ[key] = value
|
||||
|
||||
@pytest.fixture
|
||||
def python_project(temp_git_repo: Path) -> Path:
|
||||
"""Create a sample Python project structure."""
|
||||
(temp_git_repo / "pyproject.toml").write_text(toml_content)
|
||||
(temp_git_repo / "app" / "__init__.py").write_text("# App module\n")
|
||||
return temp_git_repo
|
||||
```
|
||||
|
||||
**TypeScript Setup (setup.ts):**
|
||||
```typescript
|
||||
import { vi, beforeEach, afterEach } from 'vitest';
|
||||
|
||||
// Mock localStorage for tests
|
||||
const localStorageMock = (() => {
|
||||
let store: Record<string, string> = {};
|
||||
return {
|
||||
getItem: vi.fn((key: string) => store[key] || null),
|
||||
setItem: vi.fn((key: string, value: string) => { store[key] = value; }),
|
||||
clear: vi.fn(() => { store = {}; })
|
||||
};
|
||||
})();
|
||||
|
||||
Object.defineProperty(global, 'localStorage', { value: localStorageMock });
|
||||
|
||||
// Mock window.electronAPI for renderer tests
|
||||
if (typeof window !== 'undefined') {
|
||||
(window as any).electronAPI = {
|
||||
getTasks: vi.fn(),
|
||||
createTask: vi.fn(),
|
||||
getSettings: vi.fn(),
|
||||
// ...
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
localStorageMock.clear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetModules();
|
||||
});
|
||||
```
|
||||
|
||||
**Sample Data (test_fixtures.py):**
|
||||
```python
|
||||
SAMPLE_REACT_COMPONENT = '''import React from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
function App() {
|
||||
const [count, setCount] = useState(0);
|
||||
return <div><h1>Hello World</h1></div>;
|
||||
}
|
||||
export default App;
|
||||
'''
|
||||
|
||||
SAMPLE_PYTHON_MODULE = '''"""Sample Python module."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
def hello():
|
||||
"""Say hello."""
|
||||
print("Hello")
|
||||
'''
|
||||
```
|
||||
|
||||
## Coverage
|
||||
|
||||
**Requirements:** No enforced minimum threshold, but aim for meaningful coverage
|
||||
|
||||
**View Coverage:**
|
||||
```bash
|
||||
# Backend
|
||||
apps/backend/.venv/bin/pytest tests/ --cov=apps/backend --cov-report=html
|
||||
|
||||
# Frontend
|
||||
cd apps/frontend && npm run test:coverage
|
||||
```
|
||||
|
||||
**Coverage Output:**
|
||||
- Backend: `.coverage` file, HTML report in `htmlcov/`
|
||||
- Frontend: `coverage/` directory with JSON, text, and HTML reports
|
||||
|
||||
## Test Types
|
||||
|
||||
**Unit Tests:**
|
||||
- Test individual functions/classes in isolation
|
||||
- Mock external dependencies
|
||||
- Fast execution (sub-second)
|
||||
- Location: `tests/test_*.py`, `src/**/*.test.ts`
|
||||
|
||||
**Integration Tests:**
|
||||
- Test interactions between components
|
||||
- May use real file system, git repos
|
||||
- Slower execution
|
||||
- Markers: `@pytest.mark.integration` (Python)
|
||||
- Location: `tests/` (Python), `src/__tests__/integration/` (TypeScript)
|
||||
|
||||
**E2E Tests (Frontend):**
|
||||
- Framework: Playwright (configured but limited use)
|
||||
- Config: `apps/frontend/e2e/playwright.config.ts`
|
||||
- Run: `npm run test:e2e`
|
||||
|
||||
## Common Patterns
|
||||
|
||||
**Async Testing (Python):**
|
||||
```python
|
||||
import pytest
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_async_function():
|
||||
result = await some_async_operation()
|
||||
assert result is not None
|
||||
|
||||
# pytest.ini enables asyncio_mode = auto
|
||||
# No need to manually mark simple async tests
|
||||
```
|
||||
|
||||
**Async Testing (TypeScript):**
|
||||
```typescript
|
||||
it('should handle async operation', async () => {
|
||||
const { detectRateLimit } = await import('../rate-limit-detector');
|
||||
const result = detectRateLimit('some output');
|
||||
expect(result.isRateLimited).toBe(false);
|
||||
});
|
||||
```
|
||||
|
||||
**Error Testing (Python):**
|
||||
```python
|
||||
def test_blocked_dangerous_command(self, temp_dir):
|
||||
"""Dangerous commands not in allowlist are blocked."""
|
||||
allowed, reason = validate_command("rm -rf /", temp_dir)
|
||||
assert allowed is False
|
||||
assert "not allowed for safety" in reason
|
||||
|
||||
def test_raises_on_invalid_input():
|
||||
"""Should raise ValueError on invalid input."""
|
||||
with pytest.raises(ValueError, match="Invalid configuration"):
|
||||
process_config(None)
|
||||
```
|
||||
|
||||
**Error Testing (TypeScript):**
|
||||
```typescript
|
||||
it('should return false for empty output', async () => {
|
||||
const { detectRateLimit } = await import('../rate-limit-detector');
|
||||
const result = detectRateLimit('');
|
||||
expect(result.isRateLimited).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle malformed input gracefully', () => {
|
||||
expect(() => parser.parse(null as any)).not.toThrow();
|
||||
});
|
||||
```
|
||||
|
||||
**Parameterized Tests (Python):**
|
||||
```python
|
||||
@pytest.mark.parametrize("cmd,expected", [
|
||||
("ls -la", ["ls"]),
|
||||
("cat file | grep pattern", ["cat", "grep"]),
|
||||
("", []),
|
||||
])
|
||||
def test_extract_commands(cmd, expected):
|
||||
assert extract_commands(cmd) == expected
|
||||
```
|
||||
|
||||
**Parameterized Tests (TypeScript):**
|
||||
```typescript
|
||||
const testCases = [
|
||||
'rate limit exceeded',
|
||||
'usage limit reached',
|
||||
'too many requests'
|
||||
];
|
||||
|
||||
for (const output of testCases) {
|
||||
const result = detectRateLimit(output);
|
||||
expect(result.isRateLimited).toBe(true);
|
||||
}
|
||||
```
|
||||
|
||||
## Pre-commit Testing
|
||||
|
||||
**Configuration:** `.pre-commit-config.yaml`
|
||||
|
||||
Tests run automatically on commit:
|
||||
- Python: `pytest -m "not slow and not integration"` (fast tests only)
|
||||
- TypeScript: Biome lint + TypeScript type check
|
||||
|
||||
Skipped tests in pre-commit:
|
||||
- `test_graphiti.py` (external dependencies)
|
||||
- `test_worktree.py` (git-sensitive)
|
||||
- `test_workspace.py` (Windows path issues)
|
||||
|
||||
## Test Markers (Python)
|
||||
|
||||
```python
|
||||
@pytest.mark.slow # Long-running tests
|
||||
@pytest.mark.integration # Integration tests
|
||||
@pytest.mark.asyncio # Async tests (auto-applied via config)
|
||||
```
|
||||
|
||||
**Run specific markers:**
|
||||
```bash
|
||||
# Skip slow tests
|
||||
pytest tests/ -m "not slow"
|
||||
|
||||
# Run only integration tests
|
||||
pytest tests/ -m "integration"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*Testing analysis: 2026-01-19*
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"mode": "yolo",
|
||||
"depth": "comprehensive",
|
||||
"parallelization": true,
|
||||
"created": "2026-01-19"
|
||||
}
|
||||
Reference in New Issue
Block a user