packages/cli/skills/pikku-workflows-client/SKILL.md
Run Pikku workflows from a React frontend and track their progress. Covers `useRunWorkflow` (run-and-wait), `useStartWorkflow` (fire-and-poll), and `useWorkflowStatus` (live status). TRIGGER when: a React component needs to invoke or display the status of a Pikku workflow, the user mentions long-running tasks / background jobs / progress UI tied to a workflow, or asks how to start/track a workflow from the client. DO NOT TRIGGER when: the user is wiring the workflow itself (use pikku-workflow) or only making regular RPC calls (use pikku-react-query).
npx skillsauth add pikkujs/pikku pikku-workflows-clientInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill as an execution checklist, not reference material.
pikku-meta when available; otherwise run the relevant pikku meta ... --json command and inspect only the focused output you need..pikku, node_modules, vendored packages, or broad build artifacts.pikku-verify or pikku all when functions, wirings, schemas, or generated clients may have changed.When a project has pikkuWorkflowGraph workflows, three React Query
hooks are auto-generated alongside the standard RPC hooks. They handle
the two common shapes: run-and-wait (short workflows where the
client waits for the result) and fire-and-poll (long workflows where
the client gets a runId and polls status).
yarn pikku meta clients --json | jq '.workflows'
Each entry has name, description, mode (inline | distributed), plus
input / output type names. Pass the workflow name to the hooks
below.
These hooks are generated into the same api.gen.ts as usePikkuQuery —
no extra setup beyond PikkuProvider + QueryClientProvider (see the
pikku-react and pikku-react-query skills).
useRunWorkflow(name, options?) — run and waitFor short, synchronous-feeling workflows. Returns a mutation that resolves to the workflow's output.
import { useRunWorkflow } from './pikku/api.gen'
function ChargeButton({ orderId }: { orderId: string }) {
const run = useRunWorkflow('chargeOrder', {
onSuccess: (output) => toast.success(`Charged: $${output.amount}`),
})
return (
<button onClick={() => run.mutate({ orderId })} disabled={run.isPending}>
{run.isPending ? 'Charging…' : 'Charge'}
</button>
)
}
Use this when the workflow finishes in seconds and the UI can hold open a loading state until done.
useStartWorkflow(name, options?) — fire-and-pollReturns a mutation that resolves to { runId: string } immediately. The
workflow keeps running on the server. Pair with useWorkflowStatus to
render progress.
const start = useStartWorkflow('processVideo', {
onSuccess: ({ runId }) => setActiveRunId(runId),
})
start.mutate({ videoId: '123' })
Use this for long-running workflows (uploads, batch jobs, AI generation, anything you'd want a progress bar for).
useWorkflowStatus(workflowName, runId, options?) — observePolls the workflow runtime for a run's status. Returns a typed status
object with status, optional output, and optional error.
import { useWorkflowStatus } from './pikku/api.gen'
function VideoStatus({ runId }: { runId: string }) {
const { data: status } = useWorkflowStatus('processVideo', runId, {
refetchInterval: (query) =>
query.state.data?.status === 'running' ? 1000 : false,
})
if (!status) return null
if (status.status === 'running') return <Spinner />
if (status.status === 'completed') return <Result {...status.output} />
if (status.status === 'failed')
return <Error message={status.error?.message} />
return null
}
Status values: 'running' | 'suspended' | 'completed' | 'failed' | 'cancelled'.
The hook stops auto-polling when the run reaches a terminal state (set
refetchInterval to false in those cases — pattern shown above).
function ProcessVideoFlow({ videoId }: { videoId: string }) {
const [runId, setRunId] = useState<string>()
const start = useStartWorkflow('processVideo', {
onSuccess: ({ runId }) => setRunId(runId),
})
const status = useWorkflowStatus('processVideo', runId)
if (!runId) {
return (
<button
onClick={() => start.mutate({ videoId })}
disabled={start.isPending}
>
Start
</button>
)
}
return <ProgressBar status={status.data?.status} />
}
The status hook returns a coarse-grained state machine (running,
completed, etc.). For step-by-step updates inside a long workflow,
publish events from the workflow itself via eventHub or open a
WebSocket channel — out of scope for this skill (see workflow + channel
docs).
useWorkflowStatus with
refetchInterval. It dedupes and stops on terminal states.useRunWorkflow for workflows that take more than a few
seconds. The user-facing component will hold a long-running pending
state with no progress indication; use start + status instead.usePikkuQuery /
usePikkuMutation.documentation
Deprecated — use pikku-middleware instead. Tag middleware (addTagMiddleware) is now documented as a section within the pikku-middleware skill, alongside global HTTP middleware, execution order, and the service-to-service bearer auth pattern.
testing
Use when adding authorization checks to Pikku functions or routes — pikkuPermission, pikkuAuth, per-function permissions, pattern-based permissions, or understanding OR/AND permission logic. TRIGGER when: user wants to restrict who can call a function, check resource ownership, add role-based access, or understand where permission checks belong. DO NOT TRIGGER when: user asks about middleware or request interception (use pikku-middleware), authentication strategies (use pikku-security), or session management.
testing
Use when adding any middleware to a Pikku app — global HTTP middleware, tag-scoped middleware (including service-to-service bearer auth), per-route middleware, session-setting middleware, or understanding middleware execution order and priority. TRIGGER when: user wants middleware on some or all routes, machine-to-machine auth, tag-scoped cross-cutting concerns, global interceptors, or middleware priority/order questions. DO NOT TRIGGER when: user asks about permissions/authorization checks (use pikku-permissions), auth strategies like authBearer/authCookie (use pikku-security), or deployment.
documentation
Standard cleanup to run right after a Pikku template is cloned or scaffolded into a new project. TRIGGER when: a Pikku template was just cloned/scaffolded (via `pikku create`, `git clone <template>`, or the user says "I cloned the kanban template / starter / template"), or the working tree still looks like an untouched template (template README, placeholder `@project/*` name in package.json). DO NOT TRIGGER when: working in an established project mid-feature, or editing the template repo itself.