The file C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\APP_SPEC_CONVERSATION.md has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
     1→# Autocoder 2.0 Enhancement Spec - Conversational Format
     2→
     3→Use this as your response during the spec creation interview. Copy/paste or adapt as needed.
     4→
     5→---
     6→
     7→## Initial Project Description
     8→
     9→I want to enhance Autocoder 2.0 - this is an existing, fully functional autonomous coding agent system. It already works and I use it regularly. I'm looking to add new capabilities that will make it exceptional.
    10→
    11→**Current stack:** Python/FastAPI backend, React/TypeScript frontend with Tailwind v4, SQLite database. But I'm open to changes if you think something would work better - feel free to suggest alternatives or refactor if it makes the enhancements cleaner.
    12→
    13→---
    14→
    15→## What Already Exists and Works
    16→
    17→**Core Agent System:**
    18→- Two-agent pattern: Initializer creates features from app spec, Coding agent implements them
    19→- Full agent loop with pause/resume/stop controls
    20→- YOLO mode for rapid prototyping (skips browser testing)
    21→- Auto-continuation between sessions with 3-second delay
    22→
    23→**Feature Management:**
    24→- SQLite database with priority, category, name, description, steps, status
    25→- MCP server exposing 7 tools (get_stats, get_next, mark_passing, etc.)
    26→- Kanban board UI showing pending/in-progress/done
    27→
    28→**Parallel Execution:**
    29→- `parallel_agent.py` - Run multiple agents on non-conflicting features
    30→- `smart_orchestrator.py` - AI-driven parallelization decisions
    31→- `feature_graph.py` - Tracks file conflicts between features
    32→- `file_lock_manager.py` - Async-safe locking for concurrent access
    33→
    34→**Infrastructure Awareness:**
    35→- `credential_resolver.py` - Parses credentials.md for server access
    36→- `resource_manager.py` - Tracks servers/services with SSH verification
    37→- `resource_context.py` - Merges global + project resources
    38→- Context injection into agent prompts (agents know about my infrastructure)
    39→
    40→**UI & Real-time:**
    41→- React 18 with TanStack Query, Radix UI components
    42→- Neobrutalism design system with custom animations
    43→- WebSocket for real-time logs, status, and feature updates
    44→- Project registry supporting projects in any directory
    45→- Folder browser for project selection
    46→- Multi-step project creation wizard with spec interview
    47→
    48→**Server Architecture:**
    49→- FastAPI with 77 API routes across 11 routers
    50→- Localhost-only security middleware
    51→- Services: AgentRunner, SessionManager, SpecGenerator, SmartScheduler, etc.
    52→
    53→**Recent Bug Fix (Already Applied):**
    54→- Process tree termination - stopping an agent now kills all child processes (MCP servers, Playwright)
    55→- Added `/api/system/orphans` and `/api/system/cleanup` endpoints for zombie cleanup
    56→- Uses `psutil.Process.children(recursive=True)` for thorough cleanup
    57→
    58→---
    59→
    60→## What I Want to Add
    61→
    62→### Priority 1: Observability & Reliability
    63→
    64→**1. Token and Cost Tracking**
    65→I want visibility into how much each session and feature costs. Store usage data in SQLite, show running cost in the UI header as a badge that updates in real-time. Include:
    66→- Tokens per session (input/output breakdown)
    67→- Cost estimate using current Anthropic pricing
    68→- Historical data - "this project has used X tokens / $Y total"
    69→- Per-feature cost attribution
    70→
    71→**2. Session Recovery / Checkpointing**
    72→If the agent crashes or I close it accidentally, resume where it left off instead of restarting. Save state periodically - every few tool calls or after significant actions. Options:
    73→- Add `--resume` flag to CLI
    74→- Or make it automatic - detect incomplete session and offer to resume
    75→- Store checkpoint in project directory (`.agent_checkpoint.json` or similar)
    76→
    77→**3. Better Error Recovery**
    78→When the agent gets stuck or fails repeatedly on a feature:
    79→- Detect the stuck state (same error 3+ times)
    80→- Option to escalate to a more capable model (Opus)
    81→- Option to skip and move to next feature
    82→- Log detailed failure info for later analysis
    83→
    84→### Priority 2: Developer Experience
    85→
    86→**4. Git Integration**
    87→Automate version control during development:
    88→- Auto-commit after each feature passes with meaningful message derived from feature description
    89→- Option to create branch per feature (`feature/feature-name`)
    90→- Generate PR descriptions when ready to merge
    91→- Handle merge conflicts with AI assistance (or at least flag them clearly)
    92→
    93→**5. Multi-Model Support**
    94→Route tasks to appropriate models:
    95→- **Opus** - Complex architectural decisions, when stuck, analyzing large codebases
    96→- **Sonnet** - Standard coding work (current default)
    97→- **Haiku** - Quick validations, linting decisions, simple checks, summarization
    98→
    99→Implementation ideas:
   100→- Config file for model routing rules
   101→- Or let the orchestrator decide dynamically based on task complexity
   102→- Fallback chain: try Haiku first, escalate if it struggles
   103→
   104→**6. Improved Logging & Debugging**
   105→- Structured logs with levels (debug/info/warn/error)
   106→- Log viewer in UI with filtering
   107→- Export logs for a session
   108→- "Why did it do that?" - trace reasoning for specific actions
   109→
   110→### Priority 3: Intelligence & Learning
   111→
   112→**7. Learning from Past Work**
   113→Build project knowledge over time:
   114→- When a feature passes, index the implementation approach
   115→- On similar future features, retrieve relevant past solutions
   116→- Could be simple (keyword search over saved implementations) or sophisticated (embeddings)
   117→- Project-specific knowledge base that grows over time
   118→
   119→**8. Smarter Feature Prioritization**
   120→Go beyond simple priority numbers:
   121→- Detect dependencies automatically from code analysis
   122→- Suggest optimal ordering based on complexity and risk
   123→- Flag features that might conflict or have shared dependencies
   124→- "This feature should come after X because it depends on Y"
   125→
   126→### Priority 4: Visual & UX Improvements
   127→
   128→**9. Visual Dashboard**
   129→- Dependency graph showing how features relate (D3.js or similar)
   130→- Token usage charts over time
   131→- Timeline view of agent actions
   132→- "Thinking" indicator showing what agent is considering
   133→- Cost breakdown by feature/session
   134→
   135→**10. Enhanced Agent Controls**
   136→- "Retry with Opus" button for stuck features
   137→- Queue management - reorder pending features via drag-drop
   138→- Bulk operations - skip multiple, reprioritize
   139→- Estimated time/cost for remaining work
   140→
   141→---
   142→
   143→## Architecture Considerations
   144→
   145→**Plugin/Extension System (Future)**
   146→For extensibility, consider:
   147→- Pre/post implementation hooks
   148→- Custom MCP tools that can be added per-project
   149→- Custom validators for project-specific requirements
   150→- Would make Autocoder adaptable to different workflows
   151→
   152→**Cost Optimization**
   153→- Per-project token budgets with warnings
   154→- Prompt optimization - don't repeat unchanged context
   155→- Cache common operations
   156→- Usage analytics and trend detection
   157→
   158→---
   159→
   160→## Guidelines for Implementation
   161→
   162→**Don't break what's working** - This is enhancement, not rewrite. The current system works well.
   163→
   164→**You can refactor if needed** - If an enhancement would be cleaner with restructuring, go for it. Just ensure existing functionality still works.
   165→
   166→**Each feature should be independently testable** - No features that require 3 other things to verify.
   167→
   168→**Suggest the tech stack** - If you think Redis would be better for caching, or we need a vector DB for learning, suggest it. I trust your judgment.
   169→
   170→**Follow existing patterns** - Look at how `process_manager.py`, `resource_manager.py`, or the MCP server are structured. Consistent style matters.
   171→
   172→**Consider the parallel execution model** - New features should work correctly when multiple agents run simultaneously.
   173→
   174→---
   175→
   176→## Constraints (Don't Break These)
   177→
   178→- Security model must remain intact - don't bypass bash allowlist in `security.py`
   179→- Database migrations if changing schema - no destructive changes to `features.db`
   180→- UI changes need `npm run build` afterward
   181→- Keep localhost-only restriction for API (security middleware in `main.py`)
   182→- Don't commit credentials or API keys
   183→- Process cleanup must work - don't spawn processes that can become orphans
   184→
   185→---
   186→
   187→## Testing Strategy
   188→
   189→Each feature should be verifiable by:
   190→1. Lint passes (ruff)
   191→2. Type check passes (pyright/mypy if configured)
   192→3. Manual verification of described behavior
   193→4. Doesn't break existing features (run agent on a test project)
   194→5. Process cleanup still works (no zombies)
   195→
   196→---
   197→
   198→## File Locations Reference
   199→
   200→For context when implementing:
   201→
   202→```
   203→Autocoder-2.0/
   204→├── agent.py                 # Main agent loop - ADD checkpointing here
   205→├── client.py                # Claude SDK config - ADD multi-model here
   206→├── progress.py              # Progress tracking - ADD token counting here
   207→├── parallel_agent.py        # Parallel runner
   208→├── smart_orchestrator.py    # AI parallelization
   209→│
   210→├── server/
   211→│   ├── main.py              # FastAPI app (77 routes)
   212→│   ├── services/
   213→│   │   ├── process_manager.py  # Process lifecycle (UPDATED with tree kill)
   214→│   │   ├── credential_resolver.py
   215→│   │   ├── feature_graph.py
   216→│   │   ├── smart_scheduler.py  # ADD smarter prioritization here
   217→│   │   └── ...
   218→│   └── routers/
   219→│       ├── system.py        # NEW - orphan cleanup endpoints
   220→│       └── ...
   221→│
   222→├── ui/src/
   223→│   ├── App.tsx              # ADD cost badge, enhanced controls
   224→│   ├── components/          # 24 components
   225→│   └── hooks/               # ADD useUsage, useCheckpoint hooks
   226→│
   227→├── api/database.py          # SQLAlchemy models - ADD Usage table
   228→└── mcp_server/feature_mcp.py  # MCP tools
   229→```
   230→
   231→---
   232→
   233→## Notes for Interview Clarifications
   234→
   235→**On priority:** Token tracking and session recovery are highest - they help me immediately. Git integration and multi-model are medium priority. Learning and visual improvements are nice-to-have.
   236→
   237→**On scope:** Start with core functionality, don't gold-plate. Working basics beat elaborate features that don't quite work.
   238→
   239→**On architecture:** Prefer composition over inheritance, small focused modules, clear separation. The existing services are good examples.
   240→
   241→**On the learning feature:** Start simple - even just saving successful implementations as searchable markdown would be valuable. Don't need vector embeddings immediately.
   242→
   243→**On multi-model:** Config-driven is fine initially. Dynamic routing can come later.
   244→

