Writing a Workflow and its prompts
Rules for a Workflow file and the prompts of its agent Steps, which run with no human to answer a question.
A Workflow is a TOML file in .vago/workflows/, named by its file, listing the Steps every Ticket goes through. Every key it takes is on Workflows. Vago decides how a Workflow runs; the Project decides what its Steps do.
The Workflow
- Start from a copy of a starter,
small.tomlortry-hard.toml, under a new name.vago updateoverwrites the starter files that differ from Vago’s, so a changed starter loses its changes. - Put the git work in Steps. Vago cuts
vago/<goal>and nothing else. Branching per Ticket, committing, merging, pushing and the PR are shell Steps or prompt instructions, or they don’t happen. - Make every shell Step safe to run twice. A stuck Ticket is picked up at the Step it stopped on, and a shell Step runs its command again from the start. Check before you create, push or post, as the starter’s
branch.sh,merge.shandready.shdo. - A shell Step that exits non-zero makes the Ticket stuck, unless it has
on_fail = "continue". Use that for a check whose failure a later agent Step reads and fixes through{{steps.<id>.output}}. - Shell Steps are never retried; agent Steps are retried three times, by resuming the same session.
- Ids are for files, names are for people.
idappears in logs, Ticket headers and{{steps.<id>.output}}, and must be unique acrossbefore_all,stepsandafter_all. Don’t change anidwhile a Ticket is stuck on it.nameis what the TUI shows and is safe to change. when = "last-ticket"runs a Step only on the Ticket that starts with every other Ticketdone.before_allandafter_allhold Goal Steps, which run once per Goal in its worktree, with no Ticket. Their prompts may not read{{ticket}}.after_allruns again whenever a Ticket was added since its last pass, so a Goal Step that mustn’t repeat checks for itself.- Set
harnessandmodeltogether. A model belongs to one Harness:claude-codeorcodex. A Step that sets its ownharnesssets its ownmodel, and its ownargswhen the Workflow has any. - Never put a flag that turns a Harness’s guard off in
args. Vago runs Claude Code in itsautopermission mode and Codex in itsworkspace-writesandbox, and a refused tool call ends the Steppermission-denied. - Check it before anyone runs it:
vago goal new --workflow <name>refuses a Workflowvago runwould refuse, naming the file and the problem.
Shell Steps get $VAGO_GOAL, $VAGO_PROJECT_ROOT, and for a Ticket $VAGO_TICKET and $VAGO_LAST_TICKET.
The prompts
A prompt is a Markdown file under .vago/, named by the Step’s prompt. The session that reads it works alone until it ends.
- Say what done means. The agent can’t ask; it stops when it thinks it’s finished. End each part with a “Done when” the agent can check, like “
bun run checkexits zero on a clean tree”. - Say where it works and what it leaves. The branch that is checked out, whether to commit, and that the tree ends clean when a later shell Step merges.
- Name only the texts it needs:
{{goal}},{{ticket}},{{goal_name}}and{{steps.<id>.output}}, the last only for a Step earlier in the same list. A prompt gets nothing it doesn’t name. - Ask for the output later Steps read. An agent Step’s output is its session’s final answer. A Step whose output a review reads asks for a short report with fixed headings.
- Point to the Project’s docs instead of copying them. Name them, or attach them with
include, which appends whole files under a heading after the placeholders are filled. - Load skills by name, like “Run the
vago-write-codeskill”.vago initinstalls the starter skills for both Harnesses, so a prompt works on either. - Don’t tell the agent to mark the Ticket done or edit
.vago-goals/. Vago sets status, and only Vago writes a header.
Where changes take effect
Vago reads each Workflow, its prompts and include files once, when vago run starts. A Goal’s worktree holds a copy of the main checkout’s .vago/, which git there won’t stage. So change .vago/ in the main checkout, between runs; a change an agent makes to .vago/ inside a Goal’s worktree never reaches a commit or a run.