Skip to content

Latest commit

 

History

History
923 lines (728 loc) · 27.4 KB

File metadata and controls

923 lines (728 loc) · 27.4 KB

Contributing to Awesome Motia Plugins

Thank you for your interest in contributing to the Awesome Motia Plugins list! We welcome contributions from the community, whether you're adding an existing plugin to the list or creating a brand new plugin to share with the ecosystem.

Table of Contents


How to Add a Plugin to the List

Already created a plugin? Here's how to add it to the awesome list:

  1. Search: Ensure your plugin isn't already listed in the README.
  2. Fork: Fork this repository.
  3. Add: Add your plugin to the README.md file in the appropriate category.
    • Format: - [Plugin Name](Link) - Description.
    • Keep descriptions concise and clear (1-2 sentences).
  4. Pull Request: Submit a Pull Request with a clear title (e.g., "Add plugin-analytics").

Submission Format Example

@yourusername/motia-plugin-analytics

npm version

Performance analytics and monitoring for Motia workbench.

Installation:

pnpm add @yourusername/motia-plugin-analytics

Usage:

import analyticsPlugin from '@yourusername/motia-plugin-analytics/plugin'

export default {
  plugins: [analyticsPlugin],
}

Guidelines for Listed Plugins

To maintain quality and consistency, plugins listed here should meet the following criteria:

  • Useful and Relevant: Plugins should provide meaningful functionality for the Motia ecosystem
  • Valid Links: All links should be accessible and point to active resources
  • Documentation: Include clear installation and usage instructions
  • Open Source Preferred: If your plugin is open source, please provide a link to the repository
  • NPM Package Recommended: Publishing to NPM makes installation easier (though not strictly required)
  • Working: Plugin should be tested and functional with the latest Motia version
  • Maintained: Plugin should be actively maintained or clearly marked as archived

Creating a New Plugin

Want to create a new plugin for Motia? This guide will walk you through the entire process, from creation to publication.

Overview

Motia plugins extend the workbench functionality with custom visualizations, integrations, and features. You can create plugins as independent NPM packages without modifying the core Motia repository.

Benefits:

  • ✅ Maintain your plugin independently with your own versioning
  • ✅ Share functionality across multiple projects
  • ✅ Contribute to the community via this awesome-plugins list
  • ✅ Publish to NPM for easy distribution

Quick Start with CLI

The fastest way to create a plugin:

# Create a new plugin project
pnpm dlx motia@latest create --plugin my-awesome-plugin

# Navigate to the plugin directory
cd my-awesome-plugin

# Install dependencies
pnpm install

# Build the plugin
pnpm run build

This generates a complete plugin project with:

  • ✅ TypeScript and React configuration
  • ✅ tsdown for fast, performant builds with React Compiler and Tailwind CSS v4
  • ✅ Example workbench UI component
  • ✅ All required dependencies

Manual Setup

If you want to understand or customize the plugin structure, here's what the CLI generates:

1. Project Structure

my-awesome-plugin/
├── src/
│   ├── components/
│   │   └── example-page.tsx    # Main UI component
│   ├── index.ts                 # Package entry point
│   ├── plugin.ts                # Plugin definition
│   └── styles.css               # Tailwind styles
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js            # PostCSS configuration
├── README.md
├── tsconfig.json
└── tsdown.config.ts             # tsdown build/bundle configuration

2. Configure package.json

{
  "name": "@yourusername/motia-plugin-yourfeature",
  "version": "1.0.0",
  "description": "Your awesome Motia plugin",
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "keywords": ["motia", "motia-plugin", "yourfeature"],
  "author": "Your Name",
  "license": "Apache-2.0",
  "repository": {
    "type": "git",
    "url": "https://github.com/yourusername/motia-plugin-yourfeature"
  },
  "exports": {
    ".": {
      "development": "./dist/index.development.js",
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    },
    "./plugin": {
      "development": "./dist/plugin.development.js",
      "types": "./dist/plugin.d.ts",
      "import": "./dist/plugin.js"
    },
    "./styles.css": "./dist/index.css"
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "tsdown",
    "dev": "tsdown --watch",
    "clean": "rm -rf dist"
  },
  "devDependencies": {
    "@motiadev/core": "latest",
    "@motiadev/ui": "latest",
    "@rollup/plugin-babel": "^6.0.4",
    "@tailwindcss/postcss": "^4.1.16",
    "@types/node": "^24.9.2",
    "@types/react": "^19.2.2",
    "babel-plugin-react-compiler": "^19.1.0-rc.2",
    "postcss": "^8.5.6",
    "react": "^19.2.0",
    "rollup-plugin-postcss": "^4.0.2",
    "tailwindcss": "^4.1.16",
    "tsdown": "^0.12.5",
    "typescript": "^5.9.3"
  },
  "publishConfig": {
    "exports": {
      ".": "./dist/index.js",
      "./plugin": "./dist/plugin.js",
      "./styles.css": "./dist/index.css"
    }
  }
}

3. Define Plugin Entry (src/plugin.ts)

import type { MotiaPlugin, MotiaPluginContext } from '@motiadev/core'

export default function plugin(motia: MotiaPluginContext): MotiaPlugin {
  // Optional: Register custom API endpoints
  motia.registerApi(
    {
      method: 'GET',
      path: '/__motia/my-plugin/data',
    },
    async (req, ctx) => {
      return {
        status: 200,
        body: { message: 'Hello from my plugin!' },
      }
    }
  )

  return {
    workbench: [
      {
        packageName: '@yourusername/motia-plugin-yourfeature',
        cssImports: ['@yourusername/motia-plugin-yourfeature/dist/styles.css'],
        label: 'Your Feature',
        position: 'bottom', // or 'top'
        componentName: 'ExamplePage',
        labelIcon: 'sparkles', // lucide-react icon name
      },
    ],
  }
}

Plugin Context API:

  • motia.printer - Logging utilities
  • motia.state - State management adapter
  • motia.lockedData - Thread-safe data access
  • motia.tracerFactory - Tracing functionality
  • motia.eventAdapter - Event system adapter
  • motia.registerApi() - Register custom API endpoints

4. Create UI Component (src/components/example-page.tsx)

import { Badge, Button } from '@motiadev/ui'
import { Sparkles } from 'lucide-react'
import type React from 'react'

export const ExamplePage: React.FC = () => {
  return (
    <div className="h-full w-full p-6 overflow-auto">
      <div className="max-w-4xl mx-auto space-y-6">
        <div className="flex items-center gap-3">
          <Sparkles className="w-8 h-8 text-primary" />
          <h1 className="text-3xl font-bold">Example Plugin</h1>
          <Badge variant="info">v1.0.0</Badge>
        </div>

        <p className="text-muted-foreground text-lg">
          Welcome to the example plugin! This demonstrates the basic structure and functionality of a Motia plugin.
        </p>

        <div className="p-6 space-y-4">
          <h2 className="text-xl font-semibold">What is this?</h2>
          <p className="text-muted-foreground">
            This is a minimal example plugin that shows how to create custom workbench tabs in Motia. Plugins can extend
            the Motia workbench with custom functionality, visualizations, and tools.
          </p>

          <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
            <div className="p-4 border rounded-lg">
              <h3 className="font-semibold mb-2">Easy to Create</h3>
              <p className="text-sm text-muted-foreground">Build plugins with React, TypeScript, and Tailwind CSS</p>
            </div>
            <div className="p-4 border rounded-lg">
              <h3 className="font-semibold mb-2">Integrated</h3>
              <p className="text-sm text-muted-foreground">Seamlessly integrate with Motia's workbench UI</p>
            </div>
            <div className="p-4 border rounded-lg">
              <h3 className="font-semibold mb-2">Powerful</h3>
              <p className="text-sm text-muted-foreground">Access Motia's plugin context and APIs</p>
            </div>
          </div>

          <div className="flex gap-2 mt-6">
            <Button variant="default">
              <Sparkles className="w-4 h-4" />
              Get Started
            </Button>
            <Button variant="outline">View Documentation</Button>
          </div>
        </div>

        <div className="p-6 space-y-4">
          <h2 className="text-xl font-semibold">Plugin Features</h2>
          <ul className="list-disc list-inside space-y-2 text-muted-foreground">
            <li>Custom workbench tabs with position control (top/bottom)</li>
            <li>Access to Motia's UI components library</li>
            <li>Integration with state management and APIs</li>
            <li>Real-time updates through streams</li>
            <li>TypeScript support with full type safety</li>
          </ul>
        </div>
      </div>
    </div>
  )
}

Styling Guidelines:

  • ✅ Use Tailwind utility classes only
  • ✅ Use Motia's UI component library (@motiadev/ui)
  • ✅ Avoid arbitrary values - use design system scales
  • ✅ Keep components responsive
  • ✅ Follow Motia's design patterns

5. Export Components (src/index.ts)

import './styles.css'

export { ExamplePage } from './components/example-page'

6. Add Styles (src/styles.css)

@import "@motiadev/ui/globals.css";
@import "tailwindcss";

7. Configure tsdown for Bundling (tsdown.config.ts)

import pluginBabel from '@rollup/plugin-babel'
import postcss from 'rollup-plugin-postcss'
import { defineConfig } from 'tsdown'

export default defineConfig([
  // Main JavaScript/TypeScript build
  {
    entry: {
      index: './src/index.ts',
      plugin: './src/plugin.ts',
    },
    format: 'esm',
    platform: 'browser',
    external: [/^react($|\/)/, 'react/jsx-runtime'],
    dts: { build: true },
    exports: { devExports: 'development' },
    clean: true,
    publint: true,
    unused: true,
    outDir: 'dist',
    plugins: [
      pluginBabel({
        babelHelpers: 'bundled',
        plugins: ['babel-plugin-react-compiler'],
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
      }),
    ],
  },
  // Separate CSS build
  {
    entry: { index: './src/styles.css' },
    format: 'esm',
    platform: 'browser',
    outDir: 'dist',
    clean: false,
    plugins: [
      postcss({
        extract: true,
        minimize: process.env.NODE_ENV === 'prod',
      }),
    ],
  },
])

Benefits of tsdown for bundling:

  • ✅ Faster, more performant builds than alternatives
  • ✅ Consistency with other Motia packages
  • ✅ Simpler configuration with sensible defaults
  • ✅ Built-in TypeScript declarations generation
  • ✅ React Compiler optimization via Babel plugin
  • ✅ Development exports for HMR support

8. PostCSS Configuration (postcss.config.js)

export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
}

9. TypeScript Configuration (tsconfig.json)

{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src"],
  "exclude": ["dist", "node_modules"]
}

10. Build Your Plugin

# Install dependencies
pnpm install

# Build
pnpm run build

# Watch mode for development
pnpm run dev

Plugin Architecture

Core Types

MotiaPlugin

type MotiaPlugin = {
  workbench: WorkbenchPlugin[]  // Array of workbench tab configurations
  dirname?: string              // Optional plugin directory
  steps?: string[]              // Optional custom steps
}

WorkbenchPlugin

type WorkbenchPlugin = {
  packageName: string           // Package registry name
  componentName?: string        // React component name to render
  label?: string                // Tab label text
  labelIcon?: string            // Icon name from lucide-react
  position?: 'bottom' | 'top'   // Tab position in workbench
  cssImports?: string[]         // CSS files to import
  props?: Record<string, any>   // Props passed to component
}

MotiaPluginContext

type MotiaPluginContext = {
  printer: Printer              // Logging utilities
  state: StateAdapter           // State management
  lockedData: LockedData        // Thread-safe data access
  tracerFactory: TracerFactory  // Tracing functionality
  eventAdapter: EventAdapter    // Event system
  registerApi: (...)            // Register custom API endpoints
}

Testing Your Plugin

Before publishing, test your plugin in a Motia project:

Method 1: NPM Link (Recommended)

# In your plugin directory
pnpm link --global

# In your Motia project
pnpm link --global @yourusername/motia-plugin-yourfeature

Method 2: Local Path

In your Motia project's package.json:

{
  "dependencies": {
    "@yourusername/motia-plugin-yourfeature": "file:../path/to/your/plugin"
  }
}

Use in motia.config.ts

import yourPlugin from '@yourusername/motia-plugin-yourfeature/plugin'

export default {
  plugins: [yourPlugin],
}

Start Motia and Test

# In your Motia project
npx motia dev

# Open workbench and verify your plugin appears
# Test all functionality
# Check browser console for errors

Publishing to NPM

Once your plugin is tested and ready, publish it to NPM for easy distribution.

Prerequisites

  1. Create NPM account: npmjs.com/signup
  2. Login to NPM CLI:
    npm login

Publishing Steps

  1. Build your plugin:

    pnpm run build
  2. Verify package contents:

    npm pack --dry-run

    This shows what will be published. Ensure only dist/ and necessary files are included.

  3. Publish to NPM:

    npm publish --access public

    Note: For scoped packages (@yourusername/...), you need --access public for the first publish

  4. Verify publication:

    npm view @yourusername/motia-plugin-yourfeature

Version Updates

When releasing updates:

# Patch release (1.0.0 → 1.0.1) - Bug fixes
npm version patch

# Minor release (1.0.1 → 1.1.0) - New features, backward compatible
npm version minor

# Major release (1.1.0 → 2.0.0) - Breaking changes
npm version major

# Rebuild and publish
pnpm run build
npm publish

Publishing Checklist

Before publishing, ensure:

  • ✅ README.md is comprehensive
  • ✅ package.json metadata is complete (description, keywords, author, repository)
  • ✅ LICENSE file is included
  • ✅ Plugin builds without errors
  • ✅ Plugin has been tested in a real Motia project
  • ✅ Version number follows semantic versioning
  • ✅ CHANGELOG.md documents changes (recommended)
  • dist/ folder contains all necessary files
  • ✅ CSS is properly exported in package.json

Plugin Best Practices

Naming Convention

  • ✅ Use @yourusername/motia-plugin-featurename (scoped, recommended)
  • ✅ Or motia-plugin-featurename (unscoped)
  • ✅ Include "motia" and "plugin" for discoverability
  • ✅ Use lowercase and hyphens, no spaces

Good Examples:

  • @acme/motia-plugin-analytics
  • @mycompany/motia-plugin-performance
  • motia-plugin-custom-charts

Bad Examples:

  • my-plugin (not discoverable)
  • MotiaPluginAnalytics (should be lowercase)
  • @acme/analytics (missing motia/plugin context)

Documentation

Your plugin repository should include:

  • Comprehensive README.md with:

    • Clear description of what the plugin does
    • Installation instructions
    • Usage examples with code snippets
    • Configuration options
    • Screenshots or GIFs showing the plugin in action
    • API endpoint documentation (if applicable)
    • Environment variables (if any)
    • Troubleshooting section
  • LICENSE file (MIT, Apache 2.0, etc.)

  • CHANGELOG.md documenting version changes

  • Contributing guidelines (if accepting contributions)

Code Quality

  • ✅ Use TypeScript for type safety
  • ✅ Follow Motia's design system
  • ✅ Keep components simple and performant
  • ✅ Add proper error handling
  • ✅ Use meaningful variable and function names
  • ✅ Add comments for complex logic
  • ✅ Handle loading and error states in UI

Versioning

  • ✅ Follow Semantic Versioning
    • MAJOR: Breaking changes
    • MINOR: New features, backward compatible
    • PATCH: Bug fixes
  • ✅ Test with latest Motia version before releasing
  • ✅ Document breaking changes clearly

Dependencies

  • ✅ Use peer dependencies for Motia packages
  • ✅ Minimize additional dependencies
  • ✅ Pin versions or use caret ranges (^)
  • ✅ Document required peer dependencies in README
  • ✅ Keep dependencies up to date

Performance

  • ✅ Lazy load heavy components when possible
  • ✅ Debounce API calls and user inputs
  • ✅ Use React.memo for expensive components
  • ✅ Optimize images and assets
  • ✅ Avoid unnecessary re-renders

Advanced Features

Including Custom Steps

Plugins can include their own steps (API routes, event handlers, cron jobs):

import path from 'node:path'
import type { MotiaPlugin, MotiaPluginContext } from '@motiadev/core'

export default function plugin(motia: MotiaPluginContext): MotiaPlugin {
  return {
    dirname: path.join(__dirname, 'steps'),
    steps: ['**/*.step.ts', '**/*_step.py'],
    workbench: [
      {
        packageName: '@yourusername/motia-plugin-yourfeature',
        // ... other config
      },
    ],
  }
}

Plugin steps are discovered recursively following the same rules as regular steps. This allows you to:

  • Add custom API endpoints as steps
  • Include background event handlers
  • Add scheduled cron jobs
  • Provide example workflows

Using State Management

export default function plugin(motia: MotiaPluginContext): MotiaPlugin {
  motia.registerApi(
    { method: 'GET', path: '/__motia/my-plugin/state' },
    async (req, ctx) => {
      const value = await motia.state.get('my-key')
      return { status: 200, body: { value } }
    }
  )
  
  motia.registerApi(
    { method: 'POST', path: '/__motia/my-plugin/state' },
    async (req, ctx) => {
      await motia.state.set('my-key', req.body.value)
      return { status: 200, body: { success: true } }
    }
  )
  
  return { workbench: [/* ... */] }
}

Accessing Event System

export default function plugin(motia: MotiaPluginContext): MotiaPlugin {
  // Emit events
  motia.registerApi(
    { method: 'POST', path: '/__motia/my-plugin/notify' },
    async (req, ctx) => {
      await motia.eventAdapter.emit('my-plugin-event', req.body)
      return { status: 200, body: { sent: true } }
    }
  )
  
  return { workbench: [/* ... */] }
}

Environment Configuration

If your plugin needs configuration, use environment variables:

export default function plugin(motia: MotiaPluginContext): MotiaPlugin {
  const apiKey = process.env.MY_PLUGIN_API_KEY
  const endpoint = process.env.MY_PLUGIN_ENDPOINT || 'https://default.api'
  
  if (!apiKey) {
    motia.printer.printPluginWarn('MY_PLUGIN_API_KEY not set')
  }
  
  // ... use config
}

Document required environment variables in your README:

## Configuration

Set the following environment variables:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `MY_PLUGIN_API_KEY` | Yes | - | API key for service |
| `MY_PLUGIN_ENDPOINT` | No | `https://default.api` | API endpoint URL |

Adding Custom Dependencies

Add any dependencies your plugin needs:

pnpm add axios zustand date-fns

Update package.json:

{
  "dependencies": {
    "lucide-react": "^0.548.0"
  }
}

Examples and References

Official Plugins Reference

Note: The CLI (pnpm dlx motia@latest create --plugin) generates plugins that use tsdown for fast, performant bundling with React Compiler and Tailwind CSS v4 support. All official plugins in the monorepo use tsdown for a consistent build experience across the Motia ecosystem.

Study these official plugins for inspiration:

Plugin Purpose Key Features Source
plugin-example Minimal template Basic structure, simple UI Code
plugin-logs Log viewer Real-time streaming, filtering, search Code
plugin-bullmq Queue management Custom APIs, state management, complex UI Code
plugin-endpoint API testing Request handling, forms, response visualization Code
plugin-observability Performance tracing Trace visualization, metrics, distributed tracing Code
plugin-states State inspector State management, history tracking, JSON viewer Code

Official Resources

Community


Troubleshooting

Plugin Not Showing in Workbench

Symptoms: Plugin doesn't appear in workbench tabs after installation

Solutions:

  • ✅ Check plugin is imported in motia.config.ts
  • ✅ Verify componentName matches your exported component exactly
  • ✅ Ensure plugin is built (pnpm run build)
  • ✅ Check browser console for errors
  • ✅ Restart Motia dev server after adding plugin
  • ✅ Clear browser cache and reload

Styles Not Loading

Symptoms: Plugin appears but styling is broken or missing

Solutions:

  • ✅ Verify CSS is imported in src/index.ts
  • ✅ Check cssImports path in src/plugin.ts points to dist/index.css
  • ✅ Ensure PostCSS is configured in tsdown.config.ts
  • ✅ Rebuild plugin: pnpm run build
  • ✅ Check that dist/index.css exists after build
  • ✅ Verify PostCSS configuration in postcss.config.js

Type Errors

Symptoms: TypeScript errors when importing or using plugin

Solutions:

  • ✅ List @motiadev/core and @motiadev/ui in peerDependencies, not dependencies
  • ✅ Run pnpm install to resolve peer dependencies
  • ✅ Set declaration: true in tsconfig.json
  • ✅ Check TypeScript version compatibility (use ^5.7.0)
  • ✅ Rebuild with pnpm run build to regenerate type definitions
  • ✅ Ensure dist/ contains .d.ts files

Build Errors

Symptoms: pnpm run build fails

Solutions:

  • ✅ Check all imports are correct
  • ✅ Ensure all dependencies are installed
  • ✅ Verify tsdown.config.ts configuration
  • ✅ Check for TypeScript errors: tsc --noEmit
  • ✅ Clear build cache: pnpm run clean && pnpm run build
  • ✅ Update dependencies to compatible versions
  • ✅ Ensure tsdown and Babel plugins are installed

Plugin Works Locally But Not After Publishing

Symptoms: Plugin works with pnpm link but fails when installed from NPM

Solutions:

  • ✅ Check files field in package.json includes dist/
  • ✅ Verify exports in package.json are correct
  • ✅ Test with npm pack and inspect the tarball before publishing
  • ✅ Ensure peer dependencies match consumer's versions
  • ✅ Check external dependencies are correctly configured in tsdown
  • ✅ Rebuild before publishing: pnpm run clean && pnpm run build
  • ✅ Verify CSS file is included in the package

Need Help?

If you're stuck or have questions:

  1. Check Documentation: Review the official plugin guide
  2. Review Examples: Look at official plugin implementations
  3. Search Issues: Check if someone already asked in GitHub Issues
  4. Ask Community: Join Motia Discord for real-time help
  5. Open Discussion: Start a GitHub Discussion

Summary

Creating and contributing a Motia plugin:

  1. Create: pnpm dlx motia@latest create --plugin my-plugin
  2. Develop: Build your plugin with React, TypeScript, tsdown, and Motia UI
  3. Test: Link locally and test thoroughly in a Motia project
  4. Document: Write comprehensive README with examples and screenshots
  5. Publish: npm publish --access public
  6. Share: Submit PR to awesome-plugins

Let's build an amazing ecosystem together! 🚀


License

This repository and its contents are licensed under the Apache License 2.0. See the LICENSE file for details.