# Edit History — 2026-04-01

## Summary

Completed **Phase 2 end-to-end validation** (SEO agent template, Docker build fixes, A2A proxy endpoint) and **comprehensive PLAN.md rewrite** (10 → 15 phases). Two rounds of code review fixes on canvas and platform code.

## Phase 2: End-to-End Validation

### SEO Agent Template (8a)
- Created `workspace-configs-templates/seo-agent/config.yaml` — Tier 1, two skills, web_search tool
- Created `workspace-configs-templates/seo-agent/system-prompt.md` — SEO specialist identity
- Created `workspace-configs-templates/seo-agent/skills/generate-seo-page/SKILL.md` — 4-step SEO page generation process
- Created `workspace-configs-templates/seo-agent/skills/generate-seo-page/tools/score_seo.py` — @tool function scoring content for SEO factors (word count, keyword density, H1/H2 structure, meta description)
- Created `workspace-configs-templates/seo-agent/skills/audit-seo-page/SKILL.md` — Comprehensive SEO audit checklist

### Docker Build Fixes (8b)
- Fixed `workspace-template/requirements.txt` — `a2a-python>=0.2.0` → `a2a-sdk[http-server]>=0.3.0` (correct PyPI package)
- Fixed `workspace-template/agent.py` — Use `ChatAnthropic` directly instead of `init_chat_model` (not available in current langchain-core). Added provider-agnostic model loading with ImportError handling.
- Fixed `workspace-template/skills/loader.py` — Detect tools via `isinstance(BaseTool)` instead of `is_tool` attribute (Pydantic v2 compatibility)
- Fixed `workspace-template/tools/delegation.py` — Removed `is_tool` attribute set (Pydantic v2 rejects arbitrary attributes on StructuredTool)

### End-to-End Deployment Verified (8c-8d)
- Container starts, loads 2 skills, serves Agent Card at `/.well-known/agent-card.json`
- Registers with platform → status `online` with full Agent Card (skills, capabilities)
- A2A proxy forwards messages through platform to agent → agent calls Claude API
- Blocked by 429 rate limit during testing (subscription quota contention)

## POST /workspaces/:id/a2a Proxy Endpoint (Phase 11, 17s)

**New files:**
- `platform/internal/handlers/workspace.go` — Added `ProxyA2A` handler
- `platform/internal/router/router.go` — Added route

**Behavior:**
1. Resolves workspace URL via Redis cache → DB fallback
2. Wraps bare method+params in JSON-RPC 2.0 envelope if needed
3. Forwards to agent with 120s timeout via shared `http.Client`
4. Request body capped at 1MB, response at 10MB (`io.LimitReader`)
5. Returns agent response directly

## Code Review Fixes (Round 3)

- `workspace.go` — Reuse package-level `http.Client`, add `io.LimitReader` for request (1MB) and response (10MB), handle `json.Marshal` error
- `delegation.py` — Removed `/a2a` suffix from target URL (A2A SDK serves at root), read retry config from env vars (`DELEGATION_RETRY_ATTEMPTS`, `DELEGATION_RETRY_DELAY`, `DELEGATION_TIMEOUT`)
- `a2a_executor.py` — Return error message on empty input instead of sending `str(parts)` to LLM, use tuple message format `("user", text)`
- `loader.py` — Move `BaseTool` import outside the per-file loop
- `score_seo.py` — Use word-boundary regex (`\b`) for keyword density instead of substring count
- `agent.py` — Catch `ImportError` for optional provider packages with clear install message

## PLAN.md Comprehensive Rewrite

Expanded from 10 phases to 15 phases after cross-referencing all 29 docs files:
- Added Phase 5 (Agent Management), Phase 9 (HMA Memory), Phase 12 (Code Sandbox), Phase 13 (Runtime Enhancements), Phase 15 (SaaS Preparation)
- Tracked all PRD features: F1.13 connection breakage, F4.4 ClawHub, F6.5 configurable approval rules
- Added event type annotations (AGENT_*, WORKSPACE_EXPANDED/COLLAPSED)
- Final counts: 15 phases, 107 tracked items (25 done, 81 todo, 1 partial)

## Canvas Drag-to-Nest (Phase 3, 9e)

- `canvas/src/store/canvas.ts` — Added `dragOverNodeId`, `setDragOverNode`, `nestNode()`, `isDescendant()` to store
- `canvas/src/components/Canvas.tsx` — Wrapped in `ReactFlowProvider`, uses `getIntersectingNodes()` during `onNodeDrag` for overlap detection, `onNodeDragStop` to finalize nesting or un-nesting
- `canvas/src/components/WorkspaceNode.tsx` — Green ring highlight (`border-green-500 ring-2 scale-105`) when node is a valid drop target

## Provisioner Package (Phase 4, 10a-10g)

- Created `platform/internal/provisioner/provisioner.go` — Docker SDK integration with `Start()`, `Stop()`, `IsRunning()`
- Wired into workspace creation: `POST /workspaces` with `template` field triggers auto-provisioning
- Added `POST /workspaces/:id/retry` endpoint for failed workspaces
- Secret injection from `workspace_secrets` table
- Lifecycle: provisioning → online (via heartbeat) or → failed (3min timeout)
- Provisioner initialized in `main.go` with graceful degradation if Docker unavailable

## Agent Management (Phase 5, 11a-11d)

- Created `platform/internal/handlers/agent.go` with 4 endpoints
- `POST /workspaces/:id/agent` — assign (AGENT_ASSIGNED)
- `PATCH /workspaces/:id/agent` — replace model (AGENT_REPLACED)
- `DELETE /workspaces/:id/agent` — remove (AGENT_REMOVED)
- `POST /workspaces/:id/agent/move` — move between workspaces (AGENT_MOVED on both)

## Bundle Export/Import (Phase 6, 12a-12c)

- Created `platform/internal/bundle/` package (types.go, exporter.go, importer.go)
- `GET /bundles/export/:id` — serialize workspace → bundle JSON with recursive sub-workspaces
- `POST /bundles/import` — create workspace records + trigger provisioner from bundle
- Created `platform/internal/handlers/bundle.go`

## A2A Proxy Fix

- Fixed `POST /workspaces/:id/a2a` — injects `messageId` into `params.message` (required by a2a-sdk v0.3+)
- Fixed stale process on port 8080 serving old binary

## Code Review Fixes (Round 4)

- Removed debug log lines from ProxyA2A
- Guard short ID slicing in provisioner and importer (`[:12]`, `[:8]`)
- Fixed `findConfigDir` to match by workspace name in config.yaml
- Handle `os.WriteFile` errors in bundle importer
- Handle DB error in agent Move handler (not just ErrNoRows)
- Handle `json.Unmarshal` error in bundle exporter
- Use optional chaining in `isDescendant` store function

## CLAUDE.md Updates

- Added API routes: config, memory, a2a, retry, agent CRUD, bundles
- Fixed migration count from 5 to 6
- Added `CONFIGS_DIR` env var
