Unlike unpredictable agent-based systems, Kubiya workflows are deterministic by design. Same input → Same execution path → Same output, every time.

The Problem with Non-Deterministic Systems

Traditional Agent Systems

Problems:

  • 🎲 Different execution paths each time
  • 🐛 Impossible to debug failures
  • 📈 Errors compound through the chain
  • ⏱️ Unpredictable execution time
  • 🔍 No clear audit trail

Kubiya’s Deterministic Approach

Benefits:

  • ✅ Same execution path every time
  • ✅ Clear debugging with step-by-step logs
  • ✅ Isolated failures don’t cascade
  • ✅ Predictable performance
  • ✅ Complete audit trail

What Makes Kubiya Deterministic?

1. DAG-Based Execution

Workflows are Directed Acyclic Graphs (DAGs):

workflow = (
    Workflow("deploy-app")
    .step("validate", "validate.sh")
    .step("build", "docker build -t app:latest .", depends_on=["validate"])
    .step("test", "pytest tests/", depends_on=["build"])
    .step("deploy", "kubectl apply -f k8s/", depends_on=["test"])
)

Why DAGs?

  • No circular dependencies
  • Clear execution order
  • Parallelizable where possible
  • Stateless between runs

2. Isolated Step Execution

Each step runs in an isolated container:

# Step execution
apiVersion: batch/v1
kind: Job
metadata:
  name: workflow-${id}-step-${name}
spec:
  template:
    spec:
      containers:
      - name: step
        image: ${step.image}
        command: ${step.command}
        env: ${step.env}
      restartPolicy: Never

Isolation Benefits:

  • No side effects between steps
  • Clean environment each time
  • Resource limits enforced
  • Security boundaries maintained

3. Immutable Workflow Definitions

Once defined, workflows don’t change during execution:

# Workflow is compiled to immutable JSON
{
    "name": "deploy-app",
    "version": "1.0.0",
    "steps": [
        {
            "name": "validate",
            "command": "validate.sh",
            "hash": "abc123..."  # Content-addressed
        }
    ]
}

4. Explicit Dependencies

Dependencies are declared, not discovered:

# Clear dependency graph
.step("fetch-data", "wget data.csv")
.step("process", "python process.py", depends_on=["fetch-data"])
.step("upload", "aws s3 cp output.csv s3://bucket/", depends_on=["process"])

Comparison with Other Systems

FeatureKubiyaLangChain/AgentsTraditional CI/CDStep Functions
Deterministic✅ Always❌ Varies✅ Yes✅ Yes
Debuggable✅ Step-by-step❌ Black box⚠️ Limited⚠️ Limited
Scalable✅ K8s native❌ Single process⚠️ Runner limits✅ AWS only
Portable✅ Any K8s❌ Python only❌ Platform specific❌ AWS only
AI Integration✅ Optional✅ Core❌ None❌ None

Determinism in Practice

Example: Database Backup Workflow

backup_workflow = (
    Workflow("db-backup")
    # Always executes in this order
    .step("check-space", "df -h /backup")
    .step("dump-db", "pg_dump -Fc mydb > backup.sql", depends_on=["check-space"])
    .step("compress", "gzip backup.sql", depends_on=["dump-db"])
    .step("upload", "aws s3 cp backup.sql.gz s3://backups/", depends_on=["compress"])
    .step("verify", "aws s3 ls s3://backups/backup.sql.gz", depends_on=["upload"])
    .step("cleanup", "rm backup.sql.gz", depends_on=["verify"])
)

Guarantees:

  1. Space is always checked first
  2. Database is only dumped if space available
  3. Upload only happens after successful compression
  4. Cleanup only after verification
  5. Same execution order every time

Handling Non-Deterministic Operations

Even with external services, maintain determinism:

# Deterministic retry logic
.step("api-call", 
    command="curl https://api.example.com/data",
    retry=RetryPolicy(
        max_attempts=3,
        backoff="exponential",
        max_delay=60
    )
)

AI Integration Without Chaos

When using AI providers, the workflow structure remains deterministic:

# AI generates the workflow, but execution is deterministic
adk = get_provider("adk")
workflow = adk.generate_workflow("backup databases")

# The generated workflow is a fixed DAG
print(workflow)
# {
#   "name": "backup-databases",
#   "steps": [
#     {"name": "check-disk", "command": "df -h"},
#     {"name": "dump-postgres", "command": "pg_dump..."},
#     ...
#   ]
# }

# Execution is 100% predictable
client.execute_workflow(workflow)

Benefits for Production

1. Reliable Deployments

deploy_workflow = (
    Workflow("production-deploy")
    .step("run-tests", "pytest")
    .step("build", "docker build", depends_on=["run-tests"])
    .step("push", "docker push", depends_on=["build"])
    .step("deploy", "kubectl rollout", depends_on=["push"])
    .step("verify", "curl health-check", depends_on=["deploy"])
)

# This ALWAYS follows the same path
# No surprises in production

2. Debugging Failures

# When something fails, you know exactly where
$ kubiya logs workflow-123

Step: run-tests [SUCCESS] 2.3s
Step: build [SUCCESS] 45.2s
Step: push [FAILED] 12.1s
  Error: Registry timeout
  Retry 1/3...

3. Compliance and Auditing

// Complete execution history
{
  "workflow": "financial-report",
  "execution_id": "exec-789",
  "steps": [
    {
      "name": "fetch-transactions",
      "started": "2024-01-15T10:00:00Z",
      "completed": "2024-01-15T10:00:45Z",
      "status": "success",
      "output_hash": "sha256:abc..."
    }
  ]
}

Best Practices for Deterministic Workflows

The Bottom Line

Predictable

Same workflow, same execution, every time

Debuggable

Clear visibility into every step

Auditable

Complete execution history

Scalable

Determinism enables parallelization

What’s Next?