# Autocoder 2.0 Enhancement Spec - Conversational Format

Use this as your response during the spec creation interview. Copy/paste or adapt as needed.

---

## Initial Project Description

I want to enhance Autocoder 2.0 - this is an existing, fully functional autonomous coding agent system. It already works and I use it regularly. I'm looking to add new capabilities that will make it exceptional.

**Current stack:** Python/FastAPI backend, React/TypeScript frontend with Tailwind v4, SQLite database. But I'm open to changes if you think something would work better - feel free to suggest alternatives or refactor if it makes the enhancements cleaner.

---

## What Already Exists and Works

**Core Agent System:**
- Two-agent pattern: Initializer creates features from app spec, Coding agent implements them
- Full agent loop with pause/resume/stop controls
- YOLO mode for rapid prototyping (skips browser testing)
- Auto-continuation between sessions with 3-second delay

**Feature Management:**
- SQLite database with priority, category, name, description, steps, status
- MCP server exposing 7 tools (get_stats, get_next, mark_passing, etc.)
- Kanban board UI showing pending/in-progress/done

**Parallel Execution:**
- `parallel_agent.py` - Run multiple agents on non-conflicting features
- `smart_orchestrator.py` - AI-driven parallelization decisions
- `feature_graph.py` - Tracks file conflicts between features
- `file_lock_manager.py` - Async-safe locking for concurrent access

**Infrastructure Awareness:**
- `credential_resolver.py` - Parses credentials.md for server access
- `resource_manager.py` - Tracks servers/services with SSH verification
- `resource_context.py` - Merges global + project resources
- Context injection into agent prompts (agents know about my infrastructure)

**UI & Real-time:**
- React 18 with TanStack Query, Radix UI components
- Neobrutalism design system with custom animations
- WebSocket for real-time logs, status, and feature updates
- Project registry supporting projects in any directory
- Folder browser for project selection
- Multi-step project creation wizard with spec interview

**Server Architecture:**
- FastAPI with 77 API routes across 11 routers
- Localhost-only security middleware
- Services: AgentRunner, SessionManager, SpecGenerator, SmartScheduler, etc.

**Recent Bug Fix (Already Applied):**
- Process tree termination - stopping an agent now kills all child processes (MCP servers, Playwright)
- Added `/api/system/orphans` and `/api/system/cleanup` endpoints for zombie cleanup
- Uses `psutil.Process.children(recursive=True)` for thorough cleanup

---

## What I Want to Add

### Priority 1: Observability & Reliability

**1. Token and Cost Tracking**
I want visibility into how much each session and feature costs. Store usage data in SQLite, show running cost in the UI header as a badge that updates in real-time. Include:
- Tokens per session (input/output breakdown)
- Cost estimate using current Anthropic pricing
- Historical data - "this project has used X tokens / $Y total"
- Per-feature cost attribution

**2. Session Recovery / Checkpointing**
If the agent crashes or I close it accidentally, resume where it left off instead of restarting. Save state periodically - every few tool calls or after significant actions. Options:
- Add `--resume` flag to CLI
- Or make it automatic - detect incomplete session and offer to resume
- Store checkpoint in project directory (`.agent_checkpoint.json` or similar)

**3. Better Error Recovery**
When the agent gets stuck or fails repeatedly on a feature:
- Detect the stuck state (same error 3+ times)
- Option to escalate to a more capable model (Opus)
- Option to skip and move to next feature
- Log detailed failure info for later analysis

### Priority 2: Developer Experience

**4. Git Integration**
Automate version control during development:
- Auto-commit after each feature passes with meaningful message derived from feature description
- Option to create branch per feature (`feature/feature-name`)
- Generate PR descriptions when ready to merge
- Handle merge conflicts with AI assistance (or at least flag them clearly)

**5. Multi-Model Support**
Route tasks to appropriate models:
- **Opus** - Complex architectural decisions, when stuck, analyzing large codebases
- **Sonnet** - Standard coding work (current default)
- **Haiku** - Quick validations, linting decisions, simple checks, summarization

Implementation ideas:
- Config file for model routing rules
- Or let the orchestrator decide dynamically based on task complexity
- Fallback chain: try Haiku first, escalate if it struggles

**6. Improved Logging & Debugging**
- Structured logs with levels (debug/info/warn/error)
- Log viewer in UI with filtering
- Export logs for a session
- "Why did it do that?" - trace reasoning for specific actions

### Priority 3: Intelligence & Learning

**7. Learning from Past Work**
Build project knowledge over time:
- When a feature passes, index the implementation approach
- On similar future features, retrieve relevant past solutions
- Could be simple (keyword search over saved implementations) or sophisticated (embeddings)
- Project-specific knowledge base that grows over time

