Pi Extensible Workflows: Full Guide

Pi Extensible Workflows: Putting the Loop Back in Code

Asking a model to "keep going until the tests pass" makes the model responsible for the loop โ€” and models forget, and models cheat. This extension moves the control flow into a small DSL, keeps the sub-agent output out of your context window, and makes cleanup deterministic again.

Video thumbnail
๐Ÿ“บ Andrea Baccega โฑ๏ธ 28:11 ๐Ÿ“… 25 July 2026
Pi Workflow DSL Multi-agent Context engineering Determinism TypeScript

๐Ÿ” Who is responsible for the loop 2:44

The clearest argument in the video arrives early, and it is worth stating plainly because it generalises well beyond Pi.

Suppose you have just done a large refactor and a pile of tests are broken. The familiar approach is a /go-style command: ask the main model to keep working until everything is green. That works โ€” sometimes. But it places responsibility for the termination condition on the model.

"The main model might forget it, might want to cheat about it, might want to do a lot of things."

The alternative is unglamorous and much more reliable: write a loop. A bounded number of attempts, with an exit condition that is a shell command returning zero.

// the exit condition is a fact, not a judgement
until (shell("yarn test").exitCode === 0) { ... }   // bounded attempts
The distinction being drawn is between probabilistic and deterministic work. "Did the tests pass?" has a correct answer that a process exit code already knows. Asking a language model to assess it introduces a failure mode โ€” self-assessment โ€” for no benefit. The model should do the part that requires judgement; the loop should be code.

๐Ÿง  Two problems, one mechanism 4:15

The second motivation is about context, and it is the one experienced agent users will feel most immediately.

With ordinary sub-agents, work fans out and the results come back into the main agent's context window. Every intermediate finding, every retry, every verbose tool result accumulates in the one place you most need to stay clean. Under this model, sub-agent output does not return to the caller โ€” only a summary does.

Classic sub-agentsWorkflow
Control flowMain model decides what to spawn nextScript decides โ€” a small DSL
ResultsLand in the main context windowStay in the workflow; only a summary returns
TerminationModel judges when it is doneExit code, or a bounded retry count
System promptWhatever the main agent carriesNarrow, per-role, with tools disabled

The author is careful to credit the origin: the pattern was published by the Claude Code team in May, and he describes it as a good concept rather than a novel one. What his extension adds is extensibility โ€” other extensions can register new functions into the same DSL.

โš™๏ธ The workflow in production 5:00

The demonstration is the extension developing itself, which is the right kind of evidence โ€” five agents running against his own open GitHub issues.

His actual working loop: dump an idea or a bug into a GitHub issue, then trigger everything with one sentence โ€” "develop issues until approved of all the currently ready". He notes he did not even say GitHub issues; the agent found the capability through a discovery tool that exposes registered functions.

The develop-until-approved pattern

This is the part worth stealing. Two different models in defined roles:

  1. A developer model implements the issue
  2. A reviewer model assesses the result
  3. If the reviewer rejects, its findings are fed back to the developer, which retries
  4. Bounded by a maximum iteration count โ€” five in his configuration
Why two models rather than one model reviewing itself: a model asked to check its own work shares the blind spots that produced the work. Separating the roles โ€” and using different models with different training โ€” makes the review an independent check rather than a second opinion from the same source. The bounded retry count is what stops it becoming an infinite argument.

Each parallel subtask opens its own git worktree, so agents working simultaneously do not collide. A merge phase then runs the same develop-until-approved loop with a different task: merge all the worktrees together.

๐Ÿงน Deterministic cleanup 7:22

After the merge comes a cleanup step, and the author is emphatic that this one is not an agent. It is plain code: run git merge-base --is-ancestor, confirm the work actually landed in main, then remove the worktree.

