Skip to content
Data
Skill

/dynamic-workflows

How to write JavaScript workflow scripts for the `workflow` tool - fanning work out across many isolated subagents with agent(), parallel(), and pipeline(), then synthesizing one result. Use when a task decomposes into several independent investigations or changes (codebase

From plugin
posthog
38k156 skills11 agents1 command2 MCP
Install
$ npx -y skills add posthog/posthog --skill dynamic-workflows --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/dynamic-workflows

Context preview

The summary Claude sees to decide when to auto-load this skill.

How to write JavaScript workflow scripts for the `workflow` tool - fanning work out across many isolated subagents with agent(), parallel(), and pipeline(), then synthesizing one result. Use when a task decomposes into several independent investigations or changes (codebase

SKILL.md

dynamic-workflows.SKILL.md
name: dynamic-workflows
description: How to write JavaScript workflow scripts for the `workflow` tool - fanning work out across many isolated subagents with agent(), parallel(), and pipeline(), then synthesizing one result. Use when a task decomposes into several independent investigations or changes (codebase audits, many-file analysis, wide research, multi-perspective review, applying the same edit across many independent files).

Dynamic Workflows

The `workflow` tool executes a JavaScript orchestration script you write. The script holds the loop, branching, and intermediate results; each `agent()` call runs one isolated subagent in its own pi process; only the script's return value comes back into your context. This is how you audit 20 files, research 8 topics, or apply the same change across 20 independent files without burning your own context window on the intermediate output.

When to use it

  • The work decomposes into **several independent investigations or changes** whose

intermediate outputs you don't need verbatim - only a synthesis (or a report of what changed).

  • Examples: audit every route/module for a property, summarize each package of a

monorepo, verify a list of findings adversarially, research N alternatives, rename an API across every file that references it.

Do **not** use it for: a single question or a single edit (use `subagent` or just do it directly), one or two parallel tasks (use `subagent` parallel mode), or work needing your full conversation context.

Script shape

Prefer the **strict declared-plan contract** below. Strict mode turns on only when `meta.phases` is a literal object the runtime can read without executing code; older/dynamic scripts keep their legacy behavior. Do not set token budgets: choose only the appropriate persona/model tier and let the host account actual usage.

export const meta = {
  name: 'audit_routes',
  goal: 'Produce a decision-ready router audit',
  inputs: ['repository'],
  phases: [
    { title: 'Scan', goal: 'Map routers', inputs: ['repository'], produces: ['router inventory'] },
    { title: 'Audit', goal: 'Check the inventory', inputs: ['router inventory'], produces: ['router audits'] },
    { title: 'Synthesize', goal: 'Deliver the verdict', inputs: ['router audits'], produces: ['audit verdict'] },
  ],
  synthesis: { phase: 'Synthesize', inputs: ['router audits'], produces: ['audit verdict'] },
}

phase('Scan')

const inventory = await agent(
  'List every *.router.ts file under packages/host-router/src/routers. Reply with only JSON.',
  {
    label: 'route inventory',
    objective: 'Produce the complete router inventory for the audit.',
    inputs: ['repository'],
    produces: 'router inventory',
    schema: { type: 'object', required: ['files'], properties: { files: { type: 'array', items: { type: 'string' } } } },
  },
)
if (!inventory) return { ok: false, error: 'inventory failed' }

phase('Audit')
const audits = await agent(
  'Audit the router inventory against the one-line-forward rule. Return every violation as JSON.',
  { label: 'router audit', objective: 'Audit all discovered routers for inline logic.', inputs: ['router inventory'], produces: 'router audits', schema: { type: 'object', required: ['violations'] } },
)

phase('Synthesize')
const verdict = await agent(
  'Summarize the supplied router audits into {ok, violations: [...]}. Reply with only JSON.',
  { label: 'final verdict', agent: 'Plan', objective: 'Create the final decision-ready audit report.', inputs: ['router audits'], produces: 'audit verdict', schema: { type: 'object', required: ['ok', 'violations'] } },
)
return verdict

In strict mode, activate declared phases exactly in order; agent inputs are artifact-name arrays (not inline records), every declared phase output must be published exactly once (an agent automatically publishes its declared `produces`, or use `publish(name, value)` for aggregates), and the final `synthesis` phase must publish its named final artifact. Give every phase a goal, every agent a unique label and objective, and all real handoffs named inputs/outputs.

Rules: plain JavaScript (no TypeScript, no `import`/`require`); the leading `export const meta = { name, description }` is optional but conventional; the script must call `agent()` at least once; the return value must be JSON-serializable (a common mistake is returning an unawaited `agent()` promise).

API

| Global | Behavior | |--------|----------| | `agent(prompt, opts)` | Runs one subagent; resolves to its final text, or the parsed+shape-checked object when `opts.schema` is set, or `null` on failure. Opts: `label` (short, unique - drives the live display), `objective` (responsibility), `inputs` (artifact-name strings or a record of named string values), `produces` (one artifact name), `agent` (`'Explore'` default, `'Plan'`, or `'General'`), `schema` (plain JSON Schema), `cwd`, `model` (tier keyword, see below). | | `parallel(thunks)` | `await parallel(items.map(i => () => agent(...)))` - functions, **not** promises. Results in input order; failed branches are `null`. | | `pipeline(items, ...stages)` | Fans items through sequential stages (map → verify → summarize). Items run concurrently; each item's stages run in order; each stage receives `(previousValue, originalItem, index)`. A failed stage nulls that item's slot. | | `phase(title, meta?)` | Marks a new stage of work for the live progress display. Prefer `phase('Audit', { goal: '...', inputs: ['inventory'], produces: ['findings'] })` so the upcoming plan and dependencies are visible before it runs. `goal`, `inputs`, and `produces` are optional; dynamic/conditional phases remain supported. | | `log(message)` | Appends a workflow-level log line (shown in the expanded view). | | `parseJson(text)` | Extracts JSON from an agent's text reply, tolerating fences and surrounding prose. Prefer `schema` on `agent()` instead. | | `args` | The JSON value passed in the tool ca

Read more
Ships withposthog

:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.

Get the whole plugin

Other skills on posthog.