Skip to main content
This is the first step to create a workflow: defining who. Agents are the actors that execute each step of your workflow. Agents are configured in JavaScript files inside the config/ folder. Each agent type has its own configuration file.
FileAgent TypePurpose
main.agents.jsMain agentsCore workflow steps
modules.jsModulesAgents with loop behavior
sub.agents.jsSub-agentsDelegated tasks spawned by main agents
Controllers are defined in main.agents.js with role: 'controller'. They’re main agents with special orchestration capabilities.

Main Agents

Main agents are the core building blocks of your workflow. Each main agent runs as a step in the workflow sequence.

Basic Structure

config/main.agents.js
const path = require('node:path');
const promptsDir = path.join(__dirname, '..', 'prompts', 'templates');

module.exports = [
  {
    id: 'planner',
    name: 'Project Planner',
    description: 'Analyzes requirements and creates implementation plan',
    promptPath: path.join(promptsDir, 'planner', 'main.md'),
  },
];

Agent Fields

FieldRequiredDescription
idYesUnique identifier (lowercase, hyphens)
nameYesDisplay name shown in UI
descriptionYesBrief description of what the agent does
promptPathYesPath or array of paths to prompt files
chainedPromptsPathNoArray of chained prompt paths (multi-step agents)
roleNoSet to 'controller' for controller agents only
engineNoAI engine to use (defaults to workflow default)
modelNoAI model to use (defaults to engine default)
tracksNoArray of track IDs this agent runs for
conditionsNoArray of condition IDs (runs when ALL are selected)
conditionsAnyNoArray of condition IDs (runs when ANY is selected)

Prompt Path: String vs Array

The promptPath field accepts either a single path or an array of paths.
One prompt file loaded as the agent’s instructions.
{
  id: 'planner',
  promptPath: path.join(promptsDir, 'planner', 'main.md'),
}
promptPath array = Files merged into one prompt, shown at once.chainedPromptsPath = Separate prompts injected sequentially, one after another with user interaction between each.

When to Use Array promptPath

Use CaseExample
Organizing large promptsSplit persona, instructions, and examples into separate files
Reusing prompt componentsShare common instructions across agents
Maintaining readabilityKeep individual files focused and manageable
// Complex agent with organized prompt structure
{
  id: 'architect',
  name: 'System Architect',
  description: 'Designs system architecture',
  promptPath: [
    path.join(promptsDir, 'shared', 'coding-standards.md'),
    path.join(promptsDir, 'architect', 'persona.md'),
    path.join(promptsDir, 'architect', 'workflow.md'),
    path.join(promptsDir, 'architect', 'output-format.md'),
  ],
}

Single-Step vs Multi-Step

Agents can be single-step or multi-step based on whether they have chained prompts.
One prompt file, injected once. Best for focused tasks.
{
  id: 'code-reviewer',
  name: 'Code Reviewer',
  description: 'Reviews code for issues and improvements',
  promptPath: path.join(promptsDir, 'reviewer', 'main.md'),
}

When to Use Each

TypeUse When
Single-stepFocused tasks, smaller prompts, minimal context needed
Multi-stepQ&A flows, progressive context building, conversational agents
Multi-step agents maintain the same session throughout all steps. The agent remembers everything from previous steps.

Modules

Modules are main agents with loop behavior. They can send the workflow back to earlier steps, creating validation gates and iteration cycles.

Module Structure

config/modules.js
const path = require('node:path');
const promptsDir = path.join(__dirname, '..', 'prompts', 'modules');

module.exports = [
  {
    id: 'quality-gate',
    name: 'Quality Gate',
    description: 'Validates work and loops back if issues found',
    promptPath: path.join(promptsDir, 'quality-gate', 'main.md'),
    behavior: {
      type: 'loop',
      action: 'stepBack',
    },
  },
];

Module Fields

In addition to standard agent fields, modules have:
FieldRequiredDescription
behavior.typeYesMust be 'loop'
behavior.actionYesMust be 'stepBack'

How Modules Control Flow

Modules communicate with the workflow by writing to a directive file when validation fails:
.codemachine/memory/directive.json
{
  "action": "loop",
  "reason": "Validation failed: 3 tests failing, missing error handling",
  "target": "developer"
}
If validation passes, no action is needed. The workflow continues to the next step by default.
Your module’s prompt must include instructions on how to validate and how to write the directive file. Without these instructions, the agent won’t know how to trigger the loop.

Writing Module Prompts

Learn how to write prompts that instruct modules to validate and write directives

Workflow Signals MCP

Configure MCP for directive-based workflow control

Common Module Patterns

Check work quality, fix issues, re-check until passing.
{
  id: 'validator',
  name: 'Code Validator',
  description: 'Validates code quality and loops if issues found',
  promptPath: path.join(promptsDir, 'validator', 'main.md'),
  behavior: { type: 'loop', action: 'stepBack' },
}
Review output, request changes, iterate until approved.
{
  id: 'reviewer',
  name: 'Review Module',
  description: 'Reviews and requests revisions until approved',
  promptPath: path.join(promptsDir, 'reviewer', 'main.md'),
  behavior: { type: 'loop', action: 'stepBack' },
}
Block progression until quality threshold is met.
{
  id: 'quality-gate',
  name: 'Quality Gate',
  description: 'Ensures quality standards before proceeding',
  promptPath: path.join(promptsDir, 'quality-gate', 'main.md'),
  behavior: { type: 'loop', action: 'stepBack' },
}

Workflow File Options

When using modules in your workflow file, you can configure loop behavior:
resolveModule('quality-gate', {
  loopSteps: 2,           // How many steps to go back
  loopMaxIterations: 3,   // Maximum loop attempts
  loopSkip: ['logger'],   // Agents to skip on re-loop
})

Sub-Agents

Sub-agents are helper agents that main agents can spawn during execution. They run as separate sessions and return results to the calling agent.

When to Use Sub-Agents

  • Delegating specialized subtasks
  • Parallel task execution
  • Context isolation for specific work
  • Reusable agent capabilities

Sub-Agent Types

Pre-defined prompt file. You define the prompt at build time.
config/sub.agents.js
{
  id: 'test-writer',
  name: 'Test Writer',
  description: 'Writes unit tests for given code',
  mirrorPath: path.join(promptsDir, 'sub-agents', 'test-writer.md'),
}

Why Sub-Agent Prompts Live in .codemachine/

Unlike main agents whose prompts are in the prompts/ folder, sub-agent prompts live in the runtime .codemachine/agents/ folder. This design enables:
  • Dynamic prompt generation - A main agent (like an agent-builder) can write prompts for sub-agents at runtime
  • Cross-agent access - Other agents can read and modify sub-agent prompts during workflow execution
  • Flexibility - Use static prompts via mirrorPath, or leave it empty for fully dynamic sub-agents that receive instructions when invoked
Sub-agents are also accessible via the codemachine run command for direct execution.

Sub-Agent Fields

FieldRequiredDescription
idYesUnique identifier
nameYesDisplay name
descriptionYesWhat the sub-agent does
mirrorPathStatic onlyPath to pre-defined prompt file

Invoking Sub-Agents

Sub-agents must be invoked via MCP tools or CLI commands. Example orchestrator with agent-coordination MCP:
main.agents.js
{
  id: 'blueprint-orchestrator',
  name: 'Blueprint Orchestrator',
  description: 'Coordinates architecture sub-agents',
  promptPath: path.join(promptsDir, 'orchestrator', 'main.md'),
  mcp: [
    {
      server: 'agent-coordination',
      only: ['run_agents', 'get_agent_status', 'list_available_agents'],
      targets: ['data-architect', 'api-architect', 'ui-architect'],
    },
  ],
}
Include MCP tools documentation in your main agent’s prompt if it needs to call sub-agents.

Writing Sub-Agent Prompts

Learn how to write prompts for agents that orchestrate sub-agents

Controllers

Controllers are special agents that orchestrate autonomous workflows. They respond on behalf of the user, driving the entire workflow. Controllers require role: 'controller' and must be configured with the workflow-signals MCP to approve step transitions. Example controller and step agent with workflow-signals MCP:
main.agents.js
module.exports = [
  // Controller - Approves/rejects step transitions
  {
    id: 'project-controller',
    name: 'Project Controller',
    role: 'controller',
    promptPath: path.join(promptsDir, 'controller', 'main.md'),
    mcp: [
      {
        server: 'workflow-signals',
        only: ['approve_step_transition', 'get_pending_proposal'],
      },
    ],
  },

  // Step agents - Propose completion
  {
    id: 'pm',
    name: 'Product Manager',
    promptPath: path.join(promptsDir, 'pm', 'main.md'),
    mcp: [
      {
        server: 'workflow-signals',
        only: ['propose_step_completion'],
      },
    ],
  },

  // ... other step agents with same MCP config
];
Both controller and all step agents must have workflow-signals MCP configured for autonomous mode to work.

Built-in MCP Servers

CodeMachine provides built-in MCP servers for agent coordination and workflow control. Configure these on your agents using the mcp field.

MCP Configuration Fields

FieldDescription
serverThe MCP server name ('workflow-signals' or 'agent-coordination')
onlyArray of tool names to expose (limits available tools)
targetsArray of sub-agent IDs that can be invoked (agent-coordination only)

Workflow Signals

Controllers and step agents communicate through the workflow-signals MCP. Step agents propose completion, and the controller approves or rejects.
Both controller and all step agents must have workflow-signals MCP configured for autonomous mode to work.
The controller approves or rejects step transitions.
{
  id: 'project-controller',
  name: 'Project Controller',
  description: 'Orchestrates workflow and approves transitions',
  role: 'controller',
  promptPath: path.join(promptsDir, 'controller', 'main.md'),
  mcp: [
    {
      server: 'workflow-signals',
      only: ['approve_step_transition', 'get_pending_proposal'],
    },
  ],
}
ToolDescription
approve_step_transitionAccept or reject a step’s completion proposal
get_pending_proposalRead the current pending proposal from a step

See Autonomous Example

View a complete autonomous workflow with controller and step agents

Agent Coordination

Main agents or controllers that orchestrate sub-agents need the agent-coordination MCP configured.
{
  id: 'orchestrator',
  name: 'Orchestrator',
  description: 'Coordinates sub-agents for specialized tasks',
  promptPath: path.join(promptsDir, 'orchestrator', 'main.md'),
  mcp: [
    {
      server: 'agent-coordination',
      only: ['run_agents', 'get_agent_status'],
      targets: ['code-generator', 'test-runner', 'doc-writer'],
    },
  ],
}
ToolDescription
list_available_agentsDiscover available sub-agents
run_agentsExecute sub-agent scripts
get_agent_statusCheck execution status
list_active_agentsSee currently running agents

See Sub-Agent Example

View a complete workflow using sub-agents with agent-coordination MCP

Agent Characters

Agent characters give your agents visual personality in the CLI. Each agent can have custom ASCII faces and phrases.

Character Configuration

config/agent-characters.json
{
  "personas": {
    "swagger": {
      "baseFace": "(⌐■_■)",
      "expressions": {
        "thinking": "(╭ರ_•́)",
        "tool": "<(•_•<)",
        "error": "(╥﹏╥)",
        "idle": "(⌐■_■)"
      },
      "phrases": {
        "thinking": ["Processing...", "Working on it..."],
        "tool": ["Got what I needed", "Perfect, moving on"],
        "error": ["Hmm, that didn't work", "Trying another way"],
        "idle": ["Ready when you are", "Your turn"]
      }
    }
  },
  "agents": {
    "planner": "swagger",
    "reviewer": "analytical"
  },
  "defaultPersona": "friendly"
}

Pre-built Styles

StyleBase FaceBest For
swagger(⌐■_■)Cool, confident agents
friendly(˶ᵔ ᵕ ᵔ˶)Warm, helpful agents
analytical[•_•]Logical, precise agents
cheerful◕‿◕Upbeat, positive agents
technical{•_•}Developer-focused agents
precise<•_•>Validation, QA agents

Custom Characters

Create custom characters by defining all expressions and phrases:
{
  "personas": {
    "my-custom-style": {
      "baseFace": "[◉_◉]",
      "expressions": {
        "thinking": "[◉~◉]",
        "tool": "[◉!◉]",
        "error": "[x_x]",
        "idle": "[◉_◉]"
      },
      "phrases": {
        "thinking": ["Analyzing...", "Computing..."],
        "tool": ["Data received", "Processing result..."],
        "error": ["Error encountered", "Retrying..."],
        "idle": ["Standing by", "Awaiting input"]
      }
    }
  }
}
If no character is defined for an agent, it falls back to the swagger character.

Engine & Model

Each agent can use a different AI engine and model. Configure engine and model fields to optimize for your use case.

Model Configuration

See available engines, model options, reasoning effort, and fallback system

Track & Condition Filtering

Filter when agents run based on user-selected tracks and conditions.

Agent-Level Filtering

Control when an entire agent runs:
{
  id: 'frontend-specialist',
  name: 'Frontend Specialist',
  description: 'Handles frontend implementation',
  promptPath: path.join(promptsDir, 'frontend', 'main.md'),
  tracks: ['frontend', 'fullstack'],    // Only runs for these tracks
  conditions: ['has_ui'],                // AND only if has_ui is selected
}

Step-Level Filtering

For multi-step agents, filter individual steps:
{
  id: 'developer',
  name: 'Full Stack Developer',
  description: 'Implements features',
  promptPath: path.join(promptsDir, 'developer', 'main.md'),
  chainedPromptsPath: [
    // Always loads
    path.join(promptsDir, 'developer', 'chained', 'step-01-setup.md'),
    // Only for frontend track
    {
      path: path.join(promptsDir, 'developer', 'chained', 'step-02-react.md'),
      tracks: ['frontend'],
    },
    // Only if mobile condition selected
    {
      path: path.join(promptsDir, 'developer', 'chained', 'step-03-mobile.md'),
      conditions: ['has_mobile'],
    },
  ],
}

Filtering Rules

  • Both track AND conditions must match if both are specified
  • Empty arrays = always runs/loads
  • Agent-level filtering is checked first, then step-level

Complete Example

Here’s a complete main.agents.js with multiple agent types:
config/main.agents.js
const path = require('node:path');
const promptsDir = path.join(__dirname, '..', 'prompts', 'templates');

module.exports = [
  // Single-step main agent
  {
    id: 'planner',
    name: 'Project Planner',
    description: 'Analyzes requirements and creates implementation plan',
    promptPath: path.join(promptsDir, 'planner', 'main.md'),
    engine: 'claude',
    model: 'opus',
  },

  // Multi-step main agent with filtering
  {
    id: 'developer',
    name: 'Developer',
    description: 'Implements the planned features',
    promptPath: path.join(promptsDir, 'developer', 'main.md'),
    chainedPromptsPath: [
      path.join(promptsDir, 'developer', 'chained', 'step-01-setup.md'),
      {
        path: path.join(promptsDir, 'developer', 'chained', 'step-02-frontend.md'),
        tracks: ['frontend', 'fullstack'],
      },
      {
        path: path.join(promptsDir, 'developer', 'chained', 'step-03-backend.md'),
        tracks: ['backend', 'fullstack'],
      },
    ],
    engine: 'codex',
    modelReasoningEffort: 'medium',
  },

  // Controller agent
  {
    id: 'project-controller',
    name: 'Project Owner',
    description: 'Orchestrates the workflow autonomously',
    role: 'controller',
    promptPath: path.join(promptsDir, 'controller', 'project-owner.md'),
    engine: 'claude',
    model: 'opus',
  },
];

Next Steps