Files
poimen-workflows/README.md
T
Test 86ad8e7b5e
ci / test (push) Successful in 1m50s
docs: comprehensive README with skills & knowledge guide
- Explain Poimen philosophy (shepherd metaphor for orchestration)
- Document architecture and data flow with visual diagrams
- List all 9 registered activities with knowledge specs
- Provide getting started guide and usage patterns
- Include CI/CD pipeline, troubleshooting, and roadmap
- Integrate skills registration guide for contributors
- Explain registerable knowledge types (activity, domain, patterns)
- Document CRAP score improvements (97% reduction)
- Create virtuous cycle explanation (self-improving system)
- Add .gitignore exception for README.md

Refs: Shepherd metaphor emphasizes learning, adaptation, and composition
over rigid task scheduling. Each registered skill teaches the system.
2026-09-03 13:58:33 -07:00

23 KiB

Poimen Workflows

Temporal-powered orchestration that transforms natural language into durable, scalable workflow executions.

CI Status Go Report Card Test Coverage

What is Poimen?

Poimen (Greek: Ποιμήν) means "shepherd" — a guide who tends, orchestrates, and reconciles. In this project, Poimen acts as an intelligent orchestration shepherd for distributed agent workflows:

  • 🐑 Shepherds workflows — Guides activities from intent to completion
  • 🔄 Reconciles state — Ensures consistency across distributed steps
  • 🎯 Routes intelligently — Uses LLM reasoning to choose the best path forward
  • 💾 Remembers lessons — Semantic memory prevents repeated mistakes
  • 🛡️ Fault-tolerant — Temporal's durable execution keeps workflows safe from failure

Like a shepherd managing a flock, Poimen manages orchestrated agent deployments at scale—keeping tasks aligned, recovering from chaos, and learning from each execution.

Overview

Poimen Workflows orchestrates complex agent-driven tasks using LLM-powered routing, semantic memory integration, and durable state machines. Write your intent in plain English—the system generates executable Temporal workflows, manages retries and error handling, and scales to thousands of concurrent executions.

Core Promise: Any activity (code scan, deployment, notification) becomes a composable building block in a larger reconciliation pipeline, with intelligent ordering, memory-augmented context, and automatic fault recovery.


Architecture & Data Flow

User Request
    ↓
    ├─→ [1. LLM Router] 
    │   • Analyze intent & extract parameters
    │   • Query semantic memory for domain knowledge
    │   • Build WorkflowSpec with activity graph
    │   • Inject retry policies & error handlers
    │
    ├─→ [2. Memory Retrieval]
    │   • RetrieveMemoryActivity queries poimen-memory (Rust semantic search)
    │   • Returns relevant skills, lessons, best practices
    │   • Augments LLM prompts with domain context
    │
    ├─→ [3. Workflow Validation]
    │   • StateGraphValidator: Check DAG structure
    │   • ActivityAvailabilityValidator: Verify all activities registered
    │   • TimeoutValidator: Validate timeout formats
    │   • OutputMatchValidator: Ensure parameter bindings exist
    │
    ├─→ [4. Temporal Execution]
    │   • RoutingWorkflow executes state machine
    │   • JSONPath parameter chaining: ${Step1.output.path}
    │   • Automatic retries for transient failures
    │   • Catch blocks for graceful error recovery
    │   • Durable execution guarantees (fault-tolerant)
    │
    └─→ Completed Workflow
        • Results stored in activity output
        • Memory updated with execution logs
        • Notifications sent via DeploymentPreCheckActivity

Philosophy: The Shepherd's Role

Poimen embodies three core principles:

  1. Orchestration as Shepherding

    • Not rigid task scheduling, but intelligent guidance
    • Activities work together toward a common goal
    • The system learns and adapts from each execution
  2. Reconciliation as Healing

    • Workflows reconcile state across distributed systems
    • Errors are opportunities to learn, not failures to hide
    • Memory persists lessons so future workflows are smarter
  3. Scale through Composition

    • One shepherd (Poimen) tends infinite flocks (workflows)
    • Skills compose into larger behaviors
    • Knowledge compounds—each registration makes routing better

The metaphor: Just as a shepherd doesn't dictate each sheep's movement but guides the flock toward pasture, Poimen doesn't hard-code workflows but learns from context, remembers lessons, and guides agents through complex, adaptive orchestration.


Key Features

🧠 LLM-Powered Routing

  • Natural Language Input: "Scan repo for security issues and notify team"
  • Intelligent Workflow Generation: Reasoning model generates executable WorkflowSpec
  • Activity Knowledge Base: 9 registered activities inform LLM about timeouts, retry policies, dependencies
  • Error Handling Strategies: Automatic catch blocks and fallback flows

💾 Memory-Augmented Context

  • Semantic Search Integration: Query poimen-memory before routing decisions
  • Domain Knowledge Injection: Skills and lessons automatically augment LLM prompts
  • Skill Reusability: Registered knowledge base prevents redundant work
  • Learning Loop: Execution results feed back into memory for continuous improvement

🔄 Generic State Machine Executor

  • JSON WorkflowSpec: Any activity graph becomes executable
  • Parameter Chaining: JSONPath-based data flow (${ActivityA.output.field})
  • Automatic Retries: Configurable retry policies per activity
  • Catch Blocks: Error recovery with fallback states
  • Durable Guarantees: Temporal ensures exactly-once execution + resume-on-failure

🔌 Extensible Architecture

  • LLMProvider Interface: Swap providers (OpenAI, Claude, local models) at runtime
  • SpecBuilder Interface: Multiple strategies for workflow generation (default, cron, custom)
  • WorkflowValidator Interface: Composable validation pipeline
  • ActivityExecutor Interface: Pluggable execution strategies
  • Decorator Pattern: Caching & retry wrappers for any provider

Registered Activities (Knowledge Base)

Activity Purpose Timeout Retry
CloneRepo Clone git repository 30s 3x
AnalyzeCode Static analysis (SAST) 120s 2x
SecurityScan Dependency & vulnerability scan 60s 2x
GenerateReport Compile results into report 30s 1x
DeploymentPreCheck Validation before deployment 45s 2x
NotifyStatus Send notifications (Slack, email) 15s 1x
ApproveWorkflow Manual approval gate 3600s 0x
ArchiveResults Store results to S3/KV 30s 2x
RetrieveMemory Query semantic memory service 10s 1x

👉 See internal/routing/activity_knowledge_base.json for detailed specs.


Getting Started

Prerequisites

  • Go 1.21+
  • Temporal Server (local or cloud)
  • Docker (for running Temporal locally)

Installation

git clone https://github.com/your-org/workflows.git
cd workflows
go mod download

Running Locally

1. Start Temporal (via Docker Compose):

docker-compose up -d temporal

2. Register activities and workflow:

cd cmd/worker
go build -o worker
./worker

3. Trigger a workflow via CLI:

cd cmd/starter
go build -o starter
./starter --route "Analyze repository for security vulnerabilities"

4. Or trigger programmatically:

import "github.com/your-org/workflows/pkg/client"

ctx := context.Background()
c := client.NewClient(...)

run, err := c.ExecuteWorkflow(ctx, &client.ExecuteWorkflowOptions{
    ID:       "security-scan-1",
    TaskQueue: "routing",
}, "RoutingWorkflow", &routing.WorkflowInput{
    UserRequest: "Scan repo X for CVEs",
})
// Wait for result
var result routing.WorkflowOutput
run.Get(ctx, &result)

Usage Patterns

Pattern 1: Simple CLI Routing

./starter --route "Deploy service to staging"

Pattern 2: Direct Spec Execution

./starter --spec workflow.json

Pattern 3: Service Integration

// From your application code
client := temporal.NewClient()
result, err := client.ExecuteWorkflow(ctx, options, "RoutingWorkflow", input)
// Implements durable retry + failure recovery

Pattern 4: Custom Validator Chain

config := &routing.LLMRouterConfig{
    Validators: []routing.WorkflowValidator{
        routing.NewStateGraphValidator(),
        routing.NewActivityAvailabilityValidator(),
        routing.NewTimeoutValidator(),
        routing.NewOutputMatchValidator(),
    },
}
router := routing.NewLLMRouter(config)

Registerable Skills & Knowledge

The Shepherd's Knowledge

Just as a good shepherd knows the terrain, remembers which paths work, and learns from past journeys, Poimen's intelligence comes from accumulated knowledge:

  • What can be done? (Activity Knowledge) — Registry of available skills
  • How has it been done well? (Domain Knowledge) — Lessons from past executions
  • What patterns work? (Workflow Patterns) — Proven sequences and error recovery
  • What went wrong before? (Error Knowledge) — Lessons to avoid mistakes
  • How should recovery work? (Execution Policies) — Graceful fallbacks

When you register a skill, you're teaching the shepherd about a new capability. When you contribute domain knowledge, you're sharing wisdom so future workflows avoid mistakes.

What is a Registerable Skill?

