pi-taskflow 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -3
- package/extensions/agents.ts +47 -0
- package/extensions/index.ts +20 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
<a href="https://www.npmjs.com/package/pi-taskflow"><img src="https://img.shields.io/npm/dm/pi-taskflow?style=flat-square&color=6E8BFF&label=downloads" alt="npm downloads"></a>
|
|
8
8
|
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-43D9AD?style=flat-square" alt="MIT license"></a>
|
|
9
9
|
<a href="#whats-inside"><img src="https://img.shields.io/badge/runtime%20deps-0-43D9AD?style=flat-square" alt="zero runtime dependencies"></a>
|
|
10
|
-
<a href="
|
|
10
|
+
<a href="https://github.com/heggria/pi-taskflow/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/heggria/pi-taskflow/ci.yml?branch=main&style=flat-square&label=CI" alt="CI status"></a>
|
|
11
|
+
<a href="#whats-inside"><img src="https://img.shields.io/badge/tests-394-6E8BFF?style=flat-square" alt="394 tests"></a>
|
|
12
|
+
<a href="#whats-inside"><img src="https://img.shields.io/badge/dogfooded-%E2%9C%93-43D9AD?style=flat-square" alt="dogfooded"></a>
|
|
11
13
|
<a href="https://pi.dev"><img src="https://img.shields.io/badge/for-Pi%20coding%20agent-B692FF?style=flat-square" alt="for the Pi coding agent"></a>
|
|
12
14
|
</p>
|
|
13
15
|
|
|
@@ -574,7 +576,7 @@ Copy one into `.pi/taskflows/<name>.json` (or `~/.pi/agent/taskflows/`) and it r
|
|
|
574
576
|
|
|
575
577
|
<div align="center">
|
|
576
578
|
|
|
577
|
-
**0 runtime dependencies** · **
|
|
579
|
+
**0 runtime dependencies** · **394 tests** · **10 phase types** · **cross-session resume** · **cross-run memoization** · **~4.9k LOC runtime**
|
|
578
580
|
|
|
579
581
|
</div>
|
|
580
582
|
|
|
@@ -583,7 +585,21 @@ Copy one into `.pi/taskflows/<name>.json` (or `~/.pi/agent/taskflows/`) and it r
|
|
|
583
585
|
- **Hardened by design.** Path-traversal defense (lexical + `realpath`), runId validation, HTML/error sanitization, atomic writes, stale-lock stealing via `rename`, and an idle watchdog that kills wedged subagents.
|
|
584
586
|
- **Dogfooded.** Every new feature has to survive the project's own `self-improve` taskflow before it ships.
|
|
585
587
|
|
|
586
|
-
|
|
588
|
+
## 🍽️ We eat our own dog food
|
|
589
|
+
|
|
590
|
+
Every feature in `pi-taskflow` ships **through `pi-taskflow`.**
|
|
591
|
+
|
|
592
|
+
Our `self-improve` flow is a 10-phase DAG — it audits the codebase, patches defects, verifies correctness, gates on quality, and surfaces the report — all declaratively. It's saved as `/tf:self-improve` and run before every release. No other agent orchestrator in the Pi ecosystem builds itself with itself.
|
|
593
|
+
|
|
594
|
+
| Campaign | Scale | Phases | Outcome |
|
|
595
|
+
|----------|-------|--------|---------|
|
|
596
|
+
| [v0.0.8 dogfood](./docs/dogfooding-v0.0.8-report.md) | Full codebase audit → triage → fix → verify | 10 phases, 234 tests | 13 fixes, all pass |
|
|
597
|
+
| [v0.0.6 self-audit](./docs/self-audit-report.md) | inventory → map audit → gate → approval → map fix → reduce | 9 phases | 11 critical defects fixed |
|
|
598
|
+
| [Cross-run cache dogfood](./docs/rfc-cross-run-memoization.md) | Real runtime + on-disk store | Dedicated test harness | Cache correctness under adversarial fingerprints |
|
|
599
|
+
| [Adversarial cross-review](./docs/brainstorm-adversarial-review-report.md) | Multi-agent adversarial review | `tournament` + `gate` | P0 cache-key fix shipped |
|
|
600
|
+
| [Init redesign review](./docs/issue-necessity-review-report.md) | Necessity audit → parallel checks → verdict | 7 phases | Full redesign plan validated |
|
|
601
|
+
|
|
602
|
+
> **Meta:** we used `pi-taskflow`'s `map` fan-out, `gate` verdicts, `approval` human-in-the-loop, `tournament` best-of-N, `loop` until-done, and `cross-run` cache — to build `pi-taskflow`.
|
|
587
603
|
|
|
588
604
|
## Status & limits
|
|
589
605
|
|
package/extensions/agents.ts
CHANGED
|
@@ -208,3 +208,50 @@ export function readSubagentSettings(): SubagentSettings {
|
|
|
208
208
|
return {};
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Copy the 18 built-in agents from extensions/agents/*.md into the project's
|
|
214
|
+
* .pi/agents/ directory so Pi's native subagent tool (and any other extension)
|
|
215
|
+
* can discover them. taskflow's own discoverAgents() already reads from this
|
|
216
|
+
* directory with lower priority than built-in, so the copy is a no-op for
|
|
217
|
+
* taskflow phases — it only matters for Pi's native agent discovery.
|
|
218
|
+
*
|
|
219
|
+
* Idempotent: only copies agents whose built-in source is newer than the
|
|
220
|
+
* project copy (or that don't exist yet).
|
|
221
|
+
*/
|
|
222
|
+
export function syncBuiltinAgentsToProject(cwd: string): void {
|
|
223
|
+
const builtInDir = path.resolve(import.meta.dirname, "agents");
|
|
224
|
+
if (!fs.existsSync(builtInDir)) return;
|
|
225
|
+
|
|
226
|
+
const projectAgentsDir = path.join(cwd, ".pi", "agents");
|
|
227
|
+
fs.mkdirSync(projectAgentsDir, { recursive: true });
|
|
228
|
+
|
|
229
|
+
let entries: fs.Dirent[];
|
|
230
|
+
try {
|
|
231
|
+
entries = fs.readdirSync(builtInDir, { withFileTypes: true });
|
|
232
|
+
} catch {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
for (const entry of entries) {
|
|
237
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
238
|
+
const src = path.join(builtInDir, entry.name);
|
|
239
|
+
const dst = path.join(projectAgentsDir, entry.name);
|
|
240
|
+
|
|
241
|
+
let srcMtime = 0;
|
|
242
|
+
try { srcMtime = fs.statSync(src).mtimeMs; } catch { continue; }
|
|
243
|
+
|
|
244
|
+
let dstMtime = 0;
|
|
245
|
+
try { dstMtime = fs.statSync(dst).mtimeMs; } catch { /* dst doesn't exist yet */ }
|
|
246
|
+
|
|
247
|
+
// Only copy when the source is newer (or the destination is missing).
|
|
248
|
+
if (srcMtime <= dstMtime) continue;
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
const content = fs.readFileSync(src, "utf-8");
|
|
252
|
+
fs.writeFileSync(dst, content, "utf-8");
|
|
253
|
+
} catch {
|
|
254
|
+
// Best-effort: a locked file must not block the sync.
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
package/extensions/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
runInteractiveInit,
|
|
25
25
|
} from "./init.ts";
|
|
26
26
|
import { Type } from "typebox";
|
|
27
|
-
import { type AgentScope, discoverAgents, readSubagentSettings } from "./agents.ts";
|
|
27
|
+
import { type AgentScope, discoverAgents, readSubagentSettings, syncBuiltinAgentsToProject } from "./agents.ts";
|
|
28
28
|
import { renderRunResult, summarizeRun } from "./render.ts";
|
|
29
29
|
import { RunHistoryComponent, type RunHistoryResult } from "./runs-view.ts";
|
|
30
30
|
import { executeTaskflow, type ApprovalDecision, type ApprovalRequest, type RuntimeResult } from "./runtime.ts";
|
|
@@ -255,6 +255,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
255
255
|
pi.on("session_start", async (_e, ctx) => {
|
|
256
256
|
registerSavedFlowCommands(ctx);
|
|
257
257
|
|
|
258
|
+
// Sync built-in agents into .pi/agents/ so Pi's native subagent tool
|
|
259
|
+
// (and any other extension) can discover them — taskflow's
|
|
260
|
+
// extensions/agents/ directory is invisible to the rest of Pi.
|
|
261
|
+
try {
|
|
262
|
+
syncBuiltinAgentsToProject(ctx.cwd);
|
|
263
|
+
} catch {
|
|
264
|
+
// Best-effort: a locked or readonly .pi/ directory must not block
|
|
265
|
+
// session startup.
|
|
266
|
+
}
|
|
267
|
+
|
|
258
268
|
// Hint: prompt to configure model roles if not set
|
|
259
269
|
try {
|
|
260
270
|
const settings = readSubagentSettings();
|
|
@@ -272,20 +282,19 @@ export default function (pi: ExtensionAPI) {
|
|
|
272
282
|
name: "taskflow",
|
|
273
283
|
label: "Taskflow",
|
|
274
284
|
description: [
|
|
275
|
-
"Orchestrate
|
|
276
|
-
"
|
|
277
|
-
"
|
|
278
|
-
"
|
|
279
|
-
"Use action=
|
|
280
|
-
"
|
|
281
|
-
"Phase types: agent (one subagent), parallel (static branches), map (dynamic fan-out over an array), gate (VERDICT: PASS/BLOCK quality gate), reduce (aggregate from N phases), approval (human-in-the-loop pause), flow (run a saved sub-flow), loop (re-run a task until 'until' is truthy / converged / maxIterations; body reads {loop.iteration} and {loop.lastOutput}), tournament (spawn N variants of 'task' — or distinct 'branches' — then a judge picks the best / aggregates; mode:'best'|'aggregate'). join:'any' is an OR-join; when is a conditional guard; retry adds backoff; budget caps run cost.",
|
|
285
|
+
"Orchestrate subagents — the ONLY delegation tool. Fully replaces the built-in subagent tool.",
|
|
286
|
+
"Shorthand (same API as subagent): pass `task` (+optional `agent`) for one task, `tasks:[{task,agent?}]` for parallel, or `chain:[{task,agent?}]` for sequential (use {previous.output}).",
|
|
287
|
+
"DSL: use action=run with an inline `define` (you write the DAG) or a saved `name`. Phases (agent, parallel, map, gate, reduce, approval, flow, loop, tournament) form a DAG; intermediate outputs stay out of your context — only the final phase output is returned.",
|
|
288
|
+
"Every delegation is tracked (runId), resumable across sessions, and saveable as /tf:<name> via action=save.",
|
|
289
|
+
"Use action=agents to list the 18 built-in agents (executor, scout, planner, analyst, critic, reviewer, risk-reviewer, security-reviewer, plan-arbiter, final-arbiter, test-engineer, doc-writer, executor-code, executor-fast, executor-ui, recover, verifier, visual-explorer). Do NOT invent agent names.",
|
|
290
|
+
"Phase types: agent, parallel (static branches), map (dynamic fan-out over array), gate (VERDICT: PASS/BLOCK), reduce (aggregate from N), approval (human-in-the-loop), flow (run saved sub-flow), loop (iterate until condition/convergence/cap), tournament (N variants, judge picks best/aggregate).",
|
|
282
291
|
"Interpolation: {args.X}, {steps.ID.output}, {steps.ID.json}, {item} (map), {previous.output}.",
|
|
283
292
|
].join(" "),
|
|
284
293
|
parameters: TaskflowParams,
|
|
285
|
-
promptSnippet: "Orchestrate
|
|
294
|
+
promptSnippet: "Orchestrate subagents — single, parallel, chain, or DAG — with tracking, resume, and context isolation. Replaces the subagent tool.",
|
|
286
295
|
promptGuidelines: [
|
|
287
|
-
"
|
|
288
|
-
"
|
|
296
|
+
"Use taskflow for ALL delegation — single tasks, parallel, chain, or full DAG orchestration. It fully replaces the subagent tool: every delegation is tracked with a runId, resumable across sessions, context-isolated (only final output returns), and saveable as /tf:<name>. Do NOT call the subagent tool directly; use taskflow shorthand (task/tasks/chain) for simple cases instead.",
|
|
297
|
+
"For complex multi-phase work (explore / 审计 / analyze the project, auditing endpoints, reviewing or migrating many files/modules, cross-checked research), use the full DSL with phases. For taskflow map phases, have the upstream phase emit a JSON array and set output:'json'.",
|
|
289
298
|
"For taskflow map phases, have the upstream phase emit a JSON array and set output:'json'.",
|
|
290
299
|
],
|
|
291
300
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-taskflow",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Lightweight workflow orchestration for the Pi coding agent — declarative multi-phase taskflows with dynamic fan-out, isolated subagent context, resumable runs, and saveable commands.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|