codex-taskflow 0.1.5 → 0.1.6

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 heggria
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -3,14 +3,14 @@
3
3
  <img src="https://raw.githubusercontent.com/heggria/taskflow/main/assets/hero.png" alt="taskflow — a declarative, verifiable graph of task nodes for coding-agent subagents: stateful, resumable, context-isolated" width="900">
4
4
 
5
5
  <p>
6
- <a href="https://www.npmjs.com/package/pi-taskflow"><img src="https://img.shields.io/npm/v/pi-taskflow?style=flat-square&color=B692FF&label=npm" alt="npm version"></a>
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
- <a href="https://github.com/heggria/taskflow/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-43D9AD?style=flat-square" alt="MIT license"></a>
9
- <a href="#whats-inside"><img src="https://img.shields.io/badge/runtime%20deps-0-43D9AD?style=flat-square" alt="zero runtime dependencies"></a>
6
+ <a href="https://www.npmjs.com/package/pi-taskflow"><img src="https://img.shields.io/npm/v/pi-taskflow?style=flat-square&color=4B4ACF&label=npm" alt="npm version"></a>
7
+ <a href="https://www.npmjs.com/package/pi-taskflow"><img src="https://img.shields.io/npm/dm/pi-taskflow?style=flat-square&color=5A5D63&label=downloads" alt="npm downloads"></a>
8
+ <a href="https://github.com/heggria/taskflow/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-0E8A66?style=flat-square" alt="MIT license"></a>
9
+ <a href="#whats-inside"><img src="https://img.shields.io/badge/runtime%20deps-0-0E8A66?style=flat-square" alt="zero runtime dependencies"></a>
10
10
  <a href="https://github.com/heggria/taskflow/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/heggria/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-918-6E8BFF?style=flat-square" alt="918 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>
13
- <a href="#run-it-on-your-agent"><img src="https://img.shields.io/badge/runs%20on-Pi%20%2B%20Codex-B692FF?style=flat-square" alt="runs on Pi and Codex"></a>
11
+ <a href="#whats-inside"><img src="https://img.shields.io/badge/tests-1140-4B4ACF?style=flat-square" alt="1140 tests"></a>
12
+ <a href="#whats-inside"><img src="https://img.shields.io/badge/dogfooded-%E2%9C%93-0E8A66?style=flat-square" alt="dogfooded"></a>
13
+ <a href="#run-it-on-your-agent"><img src="https://img.shields.io/badge/runs%20on-Pi%20%2B%20Codex%20%2B%20Claude%20Code%20%2B%20OpenCode-4B4ACF?style=flat-square" alt="runs on Pi, Codex, Claude Code, and OpenCode"></a>
14
14
  </p>
15
15
 
16
16
  <p align="center">
@@ -18,9 +18,13 @@
18
18
  <a href="https://github.com/heggria/taskflow/blob/main/README.zh-CN.md">简体中文</a>
19
19
  </p>
20
20
 
21
+ <p align="center">
22
+ <a href="https://heggria.github.io/taskflow/en"><img src="https://img.shields.io/badge/📖_Read_the_docs-heggria.github.io%2Ftaskflow-4B4ACF?style=for-the-badge&labelColor=2D2F5A" alt="Read the docs — heggria.github.io/taskflow"></a>
23
+ </p>
24
+
21
25
  <p><strong>A declarative, verifiable <em>graph of tasks</em> for coding-agent subagents.</strong><br/>
22
26
  Not a workflow you script — a DAG you declare. Fan out · gate · loop · tournament · resume · save as a command — intermediate results stay out of your context.<br/>
23
- Runs on the <a href="https://pi.dev">Pi</a> coding agent and on <a href="https://github.com/openai/codex">OpenAI Codex</a>.</p>
27
+ Runs on the <a href="https://pi.dev">Pi</a> coding agent, on <a href="https://github.com/openai/codex">OpenAI Codex</a>, on <a href="https://claude.com/product/claude-code">Claude Code</a>, and on <a href="https://opencode.ai">OpenCode</a>.</p>
24
28
 
25
29
  </div>
26
30
 
@@ -31,13 +35,20 @@ pi install npm:pi-taskflow
31
35
  # Codex
32
36
  codex plugin marketplace add heggria/taskflow
33
37
  codex plugin add taskflow@taskflow
38
+
39
+ # Claude Code
40
+ claude plugin marketplace add heggria/taskflow
41
+ claude plugin install claude-taskflow@taskflow
42
+
43
+ # OpenCode — add the MCP server to opencode.json (see the OpenCode guide)
44
+ opencode mcp add taskflow -- npx -y -p opencode-taskflow opencode-taskflow-mcp
34
45
  ```
35
46
 
36
47
  ---
37
48
 
38
49
  **A `workflow` flows. A `taskflow` is a *graph*.** Other orchestrators let the model *script* the work — imperative code that flows step by step, with the graph hidden inside control flow. `taskflow` does the opposite: you **declare** the work as a graph of discrete, named **task** nodes connected by `dependsOn` edges — and the runtime *verifies that graph before it spends a single token.*
39
50
 
40
- You already know your agent's built-in subagent shorthand — `task` / `tasks` / `chain`. `taskflow` speaks the *same* shorthand — so your existing delegations instantly become **tracked, resumable, and saveable by name** (on Pi, a saved flow becomes a one-word `/tf:<name>` command; on Codex you run it by name through `taskflow_run`). When you outgrow the shorthand, the full DSL gives you a real DAG: dynamic fan-out over dozens of items, conditional routing, quality gates, human approvals, retries, loops, tournaments, and a hard spend ceiling.
51
+ You already know your agent's built-in subagent shorthand — `task` / `tasks` / `chain`. `taskflow` speaks the *same* shorthand — so your existing delegations instantly become **tracked, resumable, and saveable by name** (on Pi, a saved flow becomes a one-word `/tf:<name>` command; on Codex, Claude Code, and OpenCode you run it by name through `taskflow_run`). When you outgrow the shorthand, the full DSL gives you a real DAG: dynamic fan-out over dozens of items, conditional routing, quality gates, human approvals, retries, loops, tournaments, and a hard spend ceiling.
41
52
 
42
53
  And the whole time, **only the final phase reaches your conversation.** Every intermediate transcript stays in the runtime, never your context window.
43
54
 
@@ -173,6 +184,41 @@ codex plugin add taskflow@taskflow
173
184
 
174
185
  The plugin's MCP server runs via `npx` (a version-pinned `codex-taskflow`), so there's nothing else to install globally and the plugin version binds the exact code that runs. Then just ask Codex to run a multi-phase or fan-out job and it calls the tools. See the [Codex guide](https://github.com/heggria/taskflow/blob/main/docs/codex-mcp.md).
175
186
 
187
+ ### On Claude Code
188
+
189
+ taskflow ships as a Claude Code **plugin** too — install it once and the `taskflow_*` MCP tools plus a routing skill light up automatically, no manual `mcp add` and no config editing:
190
+
191
+ ```bash
192
+ claude plugin marketplace add heggria/taskflow
193
+ claude plugin install claude-taskflow@taskflow
194
+ ```
195
+
196
+ The plugin's MCP server runs via `npx` (a version-pinned `claude-taskflow`), so there's nothing else to install globally and the plugin version binds the exact code that runs. Each phase's subagent then runs as an isolated `claude -p` session. Just ask Claude Code to run a multi-phase or fan-out job and it calls the tools. See the [Claude Code guide](https://github.com/heggria/taskflow/blob/main/docs/claude-mcp.md).
197
+
198
+ ### On OpenCode
199
+
200
+ OpenCode reaches taskflow through the same MCP server. Register it once — either with the CLI or by adding an `mcp` entry to your `opencode.json`:
201
+
202
+ ```bash
203
+ opencode mcp add taskflow -- npx -y -p opencode-taskflow opencode-taskflow-mcp
204
+ ```
205
+
206
+ ```jsonc
207
+ // opencode.json
208
+ {
209
+ "$schema": "https://opencode.ai/config.json",
210
+ "mcp": {
211
+ "taskflow": {
212
+ "type": "local",
213
+ "command": ["npx", "-y", "-p", "opencode-taskflow", "opencode-taskflow-mcp"],
214
+ "enabled": true
215
+ }
216
+ }
217
+ }
218
+ ```
219
+
220
+ The server runs via `npx` (a version-pinned `opencode-taskflow`), and each phase's subagent runs as an isolated `opencode run` session. OpenCode also auto-discovers the bundled routing skill (`**/SKILL.md`). Then just ask OpenCode to run a multi-phase or fan-out job and it calls the tools. See the [OpenCode guide](https://github.com/heggria/taskflow/blob/main/docs/opencode-mcp.md).
221
+
176
222
  ### The shorthand (same shape as the built-in tool)
177
223
 
178
224
  ```jsonc
@@ -413,6 +459,46 @@ with the run — flows that don't opt in behave exactly as before.
413
459
  "task": "ctx_read 'endpoints' for shared context, then audit {item} for missing auth." }
414
460
  ```
415
461
 
462
+ ### Library: search before author
463
+
464
+ A flow that took work to generalize is an asset — but only if you can find it
465
+ again. Phase 1 of the **taskflow library** adds sidecar `.meta.json` metadata
466
+ (`purpose`, `tags`, `phaseSignature`, `generality`, `reuseCount`) to saved
467
+ flows, plus a search tool that surfaces reusable flows before you write a new
468
+ one:
469
+
470
+ ```jsonc
471
+ // MCP
472
+ { "name": "taskflow_search", "arguments": { "query": "audit API endpoints for missing auth" } }
473
+ // Pi tool
474
+ { "action": "search", "query": "审计接口鉴权" }
475
+ ```
476
+
477
+ Search is **structural + keyword** by default (zero dependencies, zero tokens):
478
+ `phaseSignature` (`agent→map→reduce`) and phase-count similarity are blended
479
+ with keyword overlap. It is **CJK-aware**, so a Chinese query like
480
+ `"检查接口安全性 鉴权 缺失"` still matches a purpose containing
481
+ `"审计...是否缺少鉴权检查"`. Embedding-based semantic search is Phase 2 —
482
+ the `embedder` seam is already in place and search degrades gracefully when it
483
+ is not configured.
484
+
485
+ When you run a flow you discovered via search, pass `reusedFromSearch: true`
486
+ (`taskflow_run` MCP, or `action=run` in Pi). That bumps the flow's
487
+ `reuseCount`, so high-quality reusable patterns rank higher over time. When you
488
+ write a new reusable flow, save it with metadata:
489
+
490
+ ```jsonc
491
+ { "name": "taskflow_save",
492
+ "arguments": {
493
+ "name": "audit-endpoints",
494
+ "definition": { ... },
495
+ "purpose": "Audit API endpoints for missing auth checks",
496
+ "tags": ["audit", "security", "auth"] } }
497
+ ```
498
+
499
+ See `docs/rfc-library-reuse.md` for the design and `skills-src/taskflow/library.md`
500
+ for the agent-facing search→reuse→generalize→re-save workflow.
501
+
416
502
  ### Control flow & reliability
417
503
 
418
504
  - **`when`** — skip a phase unless an expression is truthy. Supports `{refs}`, `== != < > <= >=`, `&& || !`, parentheses, and quoted strings/numbers. Pair with `join: "any"` on the merge phase for real if/else routing. Parse errors **fail open** (the phase runs — never silently dropped).
@@ -476,7 +562,7 @@ Not every step needs a model. A `script` phase runs a **shell command** directly
476
562
  {
477
563
  "id": "build",
478
564
  "type": "script",
479
- "run": "npm run build", // string → runs in a shell
565
+ "run": "pnpm run build", // string → runs in a shell
480
566
  "timeout": 120000 // optional ms cap (1000–300000, default 60000)
481
567
  },
482
568
  {
@@ -552,7 +638,7 @@ Condition grammar (for `when`): `== != < > <= >=`, `&& || !`, parentheses, quote
552
638
 
553
639
  ## Commands
554
640
 
555
- Saved flows become CLI shortcuts. **These `/tf` commands are Pi-only** (they run in the Pi session). On Codex, use the `taskflow_*` MCP tools instead — `taskflow_list` / `taskflow_show` / `taskflow_run` (by `name`) / `taskflow_verify` / `taskflow_compile`.
641
+ Saved flows become CLI shortcuts. **These `/tf` commands are Pi-only** (they run in the Pi session). On Codex, Claude Code, and OpenCode, use the `taskflow_*` MCP tools instead — `taskflow_list` / `taskflow_show` / `taskflow_run` (by `name`) / `taskflow_verify` / `taskflow_compile` / `taskflow_peek`.
556
642
 
557
643
  | Command | What it does |
558
644
  |---|---|
@@ -565,7 +651,7 @@ Saved flows become CLI shortcuts. **These `/tf` commands are Pi-only** (they run
565
651
  | `/tf init` | **Interactively map model roles** to your enabled models (writes `~/.pi/agent/settings.json`) |
566
652
  | `/tf:<name> [args]` | Shortcut — runs the flow in one tap |
567
653
 
568
- Tool actions (used by the model on Pi): `run` (inline `define` or saved `name`), `save`, `resume`, `list`, `agents`, `init`, `verify`, `compile`, `ir`, `provenance`, `why-stale`, `recompute`, `cache-clear`. On Codex the exposed MCP tools are `taskflow_run` / `taskflow_list` / `taskflow_show` / `taskflow_verify` / `taskflow_compile`.
654
+ Tool actions (used by the model on Pi): `run` (inline `define` or saved `name`), `save`, `resume`, `list`, `agents`, `init`, `verify`, `compile`, `ir`, `provenance`, `why-stale`, `recompute`, `cache-clear`. On Codex, Claude Code, and OpenCode the exposed MCP tools are `taskflow_run` / `taskflow_list` / `taskflow_show` / `taskflow_verify` / `taskflow_compile` / `taskflow_peek`.
569
655
 
570
656
  ## Background (detached) execution
571
657
 
@@ -779,12 +865,12 @@ Copy one into `.pi/taskflows/<name>.json` (or `~/.pi/agent/taskflows/`) and it r
779
865
 
780
866
  <div align="center">
781
867
 
782
- **0 runtime dependencies** · **918 tests** · **10 phase types** · **shared context tree** · **cross-session resume** · **cross-run memoization** · **per-item map caching** · **incremental recompute** · **FlowIR compile seam** · **detached execution** · **`compile` Mermaid renderer** · **~9k LOC runtime**
868
+ **0 runtime dependencies** · **1140 tests** · **10 phase types** · **shared context tree** · **cross-session resume** · **cross-run memoization** · **per-item map caching** · **incremental recompute** · **FlowIR compile seam** · **detached execution** · **`compile` Mermaid renderer** · **~9k LOC runtime**
783
869
 
784
870
  </div>
785
871
 
786
872
  - **Zero runtime dependencies.** No `dependencies` field — the runtime is built entirely on Node built-ins (`fs` / `path` / `os` / `child_process` / `crypto`). The file lock is `fs.openSync("wx")`, not a third-party library.
787
- - **918 tests across 52 test files** covering concurrency, atomic file locking (8-process race regressions), path-traversal hardening, cross-session resume, cross-run cache freshness (flow/thinking/tools key isolation, fingerprint invalidation, TTL/LRU eviction), backward-compatible cache-key migration (4-tier legacy fallback), per-phase structural sub-fingerprint (v3:phasefp — editing one phase invalidates only it and its dependents), per-item map caching (one changed item re-executes, N−1 cache hits), the `incremental` flag (run-wide cross-run default), reuse reporting, the FlowIR compile seam (determinism, declared-plane synthesis), incremental recompute (early-cutoff propagation, partial cascade strictly < full, observed ∪ declared union frontier), gate verdicts, budget caps, retry/backoff, approval flows, loop termination, tournament judging, sub-flow composition, the shared context tree (blackboard reuse, supervision spawn, subflow validation/nesting), workspace isolation (temp/dedicated/worktree lifecycle, fail-open degrade, dynamic-flow rejection), dynamic sub-flow security hardening, detached execution (PID persistence, stale detection, crash→failed, resume after failure), live run-history refresh, callback isolation, the idle watchdog, model-role init config, parseModelFromLabel with parenthesized-model-name regression, and multi-fence `safeParse` recovery, plus the `compile` Mermaid renderer (id-collision disambiguation, markdown-injection hardening, and full verify-overlay category coverage).
873
+ - **1140 tests across 70 test files** covering concurrency, atomic file locking (8-process race regressions), path-traversal hardening, cross-session resume, cross-run cache freshness (flow/thinking/tools key isolation, fingerprint invalidation, TTL/LRU eviction), backward-compatible cache-key migration (4-tier legacy fallback), per-phase structural sub-fingerprint (v3:phasefp — editing one phase invalidates only it and its dependents), per-item map caching (one changed item re-executes, N−1 cache hits), the `incremental` flag (run-wide cross-run default), reuse reporting, the FlowIR compile seam (determinism, declared-plane synthesis), incremental recompute (early-cutoff propagation, partial cascade strictly < full, observed ∪ declared union frontier), gate verdicts, budget caps, retry/backoff, approval flows, loop termination, tournament judging, sub-flow composition, the shared context tree (blackboard reuse, supervision spawn, subflow validation/nesting), workspace isolation (temp/dedicated/worktree lifecycle, fail-open degrade, dynamic-flow rejection), dynamic sub-flow security hardening, detached execution (PID persistence, stale detection, crash→failed, resume after failure), live run-history refresh, callback isolation, the idle watchdog, model-role init config, parseModelFromLabel with parenthesized-model-name regression, multi-fence `safeParse` recovery, host argv-contract locking (codex/claude/opencode `buildXxxArgs`), the `compile` Mermaid renderer (id-collision disambiguation, markdown-injection hardening, and full verify-overlay category coverage), plus the library Phase 1 metadata/search/store layer (phaseSignature, generality, CJK text scoring, staleness detection, sidecar persistence, A1 ghost-flow guard).
788
874
  - **Hardened by design.** Path-traversal defense (lexical + `realpath` containment check), runId validation, HTML/error sanitization, atomic writes, stale-lock stealing via `rename`, and an idle watchdog that kills wedged subagents (SIGTERM → SIGKILL after 5 minutes of silence). Dynamic sub-flows additionally get breadth caps, `cwd` containment, budget clamping, nesting depth caps, and prototype-pollution defense.
789
875
  - **Dogfooded.** Every new feature has to survive the project's own `self-improve` taskflow before it ships.
790
876
 
@@ -809,7 +895,7 @@ Our `self-improve` flow is a 10-phase DAG — it audits the codebase, patches de
809
895
 
810
896
  ## Status & limits
811
897
 
812
- **v0.1.3** — the current release. See [CHANGELOG](https://github.com/heggria/taskflow/blob/main/CHANGELOG.md) for the full history (incl. the v0.1.1 execution fix for issue #3). This release adds the Codex MCP `taskflow_compile` SVG diagram and a full malformed-input hardening pass across `validate`/`verify`/`compile`. Baseline: **multi-host monorepo** — the engine is split into the host-neutral `taskflow-core` plus `pi-taskflow` (Pi adapter) and `codex-taskflow` (Codex runner + MCP server + plug-and-play Codex plugin). **Shared Context Tree**: opt-in (`shareContext` / `contextSharing`) blackboard + supervision tools (`ctx_read`/`ctx_write` horizontal reuse, `ctx_report`/`ctx_spawn` vertical supervision); `ctx_spawn` accepts a flat task **or** a dependency-bearing `subflow` (a runtime-validated nested DAG), depth-capped on a unified nesting counter with budget accounting. **Workspace isolation**: a phase's `cwd` accepts reserved keywords `temp`/`dedicated`/`worktree` — the runtime allocates an isolated dir (or a git worktree on a throwaway branch) and tears it down after the phase, fail-open, rejected in LLM-authored sub-flows. **Detached execution**: runs can execute in the background, detached from the Pi session. Prior: loop-until-done (`loop`), tournament (best-of-N with a judge), cross-run memoization (content-addressed cache with git/file/glob/env fingerprints and TTL), interactive `/tf init`, configurable built-in agents, 18 built-in agents with 6 model roles. Full control-flow & reliability layer (`when` guards, `join: any`, `retry`/backoff, `approval`, `flow` composition, `budget` caps, `onBlock: "retry"`, `eval` machine gates, idle watchdog) on top of the DSL + DAG runtime (`agent`/`parallel`/`map`/`gate`/`reduce`). Inline + saved flows, cross-session resume, live progress, and isolated context. A run executes as one streaming tool call.
898
+ **v0.1.6** (current release) — adds **library Phase 1** (search-before-author + reusable-flow sidecar metadata), the **`defineFile`** parameter (verify/compile/run a flow from a path on disk), and **JSONC comment support** in flow definition files (`//` and `/* */` comments + trailing commas, parsed by the new zero-dependency `parseJsonc`). **v0.1.5** added **Claude Code and OpenCode as hosts**, **extracted the MCP server into its own `taskflow-mcp-core` package**, and **de-duplicated the three host runners** into a shared `runSubagentProcess`. See [CHANGELOG](https://github.com/heggria/taskflow/blob/main/CHANGELOG.md) for the full history. Baseline: **multi-host monorepo of seven packages** — the host-neutral `taskflow-core` engine, the host-neutral `taskflow-mcp-core` MCP server, the shared host-runner `taskflow-hosts`, plus `pi-taskflow` (Pi adapter), `codex-taskflow`, `claude-taskflow`, and `opencode-taskflow` (the three delivery packages re-export their runners from `taskflow-hosts` and each ships an MCP bin + plugin/config), all sharing the host-neutral MCP server in `taskflow-mcp-core`. **Library Phase 1**: save flows with `purpose`+`tags` via `taskflow_save` (MCP) or `action=save` (Pi), search them with structural + CJK-aware keyword scoring via `taskflow_search`/`action=search`, and track `reuseCount` via `reusedFromSearch`. **`defineFile`**: pass a `defineFile` path (or `{defineFile, name}`) to `action=run` (Pi) or `taskflow_run`/`taskflow_verify`/`taskflow_compile` (MCP) instead of an inline `define`, and the engine reads the flow from disk — pair it with JSONC comments to annotate saved flows. **JSONC**: flow-definition `.json` files may now carry `//` and `/* */` comments and trailing commas (parsed by `parseJsonc`, re-exported from the `taskflow-core` barrel); LLM-output parsing via `safeParse` stays strict. **Shared Context Tree**: opt-in (`shareContext` / `contextSharing`) blackboard + supervision tools (`ctx_read`/`ctx_write` horizontal reuse, `ctx_report`/`ctx_spawn` vertical supervision); `ctx_spawn` accepts a flat task **or** a dependency-bearing `subflow` (a runtime-validated nested DAG), depth-capped on a unified nesting counter with budget accounting. **Workspace isolation**: a phase's `cwd` accepts reserved keywords `temp`/`dedicated`/`worktree` — the runtime allocates an isolated dir (or a git worktree on a throwaway branch) and tears it down after the phase, fail-open, rejected in LLM-authored sub-flows. **Detached execution**: runs can execute in the background, detached from the Pi session. Prior: loop-until-done (`loop`), tournament (best-of-N with a judge), cross-run memoization (content-addressed cache with git/file/glob/env fingerprints and TTL), interactive `/tf init`, configurable built-in agents, 18 built-in agents with 6 model roles. Full control-flow & reliability layer (`when` guards, `join: any`, `retry`/backoff, `approval`, `flow` composition, `budget` caps, `onBlock: "retry"`, `eval` machine gates, idle watchdog) on top of the DSL + DAG runtime (`agent`/`parallel`/`map`/`gate`/`reduce`). Inline + saved flows, cross-session resume, live progress, and isolated context. A run executes as one streaming tool call.
813
899
 
