Psi can delegate reusable tasks to named workflows.
A workflow is a named prompt or orchestration loaded from .psi/workflows/*.md
as a built-in core capability. Some workflows are single focused agents;
others are multi-step flows that pass results from one step to the next.
This document is the primary example-led guide for workflow authoring. It covers the user-facing workflow surface, how to enable and run workflows, and the supported target-authored grammar.
Workflow loading is built in.
No extension manifest entry is required to enable /delegate or .psi/workflows/*.md discovery.
Optional workflow-adjacent extensions such as psi/mementum still use normal extension install manifests.
For manifest details and install options, see doc/extensions-install.md.
Workflow definitions are discovered from:
.psi/workflows/*.md
This repository includes many examples there, including:
plan-buildplan-build-reviewdelegate-build-reviewgh-bug-triage-modularplannerbuilderreviewerThe authoritative example set is:
plan-build — compact inline-session authoring exampleplan-build-review — compact multi-step inline-session exampledelegate-build-review — executable delegate-heavy target-authored example proving canonical downstream delegated yielded-text consumptiongh-bug-triage-modular — richer target-authored orchestration example proving delegated yielded text plus structured delegated handoff consumptionPsi exposes:
/delegate <workflow> <prompt>/delegate-reloadTypical usage:
/delegate planner analyze the scope of the current refactor
/delegate plan-build-review add user-facing workflow docs
/delegate gh-bug-triage-modular issue 123
What happens:
If you want a workflow to continue from a narrow request, put that request after the workflow name as the prompt text.
When editing .psi/workflows/*.md, reload them without restarting psi:
/delegate-reload
Reloading:
Use this during workflow authoring or prompt iteration.
Prefer the converged target workflow grammar for new examples and new workflow files.
That grammar has three explicit step forms:
:type :invoke — deterministic operation call:type :session — inline child-session construction:type :delegate — call another named workflow through an explicit boundaryAt a high level:
:invoke when code should do deterministic work and return structured data:session when you want to assemble a child conversation inline:delegate when you want to call a reusable named workflowFor the formal grammar, see doc/workflow-grammar.md.
For the conceptual explanation, see
doc/workflow-grammar-concepts.md.
plan-build is the smallest authoritative example of the preferred inline
session style.
---
name: plan-build
description: Plan and build without review
---
{:steps [{:name "plan"
:type :session
:tools ["read" "bash"]
:contributions [{:type :template
:text "{{input}}"
:vars {"input" {:from :workflow-input
:path [:input]}}}]}
{:name "build"
:type :session
:tools ["read" "bash" "edit" "write"]
:contributions [{:type :source
:from :workflow-original}
{:type :template
:text "Execute this plan:\n\n{{plan}}\n\nOriginal request: {{original}}"
:vars {"plan" {:from {:step "plan" :yield :text}}
"original" {:from :workflow-original
:path [:original]}}}]}]}
What this teaches:
:type :session:contributions:text + :vars{:from {:step "plan" :yield :text}}:workflow-originalplan-build-review extends the same style with one more downstream step.
---
name: plan-build-review
description: Plan, build, and review code changes
---
{:steps [{:name "plan"
:type :session
:tools ["read" "bash"]
:contributions [{:type :template
:text "{{input}}"
:vars {"input" {:from :workflow-input
:path [:input]}}}]}
{:name "build"
:type :session
:tools ["read" "bash" "edit" "write"]
:contributions [{:type :source
:from :workflow-original}
{:type :template
:text "Execute this plan:\n\n{{plan}}\n\nOriginal request: {{original}}"
:vars {"plan" {:from {:step "plan" :yield :text}}
"original" {:from :workflow-original
:path [:original]}}}]}
{:name "review"
:type :session
:tools ["read" "bash"]
:contributions [{:type :source
:from :workflow-original}
{:type :template
:text "Review the following implementation:\n\n{{implementation}}\n\nOriginal request: {{original}}"
:vars {"implementation" {:from {:step "build" :yield :text}}
"original" {:from :workflow-original
:path [:original]}}}]}]}
What this adds:
$INPUT / $ORIGINAL shortcutsdelegate-build-review is the authoritative checked-in target-authored example
for delegate-heavy downstream authoring.
---
name: delegate-build-review
description: Delegate planning and building, then review the delegated build result
---
{:steps [{:name "plan"
:type :delegate
:target "planner"
:prompt-string {:type :template
:text "{{input}}"
:vars {"input" {:from :workflow-input
:path [:input]}}}
:context [{:type :source
:from :workflow-original}]}
{:name "build"
:type :delegate
:target "builder"
:prompt-string {:type :template
:text "Execute this plan:\n\n{{plan}}\n\nOriginal request: {{original}}"
:vars {"plan" {:from {:step "plan" :yield :text}}
"original" {:from :workflow-original
:path [:original]}}}
:context [{:type :source
:from :workflow-original}
{:type :source
:from {:step "plan" :yield :text}}]}
{:name "review"
:type :session
:tools ["read" "bash"]
:contributions [{:type :source
:from :workflow-original}
{:type :template
:text "Review the following delegated implementation:\n\n{{implementation}}\n\nOriginal request: {{original}}"
:vars {"implementation" {:from {:step "build" :yield :text}}
"original" {:from :workflow-original
:path [:original]}}}]}]}
What this teaches:
:type :delegate boundaries for reusable named workflows{:from {:step "..." :yield :text}}:prompt-string as the new immediate ask for the callee:context as forwarded reference material:yield :text ref shape used for prior session resultsMinimum canonical delegated result model:
{:from {:step "..." :yield :text}}:terminal-contract {:handoff {:type :markdown-handoff-data}}{:from {:step "..." :output :handoff}}:output :handoffgh-bug-triage-modular is now the richer orchestration/context/reference
example for realistic bug triage.
It proves the dual-plane delegated model directly:
:output :handoffRepresentative target-style classification step:
{:name "post-repro"
:type :delegate
:target "gh-bug-post-repro"
:outputs {:handoff {:source :delegate/handoff}}
:prompt-string {:type :template
:text "{{report}}"
:vars {"report" {:from {:step "reproduce" :yield :text}}}}
:context [{:type :source
:from :workflow-original}
{:type :source
:from {:step "discover" :output :handoff}}
{:type :source
:from {:step "worktree" :output :handoff}}
{:type :source
:from {:step "reproduce" :output :handoff}}]}
What this teaches:
:yield :text is the human-facing chaining surface:output :handoff is the machine-facing orchestration surfaceThe most important authoring references in this guide are:
:workflow-input — the current workflow's input value:workflow-original — carried original request/reference context{:from {:step "..." :yield :text}} — prior step result used as the next ask, including delegate-step yielded text{:from {:step "..." :output :handoff}} — prior delegated workflow's structured terminal handoff{:from {:step "..." :output :transcript}} with :projection — projected
transcript/reference contextInterpretation:
:workflow-input is the immediate ask for the current workflow invocation:workflow-original is the carried reference context:yield refs are the simplest way to feed one step's result into
the next step's authored text:output :handoff refs are the stable way to consume machine-facing
exported workflow data without parsing markdown heuristically downstream:context on a delegate step carries forwarded material without changing the
delegated workflow's prompt stringKeep the authoring choices practical:
:session:delegate:invokeThis guide intentionally teaches the currently migrated example-led surfaces:
:session authoring:prompt-string and :context:output :handoff:workflow-input, :workflow-original, prior
step yields, delegated handoffs, and projected transcript contextIt does not try to turn arbitrary delegate-local runtime envelopes or diagnostics
into a broad author-facing output menu. This slice standardizes one structured
export key, :handoff, and keeps other delegated internal details non-contractual.
When you need the full formal surface, use the grammar/reference docs.
Prefer:
name and description:type on every authored stepGood first workflow authoring loop:
.psi/workflows/<name>.md/delegate-reload/delegate <name> <prompt>doc/workflow-grammar.md — workflow grammardoc/workflow-grammar-concepts.md — workflow concepts and semanticsdoc/extensions-install.md — install optional extensions that may complement workflow usagedoc/extensions.md — extension/tool details for workflow-adjacent extensions and shared workflow display conventionsdoc/tui.md — general in-session command usageREADME.md — top-level project overviewCan you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |