packages/cli/skills/pikku-trigger/SKILL.md
Use when adding event-driven functions that respond to system events like Redis pub/sub, PostgreSQL LISTEN/NOTIFY, or custom event sources. Covers wireTrigger, wireTriggerSource, and pikkuTriggerFunc. TRIGGER when: code uses wireTrigger/wireTriggerSource/pikkuTriggerFunc, user asks about event-driven functions, Redis pub/sub, PostgreSQL LISTEN/NOTIFY, or reacting to external events. DO NOT TRIGGER when: user asks about scheduled tasks (use pikku-cron) or background job queues (use pikku-queue).
npx skillsauth add pikkujs/pikku pikku-triggerInstall 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.Wire Pikku functions to fire when external events occur. Triggers connect event sources (Redis pub/sub, PostgreSQL LISTEN/NOTIFY, polling, webhooks) to Pikku functions.
pikku info functions --verbose # See existing functions and their types
pikku info tags --verbose # Understand project organization
See pikku-concepts for the core mental model.
wireTrigger(config)Define the target function that handles trigger events:
import { wireTrigger } from '@pikku/core/trigger'
wireTrigger({
name: string, // Trigger name (matches source)
func: PikkuFunc, // Function to call when event fires
})
wireTriggerSource(config)Define the event source that fires triggers:
import { wireTriggerSource } from '@pikku/core/trigger'
wireTriggerSource({
name: string, // Must match wireTrigger name
func: PikkuTriggerFunc, // Source function (sets up listener)
input: object, // Configuration for the source
})
pikkuTriggerFunc<TInput, TEvent>Define a trigger source function. Returns a cleanup function.
import { pikkuTriggerFunc } from '#pikku'
const source = pikkuTriggerFunc<
InputType, // Configuration input
EventType // Shape of events it emits
>(async (services, input, { trigger }) => {
// Set up listener...
trigger.invoke(eventData) // Fire the trigger
// Return cleanup function
return async () => {
/* teardown */
}
})
const redisSubscribe = pikkuTriggerFunc<
{ channels: string[] },
{ channel: string; message: any }
>(async ({ redis }, { channels }, { trigger }) => {
const subscriber = redis.duplicate()
subscriber.on('message', (channel, message) => {
trigger.invoke({ channel, message: JSON.parse(message) })
})
await subscriber.subscribe(...channels)
return async () => {
await subscriber.unsubscribe()
await subscriber.quit()
}
})
// Target function
const onOrderEvent = pikkuSessionlessFunc({
title: 'On Order Event',
func: async ({ db, logger }, { channel, message }) => {
logger.info(`Order event on ${channel}`, message)
await db.processOrderEvent(message)
},
})
// Wire them together
wireTrigger({
name: 'order-events',
func: onOrderEvent,
})
wireTriggerSource({
name: 'order-events',
func: redisSubscribe,
input: { channels: ['orders:created', 'orders:updated'] },
})
| Feature | Trigger | Queue | | ----------- | ---------------------------------- | ------------------------------ | | Execution | Synchronous, in-process | Async, distributed | | Reliability | At-most-once | At-least-once (with retries) | | Use case | React to events immediately | Reliable background processing | | Source | External systems (Redis, PG, etc.) | Enqueued programmatically |
Use triggers for real-time reactions. Use queues for reliable, retryable background work.
// functions/triggers.functions.ts
const pgListen = pikkuTriggerFunc<{ channel: string }, { payload: any }>(
async ({ db }, { channel }, { trigger }) => {
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(channel)) {
throw new Error(`Invalid channel name: ${channel}`)
}
const client = await db.pool.connect()
client.on('notification', (msg) => {
trigger.invoke({ payload: JSON.parse(msg.payload) })
})
await client.query(`LISTEN ${channel}`)
return async () => {
await client.query(`UNLISTEN ${channel}`)
client.release()
}
}
)
const onUserCreated = pikkuSessionlessFunc({
title: 'On User Created',
func: async ({ emailService, logger }, { payload }) => {
logger.info('New user created', { userId: payload.id })
await emailService.sendWelcome(payload.email)
},
})
// wirings/triggers.wiring.ts
wireTrigger({ name: 'user-created', func: onUserCreated })
wireTriggerSource({
name: 'user-created',
func: pgListen,
input: { channel: 'user_created' },
})
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.