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.

  1. tasks.yml
    1. Top-level keys
    2. A task
    3. Shared blocks
      1. vars
      2. env
      3. dotenv
      4. plugins
      5. templateOrFile
    4. Plugin args
      1. uses: ai@1
      2. uses: file@1
      3. uses: pwsh@1
      4. uses: shell@1

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.


Back to top

Local Workflows is a VS Code extension. Everything it does is declared in a YAML file you own.