Authoring reference
Every key of every Local Workflows file, with the schema’s own wording,
on one page. Generated from resources/schemas/ - the same files the
editor validates against - so it cannot drift from what the parser
accepts.
Point a model at this page and it has the whole grammar in one fetch.
tasks.yml
A flat library of independently runnable tasks, ordered only by ‘needs:’. One file per .local-workflows folder, so a monorepo keeps a tasks.yml beside each package it builds.
Lives at .local-workflows/tasks.yml. The top-level key is tasks:.
A file keyed on anything else parses into no tasks at all rather than
reporting an error, because there is nothing there to reject.
Top-level keys
| Key | Type | Default | What it does |
|---|---|---|---|
version |
1 |
The schema this file is written for. Optional here and required in a workflow file, because every tasks.yml written before versions existed has no such line - absence means the first schema, a wrong value is still an error. | |
name |
string |
"Local Workflows" |
A name for this file’s task library. Rarely worth setting: nothing runs the file as a whole, and each task carries its own name. |
vars |
vars | Template values, substituted into this file and going no further - nothing here is exported to a spawned process. Values keep their YAML type, so a number stays a number and a whole-value ‘${{ vars.retries }}’ hands over a real one. Resolution order is anchors, then vars, then env: a var may read a sibling var, never an env var. | |
env |
env | Environment variables exported to whatever this runs. Every value is coerced to text. Declare a value here only when something being run needs to read it; to merely use it inside this file, use ‘vars:’. | |
dotenv |
dotenv | One .env path, or a list of them, layered underneath the ‘env:’ beside it. A later file wins over an earlier one, and a declared ‘env:’ value wins over both. A missing file is skipped with a line in the log, never an error - .env is the one file nobody commits. | |
plugins |
plugins | File-local plugin names: define ‘uses:’ and default args once here, then reference the bare name from any task’s ‘uses:’. Swapping what a name means stays a one-line change instead of a find-and-replace across every task that says it. | |
tasks |
object |
The tasks, keyed by id. The id is how a ‘needs:’ names one, and the name shown when a task declares no ‘name:’. |
A task
A task. A plain string is shorthand for ‘run:’ in the OS default shell.
| Key | Type | Default | What it does |
|---|---|---|---|
name |
string |
Shown in the panel and the tree. Defaults to the task’s id. | |
desc |
string |
One line on what this task is for, shown beside the name. | |
needs |
string | array |
Task ids that must finish first. A single id or a list of them - this is the only thing that orders a tasks.yml. | |
run |
string |
A command line, one-liner or block. Desugars to shell@1 with this as its script, so even the tersest task is a plugin call. Mutually exclusive with ‘uses:’. | |
uses |
string |
The plugin that runs this task: ‘id@version’ for a real one, or a bare name declared in this file’s ‘plugins:’. Mutually exclusive with ‘run:’. | |
args |
object |
Everything the plugin itself consumes. The task level is a closed set of engine keys, so anything the plugin reads belongs here. | |
shell |
pwsh | cmd | bash |
Which shell runs ‘run:’. Leave it out for whatever this OS provides - cmd on Windows, bash elsewhere. pwsh is never the default and must be named. | |
session |
string |
Names an AI conversation. Two tasks sharing a session name share one thread, so the second sees what the first reasoned. Means nothing for a task not backed by an AI plugin. | |
trigger |
auto | manual |
"auto" |
‘manual’ is a human gate: the run stops here until someone clicks Run. Nothing is executing while it waits, so closing the editor does not lose it. |
output |
string |
Stores what this task produced as a run variable of this name, for a later task to read as ‘${{ run.context.NAME.key }}’. A plugin declaring exactly one output is read as ‘${{ run.context.NAME }}’ directly. | |
if |
string | boolean | number |
Runs this task only when the condition holds. A false condition is a skip, not a failure - the run carries on. | |
continueOnError |
boolean |
Let the run carry on past this task’s failure. It is still reported as Failed, never repainted green. | |
timeout |
number | string |
How long this task gets. A bare number means seconds; ‘500ms’, ’30s’, ‘5m’ and ‘1h’ all read as what they are. | |
retries |
integer |
How many EXTRA attempts a failed task gets, so ‘retries: 1’ means two runs in total. | |
cwd |
string |
Where this task runs. Relative to the file’s own folder unless absolute; ‘${{ root }}’, ‘${{ workspace }}’ and ‘${{ cwd }}’ all resolve here. | |
vars |
vars | Template values, substituted into this file and going no further - nothing here is exported to a spawned process. Values keep their YAML type, so a number stays a number and a whole-value ‘${{ vars.retries }}’ hands over a real one. Resolution order is anchors, then vars, then env: a var may read a sibling var, never an env var. | |
env |
env | Environment variables exported to whatever this runs. Every value is coerced to text. Declare a value here only when something being run needs to read it; to merely use it inside this file, use ‘vars:’. | |
dotenv |
dotenv | One .env path, or a list of them, layered underneath the ‘env:’ beside it. A later file wins over an earlier one, and a declared ‘env:’ value wins over both. A missing file is skipped with a line in the log, never an error - .env is the one file nobody commits. |
Unknown keys are rejected: the task level is a closed set of engine
keys, and anything a plugin reads belongs under args:.
run: and uses: cannot both be present on one task.
Shared blocks
Referenced from more than one level. Declared at the top of the file, on a task, or both - the nearer one wins.
vars
Template values, substituted into this file and going no further - nothing here is exported to a spawned process. Values keep their YAML type, so a number stays a number and a whole-value ‘${{ vars.retries }}’ hands over a real one. Resolution order is anchors, then vars, then env: a var may read a sibling var, never an env var.
env
Environment variables exported to whatever this runs. Every value is coerced to text. Declare a value here only when something being run needs to read it; to merely use it inside this file, use ‘vars:’.
dotenv
One .env path, or a list of them, layered underneath the ‘env:’ beside it. A later file wins over an earlier one, and a declared ‘env:’ value wins over both. A missing file is skipped with a line in the log, never an error - .env is the one file nobody commits.
Accepts string or array.
plugins
File-local plugin names: define ‘uses:’ and default args once here, then reference the bare name from any task’s ‘uses:’. Swapping what a name means stays a one-line change instead of a find-and-replace across every task that says it.
Each entry:
| Key | Type | Default | What it does |
|---|---|---|---|
uses (required) |
string |
A real plugin ref, ‘id@version’. An alias may not point at another alias - a bare name is what tells the two apart where they are used. | |
args |
object |
Default args for every task referencing this name. A task’s own args win: the alias is a default, not an override. |
Unknown keys are rejected.
templateOrFile
A whole-value ‘${{ }}’ expression, or a file input that resolves to the document’s text. Both have no type until the run resolves them.
Accepts string.
Reads a document before the plugin runs. Required by default, so a task whose document is missing fails with the path named.
| Key | Type | Default | What it does |
|---|---|---|---|
file (required) |
string |
The path, which may itself hold ‘${{ }}’ templates. | |
optional |
boolean |
false |
Whether a missing file is acceptable, resolving to an empty string instead of failing. |
Unknown keys are rejected.
Plugin args
What each built-in plugin consumes under args:. The uses: value is
what binds a task to one of these.
uses: ai@1
AI agent - Runs an agent session on whichever provider the task names. It reads, writes and works in the repo - put a gate on a later task if you want to review before anything downstream runs. Args ai@1 does not declare are handed to the provider as written, so the runtime’s own session options - availableTools, excludedTools, mcpServers, systemMessage - are usable here under their own names.
| Key | Type | Default | What it does |
|---|---|---|---|
prompt (required) |
string |
What to ask the agent to do. | |
provider |
string |
"ghcp" |
Which agent runtime the session runs on. The vendor is named here and nowhere else, so swapping one is this line. Only providers registered by this build are accepted - a name this build does not know fails saying which ones it does. |
model |
string |
Model to run the session with. Meaning is the provider’s; this task passes it through. | |
context |
object |
Named documents laid into the session before the prompt, keyed by name - usually file args, e.g. { requirements: { file: specs/requirements.md } }. This is the whole context the session starts from: what is not named here, the session has not seen. | |
attachments |
array |
Files the session may open, as [{ path, name }]. Paths are absolute and need not be inside the working directory. Unlike ‘context’, which pastes content into the prompt, an attachment is a file the agent reads when it needs it - use it for instruction files and documents that would otherwise dominate the prompt. | |
detach |
boolean |
Deliver the prompt and return the session’s id without waiting for the turn - for a conversation a person is going to join in the editor. The agent still does the work; the engine holds the session until it goes idle. Nothing is reported and ‘target’ is not checked, because at the moment the task returns nothing has happened yet. | |
target |
string |
The file this session is expected to produce, relative to the working directory. The path is told to the agent, and the task fails if the session ends without the file on disk - the task’s honesty is the file, not the agent’s word. | |
title |
string |
A short human title, sent as the prompt’s first line. Chat histories name a session by its opening text - without this, a session shows up as its first context delimiter. |
Every arg above also accepts a whole-value ${{ }} expression or a templateOrFile { file: ... } input.
uses: file@1
Read or write a file - Reads a file into a run variable, or writes one from a value. The ‘executes’ half of AI proposes, a human approves, a plugin executes.
| Key | Type | Default | What it does |
|---|---|---|---|
operation (required) |
read | write | mkdir |
What to do with the path. | |
path (required) |
string |
Relative to the workspace unless absolute. | |
content |
string |
What to write. Required when writing, ignored when reading. | |
createDirectories |
boolean |
true |
Create the parent folders when writing, rather than failing on a missing one. |
Every arg above also accepts a whole-value ${{ }} expression or a templateOrFile { file: ... } input.
Unknown args are rejected.
uses: pwsh@1
PowerShell - Runs an inline PowerShell script or a .ps1 file.
| Key | Type | Default | What it does |
|---|---|---|---|
script |
string |
Inline PowerShell to run. Mutually exclusive with ‘file’. | |
file |
string |
Path to a .ps1 file, relative to the task’s working directory. | |
additionalArgs |
string |
Arguments appended when running ‘file’, e.g. -Name “World”. | |
shell |
pwsh |
‘pwsh’ - the only value this task accepts. A task that wants cmd wants a ‘run:’ task. | |
errorActionPreference |
default | stop | continue | silentlyContinue |
"stop" |
Prepended as $ErrorActionPreference. ‘stop’ makes a failing cmdlet fail the task - without it a cmdlet error only writes to stderr and the task still passes. |
progressPreference |
default | stop | continue | silentlyContinue |
"silentlyContinue" |
Prepended as $ProgressPreference. Left at ‘silentlyContinue’ so progress bars do not spray control characters into the log. |
failOnStderr |
boolean |
false |
Fail the task if anything is written to stderr, even when it exits zero. |
ignoreExitCode |
boolean |
false |
Report a non-zero exit without failing the task. |
Every arg above also accepts a whole-value ${{ }} expression or a templateOrFile { file: ... } input.
Unknown args are rejected.
uses: shell@1
Shell - Runs a command line through the OS shell - what a task’s run: desugars to.
| Key | Type | Default | What it does |
|---|---|---|---|
script (required) |
string |
The command line to run. | |
shell |
pwsh | cmd | bash |
Which shell runs it. Absent means whatever this OS provides by default - cmd on Windows, bash elsewhere. pwsh must be named explicitly. |
Every arg above also accepts a whole-value ${{ }} expression or a templateOrFile { file: ... } input.
Unknown args are rejected.