"It makes no point to spin up another agent to do this kind of cleanup phase. We have the tools to do that."
This is the thesis applied consistently. "Was this branch merged?" is answerable by git with certainty. Delegating it to a language model would add cost, latency and a chance of being wrong, in exchange for nothing. The discipline being modelled is knowing which questions have deterministic answers โ€” and it is a discipline most agent architectures abandon the moment an agent is available.

Then a summary phase: what succeeded, what failed review, what was tested, the per-issue results and the merge outcome. That summary is the only thing that reaches the main agent's context. Everything else โ€” every retry, every reviewer rejection โ€” stays inside the workflow.

๐Ÿ““ The journal 11:55

Runs can be paused, stopped and resumed, because every step is written to a journal. If a run exits, it can be re-launched and completed work is not repeated โ€” effectively cached.

For debugging there is a genuinely nice affordance: you can take any agent inside a run and fork it as a Pi session. So if you want to know why the reviewer rejected something, you open that reviewer's session and read the prompt it was given and everything it did.

This addresses the standard objection to multi-agent systems โ€” that they are opaque, and when one produces a bad result you cannot find out why. A per-agent forkable transcript turns the run from a black box into something you can inspect after the fact. For anyone evaluating whether to trust this class of tooling, that matters more than the orchestration features.

๐Ÿงฉ The DSL 16:22

The primitive set is deliberately small. Rather than paraphrase the video, here is the contract as it appears in the project's own source:

Verbatim from packages/core/src/workflow-evals.ts:

"agent(prompt, options) delegates; shell(command, options) runs a deterministic host command and returns exitCode/stdout/stderr; parallel(name, tasks) runs independent tasks concurrently; pipeline(name, items, stages) applies ordered stages; prompt(template, data) carries values into prompts. A role owns model/thinking/tools policy."
PrimitivePurpose
agent()Delegate to a model with a prompt and options
shell()Run a host command โ€” returns exit code, stdout, stderr
parallel()Run independent tasks concurrently
pipeline()Apply ordered stages over items
prompt()Interpolate data from a previous step into a prompt
phase()Label a stage for reporting
checkpoint()Pause for external approval
withWorkTree()Isolate a task in its own git worktree

That is the whole vocabulary โ€” and the point is what surrounds it. Because workflows are JavaScript, you get loops, conditionals and functions for free. The DSL only supplies the agent-shaped verbs; the language supplies the control flow.

Workflows can also declare a JSON schema for their output, so a workflow returns structured data to its caller rather than prose. And functions are composable: developUntilApproved(task, maxIterations) is itself defined in terms of these primitives, then registered for reuse.

The TDD example makes the composition concrete: one agent writes a failing test, a second makes it pass, with the yarn test exit code as the gate between them.

๐ŸŽญ Roles and the system prompt 20:00

Roles are the part the author considers most distinctive, and the reasoning is more interesting than the feature.

A role file binds a model alias, a tool policy and a description. A summarizer role, for instance, has no tools at all โ€” it summarises, so it needs none. A developer role has the question tool removed, because a developer agent is meant to have all its context up front and should not be stopping to ask the human questions.

Removing a tool is not only about preventing an action. Every available tool occupies system-prompt tokens and widens the space of things the model might do instead of the task. Taking tools away makes the agent cheaper and more focused โ€” the second effect being the one that matters.

The same logic extends to skills and extensions: he disables the ones irrelevant to a run so they never reach the system prompt at all.

The reported result: a 50% reduction in system prompt size for workflow runs. His own framing of the trade is admirably unhyped โ€” "you pay less, but we are talking peanuts here" โ€” the real gain being that "the model is very sharp and focused only on the task because you removed all the noise".

Role descriptions land in the main agent's system prompt, so the main LLM can choose the appropriate role the way it would select a skill.

๐Ÿ’ฐ Budgets and guard rails 15:40

Autonomous multi-agent runs can spend a lot without asking, so run budgets accept caps on time, tokens or cost โ€” with a two-stage response:

CapBehaviour
SoftInjects a message into running agents: wrap up, we are running out of quota
HardTruncates the work and stops entirely

The soft cap is the thoughtful one. A hard stop mid-task leaves partial work in an unknown state; giving agents a chance to conclude cleanly usually leaves something recoverable.

Other controls: a global concurrency limit, and a doctor command that validates roles, tools and exclusion lists โ€” because a typo in a tool exclusion list otherwise halts execution at run time rather than at configuration time.

๐Ÿ“ฆ Bundling workflows as binaries 25:45

The closing demonstration is the most forward-looking part: a workflow bundled into a binary that takes a plain prompt โ€” in his example, planning a trip to Rome โ€” and runs an extraction phase followed by parallel research phases for experiences, food and logistics.

The argument he builds around it is the one worth carrying away. Imagine a travel agency doing this daily. Some steps genuinely need a model. Others โ€” looking up hotels, hitting a booking API โ€” should be real code, for two reasons:

  • Accuracy: feeding API results into the agent stops it hallucinating the facts
  • Credentials: the authenticated calls stay in code, so secrets never enter a prompt
That second point deserves more attention than it gets in the video. "Keep the credentials in the code path, not in the agent's context" is a security property, not a convenience. Anything in a prompt can end up in a log, a transcript, or a summary that reaches another model. A workflow that calls authenticated APIs from deterministic code and passes only results to the agent has a materially smaller exposure surface than one that hands an agent a key.

He is candid that this is exploratory โ€” "I can't bundle some stuff" โ€” and frames it as a new concept for mixing JavaScript and agent workflows in one distributable artefact.

๐Ÿ“ Where it stands 27:50

The author is repeatedly clear that this is under very active development, that he is still experimenting with what belongs in role prompts, and that features are in flux. That honesty is worth matching with some context on maturity.

SignalValue
Repositoryvekexasia/pi-extensible-workflows, TypeScript
Created12 July 2026 โ€” about two weeks before the video
Stars / forks79 / 8
LicenceNone โ€” no LICENSE file in the repository
AuthorAndrea Baccega, GitHub since 2010, 103 public repos
The missing licence is the practical blocker, and the video does not mention it. A public repository with no LICENSE file grants no rights under default copyright โ€” no permission to use, modify or redistribute. For experimenting on your own machine this is a formality most people ignore. For anything touching work, it is the first thing to resolve, and it looks like an oversight on a two-week-old project rather than intent. Worth an issue.

The tooling maturity signals are otherwise good: a test suite covering workflow evaluation, a doctor validation command, journal-based resumability, and an author using it daily on his own project โ€” which is the most honest form of dogfooding available.

๐Ÿ” Claims checked

Verified against the GitHub API and the project source rather than the narration:

ClaimResult
Repository is vekexasia/pi-extensible-workflowsConfirmed โ€” TypeScript, 124 files
Actively developedCreated 12 Jul 2026, pushed 28 Jul 2026 โ€” 16 days old
DSL primitives: agent, shell, parallel, pipeline, prompt, phaseDocumented verbatim in workflow-evals.ts; phase() found in source
A role owns model / thinking / tools policyStated word-for-word in the same source file
shell() returns exit code, stdout, stderrConfirmed in the DSL contract
Workflow pattern originated with the Claude Code teamCredited by the author himself, not claimed as novel
Author is experiencedAndrea Baccega โ€” GitHub since 2010, 103 public repos
~50% system prompt reductionThe author's own measurement on his own configuration โ€” plausible, not independently verifiable
Open sourceNo LICENSE file. Public, but no rights granted by default
What cannot be checked from outside: the reliability of develop-until-approved in practice, how often the reviewer catches real problems versus generating churn, and whether the retry ceiling is well calibrated. Those need mileage, and at sixteen days old nobody has it yet โ€” including, by his own admission, the author.

Repository state verified 28 July 2026. Star counts and file contents move.

