# Poimen Routing Workflow Specification **Status**: Complete Standard **Version**: 1.0 **Architecture**: User Message → LLM-Router → JSON WorkflowSpec → RoutingWorkflow --- ## OVERVIEW ### The Flow ``` User Message: "Analyze this GitHub repo for security and quality" ↓ [llm-router Activity] ← LLM-powered intelligent agent Reads: ActivityKnowledgeBase.json ↓ Uses LLM to understand intent: - What is user asking for? - Which activities are needed? - What order? - What timeout for each? - What retry strategy? ↓ Generates JSON WorkflowSpec { "name": "repo-analysis", "input": {"repo": "https://...", "branch": "main"}, "states": [ { "name": "Clone", "type": "Task", "resource": "CloneRepoActivity", "parameters": {"repo": "${input.repo}"}, "timeout": "5m", ← LLM decided "retry": {...}, ← LLM decided "next": "Analyze" }, {...more states...} ] } ↓ [RoutingWorkflow] ← Generic executor Takes the JSON spec from llm-router Executes states in order Respects timeout/retry ↓ Final Results ``` ### Key Insight **Intelligence is distributed**: - **ActivityKnowledgeBase.json**: What activities exist, their constraints, capabilities - **llm-router Activity**: Uses LLM to reason about user intent + pick activities + decide settings - **RoutingWorkflow**: Dumb executor that just runs what the LLM decided --- ## PART 1: ACTIVITY KNOWLEDGE BASE ### What is it? Metadata about all available activities. The llm-router reads this to make intelligent decisions. ### File Location ``` internal/routing/activity_knowledge_base.json ``` ### Example Format ```json { "activities": [ { "name": "CloneRepoActivity", "description": "Clone a Git repository to local filesystem", "category": "source-control", "inputs": { "repo": { "type": "string", "description": "Repository URL (https://...)", "required": true }, "branch": { "type": "string", "description": "Branch name to clone", "required": false, "default": "main" } }, "outputs": { "path": { "type": "string", "description": "Local filesystem path to cloned repo" }, "commit": { "type": "string", "description": "Current commit hash" } }, "constraints": { "defaultTimeout": "5m", "isFlaky": false, "recommendedRetries": 2, "retryBackoff": 1.5, "dependencies": [], "notes": "Fast operation, rarely fails" } }, { "name": "AnalyzeCodeActivity", "description": "Analyze code for quality issues, complexity, patterns", "category": "analysis", "inputs": { "path": { "type": "string", "description": "Path to code directory", "required": true }, "language": { "type": "string", "description": "Programming language (go, python, js, etc)", "required": false, "default": "auto-detect" } }, "outputs": { "quality": { "type": "number", "description": "Quality score 0-1" }, "issues": { "type": "array", "description": "List of issues found" }, "complexity": { "type": "number", "description": "Cyclomatic complexity" } }, "constraints": { "defaultTimeout": "10m", "isFlaky": true, "recommendedRetries": 3, "retryBackoff": 2.0, "dependencies": ["CloneRepoActivity"], "notes": "Can timeout on large codebases, retry recommended" } }, { "name": "SecurityScanActivity", "description": "Scan code for vulnerabilities and security issues", "category": "security", "inputs": { "path": { "type": "string", "description": "Path to scan", "required": true } }, "outputs": { "vulnerabilities": { "type": "array", "description": "List of vulnerabilities found" }, "score": { "type": "number", "description": "Security score 0-1" } }, "constraints": { "defaultTimeout": "15m", "isFlaky": false, "recommendedRetries": 2, "retryBackoff": 1.5, "dependencies": ["CloneRepoActivity"], "notes": "Longer runtime, can be parallelized with other scans" } }, { "name": "PerformanceAnalysisActivity", "description": "Analyze runtime performance, bottlenecks, optimization opportunities", "category": "analysis", "inputs": { "path": { "type": "string", "description": "Path to code", "required": true } }, "outputs": { "performance": { "type": "number", "description": "Performance score 0-1" }, "bottlenecks": { "type": "array", "description": "Performance bottlenecks" } }, "constraints": { "defaultTimeout": "10m", "isFlaky": true, "recommendedRetries": 2, "retryBackoff": 2.0, "dependencies": ["CloneRepoActivity"], "notes": "Can timeout on complex analysis" } }, { "name": "JudgeActivity", "description": "Make final judgment/recommendation based on analysis results", "category": "judgment", "inputs": { "quality": { "type": "object", "description": "Code quality analysis result", "required": true }, "security": { "type": "object", "description": "Security scan result", "required": false }, "performance": { "type": "object", "description": "Performance analysis result", "required": false } }, "outputs": { "verdict": { "type": "string", "description": "approved, needs-changes, rejected" }, "score": { "type": "number", "description": "Overall score" }, "recommendations": { "type": "array", "description": "Recommendations for improvement" } }, "constraints": { "defaultTimeout": "5m", "isFlaky": false, "recommendedRetries": 1, "retryBackoff": 1.0, "dependencies": ["AnalyzeCodeActivity"], "notes": "Fast operation, only runs after analysis" } }, { "name": "CombineResultsActivity", "description": "Combine multiple analysis results into final report", "category": "aggregation", "inputs": { "results": { "type": "array", "description": "Array of previous step results", "required": true } }, "outputs": { "report": { "type": "object", "description": "Final combined report" } }, "constraints": { "defaultTimeout": "2m", "isFlaky": false, "recommendedRetries": 1, "retryBackoff": 1.0, "dependencies": [], "notes": "Fast, runs at the end" } }, { "name": "SendNotificationActivity", "description": "Send notification with results to user", "category": "notification", "inputs": { "result": { "type": "object", "description": "Results to send", "required": true }, "channel": { "type": "string", "description": "Where to send (email, slack, etc)", "required": false, "default": "email" } }, "outputs": { "sent": { "type": "boolean", "description": "Was notification sent?" } }, "constraints": { "defaultTimeout": "2m", "isFlaky": true, "recommendedRetries": 3, "retryBackoff": 2.0, "dependencies": [], "notes": "External dependency, retry recommended" } } ] } ``` ### Knowledge Base Fields Explained | Field | Purpose | Used By | |-------|---------|---------| | **name** | Unique activity identifier | llm-router for routing | | **description** | What the activity does | llm-router for reasoning | | **category** | Type of activity (analysis, security, etc) | llm-router for grouping | | **inputs** | What the activity accepts | llm-router to chain activities | | **outputs** | What the activity produces | llm-router to connect outputs to next activity inputs | | **constraints.defaultTimeout** | Recommended timeout | llm-router to decide timeout | | **constraints.isFlaky** | Does it fail often? | llm-router to decide retry count | | **constraints.recommendedRetries** | How many retries? | llm-router to configure retry | | **constraints.retryBackoff** | Backoff multiplier | llm-router to configure exponential backoff | | **constraints.dependencies** | Must run after X | llm-router to order activities | | **constraints.notes** | Special handling notes | llm-router for reasoning | --- ## PART 2: LLM-ROUTER ACTIVITY ### What is it? An Activity that uses an LLM to intelligently decide: 1. Which activities are needed 2. What order to execute them 3. What timeout for each activity 4. What retry policy for each activity 5. How to chain parameters (JSONPath) ### Input to llm-router ```json { "message": "Analyze this GitHub repo for security and code quality", "repo": "https://github.com/rockliang/poimen", "branch": "main" } ``` ### Output from llm-router ```json { "name": "repo-analysis-workflow", "input": { "repo": "https://github.com/rockliang/poimen", "branch": "main" }, "states": [ { "name": "Clone", "type": "Task", "resource": "CloneRepoActivity", "parameters": { "repo": "${input.repo}", "branch": "${input.branch}" }, "timeout": "5m", "retry": { "maxAttempts": 2, "backoffRate": 1.5, "initialInterval": "1s" }, "next": "Analyze" }, { "name": "Analyze", "type": "Task", "resource": "AnalyzeCodeActivity", "parameters": { "path": "${Clone.output.path}" }, "timeout": "10m", "retry": { "maxAttempts": 3, "backoffRate": 2.0, "initialInterval": "1s" }, "catch": [ { "errorEquals": ["Timeout"], "next": "HandleTimeout" } ], "next": "SecurityScan" }, { "name": "SecurityScan", "type": "Task", "resource": "SecurityScanActivity", "parameters": { "path": "${Clone.output.path}" }, "timeout": "15m", "retry": { "maxAttempts": 2, "backoffRate": 1.5, "initialInterval": "1s" }, "next": "Combine" }, { "name": "Combine", "type": "Task", "resource": "CombineResultsActivity", "parameters": { "results": [ "${Analyze.output}", "${SecurityScan.output}" ] }, "timeout": "2m", "retry": { "maxAttempts": 1, "backoffRate": 1.0, "initialInterval": "1s" }, "next": "SendResults" }, { "name": "SendResults", "type": "Task", "resource": "SendNotificationActivity", "parameters": { "result": "${Combine.output.report}", "channel": "email" }, "timeout": "2m", "retry": { "maxAttempts": 3, "backoffRate": 2.0, "initialInterval": "1s" }, "end": true }, { "name": "HandleTimeout", "type": "Fail", "error": "AnalysisTimeout", "cause": "Code analysis timed out after 10 minutes" } ] } ``` ### LLM-Router Logic (Pseudo-code) ```python def llm_router_activity(message: str, repo: str, branch: str) -> WorkflowSpec: # 1. Load knowledge base knowledge_base = load_activity_knowledge_base() # 2. Use LLM to understand intent intent = llm.analyze_intent(message) # intent = { # "needs_security_scan": true, # "needs_code_analysis": true, # "needs_performance_analysis": false, # "needs_final_judgment": true, # } # 3. Select activities based on intent selected_activities = [] if intent.needs_security_scan: selected_activities.append(knowledge_base["SecurityScanActivity"]) if intent.needs_code_analysis: selected_activities.append(knowledge_base["AnalyzeCodeActivity"]) if intent.needs_performance_analysis: selected_activities.append(knowledge_base["PerformanceAnalysisActivity"]) # 4. Order activities by dependencies ordered = topological_sort_by_dependencies(selected_activities) # 5. Build workflow states with intelligent settings states = [] # Always start with Clone clone_state = { "name": "Clone", "type": "Task", "resource": "CloneRepoActivity", "parameters": { "repo": "${input.repo}", "branch": "${input.branch}" }, "timeout": "5m", # From knowledge base "retry": { "maxAttempts": 2, "backoffRate": 1.5, "initialInterval": "1s" }, "next": ordered[0]["name"] } states.append(clone_state) # Add selected activities in order for i, activity in enumerate(ordered): state = { "name": activity["name"].replace("Activity", ""), "type": "Task", "resource": activity["name"], "parameters": { # Use LLM to map inputs # For each input, decide: use output from previous step? use input param? use constant? }, "timeout": activity["constraints"]["defaultTimeout"], "retry": { "maxAttempts": activity["constraints"]["recommendedRetries"], "backoffRate": activity["constraints"]["retryBackoff"], "initialInterval": "1s" }, "next": ordered[i+1]["name"] if i+1 < len(ordered) else "SendResults" } # Add error handling if flaky if activity["constraints"]["isFlaky"]: state["catch"] = [ { "errorEquals": ["Timeout"], "next": "HandleTimeout" } ] states.append(state) # Add final notification states.append({ "name": "SendResults", "type": "Task", "resource": "SendNotificationActivity", "parameters": { "result": "${" + ordered[-1]["name"].replace("Activity", "") + ".output}", "channel": "email" }, "timeout": "2m", "retry": {"maxAttempts": 3, "backoffRate": 2.0, "initialInterval": "1s"}, "end": true }) # Add error handler states.append({ "name": "HandleTimeout", "type": "Fail", "error": "AnalysisTimeout", "cause": "Activity timed out" }) # 6. Return complete workflow spec return WorkflowSpec( name="generated-workflow", input={"repo": repo, "branch": branch}, states=states ) ``` ### Go Implementation Skeleton ```go // cmd/worker/activities/llm_router.go type LLMRouterInput struct { Message string Repo string Branch string } func LLMRouterActivity(ctx context.Context, input LLMRouterInput) (routing.WorkflowSpec, error) { // 1. Load activity knowledge base kb, err := LoadActivityKnowledgeBase() if err != nil { return routing.WorkflowSpec{}, err } // 2. Use LLM to understand intent // Call memory service to get LLM analysis intent, err := llm.AnalyzeIntent(ctx, input.Message, kb) if err != nil { return routing.WorkflowSpec{}, err } // 3. Build workflow spec intelligently spec := buildWorkflowSpec(intent, input, kb) return spec, nil } func buildWorkflowSpec(intent Intent, input LLMRouterInput, kb ActivityKnowledgeBase) routing.WorkflowSpec { // Create workflow with intelligent settings from knowledge base // ... } ``` --- ## PART 3: ROUTING WORKFLOW (The Executor) ### What is it? A generic Temporal workflow that executes ANY WorkflowSpec generated by llm-router. ### Input ```go type RoutingWorkflowInput struct { WorkflowSpec routing.WorkflowSpec // Generated by llm-router } ``` ### Implementation ```go func RoutingWorkflow(ctx workflow.Context, spec routing.WorkflowSpec) (Result, error) { logger := workflow.GetLogger(ctx) // Initialize context ec := &ExecutionContext{ Input: spec.Input, StepResults: make(map[string]interface{}), } // Find first state currentStateName := FindFirstState(spec.States) // State machine loop for { logger.Info("Executing state", "state", currentStateName) state := FindStateByName(spec.States, currentStateName) if state == nil { return Result{}, fmt.Errorf("state not found: %s", currentStateName) } // Execute state (Task, Pass, Fail, etc) result, err := ExecuteState(ctx, state, ec) // Error handling if err != nil { for _, catchClause := range state.Catch { if MatchesError(err, catchClause.ErrorEquals) { logger.Info("Error caught", "handler", catchClause.Next) currentStateName = catchClause.Next break } } return Result{}, fmt.Errorf("state %s failed: %w", currentStateName, err) } // Store result ec.StepResults[state.Name] = result // Check if done if state.End { logger.Info("Workflow completed") return Result{ FinalOutput: result, Status: "COMPLETED", }, nil } // Move to next currentStateName = state.Next } } ``` --- ## PART 4: WORKFLOW SPEC FORMAT ### State Types The llm-router generates states with these types: #### Task (Execute Activity) ```json { "name": "Clone", "type": "Task", "resource": "CloneRepoActivity", "parameters": { "repo": "${input.repo}", "branch": "${input.branch:main}" }, "timeout": "5m", "retry": { "maxAttempts": 3, "backoffRate": 2.0, "initialInterval": "1s" }, "catch": [ { "errorEquals": ["Timeout", "NetworkError"], "next": "HandleError" } ], "next": "Analyze" } ``` **LLM decides**: - Which activity to use - How to chain parameters (${Clone.output.path}) - Timeout (from knowledge base + LLM reasoning) - Retry policy (from knowledge base + isFlaky flag) - Error handling (catch blocks for flaky activities) #### Pass (Static Output) ```json { "name": "CombineResults", "type": "Pass", "result": { "status": "success", "report": "Analysis complete" }, "next": "SendResults" } ``` #### Fail (Terminate) ```json { "name": "HandleError", "type": "Fail", "error": "AnalysisFailed", "cause": "Security scan timed out" } ``` --- ## PART 5: EXECUTION FLOW EXAMPLE ### User Request ``` "Analyze the GitHub repo rockliang/poimen for security vulnerabilities and code quality" ``` ### Step 1: llm-router Activity ``` Input: {message: "...", repo: "https://github.com/rockliang/poimen", branch: "main"} LLM Analysis: - User wants: security analysis + code quality - Sequence: Clone → Analyze (quality) → SecurityScan → CombineResults → Notify - Timeouts: Use defaults from knowledge base - Clone: 5m (not flaky) - Analyze: 10m (flaky, so 3 retries) - SecurityScan: 15m (not flaky, so 2 retries) - Combine: 2m (not flaky, 1 retry) - Error handling: Add catch blocks for flaky activities (Analyze) Output: WorkflowSpec (as JSON above) ``` ### Step 2: RoutingWorkflow Executes ``` State 1: Clone Execute: CloneRepoActivity({repo: "https://...", branch: "main"}) Timeout: 5m (from llm decision) Result: {path: "/tmp/cloned-repo"} ↓ State 2: Analyze Execute: AnalyzeCodeActivity({path: "/tmp/cloned-repo"}) Timeout: 10m Retry: 3 attempts (from llm decision, isFlaky=true) Attempt 1: TIMEOUT → Wait 1s Attempt 2: TIMEOUT → Wait 2s Attempt 3: SUCCESS → {quality: 0.85, issues: [...]} ↓ State 3: SecurityScan Execute: SecurityScanActivity({path: "/tmp/cloned-repo"}) Timeout: 15m Retry: 2 attempts (from llm decision, isFlaky=false) Result: {vulnerabilities: [], score: 0.95} ↓ State 4: CombineResults Execute: CombineResultsActivity({results: [...]}) Result: {report: {...}} ↓ State 5: SendResults Execute: SendNotificationActivity({result: {...}, channel: "email"}) Result: {sent: true} ↓ ✅ WORKFLOW COMPLETED ``` --- ## PART 6: GO TYPE DEFINITIONS ```go package routing import "time" // WorkflowSpec is generated by llm-router (one-time execution) type WorkflowSpec struct { Name string `json:"name"` Input map[string]interface{} `json:"input"` States []State `json:"states"` } // CronWorkflowSpec is generated by llm-router (scheduled execution) type CronWorkflowSpec struct { Name string `json:"name"` Type string `json:"type"` // "CronWorkflow" Schedule string `json:"schedule"` // Cron expression (e.g., "0 2 * * *") Timezone string `json:"timezone"` // "UTC", "America/New_York", etc Input map[string]interface{} `json:"input"` // Fixed input for each run States []State `json:"states"` // Workflow states MaxConcurrent int `json:"maxConcurrent,omitempty"` // Max parallel runs (default 1) Timeout string `json:"timeout,omitempty"` // Overall timeout per run EnableHistory bool `json:"enableHistory,omitempty"` // Keep execution history } // State is a step in the workflow type State struct { Name string Type StateType // "Task", "Pass", "Fail" // Task fields Resource string Parameters map[string]interface{} Timeout string Retry *RetryPolicy Catch []CatchClause // Pass fields Result interface{} // Fail fields Error string Cause string // Transition Next string End bool } type StateType string const ( StateTypeTask StateType = "Task" StateTypePass StateType = "Pass" StateTypeFail StateType = "Fail" ) // RetryPolicy (LLM decides this from knowledge base) type RetryPolicy struct { MaxAttempts int32 `json:"maxAttempts"` BackoffRate float64 `json:"backoffRate"` InitialInterval string `json:"initialInterval"` MaxInterval string `json:"maxInterval,omitempty"` } // CatchClause for error handling type CatchClause struct { ErrorEquals []string `json:"errorEquals"` Next string `json:"next"` } // ExecutionContext tracks state type ExecutionContext struct { Input map[string]interface{} StepResults map[string]interface{} } // Result is final output type Result struct { FinalOutput interface{} Status string Error error } ``` --- ## PART 7: CRON JOB SCHEDULING ### What is it? llm-router can generate workflows that execute **on a schedule** (cron jobs), not just one-time. ### Example: Daily Security Scan User: "Scan all repositories for security vulnerabilities every day at 2 AM" llm-router generates: ```json { "name": "daily-security-scan", "type": "CronWorkflow", "schedule": "0 2 * * *", "timezone": "UTC", "input": { "repos": [ "https://github.com/rockliang/poimen", "https://github.com/rockliang/workflow-engine" ] }, "states": [ { "name": "Clone", "type": "Task", "resource": "CloneRepoActivity", "parameters": { "repo": "${input.repos[0]}" }, "timeout": "5m", "retry": {"maxAttempts": 2, "backoffRate": 1.5, "initialInterval": "1s"}, "next": "SecurityScan" }, { "name": "SecurityScan", "type": "Task", "resource": "SecurityScanActivity", "parameters": {"path": "${Clone.output.path}"}, "timeout": "15m", "retry": {"maxAttempts": 2, "backoffRate": 1.5, "initialInterval": "1s"}, "next": "SendAlert" }, { "name": "SendAlert", "type": "Task", "resource": "SendNotificationActivity", "parameters": { "result": "${SecurityScan.output}", "channel": "slack" }, "timeout": "2m", "retry": {"maxAttempts": 3, "backoffRate": 2.0, "initialInterval": "1s"}, "end": true } ] } ``` ### Cron Format Standard Unix cron syntax: ``` ┌───────────── minute (0 - 59) │ ┌───────────── hour (0 - 23) │ │ ┌───────────── day of month (1 - 31) │ │ │ ┌───────────── month (1 - 12) │ │ │ │ ┌───────────── day of week (0 - 6, 0 = Sunday) │ │ │ │ │ │ │ │ │ │ * * * * * Examples: 0 2 * * * = Every day at 2:00 AM 0 */6 * * * = Every 6 hours 0 9 * * 1-5 = Weekdays at 9 AM 0 0 1 * * = First day of month at midnight 30 2 * * 0 = Every Sunday at 2:30 AM */15 * * * * = Every 15 minutes 0 12 * * * = Every day at noon ``` ### Cron Workflow Fields ```go type CronWorkflowSpec struct { Name string `json:"name"` Type string `json:"type"` // "CronWorkflow" Schedule string `json:"schedule"` // Cron expression Timezone string `json:"timezone"` // "UTC", "America/New_York", etc Input map[string]interface{} `json:"input"` // Fixed input for each run States []State `json:"states"` // Same as regular workflow // Optional MaxConcurrent int `json:"maxConcurrent,omitempty"` // Max parallel executions (default 1) Timeout string `json:"timeout,omitempty"` // Overall timeout per run (default 1h) EnableHistory bool `json:"enableHistory,omitempty"` // Keep execution history? } ``` ### Temporal Cron Job Implementation ```go func SubmitCronWorkflow(cronSpec CronWorkflowSpec) error { client, _ := client.Dial(client.ClientOptions{ HostPort: "temporal-frontend.temporal:7233", }) // For cron, we still use RoutingWorkflow // But Temporal handles the scheduling _, err := client.ExecuteWorkflow( context.Background(), client.StartWorkflowOptions{ ID: cronSpec.Name, TaskQueue: "poimen-taskqueue", CronSchedule: cronSpec.Schedule, // ← Temporal cron support }, RoutingWorkflow, cronSpec.States, ) return err } ``` ### Example Use Cases ``` 1. Daily Security Scan (0 2 * * *) Input: {repos: [...]} Runs: Every day at 2 AM ↓ Clone all repos → Security scan → Send alert 2. Hourly Code Quality Check (0 * * * *) Input: {repo: "https://github.com/rockliang/poimen"} Runs: Every hour ↓ Clone → Analyze → Judge → Log results 3. Weekly Performance Benchmark (0 3 * * 0) Input: {repos: [...], benchmark: true} Runs: Every Sunday at 3 AM ↓ Clone → Performance test → Compare with baseline → Report 4. Every 15 minutes Health Check (*/15 * * * *) Input: {service: "api"} Runs: Every 15 minutes ↓ Check service health → Send metrics → Alert if down ``` ### llm-router for Cron Jobs User: "Run daily security scan at 2 AM UTC on all our repositories" llm-router decision: ```python def llm_router_activity(message: str) -> WorkflowSpec: intent = llm.analyze_intent(message) # intent = { # "is_scheduled": True, # "schedule": "0 2 * * *", # LLM extracts from "2 AM" # "timezone": "UTC", # "needs_security_scan": True, # "target": "all repositories" # } if intent.is_scheduled: return CronWorkflowSpec( name="daily-security-scan", type="CronWorkflow", schedule=intent.schedule, # "0 2 * * *" timezone=intent.timezone, # "UTC" input={"repos": get_all_repos()}, states=[ # Same states as one-time workflow ] ) else: return OneTimeWorkflowSpec(...) ``` ### Execution History When `enableHistory=true`, Temporal tracks all cron executions: ``` Cron Workflow ID: daily-security-scan Execution 1: 2025-02-01 02:00:00 UTC → COMPLETED Execution 2: 2025-02-02 02:00:00 UTC → COMPLETED Execution 3: 2025-02-03 02:00:00 UTC → FAILED (timeout) Execution 4: 2025-02-04 02:00:00 UTC → COMPLETED Execution 5: 2025-02-05 02:00:00 UTC → COMPLETED (in progress...) ``` --- ## PART 8: VALIDATION Before RoutingWorkflow executes the spec, validate: ``` ✅ All state names are unique ✅ All state.next references exist ✅ All catch.next references exist ✅ All Task states have resource defined ✅ No circular loops (A→B→C→A) ✅ At least one path leads to end ✅ No dead ends ✅ Timeout format is valid (e.g., "5m") ✅ Retry settings are valid ✅ JSONPath expressions are syntactically valid ``` --- ## SUMMARY ### The Intelligence is in llm-router **llm-router activity**: - ✅ Reads ActivityKnowledgeBase.json - ✅ Uses LLM to understand user intent - ✅ Intelligently selects activities to run - ✅ Orders them by dependencies - ✅ Decides timeout for EACH activity (from knowledge base + LLM reasoning) - ✅ Decides retry policy for EACH activity (flaky? retry 3x : 1x) - ✅ Chains parameters using JSONPath (${Clone.output.path}) - ✅ Adds error handling (catch blocks) - ✅ **Detects scheduled workflows** (cron jobs) and generates CronWorkflowSpec - ✅ Returns complete JSON WorkflowSpec (one-time or recurring) ### The Executor is Generic **RoutingWorkflow**: - ✅ Takes JSON spec from llm-router - ✅ Executes states in order - ✅ Respects timeout/retry - ✅ Handles errors with catch blocks - ✅ Works for both one-time and cron workflows - ✅ Returns results ### Execution Modes | Mode | Triggered By | Execution | Example | |------|---|---|---| | **One-Time** | API call / CLI / Direct | Runs once, returns immediately | Analyze repo, generate report | | **Cron Job** | Schedule | Runs repeatedly on schedule | Daily security scan at 2 AM | | **Blocking** | User waits | Synchronous, returns results | Execute template, get output | | **Async** | User polls | Asynchronous, check status later | Submit workflow, poll status | ### Files Needed ``` 1. internal/routing/activity_knowledge_base.json ↑ Static metadata about activities (timeouts, retry, flaky, etc) 2. cmd/worker/activities/llm_router.go ↑ LLM-powered activity that generates WorkflowSpec or CronWorkflowSpec 3. statemachine/routing_workflow.go ↑ Generic executor for any spec (one-time or cron) 4. internal/routing/validator.go ↑ Validate specs before execution ↑ Validate cron expressions 5. cmd/api-server/cron_handlers.go (optional) ↑ Endpoints to manage cron workflows ↑ GET /api/v1/cron/{id}/status ↑ DELETE /api/v1/cron/{id} (cancel) ``` This is the **correct, complete architecture**! 🎯 ### Quick Feature Checklist - ✅ **One-time workflows** (API/CLI submit) - ✅ **Scheduled workflows** (Cron jobs with schedule) - ✅ **Intelligent routing** (LLM decides what to run) - ✅ **Smart timeouts** (From activity knowledge base) - ✅ **Smart retries** (Based on isFlaky flag) - ✅ **Error handling** (Catch blocks for flaky activities) - ✅ **Parameter chaining** (JSONPath resolution) - ✅ **Execution history** (For cron jobs) - ✅ **Temporal durability** (Automatic replay)