Agent-facing reference for creating and inspecting OpenFlow work from a shell.
For dev setup, environment isolation, and packaging see
docs/development.md; for design rationale see
docs/subdocs/cli-design.md.
The CLI reads OpenFlow metadata from OPENFLOW_HOME and uses a local bridge to
talk to the running app for task creation/start.
Tips for creating OpenFlow work from the CLI:
- Discover ids and templates:
openflow project list --json openflow agent list --json openflow platform list --json openflow workflow list --json
- If the task comes after a long planning/debugging discussion, suggest saving that conversation as a plan or reference doc in the working directory or another user-approved location. Attach or cite that doc in the task description/stage prompts so future agents can use it as context.
- Before creating or starting anything, show the user the proposed title, project, template, agents, stages, and stage prompts.
- Prefer draft
task create; it opens the New Task dialog for human review. Use--directonly when the user explicitly asks for immediate creation. - Use
--jsonfor structured output. If the CLI returnswarnings, report them and adjust the request if needed. - On failure, fix obvious CLI/schema issues locally. If user input is needed, stop and include the exact command, exit code, stderr, and invalid/missing field.
Direct create + start: capture .taskId from task create --direct --json,
then pass it to task start.
Cron/CI can create direct tasks; treat start exit 4 as "queued, start later" if the app is unavailable.
openflow <command> [args]
Commands:
docs Recommended first; includes agent task-creation instructions
task create Create a new task
task list List tasks
task start Start a pending task
task stop Stop a running task
task restart Clone and restart a task
task resume Resume a paused/failed task
task inbox Send a message to a team task leader
agent list List agent prompts
platform list List agent platforms
project list List projects
workflow list List workflow templatesRun openflow <command> --help for command-specific help.
Agents should always run openflow docs first before create openflow task; it
includes the openflow bin usage instruction.
| Variable | Purpose | Default |
|---|---|---|
OPENFLOW_HOME |
Data root the CLI reads/writes | ~/.openflow |
The CLI does not read the GUI's stored home override. If the app uses a custom
home, export the same OPENFLOW_HOME.
task create and task start require the app to be running with System
settings -> Local HTTP bridge enabled. List commands read files directly and
work without the app.
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | other failure |
| 2 | validation failure |
| 3 | not found |
| 4 | cannot connect to app bridge |
| 5 | bridge auth failed |
| 6 | task already running or not startable |
| 7 | engine not ready |
Exit 4 means the CLI could not connect to the local app bridge required by task
mutation commands (task create, task start, task stop, task restart,
task resume, and task inbox). Common causes:
| Cause | Check | Fix |
|---|---|---|
| App is closed | No OpenFlow window/process is running | Open the app |
| Local HTTP bridge is disabled | System settings -> Local HTTP bridge is off | Enable the bridge |
| CLI and app use different homes | OPENFLOW_HOME differs from the app home shown in System settings |
Export the same OPENFLOW_HOME or unset it |
| Runtime file is stale | $OPENFLOW_HOME/.runtime/cli-port.json exists, but its port is not listening |
Restart the app |
| Port is blocked or occupied | Bridge log shows bind/connect errors for the configured port | Free the port or change the bridge port in System settings |
| Shell is sandboxed | The port is listening on the host, but the command cannot connect from the sandbox | Run with host/localhost network access, or run from a normal terminal |
# Spec mode
openflow task create --spec @path/to/spec.json [--direct] [--json]
openflow task create --spec - < spec.json
openflow task create --stdin < spec.json
# Inline mode: one stage per --agent, in order
openflow task create \
--project <name|id> \
--title "..." \
[--description "..."] \
[--team-mode solo|team] \
[--template <id>] \
--agent <platform>:<promptId> \
[--leader <agent-id>] \
[--direct] \
[--json]Default mode opens the New Task dialog pre-filled in the app and returns a draft
response. --direct validates the full schema and writes the task immediately.
Required for draft mode: project/projectId and title. Required for
--direct: the full spec below.
Team-mode default depends on the path. For normal agent use, omit teamMode
unless the user explicitly asks for linear/solo execution:
- Draft path: if
teamModeis omitted, the New Task dialog defaults toteam. - Direct path: if
teamModeis omitted from a full spec, the service schema defaults it tosolo.
Only the fields shown in settings are accepted. The CLI prunes unused
agentInstances. stages[].agentInstanceId and leaderAgentInstanceId must
reference an agent instance id.
| Field | Notes |
|---|---|
teamMode: "solo" |
Stages run sequentially. Previous stage output becomes next stage input. Pauses on failed/review states. |
teamMode: "team" |
A leader agent runs alongside stages and routes via leader/commands.jsonl (dispatch, approve, rerun, complete, chat, noop). |
needsReview: true |
Stage parks in awaiting_review after completion until approved in the GUI. |
isolationMode: "none" |
Agents run in the project repo as-is. |
isolationMode: "branch" |
Engine creates openflow/<slug>-<taskId> in-place; dirty trees are refused. |
isolationMode: "worktree" |
Engine creates <repo>/.worktrees/<taskId> on a new branch. |
Branches/worktrees persist after task completion for manual review/cleanup. The desktop app asks by default whether to delete a task-created branch/worktree before archive/delete; this can be disabled in System settings.
openflow project list --json # project ids and repo paths
openflow platform list --json # platform ids: claude, codex, gemini, ...
openflow agent list --json # prompt ids: builder, reviewer, ...The GUI also shows platform, prompt, workflow, project, and task ids.
openflow task list [--project <name|id>] [--status <status>] [--include-archived] [--json]--status accepts pending, running, paused,
awaiting_final_review, done, failed, or cancelled. Default output is
ID TITLE STATUS PROJECT CREATED; --json returns full task objects.
Example: openflow task list --project openflow --status pending --json.
openflow project list [--json]Lists configured projects from $OPENFLOW_HOME/projects; no running app
required. Default output is ID NAME PATH CREATED; --json returns full
project objects.
openflow agent list [--json]Lists agent prompt templates from $OPENFLOW_HOME/agents; no running app
required. Default output is ID NAME UPDATED; --json returns full agent
prompt objects, including systemPromptMd.
openflow platform list [--json]Lists agent platforms from $OPENFLOW_HOME/platforms; no running app required.
Default output is ID NAME BUILTIN SPAWN; --json returns full platform
objects.
openflow workflow list [--json]Lists templates from $OPENFLOW_HOME/workflows; no running app required.
Human output includes template id/name/description, agents, platform/prompt
metadata, stages, review gates, and stage prompts.
--json returns the same templates with resolved metadata:
| JSON field | Meaning |
|---|---|
agentInstances[].promptTemplate |
{ id, name } or null |
agentInstances[].platformInfo |
{ id, displayName } or null |
stages[].agentInstance |
{ id, name } or null |
stages[].index |
1-based stage position |
Recommended agent flow: run workflow list first, ask the user to review the
proposed task spec, then use draft task create unless --direct is requested.
openflow task start <task-id-or-prefix> [--leader <agent-instance-id>] [--json]<task-id-or-prefix> may be a full id or unambiguous prefix. --leader
overrides the leader for team-mode starts. --json returns
{ status, taskId, teamMode }.
task start posts to the running app's bridge and returns after the engine
accepts the request; it does not tail logs. Progress is in the GUI, task log,
and $OPENFLOW_HOME/logs/main-YYYY-MM-DD.log.
| Bridge result | Exit | Meaning |
|---|---|---|
| 200 | 0 | accepted |
| 401 | 5 | bad bearer token |
| 404 | 3 | no matching task |
| 409 | 6 | task already running/not pending |
| 422 | 2 | invalid request |
| 503 | 7 | engine not ready |
| connection refused | 4 | cannot connect to app bridge |
openflow task stop <task-id-or-prefix> [--json]
openflow task restart <task-id-or-prefix> [--json]
openflow task resume <task-id-or-prefix> [--json]All three commands require the running app bridge and resolve full task ids or unambiguous prefixes in the app-owned repo.
| Command | Behavior |
|---|---|
task stop |
Calls the engine abort path, kills task tmux sessions, marks active stages failed, and marks the task cancelled. |
task restart |
Aborts the old task, clones it to a fresh task id/stage ids, archives the old task, and starts the clone. JSON includes newTaskId. |
task resume |
Re-enters the engine drive loop for a paused or failed task. |
openflow task inbox <task-id-or-prefix> --message "..." [--json]Appends { from: "user", text, ts } to
projects/{projectId}/tasks/{taskId}/leader/inbox.jsonl through the running
app bridge. Use this for async user guidance to a team-mode leader; the leader
reads the inbox on its next tick. Solo tasks return conflict (exit 6).
Repo/dev: pnpm install && pnpm cli:build && pnpm link --global.
Dev mode: pnpm cli:dev task list --json.
DMG app: Open OpenFlow -> System settings -> Command line tool -> Install, or:
mkdir -p "$HOME/.local/bin"
ln -sf "/Applications/OpenFlow.app/Contents/Resources/app/bin/openflow" "$HOME/.local/bin/openflow"Ensure ~/.local/bin is on PATH.
The CLI is a thin HTTP client. Runtime discovery lives at
$OPENFLOW_HOME/.runtime/cli-port.json with mode 0600, shaped like
{ "port": 61234, "token": "...", "pid": 12345, "startedAt": "..." }.
The bridge binds 127.0.0.1 only and regenerates the token every start.
Routes: GET /healthz (no auth), POST /tasks (draft create),
POST /tasks?mode=direct (direct create), and POST /engine/start.
Authenticated routes require Authorization: Bearer <token>.
| Symptom | Likely cause | Fix |
|---|---|---|
Openflow CLI cannot connect to the app bridge / exit 4 |
App closed, bridge disabled, CLI home mismatch, stale runtime file, port blocked, or sandboxed localhost access | Use the Exit 4 troubleshooting table above |
| Exit 5 | Runtime token mismatch | Restart app |
| Exit 3 for project/task | Typo or ambiguous prefix/name | Use exact ids from project list --json, task list --json, or GUI |
| Exit 2 on create | Invalid spec | Read stderr paths; check required fields and dangling agent refs |
task start returns 0 but task does not progress |
Engine accepted async then failed | Check task log and $OPENFLOW_HOME/logs/main-YYYY-MM-DD.log |
Cannot find package 'X' imported from out/cli-bundle/... |
Stale build/deps | pnpm install && pnpm cli:build |
{ "project": "openflow", // name or id; "projectId" also accepted "title": "Add CLI", "description": "optional", "templateId": "blank", // audit stamp; default "blank" "teamMode": "team", // optional; omit in draft mode to use GUI default team "leaderAgentInstanceId": null, // required only for direct team-mode create "agentInstances": [ { "id": "builder", // optional; "instanceId" alias also accepted "name": "builder", "promptTemplateId": "builder", // ~/.openflow/agents/<id>.md "platform": "codex", // ~/.openflow/platforms/<id>.yaml "extraArg": "" } ], "stages": [ { "name": "build", "agentInstanceId": "builder", "extraPrompt": "", // "prompt" alias also accepted "needsReview": false } ], "settings": { "maxRerunsPerStage": 3, "requireFinalReview": true, "expectedDurationSec": 300, "isolationMode": "worktree" // "none" | "branch" | "worktree" } }