**8. Smarter Feature Prioritization**
Go beyond simple priority numbers:
- Detect dependencies automatically from code analysis
- Suggest optimal ordering based on complexity and risk
- Flag features that might conflict or have shared dependencies
- "This feature should come after X because it depends on Y"

### Priority 4: Visual & UX Improvements

**9. Visual Dashboard**
- Dependency graph showing how features relate (D3.js or similar)
- Token usage charts over time
- Timeline view of agent actions
- "Thinking" indicator showing what agent is considering
- Cost breakdown by feature/session

**10. Enhanced Agent Controls**
- "Retry with Opus" button for stuck features
- Queue management - reorder pending features via drag-drop
- Bulk operations - skip multiple, reprioritize
- Estimated time/cost for remaining work

---

## Architecture Considerations

**Plugin/Extension System (Future)**
For extensibility, consider:
- Pre/post implementation hooks
- Custom MCP tools that can be added per-project
- Custom validators for project-specific requirements
- Would make Autocoder adaptable to different workflows

**Cost Optimization**
- Per-project token budgets with warnings
- Prompt optimization - don't repeat unchanged context
- Cache common operations
- Usage analytics and trend detection

---

## Guidelines for Implementation

**Don't break what's working** - This is enhancement, not rewrite. The current system works well.

**You can refactor if needed** - If an enhancement would be cleaner with restructuring, go for it. Just ensure existing functionality still works.

**Each feature should be independently testable** - No features that require 3 other things to verify.

**Suggest the tech stack** - If you think Redis would be better for caching, or we need a vector DB for learning, suggest it. I trust your judgment.

**Follow existing patterns** - Look at how `process_manager.py`, `resource_manager.py`, or the MCP server are structured. Consistent style matters.

**Consider the parallel execution model** - New features should work correctly when multiple agents run simultaneously.

---

## Constraints (Don't Break These)

- Security model must remain intact - don't bypass bash allowlist in `security.py`
- Database migrations if changing schema - no destructive changes to `features.db`
- UI changes need `npm run build` afterward
- Keep localhost-only restriction for API (security middleware in `main.py`)
- Don't commit credentials or API keys
- Process cleanup must work - don't spawn processes that can become orphans

---

## Testing Strategy

Each feature should be verifiable by:
1. Lint passes (ruff)
2. Type check passes (pyright/mypy if configured)
3. Manual verification of described behavior
4. Doesn't break existing features (run agent on a test project)
5. Process cleanup still works (no zombies)

---

## File Locations Reference

For context when implementing:

```
Autocoder-2.0/
├── agent.py                 # Main agent loop - ADD checkpointing here
├── client.py                # Claude SDK config - ADD multi-model here
├── progress.py              # Progress tracking - ADD token counting here
├── parallel_agent.py        # Parallel runner
├── smart_orchestrator.py    # AI parallelization
│
├── server/
│   ├── main.py              # FastAPI app (77 routes)
│   ├── services/
│   │   ├── process_manager.py  # Process lifecycle (UPDATED with tree kill)
│   │   ├── credential_resolver.py
│   │   ├── feature_graph.py
│   │   ├── smart_scheduler.py  # ADD smarter prioritization here
│   │   └── ...
│   └── routers/
│       ├── system.py        # NEW - orphan cleanup endpoints
│       └── ...
│
├── ui/src/
│   ├── App.tsx              # ADD cost badge, enhanced controls
│   ├── components/          # 24 components
│   └── hooks/               # ADD useUsage, useCheckpoint hooks
│
├── api/database.py          # SQLAlchemy models - ADD Usage table
└── mcp_server/feature_mcp.py  # MCP tools
```

---

## Notes for Interview Clarifications

**On priority:** Token tracking and session recovery are highest - they help me immediately. Git integration and multi-model are medium priority. Learning and visual improvements are nice-to-have.

**On scope:** Start with core functionality, don't gold-plate. Working basics beat elaborate features that don't quite work.

**On architecture:** Prefer composition over inheritance, small focused modules, clear separation. The existing services are good examples.

**On the learning feature:** Start simple - even just saving successful implementations as searchable markdown would be valuable. Don't need vector embeddings immediately.

**On multi-model:** Config-driven is fine initially. Dynamic routing can come later.

-**Current stack:** Python/FastAPI backend, React/TypeScript frontend with Tailwind v4, SQLite database. But I'm open to changes if you think something would work better - feel free to suggest alternatives.

+**Current stack:** Python/FastAPI backend, React/TypeScript frontend with Tailwind v4, SQLite database. But I'm open to changes if you think something would work better - feel free to suggest alternatives or refactor if it makes the enhancements cleaner.

-**What already exists and works well:**

+- Two-agent pattern: Initializer creates features from app spec, Coding agent implements them

- Full agent loop with pause/resume/stop controls

-- Feature database with MCP server for progress tracking

-- React UI with kanban board showing pending/in-progress/done features

-- Real-time WebSocket updates for logs and status

-- Parallel agent execution with file locking for conflict prevention

-- Smart scheduler that uses AI to decide what can run in parallel

-- Infrastructure context injection - agents know about my servers and credentials

-- YOLO mode for rapid prototyping without browser testing

+- YOLO mode for rapid prototyping (skips browser testing)

+- Auto-continuation between sessions with 3-second delay

+- SQLite database with priority, category, name, description, steps, status

+- MCP server exposing 7 tools (get_stats, get_next, mark_passing, etc.)

+- Kanban board UI showing pending/in-progress/done

+- `parallel_agent.py` - Run multiple agents on non-conflicting features

+- `smart_orchestrator.py` - AI-driven parallelization decisions

+- `feature_graph.py` - Tracks file conflicts between features

+- `file_lock_manager.py` - Async-safe locking for concurrent access

+- `credential_resolver.py` - Parses credentials.md for server access

+- `resource_manager.py` - Tracks servers/services with SSH verification

+- `resource_context.py` - Merges global + project resources

+- Context injection into agent prompts (agents know about my infrastructure)

+- React 18 with TanStack Query, Radix UI components

+- Neobrutalism design system with custom animations

+- WebSocket for real-time logs, status, and feature updates

- Project registry supporting projects in any directory

+- Multi-step project creation wizard with spec interview

-- Process tree termination - when stopping an agent, it now kills all child processes (MCP servers, Playwright) not just the parent

-- Added `/api/system/orphans` and `/api/system/cleanup` endpoints for finding and killing zombie processes

+- FastAPI with 77 API routes across 11 routers

+- Services: AgentRunner, SessionManager, SpecGenerator, SmartScheduler, etc.

+- Process tree termination - stopping an agent now kills all child processes (MCP servers, Playwright)

+- Added `/api/system/orphans` and `/api/system/cleanup` endpoints for zombie cleanup

+- Uses `psutil.Process.children(recursive=True)` for thorough cleanup

-In rough priority order, but you can reorder based on dependencies:

+### Priority 1: Observability & Reliability

-I want visibility into how much each session and feature costs. Store usage data somewhere (SQLite is fine), show running cost in the UI. Maybe a little badge in the header that updates as the agent works. Historical data would be nice too - "this project has used X tokens total."

+I want visibility into how much each session and feature costs. Store usage data in SQLite, show running cost in the UI header as a badge that updates in real-time. Include:

+- Tokens per session (input/output breakdown)

+- Cost estimate using current Anthropic pricing

+- Historical data - "this project has used X tokens / $Y total"

-### 2. Session Recovery / Checkpointing

-If the agent crashes or I accidentally close it, I want to resume where it left off instead of restarting the feature from scratch. Save state periodically - maybe every few tool calls or after each significant action. Add a `--resume` flag or make it automatic.

