Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Publish & Release

# Publishes taskflow-core + taskflow-mcp + taskflow-hosts + pi-taskflow + codex-taskflow +
# Publishes taskflow-core + taskflow-mcp-core + taskflow-hosts + pi-taskflow + codex-taskflow +
# claude-taskflow + opencode-taskflow to npmjs.com and creates a GitHub Release, when a v* tag is
# pushed (e.g. `git tag v0.1.0 && git push origin v0.1.0`). All seven workspace
# versions must equal the tag.
Expand Down Expand Up @@ -46,7 +46,7 @@ jobs:
echo "::error::Tag $TAG does not match root version $EXPECT"
exit 1
fi
for pkg in taskflow-core taskflow-mcp taskflow-hosts pi-taskflow codex-taskflow claude-taskflow opencode-taskflow; do
for pkg in taskflow-core taskflow-mcp-core taskflow-hosts pi-taskflow codex-taskflow claude-taskflow opencode-taskflow; do
V="v$(node -p "require('./packages/$pkg/package.json').version")"
if [ "$V" != "$TAG" ]; then
echo "::error::Tag $TAG does not match $pkg version $V"
Expand Down Expand Up @@ -103,7 +103,7 @@ jobs:
fi
}
publish_one taskflow-core
publish_one taskflow-mcp
publish_one taskflow-mcp-core
publish_one taskflow-hosts
publish_one pi-taskflow
publish_one codex-taskflow
Expand All @@ -129,7 +129,7 @@ jobs:
}
} catch {}
const text = body.join('\n').trim();
fs.writeFileSync('/tmp/release-notes.md', text || ('Release ' + process.argv[1] + ' \u2014 taskflow-core, taskflow-mcp, taskflow-hosts, pi-taskflow, codex-taskflow, claude-taskflow, opencode-taskflow.'));
fs.writeFileSync('/tmp/release-notes.md', text || ('Release ' + process.argv[1] + ' \u2014 taskflow-core, taskflow-mcp-core, taskflow-hosts, pi-taskflow, codex-taskflow, claude-taskflow, opencode-taskflow.'));
" "$VERSION"
gh release create "$GITHUB_REF_NAME" \
--notes-file /tmp/release-notes.md \
Expand Down
16 changes: 8 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ taskflow is a **declarative DAG orchestration runtime** for coding agents — it

**Language:** TypeScript (ES2022, ESM, `--experimental-strip-types` for direct execution in dev)\
**Runtime:** Node.js ≥ 22.19 (uses `fs.globSync`, `Atomics.wait`)\
**Dependencies:** Zero runtime deps. The Pi adapter (`pi-taskflow`) peer-depends on `@earendil-works/pi-{agent-core,ai,coding-agent,tui}`; the host-neutral MCP server (`taskflow-mcp`) and the three MCP host adapters (`codex-taskflow`, `claude-taskflow`, `opencode-taskflow`) all depend on `taskflow-core` (the adapters also depend on `taskflow-mcp`). Everything depends on `typebox`.\
**Layout:** pnpm-workspace monorepo of seven published packages — `taskflow-core` (host-neutral engine), `taskflow-mcp` (the host-neutral MCP server + DAG renderer, depends on core), `taskflow-hosts` (shared host-runner collection: the codex/claude/opencode SubagentRunner impls + argv builders + event-stream parsers, depends on core), `pi-taskflow` (Pi extension adapter, installed via `pi install npm:pi-taskflow`), `codex-taskflow` (Codex MCP server + bin + a `plugin/` scaffold installable via `codex plugin add`; re-exports the runner from `taskflow-hosts`), `claude-taskflow` (Claude Code MCP server + bin + a `plugin/` scaffold installable via `claude plugin install`; re-exports the runner from `taskflow-hosts`), and `opencode-taskflow` (OpenCode MCP server + bin + an `opencode.json` config scaffold; re-exports the runner from `taskflow-hosts`).\
**Dependencies:** Zero runtime deps. The Pi adapter (`pi-taskflow`) peer-depends on `@earendil-works/pi-{agent-core,ai,coding-agent,tui}`; the host-neutral MCP server (`taskflow-mcp-core`) and the three MCP host adapters (`codex-taskflow`, `claude-taskflow`, `opencode-taskflow`) all depend on `taskflow-core` (the adapters also depend on `taskflow-mcp-core`). Everything depends on `typebox`.\
**Layout:** pnpm-workspace monorepo of seven published packages — `taskflow-core` (host-neutral engine), `taskflow-mcp-core` (the host-neutral MCP server + DAG renderer, depends on core), `taskflow-hosts` (shared host-runner collection: the codex/claude/opencode SubagentRunner impls + argv builders + event-stream parsers, depends on core), `pi-taskflow` (Pi extension adapter, installed via `pi install npm:pi-taskflow`), `codex-taskflow` (Codex MCP server + bin + a `plugin/` scaffold installable via `codex plugin add`; re-exports the runner from `taskflow-hosts`), `claude-taskflow` (Claude Code MCP server + bin + a `plugin/` scaffold installable via `claude plugin install`; re-exports the runner from `taskflow-hosts`), and `opencode-taskflow` (OpenCode MCP server + bin + an `opencode.json` config scaffold; re-exports the runner from `taskflow-hosts`).\
**Build:** each package compiles to `dist/*.js` + `.d.ts` (`tsc`); published packages ship `dist` (Node refuses to type-strip `.ts` under `node_modules`). Dev resolves the TypeScript sources directly via a `development` export condition — no build needed to typecheck or test.

## Architecture
Expand Down Expand Up @@ -39,7 +39,7 @@ packages/
│ │ ├─ typebox-helpers.ts / frontmatter.ts / paths.ts ← vendored pi-SDK helpers (zero-dep)
│ │ └─ agents/ ← 18 built-in agent definitions (*.md with YAML frontmatter; copied to dist)
│ └─ test/ ← engine unit tests
├─ taskflow-mcp/ ← host-neutral MCP server (depends on taskflow-core)
├─ taskflow-mcp-core/ ← host-neutral MCP server (depends on taskflow-core)
│ ├─ src/mcp/ ← jsonrpc.ts (stdio JSON-RPC), server.ts (taskflow_* tools; parameterized by
│ │ a SubagentRunner), svg.ts (DAG SVG/outline renderer)
│ └─ test/ ← (covered by the host adapters' MCP tests)
Expand All @@ -59,7 +59,7 @@ packages/
│ │ └─ init.ts ← /tf init command: scaffolds a taskflow / model roles interactively
│ ├─ test/ ← pi-adapter unit tests + .mts e2e scripts
│ └─ skills/ ← GENERATED per-host skill files (do not edit; see skills-src/)
└─ codex-taskflow/ ← Codex DELIVERY package (depends on taskflow-hosts + taskflow-mcp)
└─ codex-taskflow/ ← Codex DELIVERY package (depends on taskflow-hosts + taskflow-mcp-core)
├─ src/
│ ├─ index.ts ← re-exports the codex runner from taskflow-hosts (back-compat public surface)
│ └─ mcp/ ← thin bind: server.ts re-exports core's MCP server bound to codexSubagentRunner; bin.ts
Expand All @@ -69,7 +69,7 @@ packages/
│ ├─ skills/taskflow/ ← GENERATED per-host skill files (do not edit; see skills-src/)
│ └─ assets/ ← plugin icons (taskflow.svg, taskflow-small.svg)
└─ test/ ← mcp-server unit test + .mts e2e scripts
└─ claude-taskflow/ ← Claude Code DELIVERY package (depends on taskflow-hosts + taskflow-mcp)
└─ claude-taskflow/ ← Claude Code DELIVERY package (depends on taskflow-hosts + taskflow-mcp-core)
├─ src/
│ ├─ index.ts ← re-exports the claude runner from taskflow-hosts (back-compat public surface)
│ └─ mcp/ ← thin bind: server.ts re-exports core's MCP server bound to claudeSubagentRunner; bin.ts
Expand All @@ -79,7 +79,7 @@ packages/
│ ├─ skills/taskflow/ ← GENERATED per-host skill files (do not edit; see skills-src/)
│ └─ assets/ ← plugin icons (taskflow.svg, taskflow-small.svg)
└─ test/ ← mcp-server unit test + .mts e2e scripts
└─ opencode-taskflow/ ← OpenCode DELIVERY package (depends on taskflow-hosts + taskflow-mcp)
└─ opencode-taskflow/ ← OpenCode DELIVERY package (depends on taskflow-hosts + taskflow-mcp-core)
├─ src/
│ ├─ index.ts ← re-exports the opencode runner from taskflow-hosts (back-compat public surface)
│ └─ mcp/ ← thin bind: server.ts re-exports core's MCP server bound to opencodeSubagentRunner; bin.ts
Expand Down Expand Up @@ -211,7 +211,7 @@ pnpm run test:e2e-opencode-mcp # opencode MCP stdio e2e (src; no live opencod

### File Structure Rules
- **Source**: `.ts` source lives in `packages/<pkg>/src/`. Host-neutral logic goes in `taskflow-core`; host **runner** code (the `SubagentRunner` impl, argv builder, event-stream parser for codex/claude/opencode) goes in `taskflow-hosts`; host **delivery** code (the MCP server/bin + plugin scaffold) goes in the `codex-taskflow` / `claude-taskflow` / `opencode-taskflow` packages; the pi adapter (which peer-depends the pi SDK) stays in `pi-taskflow`. `taskflow-core` must never import a host SDK (`@earendil-works/*`).
- **Imports**: adapters import the engine via the bare specifier `taskflow-core` (never a relative path into `../taskflow-core/src`). The MCP server lives in the separate `taskflow-mcp` package — host adapters import it via `taskflow-mcp/server` / `taskflow-mcp/jsonrpc`. `detached-runner.ts` is spawn-only — reference it by `taskflow-core/detached-runner.js`, never via the barrel. `runSubagentProcess` (in `runner-core.ts`, re-exported from the `taskflow-core` barrel) is the shared spawn+classify helper every host runner delegates to.
- **Imports**: adapters import the engine via the bare specifier `taskflow-core` (never a relative path into `../taskflow-core/src`). The MCP server lives in the separate `taskflow-mcp-core` package — host adapters import it via `taskflow-mcp-core/server` / `taskflow-mcp-core/jsonrpc`. `detached-runner.ts` is spawn-only — reference it by `taskflow-core/detached-runner.js`, never via the barrel. `runSubagentProcess` (in `runner-core.ts`, re-exported from the `taskflow-core` barrel) is the shared spawn+classify helper every host runner delegates to.
- **Tests**: `.test.ts` in the owning package's `test/`. Named `<module>.test.ts` or `<feature>.test.ts`.
- **Agents**: built-in agent `.md` files in `packages/taskflow-core/src/agents/` (copied to `dist/agents` at build).
- **Examples**: flow definitions as `.json` in `examples/`.
Expand Down Expand Up @@ -264,7 +264,7 @@ All engine files live in `packages/taskflow-core/src/`; the pi entry lives in `p
| `runtime.ts` | Core orchestration: `executeTaskflow()`, `executePhase()`, all 10 phase types |
| `schema.ts` | DSL types, validation, desugar, topo sort, cycle detection |
| `runner-core.ts` | Host-neutral runner helpers: failure classification, NDJSON accumulator, error sanitization, `mapWithConcurrencyLimit`, AND `runSubagentProcess` (the shared spawn/idle/abort/classify block every host runner delegates to) + `unknownAgentResult` |
| `taskflow-mcp/src/mcp/server.ts` | Host-neutral MCP server: the `taskflow_*` tool schemas + handlers, parameterized by a `SubagentRunner` (codex/claude/opencode adapters bind their runner + a thin bin) |
| `taskflow-mcp-core/src/mcp/server.ts` | Host-neutral MCP server: the `taskflow_*` tool schemas + handlers, parameterized by a `SubagentRunner` (codex/claude/opencode adapters bind their runner + a thin bin) |
| `pi-taskflow/src/runner.ts` | Pi subagent spawn (`pi --mode json`), idle watchdog; re-exports the core helpers |
| `taskflow-hosts/src/codex-runner.ts` | Codex subagent spawn (`codex exec --json`); `codexSubagentRunner` + `buildCodexArgs` |
| `taskflow-hosts/src/claude-runner.ts` | Claude Code subagent spawn (`claude -p --output-format stream-json`); `claudeSubagentRunner` + `buildClaudeArgs` + permission mapping |
Expand Down
35 changes: 26 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ All notable changes to taskflow are documented here. This project follows [Keep
## [0.1.6] — 2026-07-06

### Changed
- **Extracted the MCP server into its own `taskflow-mcp` package** (sixth
- **Extracted the MCP server into its own `taskflow-mcp-core` package** (sixth
package). The stdio JSON-RPC server + `taskflow_*` tool handlers + DAG
SVG/outline renderer moved out of `taskflow-core` into `taskflow-mcp`, so
SVG/outline renderer moved out of `taskflow-core` into `taskflow-mcp-core`, so
core is again purely the portable engine (DSL/runtime/cache/verify) and the
MCP presentation layer is an independently-publishable unit. The host
adapters (codex/claude/opencode) now depend on `taskflow-mcp` and import it
via `taskflow-mcp/server` / `taskflow-mcp/jsonrpc`. `pi-taskflow` is
adapters (codex/claude/opencode) now depend on `taskflow-mcp-core` and import it
via `taskflow-mcp-core/server` / `taskflow-mcp-core/jsonrpc`. `pi-taskflow` is
unaffected (it never used the MCP server).
- **De-duplicated the three host runners.** The codex/claude/opencode runners
each copy-pasted ~82 lines of identical process-handling boilerplate
Expand All @@ -22,9 +22,17 @@ All notable changes to taskflow are documented here. This project follows [Keep
parameterized by a per-host `SubagentAccumulator` + `foldLine`. Each host
runner shrank to just its host-specific bits (argv, model-id rule,
permission mapping, event parser): codex 366→217, claude 417→266, opencode
397→247 lines. Behavior is identical (1092/1092 tests pass); adding a new
397→247 lines. Behavior is identical (1140/1140 tests pass); adding a new
host can no longer drift the process/classify contract.

- **Renamed the MCP server package from `taskflow-mcp` to `taskflow-mcp-core`**
at release time: `taskflow-mcp` (and `taskflow-mcp-server`) had been squatted
on npm by an unrelated package, so the host-neutral MCP server ships as
`taskflow-mcp-core`. The directory (`packages/taskflow-mcp-core`), the host
adapters dependency pins, and all `taskflow-mcp/server` / `taskflow-mcp/jsonrpc`
imports were updated accordingly. The adapters own bin names
(`codex-taskflow-mcp` / `claude-taskflow-mcp` / `opencode-taskflow-mcp`) are unchanged.

### Added
- **Library Phase 1: search-before-author + reusable-flow assets.** A new
reusable-flow asset layer with sidecar `.meta.json` metadata
Expand All @@ -44,7 +52,7 @@ All notable changes to taskflow are documented here. This project follows [Keep
config scaffold, mirroring the Codex/Claude adapters. A flow's subagents can
now execute as isolated `opencode run` sessions, and taskflow is exposed to
OpenCode via the same `taskflow_*` MCP tools. Register with
`opencode mcp add taskflow -- npx -y -p opencode-taskflow opencode-taskflow-mcp`
`opencode mcp add taskflow -- npx -y -p opencode-taskflow opencode-taskflow-mcp-core`
(or an `opencode.json` `mcp` entry). See `docs/opencode-mcp.md`.
- Read-only phases inject a deny-mutations permission policy via
`OPENCODE_CONFIG_CONTENT` (genuinely enforced); mutating phases run with
Expand Down Expand Up @@ -91,6 +99,15 @@ All notable changes to taskflow are documented here. This project follows [Keep
and saved flows from the library. `safeParse()` for LLM output remains
strict. Re-exported from the `taskflow-core` barrel as `parseJsonc`.

### Fixed
- **The pi-taskflow "built-in agents upgrade" hint is now truly one-time.** It
previously re-printed every session while `settings.json` lacked a `taskflow`
key and the project had `.pi/agents/*.md`. A marker file
(`~/.pi/agent/.taskflow-upgrade-hint-shown`) is now written atomically (`wx`
flag) after the first print, so subsequent sessions skip it. Best-effort: an
unwritable agent dir only means the hint may show once more; it never blocks
session startup.

## [0.1.5] — 2026-07-03

### Added
Expand Down Expand Up @@ -325,7 +342,7 @@ All notable changes to taskflow are documented here. This project follows [Keep
- **Codex plugin** (`packages/codex-taskflow/plugin/`) for zero-config,
plug-and-play install: `codex plugin marketplace add heggria/taskflow` then
`codex plugin add taskflow@taskflow`. Ships a `.codex-plugin/plugin.json`
manifest, a `.mcp.json` that launches the MCP server via `npx -y -p codex-taskflow@<version> codex-taskflow-mcp`
manifest, a `.mcp.json` that launches the MCP server via `npx -y -p codex-taskflow@<version> codex-taskflow-mcp-core`
(no separate global install), and a routing `SKILL.md` so Codex reaches for the
`taskflow_*` tools on multi-phase / fan-out work automatically. A repo-root
`.claude-plugin/marketplace.json` makes the plugin discoverable.
Expand Down Expand Up @@ -403,9 +420,9 @@ All notable changes to taskflow are documented here. This project follows [Keep
typebox). Vendors the three small pi helpers it used (`StringEnum`,
`parseFrontmatter`, `getAgentDir`) so it is fully standalone.
- **`codex-taskflow`** — run taskflow on OpenAI Codex: a `codex exec`-backed
subagent runner, plus a dependency-free MCP server (`codex-taskflow-mcp`) that
subagent runner, plus a dependency-free MCP server (`codex-taskflow-mcp-core`) that
exposes `taskflow_run/list/show/verify/compile` to Codex users. Register with
`codex mcp add taskflow -- codex-taskflow-mcp`.
`codex mcp add taskflow -- codex-taskflow-mcp-core`.
- **Host-neutral `SubagentRunner` seam** — the engine drives any host via an
injected `runTask`; `piSubagentRunner` and `codexSubagentRunner` are the two
implementations.
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ See [`AGENTS.md`](./AGENTS.md) for the full layout and conventions. `taskflow` i
|---------------------|------|
| `packages/taskflow-core/` | Host-neutral engine: runtime, schema, agents, store, cache, verify, compile, context-store (zero host-SDK deps) |
| `packages/taskflow-core/src/agents/` | 18 built-in agent definitions (`.md` with YAML frontmatter) |
| `packages/taskflow-mcp/` | Host-neutral MCP server: stdio JSON-RPC + `taskflow_*` tools + DAG SVG/outline renderer (depends on taskflow-core) |
| `packages/taskflow-mcp-core/` | Host-neutral MCP server: stdio JSON-RPC + `taskflow_*` tools + DAG SVG/outline renderer (depends on taskflow-core) |
| `packages/pi-taskflow/` | Pi extension adapter (`taskflow` tool + `/tf` commands, TUI) + `skills/` |
| `packages/codex-taskflow/` | Codex subagent runner + MCP bin + Codex plugin |
| `packages/claude-taskflow/` | Claude Code subagent runner + MCP bin + Claude Code plugin |
Expand Down
6 changes: 3 additions & 3 deletions DECISIONS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Architecture Decisions (taskflow)

> Status: **living document**. Records the structural decisions behind the
> multi-host layout (taskflow-core / taskflow-mcp / taskflow-hosts / pi-taskflow /
> multi-host layout (taskflow-core / taskflow-mcp-core / taskflow-hosts / pi-taskflow /
> codex-taskflow / claude-taskflow / opencode-taskflow), the trade-offs that
> were considered, and the direction to take as the host count grows.
>
Expand Down Expand Up @@ -164,12 +164,12 @@ error blob.
- **`runner-core.ts` lives in `taskflow-core`.** It is host-neutral (no host
SDK import — only `node:child_process`), so keeping it in core does not
violate the "core has zero host-SDK deps" rule. Moving it out (e.g. into
`taskflow-mcp`) would force every host adapter to depend on a second package
`taskflow-mcp-core`) would force every host adapter to depend on a second package
for no benefit.
- **Skill generation is single-sourced** (`skills-src/` + `build-skills.mjs` +
a drift-guard test). New hosts add one `entry.<host>.md` and extend the
comma host list; the skill body is shared. Do not per-host the skill body.
- **MCP server is its own package (`taskflow-mcp`)** — a pure presentation
- **MCP server is its own package (`taskflow-mcp-core`)** — a pure presentation
layer over core. Pi users never pull MCP code. This boundary is correct.
- **Lockstep versioning is kept for now** (all seven packages share a version).
It is crude but it is *less* work than tracking which subset of packages need
Expand Down
Loading
Loading