Create a Plugin

Create a Plugin

Goal: Build a custom plugin for document processing

This guide provides an overview of plugin development. For detailed guides, see the plugin-type-specific pages below.


Install the SDK

pip install bizsupply-sdk

The bizsupply-sdk package provides all base classes, models, and CLI tools for plugin development.


Plugin Types

TypePurposeGuide
ClassificationCategorize documents with labelsCreate a Classification Plugin
ExtractionExtract structured data from documentsCreate an Extraction Plugin
SourceIngest documents from external systemsCreate a Source Plugin
BenchmarkScore documents and compare metricsCreate a Benchmark
AggregationCreate relationships between documentsContact support

CRITICAL: Plugin Requirements

All plugins MUST follow these requirements or they will fail:

RequirementDetailsIf Violated
Install SDKpip install bizsupply-sdkImport errors
Import base classfrom bizsupply_sdk import ClassificationPluginNameError
Inherit base classclass MyPlugin(ClassificationPlugin):Registration fails
Type-specific methodclassify(), extract(), or fetch()Runtime error
Async methodasync def classify(...)Runtime error
Correct return typestr | None, ExtractionResult, or AsyncIterator[DocumentInput]Job fails
Await async callsawait self.prompt_llm(...)Timeout/hang

Quick Start

1. Choose Your Plugin Type

2. Scaffold with the CLI

Use bizsupply init to generate a starting template:

bizsupply init classification --name my_classifier
bizsupply init extraction --name my_extractor
bizsupply init source --name my_source
bizsupply init benchmark --name my_benchmark

Or copy the template from the dedicated plugin guides.

3. Validate Your Plugin

bizsupply validate my_plugin.py

4. Register via API

curl -X POST "https://api.bizsupply.com/api/v1/plugins" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Plugin",
    "description": "What this plugin does",
    "code": "... your plugin code as string ..."
  }'

Or using form data:

curl -X POST "https://api.bizsupply.com/api/v1/plugins" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "name=My Plugin" \
  -F "description=What this plugin does" \
  -F "code_file=@your_plugin.py"

Plugin Structure

Every plugin follows this basic structure:

from bizsupply_sdk import ClassificationPlugin

class MyPlugin(ClassificationPlugin):
    """Your plugin description."""

    # Optional: Define configurable parameters
    configurable_parameters = [
        {
            "parameter_name": "my_param",
            "parameter_type": "str",
            "default_value": "default",
            "description": "What this parameter does",
        },
    ]

    async def classify(
        self,
        document,
        file_data,
        mime_type,
        available_labels,
        current_path,
        configs,
    ):
        """Classify at a single hierarchy level."""
        result = await self.prompt_llm(
            prompt=f"Select from: {available_labels}",
            file_data=file_data,
            mime_type=mime_type,
        )
        return result.get("category") if result else None

Key Points:

  • Plugin type is determined by the base class you inherit from
  • All configuration is defined as class attributes (no separate manifest file)
  • Each plugin type has its own method: classify(), extract(), or fetch()
  • The Engine handles persistence, document fetching, and ontology traversal

Common Mistakes

No Base Class or Missing Import

# WRONG - no import, no base class
class MyPlugin:
    async def classify(self, ...):
        pass

# CORRECT
from bizsupply_sdk import ClassificationPlugin

class MyPlugin(ClassificationPlugin):
    async def classify(self, document, file_data, mime_type, available_labels, current_path, configs):
        ...

Using Old execute() Method

# WRONG - execute() is the old v1.0 API
async def execute(self, context: PluginContext):
    ...

# CORRECT - use type-specific method
async def classify(self, document, file_data, mime_type, available_labels, current_path, configs):
    ...

Missing Async/Await

# WRONG
result = self.prompt_llm(prompt="...")  # Returns coroutine!

# CORRECT
result = await self.prompt_llm(prompt="...")

Reference Documentation


Next Steps

Choose your plugin type and follow the dedicated guide:

  1. Classification Plugin - Categorize documents
  2. Extraction Plugin - Extract structured data
  3. Source Plugin - Ingest from external sources
  4. Benchmark - Score documents and compare metrics

After creating your plugin: