@workflow-manager/runner 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/acpExecutor.d.ts +2 -2
- package/dist/acpExecutor.js +9 -8
- package/dist/cliRunRenderer.js +17 -0
- package/dist/engine.js +201 -68
- package/dist/generated/bundledSkills.d.ts +5 -0
- package/dist/generated/bundledSkills.js +22 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +409 -55
- package/dist/manPage.d.ts +1 -1
- package/dist/manPage.js +44 -9
- package/dist/parser.js +10 -1
- package/dist/runnerApi.js +14 -0
- package/dist/runtimePreflight.js +3 -2
- package/dist/sessionFile.d.ts +11 -0
- package/dist/sessionFile.js +61 -0
- package/dist/tui/tuiRunRenderer.js +11 -0
- package/dist/types.d.ts +15 -8
- package/package.json +3 -2
- package/skills/workflow-author/README.md +18 -0
- package/skills/workflow-author/SKILL.md +308 -0
package/dist/manPage.js
CHANGED
|
@@ -21,25 +21,36 @@ List the agent skills bundled with the npm package.
|
|
|
21
21
|
.B skill install [name ...] [--agent claude|opencode] [--global] [--dir path] [--all] [--force]
|
|
22
22
|
Install bundled agent skills into an agent skill directory. Defaults to the workflow-manager-cli skill and the project-level Claude Code directory (./.claude/skills). Existing skills are not overwritten unless --force is passed.
|
|
23
23
|
.TP
|
|
24
|
-
.B scaffold [path] [--format markdown|json]
|
|
24
|
+
.B scaffold [path] [--format markdown|json] [--template default|agent-validated]
|
|
25
25
|
Create a starter workflow file. Format defaults to markdown unless the output
|
|
26
|
-
path ends in .json.
|
|
26
|
+
path ends in .json. Template defaults to default (the general multi-step example);
|
|
27
|
+
agent-validated scaffolds a compact pipeline demonstrating first-class agent
|
|
28
|
+
validation (validation.mode: agent with a validator agent and criteria).
|
|
27
29
|
.TP
|
|
28
30
|
.B validate <workflow.md|workflow.json>
|
|
29
31
|
Validate workflow structure and report schema errors.
|
|
30
32
|
.TP
|
|
31
|
-
.B run <workflow.md|workflow.json> [--input input.json] [--objective text] [--confirm list] [--auto-confirm-all] [--port number] [--verbose] [--json] [--ui]
|
|
33
|
+
.B run <workflow.md|workflow.json> [--input input.json] [--objective text] [--confirm list] [--auto-confirm-all] [--port number] [--session-file path] [--verbose] [--json] [--ui]
|
|
32
34
|
Run the workflow with live CLI progress and optional JSON output.
|
|
33
35
|
.TP
|
|
34
|
-
.B approve [--url value] [--token value] [--run-id value] [--step value] [--actor value] [--note text]
|
|
36
|
+
.B approve [--url value] [--token value] [--session-file path] [--run-id value] [--step value] [--actor value] [--note text]
|
|
35
37
|
Approve the current waiting runner step through the local attach API.
|
|
36
38
|
.TP
|
|
37
|
-
.B resume [--url value] [--token value] [--run-id value] [--step value] [--actor value] [--note text]
|
|
39
|
+
.B resume [--url value] [--token value] [--session-file path] [--run-id value] [--step value] [--actor value] [--note text]
|
|
38
40
|
Alias for approve, intended for external resume flows.
|
|
39
41
|
.TP
|
|
40
|
-
.B cancel [--url value] [--token value] [--run-id value] [--step value] [--actor value] [--note text]
|
|
42
|
+
.B cancel [--url value] [--token value] [--session-file path] [--run-id value] [--step value] [--actor value] [--note text]
|
|
41
43
|
Cancel the current waiting runner step through the local attach API.
|
|
42
44
|
.TP
|
|
45
|
+
.B status [--url value] [--token value] [--session-file path] [--run-id value] [--step key]
|
|
46
|
+
Print the current run snapshot (or one step detail with --step) as JSON on stdout.
|
|
47
|
+
.TP
|
|
48
|
+
.B logs [--url value] [--token value] [--session-file path] [--run-id value] [--step key] [--limit number] [--cursor value]
|
|
49
|
+
Print buffered agent stdout/stderr chunks as JSON on stdout.
|
|
50
|
+
.TP
|
|
51
|
+
.B events [--url value] [--token value] [--session-file path] [--run-id value] [--since sequence] [--include-logs]
|
|
52
|
+
Print run events as JSON on stdout in a single poll (no streaming). Log events are excluded unless --include-logs is passed.
|
|
53
|
+
.TP
|
|
43
54
|
.B auth <login|whoami|logout> [--token value]
|
|
44
55
|
Manage remote registry authentication for CLI publish and pull flows.
|
|
45
56
|
.TP
|
|
@@ -77,6 +88,9 @@ Bypass confirmation gating for all steps.
|
|
|
77
88
|
.B --port <number>
|
|
78
89
|
Bind the local attach API to a specific port. If omitted, the OS assigns a free port on 127.0.0.1.
|
|
79
90
|
.TP
|
|
91
|
+
.B --session-file <path>
|
|
92
|
+
Write attach connection details (base URL, bearer token, run id, pid, timestamps) to a JSON file with mode 0600 when the run starts, and rewrite it with endedAt and the final status when the run finishes. Attach commands (approve, resume, cancel, status, logs, events) accept the same flag to read those details back.
|
|
93
|
+
.TP
|
|
80
94
|
.B --verbose
|
|
81
95
|
Stream per-step agent output and execution updates to stderr while the workflow runs.
|
|
82
96
|
.TP
|
|
@@ -89,16 +103,28 @@ Full-screen terminal UI (requires a TTY; falls back to standard output).
|
|
|
89
103
|
Human approval steps in an interactive terminal show an inline review prompt so they can be approved or cancelled without a separate HTTP client.
|
|
90
104
|
.TP
|
|
91
105
|
.B --url <value>
|
|
92
|
-
Runner attach API base URL for approve, resume, or
|
|
106
|
+
Runner attach API base URL for approve, resume, cancel, status, logs, or events commands.
|
|
93
107
|
.TP
|
|
94
108
|
.B --token <value>
|
|
95
|
-
Runner attach API bearer token for approve, resume, or
|
|
109
|
+
Runner attach API bearer token for approve, resume, cancel, status, logs, or events commands.
|
|
96
110
|
.TP
|
|
97
111
|
.B --run-id <value>
|
|
98
112
|
Runner id to control. If omitted, the CLI reads it from /session.
|
|
99
113
|
.TP
|
|
100
114
|
.B --step <value>
|
|
101
|
-
Optional step key when controlling a specific waiting step.
|
|
115
|
+
Optional step key when controlling a specific waiting step, or when scoping status and logs output.
|
|
116
|
+
.TP
|
|
117
|
+
.B --limit <number>
|
|
118
|
+
Maximum number of log chunks returned by the logs command. Defaults to 200.
|
|
119
|
+
.TP
|
|
120
|
+
.B --cursor <value>
|
|
121
|
+
Pagination cursor for the logs command, taken from a previous nextCursor value.
|
|
122
|
+
.TP
|
|
123
|
+
.B --since <sequence>
|
|
124
|
+
Only return events with a sequence greater than this value in the events command.
|
|
125
|
+
.TP
|
|
126
|
+
.B --include-logs
|
|
127
|
+
Include agent.stdout and agent.stderr events in the events command output.
|
|
102
128
|
.TP
|
|
103
129
|
.B --actor <value>
|
|
104
130
|
Actor name recorded in approval audit events.
|
|
@@ -116,6 +142,9 @@ Validate json workflow:
|
|
|
116
142
|
Scaffold json workflow file:
|
|
117
143
|
.B wfm scaffold ./new-workflow.json --format json
|
|
118
144
|
.TP
|
|
145
|
+
Scaffold an agent-validated pipeline example:
|
|
146
|
+
.B wfm scaffold ./agent-validated.md --template agent-validated
|
|
147
|
+
.TP
|
|
119
148
|
Authenticate with a CLI token:
|
|
120
149
|
.B wfm auth login --token wm_exampletoken
|
|
121
150
|
.TP
|
|
@@ -131,6 +160,12 @@ Search the remote registry:
|
|
|
131
160
|
Run with explicit confirmations:
|
|
132
161
|
.B wfm run ./example-workflow.json --confirm discover:human,qa_gate:human
|
|
133
162
|
.TP
|
|
163
|
+
Run with a session file for attach clients:
|
|
164
|
+
.B wfm run ./example-workflow.json --session-file ./run-session.json
|
|
165
|
+
.TP
|
|
166
|
+
Observe and control the run through the session file:
|
|
167
|
+
.B wfm status --session-file ./run-session.json && wfm approve --session-file ./run-session.json --step qa_gate
|
|
168
|
+
.TP
|
|
134
169
|
Inspect host setup:
|
|
135
170
|
.B wfm doctor
|
|
136
171
|
.TP
|
package/dist/parser.js
CHANGED
|
@@ -185,9 +185,18 @@ export function validateWorkflow(def) {
|
|
|
185
185
|
errors.push(`Unsupported adapter for ${step.key}: ${adapter}`);
|
|
186
186
|
}
|
|
187
187
|
const mode = step.validation?.mode ?? step.approvalSpec?.validation?.mode;
|
|
188
|
-
if (mode && !["none", "human", "external"].includes(mode)) {
|
|
188
|
+
if (mode && !["none", "human", "external", "agent"].includes(mode)) {
|
|
189
189
|
errors.push(`Invalid validation mode for ${step.key}: ${mode}`);
|
|
190
190
|
}
|
|
191
|
+
if (step.approvalSpec?.validation?.mode === "agent") {
|
|
192
|
+
errors.push(`Approval step ${step.key} cannot use agent validation`);
|
|
193
|
+
}
|
|
194
|
+
if (step.validation?.mode === "agent" && step.validation.agent?.adapterKey) {
|
|
195
|
+
const validatorAdapter = step.validation.agent.adapterKey;
|
|
196
|
+
if (!SUPPORTED_ADAPTERS.includes(validatorAdapter)) {
|
|
197
|
+
errors.push(`Unsupported validator adapter for ${step.key}: ${validatorAdapter}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
191
200
|
}
|
|
192
201
|
const cycle = findDependencyCycle(def);
|
|
193
202
|
if (cycle) {
|
package/dist/runnerApi.js
CHANGED
|
@@ -136,6 +136,20 @@ export async function startRunnerApiServer(store, requestedPort) {
|
|
|
136
136
|
});
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
|
+
const eventsListMatch = pathname.match(/^\/runs\/([^/]+)\/events\/list$/);
|
|
140
|
+
if (method === "GET" && eventsListMatch) {
|
|
141
|
+
const runId = decodeURIComponent(eventsListMatch[1] ?? "");
|
|
142
|
+
if (!store.isKnownRun(runId)) {
|
|
143
|
+
errorResponse(res, 404, "not_found", `Unknown run: ${runId}`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const sinceSequence = Number.parseInt(url.searchParams.get("sinceSequence") ?? "0", 10) || undefined;
|
|
147
|
+
const includeLogs = parseBoolean(url.searchParams.get("includeLogs"), true);
|
|
148
|
+
const items = store.events(sinceSequence, includeLogs);
|
|
149
|
+
const nextSequence = items.reduce((max, event) => Math.max(max, event.sequence), sinceSequence ?? 0);
|
|
150
|
+
jsonResponse(res, 200, { items, nextSequence });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
139
153
|
const eventsMatch = pathname.match(/^\/runs\/([^/]+)\/events$/);
|
|
140
154
|
if (method === "GET" && eventsMatch) {
|
|
141
155
|
const runId = decodeURIComponent(eventsMatch[1] ?? "");
|
package/dist/runtimePreflight.js
CHANGED
|
@@ -178,6 +178,7 @@ export function runtimeDoctorChecks(env = process.env) {
|
|
|
178
178
|
return [
|
|
179
179
|
commandCheck("pi-agent", "Pi command", piAgentCommand(piAgentStep, env), true, env),
|
|
180
180
|
acpCheck,
|
|
181
|
+
commandCheck("codex-acp", "Codex ACP bridge", "codex-acp", false, env),
|
|
181
182
|
commandCheck("opencode", "OpenCode command (legacy)", "opencode", false, env),
|
|
182
183
|
commandCheck("claude", "Claude Code command (legacy)", "claude", false, env),
|
|
183
184
|
envCheck("openrouter-key", "OpenRouter API key", "OPENROUTER_API_KEY", env),
|
|
@@ -220,7 +221,7 @@ export function adapterMockFallbackReason(step) {
|
|
|
220
221
|
// command) but useRealAdapter is off, so the step still mocks.
|
|
221
222
|
return `adapterKey '${adapter}' is set, but useRealAdapter is not enabled, so the step runs as a mock. Set taskSpec.payload.useRealAdapter: true to run it through ACP.`;
|
|
222
223
|
}
|
|
223
|
-
// Bare acp
|
|
224
|
+
// Bare acp with no agent configured is treated as an intentional mock.
|
|
224
225
|
return null;
|
|
225
226
|
}
|
|
226
227
|
export function adapterMockFallbackWarnings(definition) {
|
|
@@ -258,7 +259,7 @@ export function adapterImplementationStatuses() {
|
|
|
258
259
|
{
|
|
259
260
|
adapter: "codex",
|
|
260
261
|
status: "partial",
|
|
261
|
-
detail: "routed through ACP
|
|
262
|
+
detail: "routed through ACP via the codex-acp bridge when useRealAdapter is true; otherwise mock",
|
|
262
263
|
},
|
|
263
264
|
{
|
|
264
265
|
adapter: "claude-code",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface RunnerSessionFile {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
attachToken: string;
|
|
4
|
+
runId: string;
|
|
5
|
+
pid: number;
|
|
6
|
+
startedAt: string;
|
|
7
|
+
endedAt?: string;
|
|
8
|
+
status?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function writeSessionFile(filePath: string, session: RunnerSessionFile): void;
|
|
11
|
+
export declare function readSessionFile(filePath: string): RunnerSessionFile | string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
export function writeSessionFile(filePath, session) {
|
|
4
|
+
const resolvedPath = path.resolve(filePath);
|
|
5
|
+
fs.mkdirSync(path.dirname(resolvedPath), { recursive: true });
|
|
6
|
+
fs.writeFileSync(resolvedPath, `${JSON.stringify(session, null, 2)}\n`, {
|
|
7
|
+
encoding: "utf-8",
|
|
8
|
+
mode: 0o600,
|
|
9
|
+
});
|
|
10
|
+
// writeFileSync only applies the mode on creation; enforce it on rewrites too.
|
|
11
|
+
fs.chmodSync(resolvedPath, 0o600);
|
|
12
|
+
}
|
|
13
|
+
export function readSessionFile(filePath) {
|
|
14
|
+
const resolvedPath = path.resolve(filePath);
|
|
15
|
+
let raw;
|
|
16
|
+
try {
|
|
17
|
+
raw = fs.readFileSync(resolvedPath, "utf-8");
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
return `Could not read session file ${resolvedPath}: ${error.message}`;
|
|
21
|
+
}
|
|
22
|
+
let parsed;
|
|
23
|
+
try {
|
|
24
|
+
parsed = JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return `Session file ${resolvedPath} is not valid JSON`;
|
|
28
|
+
}
|
|
29
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
30
|
+
return `Session file ${resolvedPath} must contain a JSON object`;
|
|
31
|
+
}
|
|
32
|
+
const record = parsed;
|
|
33
|
+
for (const field of ["baseUrl", "attachToken", "runId", "startedAt"]) {
|
|
34
|
+
if (typeof record[field] !== "string" || record[field] === "") {
|
|
35
|
+
return `Session file ${resolvedPath} is missing required field: ${field}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (typeof record.pid !== "number" || !Number.isInteger(record.pid)) {
|
|
39
|
+
return `Session file ${resolvedPath} is missing required field: pid`;
|
|
40
|
+
}
|
|
41
|
+
if (record.endedAt !== undefined && typeof record.endedAt !== "string") {
|
|
42
|
+
return `Session file ${resolvedPath} has an invalid endedAt field`;
|
|
43
|
+
}
|
|
44
|
+
if (record.status !== undefined && typeof record.status !== "string") {
|
|
45
|
+
return `Session file ${resolvedPath} has an invalid status field`;
|
|
46
|
+
}
|
|
47
|
+
const session = {
|
|
48
|
+
baseUrl: record.baseUrl,
|
|
49
|
+
attachToken: record.attachToken,
|
|
50
|
+
runId: record.runId,
|
|
51
|
+
pid: record.pid,
|
|
52
|
+
startedAt: record.startedAt,
|
|
53
|
+
};
|
|
54
|
+
if (typeof record.endedAt === "string") {
|
|
55
|
+
session.endedAt = record.endedAt;
|
|
56
|
+
}
|
|
57
|
+
if (typeof record.status === "string") {
|
|
58
|
+
session.status = record.status;
|
|
59
|
+
}
|
|
60
|
+
return session;
|
|
61
|
+
}
|
|
@@ -38,6 +38,17 @@ function buildEventMetaText(event) {
|
|
|
38
38
|
const feedbackReason = readString(payload, "feedbackReason");
|
|
39
39
|
return `execution finished: ${status}${action ? ` action=${action}` : ""}${feedbackReason ? ` reason=${feedbackReason}` : ""}`;
|
|
40
40
|
}
|
|
41
|
+
if (event.type === "step.validation_started") {
|
|
42
|
+
const adapter = readString(payload, "adapter");
|
|
43
|
+
const criteria = readString(payload, "criteria");
|
|
44
|
+
return `agent validation started${adapter ? ` (${adapter})` : ""}${criteria ? ` criteria=${criteria}` : ""}`;
|
|
45
|
+
}
|
|
46
|
+
if (event.type === "step.validation_finished") {
|
|
47
|
+
const status = readString(payload, "status") ?? "unknown";
|
|
48
|
+
const action = readString(payload, "action");
|
|
49
|
+
const feedbackReason = readString(payload, "feedbackReason");
|
|
50
|
+
return `agent validation: ${status}${action ? ` action=${action}` : ""}${feedbackReason ? ` reason=${feedbackReason}` : ""}`;
|
|
51
|
+
}
|
|
41
52
|
if (event.type === "step.retried") {
|
|
42
53
|
const attempt = typeof payload.attempt === "number" ? payload.attempt : undefined;
|
|
43
54
|
return attempt !== undefined ? `retry scheduled (attempt ${attempt})` : "retry scheduled";
|
package/dist/types.d.ts
CHANGED
|
@@ -4,17 +4,11 @@ export type StepKind = "task" | "approval" | "system";
|
|
|
4
4
|
export type NodeType = "AGENT" | "HUMAN" | "SYSTEM";
|
|
5
5
|
export type ExecutionStatus = "SUCCESS" | "QA_REJECTED" | "YIELD_EXTERNAL" | "FAILED";
|
|
6
6
|
export type QaAction = "PROCEED" | "RETRY_CURRENT" | "ROLLBACK_PREVIOUS" | "RESTART_ALL";
|
|
7
|
-
export type ValidationMode = "none" | "human" | "external";
|
|
7
|
+
export type ValidationMode = "none" | "human" | "external" | "agent";
|
|
8
8
|
export type AdapterKey = "pi-agent" | "mock" | "opencode" | "codex" | "claude-code" | "acp";
|
|
9
9
|
export interface RetryPolicy {
|
|
10
10
|
maxAttempts?: number;
|
|
11
11
|
}
|
|
12
|
-
export interface ValidationSpec {
|
|
13
|
-
mode?: ValidationMode;
|
|
14
|
-
required?: boolean;
|
|
15
|
-
autoConfirm?: boolean;
|
|
16
|
-
confirmerPolicy?: string;
|
|
17
|
-
}
|
|
18
12
|
export interface TaskInitConfig {
|
|
19
13
|
context?: Record<string, unknown> | string;
|
|
20
14
|
skills?: string[];
|
|
@@ -22,6 +16,19 @@ export interface TaskInitConfig {
|
|
|
22
16
|
systemPrompts?: string[];
|
|
23
17
|
model?: string;
|
|
24
18
|
}
|
|
19
|
+
export interface AgentValidationSpec {
|
|
20
|
+
adapterKey?: AdapterKey;
|
|
21
|
+
init?: TaskInitConfig;
|
|
22
|
+
criteria?: string;
|
|
23
|
+
payload?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
export interface ValidationSpec {
|
|
26
|
+
mode?: ValidationMode;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
autoConfirm?: boolean;
|
|
29
|
+
confirmerPolicy?: string;
|
|
30
|
+
agent?: AgentValidationSpec;
|
|
31
|
+
}
|
|
25
32
|
export interface StepDefinition {
|
|
26
33
|
key: string;
|
|
27
34
|
kind: StepKind;
|
|
@@ -260,7 +267,7 @@ export interface RunEvent {
|
|
|
260
267
|
id: string;
|
|
261
268
|
runId: string;
|
|
262
269
|
stepRunId?: string;
|
|
263
|
-
type: "run.created" | "run.started" | "run.waiting_for_approval" | "step.runnable" | "step.claimed" | "step.execution_started" | "step.execution_finished" | "step.waiting_for_approval" | "approval.resolved" | "step.retried" | "step.confirmed" | "agent.started" | "agent.stdout" | "agent.stderr" | "agent.finished" | "run.completed" | "run.failed" | "run.cancelled";
|
|
270
|
+
type: "run.created" | "run.started" | "run.waiting_for_approval" | "step.runnable" | "step.claimed" | "step.execution_started" | "step.execution_finished" | "step.validation_started" | "step.validation_finished" | "step.waiting_for_approval" | "approval.resolved" | "step.retried" | "step.confirmed" | "agent.started" | "agent.stdout" | "agent.stderr" | "agent.finished" | "run.completed" | "run.failed" | "run.cancelled";
|
|
264
271
|
sequenceNumber: number;
|
|
265
272
|
occurredAt: string;
|
|
266
273
|
actor: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workflow-manager/runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "CLI runner for in-memory and markdown workflow orchestration using ATEP-like envelopes",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsc -p tsconfig.json",
|
|
26
|
+
"generate:skills": "node ./scripts/generate-bundled-skills.mjs",
|
|
26
27
|
"build:bin": "node ./scripts/build-binary.mjs --outfile ./dist/wfm",
|
|
27
28
|
"build:bin:macos": "node ./scripts/build-binary.mjs --target bun-darwin-arm64 --outfile ./dist/wfm-macos-arm64",
|
|
28
29
|
"build:bin:linux": "node ./scripts/build-binary.mjs --target bun-linux-x64 --outfile ./dist/wfm-linux-x64",
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
],
|
|
73
74
|
"license": "MIT",
|
|
74
75
|
"dependencies": {
|
|
75
|
-
"@
|
|
76
|
+
"@agentclientprotocol/sdk": "^1.2.1",
|
|
76
77
|
"gray-matter": "^4.0.3",
|
|
77
78
|
"picocolors": "^1.1.1"
|
|
78
79
|
},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# workflow-author skill
|
|
2
|
+
|
|
3
|
+
Teaches a host coding agent (Claude Code, opencode, pi) how to turn a natural-language
|
|
4
|
+
task description into a repeatable `wfm` workflow, validate it, run it, and narrate
|
|
5
|
+
progress — including approval gates — back to the user.
|
|
6
|
+
|
|
7
|
+
This skill ships inside the root `@workflow-manager/runner` npm package alongside
|
|
8
|
+
`workflow-manager-cli`. Install it into an agent's skill directory with:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
wfm skill install workflow-author # -> ./.claude/skills/
|
|
12
|
+
wfm skill install workflow-author --agent opencode # -> ./.opencode/skill/
|
|
13
|
+
wfm skill install workflow-author --global # -> ~/.claude/skills/
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
See `SKILL.md` for the full operating manual, and `doc/guide/workflow-schema.md` /
|
|
17
|
+
`doc/guide/runner-api.md` for the underlying schema and attach-API contract this
|
|
18
|
+
skill is built on.
|