Claude Code Plugins

Community-maintained marketplace

Feedback
0
0

Write external integrations following the Epic architecture patterns. Use when creating services for third-party APIs, email, payments, or complex business logic. Triggers on "create an integration", "add a service", or "integrate with".

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name write-integration
description Write external integrations following the Epic architecture patterns. Use when creating services for third-party APIs, email, payments, or complex business logic. Triggers on "create an integration", "add a service", or "integrate with".

Write Integration

Overview

This skill creates external integrations that follow the Epic three-layer architecture. Integrations belong to the Infrastructure layer and handle external API calls, complex business logic, and reusable services.

Architecture Context

Backend: Actions call integrations
            |
            v
Infrastructure: Integrations (external APIs, complex logic)
                     |
                     v
              External Services (Stripe, GitHub, OpenAI, etc.)

Integrations:

  • Run on the server (Infrastructure layer)
  • Handle external API integrations
  • Implement complex reusable business logic
  • May only be called by Backend layer (Actions, Routes)
  • NEVER imported by Frontend
  • NEVER call other routes or actions

Integration Location

shared/integrations/
  integration-name/
    integration-name.ts       # Main integration
    types.ts                  # TypeScript types
    index.ts                  # Public exports

Class Specification Format

Follow the Epic Class specification format from docs/Epic.md:

# ServiceName

[Description of what external system this integrates with]

## Properties
- config: ServiceConfig
- client: ExternalClient

## Methods
- methodName(params): Promise<Result>

## Relationships
- Composes: ExternalSDK

Implementation Pattern

import 'server-only';

interface ServiceConfig {
  apiKey: string;
  baseUrl?: string;
}

interface MethodResult<T> {
  success: boolean;
  data?: T;
  error?: string;
}

const defaultConfig: Partial<ServiceConfig> = {
  baseUrl: 'https://api.example.com',
};

export class ServiceName {
  private config: ServiceConfig;

  constructor(config?: Partial<ServiceConfig>) {
    this.config = {
      ...defaultConfig,
      apiKey: config?.apiKey || process.env.SERVICE_API_KEY!,
      ...config,
    };

    if (!this.config.apiKey) {
      throw new Error('ServiceName: API key is required');
    }
  }

  async methodName(params: MethodParams): Promise<MethodResult<ReturnType>> {
    try {
      const response = await fetch(`${this.config.baseUrl}/endpoint`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.config.apiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(params),
      });

      if (!response.ok) {
        const error = await response.text();
        return { success: false, error };
      }

      const data = await response.json();
      return { success: true, data };
    } catch (error) {
      console.error('ServiceName.methodName error:', error);
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }
}

// Export singleton instance
export const serviceName = new ServiceName();

Integration Categories

1. Communication Services

// Email (Resend, SendGrid)
export class EmailService {
  async send(to: string, subject: string, html: string): Promise<Result> {
    // Implementation
  }
}

// SMS (Twilio)
export class SMSService {
  async send(to: string, message: string): Promise<Result> {
    // Implementation
  }
}

2. Payment Services

// Stripe
export class StripeService {
  async createCheckoutSession(params: CheckoutParams): Promise<Result<Session>> {
    // Implementation
  }

  async handleWebhook(payload: string, signature: string): Promise<Event> {
    // Implementation
  }
}

3. AI/ML Services

// OpenAI, Anthropic
export class AIService {
  async complete(prompt: string, options?: Options): Promise<Result<string>> {
    // Implementation
  }

  async embed(text: string): Promise<Result<number[]>> {
    // Implementation
  }
}

4. Storage Services

// S3, Cloudinary
export class StorageService {
  async upload(file: Buffer, path: string): Promise<Result<string>> {
    // Implementation
  }

  async delete(path: string): Promise<Result<boolean>> {
    // Implementation
  }
}

5. External APIs

// GitHub, Vercel, etc.
export class GitHubService {
  async createRepository(name: string): Promise<Result<Repository>> {
    // Implementation
  }

  async createIssue(repo: string, title: string): Promise<Result<Issue>> {
    // Implementation
  }
}

Error Handling Pattern

async methodName(params: Params): Promise<Result<T>> {
  try {
    // Validate configuration
    if (!this.config.apiKey) {
      return { success: false, error: 'API key not configured' };
    }

    // Make request with retry logic
    const response = await this.withRetry(() =>
      fetch(url, options)
    );

    // Handle rate limiting
    if (response.status === 429) {
      return { success: false, error: 'Rate limit exceeded' };
    }

    // Handle errors
    if (!response.ok) {
      const error = await response.json();
      return { success: false, error: error.message };
    }

    const data = await response.json();
    return { success: true, data };
  } catch (error) {
    console.error('Service error:', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Unknown error',
    };
  }
}

private async withRetry<T>(
  fn: () => Promise<T>,
  retries = 3
): Promise<T> {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(r => setTimeout(r, 1000 * (i + 1)));
    }
  }
  throw new Error('Max retries exceeded');
}

Constraints

  • MUST include import 'server-only' at top
  • NEVER import React, Jotai, or frontend code
  • NEVER call other routes or actions
  • ALWAYS use environment variables for secrets
  • ALWAYS return consistent { success, data?, error? } format
  • ALWAYS implement proper error handling
  • ALWAYS log errors for debugging

Checklist

Before finalizing an integration:

  • server-only import present
  • Environment variables documented
  • Error handling with try/catch
  • Consistent return format
  • Retry logic for transient failures
  • Rate limiting handling
  • Logging for debugging
  • TypeScript types exported

Example Specification

# StripeService

Handles Stripe payment processing and subscription management.

## Properties
- stripe: Stripe - SDK client instance

## Methods
- createCheckoutSession(params: CheckoutParams): Promise<Result<Session>>
- createCustomer(email: string): Promise<Result<Customer>>
- handleWebhook(payload: string, signature: string): Promise<Event>

## Relationships
- Composes: Stripe SDK