Skip to main content
Playbooks are parameterized mission playbooks — JSON files that define a complete Mission with {{placeholder}} parameters. When you execute a playbook, Polpo substitutes your parameters, saves the result as a standard Mission, and runs it.
# Review the auth module, focusing on security
polpo playbook run code-review --param module=src/auth --param focus=security

# Fix a specific bug
polpo playbook run bug-fix --param issue="Login fails when email has + character"
A playbook is data, not code — a JSON file on disk. When executed, it becomes a regular Mission with no new runtime concepts or special execution path.

Quick Start

  1. Create the playbook directory
    mkdir -p .polpo/playbooks/my-playbook
    
  2. Create playbook.json
    {
      "name": "my-playbook",
      "description": "What this playbook does in one sentence",
      "parameters": [
        {
          "name": "target",
          "description": "The module or file to operate on",
          "type": "string",
          "required": true
        }
      ],
       "mission": {
         "tasks": [
           {
             "title": "Do the thing to {{target}}",
             "description": "Detailed instructions for the agent about what to do with {{target}}.",
             "assignTo": "default"
           }
         ]
       }
     }
    
  3. Validate it
    polpo playbook validate my-playbook
    
  4. Run it
    polpo playbook run my-playbook --param target=src/auth
    

Anatomy of a Playbook

A playbook lives in a directory with a playbook.json file:
.polpo/playbooks/
  code-review/
    playbook.json
  bug-fix/
    playbook.json
The playbook.json has three required fields and one optional:
{
  "name": "code-review",
  "description": "Deep code review of a module: analysis, fixes, and verification",
  "parameters": [ ... ],
  "mission": { ... }
}
FieldTypeRequiredDescription
namestringYesPlaybook identifier (kebab-case, must match directory name)
descriptionstringYesHuman-readable summary
parametersarrayNoDeclared parameters (see below)
missionobjectYesMission body — same shape as a MissionDocument, with {{placeholders}}

Parameters

Each parameter declares a name, type, and constraints:
{
  "name": "module",
  "description": "Module or directory to review",
  "type": "string",
  "required": true
}
FieldTypeDefaultDescription
namestringParameter name, used as {{name}} in the mission
descriptionstringHuman-readable explanation
type"string" | "number" | "boolean""string"Value type — booleans accept true/false/yes/no/1/0
requiredbooleanfalseWhether the parameter must be provided
defaultstring | number | booleanDefault value when not provided
enumarrayAllowed values (enum constraint)
Parameters with a default value don’t need to be marked required — they’ll always resolve to something.

Enum Parameters

Constrain a parameter to specific values:
{
  "name": "focus",
  "description": "Review focus area",
  "type": "string",
  "default": "general",
  "enum": ["general", "performance", "security", "readability", "types"]
}

Parameter Design Tips

  • Make the minimum required. Only mark parameters required if the playbook literally cannot function without them. Everything else should have a sensible default.
  • Use enums for constrained choices. If a parameter only makes sense with specific values, declare them.
  • Use descriptive names. The parameter name appears in CLI output, TUI pickers, and error messages. test_command is better than tc.
  • Document defaults in description. Mention what happens when the parameter isn’t provided:
{
  "name": "test_command",
  "description": "Command to run tests (defaults to 'pnpm run test')",
  "type": "string",
  "default": "pnpm run test"
}

Writing the Mission Playbook

The mission field is a standard Mission structure — teams, tasks, dependencies, expectations, quality gates — with {{placeholder}} tokens wherever you want parameter substitution.

Teams

Define volatile agents specific to this playbook:
{
  "mission": {
    "team": [
      {
        "name": "analyst",
        "role": "Senior code analyst — identifies issues and improvement opportunities"
      },
      {
        "name": "fixer",
        "role": "Implementation specialist — applies targeted fixes"
      }
    ],
    "tasks": [ ... ]
  }
}
You can omit the team field entirely if you want the playbook to use the project’s existing agents. Just reference them by name in assignTo.

Tasks with Placeholders

