Renames: - platform/ → workspace-server/ (Go module path stays as "platform" for external dep compat — will update after plugin module republish) - workspace-template/ → workspace/ Removed (moved to separate repos or deleted): - PLAN.md — internal roadmap (move to private project board) - HANDOFF.md, AGENTS.md — one-time internal session docs - .claude/ — gitignored entirely (local agent config) - infra/cloudflare-worker/ → Molecule-AI/molecule-tenant-proxy - org-templates/molecule-dev/ → standalone template repo - .mcp-eval/ → molecule-mcp-server repo - test-results/ — ephemeral, gitignored Security scrubbing: - Cloudflare account/zone/KV IDs → placeholders - Real EC2 IPs → <EC2_IP> in all docs - CF token prefix, Neon project ID, Fly app names → redacted - Langfuse dev credentials → parameterized - Personal runner username/machine name → generic Community files: - CONTRIBUTING.md — build, test, branch conventions - CODE_OF_CONDUCT.md — Contributor Covenant 2.1 All Dockerfiles, CI workflows, docker-compose, railway.toml, render.yaml, README, CLAUDE.md updated for new directory names. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.2 KiB
6.2 KiB
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/requirements.txt—a2a-python>=0.2.0→a2a-sdk[http-server]>=0.3.0(correct PyPI package) - Fixed
workspace/agent.py— UseChatAnthropicdirectly instead ofinit_chat_model(not available in current langchain-core). Added provider-agnostic model loading with ImportError handling. - Fixed
workspace/skills/loader.py— Detect tools viaisinstance(BaseTool)instead ofis_toolattribute (Pydantic v2 compatibility) - Fixed
workspace/tools/delegation.py— Removedis_toolattribute 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
onlinewith 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:
workspace-server/internal/handlers/workspace.go— AddedProxyA2Ahandlerworkspace-server/internal/router/router.go— Added route
Behavior:
- Resolves workspace URL via Redis cache → DB fallback
- Wraps bare method+params in JSON-RPC 2.0 envelope if needed
- Forwards to agent with 120s timeout via shared
http.Client - Request body capped at 1MB, response at 10MB (
io.LimitReader) - Returns agent response directly
Code Review Fixes (Round 3)
workspace.go— Reuse package-levelhttp.Client, addio.LimitReaderfor request (1MB) and response (10MB), handlejson.Marshalerrordelegation.py— Removed/a2asuffix 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 sendingstr(parts)to LLM, use tuple message format("user", text)loader.py— MoveBaseToolimport outside the per-file loopscore_seo.py— Use word-boundary regex (\b) for keyword density instead of substring countagent.py— CatchImportErrorfor 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— AddeddragOverNodeId,setDragOverNode,nestNode(),isDescendant()to storecanvas/src/components/Canvas.tsx— Wrapped inReactFlowProvider, usesgetIntersectingNodes()duringonNodeDragfor overlap detection,onNodeDragStopto finalize nesting or un-nestingcanvas/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
workspace-server/internal/provisioner/provisioner.go— Docker SDK integration withStart(),Stop(),IsRunning() - Wired into workspace creation:
POST /workspaceswithtemplatefield triggers auto-provisioning - Added
POST /workspaces/:id/retryendpoint for failed workspaces - Secret injection from
workspace_secretstable - Lifecycle: provisioning → online (via heartbeat) or → failed (3min timeout)
- Provisioner initialized in
main.gowith graceful degradation if Docker unavailable
Agent Management (Phase 5, 11a-11d)
- Created
workspace-server/internal/handlers/agent.gowith 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
workspace-server/internal/bundle/package (types.go, exporter.go, importer.go) GET /bundles/export/:id— serialize workspace → bundle JSON with recursive sub-workspacesPOST /bundles/import— create workspace records + trigger provisioner from bundle- Created
workspace-server/internal/handlers/bundle.go
A2A Proxy Fix
- Fixed
POST /workspaces/:id/a2a— injectsmessageIdintoparams.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
findConfigDirto match by workspace name in config.yaml - Handle
os.WriteFileerrors in bundle importer - Handle DB error in agent Move handler (not just ErrNoRows)
- Handle
json.Unmarshalerror in bundle exporter - Use optional chaining in
isDescendantstore function
CLAUDE.md Updates
- Added API routes: config, memory, a2a, retry, agent CRUD, bundles
- Fixed migration count from 5 to 6
- Added
CONFIGS_DIRenv var