@taskflow-corp/cli

Multi-agent orchestration harness for AI coding agents (claude-code, codex, cursor, opencode, pi). Async-await TypeScript API; lifecycle hooks; auto-todos with verify-loop.
Install
npm install @taskflow-corp/cli
Quick start
import { taskflow } from '@taskflow-corp/cli';
await taskflow('hello').run(async ({ phase, session }) => {
await phase('greet', async () => {
await session('say-hi', { with: 'claude-code', task: 'Print hello world' });
});
});
Install harnesses from anywhere — taskflow add
Shadcn-style distribution: drop any harness into any project with a single command. You never need to install the package locally — npx @taskflow-corp/cli@latest <command> works from any directory and always pulls the newest version.
Source formats (every form accepted by add)
npx @taskflow-corp/cli@latest add ui-harness-trio
npx @taskflow-corp/cli@latest add @acme/e2e-video-tests
npx @taskflow-corp/cli@latest add @acme/e2e-video-tests@^1.2.0
npx @taskflow-corp/cli@latest add https://example.com/r/harness.json
npx @taskflow-corp/cli@latest add https://raw.githubusercontent.com/you/repo/main/r/x.json
npx @taskflow-corp/cli@latest add ./my-harness.json
npx @taskflow-corp/cli@latest add /abs/path/harness.json
npx @taskflow-corp/cli@latest add ~/shared/harness.json
npx @taskflow-corp/cli@latest add user/repo
npx @taskflow-corp/cli@latest add user/repo/path/to/item.json
npx @taskflow-corp/cli@latest add user/repo/path/to/item.json
npx @taskflow-corp/cli@latest add github:user/repo/items/foo.json
npx @taskflow-corp/cli@latest add gitlab:user/repo/items/foo.json
npx @taskflow-corp/cli@latest add bitbucket:user/repo/items/foo.json
npx @taskflow-corp/cli@latest add git::https://host/org/repo.git//items/foo.json?ref=v1
npx @taskflow-corp/cli@latest add git::ssh://git@github.com/you/priv.git//items/foo.json?ref=main
npx @taskflow-corp/cli@latest add https::https://example.com/bundle.json?sha256=abc123
npx @taskflow-corp/cli@latest add file::./local/harness.json
Detection order (first match wins, mirrors shadcn's resolver):
- ends with
.json and not a URL → local file
git:: / https:: / file:: prefix → fully qualified
github: / gitlab: / bitbucket: prefix → host shortcut
- parses as a URL → raw URL
@ns/name → namespace lookup
user/repo[/subpath][#ref] → bare GitHub shortcut
- otherwise → bare name (built-in
@taskflow registry)
Every form resolves to: fetch → validate (Zod) → write files → patch .agents/taskflow/config.ts (ts-morph AST merge) → merge .env.local → upsert taskflow.lock.
Multiple sources in one call
npx @taskflow-corp/cli@latest add ui-harness-trio @acme/video-tests ./local.json
registryDependencies from each item are resolved transitively (BFS + Kahn topo sort with cycle tolerance), so one command can pull a whole dependency graph.
Lifecycle commands
taskflow init | Scaffold taskflow.json + .agents/taskflow/config.ts + harness/rules dirs (auto-invoked by add on first use) |
taskflow add <source...> | Install one or more harnesses |
taskflow view <source> | Print the resolved registry-item JSON (no write, no install) |
taskflow list | List installed harnesses from taskflow.lock |
taskflow search <query> | Fuzzy-match against the public registries index |
taskflow update [name...] | Re-resolve; rewrite files + lockfile (--all implied if no names) |
taskflow remove <name> | Delete installed files + lockfile entry |
taskflow apply <preset> | add --overwrite alias (shadcn-style re-skin) |
taskflow build [input] | Publisher: inline source file contents, emit r/*.json + r/registry.json |
taskflow mcp | Start MCP server over stdio (tools: list_harnesses, search, install) |
taskflow run <harness.ts> | Execute an installed harness (TUI if TTY else JSONL) |
taskflow watch <harness.ts> | Alias for run |
taskflow plan <harness.ts> | Static AST preview — no LLM calls |
Flag reference for add
-y, --yes | false | Skip all confirmation prompts. On existing-file conflicts, skips the file (does NOT auto-overwrite — use --overwrite for that). |
-o, --overwrite | false | Replace existing files without prompt. Orthogonal to --yes. |
--dry-run | false | Resolve + validate, print what would change, do not write. |
--diff | false | Like --dry-run with a diff. Implies --dry-run. |
--view | false | Resolve and print the registry-item JSON to stdout. Do not write, do not preflight. |
-p, --path <dir> | harnessDir from taskflow.json | Override install directory for this run. |
-c, --cwd <dir> | process.cwd() | Run as if invoked from <dir>. |
-s, --silent | false | Mute all @clack/prompts output. On conflicts, skips like --yes. |
--frozen | false | CI mode: error if resolved items don't match taskflow.lock. |
--skip-adapter-check | false | Skip the requiredAdapters preflight check. |
Getting started in any project (30 seconds)
cd /path/to/some/project
npx @taskflow-corp/cli@latest add <your-source> -y --skip-adapter-check
npx @taskflow-corp/cli@latest list
npx @taskflow-corp/cli@latest run .agents/taskflow/harness/<name>.ts
File layout after init + add
project/
├── taskflow.json # config + registries map
├── taskflow.lock # content-addressed install manifest
├── .env.local # auto-loaded; ${VAR} expansion for registries
└── .agents/
└── taskflow/
├── config.ts # hooks, plugins, scope
├── harness/<name>.ts # installed harness files
├── harness/plugins/<name>.ts # installed plugins
├── harness/utils/<name>.ts # installed utilities
├── harness/examples/<name>.ts
└── rules/<name>.md # installed rules files
Private registries with auth
taskflow.json:
{
"$schema": "https://taskflow.sh/schema/taskflow.json",
"version": "1",
"registries": {
// simple form — string URL template
"@acme": "https://registry.acme.com/r/{name}.json",
// advanced form — per-registry headers and query params
"@private": {
"url": "https://api.corp.com/taskflow/{name}.json",
"headers": { "Authorization": "Bearer ${TASKFLOW_TOKEN}" },
"params": { "v": "latest" }
}
}
}
{name} placeholder is mandatory; {style} is reserved for future use.
${VAR_NAME} (braces required, no $VAR form) interpolates from process.env.
.env and .env.local are auto-loaded before resolution.
- Missing env vars fail pre-flight with a clear
RegistryMissingEnvironmentVariablesError.
- HTTP 401/403/404/410 map to specific typed errors with actionable hints.
Publishing your own registry
- Author
registry/registry.json:
{
"$schema": "https://taskflow.sh/schema/registry.json",
"name": "@yourname",
"homepage": "https://yourname.dev",
"items": [
{
"$schema": "https://taskflow.sh/schema/registry-item.json",
"name": "my-harness",
"type": "taskflow:harness",
"files": [
{ "path": "items/my-harness.ts", "type": "taskflow:harness" }
]
}
]
}
- Write the source
.ts files referenced by files[].path.
- Run
npx @taskflow-corp/cli@latest build -c ./registry --output ./registry/r.
- Host the emitted
r/ directory (GitHub Pages, S3, your CDN).
- Consumers then:
npx @taskflow-corp/cli@latest add https://<your-host>/r/my-harness.json
See registry/ in this repo for a worked example.
Item types (registry-item.json → type)
taskflow:harness | <harnessDir>/<basename> | Main .ts the user runs |
taskflow:plugin | <harnessDir>/plugins/<basename> | Imported from config.ts |
taskflow:utils | <harnessDir>/utils/<basename> | Shared TS |
taskflow:example | <harnessDir>/examples/<basename> | Sample invocation |
taskflow:rules | <rulesDir>/<basename> or target | Markdown rules |
taskflow:config-patch | Merged into config.ts via ts-morph AST | Not a file |
taskflow:file | target (required) | Arbitrary path incl. ~/ |
MCP integration (Claude Code / Cursor / Codex)
npx @taskflow-corp/cli@latest mcp
Exposes three tools over stdio:
list_harnesses — return installed harnesses from taskflow.lock
search — fuzzy-match the public registries index
install — delegate to runAdd
Wire it into your MCP client config and the model can discover and install harnesses autonomously.
CI usage
npx @taskflow-corp/cli@latest add <source> --yes --silent --frozen
Full design notes: docs/add-command-plan.md.
Hooks via .agents/taskflow/config.ts
import { defineConfig } from '@taskflow-corp/cli/config';
export default defineConfig({
events: {
afterTaskDone: async (ctx, { spec, result }) => {
},
},
todos: { autoExtract: true, maxRetries: 3 },
});
Structured output
Sessions with a zod schema return typed results. claude-code uses native tool-use. codex (on gpt-5 / gpt-5.4 models) uses --output-schema; gpt-5-codex variants fall back to prompt-engineered JSON pending openai/codex#4181. Other adapters (cursor, opencode, pi) use prompt-engineered JSON. Override codex behavior with HARNESS_CODEX_SCHEMA=0|1.
import { z } from 'zod';
const result = await session('summary', {
with: 'codex:gpt-5.4',
task: 'Summarize the repo',
schema: z.object({ title: z.string(), bullets: z.array(z.string()) }),
});
Plugins
A plugin contributes hooks, a ctx.plugins.<name> namespace, and optional config fragments:
import type { Plugin } from '@taskflow-corp/cli/core';
export const myPlugin: Plugin = () => ({
name: 'my-plugin',
events: {
afterTaskDone: async (ctx, { spec }) => { },
},
ctx: () => ({ hello: () => 'world' }),
});
To get typed access to ctx.plugins.myPlugin.hello() in downstream hooks, module-augment the plugin namespace registry:
declare module '@taskflow-corp/cli/core' {
interface PluginNamespaces {
'my-plugin': { hello: () => string };
}
}
See examples/omai-plugin-starter/ for a fuller scaffold (screen capture + UI-TARS wiring stubs).
Environment variables
ANTHROPIC_API_KEY | Required for claude-code sessions and pi:anthropic/*. |
OPENAI_API_KEY, GROQ_API_KEY, CEREBRAS_API_KEY, GEMINI_API_KEY | Required per-session for the respective providers. |
HARNESS_PI_BIN | Override the pi binary name (default pi). Use omp with @oh-my-pi/pi-coding-agent. |
HARNESS_CODEX_SCHEMA | 0 forces prompt-engineered JSON for codex; 1 forces native --output-schema. |
HARNESS_ADAPTER_OVERRIDE=mock | Swap every agent for the mock adapter — smoke runs with zero token cost. |
HARNESS_NO_TTY=1 | Force headless JSONL output even when a TTY is attached. |
HARNESS_RUNS_DIR=... | Override the runs archive directory (default data/runs). |
HARNESS_REAL_TESTS=1 | Enable integration tests that make real LLM calls (default-skipped). |
Docs
See .claude/skills/taskflow/SKILL.md for the authoring guide.