From harness-claude
Generates full TypeScript type safety for XState machines using typegen (v4) and setup pattern (v5). Provides autocompletion for states/events/actions; resolves errors in guards/actions.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Generate full type safety for XState machines with typegen (v4) and the setup pattern (v5)
Defines XState state machines with createMachine for explicit states, transitions, context, and events. For modeling complex UI flows like forms, wizards, authentication, and workflows preventing illegal transitions.
Builds, tests, and debugs event-driven state machines with EventMachine Laravel package for declarative workflows, parallel states, child delegation, event sourcing, timers, and HTTP endpoints.
Designs finite state machines and statecharts for modeling entity lifecycles, workflows, and system behaviors using Harel semantics, PlantUML, and Mermaid notation.
Share bugs, ideas, or general feedback.
Generate full type safety for XState machines with typegen (v4) and the setup pattern (v5)
setup() to declare all types, actions, guards, actors, and delays before creating the machine.types with TypeScript as assertion for context, events, input, and output.setup() — runtime errors if missing.setup() declaration — no separate code generation step.// auth.machine.ts (v5)
import { setup, assign, fromPromise } from 'xstate';
interface AuthContext {
user: { id: string; name: string } | null;
error: string | null;
}
type AuthEvent = { type: 'LOGIN'; email: string; password: string } | { type: 'LOGOUT' };
const authMachine = setup({
types: {} as {
context: AuthContext;
events: AuthEvent;
input: { redirectUrl?: string };
},
actors: {
authenticate: fromPromise(async ({ input }: { input: { email: string; password: string } }) => {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(input),
});
if (!res.ok) throw new Error('Auth failed');
return res.json() as Promise<{ id: string; name: string }>;
}),
},
actions: {
setUser: assign({
user: (_, params: { id: string; name: string }) => params,
}),
clearUser: assign({ user: null, error: null }),
setError: assign({
error: (_, params: { message: string }) => params.message,
}),
},
guards: {
isAuthenticated: ({ context }) => context.user !== null,
},
}).createMachine({
id: 'auth',
initial: 'idle',
context: ({ input }) => ({
user: null,
error: null,
}),
states: {
idle: {
on: { LOGIN: 'authenticating' },
},
authenticating: {
invoke: {
src: 'authenticate',
input: ({ event }) => ({
email: (event as { email: string }).email,
password: (event as { password: string }).password,
}),
onDone: {
target: 'authenticated',
actions: { type: 'setUser', params: ({ event }) => event.output },
},
onError: {
target: 'error',
actions: {
type: 'setError',
params: ({ event }) => ({ message: (event.error as Error).message }),
},
},
},
},
authenticated: {
on: { LOGOUT: { target: 'idle', actions: 'clearUser' } },
},
error: {
on: { LOGIN: 'authenticating' },
},
},
});
@xstate/cli: npm install -D @xstate/cli.tsTypes: {} to the machine config to enable typegen.xstate typegen "src/**/*.machine.ts" to generate .typegen.ts files.// v4 with typegen
import { createMachine } from 'xstate';
const machine = createMachine({
tsTypes: {} as import('./auth.machine.typegen').Typegen0,
schema: {
context: {} as AuthContext,
events: {} as AuthEvent,
services: {} as { authenticate: { data: User } },
},
// ...
});
v5 setup benefits over v4 typegen:
setup() directlyfromPromise, fromCallback, etc..typegen.ts files to maintain or commitTyping event narrowing in actions: In v5, action implementations receive the full event union. Narrow when needed:
actions: {
handleLogin: ({ event }) => {
if (event.type === 'LOGIN') {
console.log(event.email); // Typed correctly
}
},
},
Common type issues:
Type 'string' is not assignable to type 'never' in transitions — usually means the event is not listed in the events typesetup() — v5 requires all referenced names to be declared upfrontcontext function returnhttps://stately.ai/docs/typescript