Agentic AI Atlasby a5c.ai
OverviewWikiGraphFor AgentsEdgesSearchWorkspace
/
GitHubDocsDiscord
iiRecord
Agentic AI Atlas · Process Definitions: JavaScript Workflow Orchestration
page:docs-user-guide-features-process-definitionsa5c.ai
Search record views/
Record · tabs

Available views

II.Record viewspp. 1 - 1
overviewarticlejsongraph
II.
Page JSON

page:docs-user-guide-features-process-definitions

Structured · live

Process Definitions: JavaScript Workflow Orchestration json

Inspect the normalized record payload exactly as the atlas UI reads it.

File · wiki/docs/user-guide/features/process-definitions.mdCluster · wiki
Record JSON
{
  "id": "page:docs-user-guide-features-process-definitions",
  "_kind": "Page",
  "_file": "wiki/docs/user-guide/features/process-definitions.md",
  "_cluster": "wiki",
  "attributes": {
    "nodeKind": "Page",
    "sourcePath": "docs/user-guide/features/process-definitions.md",
    "sourceKind": "repo-docs",
    "title": "Process Definitions: JavaScript Workflow Orchestration",
    "displayName": "Process Definitions: JavaScript Workflow Orchestration",
    "slug": "docs/user-guide/features/process-definitions",
    "articlePath": "wiki/docs/user-guide/features/process-definitions.md",
    "article": "\n# Process Definitions: JavaScript Workflow Orchestration\n\n**Version:** 1.1\n**Last Updated:** 2026-01-26\n**Category:** Feature Guide\n\n---\n\n## In Plain English\n\n**A process is a recipe that tells Babysitter what to do.**\n\nJust like a cooking recipe says \"chop vegetables, then cook them, then serve\" - a process says \"research the codebase, then write tests, then implement, then verify.\"\n\n<!-- process-definitions:lead:start -->\n**You don't need to write processes to use Babysitter.** The [Process Library](./process-library.md) is the SDK-managed library under `library/`, and the current generated snapshot counts 2,239 JavaScript process files in the live repository tree.\n<!-- process-definitions:lead:end -->\n\n**When would you write a process?**\n- You have a specific workflow your team follows\n- The pre-built processes don't match your needs\n- You want to customize how quality gates work\n\n**Tip for beginners:** Start with pre-built processes. Once you're comfortable, come back here to learn how to create your own.\n\n---\n\n## Overview\n\nProcess definitions are JavaScript functions that orchestrate workflows in Babysitter. A process defines what tasks to execute, in what order, and how to handle results. The process function acts as the \"brain\" of your workflow, making decisions and coordinating execution while Babysitter handles state management, persistence, and resumability.\n\n### Why Use Process Definitions\n\n- **Deterministic Execution**: Same inputs and journal produce the same execution path\n- **Full JavaScript Power**: Use loops, conditionals, and async/await for complex logic\n- **Modular Design**: Define reusable tasks and compose them into workflows\n- **Event-Sourced**: All state changes recorded for replay and debugging\n- **Resumable**: Workflows automatically resume from where they left off\n\n---\n\n## Use Cases and Scenarios\n\n### Scenario 1: Simple Build and Test Pipeline\n\nA basic process that builds and tests a project.\n\n```javascript\nimport { defineTask } from '@a5c-ai/babysitter-sdk';\n\nexport async function process(inputs, ctx) {\n  // Build the project\n  const buildResult = await ctx.task(buildTask, { target: inputs.target });\n\n  // Run tests\n  const testResult = await ctx.task(testTask, { suite: 'unit' });\n\n  // Return results\n  return {\n    success: buildResult.success && testResult.success,\n    build: buildResult,\n    tests: testResult\n  };\n}\n\nconst buildTask = defineTask('build', (args, taskCtx) => ({\n  kind: 'node',\n  title: `Build ${args.target}`,\n  node: {\n    entry: 'scripts/build.js',\n    args: ['--target', args.target]\n  },\n  io: {\n    inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,\n    outputJsonPath: `tasks/${taskCtx.effectId}/result.json`\n  }\n}));\n\nconst testTask = defineTask('test', (args, taskCtx) => ({\n  kind: 'node',\n  title: `Run ${args.suite} tests`,\n  node: {\n    entry: 'scripts/test.js',\n    args: ['--suite', args.suite]\n  },\n  io: {\n    inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,\n    outputJsonPath: `tasks/${taskCtx.effectId}/result.json`\n  }\n}));\n```\n\n### Scenario 2: CI Pipeline with Conditional Steps\n\nA more complex pipeline with parallel execution and conditional logic.\n\n```javascript\nexport async function process(inputs, ctx) {\n  // Build first\n  const buildResult = await ctx.task(buildTask, { target: 'app' });\n\n  // Run lint and tests in parallel\n  const [lintResult, testResult] = await ctx.parallel.all([\n    () => ctx.task(lintTask, { files: buildResult.files }),\n    () => ctx.task(testTask, { suite: 'smoke' })\n  ]);\n\n  // Conditional: request approval if issues found\n  if (!lintResult.ok || !testResult.ok) {\n    await ctx.breakpoint({\n      question: 'Lint/tests failed. Continue anyway?',\n      title: 'Quality Gate',\n      context: {\n        runId: ctx.runId,\n        files: [{ path: 'artifacts/quality-report.md', format: 'markdown' }]\n      }\n    });\n  }\n\n  // Agent-based code review\n  const review = await ctx.task(codeReviewAgentTask, { diffRef: buildResult.diffRef });\n\n  return { success: true, review: review.summary };\n}\n```\n\n### Scenario 3: Multi-Phase Feature Development\n\nA comprehensive workflow with research, planning, implementation, and verification phases.\n\n```javascript\nexport async function process(inputs, ctx) {\n  const { feature, targetQuality = 85, maxIterations = 5 } = inputs;\n\n  // Phase 1: Research\n  const research = await ctx.task(researchTask, { feature });\n\n  // Phase 2: Planning\n  const plan = await ctx.task(planningTask, { feature, research });\n\n  // Breakpoint: Approve plan\n  await ctx.breakpoint({\n    question: `Review plan for \"${feature}\". Approve to proceed?`,\n    title: 'Plan Review',\n    context: { runId: ctx.runId, files: [{ path: 'artifacts/plan.md', format: 'markdown' }] }\n  });\n\n  // Phase 3: Implementation with quality convergence\n  let iteration = 0;\n  let quality = 0;\n\n  while (iteration < maxIterations && quality < targetQuality) {\n    iteration++;\n\n    const impl = await ctx.task(implementTask, { feature, plan, iteration });\n    const score = await ctx.task(scoreQualityTask, { impl });\n\n    quality = score.overall;\n    ctx.log(`Iteration ${iteration}: Quality ${quality}/${targetQuality}`);\n  }\n\n  // Phase 4: Final verification\n  await ctx.breakpoint({\n    question: `Quality: ${quality}. Approve for merge?`,\n    title: 'Final Approval'\n  });\n\n  return { success: quality >= targetQuality, iterations: iteration, quality };\n}\n```\n\n---\n\n## Step-by-Step Instructions\n\n### Step 1: Create the Process File\n\nCreate a JavaScript file with an exported `process` function.\n\n**Location:** `.a5c/runs/<runId>/code/main.js` or a custom path\n\n```javascript\n// main.js\nexport async function process(inputs, ctx) {\n  // Your workflow logic here\n  return { success: true };\n}\n```\n\n### Step 2: Define Tasks\n\nTasks are the building blocks of your workflow. Define them using `defineTask`.\n\n```javascript\nimport { defineTask } from '@a5c-ai/babysitter-sdk';\n\nexport const myTask = defineTask('my-task', (args, taskCtx) => ({\n  kind: 'node',\n  title: `Execute ${args.action}`,\n  node: {\n    entry: 'scripts/my-script.js',\n    args: ['--action', args.action]\n  },\n  io: {\n    inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,\n    outputJsonPath: `tasks/${taskCtx.effectId}/result.json`\n  }\n}));\n```\n\n### Step 3: Use the Process Context\n\nThe `ctx` object provides intrinsics for orchestration.\n\n```javascript\nexport async function process(inputs, ctx) {\n  // Execute a task\n  const result = await ctx.task(myTask, { action: 'build' });\n\n  // Request human approval (returns BreakpointResult)\n  const approval = await ctx.breakpoint({ question: 'Approve?' });\n  if (!approval.approved) {\n    return { success: false, reason: approval.feedback };\n  }\n\n  // Sleep until a specific time\n  await ctx.sleepUntil('2026-01-26T09:00:00.000Z');\n\n  // Execute tasks in parallel\n  const [a, b] = await ctx.parallel.all([\n    () => ctx.task(taskA, {}),\n    () => ctx.task(taskB, {})\n  ]);\n\n  // Log to the journal\n  ctx.log('Workflow completed', { result });\n\n  // Get current time (deterministic)\n  const now = ctx.now();\n\n  return { success: true };\n}\n```\n\n### Step 4: Create a Run\n\nUse the CLI to create a run with your process.\n\n```bash\nbabysitter run:create \\\n  --process-id my-workflow \\\n  --entry ./code/main.js#process \\\n  --inputs ./inputs.json \\\n  --run-id \"run-$(date -u +%Y%m%d-%H%M%S)\" \\\n  --prompt \"Run my custom workflow\"\n```\n\n### Step 5: Execute the Run\n\nUse the babysitter skill or CLI to drive execution.\n\n```bash\n# Via skill\nclaude \"/babysitter:call run my-workflow\"\n\n# Via CLI iteration loop\nwhile true; do\n  RESULT=$(babysitter run:iterate \"$RUN_ID\" --json)\n  STATUS=$(echo \"$RESULT\" | jq -r '.status')\n  [ \"$STATUS\" = \"completed\" ] && break\n  [ \"$STATUS\" = \"failed\" ] && exit 1\ndone\n```\n\n---\n\n## Configuration Options\n\n### Process Function Signature\n\n```javascript\nasync function process(inputs, ctx) {\n  // inputs: Object - Initial inputs passed to the run\n  // ctx: ProcessContext - Orchestration intrinsics\n  // returns: any - Final output of the process\n}\n```\n\n### Task Definition Schema\n\n```javascript\ndefineTask<TArgs, TResult>(id: string, impl: TaskImpl<TArgs>): DefinedTask<TArgs, TResult>\n```\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `kind` | string | Yes | Task type: `node`, `shell`, `agent`, `breakpoint` |\n| `title` | string | No | Human-readable title |\n| `description` | string | No | Detailed description |\n| `node.entry` | string | Yes (for node) | Path to Node.js script |\n| `node.args` | string[] | No | Command-line arguments |\n| `node.env` | object | No | Environment variables |\n| `node.cwd` | string | No | Working directory |\n| `node.timeout` | number | No | Timeout in milliseconds |\n| `shell.command` | string | Yes (for shell) | Shell command to execute |\n| `agent.name` | string | Yes (for agent) | Agent name |\n| `agent.prompt` | object | Yes (for agent) | Agent prompt configuration |\n| `io.inputJsonPath` | string | No | Path for input JSON |\n| `io.outputJsonPath` | string | No | Path for output JSON |\n| `labels` | string[] | No | Labels for categorization |\n| `execution.harness` | string | No | Preferred harness CLI for task execution (internal-only) |\n| `execution.model` | string | No | Preferred model for agent tasks |\n| `execution.permissions` | string[] | No | Permission list for task execution (internal-only) |\n\n### Process Context Intrinsics\n\n| Method | Description |\n|--------|-------------|\n| `ctx.task(taskDef, args, options?)` | Execute a task |\n| `ctx.breakpoint(payload)` | Request human approval, returns `BreakpointResult`. Supports routing via `expert`, `tags`, `strategy`, `previousFeedback`, and `attempt` fields. |\n| `ctx.sleepUntil(timestamp)` | Sleep until a specific time |\n| `ctx.parallel.all(thunks)` | Execute tasks in parallel |\n| `ctx.parallel.map(items, fn)` | Map items to parallel tasks |\n| `ctx.log(...args)` | Log to the journal |\n| `ctx.now()` | Get current time (deterministic) |\n| `ctx.runId` | The current run ID |\n\n---\n\n## Code Examples and Best Practices\n\n### Example 1: Node Task Definition\n\n```javascript\nexport const buildTask = defineTask('build', (args, taskCtx) => ({\n  kind: 'node',\n  title: `Build ${args.target}`,\n  description: 'Compile and bundle the application',\n  node: {\n    entry: 'scripts/build.js',\n    args: ['--target', args.target, '--effect-id', taskCtx.effectId],\n    env: { NODE_ENV: 'production' },\n    timeout: 300000  // 5 minutes\n  },\n  io: {\n    inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,\n    outputJsonPath: `tasks/${taskCtx.effectId}/result.json`\n  },\n  labels: ['build', 'production']\n}));\n```\n\n### Example 2: Shell Task Definition\n\n```javascript\nexport const lintTask = defineTask('lint', (args, taskCtx) => ({\n  kind: 'shell',\n  title: 'Run linter',\n  description: 'Check code style and common issues',\n  shell: {\n    command: `npx eslint ${args.files.join(' ')} --format json --output-file tasks/${taskCtx.effectId}/result.json`\n  },\n  labels: ['quality', 'lint']\n}));\n```\n\n### Example 3: Agent Task Definition\n\n```javascript\nexport const codeReviewAgentTask = defineTask('code-review', (args, taskCtx) => ({\n  kind: 'agent',\n  title: 'AI Code Review',\n  description: 'LLM-based code review',\n  agent: {\n    name: 'code-reviewer',\n    prompt: {\n      role: 'senior software engineer',\n      task: 'Review the code changes and provide feedback',\n      context: {\n        diffRef: args.diffRef\n      },\n      instructions: [\n        'Check for bugs and security issues',\n        'Review code quality and style',\n        'Suggest improvements'\n      ],\n      outputFormat: 'JSON with summary, issues, and suggestions'\n    },\n    outputSchema: {\n      type: 'object',\n      required: ['summary', 'issues'],\n      properties: {\n        summary: { type: 'string' },\n        issues: { type: 'array', items: { type: 'object' } },\n        suggestions: { type: 'array', items: { type: 'string' } }\n      }\n    }\n  },\n  execution: {\n    model: 'claude-sonnet-4-20250514',  // Preferred model for this task\n  },\n  io: {\n    inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,\n    outputJsonPath: `tasks/${taskCtx.effectId}/result.json`\n  },\n  labels: ['agent', 'code-review']\n}));\n```\n\n### Execution Hints\n\nTask definitions support optional `execution` hints that influence how the orchestrator runs the task:\n\n| Field | Type | Visibility | Description |\n|-------|------|------------|-------------|\n| `execution.model` | string | Universal | Preferred model for agent tasks (e.g., `'claude-sonnet-4-20250514'`) |\n| `execution.harness` | string | Internal-only | Preferred harness CLI for task execution |\n| `execution.permissions` | string[] | Internal-only | Permission list for the task execution environment |\n\n```javascript\nconst heavyAnalysisTask = defineTask('heavy-analysis', (args, taskCtx) => ({\n  kind: 'agent',\n  title: 'Deep code analysis',\n  agent: { /* ... */ },\n  execution: {\n    model: 'claude-opus-4-20250514',         // Use a more capable model\n    harness: 'claude',                       // Internal: prefer Claude Code harness\n    permissions: ['read', 'write', 'shell'], // Internal: required permissions\n  },\n}));\n```\n\n### Example 4: Error Handling in Processes\n\n```javascript\nexport async function process(inputs, ctx) {\n  try {\n    const result = await ctx.task(riskyTask, { data: inputs.data });\n    return { success: true, result };\n  } catch (error) {\n    // Log the error\n    ctx.log('Task failed', { error: error.message });\n\n    // Request human intervention\n    await ctx.breakpoint({\n      question: `Task failed: ${error.message}. How to proceed?`,\n      title: 'Error Recovery',\n      context: {\n        runId: ctx.runId,\n        files: [{ path: 'artifacts/error-details.json', format: 'code', language: 'json' }]\n      }\n    });\n\n    // Retry with different parameters\n    const retryResult = await ctx.task(riskyTask, { data: inputs.data, retryMode: true });\n    return { success: true, result: retryResult, retried: true };\n  }\n}\n```\n\n### Example 5: Dynamic Task Selection\n\n```javascript\nexport async function process(inputs, ctx) {\n  const { taskType, config } = inputs;\n\n  // Select task based on input\n  let taskDef;\n  switch (taskType) {\n    case 'build':\n      taskDef = buildTask;\n      break;\n    case 'test':\n      taskDef = testTask;\n      break;\n    case 'deploy':\n      taskDef = deployTask;\n      break;\n    default:\n      throw new Error(`Unknown task type: ${taskType}`);\n  }\n\n  const result = await ctx.task(taskDef, config);\n  return result;\n}\n```\n\n### Best Practices\n\n1. **Keep Processes Deterministic**: Avoid random values or non-deterministic operations; use `ctx.now()` for timestamps\n2. **Use Descriptive Task IDs**: Task IDs should clearly indicate what the task does\n3. **Handle Errors Gracefully**: Implement error handling and recovery strategies\n4. **Break Complex Workflows into Phases**: Structure processes with clear phases for readability\n5. **Document Process Purpose**: Add comments explaining the workflow logic\n6. **Use Labels for Categorization**: Tag tasks with labels for filtering and organization\n7. **Separate Task Definitions**: Keep task definitions in separate files for reusability\n\n---\n\n## Common Pitfalls and Troubleshooting\n\n### Pitfall 1: Non-Deterministic Process Code\n\n**Symptom:** Process behaves differently on resume.\n\n**Cause:** Using non-deterministic values.\n\n**Wrong:**\n```javascript\nconst timestamp = Date.now();  // Non-deterministic\nconst id = Math.random().toString(36);  // Non-deterministic\n```\n\n**Correct:**\n```javascript\nconst timestamp = ctx.now().getTime();  // Deterministic\nconst id = `task-${ctx.runId}-${iteration}`;  // Deterministic\n```\n\n### Pitfall 2: Missing Input/Output Paths\n\n**Symptom:** Task results not persisted or not found on resume.\n\n**Cause:** Missing `io` configuration.\n\n**Solution:**\n```javascript\ndefineTask('my-task', (args, taskCtx) => ({\n  kind: 'node',\n  node: { entry: 'scripts/task.js' },\n  io: {\n    inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,   // Add this\n    outputJsonPath: `tasks/${taskCtx.effectId}/result.json`  // Add this\n  }\n}));\n```\n\n### Pitfall 3: Process Code Changed Between Iterations\n\n**Symptom:** Replay produces different results.\n\n**Cause:** Process code modified after run started.\n\n**Solution:**\n- Avoid modifying process code for in-progress runs\n- The SDK stores `processRevision` to detect changes\n- Create a new run if workflow logic needs to change\n\n### Pitfall 4: Task Function Not Exported\n\n**Symptom:** `ReferenceError: task is not defined`\n\n**Cause:** Task function not exported or imported incorrectly.\n\n**Solution:**\n```javascript\n// In tasks.js\nexport const myTask = defineTask('my-task', ...);\n\n// In main.js\nimport { myTask } from './tasks.js';\n\nexport async function process(inputs, ctx) {\n  const result = await ctx.task(myTask, { /* args */ });\n}\n```\n\n### Pitfall 5: Incorrect Entry Point Syntax\n\n**Symptom:** `Error: Cannot find module`\n\n**Cause:** Incorrect entry point format in run:create.\n\n**Correct syntax:**\n```bash\n--entry ./code/main.js#process\n       ^              ^\n       path           export name (after #)\n```\n\n---\n\n## Related Documentation\n\n- [Quality Convergence](./quality-convergence.md) - Implement iterative improvement loops\n- [Parallel Execution](./parallel-execution.md) - Run tasks concurrently\n- [Breakpoints](./breakpoints.md) - Add human approval gates\n- [Journal System](./journal-system.md) - Understand event sourcing\n- [Best Practices](./best-practices.md) - Patterns for process structure, error handling, idempotency, and testing\n- [Process Library](./process-library.md) - SDK-managed built-in library and current counts\n\n---\n\n## Pre-Built Workflows: Methodologies & Processes\n\n**Don't start from scratch!** Babysitter includes thousands of ready-to-use workflows:\n\n### Methodologies (38 directories in this repo snapshot) - Development Approaches\n\nHigh-level approaches you can apply to any project:\n\n- **TDD Quality Convergence** - Test-first with iterative quality improvement\n- **GSD (Get Stuff Done)** - Rapid 8-phase execution workflow\n- **Spec-Kit** - Specification-driven with governance\n- **Domain-Driven Design** - Strategic and tactical DDD patterns\n- And many more under [`library/methodologies/`](../../../library/methodologies/)\n\n**Browse methodologies:**\n- [Methodology overview](../reference/glossary.md#methodology)\n- [Methodologies folder](../../../library/methodologies/)\n\n### Domain Processes - Task-Specific Workflows\n\nComplete process definitions for specific domains:\n\n<!-- process-definitions:domains:start -->\n| Domain | Processes | Browse |\n|--------|-----------|--------|\n| **Development and technical specializations** | 837 | [Browse →](../../../library/specializations/) |\n| **Business domains** | 490 | [Browse →](../../../library/specializations/domains/business/) |\n| **Science & engineering domains** | 551 | [Browse →](../../../library/specializations/domains/science/) |\n| **Social sciences & humanities** | 160 | [Browse →](../../../library/specializations/domains/social-sciences-humanities/) |\n<!-- process-definitions:domains:end -->\n\nSee the full catalog with descriptions in the [Process Library](./process-library.md).\n\n---\n\n## Summary\n\nProcess definitions are JavaScript functions that orchestrate workflows. Define reusable tasks, compose them with conditionals and loops, and let Babysitter handle state management. Keep processes deterministic for reliable replay and resumption. Use the full power of JavaScript while benefiting from event-sourced persistence.\n",
    "documents": []
  },
  "outgoingEdges": [],
  "incomingEdges": []
}

Shortcuts

Back to overview
Open graph tab