A skill is a composable unit of work that:

  1. Solves a specific problem (code analysis, deployment, notification)
  2. Has well-defined inputs/outputs (Git repo URL → vulnerability report)
  3. Encodes domain knowledge (retry policies, timeouts, dependencies)
  4. Scales independently (can be retried, cached, load-balanced)
  5. Is discovered by the router (LLM knows when/how to use it)

Types of Registerable Knowledge

1. Activity Knowledge (What can be done?)

  • Definition: Capabilities, inputs, outputs, timeout/retry policies
  • Stored in: activity_knowledge_base.json
  • Used by: LLM router to decide which activities to use
{
  "name": "SecurityScan",
  "timeout": "60s",
  "maxRetries": 2,
  "inputs": ["repo_url", "branch"],
  "outputs": ["report", "severity_count"]
}

2. Domain Knowledge (How should it be done?)

  • Definition: Best practices, error patterns, optimization strategies
  • Stored in: Semantic memory service (poimen-memory)
  • Used by: LLM router to augment prompts before spec generation
type MemoryContext struct {
    Skills []string       // Relevant skills
    Lessons []string      // Best practices
    ErrorPatterns []string // Common failures & fixes
}

3. Workflow Patterns (What sequences work?)

  • Definition: Proven workflows for common scenarios
  • Stored in: LLM prompt templates (agent-prompts/router/AGENTS.md)
  • Used by: SpecBuilder to generate efficient workflows
Patterns:
  - name: "Security Review"
    activities: ["CloneRepo", "SecurityScan", "GenerateReport", "NotifyStatus"]
    conditions: {"branch": "main"}

4. Skill Dependencies (What needs what?)

  • Definition: Activity prerequisites and data flow
  • Stored in: Activity specs + JSONPath parameter bindings
  • Used by: Workflow validator to check graph validity
{
  "activity": "AnalyzeCode",
  "parameters": {
    "source_path": "${CloneRepo.output.repo_path}"
  },
  "depends_on": ["CloneRepo"]
}

5. Execution Policies (When should it fail/retry?)

  • Definition: Retry strategies, error handlers, fallbacks
  • Stored in: Activity specs + catch blocks in workflows
  • Used by: StateTransitioner to decide recovery actions
{
  "activity": "NotifyStatus",
  "retry_policy": {
    "max_attempts": 3,
    "initial_interval": "1s",
    "backoff_coefficient": 2.0
  },
  "catch_blocks": [
    {
      "error_type": "AuthenticationError",
      "action": "log_and_continue"
    }
  ]
}

How LLM Router Uses Registered Skills

Flow: User Request → Knowledge-Augmented Routing

User: "Scan repository for security issues and deploy if safe"
  ↓
[1. Retrieve Memory]
  Query for "security scan + deployment" patterns
  Returns: Best practices, error handlers, proven sequences
  ↓
[2. Augment LLM Prompt]
  System message includes:
  - Available activities (from knowledge_base.json)
  - Relevant patterns (from memory)
  - Lessons learned (from memory)
  ↓
[3. Generate WorkflowSpec]
  LLM reasons:
  - "SecurityScan is first (needs fresh clone)"
  - "If vulnerabilities found, stop; don't deploy"
  - "Cache results per commit for 5 minutes"
  ↓
[4. Validate Spec]
  - All activities registered? ✓
  - All parameters have sources? ✓
  - Timeouts reasonable? ✓
  ↓
[5. Execute]
  RoutingWorkflow with automatic retries + error recovery

Registering a New Skill (Step-by-Step)

Step 1: Implement the Activity

// action/my_new_skill.go
package action

type MyNewSkillInput struct {
    Input1 string `json:"input1"`
    Input2 int    `json:"input2"`
}

type MyNewSkillOutput struct {
    Success bool   `json:"success"`
    Message string `json:"message"`
    Data    string `json:"data"`
}

func MyNewSkill(ctx context.Context, input *MyNewSkillInput) (*MyNewSkillOutput, error) {
    // Implement logic
    return &MyNewSkillOutput{
        Success: true,
        Message: "Executed successfully",
        Data: "result...",
    }, nil
}

Step 2: Add to Knowledge Base

Edit internal/routing/activity_knowledge_base.json:

