@agimon-ai/po-workflow
GitHub Actions-style workflow graphs, artifacts, recovery, and asynchronous runs for Po.
Package details
Install @agimon-ai/po-workflow from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@agimon-ai/po-workflow- Package
@agimon-ai/po-workflow- Version
0.0.0-alpha.107- Published
- Nov 4, 2026
- Downloads
- 18.4K/mo · 8,269/wk
- Author
- agiflow-ai
- License
- BUSL-1.1
- Types
- extension
- Size
- 6.8 MB
- Dependencies
- 18 dependencies · 2 peers
Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@agimon-ai/po-workflow
Discover, launch, monitor, control, and recover asynchronous Po workflows.
Part of the Po distribution.
This package owns the workflow engine and the workflow-mcp CLI (po-workflow-mcp is an alias).
Workflow files describe job dependencies and host-executed steps, while Po provides session-scoped tools.
Alpha: workflow and recovery contracts may change between releases.
Requirements
- Node.js 24 or newer
Install
The seeded modes.yaml selects the workflow layer in minimal, copilot and examples.
Remove it from a mode to omit Workflow there. No minor-mode activation is required.
Define a workflow
Create a *.workflow.yml file:
name: verify
jobs:
test:
steps:
- name: Run tests
run: pnpm test
summarize:
needs: test
steps:
- name: Record result
run: node scripts/write-verification-summary.mjs
run commands execute on the host with the workflow process's environment and privileges. There is
no VM, container, or sandbox. Review workflow files as executable code. Runner-specific
interactiveRun mappings are available for commands that require a TTY.
A step can also declare runConfig (major mode, minor modes, profile, domains, model, thinking)
and customRun (a prompt). Launched from the Po server, a customRun step runs as a child
session of the launching session with those settings, until the agent has recorded what the step
needs, and run and interactiveRun steps each get their own RMUX pane. Each run keeps its engine
log in engine.log in its run directory. See docs/automation.md for the full contract and the
CLI fallback.
Job-specific tools
Managed Po agent steps can receive a workflow-owned jobTools code-mode namespace and a pinned
workflow-job-tools skill. Select a folder at workflow level as a default, or override it per job:
name: summarize
runConfig:
majorMode: copilot
tools: ./tools/shared
jobs:
report:
tools: ./tools/report
steps:
- name: Summarize
customRun: Read workflow-job-tools, discover jobTools, then summarize this job.
The folder must contain JavaScript index.mjs and a non-empty SKILL.md. Paths are resolved relative
to the YAML that declares them, before imports and job-template inheritance. Empty paths, control
characters and URL specifiers are rejected. Parsing, listing and inspection never execute the module.
A job's main steps, preJob and postJob use its selection or the workflow default. repair.tools
overrides the default for repair triage. Global phases use the workflow default.
Only trusted, managed Po customRun and in-process interactiveRun agent sessions receive these
tools, not shell steps, ordinary sessions, or external Claude/Codex CLI runners. Each session uses its
captured workflow config. Global pre can run before the worktree YAML is reparsed, so its tools are
not necessarily selected from that worktree. Step cwd, WORKTREE_PATH and environment variables do
not select or resolve the tools folder.
index.mjs default-exports a factory, called once per managed session with:
sessionIdand the admitted working directorycwd.workflow: the trustedPoWorkflowContextService, including the captured config, job/step identity, admittedjobEnvironmentandstepEnvironment, and workflow state reader.- Injected
fsandshellcapabilities. Their methods take a call context as the last argument. signal: the session tools lifetime, aborted on session disposal or mounting failure.context: a call context forfsandshell, aborted withsignal. Insidebind(run), passrun.contextinstead, which also aborts when that exec ends.
Return the existing PoCodemodeNamespace contract: name jobTools, a non-empty one-line summary
(maximum 600 characters), TypeScript declarations for discovery, and bind(run). Bind returns flat
named async methods with JSON arguments and results. Each exec gets a fresh binding; keep per-session
state inside the factory, not at module scope. Validate method inputs and honour run.signal in long
operations. Use run.onDispose for exec-owned cleanup. The host refuses foreign sessions and calls
after cancellation/disposal, and detaches JSON values in both directions. Return null, not
undefined, for no output.
A minimal runnable tools/report/index.mjs:
export default function createJobTools({ sessionId, workflow, signal }) {
signal.throwIfAborted();
return {
name: 'jobTools',
summary: 'Describe the current workflow job with a supplied label.',
declarations: `declare const jobTools: {
describe(input: { label: string }): Promise<{ job: string; label: string }>;
};`,
bind(run) {
if (run.sessionId !== sessionId) throw new Error('Wrong session.');
return {
async describe(input) {
run.signal.throwIfAborted();
if (!input || typeof input.label !== 'string' || !input.label.trim())
throw new Error('label must be a non-empty string.');
return { job: workflow.job, label: input.label.trim() };
},
};
},
};
}
Corresponding tools/report/SKILL.md:
# Report tools
Use jobTools.describe to label the current job before writing its summary.
Discover jobTools for the current signature, then call it through exec.
Do not guess a label or repeat an effect after cancellation without checking its outcome.
Agents read the pinned skill, call discover({ namespace: 'jobTools' }), then use
exec with return await jobTools.describe({ label: 'Verification' });. Keep guidance in SKILL.md
and signatures in declarations. Optional namespace approval policies are preserved and enforced
by the existing code-mode approval path; each policy must name a returned method. An approval request
is not permission to bypass the normal approval flow.
Tools are trusted workflow code running with the host's privileges, not sandboxed code. Review the
folder before launching. Native import caches modules by file URL; editing index.mjs at the same
path requires a host restart. There is no direct TypeScript loading, hot reload, or external CLI
bridge. A missing file or invalid factory fails the managed step session rather than silently
omitting its selected tools. The namespace and skill mount and dispose together; disposing them does
not stop the owning workflow or change its recovery rules.
Step instructions
A workflow can give its managed Po agent steps their own instructions file:
instructions: ./AGENTS.md
The file replaces the AGENTS.md files the step session would discover from its working directory; it
does not add to them. The path resolves relative to the declaring YAML and is inherited through
imports as a default, like tools. A missing or unreadable file fails the step session rather than
running it without instructions. Shell steps and external Claude/Codex CLI runners ignore it.
Launch and monitor
Core tools are:
list_workflows: discover workflows.launch_workflow: register and start an asynchronous run.workflow_run: inspect or control a run through supported actions.workflow_tools(server/web sessions): read failed-run recovery evidence or resume the existing run.
Launch returns after the run is registered, not after all jobs complete. Use status for progress and wait for a completion notification.
Dynamic workflows
The package also supplies the dynamicWorkflow code-mode namespace: tracked Mastra
workflows composed with then, parallel, branch and bounded foreach, with live
team.run transcripts. It is available when the workflow layer is selected, with no
minor-mode gate. Inside a YAML run, a customRun step's agent can use it
for fan-out whose shape is only known at run time, and the run view shows those runs under
that step. See the code-mode guide.
Tracker state is in memory per session; it is not persisted with the run record.
Select the workflow layer in modes.yaml. Existing default-package entries still work
and deduplicate with the layer. No configuration migration runs, and persisted
minorModes: [workflow] has no effect.
Storage, concurrency, and lifecycle
Registry data defaults to $HOME/.workflow-mcp; set WORKFLOW_MCP_HOME to relocate it. Persisted
records contain workflow and run identity, job and step state, ownership, output locations, and
recovery evidence. The default concurrency ceiling is five runs.
Runs launched through a terminal
host such as tmux or cmux can have a different lifetime and remain manageable from the CLI. When
Team is loaded, Workflow contributes active session runs through Team's po/background-work
service. That contribution reconnects after Team is replaced and is removed when Workflow unloads.
Reconciliation distinguishes stale registry records from live processes; do not assume every run
outlives its parent session.
Each workflow or repair step can launch commands and model-backed agents, consuming provider quota and repeating external side effects.
Recovery
Recovery is available only for records in a terminal failure state. A recovery claim atomically adopts the eligible failure, validates the evidence, and transfers ownership to the replay session. Live controls remain scoped to the owning session. Recovery does not launch a second copy beside a still-running job and does not guarantee that parent-session work survives shutdown.
The package ships two skills: pinned, ungated codemode-how-to-workflow for workflow code-mode
namespaces and selected job tools, and unpinned, Help-gated help-how-to-workflow for authoring and
maintenance. A selected tools folder also supplies the managed session's pinned workflow-job-tools skill.
Workflow sessions
In a server (web cockpit) session, a launch does not run in the session that asked for it. The
session creates a child workflow session (provenance workflow-session), nested under it in the
rail, and hands it the launch. The workflow session owns the run (PO_SESSION_ID), runs its step
sessions, so its agent can troubleshoot and recover the run without a workflow minor mode. The run's
environment also carries PO_WORKFLOW_LAUNCHER_SESSION_ID, naming the launching session, which
lists the run in its Activity group, is told when it ends, and may read its status.
- The workflow session's rail row shows the run (
workflow · build › test · 4m, or a failure or pause marked like a pending question) through the host's per-session activity line. - Success is posted without starting a turn. Failure wakes the workflow owner for local diagnosis; the launcher receives a notification only. The owner gets a live brief on every turn.
- After a success, a workflow session nobody interacted with asks its launcher to release it, and it
becomes
stopped · open to wake. A session whose run failed or paused, or whose agent you prompted, stays live until you remove it. Removing or restarting a live workflow session stops its run. - Recovery is refused from any session other than the owner while the owner is live.
Development
pnpm build
pnpm typecheck
pnpm test
pnpm lint
Maintained by Agimon.
Web cockpit plugin
The .web routed files under src/extensions/workspaces/sessions/(frontend) are this package's
Po web cockpit plugin: the workflow dock face beside Activity and Context (the owned run's
jobs, active steps and artifacts, each opening its own tab), the workflow catalog and launch
dialog in the overlay slot, the Activity group's run rows (a handed-off run opens its workflow
session), their stores, and the workflow_runs session channel, compiled into the cockpit bundle
by po-web's build. Each surface keeps its components in a colocated _components folder and
its stores and helpers in _lib.
The hub-side data source lives in the package's backend API and reads the workflow registry
(run.json plus progress.ndjson) exactly as the engine writes it. The poServer and poWeb
blocks in package.json declare the backend and browser contributions.
Upgrading from the separate engine
The engine now ships inside @agimon-ai/po-workflow. Both workflow-mcp and
po-workflow-mcp invoke that package's CLI. Storage paths and registry records are unchanged.
Let active runs finish before replacing an installation, or retain their exact old Node and CLI
payloads until they finish. A run-local bin/workflow-mcp launcher contains absolute paths to the
engine that created it. Never rewrite a live launcher or hot-swap its engine.
In repositories with canonical .po/hooks.yaml, replace the old package's CLI path with
node_modules/@agimon-ai/po-workflow/dist/cli.mjs, then regenerate the frontend settings with that
repository's hook emitter. Installation alone does not migrate existing hook registries.
License
Business Source License 1.1: free for personal use, organisations under USD 1M revenue, non-profits and education. See LICENSE and https://agimon.ai/licensing.
Native execution contract
Agent steps require an effective runConfig.majorMode; delegated workflows require top-level runConfig.majorMode before their owner child is created. Selection projects major mode, minor modes, profile and domains unchanged. subagentModel and subagentThinking set Team preferences independently of the step model.
The native host requires execution-state inspection before creating agent steps. After settlement it waits for idle, no pending messages and a known background snapshot without core holds or holding-provider errors before checking decisions. Unknown ownership waits closed without consuming reminders; stops interrupt reads and retry delays. Running commands stop holding an inline step after five idle minutes, but its decision gate still runs before session release.
Delegated successes are informational. Errors wake the workflow owner through durable custom-message admission; the launcher gets an error notification, not an agent-waking failure completion. Diagnosis stays local. Recovery, pause, resume and stop are request-driven. User-requested stops do not trigger diagnosis or automatic restart.