814
900
  Known boundaries (tracked, bounded — no surprises mid-flow):
815
901
 
@@ -823,22 +909,26 @@ Known boundaries (tracked, bounded — no surprises mid-flow):
823
909
 
824
910
  ## Development
825
911
 
826
- `taskflow` is an npm-workspaces monorepo of three published packages:
912
+ `taskflow` is a pnpm-workspace monorepo of seven published packages:
827
913
 
828
914
  | Package | Role |
829
915
  |---------|------|
830
- | [`taskflow-core`](https://github.com/heggria/taskflow/blob/main/packages/taskflow-core) | Host-neutral orchestration engine (zero host-SDK deps; only `typebox`) |
916
+ | [`taskflow-core`](https://github.com/heggria/taskflow/blob/main/packages/taskflow-core) | Host-neutral orchestration engine (zero host-SDK deps; only `typebox`) — runtime, DSL, cache, verify |
917
+ | [`taskflow-mcp-core`](https://github.com/heggria/taskflow/blob/main/packages/taskflow-mcp-core) | Host-neutral MCP server (stdio JSON-RPC + `taskflow_*` tools + DAG renderer); depends on core |
918
+ | [`taskflow-hosts`](https://github.com/heggria/taskflow/blob/main/packages/taskflow-hosts) | Shared host-runner collection — the codex/claude/opencode `SubagentRunner` impls + their argv builders + event-stream parsers; depends on core |
831
919
  | [`pi-taskflow`](https://github.com/heggria/taskflow/blob/main/packages/pi-taskflow) | Pi extension adapter — `taskflow` tool + `/tf` commands (what `pi install npm:pi-taskflow` gives you) |
832
- | [`codex-taskflow`](https://github.com/heggria/taskflow/blob/main/packages/codex-taskflow) | Codex subagent runner + a dependency-free MCP server, plus the [Codex plugin](https://github.com/heggria/taskflow/blob/main/packages/codex-taskflow/plugin) ([guide](https://github.com/heggria/taskflow/blob/main/docs/codex-mcp.md)) |
920
+ | [`codex-taskflow`](https://github.com/heggria/taskflow/blob/main/packages/codex-taskflow) | Codex MCP server + bin + [Codex plugin](https://github.com/heggria/taskflow/blob/main/packages/codex-taskflow/plugin) (re-exports the runner from `taskflow-hosts`) ([guide](https://github.com/heggria/taskflow/blob/main/docs/codex-mcp.md)) |
921
+ | [`claude-taskflow`](https://github.com/heggria/taskflow/blob/main/packages/claude-taskflow) | Claude Code MCP server + bin + [Claude Code plugin](https://github.com/heggria/taskflow/blob/main/packages/claude-taskflow/plugin) (re-exports the runner from `taskflow-hosts`) ([guide](https://github.com/heggria/taskflow/blob/main/docs/claude-mcp.md)) |
922
+ | [`opencode-taskflow`](https://github.com/heggria/taskflow/blob/main/packages/opencode-taskflow) | OpenCode MCP server + bin + [OpenCode config scaffold](https://github.com/heggria/taskflow/blob/main/packages/opencode-taskflow/plugin) (re-exports the runner from `taskflow-hosts`) ([guide](https://github.com/heggria/taskflow/blob/main/docs/opencode-mcp.md)) |
833
923
 
834
924
  ```bash
835
- npm install
836
- npm run typecheck # tsc --noEmit across all packages (no build needed)
837
- npm test # unit tests — no network, no process spawning
838
- npm run test:core # engine tests only (also: test:pi, test:codex)
839
- npm run build # emit dist/*.js + .d.ts for all three packages
840
- npm run test:e2e-codex # codex executor e2e (needs `codex` + model access)
841
- npm run test:e2e-codex-mcp # codex MCP server e2e
925
+ pnpm install
926
+ pnpm run typecheck # tsc --noEmit across all packages (no build needed)
927
+ pnpm test # unit tests — no network, no process spawning
928
+ pnpm run test:hosts # host-runner tests only (also: test:pi, test:codex, test:claude, test:opencode)
929
+ pnpm run build # emit dist/*.js + .d.ts for all seven packages
930
+ pnpm run test:e2e-codex # codex executor e2e (needs `codex` + model access)
931
+ pnpm run test:e2e-codex-mcp # codex MCP server e2e
842
932
  ```
843
933
 
844
934
  The pi end-to-end suites spawn live `pi` subagents and are run directly (they use
@@ -0,0 +1,16 @@
1
+ /**
2
+ * codex-taskflow public entry.
3
+ *
4
+ * The codex runner now lives in `taskflow-hosts` (shared host-runner
5
+ * collection). This package re-exports it so the public surface of
6
+ * `codex-taskflow` is unchanged — `import { codexSubagentRunner,
7
+ * runCodexAgentTask, buildCodexArgs, foldCodexEventLine, ... } from
8
+ * "codex-taskflow"` keeps working. New code should import directly from
9
+ * `taskflow-hosts`; this re-export exists for back-compat with anything that
10
+ * already depended on the `codex-taskflow` name.
11
+ *
12
+ * The delivery surface (the MCP server + bin + Codex plugin scaffold) is still
13
+ * shipped from this package — see `./mcp/server.ts` and `./mcp/bin.ts`.
14
+ */
15
+ export * from "taskflow-hosts/codex";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * codex-taskflow public entry.
3
+ *
4
+ * The codex runner now lives in `taskflow-hosts` (shared host-runner
5
+ * collection). This package re-exports it so the public surface of
6
+ * `codex-taskflow` is unchanged — `import { codexSubagentRunner,
7
+ * runCodexAgentTask, buildCodexArgs, foldCodexEventLine, ... } from
8
+ * "codex-taskflow"` keeps working. New code should import directly from
9
+ * `taskflow-hosts`; this re-export exists for back-compat with anything that
10
+ * already depended on the `codex-taskflow` name.
11
+ *
12
+ * The delivery surface (the MCP server + bin + Codex plugin scaffold) is still
13
+ * shipped from this package — see `./mcp/server.ts` and `./mcp/bin.ts`.
14
+ */
15
+ export * from "taskflow-hosts/codex";
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,sBAAsB,CAAC"}
package/dist/mcp/bin.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Executable entry for the pi-taskflow MCP server (the `codex-taskflow-mcp` bin).
3
+ * Executable entry for the taskflow MCP server, codex-bound (the
4
+ * `codex-taskflow-mcp` bin).
4
5
  *
5
6
  * Register with Codex:
6
7
  * npm install -g codex-taskflow
@@ -1 +1 @@
1
- {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/mcp/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/mcp/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG"}
package/dist/mcp/bin.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Executable entry for the pi-taskflow MCP server (the `codex-taskflow-mcp` bin).
3
+ * Executable entry for the taskflow MCP server, codex-bound (the
4
+ * `codex-taskflow-mcp` bin).
4
5
  *
5
6
  * Register with Codex:
6
7
  * npm install -g codex-taskflow
@@ -21,7 +22,7 @@ startMcpServer(process.cwd())
21
22
  .catch((e) => {
22
23
  // Never write non-JSON to stdout (it would corrupt the MCP stream); log to
23
24
  // stderr and exit non-zero so the client sees the transport drop.
24
- process.stderr.write(`pi-taskflow mcp server fatal: ${e instanceof Error ? e.stack ?? e.message : String(e)}\n`);
25
+ process.stderr.write(`taskflow mcp server fatal: ${e instanceof Error ? e.stack ?? e.message : String(e)}\n`);
25
26
  process.exit(1);
26
27
  });
27
28
  //# sourceMappingURL=bin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/mcp/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;KAC3B,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KAC3B,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACZ,2EAA2E;IAC3E,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/mcp/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;KAC3B,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KAC3B,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACZ,2EAA2E;IAC3E,kEAAkE;IAClE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC9G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
@@ -1,31 +1,15 @@
1
1
  /**
2
- * pi-taskflow as an MCP server for Codex (and any MCP client).
2
+ * The Codex binding of the host-neutral MCP server (taskflow-mcp-core/server).
3
3
  *
4
- * Exposes the taskflow engine as MCP tools so a Codex user can declare and run
5
- * verifiable task DAGs from inside codex — the mirror of codex-runner.ts (which
6
- * lets taskflow *call* codex). Here taskflow is *called by* codex: each subagent
7
- * a flow spawns is itself a `codex exec` process (via codexSubagentRunner), so
8
- * the whole thing closes the loop with no pi process required.
9
- *
10
- * Protocol: MCP over stdio, JSON-RPC 2.0 (newline-delimited). Implemented on the
11
- * dependency-free transport in ./jsonrpc.ts — pi-taskflow keeps its zero-runtime
12
- * -deps guarantee; we do NOT use @modelcontextprotocol/sdk.
13
- *
14
- * Tools exposed:
15
- * - taskflow_run : run an inline or saved flow, return the final output
16
- * - taskflow_list : list saved flows discoverable in this cwd
17
- * - taskflow_show : show a saved flow's definition
18
- * - taskflow_verify : statically verify a flow (no execution)
19
- * - taskflow_compile : render a flow as a DAG diagram (SVG image) + status line
20
- */
21
- import { type RpcHandler } from "./jsonrpc.ts";
22
- /**
23
- * Build the per-call tool handlers. `cwd` is the directory the server was
24
- * launched in (where saved flows + agents are discovered, and where codex
25
- * subagents run).
4
+ * The protocol layer, tool schemas, and handlers all live in core; this shim
5
+ * only closes the loop for Codex: every subagent a flow spawns is itself a
6
+ * `codex exec` process (via codexSubagentRunner). Kept as a module (not just
7
+ * bin.ts) so tests and embedders get the same pre-bound surface the bin runs.
26
8
  */
9
+ import type { RpcHandler } from "taskflow-mcp-core/jsonrpc";
10
+ /** Per-call tool handlers with codex subagent execution bound in. */
27
11
  export declare function makeToolHandlers(cwd: string): Record<string, (args: Record<string, unknown>) => Promise<unknown>>;
28
- /** Build the full MCP method dispatch table (protocol + tools). */
12
+ /** Full MCP method dispatch table (protocol + tools), codex-bound. */
29
13
  export declare function makeMcpHandlers(cwd: string): Record<string, RpcHandler>;
30
14
  /** Start the stdio MCP server. Resolves when the client disconnects. */
31
15
  export declare function startMcpServer(cwd?: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAsO1E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAyJjH;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CA2BvE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAG5D,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAEjH;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAEvE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzE"}