agentcmd
ConceptsWorkflows

Workflow Phases

Phases group related steps into logical stages, making workflows easier to understand and monitor.

What are Phases?

Phases are named sections that organize your workflow:

defineWorkflow({
  id: "build-and-deploy",
  phases: ["setup", "build", "test", "deploy"]
}, async ({ step }) => {
  await step.phase("setup", async () => {
    // All setup steps here
  });

  await step.phase("build", async () => {
    // All build steps here
  });

  // ... more phases
});

Defining Phases

Simple String Array

defineWorkflow({
  id: "simple",
  phases: ["plan", "code", "test", "ship"]
}, ...)

Objects with Labels

defineWorkflow({
  id: "detailed",
  phases: [
    { id: "plan", label: "Planning & Design" },
    { id: "code", label: "Implementation" },
    { id: "test", label: "Quality Assurance" },
    { id: "ship", label: "Deployment" }
  ]
}, ...)

When to use objects:

  • Longer, more descriptive labels
  • Special characters in labels
  • UI customization

Using Phases

Basic Usage

Wrap related steps in step.phase():

await step.phase("build", async () => {
  await step.cli("install", {
    command: "pnpm install",
  });

  await step.cli("type-check", {
    command: "pnpm check-types",
  });

  await step.cli("build", {
    command: "pnpm build",
  });
});

Type Safety

If you define phases in config, TypeScript enforces valid IDs:

defineWorkflow({
  phases: ["plan", "code", "test"]
}, async ({ step }) => {
  await step.phase("plan", ...);    // ✅ Valid
  await step.phase("deploy", ...);  // ❌ Type error!
});

Optional Description

Add context for complex phases:

await step.phase("integration-test", {
  description: "Run full E2E test suite against staging"
}, async () => {
  // Steps...
});

Phase Patterns

Sequential Phases

Most common - each phase completes before next starts:

await step.phase("phase-1", async () => { ... });
await step.phase("phase-2", async () => { ... });
await step.phase("phase-3", async () => { ... });

Conditional Phases

Skip phases based on conditions:

if (needsSetup) {
  await step.phase("setup", async () => {
    // Setup steps
  });
}

await step.phase("main-work", async () => {
  // Always runs
});

if (shouldDeploy) {
  await step.phase("deploy", async () => {
    // Deployment steps
  });
}