+**2. Session Recovery / Checkpointing**

+If the agent crashes or I close it accidentally, resume where it left off instead of restarting. Save state periodically - every few tool calls or after significant actions. Options:

+- Or make it automatic - detect incomplete session and offer to resume

+- Store checkpoint in project directory (`.agent_checkpoint.json` or similar)

-Auto-commit after each feature passes with a meaningful commit message derived from the feature description. Maybe create a branch per feature automatically. Would be great if it could generate PR descriptions too when I'm ready to merge.

+When the agent gets stuck or fails repeatedly on a feature:

+- Detect the stuck state (same error 3+ times)

+- Option to escalate to a more capable model (Opus)

+- Option to skip and move to next feature

+- Log detailed failure info for later analysis

-Different Claude models for different tasks. Use your judgment on what makes sense, but my thinking is:

-- Opus for complex architectural decisions or when the agent is stuck

-- Sonnet for most coding work (current default)

-- Haiku for quick validations, simple checks, or summarization

-Should be configurable but have smart defaults.

+Automate version control during development:

+- Auto-commit after each feature passes with meaningful message derived from feature description

+- Option to create branch per feature (`feature/feature-name`)

+- Generate PR descriptions when ready to merge

+- Handle merge conflicts with AI assistance (or at least flag them clearly)

-Build up project knowledge over time. When the agent successfully implements a feature, cache the approach somehow. Next time it encounters something similar, it can reference what worked before. This could be as simple as saving successful implementations to a searchable index or as sophisticated as embeddings - you decide.

+- **Opus** - Complex architectural decisions, when stuck, analyzing large codebases

+- **Sonnet** - Standard coding work (current default)

+- **Haiku** - Quick validations, linting decisions, simple checks, summarization

-- Dependency graph showing how features relate

+- Or let the orchestrator decide dynamically based on task complexity

+- Fallback chain: try Haiku first, escalate if it struggles

+- Structured logs with levels (debug/info/warn/error)

+- "Why did it do that?" - trace reasoning for specific actions

+### Priority 3: Intelligence & Learning

+- When a feature passes, index the implementation approach

+- On similar future features, retrieve relevant past solutions

+- Could be simple (keyword search over saved implementations) or sophisticated (embeddings)

+- Project-specific knowledge base that grows over time

+- Detect dependencies automatically from code analysis

+- Suggest optimal ordering based on complexity and risk

+- Flag features that might conflict or have shared dependencies

+- "This feature should come after X because it depends on Y"

+### Priority 4: Visual & UX Improvements

+- Dependency graph showing how features relate (D3.js or similar)

-- Timeline view of agent actions/decisions

-- Maybe a "thinking" indicator showing what the agent is considering

+- "Thinking" indicator showing what agent is considering

+- "Retry with Opus" button for stuck features

+- Queue management - reorder pending features via drag-drop

+- Bulk operations - skip multiple, reprioritize

+- Estimated time/cost for remaining work

+- Custom MCP tools that can be added per-project

+- Custom validators for project-specific requirements

+- Would make Autocoder adaptable to different workflows

+- Per-project token budgets with warnings

+- Prompt optimization - don't repeat unchanged context

-**Don't break what's working** - This is enhancement, not rewrite. Be surgical.

+**Don't break what's working** - This is enhancement, not rewrite. The current system works well.

-**You can refactor if needed** - If an enhancement would be cleaner with some restructuring, go for it. Just make sure tests pass after.

+**You can refactor if needed** - If an enhancement would be cleaner with restructuring, go for it. Just ensure existing functionality still works.

-**Each feature should be independently testable** - Don't create features that can only be verified after implementing 3 other features.

+**Each feature should be independently testable** - No features that require 3 other things to verify.

-**Suggest the tech stack** - I mentioned the current stack but I trust your judgment. If you think we should use Redis for caching instead of SQLite, or add a vector database for the learning feature, suggest it.

+**Suggest the tech stack** - If you think Redis would be better for caching, or we need a vector DB for learning, suggest it. I trust your judgment.

-**Consider the existing patterns** - Look at how similar things are done in the codebase and follow those patterns unless there's a good reason not to.

+**Follow existing patterns** - Look at how `process_manager.py`, `resource_manager.py`, or the MCP server are structured. Consistent style matters.

+**Consider the parallel execution model** - New features should work correctly when multiple agents run simultaneously.

-- Security model must remain intact - don't bypass the bash allowlist

-- Database migrations if changing schema - no destructive changes

-- UI changes need `npm run build` afterward (this is documented in CLAUDE.md)

-- Keep the localhost-only restriction for the API

+- Security model must remain intact - don't bypass bash allowlist in `security.py`

+- Database migrations if changing schema - no destructive changes to `features.db`

+- UI changes need `npm run build` afterward

+- Keep localhost-only restriction for API (security middleware in `main.py`)

+- Process cleanup must work - don't spawn processes that can become orphans

-3. Manual verification of the described behavior

-4. Doesn't break existing features (basic regression)

+2. Type check passes (pyright/mypy if configured)

+3. Manual verification of described behavior

+4. Doesn't break existing features (run agent on a test project)

+5. Process cleanup still works (no zombies)

-If the spec wizard asks for clarification:

-**On priority:** Token tracking and session recovery are highest priority - they help me use Autocoder more effectively right now. Git integration and multi-model are medium. Learning and visual improvements are nice-to-have.

+├── agent.py                 # Main agent loop - ADD checkpointing here

+├── client.py                # Claude SDK config - ADD multi-model here

+├── progress.py              # Progress tracking - ADD token counting here

+├── parallel_agent.py        # Parallel runner

+├── smart_orchestrator.py    # AI parallelization

+│   ├── main.py              # FastAPI app (77 routes)

+│   │   ├── process_manager.py  # Process lifecycle (UPDATED with tree kill)

+│   │   ├── smart_scheduler.py  # ADD smarter prioritization here

+│       ├── system.py        # NEW - orphan cleanup endpoints

+│   ├── App.tsx              # ADD cost badge, enhanced controls

+│   ├── components/          # 24 components

+│   └── hooks/               # ADD useUsage, useCheckpoint hooks

+├── api/database.py          # SQLAlchemy models - ADD Usage table

+└── mcp_server/feature_mcp.py  # MCP tools

-**On scope:** Start with the core functionality, don't gold-plate. Better to have working basics than elaborate features that don't quite work.

-**On architecture:** I prefer composition over inheritance, small focused modules, clear separation of concerns. Look at how `process_manager.py` or `resource_manager.py` are structured for examples.

+**On priority:** Token tracking and session recovery are highest - they help me immediately. Git integration and multi-model are medium priority. Learning and visual improvements are nice-to-have.

+**On scope:** Start with core functionality, don't gold-plate. Working basics beat elaborate features that don't quite work.

+**On architecture:** Prefer composition over inheritance, small focused modules, clear separation. The existing services are good examples.

+**On the learning feature:** Start simple - even just saving successful implementations as searchable markdown would be valuable. Don't need vector embeddings immediately.

+**On multi-model:** Config-driven is fine initially. Dynamic routing can come later.

# Autocoder 2.0 Enhancement Spec - Conversational Format

Use this as your response during the spec creation interview. Copy/paste or adapt as needed.

---

## Initial Project Description

I want to enhance Autocoder 2.0 - this is an existing, fully functional autonomous coding agent system. It already works and I use it regularly. I'm looking to add new capabilities that will make it exceptional.

**Current stack:** Python/FastAPI backend, React/TypeScript frontend with Tailwind v4, SQLite database. But I'm open to changes if you think something would work better - feel free to suggest alternatives.

**What already exists and works well:**