๐Ÿ’ก Key takeaways

  1. Do not make the model responsible for the loop. "Keep going until the tests pass" delegates the termination condition to something that can forget or cheat. A bounded loop with an exit-code check cannot.
  2. Separate probabilistic work from deterministic work. "Did the tests pass?" and "was this branch merged?" have correct answers that git and the shell already know. Spending an agent on them adds cost and a chance of being wrong.
  3. Sub-agent output should not return to the caller. Classic fan-out dumps every intermediate result into the main context. Here only a summary comes back โ€” every retry and rejection stays inside the workflow.
  4. Two models beat one model reviewing itself. A developer role and a separate reviewer role, with findings fed back and a bounded retry count, makes review an independent check rather than a second opinion from the same blind spots.
  5. Cleanup stays code. git merge-base --is-ancestor answers the merge question with certainty. The author refuses to spend an agent on it, and that consistency is the whole argument in miniature.
  6. Isolation is per-worktree. Every parallel task gets its own git worktree, so concurrent agents cannot collide in the working directory.
  7. The journal makes runs resumable and inspectable. Pause, stop, resume without repeating completed work โ€” and fork any individual agent as a Pi session to read exactly what it was asked and what it did.
  8. That inspectability answers the usual objection to multi-agent systems. A per-agent transcript turns an opaque run into something you can audit after a bad result.
  9. The DSL is deliberately tiny. agent, shell, parallel, pipeline, prompt, phase, checkpoint, withWorkTree โ€” because workflows are JavaScript, the language already supplies loops and conditionals.
  10. Removing tools sharpens the model, not just the bill. The summarizer role has no tools; the developer role loses the question tool. Reported result: system prompt halved, and a model with less to be distracted by.
  11. Soft caps are better engineering than hard caps. Injecting "wrap up, quota is running out" lets agents finish cleanly; a hard stop leaves partial work in an unknown state.
  12. Keep credentials in code, not in prompts. The binary-bundling idea has authenticated API calls in deterministic code, passing only results to the agent โ€” a smaller exposure surface, and it also stops the model hallucinating facts it could look up.
  13. Structured output makes workflows composable. A JSON schema means a workflow returns data to its caller, not prose โ€” which is what allows developUntilApproved to be built from primitives and then reused as one.
  14. Check the licence before you adopt. The repository has no LICENSE file, which under default copyright grants no rights. Sixteen days old and almost certainly an oversight โ€” but it is the first thing to resolve for anything work-related.

๐Ÿ”— Resources & links

๐Ÿ• Timestamp index

0:00Intro and overview
1:00The workflow concept, credited to Claude's DSL
1:55Everything contained in a script
2:44Deterministic versus probabilistic
3:14The model might forget, or cheat
3:54Until yarn test exits zero
4:15Avoiding context window pollution
5:00Five agents on his own open issues
5:56Each subtask opens its own worktree
6:15Develop until approved โ€” two models
6:48Reviewer rejects, developer retries
7:22The merge phase
7:52Cleanup is not an agent โ€” it is code
9:05No point spinning up an agent for this
9:20Summary phase and what reaches the main agent
9:56Nothing leaks into the main context
11:00Triggering it all with one sentence
11:55Pause, resume, and the journal
12:45Forking any agent as a Pi session
13:40Global and project settings, concurrency
14:35Disabling resources and tools per role
14:49The developer role should not ask questions
15:40Run budgets โ€” soft and hard caps
16:22The workflow DSL primitives
17:16Checkpoint and withWorkTree
17:55The TDD loop example
19:05Structured output with JSON schema
20:00Role configuration and model aliases
20:50The summarizer role has no tools
21:50Role descriptions in the system prompt
23:20System prompt reduced by 50%
24:25Doctor, inspection and export
25:45Bundling a workflow into a binary
27:00Real API calls, and keeping credentials out
27:50Conclusion and repository