agentcmd
Reference

agentcmd-workflows SDK

The agentcmd-workflows package is installed into each of your project repositories to provide type-safe workflow definitions and slash commands. It extends Inngest with specialized step methods for agent execution, git operations, CLI commands, and more.

Install this package in every repository where you want to use AgentCmd workflows. Each project gets its own .agent/ folder structure and slash commands.

Installation

npm install agentcmd-workflows inngest

Requirements:

  • Node.js >= 22.0.0
  • Inngest ^3.0.0 (peer dependency)
  • ESM-only package

Quick Start

import { defineWorkflow } from "agentcmd-workflows";

export default defineWorkflow(
  {
    id: "my-workflow",
    name: "My First Workflow",
    phases: ["plan", "execute"] as const,
  },
  async ({ event, step }) => {
    await step.phase("plan", async () => {
      await step.agent("analyze", {
        agent: "claude",
        prompt: "Analyze the codebase structure",
      });
    });

    await step.phase("execute", async () => {
      await step.cli("build", { command: "npm run build" });
    });
  }
);

CLI Commands

Initialize Project

npx agentcmd-workflows init [path]

Sets up the complete workflow infrastructure:

What it creates:

DirectoryPurpose
.agent/workflows/definitions/Workflow definition files
.agent/specs/Spec folders (backlog/, todo/, done/)
.agent/generated/Auto-generated TypeScript types
.agent/logs/Workflow execution logs
.claude/commands/cmd/12 built-in slash commands

Also:

  • Generates TypeScript types from slash commands
  • Updates .gitignore with appropriate patterns

Init is idempotent - safe to run multiple times. Existing files are preserved.

Generate Slash Command Types

npx agentcmd-workflows generate-slash-types \
  --input .claude/commands \
  --output .agent/generated/slash-commands.ts

Regenerates TypeScript types from your .claude/commands/**/*.md files. Run this after adding or modifying slash commands.

Project Structure

After running init, your project will have:

your-project/
├── .agent/
│   ├── workflows/
│   │   └── definitions/          # Your workflow files
│   │       └── implement-review-workflow.ts
│   ├── specs/
│   │   ├── backlog/              # Future work
│   │   ├── todo/                 # Current sprint
│   │   ├── done/                 # Completed specs
│   │   └── index.json            # Spec registry
│   ├── generated/
│   │   └── slash-commands.ts     # Auto-generated types
│   └── logs/                     # Execution logs

├── .claude/
│   └── commands/
│       └── cmd/                  # Slash command definitions
│           ├── generate-spec.md
│           ├── implement-spec.md
│           └── ... (12 total)

Core API

defineWorkflow

Creates a type-safe workflow definition.

import { defineWorkflow } from "agentcmd-workflows";

export default defineWorkflow(config, handler);

Parameters:

ParameterTypeDescription
configWorkflowConfigWorkflow configuration
handler(ctx: WorkflowContext) => Promise<void>Workflow execution function

defineSchema

Creates a type-safe JSON Schema with automatic TypeScript inference.

import { defineSchema, type InferSchemaType } from "agentcmd-workflows";

const argsSchema = defineSchema({
  type: "object",
  properties: {
    featureName: { type: "string" },
    priority: { enum: ["high", "medium", "low"] },
  },
  required: ["featureName"],
});

type Args = InferSchemaType<typeof argsSchema>;
// Result: { featureName: string; priority?: "high" | "medium" | "low" }

defineSchema is a zero-cost abstraction - it's an identity function that only provides type inference at compile time.

Workflow Configuration

interface WorkflowConfig {
  id: string;                           // Unique identifier (required)
  name?: string;                        // Human-readable name
  description?: string;                 // Workflow description
  phases?: readonly PhaseDefinition[];  // Phase organization
  timeout?: number;                     // Global timeout in ms
  argsSchema?: JSONSchema;              // Input validation + type inference
}

Phases

Organize workflow steps into logical phases:

defineWorkflow({
  id: "my-workflow",
  phases: ["plan", "implement", "review"] as const,
}, handler);
defineWorkflow({
  id: "my-workflow",
  phases: [
    { id: "plan", label: "Planning Phase" },
    { id: "implement", label: "Implementation" },
    { id: "review", label: "Code Review" },
  ] as const,
}, handler);

Typed Arguments

Validate and type workflow inputs:

const argsSchema = defineSchema({
  type: "object",
  properties: {
    specFile: { type: "string" },
    dryRun: { type: "boolean" },
  },
  required: ["specFile"],
});

