New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@openpets/slack

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@openpets/slack

Slack integration plugin for OpenCode - search channels, read messages, and post to Slack

latest
npmnpm
Version
1.0.4
Version published
Maintainers
1
Created
Source

Factory-Based Plugin Template

A comprehensive template for creating OpenCode plugins using the factory pattern with multi-provider workflow management. This template demonstrates modern plugin architecture with provider abstraction, configuration management, and workflow orchestration.

Table of Contents

  • Factory Architecture
  • Multi-Provider Design
  • Quick Start
  • Configuration Management
  • Workflow Tools
  • Provider Integration
  • Best Practices
  • Migration Guide
  • Testing

Factory Architecture

This template uses the factory pattern from src/core/plugin-factory.ts:

Key Components

  • Factory Functions: createPlugin() and createSingleTool()
  • Zod Schemas: Type-safe parameter validation
  • Provider Abstraction: Dynamic provider loading and fallbacks
  • Configuration Management: Environment-based multi-provider setup

Architecture Benefits

Type Safety: Zod schemas ensure parameter validation
Provider Agnostic: Support multiple providers per service type
Graceful Fallbacks: Automatic provider switching on failures
Configuration Driven: Environment-based provider selection
Workflow Focused: High-level orchestration tools

Multi-Provider Design

Provider Types

interface PluginConfig {
  providers: {
    github?: { token: string; apiUrl?: string }
    maps?: { provider: 'googlemaps' | 'mapbox'; apiKey: string }
    ai?: { provider: 'fal'; apiKey: string }
  }
  preferences: Record<string, string>
  workflow: { timeout: number; retries: number; logLevel: string }
}

Provider Selection Logic

  • Configuration Loading: Parse PROVIDER_PREFERENCES JSON
  • Provider Initialization: Load available providers based on API keys
  • Fallback Handling: Graceful degradation when providers fail
  • Dynamic Loading: Import providers only when needed

Quick Start

1. Copy This Template

# Navigate to pets directory
cd /Users/andrewmaguire/LOCAL/Github/raggle-code/raggle-repo/core/pets/

# Copy template
cp -r _TEMPLATE_ my-workflow-manager
cd my-workflow-manager

2. Install Dependencies

npm install

3. Configure Environment

# Copy environment template
cp .env.example .env

# Edit with your API keys
nano .env

Example .env:

# Primary providers
GITHUB_TOKEN=ghp_your_github_token
GOOGLE_MAPS_API_KEY=your_google_maps_key
FAL_KEY=your_fal_api_key

# Provider preferences
PROVIDER_PREFERENCES={"maps":"googlemaps","ai":"fal"}

# Workflow settings
DEFAULT_TIMEOUT=30000
MAX_RETRIES=3
LOG_LEVEL=info

4. Test the Template

# Check provider status
opencode run "check provider status"

# Demo workflow
opencode run "demo workflow with geocode and enhance for 'New York'"

Configuration Management

Environment Variables

VariableDescriptionRequired
GITHUB_TOKENGitHub personal access tokenOptional
GOOGLE_MAPS_API_KEYGoogle Maps API keyOptional
MAPBOX_ACCESS_TOKENMapbox access tokenOptional
FAL_KEYFAL AI API keyOptional
PROVIDER_PREFERENCESJSON string with provider preferencesOptional
DEFAULT_TIMEOUTOperation timeout in millisecondsOptional
MAX_RETRIESMaximum retry attemptsOptional
LOG_LEVELLogging level (debug/info/warn/error)Optional

Provider Preferences

{
  "maps": "googlemaps",
  "ai": "fal",
  "version_control": "github"
}

Workflow Tools

1. workflow-demo

Demonstrates multi-provider workflow orchestration.

Actions:

  • geocode-and-enhance: Geocode location and enhance with AI
  • create-and-tag: Create repository with location-based tags
  • ai-process: Process text using AI provider

Examples:

opencode run "demo workflow with geocode and enhance for 'San Francisco'"
opencode run "demo workflow with create and tag for 'my-project'"
opencode run "demo workflow with ai process for 'Hello world'"

2. manage-providers

Check provider status and availability.

Actions:

  • status: Show all provider statuses
  • test: Test provider connectivity
  • list: List available and configured providers

Examples:

opencode run "check provider status"
opencode run "test all providers"
opencode run "list available providers"

3. manage-config

Manage plugin configuration.

Actions:

  • get: Get configuration values
  • set: Set configuration values
  • validate: Validate configuration

Examples:

opencode run "get configuration"
opencode run "validate plugin configuration"
opencode run "set configuration key 'test.value' to 'demo'"

Provider Integration

Adding New Providers

  • Create Provider Utils (if not exists):
# Create new provider in src/utils/
mkdir src/utils/my-provider
cd src/utils/my-provider
  • Implement Provider Interface:
// src/utils/my-provider/index.ts
export interface MyProviderConfig {
  apiKey: string
  apiUrl?: string
}

export class MyProviderAPI {
  constructor(private config: MyProviderConfig) {}
  
  async processData(data: string) {
    // Implementation
  }
}
  • Update Template Configuration:
interface PluginConfig {
  providers: {
    // Add new provider
    myprovider?: { apiKey: string; apiUrl?: string }
  }
}
  • Add Provider Initialization:
const initializeProviders = async (config: PluginConfig) => {
  const providers: any = {}
  
  if (config.providers.myprovider) {
    const { MyProviderAPI } = await import('../../src/utils/my-provider')
    providers.myprovider = new MyProviderAPI(config.providers.myprovider)
  }
  
  return providers
}

Best Practices

1. Factory Pattern Usage

// ✅ Good: Use factory for tool creation
const tools = [
  {
    name: "my-tool",
    description: "Tool description",
    schema: z.object({ /* ... */ }),
    execute: async (args) => { /* ... */ }
  }
]

return createPlugin(tools)

// ❌ Bad: Direct tool definition
return {
  tool: {
    "my-tool": tool({ /* ... */ })
  }
}

2. Provider Management

// ✅ Good: Lazy loading with error handling
const initializeProvider = async (config: any) => {
  try {
    const ProviderAPI = await import('../../src/utils/provider')
    return new ProviderAPI(config)
  } catch (error) {
    console.warn(`Provider initialization failed:`, error)
    return null
  }
}

// ❌ Bad: Eager loading without error handling
const provider = new ProviderAPI(config)  // Fails if import errors

3. Configuration Validation

// ✅ Good: Comprehensive validation
const validateConfig = (config: PluginConfig) => {
  const errors: string[] = []
  
  if (!config.providers.github && !config.providers.maps) {
    errors.push("At least one provider must be configured")
  }
  
  return { valid: errors.length === 0, errors }
}

// ❌ Bad: No validation
const providers = await initializeProviders(config)  // May fail silently

4. Error Handling

// ✅ Good: Structured error responses
return createResponse(false, undefined, [{
  error: error.message,
  provider: providerName,
  action: args.action
}], { duration: Date.now() - startTime })

// ❌ Bad: Unstructured errors
throw new Error(`Operation failed: ${error.message}`)

Migration Guide

From Legacy Plugin Structure

Old Structure:

export const LegacyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
  return {
    tool: {
      "tool-name": tool({
        description: "...",
        args: { /* ... */ },
        execute: async (args) => { /* ... */ }
      })
    }
  }
}

New Factory Structure:

export const FactoryPlugin = async () => {
  const config = loadConfiguration()
  const providers = await initializeProviders(config)
  const tools = createWorkflowTools(providers, config)
  
  return createPlugin(tools)
}

Migration Steps

  • Remove Legacy Parameters: Plugin no longer receives { project, client, $, directory, worktree }
  • Add Configuration Loading: Implement loadConfiguration() function
  • Add Provider Management: Implement initializeProviders() function
  • Convert Tools to Factory: Use createPlugin() instead of direct tool objects
  • Update Tool Schemas: Use Zod schemas instead of JSON schemas
  • Add Error Handling: Implement structured error responses

Testing

Unit Testing

# Test individual tools
npm run test:queries

# Test workflow scenarios
npm run test:scenarios

# Test all functionality
npm run test:all

Provider Testing

# Test provider connectivity
opencode run "test all providers"

# Test provider fallbacks
# Temporarily disable primary provider and test fallbacks

Configuration Testing

# Test with missing environment variables
unset GITHUB_TOKEN
opencode run "validate plugin configuration"

# Test with invalid configuration
PROVIDER_PREFERENCES='{"invalid":"provider"}' opencode run "check provider status"

Advanced Patterns

1. Dynamic Provider Discovery

const discoverProviders = async () => {
  const providerDir = '../../src/utils'
  const providers = await fs.readdir(providerDir)
  
  return Promise.all(
    providers
      .filter(name => !name.startsWith('.'))
      .map(async name => {
        try {
          const module = await import(`${providerDir}/${name}`)
          return { name, module: module.default || module }
        } catch {
          return { name, error: 'Failed to load' }
        }
      })
  )
}

2. Provider Health Monitoring

const monitorProviderHealth = async (providers: any) => {
  const health = await Promise.allSettled(
    Object.entries(providers).map(async ([name, provider]) => [
      name,
      {
        status: await testProvider(provider),
        lastCheck: new Date().toISOString(),
        responseTime: await measureResponseTime(provider)
      }
    ])
  )
  
  return Object.fromEntries(health)
}

3. Workflow Composition

const composeWorkflow = (steps: WorkflowStep[]) => async (input: any) => {
  let result = input
  
  for (const step of steps) {
    try {
      result = await step.execute(result)
    } catch (error) {
      if (step.required) {
        throw error
      }
      console.warn(`Optional step ${step.name} failed:`, error)
    }
  }
  
  return result
}

Directory Structure

my-workflow-manager/
├── index.ts              # Factory-based plugin implementation
├── package.json          # Dependencies and metadata
├── README.md             # This documentation
├── .env.example          # Environment variable template
├── .env                  # Your actual configuration (gitignored)
├── .gitignore           # Git ignore file
└── opencode.json        # OpenCode configuration

Need Help?

  • Factory Pattern: See src/core/plugin-factory.ts
  • Provider Examples: See src/utils/ directory
  • Documentation: See prompts/pet-creator.md for LLM guidance

License

MIT - feel free to use this template for your own workflow managers!

Happy workflow building! 🚀

Keywords

opencode

FAQs

Package last updated on 27 Nov 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts