๐ 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 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
๐ง 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-agents | Workflow | |
|---|---|---|
| Control flow | Main model decides what to spawn next | Script decides โ a small DSL |
| Results | Land in the main context window | Stay in the workflow; only a summary returns |
| Termination | Model judges when it is done | Exit code, or a bounded retry count |
| System prompt | Whatever the main agent carries | Narrow, 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:
- A developer model implements the issue
- A reviewer model assesses the result
- If the reviewer rejects, its findings are fed back to the developer, which retries
- Bounded by a maximum iteration count โ five in his configuration
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.
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.
๐งฉ 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:
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."
| Primitive | Purpose |
|---|---|
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.
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.
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:
| Cap | Behaviour |
|---|---|
| Soft | Injects a message into running agents: wrap up, we are running out of quota |
| Hard | Truncates 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
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.
| Signal | Value |
|---|---|
| Repository | vekexasia/pi-extensible-workflows, TypeScript |
| Created | 12 July 2026 โ about two weeks before the video |
| Stars / forks | 79 / 8 |
| Licence | None โ no LICENSE file in the repository |
| Author | Andrea Baccega, GitHub since 2010, 103 public repos |
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:
| Claim | Result |
|---|---|
Repository is vekexasia/pi-extensible-workflows | Confirmed โ TypeScript, 124 files |
| Actively developed | Created 12 Jul 2026, pushed 28 Jul 2026 โ 16 days old |
| DSL primitives: agent, shell, parallel, pipeline, prompt, phase | Documented verbatim in workflow-evals.ts; phase() found in source |
| A role owns model / thinking / tools policy | Stated word-for-word in the same source file |
shell() returns exit code, stdout, stderr | Confirmed in the DSL contract |
| Workflow pattern originated with the Claude Code team | Credited by the author himself, not claimed as novel |
| Author is experienced | Andrea Baccega โ GitHub since 2010, 103 public repos |
| ~50% system prompt reduction | The author's own measurement on his own configuration โ plausible, not independently verifiable |
| Open source | No LICENSE file. Public, but no rights granted by default |
Repository state verified 28 July 2026. Star counts and file contents move.
๐ก Key takeaways
- 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.
- 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.
- 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.
- 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.
- Cleanup stays code.
git merge-base --is-ancestoranswers the merge question with certainty. The author refuses to spend an agent on it, and that consistency is the whole argument in miniature. - Isolation is per-worktree. Every parallel task gets its own git worktree, so concurrent agents cannot collide in the working directory.
- 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.
- 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.
- The DSL is deliberately tiny. agent, shell, parallel, pipeline, prompt, phase, checkpoint, withWorkTree โ because workflows are JavaScript, the language already supplies loops and conditionals.
- 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.
- 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.
- 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.
- Structured output makes workflows composable. A JSON schema means a workflow returns data to its caller, not prose โ which is what allows
developUntilApprovedto be built from primitives and then reused as one. - 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
- Pi Extensible Workflows: Full GuideSource video โ Andrea Baccega, 28:11
- vekexasia/pi-extensible-workflowsThe extension โ TypeScript, no licence file at time of writing
workflow-evals.tsWhere the DSL contract is stated verbatim in source- Open issuesHow the author actually drives his own workflow