Examples
Two complete playbook folders. Copy one into your repository as .paseo/plugins/playbooks/ or .paseo/playbooks/, adjust it, then run validate_playbooks.
- Pull request: investigate, implement, review and local QA in parallel, babysit the PR until it is green.
- Capability: the Pull request playbook, a human gate, then the Release to dev playbook, as sub-playbooks.
- Docs check: compare the docs with the code, fix them, review and check in parallel, loop until clean, human gate. It needs no shell commands.
Pull request
From examples/.paseo/plugins/playbooks/. Steps run with bypassPermissions, so they run shell commands without asking. The Implementer pushes and opens the PR with gh.
investigate ─▶ implement ─┬─▶ review ───┬─▶ babysit ─▶ end
▲ └─▶ local_qa ─┘ │
└───── changes_requested ────┘pr.yaml
title: Pull request
description: Investigate a request, implement it, open a PR and babysit it until it is green.
inputs:
request:
type: string
required: true
description: What to change
base_branch:
type: string
default: main
description: Branch the PR targets
outputs:
pr_url: { type: string } # auto-matched from the implement step
pr_number:
type: number
value: "{{ steps.implement.outputs.pr_number }}"
steps:
- id: investigate
role: investigator
inputs: [request]
outputs:
plan: { type: string, description: Implementation plan }
prompt: |
Request: {{ inputs.request }}
- id: implement
role: implementer
needs: [investigate]
inputs: [request, plan, base_branch]
outputs:
pr_url: { type: string }
pr_number: { type: number }
branch: { type: string }
retries: 1
timeout: 1h
prompt: |
Request: {{ inputs.request }}
Plan:
{{ inputs.plan }}
Open (or update) the pull request against {{ inputs.base_branch }}.
- id: review
role: reviewer
needs: [implement]
inputs: [pr_url]
outputs:
findings: { type: string }
prompt: "Review the pull request {{ inputs.pr_url }}."
- id: local_qa
role: local_qa
needs: [implement]
inputs: [branch]
outputs:
report: { type: string }
tests_passed: { type: boolean }
prompt: "Test the branch {{ inputs.branch }}."
- id: babysit
role: babysitter
needs: [review, local_qa]
inputs:
pr_url: ~
review: "{{ steps.review.outputs.findings }}"
qa: "{{ steps.local_qa.outputs.report }}"
outcomes: [ready, changes_requested]
timeout: 2h
prompt: |
Pull request: {{ inputs.pr_url }}
Review findings:
{{ inputs.review }}
Local QA report:
{{ inputs.qa }}
on:
changes_requested: { goto: implement, max_loops: 3 }
defaults/main.yaml
# Repo-wide agent defaults. Precedence: step > role > playbook > these > the manager's own.
agent:
provider: claude
model: claude-opus-5-5
mode: bypassPermissions # steps run unattended (shell commands included)
manager:
mode: default # the manager never edits files
roles/babysitter/role.yaml
title: PR Babysitter
readonly: true
roles/babysitter/instructions.md
You are the PR Babysitter of a pull-request playbook.
Watch the pull request's CI checks (`gh pr checks --watch`) and review comments. Combine
them with the review findings and the local QA report.
Choose the outcome `ready` when CI is green and nothing blocking remains. Choose
`changes_requested` otherwise, and put every point the Implementer must fix in your
summary. Do not edit files or push.
roles/implementer/role.yaml
title: Implementer
readonly: false
roles/implementer/instructions.md
You are the Implementer of a pull-request playbook.
Implement the plan in the current checkout. You are already on the run's branch; commit
there and push it. Keep changes focused on the request. Run the relevant tests before
pushing.
Open a pull request against the base branch with `gh pr create`, or update the existing
one if this branch already has a PR. If you received feedback from a previous round,
address every point of it.
Return `pr_url`, `pr_number` and `branch`.
roles/investigator/role.yaml
title: Investigator
readonly: true
roles/investigator/instructions.md
You are the Investigator of a pull-request playbook.
Read the request and the relevant code, history and documentation. Do not edit files,
switch branches or commit. Work out what needs to change and why, and identify risks and
the tests that should prove the change.
Return a concrete implementation plan as the `plan` output: the files to touch, the
approach, edge cases, and how to verify it.
roles/local_qa/role.yaml
title: Local QA
readonly: true
roles/local_qa/instructions.md
You are the Local QA of a pull-request playbook.
Run the project's tests, linters and type checks on the current checkout. Do not edit
tracked files; build output in ignored files is fine. Report what you ran and what failed
as the `report` output, and set `tests_passed`.
roles/reviewer/role.yaml
title: Reviewer
readonly: true
roles/reviewer/instructions.md
You are the Reviewer of a pull-request playbook.
Review the pull request diff (`gh pr diff`) for correctness, security, missing tests and
clarity. Do not edit files or push. Report concrete findings with file and line, ordered
by severity, as the `findings` output. Say "No findings" when the change is good.
Capability (sub-playbooks)
From examples/.paseo/plugins/playbooks/. It builds a change with the Pull request playbook, waits for a human, then releases it with the Release to dev playbook: three steps, two of them sub-playbooks. Rejecting the gate restarts the whole PR block with your comment.
# capability.yaml
title: Capability
description: Build a change with the pull-request playbook, let a human approve it, then release it to the dev environment.
inputs:
request:
type: string
required: true
description: What to change
base_branch:
type: string
default: main
description: Branch the PR targets
outputs:
pr_url: { type: string } # from the pr block
env_url: { type: string } # from the release block
steps:
# A step with `playbook:` runs another playbook of this folder in place. Its inputs are
# matched by name (request, base_branch); its outputs (pr_url, pr_number) become this
# step's outputs. Its steps appear as pr.investigate, pr.implement, …
- id: pr
playbook: pr
- id: approve
needs: [pr]
gate: The PR is green. Release it to the dev environment, or request changes to rework it.
choices:
approved: { label: Release to dev }
rejected: { label: Request changes, comment: required, color: danger }
on:
rejected: { goto: pr } # restarts the whole pr block, with your comment as feedback
- id: release
needs: [approve]
playbook: release # pr_url comes from the pr block
# release.yaml
title: Release to dev
description: Deploy a change to the development environment and check it there.
inputs:
pr_url:
type: string
required: true
description: Pull request (or branch) to deploy
outputs:
env_url: { type: string } # auto-matched from the release step
qa_report: { type: string, value: "{{ steps.qa.outputs.report }}" }
steps:
- id: release
role: dev_env_releaser
inputs: [pr_url]
outputs:
env_url: { type: string, description: URL of the deployed dev environment }
log: { type: string, description: What was run to deploy }
timeout: 30m
prompt: "Deploy {{ inputs.pr_url }} to the development environment."
- id: qa
role: dev_env_qa
needs: [release]
inputs: [env_url, pr_url]
outputs:
report: { type: string }
passed: { type: boolean }
outcomes: [success, redeploy]
prompt: "Check {{ inputs.pr_url }} on {{ inputs.env_url }}."
on:
redeploy: { goto: release, max_loops: 1 }
The Release to dev roles, dev_env_releaser and dev_env_qa, deploy and check the change with the process your repository documents, and report a failure when there is none.
Docs check
Every role only reads or edits files, so default and acceptEdits are enough. The verdict step loops back to the writer at most twice, and a rejected gate sends the work back with your comment.
investigate ─▶ write ─┬─▶ review ──────┬─▶ verdict ─▶ ◆ approve ─▶ end
▲ └─▶ consistency ─┘ │ │
└──── changes_requested ─────┘ │
└───────────────── rejected ─────────────┘docs.yaml
title: Docs check
description: Compare the docs with the code, fix the gaps, review and check in parallel, loop until clean, then a human gate.
inputs:
focus:
type: string
default: README.md, OVERVIEW.md, skills/paseo-playbooks/SKILL.md and the website/ pages
description: Which documents to check
strictness:
type: enum
values: [light, thorough]
default: light
description: light = only wrong or missing facts; thorough = also clarity
outputs:
changes: { type: string } # auto-matched from the write step
steps:
- id: investigate
role: doc_investigator
inputs: [focus, strictness]
outputs:
gaps: { type: string, description: "Numbered list of doc statements that disagree with the code" }
gap_count: { type: number }
prompt: |
Documents to check: {{ inputs.focus }}
Strictness: {{ inputs.strictness }}
- id: write
role: doc_writer
needs: [investigate]
agent: { mode: acceptEdits }
inputs: [focus, gaps]
outputs:
changes: { type: string, description: "What you changed, per file" }
timeout: 20m
prompt: |
Fix these gaps in {{ inputs.focus }}:
{{ inputs.gaps }}
- id: review
role: doc_reviewer
needs: [write]
inputs: [changes]
outputs:
findings: { type: string }
blocking: { type: boolean }
prompt: |
The writer reports these changes (uncommitted in this checkout):
{{ inputs.changes }}
- id: consistency
role: consistency_checker
needs: [write]
inputs: [gaps, changes]
outputs:
remaining: { type: string, description: "Gaps still open, or none" }
all_fixed: { type: boolean }
prompt: |
Gaps found earlier:
{{ inputs.gaps }}
Changes made:
{{ inputs.changes }}
- id: verdict
role: doc_editor
needs: [review, consistency]
inputs: [findings, blocking, remaining, all_fixed]
outcomes: [ready, changes_requested]
prompt: |
Review findings (blocking: {{ inputs.blocking }}):
{{ inputs.findings }}
Remaining gaps (all fixed: {{ inputs.all_fixed }}):
{{ inputs.remaining }}
on:
changes_requested: { goto: write, max_loops: 2 }
- id: approve
needs: [verdict]
gate: The docs are updated, uncommitted. Approve to finish, or request changes to send them back to the writer.
choices:
approved: { label: Approve }
rejected: { label: Request changes, comment: required, color: danger }
on:
rejected: { goto: write }
defaults/main.yaml
# Local test setup: cheap step agents, a stronger manager.
agent:
provider: claude
model: claude-haiku-5-5
mode: default # read-only roles only read files: no permission prompts
manager:
model: claude-sonnet-5-5
mode: default
roles/consistency_checker/role.yaml
title: Consistency checker
readonly: true
roles/consistency_checker/instructions.md
You check that a list of documentation gaps was actually fixed. For each gap, read the
current documents and the code with your file reading tools only. Do not run shell
commands and do not edit anything.
Return in `remaining` the gaps that are still open (or "none"), and set `all_fixed`.
roles/doc_editor/role.yaml
title: Docs editor
readonly: true
roles/doc_editor/instructions.md
You are the editor who decides whether a documentation change is ready. You read the
review findings and the consistency check you are given; you may read the documents to
confirm. Do not run shell commands and do not edit anything.
Choose the outcome `ready` when nothing blocking remains and every gap is fixed. Choose
`changes_requested` otherwise, and put every point the writer must address in your
summary: it is sent back to the writer as feedback.
roles/doc_investigator/role.yaml
title: Docs investigator
readonly: true
roles/doc_investigator/instructions.md
You check documentation against the code of this repository (a Paseo plugin written in
TypeScript: server/, client/, shared/, examples/).
Read the documents you are given, then the code they describe, using your file reading
and search tools only. Do not run shell commands and do not edit anything.
List every statement in the documents that is wrong, outdated or missing compared with
the code: file paths, field names, defaults, tool names, behaviour. Quote the statement
and say what the code actually does, with the file. With strictness "thorough", also list
unclear passages. Return them as a numbered list in `gaps` and their number in
`gap_count` (0 and "none" if the docs match).
roles/doc_reviewer/role.yaml
title: Docs reviewer
readonly: true
roles/doc_reviewer/instructions.md
You review documentation changes. Read the changed documentation files (they are uncommitted in
this checkout) and the code they describe, with your file reading tools only. Do not run
shell commands and do not edit anything.
Check that every change is accurate, clear and consistent with the rest of the docs.
Return your findings in `findings` ("No findings" when it is good) and set `blocking` to
true only for wrong or misleading statements.
roles/doc_writer/role.yaml
title: Docs writer
readonly: false
roles/doc_writer/instructions.md
You fix documentation in this repository. Edit only the documentation files you were asked
to check (Markdown files, or the HTML pages under website/), with your file edit tool. In
HTML pages change only the text: keep tags, classes and the page structure. Do not run shell commands, do not commit, and do not
change code.
Fix each gap you are given, keeping the existing tone and structure. If you received
feedback from a previous round, address every point of it first. Return in `changes` a
short list of what you changed, per file.