# Worker Executor Implementation Plan > Close the last gap in the landing page cookbook: automated code generation via the worker pool. ## Context The work queue, worker registry, build audit, and code agent systems are **all implemented**. The single missing piece is a **work executor** — a background loop that consumes queued tasks and executes them via a code agent. This is analogous to the existing `QueueProcessor` (which processes per-project command queue tasks), but for the generic `WorkQueue` (cross-project worker pool tasks). ### What Already Exists | Component | File | Status | |-----------|------|--------| | Work queue (PostgreSQL) | `internal/adapter/postgres/work_queue.go` | Done | | Worker registry (PostgreSQL) | `internal/adapter/postgres/worker_registry.go` | Done | | Build audit (PostgreSQL) | `internal/adapter/postgres/build_audit.go` | Done | | WorkService (enqueue/dequeue/complete/fail) | `internal/service/work_service.go` | Done | | WorkerService (claim/complete/health) | `internal/service/worker_service.go` | Done | | BuildService (start/status/complete) | `internal/service/build_service.go` | Done | | WorkHandler (REST API) | `internal/handlers/work.go` | Done | | AgentsHandler (REST API) | `internal/handlers/agents.go` | Done | | CodeAgent interface | `internal/port/code_agent.go` | Done | | Domain models (WorkTask, Worker, BuildSpec) | `internal/domain/` | Done | | Command QueueProcessor (reference pattern) | `internal/worker/queue_processor.go` | Done | ### What's Missing | Gap | Priority | |-----|----------| | Work executor daemon (poll loop) | Critical | | BuildSpec → AgentRequest translation | Critical | | Git clone/commit/push in executor | Critical | | Git credential resolution for cross-project | High | | Worker management REST endpoints | Medium | | DNS alias endpoint | Medium | | Create-and-build endpoint | Medium | | Woodpecker build status proxy | Low | --- ## Week 1: Work Executor Core **Goal:** A background loop that claims tasks from the work queue and executes them via a code agent. By end of week, `POST /work/enqueue` → task claimed → agent executes → result recorded. ### Tasks 1. **Create `internal/worker/work_executor.go`** - Follow the `QueueProcessor` pattern from `queue_processor.go` - Poll loop: calls `WorkerService.ClaimTask(workerID)` on a ticker - On task claim: route to appropriate handler based on `task.Type` - On completion: call `WorkerService.CompleteTask(workerID, taskID, result)` - On failure: call `WorkService.FailTask(taskID, errMsg)` (handles retry logic) - Graceful shutdown via context cancellation - Self-registers as a worker via `WorkerService.Register()` on start - Sends heartbeats via `WorkerService.Heartbeat()` on a 30s ticker 2. **Create `internal/worker/build_executor.go`** - Handles `WorkTaskTypeBuild` tasks specifically - Extracts `BuildSpec` fields from `WorkTask.Spec` (map[string]any → typed fields) - Translates `BuildSpec.Prompt` into `domain.AgentRequest` - Calls `CodeAgent.Execute()` with event streaming - Collects output, files changed, duration into `domain.BuildResult` - Returns `BuildResult` to the work executor 3. **Wire into `cmd/rdev-api/main.go`** - Create `WorkExecutor` alongside existing `QueueProcessor` - Inject: `WorkerService`, `BuildService`, `CodeAgentRegistry` - Start on boot, stop on shutdown - Worker ID: hostname or pod name (from `HOSTNAME` env var) 4. **Create `internal/worker/work_executor_test.go`** - Test: executor starts and registers as a worker - Test: executor claims a task and routes to build handler - Test: build handler translates spec and calls code agent - Test: results are recorded via CompleteTask - Test: failures trigger FailTask with retry - Test: graceful shutdown stops the poll loop - Use mock implementations of ports ### Deliverables - `POST /work/enqueue` with a build task → executor picks it up → agent runs → result in `GET /work/{taskId}` - Worker visible in registry during execution - Build audit entry created with spec and result ### Files Created/Modified | File | Action | |------|--------| | `internal/worker/work_executor.go` | Create | | `internal/worker/build_executor.go` | Create | | `internal/worker/work_executor_test.go` | Create | | `cmd/rdev-api/main.go` | Modify (wire executor) | --- ## Week 2: Git Operations & Cross-Project Execution **Goal:** The executor can clone any project's repo, run the agent in that directory, and push results back. By end of week, the full build cycle works: enqueue → clone → agent generates code → commit → push → CI triggers. ### Tasks 1. **Create `internal/worker/pod_git_operations.go`** ✅ IMPLEMENTED - `CommitAndPush(ctx, podName, workDir, message, push) *PostBuildResult` - Runs git commands **inside the pod** via `kubectl exec` (not locally) - Post-build phase: Claude writes code, then rdev programmatically commits/pushes - Follows "LLM vs rdev" principle: LLMs generate code, rdev handles deterministic ops 2. **Add git credential resolution to `BuildExecutor`** - Option A (simplest): Use the Gitea token already in `InfraConfig.GiteaToken` - All project repos are in Gitea, so one token covers all repos - Pass token via HTTPS clone URL: `https://token@git.threesix.ai/org/repo.git` - Option B (per-project): Look up project's git URL from database, resolve credentials - **Recommendation:** Option A — the Gitea token is already loaded and available 3. **Integrate git ops into `BuildExecutor`** - Before agent execution: clone the project's repo to a temp directory - Look up project git URL from database (add `ProjectStore` port or query directly) - After agent execution: if `auto_commit` is true, commit changes - After commit: if `auto_push` is true, push to remote - Capture `commit_sha` and `files_changed` in `BuildResult` 4. **Add project git URL lookup** - The `ProjectInfraService` stores git URLs in the database during `CreateProject` - Add a method to retrieve git info by project ID - Or: include `git_url` in the `WorkTask.Spec` at enqueue time (simpler, no extra lookup) 5. **Test pod git operations** - Integration test via cookbook scripts - Verify commit is created in pod workspace - Verify push succeeds via kubectl exec 6. **Integration test** - Enqueue a build task with a real prompt - Verify agent executes in cloned repo - Verify commit is created (if auto_commit) - Verify push succeeds (if auto_push) - Verify BuildResult has correct fields ### Deliverables - Full build cycle: enqueue → clone → execute → commit → push - Git credentials resolved from infrastructure config - Temp workspace created and cleaned per task - Build audit shows commit SHA and files changed ### Files Created/Modified | File | Action | |------|--------| | `internal/worker/pod_git_operations.go` | Create ✅ | | `internal/worker/build_executor.go` | Modify (add git integration) | | `internal/worker/work_executor.go` | Modify (pass git config) | | `cmd/rdev-api/main.go` | Modify (pass gitea token to executor) | --- ## Week 3: API Enhancements **Goal:** Add the REST endpoints that complete the platform experience. By end of week, users can create a project, enqueue a build, monitor CI status, and manage DNS — all through rdev-api. ### Tasks 1. **Worker management endpoints — `internal/handlers/workers.go`** - `GET /workers` — list all workers with status - `GET /workers/{id}` — get worker details - `POST /workers/{id}/drain` — drain a worker - Wire `WorkerService` into handler - Register in `cmd/rdev-api/main.go` and `openapi.go` 2. **Build management endpoints — `internal/handlers/builds.go`** - `POST /projects/{id}/builds` — enqueue a build (wraps `BuildService.StartBuild()`) - `GET /projects/{id}/builds` — list build history - `GET /projects/{id}/builds/{taskId}` — get build status - Simpler API than raw `/work/enqueue` — project-scoped, build-specific - Register in `cmd/rdev-api/main.go` and `openapi.go` 3. **DNS alias endpoint — `internal/handlers/infrastructure.go`** - `POST /projects/{id}/domains` — add DNS alias (A or CNAME record) - `GET /projects/{id}/domains` — list domains for project - `DELETE /projects/{id}/domains/{domain}` — remove alias - Uses existing Cloudflare adapter's `CreateRecord()` and `DeleteRecordByName()` - The adapter already supports full CRUD — just needs a handler 4. **Woodpecker build status proxy — `internal/handlers/ci.go`** - `GET /projects/{id}/ci/pipelines` — list recent Woodpecker pipelines - `GET /projects/{id}/ci/pipelines/{number}` — get pipeline details - Add `ListPipelines()` and `GetPipeline()` to `port.CIProvider` - Implement in `internal/adapter/woodpecker/client.go` using Woodpecker SDK - Low priority — can defer if time is tight 5. **Create-and-build endpoint — `internal/handlers/project_management.go`** - `POST /project/create-and-build` - Request: `{ name, description, template, prompt, auto_push }` - Calls `ProjectInfraService.CreateProject()` then `BuildService.StartBuild()` - Returns project info + task ID - Trivial once executor is working 6. **Tests for all new handlers** - Follow existing patterns in `handlers/*_test.go` - Test request validation, success paths, error handling ### Deliverables - `POST /projects/{id}/builds` as the clean API for code generation - `GET /workers` for monitoring the worker pool - `POST /projects/{id}/domains` for DNS aliases - `POST /project/create-and-build` for the single-call flow - All endpoints documented in `openapi.go` ### Files Created/Modified | File | Action | |------|--------| | `internal/handlers/workers.go` | Create | | `internal/handlers/workers_test.go` | Create | | `internal/handlers/builds.go` | Create | | `internal/handlers/builds_test.go` | Create | | `internal/handlers/infrastructure.go` | Modify (add domain endpoints) | | `internal/handlers/ci.go` | Create (if time) | | `internal/handlers/project_management.go` | Modify (add create-and-build) | | `internal/adapter/woodpecker/client.go` | Modify (add pipeline methods, if time) | | `internal/port/ci.go` or port updates | Modify (add pipeline interface, if time) | | `cmd/rdev-api/main.go` | Modify (wire new handlers) | | `cmd/rdev-api/openapi.go` | Modify (add routes to spec) | --- ## Week 4: Polish, Validation & Observability **Goal:** End-to-end validation of the cookbook flow. Observability for production operation. Documentation updated. ### Tasks 1. **End-to-end cookbook validation** - Run the landing page cookbook flow from start to finish - `POST /project` with `astro-landing` template - `POST /projects/landing/builds` with customization prompt - Monitor via `GET /work/{taskId}/status` - Verify CI triggers on push - Verify site is live at `https://landing.threesix.ai` - Fix any issues found during validation 2. **Stale task recovery** - Add periodic `RequeueStale()` call to the work executor - Requeue tasks where the worker crashed mid-execution - Add periodic `CleanupOld()` call to remove ancient completed tasks - These methods exist on `WorkQueue` but nothing calls them 3. **Observability additions** - Add metrics to work executor: tasks_claimed, tasks_completed, tasks_failed, execution_duration - Add metrics to worker service: workers_registered, workers_idle, workers_busy - Follow existing pattern in `internal/metrics/metrics.go` - Add work executor health to readiness check (`GET /ready`) 4. **Queue maintenance worker** - Create `internal/worker/queue_maintenance.go` - Runs on a slower ticker (every 5 minutes) - Calls `RequeueStale(ctx, 10*time.Minute)` — requeue tasks running > 10min with no heartbeat - Calls `CleanupOld(ctx, 7*24*time.Hour)` — prune tasks older than 7 days - Wire into main.go 5. **Update documentation** - Update `cookbooks/landing-page.md` with final validated flow - Update `ai-lookup/features/build-orchestration.md` - Update `ai-lookup/services/worker-pool.md` - Add `.claude/guides/services/build-orchestration.md` if needed 6. **Update CLAUDE.md roadmap** - Mark "Work Queue" as implemented - Mark "Worker Pool" as implemented - Mark "Build Orchestration" as implemented - Update "Bot Communication" status ### Deliverables - Cookbook flow works end-to-end without manual intervention (except code generation prompt) - Stale task recovery running in production - Metrics visible in `/metrics` endpoint - All documentation reflects actual capabilities ### Files Created/Modified | File | Action | |------|--------| | `internal/worker/queue_maintenance.go` | Create | | `internal/metrics/metrics.go` | Modify (add work executor metrics) | | `internal/handlers/health.go` | Modify (add executor health) | | `cookbooks/landing-page.md` | Modify (final validation) | | `ai-lookup/features/build-orchestration.md` | Modify | | `ai-lookup/services/worker-pool.md` | Modify | | `CLAUDE.md` | Modify (update roadmap) | | `cmd/rdev-api/main.go` | Modify (wire maintenance worker) | --- ## Risk & Dependencies | Risk | Mitigation | |------|-----------| | CodeAgent execution in a temp directory (not a K8s pod) may not work the same as in-pod execution | Test early in Week 1; fallback is to kubectl exec into a worker pod | | Gitea token may lack permissions for new repos created by different users | Test with actual token; all repos should be in the same org | | Agent execution may take longer than expected (10+ minutes for complex prompts) | Make timeout configurable; increase default | | Worker process crash loses in-flight task | Stale requeue (Week 4) handles this automatically | | 500-line file limit may require splitting new files | Plan for split from the start; `work_executor.go` + `build_executor.go` + `pod_git_operations.go` keeps things modular | ## Architecture Decision: In-Process vs External Worker The plan above implements the executor **in-process** (running inside the rdev-api binary). This is simpler and matches the existing `QueueProcessor` pattern. The alternative would be a separate worker binary, which would allow independent scaling. The in-process approach is the right starting point — it can be extracted into a separate binary later if scaling requires it. ## Summary | Week | Focus | Key Deliverable | |------|-------|----------------| | 1 | Work executor core | Tasks flow from queue → agent → result | | 2 | Git operations | Clone → execute → commit → push cycle | | 3 | API enhancements | Build, worker, DNS, create-and-build endpoints | | 4 | Polish & validation | E2E cookbook flow, observability, docs |