Create a Plugin

This guide walks you through creating your first bizSupply plugin. By the end you will have a working plugin that you can submit for review and — once approved — use in a pipeline.

Last updated: 2026-07-21

This guide walks you through creating your first bizSupply plugin. By the end you will have a working plugin that you can submit for review and — once approved — use in a pipeline.

For plugin-type-specific walkthroughs, see the dedicated guides linked below.


Two ways to author a plugin

bizSupply supports two authoring paths for the same outcome. Both produce a Python plugin that lands in the same human-review queue and, once approved, executes identically. Pick the one that fits how you work.

PathWhen to use
Conversational (Plugin Fabric)You want to describe what the plugin should do in natural language and iterate with an AI assistant. No local environment required — open bizsupply.ai, go to Plugins → New, pick "Build with chat", and start the conversation. Up to 30 user turns per conversation; the assistant returns a complete plugin, syntax-validated each turn. Submit when satisfied.
Manual codingYou want full control over the source, run the SDK locally, write tests, or ship plugins from a CI pipeline. Install the SDK (below), scaffold with bizsupply init, validate locally, then submit.

Same gate, same review. Conversational submissions are not "lower trust" — both paths feed the same plugin review queue, both validate the code before it is stored, and both wait for a platform administrator's explicit approve/reject. How the code was authored is invisible to the reviewer.

The rest of this guide covers the manual path. The conversational path is self-explanatory once you start the chat — the assistant prompts you for what it needs.


Install the SDK

The bizSupply SDK is distributed as a Python package. Install it with pip:

bash
pip install bizsupply-sdk

The SDK requires Python 3.10 or later and provides all base classes, models, and CLI tools for plugin development. Verify your installation:

bash
python -c "import bizsupply_sdk; print(bizsupply_sdk.__version__)"

Plugin Types

bizSupply supports the following plugin types. Choose the one that matches your use case — the type is determined by the base class you inherit from.

TypeBase ClassWhen to Use
ClassificationClassificationPluginYou need to categorize a document (invoice, contract, receipt, etc.).
ExtractionExtractionPluginYou need to pull structured fields from a document based on an ontology.
SourceSourcePluginYou need to ingest documents from an external system (email, cloud storage, API).
BenchmarkBaseBenchmarkYou need to score documents and compare metrics.

Need to create relationships across documents (aggregation-style workflows)? Contact support.

Each type has a dedicated guide:


CRITICAL: Plugin Requirements

All plugins must satisfy these requirements. Violating any of them will cause registration or execution failures.

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

The platform handles persistence, document fetching, and ontology traversal. Plugins must not directly modify documents, pipelines, or other platform resources — return data and let the platform persist it.


Quick Start

1. Choose Your Plugin Type

2. Scaffold with the CLI

Use bizsupply init to generate a starting template with the correct structure:

bash
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

Before submitting, validate that your plugin meets all requirements:

bash
bizsupply validate my_plugin.py

4. Submit Your Plugin

Pick whichever submission path fits your workflow — the server runs the same validation, queues the same review, and returns the same review_id regardless of how the code arrives.

#MethodWhen to use
1SDK (bizsupply submit)Local development; pairs naturally with bizsupply validate
2CLI (bizsupply register)CI pipelines and shell scripts
3curl / HTTP clientCustom tooling, language-agnostic submissions
4MCP toolAI assistants and IDE integrations driving the platform
5Platform admin consolePlatform administrators authoring or pasting code directly in the browser

Registration is a multipart upload — the plugin type and configurable parameters are extracted automatically from your code, so there is no separate manifest to maintain.

curl example

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

Admin console submission (platform administrators only)

Platform administrators can also submit through the platform's admin console, which wraps the same endpoint behind a guided form: drag-and-drop a .py file (or paste source), pick the plugin type, and submit. It enforces the same file-size limit, and validation errors are rendered inline against the offending lines. Platform administrators may register a plugin at global scope (available to every tenant); everyone else is limited to their own tenant.

What happens after you submit

Plugins do not go live immediately. Plugin code runs inside an isolated execution environment, so every submission — including those from platform administrators — is sent to human review before it can be used.

json
{"review_id": "...", "status": "pending_review"}

A platform administrator must approve the review via POST /api/v1/reviews/{review_id}/approve before the plugin becomes available in your tenant. You are notified once the decision is made.

Edits to an already-approved plugin (PATCH /api/v1/plugins/{plugin_id}) go through the same gate — the currently-approved version keeps serving traffic until the updated version is approved.


Plugin Structure

Here is a complete plugin that uses the LLM service to classify documents. Every plugin follows this basic shape — inherit a base class, optionally declare configurable parameters, and implement the one async method for your type:

python
from bizsupply_sdk import ClassificationPlugin


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

    # Optional: declare configurable parameters as a class attribute
    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 — there is no separate manifest file.
  • Each plugin type has its own method: classify(), extract(), or fetch().
  • The platform handles persistence, document fetching, and ontology traversal.

Common Mistakes

These are the most frequent errors when developing plugins.

No base class or missing import

python
# 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 the old execute() method

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

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

Missing async/await

python
# WRONG - returns a coroutine, not the result
result = self.prompt_llm(prompt="...")

# 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: