All Docs
FeaturesSidekickUpdated March 11, 2026

UnifiedEvent & UnifiedAction: The Type System Powering Every Integration

UnifiedEvent & UnifiedAction: The Type System Powering Every Integration

Sidekick connects to 100+ services — chat platforms, email, calendars, dev tools, smart home devices, and more. For the agent engine to reason across all of them coherently, every integration must speak the same language. That language is the UnifiedEvent and UnifiedAction type system, introduced in v1.0.0.


The Problem: 100+ APIs, 100+ Shapes

Every external service has its own event format. A GitHub push webhook looks nothing like a Slack message, which looks nothing like a Google Calendar update. Without normalization, the agent engine would need bespoke logic for every service — impossible to maintain and impossible to scale.

Sidekick solves this with a unified adapter architecture. Every integration is responsible for one thing: translating its native API payloads into a standard shape the engine understands. That standard shape is UnifiedEvent (for inbound data) and UnifiedAction (for outbound instructions).


UnifiedEvent

A UnifiedEvent represents anything that happened in a connected service — a new email arrived, a repo was pushed to, a smart home sensor triggered. Regardless of which integration produced it, every event the agent engine receives is a UnifiedEvent.

// Every adapter normalizes its raw webhook/poll payload into this shape
interface UnifiedEvent {
  id: string;              // Unique event ID
  source: string;          // Integration identifier (e.g. "github", "gmail")
  type: string;            // Event type (e.g. "push", "message.received")
  timestamp: string;       // ISO 8601 timestamp
  payload: Record<string, unknown>; // Normalized event data
  raw?: unknown;           // Original payload (preserved for debugging)
}

Validation

All UnifiedEvent instances are validated at the adapter boundary using a Zod schema. If an adapter produces a malformed event, it is caught and rejected before it can reach the agent engine:

import { UnifiedEventSchema } from '@sidekick/types';

const result = UnifiedEventSchema.safeParse(rawPayload);
if (!result.success) {
  // Invalid event — logged and dropped before reaching the engine
}

UnifiedAction

A UnifiedAction represents something the agent engine wants to do — send a Slack message, create a calendar event, merge a pull request. The engine emits actions in this standard shape; adapters translate them into the appropriate API calls.

// The agent engine emits this shape; adapters execute the underlying API call
interface UnifiedAction {
  id: string;              // Unique action ID
  target: string;          // Integration identifier (e.g. "slack", "gcal")
  type: string;            // Action type (e.g. "message.send", "event.create")
  payload: Record<string, unknown>; // Action parameters
  correlationId?: string;  // Links the action back to a triggering event
}

Validation

Like events, all actions are validated before dispatch:

import { UnifiedActionSchema } from '@sidekick/types';

const result = UnifiedActionSchema.safeParse(agentOutput);
if (!result.success) {
  // Invalid action — not dispatched to the adapter
}

Database Serialization

Both types include serialization helpers for persisting to and restoring from the database. This enables:

  • Audit trails — every event received and action taken is recorded.
  • Replay — events can be reprocessed if an adapter or skill is updated.
  • Retry — failed actions can be re-dispatched without re-fetching the original payload.
import { serializeUnifiedEvent, deserializeUnifiedEvent } from '@sidekick/types';

// Persist
const row = serializeUnifiedEvent(event);
await db.insert('events', row);

// Restore
const event = deserializeUnifiedEvent(row);

Why This Matters for ClawHub Skills

Sidekick is fully compatible with OpenClaw's 13,000+ community skills via ClawHub. Every skill is written against the same UnifiedEvent/UnifiedAction contract. When a SKILL.md is imported, Sidekick's runtime maps its event triggers and action outputs to this type system automatically — local binary requirements are translated to cloud services transparently. No changes to the skill are needed.


Building an Adapter

If you are implementing a new integration, your adapter has two responsibilities:

  1. Inbound: Translate raw payloads from the external service into UnifiedEvent instances and pass them to the engine.
  2. Outbound: Accept UnifiedAction instances from the engine and execute the appropriate API call against the external service.

The type definitions and Zod schemas are exported from @sidekick/types:

import {
  UnifiedEvent,
  UnifiedEventSchema,
  UnifiedAction,
  UnifiedActionSchema,
  serializeUnifiedEvent,
  deserializeUnifiedEvent,
  serializeUnifiedAction,
  deserializeUnifiedAction,
} from '@sidekick/types';

Every adapter that correctly implements this contract works with the full Sidekick platform — including the agent engine, the audit log, action retry, and ClawHub skill compatibility — with no additional integration work.