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.
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.
| Path | When 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 coding | You 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:
pip install bizsupply-sdkThe SDK requires Python 3.10 or later and provides all base classes, models, and CLI tools for plugin development. Verify your installation:
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.
| Type | Base Class | When to Use |
|---|---|---|
| Classification | ClassificationPlugin | You need to categorize a document (invoice, contract, receipt, etc.). |
| Extraction | ExtractionPlugin | You need to pull structured fields from a document based on an ontology. |
| Source | SourcePlugin | You need to ingest documents from an external system (email, cloud storage, API). |
| Benchmark | BaseBenchmark | You 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.
| Requirement | Details | If Violated | |
|---|---|---|---|
| Install SDK | pip install bizsupply-sdk | Import errors | |
| Import base class | from bizsupply_sdk import ClassificationPlugin | NameError | |
| Inherit base class | class MyPlugin(ClassificationPlugin): | Registration fails validation | |
| Type-specific method | classify(), extract(), or fetch() | Runtime error — the pipeline stage fails | |
| Async method | async def classify(...) | Runtime error | |
| Correct return type | `str \ | None, ExtractionResult, or AsyncIterator[DocumentInput]` | Job fails |
| Await async calls | await 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
- Need to categorize documents? → Classification Plugin
- Need to extract data fields? → Extraction Plugin
- Need to pull from external sources? → Source Plugin
2. Scaffold with the CLI
Use bizsupply init to generate a starting template with the correct structure:
bizsupply init classification --name my_classifier
bizsupply init extraction --name my_extractor
bizsupply init source --name my_source
bizsupply init benchmark --name my_benchmarkOr copy the template from the dedicated plugin guides.
3. Validate Your Plugin
Before submitting, validate that your plugin meets all requirements:
bizsupply validate my_plugin.py4. 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.
| # | Method | When to use |
|---|---|---|
| 1 | SDK (bizsupply submit) | Local development; pairs naturally with bizsupply validate |
| 2 | CLI (bizsupply register) | CI pipelines and shell scripts |
| 3 | curl / HTTP client | Custom tooling, language-agnostic submissions |
| 4 | MCP tool | AI assistants and IDE integrations driving the platform |
| 5 | Platform admin console | Platform 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
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.
{"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:
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 NoneKey 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(), orfetch(). - 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
# 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
# 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
# WRONG - returns a coroutine, not the result
result = self.prompt_llm(prompt="...")
# CORRECT
result = await self.prompt_llm(prompt="...")Reference Documentation
- Plugin Interface Specification — complete contract
- Plugin Service API — available service methods
Next Steps
Choose your plugin type and follow the dedicated guide:
- Classification Plugin — categorize documents
- Extraction Plugin — extract structured data
- Source Plugin — ingest from external sources
- Benchmark — score documents and compare metrics
After creating your plugin:
- Use Plugins — execute in a pipeline
- Create an Ontology — define extraction schemas
- Create a Prompt — LLM instruction templates