Develop custom FiftyOne plugins (operators and panels) from scratch...
Create custom FiftyOne plugins with full lifecycle support: requirements gathering, code generation, local testing, and iterative refinement.
Use this skill when:
pip install fiftyone)ALWAYS follow these rules:
Ask clarifying questions. Never assume what the plugin should do.
Present file structure and design. Get user approval before generating code.
list_plugins(enabled=True)
list_operators(builtin_only=False)
get_operator_schema(operator_uri="@voxel51/brain/compute_similarity")
Install plugin and verify it works in FiftyOne App.
Refine until the plugin works as expected.
Ask these questions:
@org/plugin-name)See PLUGIN-STRUCTURE.md for file formats.
Create these files:
| File | Required | Purpose |
|---|---|---|
fiftyone.yml |
Yes | Plugin manifest |
__init__.py |
Yes | Python operators/panels |
requirements.txt |
If deps | Python dependencies |
package.json |
JS only | Node.js metadata |
src/index.tsx |
JS only | React components |
Reference docs:
# Find plugins directory
python -c "import fiftyone as fo; print(fo.config.plugins_dir)"
# Copy plugin
cp -r ./my-plugin ~/.fiftyone/plugins/
# Verify detection
python -c "import fiftyone as fo; print(fo.plugins.list_plugins())"
Test in App:
launch_app(dataset_name="test-dataset")
# Press Cmd/Ctrl + ` to open operator browser
# Search for your operator
| Type | Language | Use Case |
|---|---|---|
| Operator | Python | Data processing, computations |
| Panel | Python | Simple interactive UI |
| Panel | JavaScript | Rich React-based UI |
| Option | Effect |
|---|---|
dynamic=True |
Recalculate inputs on change |
execute_as_generator=True |
Stream progress |
allow_delegated_execution=True |
Background execution |
unlisted=True |
Hide from browser |
| Type | Method |
|---|---|
| Text | inputs.str() |
| Number | inputs.int() / inputs.float() |
| Boolean | inputs.bool() |
| Dropdown | inputs.enum() |
| File | inputs.file() |
| View | inputs.view_target() |
fiftyone.yml:
name: "@myorg/hello-world"
type: plugin
operators:
- hello_world
init.py:
import fiftyone.operators as foo
import fiftyone.operators.types as types
class HelloWorld(foo.Operator):
@property
def config(self):
return foo.OperatorConfig(
name="hello_world",
label="Hello World"
)
def resolve_input(self, ctx):
inputs = types.Object()
inputs.str("message", label="Message", default="Hello!")
return types.Property(inputs)
def execute(self, ctx):
print(ctx.params["message"])
return {"status": "done"}
def register(p):
p.register(HelloWorld)
Plugin not appearing:
fiftyone.yml exists in plugin root~/.fiftyone/plugins/Operator not found:
fiftyone.ymlregister() functionlist_operators() to debugSecrets not available:
fiftyone.yml under secrets:Copyright 2017-2025, Voxel51, Inc. Apache 2.0 License