Files
poimen-workflows/tasks/INDEX.md
T
Test 3a8f946105 Scaffold: PLAN.md, tasks/INDEX.md, tasks/board.md
Initial project structure documentation and task breakdown for Multi-Agent Dev Orchestrator (Temporal + Go).
2026-08-20 22:10:14 -07:00

6.9 KiB

Poimen Workflows — Development Guidelines

This project orchestrates multi-agent software development tasks using Temporal + Go. The repo is organized as:

  • statemachine/ — Temporal workflow definitions (deterministic state machines)
  • action/ — Temporal activity definitions (units of work / LLM calls)
  • cmd/ — CLI entry points (worker registration, workflow starter)
  • prompts/ — LLM prompt templates (Go-embedded, live-updatable)
  • internal/ — Shared config/locking utilities
  • tests/ — Unit tests via go.temporal.io/sdk/testsuite

Code Standards

Go Style

Follow golang-skills conventions from ~/.claude/skills/golang-skills/:

  • Error handling mandatory; no naked _ = discards.
  • Idiomatic naming: ctx for context, err for error returns.
  • Interfaces kept narrow; one struct per concern.
  • No over-generalization for hypothetical use.
  • Documentation via comments only where the WHY is non-obvious.

Testing

  • Every statemachine/* change ships with a testsuite-based test in tests/.
  • Unit tests use go.temporal.io/sdk/testsuite.WorkflowTestEnvironment with mocked activities.
  • Activities are tested in isolation before integrating into workflows.
  • No literal timeout/retry values in action/* code — all come from OrchestratorConfig.Tuning at runtime.

Activity Design

Activities stay side-effect-isolated (one concern per file) so they remain independently reusable across projects.

  • action/git.go — all git operations
  • action/skills.go — skill prep / pi command
  • action/planner.go — Planner LLM call
  • action/judge.go — Judge LLM call
  • action/implementer.go — Implementer LLM + tool-call loop
  • action/lessons.go — Lessons store read/write

No composite activities like PrepareAndImplement; that's a workflow's job, not an activity's.

Config as Data

No hardcoded numbers. Every timeout, retry count, backoff coefficient, stream timeout — all come from OrchestratorConfig.Tuning (or role-specific PromptSpec.Model), read at execution time. This lets:

  • update-tuning signal to dynamically adjust timeouts without redeployment
  • Planner activity to recommend per-task overrides
  • Pi 504 handler to learn and persist StreamTimeout across ContinueAsNew cycles

No LLM model hardcoded. Every model ID comes from ModelSpec.ModelID, passed as data.

Concurrency & Locking

Target repo sits on shared filesystem. Git concurrency is safe by construction:

  • Task units use isolated worktrees (git worktree add -b task/T0.x ...)
  • Commits within a worktree don't need a lock; git serializes object writes
  • Only CloneRepoActivity, GitPushActivity, GitSquashMergeActivity need the orchestrator.lock, since they mutate the main working tree / refs

Monitor for deadlocks: if two workflows try to push simultaneously, the lock will serialize them. Test with concurrent tasks enabled.

Task Board Format

Each task row in the board specifies:

  • ID: T0.1, T0.2, etc.
  • Description: One-line scope
  • Status: [ ] (todo), [x] (done)
  • Branch: task/T0.x (created when task starts, merged to main on submilestone complete)
  • Verification: Specific criterion that marks it done (e.g. "Unit test passes", "E2E run completes")

A task is NOT marked done until its verification step passes. This mirrors the Judge role's own job: no hallucinated completion.

Submilestones & Merges

When all tasks in T0 (T0.1 through T0.9) pass their verification:

  1. Orchestrator calls GitSquashMergeActivity to merge all task/T0.* branches into main as a single squashed commit
  2. All task/T0.* branches and worktrees are cleaned up
  3. Main branch is the canonical history; the 9 subtask commits are compacted into one

This demonstrates the very mechanism the system orchestrates: a working software dev pipeline with multiple agents collaborating on a shared codebase, guarded by state checks (Judge), and landing changes via deterministic git workflow.

Historical Lessons

Lessons live at tasks/.orchestrator/lessons/<TaskID>.jsonl — per-task file of failed attempts. When a Judge calls a task failure, the UpdateLessonsActivity appends {Attempt, Critique, FailedApproachSummary, Timestamp}. On retry, ReadLessonsActivity injects the last N entries into the Implementer's prompt as "known errors — do not repeat this time".

Lessons flush to git only as part of the Planner's board commit, not on every retry — keeps history clean.

Skills & Preparation

Required skill sources are listed in OrchestratorConfig.Skills as a list of references (e.g. ["~/.claude/skills/golang-skills", "custom-skill-repo"]). PrepareSkillsActivity runs once per config change, cloning/fetching them onto the shared FS via the pi command. All retry/backoff/timeout is delegated to Temporal's retry machinery, with special handling for 504 (stream timeout learning).

Environment & Secrets

All external system access is via environment variables, loaded at worker startup:

  • TEMPORAL_NAMESPACE, TEMPORAL_TLS_CERT, TEMPORAL_TLS_KEY — Temporal cluster connection
  • ANTHROPIC_API_KEY — LLM API key
  • Any target-repo-specific credentials (e.g. git SSH key) are assumed already available on the shared FS (e.g. via Kubernetes secret mount)

Use homelab's vsource .env pattern to load from a .env file during local development.

Observability

  • Temporal Web UI (temporal.riotpiao.com:8080 or similar) shows workflow execution, signal delivery, activity retries
  • Workflow current-config query returns live OrchestratorConfig (useful for debugging which tuning values are in effect)
  • Activity heartbeats (activity.RecordHeartbeat) are sent after each tool-call iteration, visible in Temporal's activity details
  • Lessons file grows as retries happen; inspect it on failure to understand what the Implementer is learning

Deployment & Homelab Integration

This repo is application-layer code against the homelab's Temporal cluster. The orchestrator runs as a Kubernetes pod with:

  • Persistent volume (PVC) for the shared FS where target repos are cloned
  • Network access to Temporal + Anthropic APIs
  • Git SSH key mounted for cloning target repos

The Kubernetes manifests + Helm charts live in the homelab repo under k8s/ and follow homelab's GitOps workflow (commit → ArgoCD sync). This repo's CI/CD (GitHub Actions or Forgejo Actions) builds and pushes the Docker image; the homelab repo triggers a new pod deploy on image push.

Questions & Debugging

If a task is marked done but you suspect it's wrong:

  1. Re-run its verification step manually
  2. Check the unit test against the latest code
  3. For e2e tasks, review Temporal Web UI logs + board file + lessons file on the target repo
  4. Update the board and task description if the criterion was misunderstood

If code doesn't compile or tests fail:

  1. Check Go version and Temporal SDK version match
  2. Run go mod tidy and go mod vendor if dependencies drift
  3. Look for hardcoded values or model IDs that should be config instead