
Security News
PHP Foundation Says Chainguard Broke Security Embargo Ahead of Emergency Patches
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.
gpt-workflow
Advanced tools
A deterministic multi-agent workflow runtime powered by Codex App Server.
Control flow — loops, branches, retries — is plain JavaScript in your script;
agent() delegates bounded judgment to Codex threads, and parallel(),
pipeline(), and child workflow() calls fan that work out.
Compared to driving Codex directly, a workflow adds:
agent() and the
runtime validates the reply and retries invalid ones, instead of you
policing format in prompt text.null instead of aborting the fan-out.How did I use Codex to build gpt-workflow?
Everything requires Bun 1.3 or newer, with the Codex CLI installed and authenticated for live runs. Node.js is not a supported runtime.
The preferred install is the Codex plugin. It bundles a skill that authors,
runs, and debugs workflows for you, and it runs the published CLI through
bunx, so there is no separate package to install:
codex plugin marketplace add CyrusNuevoDia/gpt-workflow
codex plugin add gpt-workflow@gpt-workflow
Restart the ChatGPT desktop app after installing and start a new task so the bundled skill loads; see plugin installation and behavior.
To drive the CLI yourself, install globally:
bun add --global gpt-workflow
For library use:
bun add gpt-workflow
Store project workflows under .codex/workflows/; this example is
summarize-files.js:
export const meta = {
name: "summarize-files",
description: "Summarize files concurrently and merge the findings",
};
const files = args.files;
const summaries = await parallel(
files.map(
(file) => () =>
agent(`Read ${file} and return three factual bullets.`, {
label: `summarize:${file}`,
})
)
);
return { summaries: summaries.filter(Boolean) };
args is the run's input; the --args flag in the next section supplies it.
meta.name is also the run-storage directory name, so it may contain only
letters, numbers, periods, underscores, and hyphens, and cannot be . or ...
If an agent's thread ends in an error, times out, returns no final message,
or exhausts its structured-output retries, that call resolves to null and is
recorded in the run's failures — the filter(Boolean) drops those slots. Script bugs,
setup problems such as missing models or bad option types, cancellation,
worktree-setup failures, and transport failures reject the whole run instead.
Workflow source is trusted repository code; it runs inside node:vm as a
semantic boundary, not a security sandbox for hostile JavaScript.
A live run spends model tokens. Resume replays completed calls from the journal — their tokens are not spent again — then runs the rest live:
gpt-workflow models
gpt-workflow run --default-model gpt-5.6-luna \
--args '{"files":["src/cli.ts","src/runtime.ts"]}' \
.codex/workflows/summarize-files.js
gpt-workflow run --default-model gpt-5.6-luna --resume workflow-123 \
--args '{"files":["src/cli.ts","src/runtime.ts"]}' \
.codex/workflows/summarize-files.js
--default-model supplies the model for agent() calls that omit
options.model; without either, the run rejects with a model error.
--args takes strict JSON and becomes the script's args global; pass a
plain string as quoted JSON, e.g. --args '"triage"'. Invalid JSON exits 1
with a usage error on stderr before any record is emitted. For --resume,
substitute the runId reported by your original run's records — real IDs
look like workflow-<uuid>; these examples shorten it to workflow-123.
Resume with the same --args: changed args change prompts, which miss the
journal and run live. Resume is strict: a missing run ID, duplicate run ID, or
run stored under a different workflow name exits before connecting to Codex.
models prints every model discovered from the authenticated App Server as
NDJSON without spending model tokens. Run accepts repeatable --required-model
flags plus --request-timeout-ms, --thread-start-timeout-ms, and
--turn-timeout-ms. SIGINT or SIGTERM cancels active agents, records a
terminal failure, flushes persisted events, and exits nonzero.
Stdout is ordered NDJSON; human diagnostics go to stderr. Every record
includes schemaVersion, sequence, runId, scriptPath, runDirectory,
ts (epoch milliseconds), and type. The opening run.started record
carries the script's meta; the final run.completed record carries meta,
result, usage, failures, and journalPath:
{"meta":{"name":"summarize-files","description":"Summarize files concurrently and merge the findings"},"type":"run.started","runDirectory":"/home/me/.codex/projects/-repo/workflows/summarize-files/runs/workflow-123","runId":"workflow-123","schemaVersion":1,"scriptPath":"/repo/.codex/workflows/summarize-files.js","sequence":0,"ts":1783971328984}
{"failures":[],"journalPath":"/home/me/.codex/projects/-repo/workflows/summarize-files/runs/workflow-123/journal.jsonl","meta":{"name":"summarize-files","description":"Summarize files concurrently and merge the findings"},"result":{"summaries":["…","…"]},"type":"run.completed","usage":{"agentCount":2,"liveAgentCount":2,"modelUsage":{"gpt-5.6-luna":{"liveAgentCount":2,"replayedAgentCount":0,"subagentTokens":3412}},"peakConcurrentAgents":2,"replayedAgentCount":0,"subagentTokens":3412},"runDirectory":"/home/me/.codex/projects/-repo/workflows/summarize-files/runs/workflow-123","runId":"workflow-123","schemaVersion":1,"scriptPath":"/repo/.codex/workflows/summarize-files.js","sequence":9,"ts":1783971339402}
After valid metadata creates the run directory, a top-level failure makes the
CLI emit run.failed and exit non-zero. Source-read and metadata-parse failures
write only to stderr and create no run artifact. Agent-side null failures don't fail the run: they stay
visible in the run.completed record's failures and are retried on resume.
There is no need to tee the stream for later inspection: every run also
persists a filtered copy of its NDJSON to
$CODEX_HOME/projects/<encoded-project-path>/workflows/<workflow-name>/runs/<runId>/events.jsonl
— the run, phase, and agent
status records needed to rebuild run state, without the high-volume
streaming deltas. Two commands read it back without spending model tokens:
gpt-workflow list
gpt-workflow status workflow-123
list prints one JSON line per run, newest first, with runId, name,
scriptPath, status, timestamps, and — once the run ended — finishedAt,
failureCount, and usage. status prints one JSON object that adds
ordered phases, per-agent progress and token totals, and the final
result and failures. Output is plain JSON, so jq applies:
gpt-workflow status workflow-123 | jq '.phases'
A run with no terminal record reports "incomplete": an in-flight and an
interrupted run look identical on disk, so the CLI never claims "running" —
check lastEventAt for staleness. An unknown run ID makes status exit 1
with an error on stderr.
Live runs persist an append-only replay journal at:
$CODEX_HOME/projects/<encoded-project-path>/workflows/<workflow-name>/runs/<runId>/journal.jsonl
CODEX_HOME defaults to ~/.codex. The project key is the absolute invocation
directory with path separators replaced by dashes, including the leading root
separator: /repo becomes -repo. Run state is local user data and does not
need a repository ignore rule.
The same directory holds events.jsonl, the inspection copy described
above; the journal remains the only replay substrate.
Resume reuses that runId and directory. Completed agent() calls are
matched by their prompt and options, regardless of the order they finished
in; at the first call with no journal match, that call and every later call
runs live and appends to the same journal.
To inspect a journal, parse it one record at a time with
parseWorkflowJournalEntry — Getting started
shows a streaming loop. The parser throws a SyntaxError on blank text,
malformed JSON, or records that are not valid journal entries; it never
returns null, so wrap each parse in try/catch when surveying a damaged
journal.
The journal is workflow replay state. Codex separately persists full agent
thread rollouts and exposes them through App Server thread APIs; their private
on-disk layout is not a gpt-workflow contract.
import {
AppServerClient,
REQUIRED_APP_SERVER_MODELS,
runWorkflowScript,
} from "gpt-workflow";
const source = `
export const meta = {
name: "summarize",
description: "Summarize a topic"
}
return await agent("Summarize " + args.topic)
`;
const client = await AppServerClient.connect({
defaultModel: "gpt-5.6-luna",
requiredModels: REQUIRED_APP_SERVER_MODELS,
});
try {
const execution = await runWorkflowScript(source, {
appServer: client,
args: { topic: "deterministic orchestration" },
});
console.log(execution.result, execution.journalPath);
} finally {
await client.close();
}
Running this example spends model tokens; inject agent to drive offline
tests without Codex. REQUIRED_APP_SERVER_MODELS is the model set the
runtime depends on — connect rejects when the App Server cannot start or is
missing any of them. runWorkflowScript accepts runDirectory for
caller-owned storage and resumeFromRunId for library resume, and splits
failures exactly as Write a workflow describes:
agent-side failures resolve to null and land in execution.failures;
everything else rejects. listRunSummaries and readRunStatus expose the
list and status data programmatically; see the
API reference.
Start with Getting started or the full documentation index. Structured output schemas, budgets, agent options, and child workflows are covered in the API reference; verification and fan-out shapes in Patterns.
Migrating Claude Code workflows? See the Claude parity ledger and the migration checklist.
Working on this repository itself? See AGENTS.md.
FAQs
Deterministic multi-agent workflows powered by Codex App Server
The npm package gpt-workflow receives a total of 13 weekly downloads. As such, gpt-workflow popularity was classified as not popular.
We found that gpt-workflow demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.

Threat Research
/Security News
A supply chain attack compromised LiteLLM 1.107.0 on PyPI and Docker, spreading malware that steals cloud credentials, developer secrets, and AI provider keys.