This skill should be used when the user asks about "workflow versioning", "GetVersion", "workflow migration", "update running workflow", "workflow reset", "deploy workflow changes", "backward compatible workflow", or needs guidance on safely updating Temporal workflows.
From timelordnpx claudepluginhub therealbill/mynet --plugin timelordThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Guidance for safely updating workflows while maintaining compatibility with running executions.
Temporal replays workflow history to reconstruct state. If workflow code changes, replay may fail with non-determinism errors. Versioning ensures:
The primary tool for workflow versioning.
func MyWorkflow(ctx workflow.Context, input Input) error {
// Introduce a version branch
v := workflow.GetVersion(ctx, "change-id", workflow.DefaultVersion, 1)
if v == workflow.DefaultVersion {
// Original logic (for workflows started before change)
err := oldBehavior(ctx)
} else {
// New logic (v == 1, for new workflows)
err := newBehavior(ctx)
}
return err
}
| Parameter | Description |
|---|---|
ctx | Workflow context |
changeID | Unique identifier for this change point |
minSupported | Minimum version to support (usually DefaultVersion) |
maxSupported | Current version number |
workflow.DefaultVersion (-1): Original code before any versioning1, 2, 3, ...: Incremental version numbersfunc OrderWorkflow(ctx workflow.Context, order Order) error {
// Original activities
err := workflow.ExecuteActivity(ctx, ValidateOrder, order).Get(ctx, nil)
if err != nil {
return err
}
// Version gate for new activity
v := workflow.GetVersion(ctx, "add-fraud-check", workflow.DefaultVersion, 1)
if v >= 1 {
// New: Add fraud check for new workflows
err = workflow.ExecuteActivity(ctx, CheckFraud, order).Get(ctx, nil)
if err != nil {
return err
}
}
// Continue with rest of workflow
err = workflow.ExecuteActivity(ctx, ProcessPayment, order).Get(ctx, nil)
return err
}
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "remove-legacy-check", workflow.DefaultVersion, 1)
if v == workflow.DefaultVersion {
// Old: Keep legacy activity for existing workflows
workflow.ExecuteActivity(ctx, LegacyCheck, order).Get(ctx, nil)
}
// New workflows (v >= 1) skip the legacy check
// Continue with workflow
return workflow.ExecuteActivity(ctx, ProcessOrder, order).Get(ctx, nil)
}
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "new-shipping-params", workflow.DefaultVersion, 1)
var shippingResult ShippingResult
if v == workflow.DefaultVersion {
// Old parameter format
err := workflow.ExecuteActivity(ctx, ShipOrder, order.ID).Get(ctx, &shippingResult)
} else {
// New parameter format with more data
input := ShippingInput{
OrderID: order.ID,
Priority: order.Priority,
Address: order.ShippingAddress,
}
err := workflow.ExecuteActivity(ctx, ShipOrderV2, input).Get(ctx, &shippingResult)
}
return err
}
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "payment-flow", workflow.DefaultVersion, 2)
switch v {
case workflow.DefaultVersion:
// Original: single payment call
return processPaymentV1(ctx, order)
case 1:
// V1: Added retry logic
return processPaymentV2(ctx, order)
default:
// V2 (current): Added fraud check
return processPaymentV3(ctx, order)
}
}
Day 0: Deploy code with GetVersion
- New workflows: use new logic
- Old workflows: use old logic
Day 1-N: Old workflows complete naturally
Monitor for issues
Day N+1: Once all old workflows done:
- Remove version gates
- Simplify to new logic only
# Watch for non-determinism errors
sum(rate(temporal_workflow_task_execution_failed_total{failure_reason="NonDeterminismError"}[5m]))
# Track workflow completions by version
# (requires custom search attributes)
Alternative to versioning for fixing stuck workflows.
# Reset to specific event
temporal workflow reset \
--workflow-id <id> \
--event-id 10 \
--reason "Reset after bug fix"
# Reset to last workflow task
temporal workflow reset \
--workflow-id <id> \
--type LastWorkflowTask \
--reason "Retry last decision"
# Reset to first workflow task
temporal workflow reset \
--workflow-id <id> \
--type FirstWorkflowTask \
--reason "Start over"
# Batch reset multiple workflows
temporal workflow reset-batch \
--query "WorkflowType='OrderWorkflow' AND ExecutionStatus='Running'" \
--type LastWorkflowTask \
--reason "Batch reset for bug fix"
| Type | Description | Use Case |
|---|---|---|
FirstWorkflowTask | Restart from beginning | Complete redo |
LastWorkflowTask | Redo last decision | Recent bug |
--event-id N | Reset to specific event | Targeted retry |
Use descriptive, unique change IDs:
// GOOD: Descriptive and unique
workflow.GetVersion(ctx, "add-fraud-check-2024-01", ...)
workflow.GetVersion(ctx, "payment-retry-logic", ...)
workflow.GetVersion(ctx, "shipping-v2-params", ...)
// BAD: Generic or reused
workflow.GetVersion(ctx, "change1", ...)
workflow.GetVersion(ctx, "fix", ...)
After all old workflows complete:
// Before cleanup (versioned)
func OrderWorkflow(ctx workflow.Context, order Order) error {
v := workflow.GetVersion(ctx, "add-validation", workflow.DefaultVersion, 1)
if v >= 1 {
validate(ctx, order)
}
return process(ctx, order)
}
// After cleanup (simplified)
func OrderWorkflow(ctx workflow.Context, order Order) error {
validate(ctx, order) // Now always runs
return process(ctx, order)
}
Test both old and new paths:
func TestOrderWorkflow_NewVersion(t *testing.T) {
env := s.NewTestWorkflowEnvironment()
// Test new logic
env.ExecuteWorkflow(OrderWorkflow, testOrder)
// Assert new behavior
}
func TestOrderWorkflow_ReplayOldHistory(t *testing.T) {
replayer := worker.NewWorkflowReplayer()
replayer.RegisterWorkflow(OrderWorkflow)
// Replay with old history
err := replayer.ReplayWorkflowHistoryFromJSONFile(nil, "old_history.json")
require.NoError(t, err)
}
// WRONG: Changing ID breaks replay
// v1 code
workflow.GetVersion(ctx, "my-change", ...)
// v2 code - BROKEN
workflow.GetVersion(ctx, "my-change-v2", ...) // Different ID!
// RIGHT: Keep same ID, increment version
// v1 code
workflow.GetVersion(ctx, "my-change", DefaultVersion, 1)
// v2 code
workflow.GetVersion(ctx, "my-change", DefaultVersion, 2) // Same ID
// WRONG: Lowering version breaks existing workflows
// v1 code
workflow.GetVersion(ctx, "change", DefaultVersion, 2)
// v2 code - BROKEN
workflow.GetVersion(ctx, "change", DefaultVersion, 1) // Lowered!
// RIGHT: Only increase versions
workflow.GetVersion(ctx, "change", DefaultVersion, 3)
For detailed versioning patterns, consult:
references/version-patterns.md - Advanced versioning scenariosreferences/migration-guide.md - Large-scale migration strategies