# Projects + Stateful Agents (Claw) — Sprint Plan

**Goal:** Ship Projects with file tools + stateful agents (branded "Claw" in UI) ASAP.
**Spec:** `docs/superpowers/specs/2026-03-16-projects-design.md`
**ADR:** `docs/adr/2026-03-19-project-sandbox-file-access.md`

---

## Architecture summary

```
agent_type = "stateless"  → warm pool (FindAvailablePod), no file sync
agent_type = "stateful"   → dedicated pod per agent (FindOrCreateStatefulPod)
                             files synced before/after run_script via activation service

File tools (read_file, write_file, list_dir, glob, grep)
  → S3 direct from Temporal activity (no pod needed)

run_script
  → stateless: warm pool pod, /workspace/ empty (agent is responsible for files)
  → stateful:  agent's dedicated pod, project files synced to /workspace/ before/after

AgentDelegationTool (existing)
  → pass project_id through → subagent inherits project context automatically

UI: agent_type="stateful" shown as "Claw" badge
```

---

## Parallel tracks

### Track A — Backend data model (Day 1)

**A1: Add `agent_type` to Agent**
- Files: `libs/agents/.../domain/models.py`, new alembic migration
- Change: add `agent_type: Mapped[str] = mapped_column(String, default="stateless")`
- Values: `"stateless"` | `"stateful"`

**A2: Project model + migration**
- Files: create `libs/projects/` library (pyproject.toml, `__init__.py` files)
- `domain/models.py`: `Project` + junction tables (`project_skills`, `project_mcp_instances`, `project_agents`)
- `infrastructure/orm.py`, `infrastructure/repository.py`, `application/service.py`
- Alembic migration: `projects` table + junction tables
- Add `project_id FK nullable` to tasks ORM + migration

**A3: Project CRUD API**
- Files: `apps/api/.../api/v1/projects.py` (new), register in router
- Endpoints: POST/GET/PATCH/DELETE `/projects`, association endpoints (`/projects/{id}/skills`, `/agents`, `/mcp-instances`), file endpoints (`/projects/{id}/files`)
- Add `project_id` to `TaskCreate` schema in `agents_tasks.py`

---

### Track B — Go: stateful pod + activation service (Day 1)

**B1: FindOrCreateStatefulPod in MCP manager**
- Files: `agentarea-mcp-manager/internal/warmpool/client.go`
- Add `FindOrCreateStatefulPod(ctx, agentID string) (*corev1.Pod, error)`:
  - List pods with label `mcp.agentarea.io/agent-id={agentID}` + `status=stateful`
  - If found: return it
  - If not: create a new pod (clone warm pool spec), label it, wait until Running
- Add `EnsureStatefulPodExists` for pre-warming on agent create/update

**B2: Workspace setup/teardown on activation service**
- Files: `agentarea-mcp-manager/activation-service/workspace_handler.go`
- `POST /workspace/setup {"minio_prefix": "...", "work_dir": "/workspace/"}` → download files from MinIO to /workspace/ using Go AWS SDK. Run `/workspace/.agentarea/setup.sh` if exists.
- `POST /workspace/teardown {"minio_prefix": "...", "work_dir": "/workspace/"}` → upload all files back to MinIO, wipe /workspace/
- Register routes in `activation-service/main.go`

**B3: New execute endpoint in MCP manager API**
- Files: `agentarea-mcp-manager/internal/api/handlers.go` (or new `stateful_handler.go`)
- `POST /stateful/{agent_id}/execute` → calls `FindOrCreateStatefulPod` then `ExecuteInPod`
- `POST /stateful/{agent_id}/workspace/setup` → proxies to pod activation service `/workspace/setup`
- `POST /stateful/{agent_id}/workspace/teardown` → proxies to pod activation service `/workspace/teardown`

---

### Track C — Helm (Day 1, independent)

**C1: Warm pool pod spec — add /workspace/ volume**
- Files: `charts/` (warm pool pod spec)
- Add `emptyDir` volume mounted at `/workspace/`
- Stateful pods: same spec + label `mcp.agentarea.io/agent-id` + no ReturnToPool

---

### Track D — Execution integration (Day 2, depends on A+B)

**D1: Thread project_id through execution models**
- `libs/execution/.../models.py`: `AgentExecutionRequest` → add `project_id: str | None = None`
- `libs/execution/.../workflows/models.py`: `AgentExecutionState` → add `project_id`, `project_context`; `ContinueAsNewState` → add `project_id`
- `libs/agents/.../domain/interfaces.py`: `StartTaskRequest` → add `project_id`
- `libs/tasks/.../domain/models.py`: `Task`, `SimpleTask` → add `project_id`
- `AgentDelegationTool.execute()`: pass parent's `project_id` to delegated `SimpleTask` → subagent inherits project

**D2: New Temporal activities**
- Files: `libs/execution/.../activities/agent_execution_activities.py`
- `resolve_project_context(project_id)` → load project from DB, return dict
- `execute_s3_file_tool(tool_name, args, minio_prefix)` → direct boto3 call (read/write/list/glob/grep)
- `execute_sandbox_tool(agent_id, agent_type, script, project_id, minio_prefix)`:
  - stateless: `FindAvailablePod` → `ExecuteInPod` → `ReturnToPool`
  - stateful: `POST /stateful/{agent_id}/workspace/setup` → `POST /stateful/{agent_id}/execute` → `POST /stateful/{agent_id}/workspace/teardown`

**D3: Workflow router — new tool branches**
- Files: `libs/execution/.../workflows/agent_execution_workflow.py`
- At workflow init: if `project_id` set → call `resolve_project_context`, store in state
- In `_process_tool_call`: add branches for S3 file tools → `execute_s3_file_tool`; `run_script` → `execute_sandbox_tool`; `get_project_info` → read from state
- Register file tools in agent tool list alongside MCP tools

---

### Track E — Frontend (Day 2, depends on A3)

**E1: Projects pages**
- `/projects` — list with create button
- `/projects/new` — name, description, instructions form
- `/projects/{id}` — tabs: Overview, Files, Agents, Skills, MCP Servers, Tasks
- `/projects/{id}/settings` — edit name/description/instructions
- Add "Projects" to sidebar between Agents and Skills

**E2: Agent type toggle**
- In agent create/edit form: toggle "Enable Claw" (sets `agent_type="stateful"`)
- Show "Claw" badge on agent cards/list when `agent_type="stateful"`

**E3: Task creation with project**
- Add project picker to task creation UI (optional dropdown)

---

## Dependency graph

```
Track A (A1, A2, A3) ──────────────────────┐
Track B (B1, B2, B3) ──────────────────────┼──→ Track D (D1 → D2 → D3)
Track C ───────────────────────────────────┘

Track A (A3 done) ─────────────────────────────→ Track E
```

**Day 1:** Tracks A, B, C in parallel
**Day 2:** Tracks D and E in parallel

---

## What we're NOT building yet

- Claw hibernation / PVC snapshots (pod just stays running)
- Per-plan Claw quotas (1 per workspace, hardcoded)
- Isolated subagent context (subagents share parent's project_id for now)
- Stateless agent `run_script` (only stateful agents get `run_script` in v1)