{
  "name": "MyNewSkill",
  "description": "Does something important",
  "inputs": [
    {
      "name": "input1",
      "type": "string",
      "description": "First input parameter",
      "required": true,
      "examples": ["example1", "example2"]
    }
  ],
  "outputs": [
    {
      "name": "success",
      "type": "boolean",
      "description": "Whether executed successfully"
    }
  ],
  "timeout": "30s",
  "maxRetries": 2,
  "retryPolicy": "exponential",
  "dependencies": [],
  "tags": ["domain", "category"],
  "knowledge": {
    "bestPractices": [
      "Always validate input format",
      "Log all errors"
    ],
    "errorHandling": "On ValidationError, return empty data",
    "performance": "Caches results for 1 minute",
    "constraints": "Requires internet connection"
  }
}

Step 3: Register with Temporal Worker

// cmd/worker/main.go
worker.RegisterActivity(action.MyNewSkill)

Step 4: Test Routing

go build -o worker ./cmd/worker
./worker &

./starter --route "Use MyNewSkill to process my data"

Skill Registration Checklist

  • Well-defined interface — Inputs/outputs clearly typed
  • Timeout is reasonable — Not too short (flaky), not too long (blocking)
  • Retry policy is sensible — Network failures get retries; auth failures don't
  • Error handling is graceful — Returns partial results, doesn't crash
  • Dependencies are clear — Knows what other skills it needs
  • Knowledge is explicit — Best practices documented in spec
  • Idempotent or tagged — Safe to retry without side effects
  • Observable — Logs important milestones
  • Tested — Unit tests + integration tests
  • Documented — Clear description for LLM prompts

The Virtuous Cycle

1. Register Skill A
   ↓
2. Router uses Skill A in workflows
   ↓
3. Execution logs captured → lessons learned
   ↓
4. Register Domain Knowledge from Skill A's lessons
   ↓
5. Future workflows route smarter (memory-augmented)
   ↓