export default defineWorkflow(
  { id: "impl", argsSchema },
  async ({ event }) => {
    // event.data.args is fully typed
    const { specFile, dryRun } = event.data.args;
  }
);

Step Methods

All step methods are available on the step object passed to your workflow handler:

StepPurposeReference
step.phase()Organize related stepsPhase
step.agent()Execute AI agents (Claude/Codex/Gemini)Agent
step.git()Git operations (commit, branch, PR)Git
step.cli()Shell command executionCLI
step.ai()Text/structured generationAI
step.preview()Docker preview containersPreview
step.artifact()File and text artifactsArtifact
step.annotation()Progress notesAnnotation
step.log()LoggingLog

Built-in Slash Commands

The SDK includes 12 pre-configured slash commands for common workflows:

Spec Generation

CommandPurpose
/cmd:generate-specGenerate feature spec with complexity scores
/cmd:generate-feature-specFeature-specific spec template
/cmd:generate-bug-specBug fix spec template
/cmd:generate-issue-specIssue-based spec template
/cmd:generate-prdProduct requirements document

Implementation

CommandPurpose
/cmd:implement-specExecute spec implementation
/cmd:review-spec-implementationReview implementation against spec
/cmd:auditComprehensive codebase audit

Spec Management

CommandPurpose
/cmd:add-specAdd new spec to project
/cmd:list-specsList specs with filtering
/cmd:move-specMove spec between folders

Git/PR

CommandPurpose
/cmd:create-prCreate pull request with commit

Type-Safe Slash Commands

Command File Format

Slash commands are defined in Markdown with frontmatter:

.claude/commands/cmd/my-command.md
---
description: "My custom command description"
argument-hint: [requiredArg, (optionalArg)]
---

# My Command

Command instructions for Claude...

## JSON Output

<json_output>
{
  "success": true,
  "message": "Result message"
}
</json_output>

Generated Types

Running generate-slash-types creates:

.agent/generated/slash-commands.ts
// Union of all command names
export type SlashCommandName = "/cmd:generate-spec" | "/cmd:implement-spec" | ...;

// Args interface per command
export interface CmdImplementSpecArgs {
  specIdOrNameOrPath: string;
}

// Response interface per command
export interface CmdImplementSpecResponse {
  success: boolean;
  message: string;
}

// Type-safe command builder
export function buildSlashCommand<T extends SlashCommandName>(
  name: T,
  args?: SlashCommandArgs[T]
): string;

Using in Workflows

import {
  buildSlashCommand,
  type CmdImplementSpecResponse,
} from "../generated/slash-commands";

await step.agent<CmdImplementSpecResponse>("implement", {
  agent: "claude",
  json: true,
  prompt: buildSlashCommand("/cmd:implement-spec", {
    specIdOrNameOrPath: "feature-auth",
  }),
});

Default Timeouts

Step TypeDefault Timeout
Agent30 minutes
Git2 minutes
CLI5 minutes
AI5 minutes
Preview5 minutes
Artifact5 minutes

Override per-step:

await step.agent("long-task", { ... }, { timeout: 3600000 }); // 1 hour

Common Patterns

Context Sharing via Closures

Share state between phases using JavaScript closures:

export default defineWorkflow(config, async ({ event, step }) => {
  interface Context {
    specFile?: string;
    prUrl?: string;
  }
  const ctx: Context = {};

  await step.phase("generate", async () => {
    const result = await step.agent("gen-spec", { ... });
    ctx.specFile = result.data.spec_file;
  });

  await step.phase("implement", async () => {
    // Access ctx.specFile from previous phase
    await step.agent("impl", {
      prompt: `Implement ${ctx.specFile}`,
    });
  });
});

Retry Loops

Retry operations with incrementing step IDs:

const MAX_ATTEMPTS = 10;

await step.phase("implement", async () => {
  for (let i = 1; i <= MAX_ATTEMPTS; i++) {
    const result = await step.agent<CmdImplementSpecResponse>(
      `implement-${i}`,  // Unique step ID per attempt
      {
        agent: "claude",
        json: true,
        prompt: buildSlashCommand("/cmd:implement-spec", { ... }),
      }
    );

    if (result.data.success) return;
  }
  throw new Error("Max attempts exceeded");
});

Conditional Execution

await step.phase("deploy", async () => {
  const testResult = await step.cli("test", { command: "npm test" });

  if (testResult.data.exitCode === 0) {
    await step.cli("deploy", { command: "npm run deploy" });
    await step.annotation("deployed", { message: "Deployment successful" });
  } else {
    await step.annotation("skipped", { message: "Tests failed, skipping deploy" });
  }
});