Placeholders work in any string value within the mission:
{
  "title": "Analyze {{module}}",
  "description": "Review {{module}} with focus on {{focus}}.",
  "assignTo": "analyst",
  "dependsOn": ["Setup {{module}}"],
  "expectations": [
    { "type": "test", "command": "{{test_command}}" }
  ]
}
Placeholders work anywhere in the mission JSON — titles, descriptions, commands, file paths, even dependsOn references. During instantiation, Polpo serializes the mission to a string, replaces all {{param}} tokens, and parses it back.
Every placeholder in the mission must correspond to a declared parameter (or have a default). Polpo will throw an error if any {{placeholder}} remains unreplaced after substitution.

Dependencies

Task dependencies work the same as in regular Missions — reference tasks by title:
{
  "tasks": [
    {
      "title": "Diagnose {{issue}}",
      "assignTo": "debugger"
    },
    {
      "title": "Fix {{issue}}",
      "assignTo": "debugger",
      "dependsOn": ["Diagnose {{issue}}"]
    },
    {
      "title": "Verify fix",
      "assignTo": "verifier",
      "dependsOn": ["Fix {{issue}}"]
    }
  ]
}
Placeholders in dependsOn must match the playbook title of the dependency — use "Diagnose {{issue}}", not the resolved "Diagnose Login bug". Both sides get substituted at the same time.

Expectations

Add assessment criteria to ensure quality:
{
  "expectations": [
    {
      "type": "file_exists",
      "paths": ["analysis-report.md"]
    },
    {
      "type": "test",
      "command": "{{test_command}}"
    },
    {
      "type": "llm_review",
      "criteria": "The analysis is thorough with specific file:line references",
      "threshold": 3.5
    }
  ]
}
See Review for all expectation types.

Quality Gates

Block progression until quality thresholds are met:
{
  "mission": {
    "qualityGates": [
      {
        "name": "analysis-quality",
        "afterTasks": ["Analyze {{module}}"],
        "blocksTasks": ["Apply fixes"],
        "minScore": 3.5
      }
    ],
    "tasks": [ ... ]
  }
}

Discovery

Polpo discovers playbooks from three locations, in priority order (first match wins by name):
PriorityLocationScope
1<polpoDir>/playbooks/Project-level
2<cwd>/.polpo/playbooks/Fallback (if polpoDir differs)
3~/.polpo/playbooks/User-level (shared across projects)
Each playbook is a directory containing a playbook.json file. Directories without a valid playbook.json are silently skipped. If two playbooks share the same name, the higher-priority location wins. This lets you override a user-level playbook with a project-specific version.

Execution Flow

When you run a playbook, four things happen:
  1. Load — the playbook definition is loaded from disk
  2. Validate — parameters are checked against declared types, enums, and required flags. Defaults are applied.
  3. Instantiate — all {{placeholder}} tokens are replaced with resolved values. The result is validated as legal JSON.
  4. Execute — the instantiated mission is saved via saveMission() and executed via executeMission() — from here on it’s a standard Mission
playbook.json + params → validation → substitution → MissionDocument → executeMission()
The playbook system adds zero runtime overhead — once instantiated, the mission executes through the exact same path as any manually created mission. Same task lifecycle, same assessment, same quality gates, same hooks.

Running Playbooks

# List available playbooks
polpo playbook list

# Show details and parameters
polpo playbook show code-review

# Run with parameters
polpo playbook run code-review --param module=src/auth --param focus=security

# Dry run — see the instantiated mission without executing
polpo playbook run code-review --param module=src/auth --dry-run

# Validate a playbook definition
polpo playbook validate code-review

Validation

Always validate before running:
polpo playbook validate code-review
The validator checks:
  • Required fields (name, description, mission) are present and valid
  • Name is kebab-case (e.g. bug-fix, code-review)
  • All {{placeholders}} in the mission have matching parameter declarations
  • Optional parameters without a default value are not used as {{placeholders}} in the mission (would fail at runtime if omitted)
  • Parameter definitions have valid name, description, and type fields

Example: Full Playbook