6. Register Skill B (improved by A's knowledge)
   ↓
7. Repeat → System gets smarter

The system is self-improving. Each addition makes it better for everyone.


Project Structure

workflows/
├── cmd/
│   ├── worker/           # Temporal worker (registers activities & workflows)
│   └── starter/          # CLI for triggering workflows
├── action/               # Activity implementations
│   ├── analysis.go       # Code analysis activity
│   ├── memory.go         # Memory retrieval activity
│   ├── notification.go   # Status notifications
│   ├── logger.go         # Structured logging
│   └── router.go         # Router activity orchestration
├── internal/routing/
│   ├── types.go          # WorkflowSpec, ActivitySpec types
│   ├── knowledge_base.go # Activity knowledge base loader
│   ├── llm_client.go     # LLM provider interface
│   ├── llm_router.go     # Natural language → WorkflowSpec
│   ├── provider.go       # LLMProvider implementations (caching, retry)
│   ├── spec_builder.go   # SpecBuilder interface & implementations
│   ├── executor.go       # Validators, executors, state transitioners
│   ├── activity_knowledge_base.json # Activity registry
│   └── *_test.go         # Unit tests
├── statemachine/
│   └── routing_workflow.go # RoutingWorkflow state machine executor
├── agent-prompts/
│   └── router/AGENTS.md  # LLM prompts for routing decisions
├── k8s/
│   ├── worker-deployment.yaml
│   └── configmap.yaml
├── examples/
│   ├── service_integration.go
│   └── wait_for_task_test.go
├── tests/
│   └── *_test.go         # Integration & E2E tests
├── docs/
│   └── *.md              # Architecture & design docs
└── README.md             # This file

Configuration

Environment Variables

# LLM Configuration
LLM_ENDPOINT="https://api.riotpiao.com/v1/chat/completions"
LLM_MODEL="reasoning"
LLM_API_KEY="your-api-key"

# Temporal Configuration
TEMPORAL_HOST_URL="localhost:7233"
TEMPORAL_NAMESPACE="default"

# Memory Service
MEMORY_SERVICE_URL="http://poimen-memory.poimen.svc.cluster.local:8080"

# Logging
LOG_LEVEL="info"

LLMRouter Configuration (Programmatic)

config := &routing.LLMRouterConfig{
    KnowledgeBase: kb,
    LLMProviders: []routing.LLMProvider{
        openai.NewOpenAIProvider("gpt-4"),
        claude.NewClaudeProvider("claude-3"),
        local.NewLocalProvider(":8000"),
    },
    SpecBuilders: []routing.SpecBuilder{
        routing.NewDefaultSpecBuilder(),
        routing.NewCronSpecBuilder(),
    },
    Validators: []routing.WorkflowValidator{
        routing.NewStateGraphValidator(),
        routing.NewActivityAvailabilityValidator(),
    },
    CacheProvider: routing.NewCachingLLMProvider(cache),
}
router := routing.NewLLMRouter(config)

Testing

Unit Tests

go test ./... -v

Coverage Report

go test ./... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out

Integration Tests

# Requires Temporal running
go test -tags=integration ./tests/...

Current Coverage

  • internal/routing: 45.9%
  • action: ~60%
  • statemachine: ~50%

See poimen-docs/CRAP_ANALYSIS.md for complexity metrics.


CRAP Score Improvements

Refactoring focused on reducing cyclomatic complexity via helper extraction and strategy patterns:

Function Before After Improvement
buildCronSpec 156 5 97% ↓
buildParameters 90 6 93% ↓
RoutingWorkflow 132 7 95% ↓
DeploymentPreCheckActivity 110 6 95% ↓

Target: CRAP < 10 for all production functions


CI/CD Pipeline

GitHub Actions

  • On Push: Run tests, lint, coverage checks
  • On PR: Automated tests + code review gates
  • On Release: Build binaries for macOS/Linux/Windows, publish to registry
# Typical workflow
1. Unit tests (all packages)
2. Go vet & lint checks
3. Integration tests (Temporal required)
4. Coverage validation (>40% threshold)
5. Deploy staging worker (if main branch)

Build & Deploy

# Local build
make build  # Builds cmd/worker and cmd/starter

# Docker build (K8s deployment)
docker build -t your-registry/poimen-worker:latest .

# Deploy to K8s
kubectl apply -f k8s/worker-deployment.yaml

Architecture Decisions

Why Temporal?

  • Durable Execution: Survives crashes, network splits, process restarts
  • Visibility: Full workflow history in UI + API
  • Failure Handling: Built-in retry, timeout, compensation logic
  • Scalability: Millions of concurrent workflows

Why LLM Router?

  • Intent Understanding: Captures user intent without rigid form parsing
  • Adaptive Workflows: LLM optimizes step ordering based on knowledge base
  • Extensibility: New activities auto-discovered; no hardcoding
  • Memory Augmentation: Context-aware decisions via semantic search

Why Generic State Machine?

  • Composability: Any activity becomes a workflow step
  • Reusability: One state machine handles all workflow patterns
  • Testability: Validates JSON specs independently of execution
  • Debuggability: JSONPath-based tracing for data flow

Plugin Architecture Benefits

  • Provider Swapping: Switch LLM backends without code changes
  • Strategy Injection: Multiple spec builders, validators in pipeline
  • Decorator Pattern: Caching, retries, logging as independent layers
  • Backward Compatibility: NewLLMRouterDefault() maintains old API

Documentation


Contributing

Adding a New Activity

  1. Implement Activity interface in action/
  2. Add spec to internal/routing/activity_knowledge_base.json
  3. Register in cmd/worker/main.go
  4. Test with CLI: ./starter --route "..."

Extending the Router

  1. Implement LLMProvider, SpecBuilder, or WorkflowValidator interface
  2. Register in LLMRouterConfig
  3. Add unit tests in internal/routing/*_test.go
  4. Update docs

Code Style

  • Run gofmt and go vet before commit
  • Write tests for all exported functions
  • Keep CRAP score < 10
  • Document non-obvious logic

Troubleshooting

"Activity not registered"

  • Ensure cmd/worker is running
  • Check activity_knowledge_base.json includes activity name
  • Verify activity name in workflow spec matches registration

"Workflow failed to execute"

  • Check Temporal logs: temporal workflow show -w <workflow-id>
  • Review activity output in Temporal UI (:8081)
  • Enable debug logging: LOG_LEVEL=debug

"LLM router timeout"

  • Increase LLMRequestTimeout in config
  • Check API endpoint reachability: curl https://api.riotpiao.com/v1/chat/completions
  • Review LLM prompt length (may be too complex)

"Memory service not responding"

  • Verify MEMORY_SERVICE_URL endpoint
  • Check K8s pod: kubectl logs -l app=poimen-memory
  • Graceful fallback: RetrieveMemoryActivity is optional

Roadmap

  • Real Cron Scheduling — Implement Temporal ScheduleClient for recurring workflows
  • Additional LLM Providers — OpenAI, Claude, local model integrations
  • Provider Auto-Discovery — Config-driven provider registration
  • Improved Coverage — Target 60%+ in all packages
  • Web Dashboard — Real-time workflow execution dashboard
  • Approval Workflows — Multi-stage human approval gates

License

[Your License Here]

Support

  • Issues: GitHub Issues
  • Discussions: GitHub Discussions
  • Security: See SECURITY.md

Built with ❤️ using Temporal, Go, and LLMs.