- Full agent loop with pause/resume/stop controls
- Feature database with MCP server for progress tracking
- React UI with kanban board showing pending/in-progress/done features
- Real-time WebSocket updates for logs and status
- Parallel agent execution with file locking for conflict prevention
- Smart scheduler that uses AI to decide what can run in parallel
- Infrastructure context injection - agents know about my servers and credentials
- YOLO mode for rapid prototyping without browser testing
- Project registry supporting projects in any directory

**Recent bug fix already applied:**
- Process tree termination - when stopping an agent, it now kills all child processes (MCP servers, Playwright) not just the parent
- Added `/api/system/orphans` and `/api/system/cleanup` endpoints for finding and killing zombie processes

---

## What I Want to Add

In rough priority order, but you can reorder based on dependencies:

### 1. Token and Cost Tracking
I want visibility into how much each session and feature costs. Store usage data somewhere (SQLite is fine), show running cost in the UI. Maybe a little badge in the header that updates as the agent works. Historical data would be nice too - "this project has used X tokens total."

### 2. Session Recovery / Checkpointing
If the agent crashes or I accidentally close it, I want to resume where it left off instead of restarting the feature from scratch. Save state periodically - maybe every few tool calls or after each significant action. Add a `--resume` flag or make it automatic.

### 3. Better Git Integration
Auto-commit after each feature passes with a meaningful commit message derived from the feature description. Maybe create a branch per feature automatically. Would be great if it could generate PR descriptions too when I'm ready to merge.

### 4. Multi-Model Support
Different Claude models for different tasks. Use your judgment on what makes sense, but my thinking is:
- Opus for complex architectural decisions or when the agent is stuck
- Sonnet for most coding work (current default)
- Haiku for quick validations, simple checks, or summarization

Should be configurable but have smart defaults.

### 5. Learning from Past Work
Build up project knowledge over time. When the agent successfully implements a feature, cache the approach somehow. Next time it encounters something similar, it can reference what worked before. This could be as simple as saving successful implementations to a searchable index or as sophisticated as embeddings - you decide.

### 6. Visual Dashboard Improvements
- Dependency graph showing how features relate
- Token usage charts over time
- Timeline view of agent actions/decisions
- Maybe a "thinking" indicator showing what the agent is considering

---

## Guidelines for Implementation

**Don't break what's working** - This is enhancement, not rewrite. Be surgical.

**You can refactor if needed** - If an enhancement would be cleaner with some restructuring, go for it. Just make sure tests pass after.

**Each feature should be independently testable** - Don't create features that can only be verified after implementing 3 other features.

**Suggest the tech stack** - I mentioned the current stack but I trust your judgment. If you think we should use Redis for caching instead of SQLite, or add a vector database for the learning feature, suggest it.

**Consider the existing patterns** - Look at how similar things are done in the codebase and follow those patterns unless there's a good reason not to.

---

## Constraints (Don't Break These)

- Security model must remain intact - don't bypass the bash allowlist
- Database migrations if changing schema - no destructive changes
- UI changes need `npm run build` afterward (this is documented in CLAUDE.md)
- Keep the localhost-only restriction for the API
- Don't commit credentials or API keys

---

## Testing Strategy

Each feature should be verifiable by:
1. Lint passes (ruff)
2. Type check passes (if applicable)
3. Manual verification of the described behavior
4. Doesn't break existing features (basic regression)

---

## Notes for the Interview

If the spec wizard asks for clarification:

**On priority:** Token tracking and session recovery are highest priority - they help me use Autocoder more effectively right now. Git integration and multi-model are medium. Learning and visual improvements are nice-to-have.

**On scope:** Start with the core functionality, don't gold-plate. Better to have working basics than elaborate features that don't quite work.

**On architecture:** I prefer composition over inheritance, small focused modules, clear separation of concerns. Look at how `process_manager.py` or `resource_manager.py` are structured for examples.


I've updated the app spec with everything we've discussed. Let me provide a summary to the user.


Updated. The spec now includes:

**What Already Exists** (detailed):
- Core agent system, feature management, parallel execution
- Infrastructure awareness (credentials, resources, context injection)
- UI/real-time features, server architecture
- The zombie process fix we just applied

**10 Enhancement Areas** (prioritized):
1. Token/Cost Tracking
2. Session Recovery/Checkpointing
3. Better Error Recovery
4. Git Integration
5. Multi-Model Support
6. Improved Logging
7. Learning from Past Work
8. Smarter Prioritization
9. Visual Dashboard
10. Enhanced Agent Controls