Here’s a complete playbook that performs a focused code review:
{
  "name": "code-review",
  "description": "Deep code review of a module: analysis, fixes, and verification",
  "parameters": [
    {
      "name": "module",
      "description": "Module or directory to review",
      "type": "string",
      "required": true
    },
    {
      "name": "test_command",
      "description": "Command to run tests",
      "type": "string",
      "default": "pnpm run test"
    },
    {
      "name": "focus",
      "description": "Review focus area",
      "type": "string",
      "default": "general",
      "enum": ["general", "performance", "security", "readability", "types"]
    }
  ],
  "mission": {
    "team": [
      {
        "name": "analyst",
        "role": "Senior code analyst — identifies issues, patterns, and improvement opportunities"
      },
      {
        "name": "reviewer",
        "role": "QA reviewer — verifies changes don't introduce regressions"
      }
    ],
    "tasks": [
      {
        "title": "Analyze {{module}}",
        "description": "Perform a deep {{focus}} review of the {{module}} module. Identify code smells, complexity hotspots, pattern violations, type safety issues, and improvement opportunities. Write findings to analysis-report.md with specific file:line references.",
        "assignTo": "analyst",
        "expectations": [
          { "type": "file_exists", "paths": ["analysis-report.md"] },
          {
            "type": "llm_review",
            "criteria": "The analysis is thorough, covers all key aspects, and provides actionable recommendations with specific file:line references",
            "threshold": 3.5
          }
        ]
      },
      {
        "title": "Apply critical fixes",
        "description": "Based on the analysis report, apply the most critical fixes to {{module}}. Focus on: correctness bugs, type safety issues, and clear anti-patterns. Do NOT refactor for style — only fix real problems.",
        "assignTo": "analyst",
        "dependsOn": ["Analyze {{module}}"],
        "expectations": [
          { "type": "test", "command": "{{test_command}}" }
        ]
      },
      {
        "title": "Verify changes",
        "description": "Review all changes applied to {{module}}. Verify: (1) each fix addresses a real issue from the analysis, (2) no regressions introduced, (3) code quality improved. Write a brief verification summary.",
        "assignTo": "reviewer",
        "dependsOn": ["Apply critical fixes"],
        "expectations": [
          {
            "type": "llm_review",
            "criteria": "The verification confirms all changes are correct, no regressions were introduced, and code quality improved",
            "threshold": 4.0
          }
        ]
      }
    ],
    "qualityGates": [
      {
        "name": "analysis-quality",
        "afterTasks": ["Analyze {{module}}"],
        "blocksTasks": ["Apply critical fixes"],
        "minScore": 3.5
      }
    ]
  }
}

Built-in Playbooks

Polpo ships with 8 ready-to-use playbooks:
PlaybookDescriptionKey Parameters
code-reviewDeep code review with analysis, fixes, and verificationmodule (required), focus, test_command
bug-fixStructured bug fix: reproduce, fix, test, verifyissue (required), scope, test_command
refactoringSafe refactoring with analysis and test validationmodule (required), goal (required), test_command
test-coverageImprove test coverage for a modulemodule (required), target_coverage, test_command
documentationGenerate or improve documentationmodule (required), style, scope
security-auditSecurity audit with vulnerability assessmentmodule (required), severity, test_command
migrationDatabase or API migration playbookfrom (required), to (required), test_command
onboardingGenerate onboarding docs for a codebasemodule (required), audience

Sharing Playbooks

Project-level

Put playbooks in .polpo/playbooks/ — they’re committed to version control and shared with your team.

User-level

Put playbooks in ~/.polpo/playbooks/ — they’re available across all your projects. Good for personal productivity playbooks.

Override precedence

If a project and user-level playbook share the same name, the project-level one wins. This lets teams override a personal playbook with a standardized version.

Playbooks vs Skills vs Missions

DimensionSkillsPlaybooksMissions
LayerPromptOrchestrationExecution
FormatMarkdown (SKILL.md)JSON (playbook.json)JSON (.polpo/missions/)
What it doesInjects instructions into agent’s system promptGenerates a Mission from a parameterized playbookDefines tasks, agents, and dependencies to execute
ReusabilityAssigned to agents across tasksInstantiated with different parametersSingle-use (one execution)
Runtime impactAffects how the agent thinksNone — becomes a standard MissionDrives task execution
Skills make agents smarter. Playbooks make processes repeatable. Missions are the execution unit.

Tips

  • Start simple. A playbook with one task and one parameter is still useful. You can add complexity later.
  • Use quality gates for multi-step playbooks. They prevent wasted work when an early step produces poor results.
  • Write detailed task descriptions. The agent only sees the resolved description — make it clear what “success” looks like.
  • Test with --dry-run. The CLI’s --dry-run flag shows the fully instantiated mission without executing, so you can verify placeholders resolve correctly.
  • Validate after editing. Run polpo playbook validate <name> to catch placeholder/parameter mismatches early.