**Plus:**
- Architecture considerations (plugins, cost optimization)
- Implementation guidelines
- Constraints (don't break these)
- File locations reference showing where to add each feature
- Interview clarification notes

Ready to use in the spec wizard at http://localhost:8080


I jsut noticed a problem in v2 that needs to be addressed.  Terminal window is not persistent, if I click somehwere else and reopen the terminal, it doesn't bring me back to the terminal session I was just in, and has no idea what the last terminal was up to.  I'd like the session to remain persistent.


The user is reporting a bug with the terminal functionality in Autocoder 2.0. When they navigate away and come back, the terminal session is lost. They want persistent terminal sessions.

Let me investigate the terminal implementation to understand how it currently works and what needs to change.


Let me investigate the terminal implementation.


     1→"""
     2→Terminal Chat Session
     3→=====================
     4→
     5→Manages interactive Claude terminal sessions for resource management,
     6→infrastructure discovery, and nuanced configuration tasks.
     7→
     8→The terminal provides full system access (no sandbox) and allows users to:
     9→- Add and configure servers, services, and credentials
    10→- Test connectivity to resources
    11→- Save resources as project-specific or global
    12→- Execute system commands for infrastructure tasks
    13→"""
    14→
    15→import json
    16→import logging
    17→import shutil
    18→import threading
    19→from datetime import datetime
    20→from pathlib import Path
    21→from typing import AsyncGenerator, Optional
    22→
    23→from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient
    24→
    25→from .credential_resolver import get_resolver
    26→from .resource_manager import (
    27→    get_manager,
    28→    Resource,
    29→    ResourceType,
    30→    ResourceScope,
    31→    AuthType,
    32→    ResourceAuth,
    33→)
    34→
    35→logger = logging.getLogger(__name__)
    36→
    37→# Root directory of the project
    38→ROOT_DIR = Path(__file__).parent.parent.parent
    39→
    40→# Terminal system prompt
    41→TERMINAL_SYSTEM_PROMPT = """You are a resource management assistant for Autocoder 2.0.
    42→
    43→## Your Role
    44→
    45→You help users manage infrastructure resources (servers, services, databases) that coding agents can use. Your job is to:
    46→
    47→1. **Add Resources** - When users mention a server or service, help add it to their resources
    48→2. **Test Connectivity** - Verify resources are accessible before saving
    49→3. **Probe Capabilities** - Discover what tools/runtimes are installed on servers
    50→4. **Manage Scope** - Help users decide if resources should be project-specific or global
    51→
    52→## Available Tools
    53→
    54→You have full system access:
    55→- **Bash**: SSH, curl, git, docker, and any system command
    56→- **Read/Write/Edit**: File operations
    57→- **Glob/Grep**: Search files
    58→
    59→## When Adding a Resource
    60→
    61→Follow this workflow:
    62→1. Get connection details from user (host, user, credentials)
    63→2. Test connectivity (SSH for servers, curl for services)
    64→3. Probe for relevant capabilities if it's a server
    65→4. Ask user: "Should this be a global resource (all projects) or project-specific?"
    66→5. Save to the appropriate resources.json
    67→
    68→## Resource Storage
    69→
    70→Resources are stored in JSON files:
    71→- **Global**: `~/.autocoder/global_resources.json`
    72→- **Project**: `{project_dir}/resources.json`
    73→
    74→Use the resource management functions to save resources programmatically.
    75→
    76→## Credential Handling
    77→
    78→Credentials are stored separately in `credentials.md`. When saving a resource:
    79→- Don't store passwords directly in resources.json
    80→- Instead, use a `credential_ref` that points to credentials.md
    81→- Example: `{"auth": {"type": "ssh-password", "credential_ref": "jupiter"}}`
    82→
    83→## Example Interactions
    84→
    85→User: "Add my build server at 172.16.3.30"
    86→You: Test SSH, probe for rust/node/docker, ask about scope, save resource
    87→
    88→User: "What servers do I have configured?"
    89→You: List resources from global + project resources
    90→
    91→User: "Test if the Gitea API is working"
    92→You: curl the API endpoint, report results
    93→
    94→## Project Context
    95→
    96→{PROJECT_CONTEXT}
    97→
    98→## Current Working Directory
    99→
   100→{CWD}
   101→"""
   102→
   103→
   104→class TerminalSession:
   105→    """
   106→    Manages an interactive Claude terminal session for one project.
   107→
   108→    The terminal provides full system access for:
   109→    - Resource management (add servers, services)
   110→    - Connection testing and capability probing
   111→    - Infrastructure configuration
   112→    """
   113→
   114→    def __init__(
   115→        self,
   116→        project_name: str,
   117→        project_dir: Path,
   118→    ):
   119→        """
   120→        Initialize the terminal session.
   121→
   122→        Args:
   123→            project_name: Name of the project
   124→            project_dir: Absolute path to the project directory
   125→        """
   126→        self.project_name = project_name
   127→        self.project_dir = project_dir
   128→        self.client: Optional[ClaudeSDKClient] = None
   129→        self.messages: list[dict] = []
   130→        self.created_at = datetime.now()
   131→        self._client_entered: bool = False
   132→        self._resource_manager = get_manager()
   133→        self._credential_resolver = get_resolver()
   134→
   135→    def get_resources(self) -> dict:
   136→        """Get current resources for the project."""
   137→        resources = self._resource_manager.get_merged_resources(
   138→            self.project_name, self.project_dir
   139→        )
   140→        return {
   141→            name: resource.to_dict()
   142→            for name, resource in resources.items()
   143→        }
   144→
   145→    async def close(self) -> None:
   146→        """Clean up resources and close the Claude client."""
   147→        if self.client and self._client_entered:
   148→            try:
   149→                await self.client.__aexit__(None, None, None)
   150→            except Exception as e:
   151→                logger.warning(f"Error closing Claude client: {e}")
   152→            finally:
   153→                self._client_entered = False
   154→                self.client = None
   155→
   156→    def _get_project_context(self) -> str:
   157→        """Generate project context for the system prompt."""
   158→        lines = [f"Project: **{self.project_name}**"]
   159→        lines.append(f"Directory: `{self.project_dir}`")
   160→        lines.append("")
   161→
   162→        # Get current resources
   163→        resources = self.get_resources()
   164→        if resources:
   165→            lines.append("### Current Resources")
   166→            for name, data in resources.items():
   167→                rtype = data.get("type", "unknown")
   168→                scope = data.get("scope", "project")
   169→                host = data.get("host") or data.get("url") or "no host"
   170→                lines.append(f"- **{name}** ({rtype}, {scope}): {host}")
   171→        else:
   172→            lines.append("_No resources configured yet._")
   173→
   174→        return "\n".join(lines)
   175→
   176→    async def start(self) -> AsyncGenerator[dict, None]:
   177→        """
   178→        Initialize session and send initial greeting.
   179→
   180→        Yields message chunks as they stream in.
   181→        """
   182→        # Ensure project directory exists
   183→        self.project_dir.mkdir(parents=True, exist_ok=True)
   184→
   185→        # Create security settings with full access
   186→        security_settings = {
   187→            "sandbox": {"enabled": False},  # Full system access
   188→            "permissions": {
   189→                "defaultMode": "acceptEdits",
   190→                "allow": [
   191→                    "Read(./**)",
   192→                    "Read(~/**)",  # Allow reading home directory
   193→                    "Write(./**)",
   194→                    "Edit(./**)",
   195→                    "Glob(./**)",
   196→                    "Grep(./**)",
   197→                    "Bash(*)",  # Full bash access
   198→                    "WebFetch",
   199→                    "WebSearch",
   200→                ],
   201→            },
   202→        }
   203→        settings_file = self.project_dir / ".claude_terminal_settings.json"
   204→        with open(settings_file, "w") as f:
   205→            json.dump(security_settings, f, indent=2)
   206→
   207→        # Build system prompt with context
   208→        system_prompt = TERMINAL_SYSTEM_PROMPT.replace(
   209→            "{PROJECT_CONTEXT}",
   210→            self._get_project_context()
   211→        ).replace(
   212→            "{CWD}",
   213→            str(self.project_dir.resolve())
   214→        )
   215→
   216→        # Use system Claude CLI
   217→        system_cli = shutil.which("claude")
   218→
   219→        try:
   220→            self.client = ClaudeSDKClient(
   221→                options=ClaudeAgentOptions(
   222→                    model="claude-sonnet-4-20250514",  # Sonnet for faster terminal responses
   223→                    cli_path=system_cli,
   224→                    system_prompt=system_prompt,
   225→                    allowed_tools=[
   226→                        "Read",
   227→                        "Write",
   228→                        "Edit",
   229→                        "Glob",
   230→                        "Grep",
   231→                        "Bash",
   232→                        "WebFetch",
   233→                        "WebSearch",
   234→                    ],
   235→                    permission_mode="acceptEdits",
   236→                    max_turns=100,
   237→                    cwd=str(self.project_dir.resolve()),
   238→                    settings=str(settings_file.resolve()),
   239→                )
   240→            )
   241→            await self.client.__aenter__()
   242→            self._client_entered = True
   243→        except Exception as e:
   244→            logger.exception("Failed to create Claude client for terminal")
   245→            yield {
   246→                "type": "error",
   247→                "content": f"Failed to initialize terminal: {str(e)}"
   248→            }
   249→            return
   250→
   251→        # Send initial greeting
   252→        initial_message = (
   253→            f"Terminal session started for project **{self.project_name}**.\n\n"
   254→            "I can help you manage resources (servers, services, databases). "
   255→            "What would you like to do?"
   256→        )
   257→
   258→        yield {"type": "text", "content": initial_message}
   259→        yield {"type": "resources", "data": self.get_resources()}
   260→        yield {"type": "response_done"}
   261→
   262→    async def send_message(
   263→        self,
   264→        user_message: str,
   265→    ) -> AsyncGenerator[dict, None]:
   266→        """
   267→        Send user message and stream Claude's response.
   268→
   269→        Args:
   270→            user_message: The user's message
   271→
   272→        Yields:
   273→            Message chunks of various types:
   274→            - {"type": "text", "content": str}
   275→            - {"type": "resource_added", "resource": dict}
   276→            - {"type": "verification_result", "result": dict}
   277→            - {"type": "error", "content": str}
   278→        """
   279→        if not self.client:
   280→            yield {
   281→                "type": "error",
   282→                "content": "Session not initialized. Call start() first."
   283→            }
   284→            return
   285→
   286→        # Store the user message
   287→        self.messages.append({
   288→            "role": "user",
   289→            "content": user_message,
   290→            "timestamp": datetime.now().isoformat()
   291→        })
   292→
   293→        try:
   294→            async for chunk in self._query_claude(user_message):
   295→                yield chunk
   296→            yield {"type": "response_done"}
   297→        except Exception as e:
   298→            logger.exception("Error during terminal query")
   299→            yield {
   300→                "type": "error",
   301→                "content": f"Error: {str(e)}"
   302→            }
   303→
   304→    async def _query_claude(
   305→        self,
   306→        message: str,
   307→    ) -> AsyncGenerator[dict, None]:
   308→        """
   309→        Query Claude and stream responses.
   310→
   311→        Handles tool calls and text responses.
   312→        Detects resource management operations and yields appropriate events.
   313→        """
   314→        if not self.client:
   315→            return
   316→
   317→        await self.client.query(message)
   318→
   319→        current_text = ""
   320→
   321→        # Stream the response
   322→        async for msg in self.client.receive_response():
   323→            msg_type = type(msg).__name__
   324→
   325→            if msg_type == "AssistantMessage" and hasattr(msg, "content"):
   326→                for block in msg.content:
   327→                    block_type = type(block).__name__
   328→
   329→                    if block_type == "TextBlock" and hasattr(block, "text"):
   330→                        text = block.text
   331→                        if text:
   332→                            current_text += text
   333→                            yield {"type": "text", "content": text}
   334→
   335→                            # Store in message history
   336→                            self.messages.append({
   337→                                "role": "assistant",
   338→                                "content": text,
   339→                                "timestamp": datetime.now().isoformat()
   340→                            })
   341→
   342→                    elif block_type == "ToolUseBlock":
   343→                        tool_name = getattr(block, "name", "")
   344→                        tool_input = getattr(block, "input", {})
   345→
   346→                        # Detect resource file writes
   347→                        if tool_name == "Write":
   348→                            file_path = tool_input.get("file_path", "")
   349→                            if "resources.json" in file_path:
   350→                                yield {
   351→                                    "type": "resource_updated",
   352→                                    "path": file_path
   353→                                }
   354→                                # Refresh resources
   355→                                yield {
   356→                                    "type": "resources",
   357→                                    "data": self.get_resources()
   358→                                }
   359→
   360→                        # Notify about bash commands (for transparency)
   361→                        if tool_name == "Bash":
   362→                            command = tool_input.get("command", "")
   363→                            yield {
   364→                                "type": "command_executing",
   365→                                "command": command[:100] + ("..." if len(command) > 100 else "")
   366→                            }
   367→
   368→            elif msg_type == "UserMessage" and hasattr(msg, "content"):
   369→                # Tool results - look for verification results
   370→                for block in msg.content:
   371→                    block_type = type(block).__name__
   372→                    if block_type == "ToolResultBlock":
   373→                        result = getattr(block, "result", "")
   374→                        # Check for SSH or connection test results
   375→                        if "connected" in str(result).lower() or "success" in str(result).lower():
   376→                            yield {
   377→                                "type": "connection_verified",
   378→                                "result": str(result)[:200]
   379→                            }
   380→
   381→
   382→# Session registry - thread-safe storage of active sessions
   383→_sessions: dict[str, TerminalSession] = {}
   384→_sessions_lock = threading.Lock()
   385→
   386→
   387→async def get_or_create_terminal_session(
   388→    project_name: str,
   389→    project_dir: Path,
   390→) -> TerminalSession:
   391→    """
   392→    Get existing terminal session or create a new one.
   393→
   394→    Args:
   395→        project_name: Name of the project
   396→        project_dir: Path to the project directory
   397→
   398→    Returns:
   399→        TerminalSession instance
   400→    """
   401→    with _sessions_lock:
   402→        # Check for existing session
   403→        if project_name in _sessions:
   404→            session = _sessions[project_name]
   405→            # Verify it's still valid
   406→            if session.client and session._client_entered:
   407→                return session
   408→            # Invalid session - remove it
   409→            del _sessions[project_name]
   410→
   411→        # Create new session
   412→        session = TerminalSession(project_name, project_dir)
   413→        _sessions[project_name] = session
   414→
   415→    return session
   416→
   417→
   418→async def close_terminal_session(project_name: str) -> None:
   419→    """
   420→    Close and remove a terminal session.
   421→
   422→    Args:
   423→        project_name: Name of the project
   424→    """
   425→    session = None
   426→    with _sessions_lock:
   427→        session = _sessions.pop(project_name, None)
   428→
   429→    if session:
   430→        await session.close()
   431→
   432→
   433→def get_active_sessions() -> list[str]:
   434→    """Get list of project names with active terminal sessions."""
   435→    with _sessions_lock:
   436→        return list(_sessions.keys())
   437→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

"""
Terminal Chat Session
=====================

Manages interactive Claude terminal sessions for resource management,
infrastructure discovery, and nuanced configuration tasks.

The terminal provides full system access (no sandbox) and allows users to:
- Add and configure servers, services, and credentials
- Test connectivity to resources
- Save resources as project-specific or global
- Execute system commands for infrastructure tasks
"""

import json
import logging
import shutil
import threading
from datetime import datetime
from pathlib import Path
from typing import AsyncGenerator, Optional

from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient

from .credential_resolver import get_resolver
from .resource_manager import (
    get_manager,
    Resource,
    ResourceType,
    ResourceScope,
    AuthType,
    ResourceAuth,
)

logger = logging.getLogger(__name__)

# Root directory of the project
ROOT_DIR = Path(__file__).parent.parent.parent

# Terminal system prompt
TERMINAL_SYSTEM_PROMPT = """You are a resource management assistant for Autocoder 2.0.

## Your Role

You help users manage infrastructure resources (servers, services, databases) that coding agents can use. Your job is to:

1. **Add Resources** - When users mention a server or service, help add it to their resources
2. **Test Connectivity** - Verify resources are accessible before saving
3. **Probe Capabilities** - Discover what tools/runtimes are installed on servers
4. **Manage Scope** - Help users decide if resources should be project-specific or global

## Available Tools

You have full system access:
- **Bash**: SSH, curl, git, docker, and any system command
- **Read/Write/Edit**: File operations
- **Glob/Grep**: Search files

## When Adding a Resource

Follow this workflow:
1. Get connection details from user (host, user, credentials)
2. Test connectivity (SSH for servers, curl for services)
3. Probe for relevant capabilities if it's a server
4. Ask user: "Should this be a global resource (all projects) or project-specific?"
5. Save to the appropriate resources.json

## Resource Storage

Resources are stored in JSON files:
- **Global**: `~/.autocoder/global_resources.json`
- **Project**: `{project_dir}/resources.json`

Use the resource management functions to save resources programmatically.

## Credential Handling

Credentials are stored separately in `credentials.md`. When saving a resource:
- Don't store passwords directly in resources.json
- Instead, use a `credential_ref` that points to credentials.md
- Example: `{"auth": {"type": "ssh-password", "credential_ref": "jupiter"}}`

## Example Interactions

User: "Add my build server at 172.16.3.30"
You: Test SSH, probe for rust/node/docker, ask about scope, save resource

User: "What servers do I have configured?"
You: List resources from global + project resources

User: "Test if the Gitea API is working"
You: curl the API endpoint, report results

## Project Context

{PROJECT_CONTEXT}

## Current Working Directory

{CWD}
"""

class TerminalSession:
    """
    Manages an interactive Claude terminal session for one project.

    The terminal provides full system access for:
    - Resource management (add servers, services)
    - Connection testing and capability probing
    - Infrastructure configuration
    """

    def __init__(
        self,
        project_name: str,
        project_dir: Path,
    ):
        """
        Initialize the terminal session.

        Args:
            project_name: Name of the project
            project_dir: Absolute path to the project directory
        """
        self.project_name = project_name
        self.project_dir = project_dir
        self.client: Optional[ClaudeSDKClient] = None
        self.messages: list[dict] = []
        self.created_at = datetime.now()
        self._client_entered: bool = False
        self._resource_manager = get_manager()
        self._credential_resolver = get_resolver()

    def get_resources(self) -> dict:
        """Get current resources for the project."""
        resources = self._resource_manager.get_merged_resources(
            self.project_name, self.project_dir
        )
        return {
            name: resource.to_dict()
            for name, resource in resources.items()
        }

    async def close(self) -> None:
        """Clean up resources and close the Claude client."""
        if self.client and self._client_entered:
            try:
                await self.client.__aexit__(None, None, None)
            except Exception as e:
                logger.warning(f"Error closing Claude client: {e}")
            finally:
                self._client_entered = False
                self.client = None

    def _get_project_context(self) -> str:
        """Generate project context for the system prompt."""
        lines = [f"Project: **{self.project_name}**"]
        lines.append(f"Directory: `{self.project_dir}`")
        lines.append("")

        # Get current resources
        resources = self.get_resources()
        if resources:
            lines.append("### Current Resources")
            for name, data in resources.items():
                rtype = data.get("type", "unknown")
                scope = data.get("scope", "project")
                host = data.get("host") or data.get("url") or "no host"
                lines.append(f"- **{name}** ({rtype}, {scope}): {host}")
        else:
            lines.append("_No resources configured yet._")

        return "\n".join(lines)

    async def start(self) -> AsyncGenerator[dict, None]:
        """
        Initialize session and send initial greeting.

        Yields message chunks as they stream in.
        """
        # Ensure project directory exists
        self.project_dir.mkdir(parents=True, exist_ok=True)

        # Create security settings with full access
        security_settings = {
            "sandbox": {"enabled": False},  # Full system access
            "permissions": {
                "defaultMode": "acceptEdits",
                "allow": [
                    "Read(./**)",
                    "Read(~/**)",  # Allow reading home directory
                    "Write(./**)",
                    "Edit(./**)",
                    "Glob(./**)",
                    "Grep(./**)",
                    "Bash(*)",  # Full bash access
                    "WebFetch",
                    "WebSearch",
                ],
            },
        }
        settings_file = self.project_dir / ".claude_terminal_settings.json"
        with open(settings_file, "w") as f:
            json.dump(security_settings, f, indent=2)

        # Build system prompt with context
        system_prompt = TERMINAL_SYSTEM_PROMPT.replace(
            "{PROJECT_CONTEXT}",
            self._get_project_context()
        ).replace(
            "{CWD}",
            str(self.project_dir.resolve())
        )

        # Use system Claude CLI
        system_cli = shutil.which("claude")

        try:
            self.client = ClaudeSDKClient(
                options=ClaudeAgentOptions(
                    model="claude-sonnet-4-20250514",  # Sonnet for faster terminal responses
                    cli_path=system_cli,
                    system_prompt=system_prompt,
                    allowed_tools=[
                        "Read",
                        "Write",
                        "Edit",
                        "Glob",
                        "Grep",
                        "Bash",
                        "WebFetch",
                        "WebSearch",
                    ],
                    permission_mode="acceptEdits",
                    max_turns=100,
                    cwd=str(self.project_dir.resolve()),
                    settings=str(settings_file.resolve()),
                )
            )
            await self.client.__aenter__()
            self._client_entered = True
        except Exception as e:
            logger.exception("Failed to create Claude client for terminal")
            yield {
                "type": "error",
                "content": f"Failed to initialize terminal: {str(e)}"
            }
            return

        # Send initial greeting
        initial_message = (
            f"Terminal session started for project **{self.project_name}**.\n\n"
            "I can help you manage resources (servers, services, databases). "
            "What would you like to do?"
        )

        yield {"type": "text", "content": initial_message}
        yield {"type": "resources", "data": self.get_resources()}
        yield {"type": "response_done"}

    async def send_message(
        self,
        user_message: str,
    ) -> AsyncGenerator[dict, None]:
        """
        Send user message and stream Claude's response.

        Args:
            user_message: The user's message

        Yields:
            Message chunks of various types:
            - {"type": "text", "content": str}
            - {"type": "resource_added", "resource": dict}
            - {"type": "verification_result", "result": dict}
            - {"type": "error", "content": str}
        """
        if not self.client:
            yield {
                "type": "error",
                "content": "Session not initialized. Call start() first."
            }
            return

        # Store the user message
        self.messages.append({
            "role": "user",
            "content": user_message,
            "timestamp": datetime.now().isoformat()
        })

        try:
            async for chunk in self._query_claude(user_message):
                yield chunk
            yield {"type": "response_done"}
        except Exception as e:
            logger.exception("Error during terminal query")
            yield {
                "type": "error",
                "content": f"Error: {str(e)}"
            }

    async def _query_claude(
        self,
        message: str,
    ) -> AsyncGenerator[dict, None]:
        """
        Query Claude and stream responses.

        Handles tool calls and text responses.
        Detects resource management operations and yields appropriate events.
        """
        if not self.client:
            return

        await self.client.query(message)

        current_text = ""

        # Stream the response
        async for msg in self.client.receive_response():
            msg_type = type(msg).__name__

            if msg_type == "AssistantMessage" and hasattr(msg, "content"):
                for block in msg.content:
                    block_type = type(block).__name__

                    if block_type == "TextBlock" and hasattr(block, "text"):
                        text = block.text
                        if text:
                            current_text += text
                            yield {"type": "text", "content": text}

                            # Store in message history
                            self.messages.append({
                                "role": "assistant",
                                "content": text,
                                "timestamp": datetime.now().isoformat()
                            })

                    elif block_type == "ToolUseBlock":
                        tool_name = getattr(block, "name", "")
                        tool_input = getattr(block, "input", {})

                        # Detect resource file writes
                        if tool_name == "Write":
                            file_path = tool_input.get("file_path", "")
                            if "resources.json" in file_path:
                                yield {
                                    "type": "resource_updated",
                                    "path": file_path
                                }
                                # Refresh resources
                                yield {
                                    "type": "resources",
                                    "data": self.get_resources()
                                }

                        # Notify about bash commands (for transparency)
                        if tool_name == "Bash":
                            command = tool_input.get("command", "")
                            yield {
                                "type": "command_executing",
                                "command": command[:100] + ("..." if len(command) > 100 else "")
                            }

            elif msg_type == "UserMessage" and hasattr(msg, "content"):
                # Tool results - look for verification results
                for block in msg.content:
                    block_type = type(block).__name__
                    if block_type == "ToolResultBlock":
                        result = getattr(block, "result", "")
                        # Check for SSH or connection test results
                        if "connected" in str(result).lower() or "success" in str(result).lower():
                            yield {
                                "type": "connection_verified",
                                "result": str(result)[:200]
                            }

# Session registry - thread-safe storage of active sessions
_sessions: dict[str, TerminalSession] = {}
_sessions_lock = threading.Lock()

async def get_or_create_terminal_session(
    project_name: str,
    project_dir: Path,
) -> TerminalSession:
    """
    Get existing terminal session or create a new one.

    Args:
        project_name: Name of the project
        project_dir: Path to the project directory

    Returns:
        TerminalSession instance
    """
    with _sessions_lock:
        # Check for existing session
        if project_name in _sessions:
            session = _sessions[project_name]
            # Verify it's still valid
            if session.client and session._client_entered:
                return session
            # Invalid session - remove it
            del _sessions[project_name]

        # Create new session
        session = TerminalSession(project_name, project_dir)
        _sessions[project_name] = session

    return session

async def close_terminal_session(project_name: str) -> None:
    """
    Close and remove a terminal session.

    Args:
        project_name: Name of the project
    """
    session = None
    with _sessions_lock:
        session = _sessions.pop(project_name, None)

    if session:
        await session.close()

def get_active_sessions() -> list[str]:
    """Get list of project names with active terminal sessions."""
    with _sessions_lock:
        return list(_sessions.keys())