# How to Create Custom OBBject Extensions in the OpenBB Platform

> Learn to create custom OBBject extensions in the OpenBB Platform. Register cached accessors via Python entry points to extend data containers without altering core code.

- Repository: [OpenBB/OpenBB](https://github.com/OpenBB-finance/OpenBB)
- Tags: how-to-guide
- Published: 2026-03-06

---

**Custom OBBject extensions in the OpenBB Platform are created by registering a cached accessor on the `OBBject` class through Python entry points, allowing developers to augment data containers without modifying core library code.**

The OpenBB Platform provides a flexible extension system that lets developers add functionality to the `OBBject` class—the pandas-like data container used throughout the library. By creating custom OBBject extensions, you can attach domain-specific methods and accessors that become automatically available on every data object. This guide explains the complete implementation using the actual source code from the OpenBB-finance/OpenBB repository.

## Understanding the Extension Architecture

The extension mechanism relies on three coordinated components that handle discovery, registration, and runtime behavior.

### The Extension Model

The `Extension` class in [`openbb_platform/core/openbb_core/app/model/extension.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/core/openbb_core/app/model/extension.py) defines the metadata and registration logic for every OBBject extension. It validates configuration flags such as `on_command_output`, `command_output_paths`, `results_only`, and `immutable`, and exposes the `obbject_accessor` property that returns a decorator for registering accessors on the `OBBject` class.

### The ExtensionLoader

The `ExtensionLoader` class in [`openbb_platform/core/openbb_core/app/extension_loader.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/core/openbb_core/app/extension_loader.py) acts as a singleton that discovers installed extensions via the Python entry-point group `openbb_obbject_extension`. At runtime, it loads each extension, builds a dictionary mapping extension names to `Extension` instances in `obbject_objects`, and registers callbacks for extensions configured to act on command output.

### Entry Point Discovery

Extensions are discovered through standard Python packaging entry points declared in [`pyproject.toml`](https://github.com/OpenBB-finance/OpenBB/blob/main/pyproject.toml). The loader specifically looks for the group `openbb_obbject_extension` and imports the specified `Extension` instance when the package is installed.

## Creating Your First OBBject Extension

Building an extension requires three steps: configuring the package metadata, instantiating the `Extension` class, and registering an accessor function.

### Project Configuration

Declare the entry point in your package's [`pyproject.toml`](https://github.com/OpenBB-finance/OpenBB/blob/main/pyproject.toml) to enable discovery:

```toml
[tool.poetry.plugins."openbb_obbject_extension"]
my_stats = "my_extension.extension:my_ext"

```

This tells the `ExtensionLoader` to import `my_ext` from `my_extension.extension` when the package is installed.

### Implementing the Extension Class

Create an `Extension` instance with appropriate metadata and validation flags:

```python
from openbb_core.app.model.extension import Extension

my_ext = Extension(
    name="my_stats",
    description="Adds statistical helpers to OBBject",
    on_command_output=False,
    immutable=True,
)

```

The constructor validates that if `on_command_output=False`, you cannot set `command_output_paths`, `results_only=True`, or `immutable=False`. Violating this rule raises a `ValueError` during instantiation.

### Registering the Accessor

Use the `obbject_accessor` property to attach a cached accessor to `OBBject`:

```python
@my_ext.obbject_accessor
def stats(self):
    """
    `self` is the OBBject instance. The result is cached on first access.
    """
    return self.df.describe()

```

The decorator stores a `CachedAccessor` descriptor on `OBBject` under the key `my_stats`. When `obbject.my_stats` is accessed, the function runs once, its result is cached on the instance, and subsequent accesses return the cached object. If an accessor name already exists, registration issues a `UserWarning` but overwrites the attribute.

## Hooking Into Command Output

Extensions can modify or react to command output by enabling specific configuration flags and security settings.

### Configuration Flags for Command Output

Set `on_command_output=True` when you need the extension to process data after a command executes:

```python
my_ext = Extension(
    name="price_plot",
    on_command_output=True,
    command_output_paths=["/stock/price"],
    immutable=False,
)

```

The `command_output_paths` parameter restricts the extension to specific endpoints, while `immutable=False` allows the accessor to mutate returned objects.

### Security Validation Requirements

Extensions that act on command output or mutate data require explicit permission through system settings. You must set `allow_on_command_output: true` in [`system_settings.json`](https://github.com/OpenBB-finance/OpenBB/blob/main/system_settings.json) or the environment variable `OPENBB_ALLOW_ON_COMMAND_OUTPUT`. For mutable extensions, also set `allow_mutable_extensions: true` or `OPENBB_ALLOW_MUTABLE_EXTENSIONS`.

If these flags are missing, `Extension.__init__` raises a `RuntimeError` explaining the required configuration.

## Complete Implementation Example

Here is a minimal yet functional OBBject extension package structure:

```

my_extension/
│   pyproject.toml
│   my_extension/
│       __init__.py
│       extension.py

```

**[`pyproject.toml`](https://github.com/OpenBB-finance/OpenBB/blob/main/pyproject.toml)**

```toml
[tool.poetry]
name = "my_extension"
version = "0.1.0"

[tool.poetry.plugins."openbb_obbject_extension"]
my_stats = "my_extension.extension:my_ext"

```

**[`extension.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/extension.py)**

```python
from openbb_core.app.model.extension import Extension

my_ext = Extension(
    name="my_stats",
    description="Statistical helpers",
    on_command_output=False,
    immutable=True,
)

@my_ext.obbject_accessor
def stats(self):
    return self.df.describe()

```

**Usage**

```python
from openbb_core.app.model.obbject import OBBject

data = OBBject({"a": [1, 2, 3], "b": [4, 5, 6]})
print(data.my_stats)

```

## Summary

- **Entry Point Registration**: Declare extensions in [`pyproject.toml`](https://github.com/OpenBB-finance/OpenBB/blob/main/pyproject.toml) under the `openbb_obbject_extension` group to enable discovery by `ExtensionLoader`.
- **Accessor Pattern**: Use `Extension.obbject_accessor` to register cached accessors on `OBBject`, with automatic caching on first access.
- **Validation Rules**: Extensions with `on_command_output=False` cannot set `command_output_paths`, `results_only=True`, or `immutable=False`.
- **Security Gates**: Command-output and mutable extensions require `allow_on_command_output` and `allow_mutable_extensions` in system settings or environment variables.
- **File References**: Core logic resides in [`openbb_platform/core/openbb_core/app/model/extension.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/core/openbb_core/app/model/extension.py) and [`openbb_platform/core/openbb_core/app/extension_loader.py`](https://github.com/OpenBB-finance/OpenBB/blob/main/openbb_platform/core/openbb_core/app/extension_loader.py).

## Frequently Asked Questions

### What is the difference between `immutable=True` and `immutable=False` in an OBBject extension?

When `immutable=True`, the accessor must return a new object without modifying the original `OBBject` instance. When `immutable=False`, the accessor can mutate the returned data or the extension instance itself. Mutable extensions require the `allow_mutable_extensions` system setting to be enabled, whereas immutable extensions work without additional configuration.

### Why does my extension raise a `ValueError` during initialization?

The `Extension` class validates that incompatible flags are not combined. If `on_command_output=False`, you cannot set `command_output_paths`, `results_only=True`, or `immutable=False`. The constructor raises `ValueError` if these restrictions are violated, as these features only apply when hooking into command output.

### How does the `ExtensionLoader` discover my custom extension?

The `ExtensionLoader` singleton calls `entry_points(group="openbb_obbject_extension")` at runtime to find all packages declaring that entry point group. It then loads the specified module, imports the `Extension` instance, and registers its accessor on the `OBBject` class. This process happens automatically when the OpenBB Platform initializes.

### Can I override an existing OBBject accessor with my extension?

Yes, but the system warns you first. If you register an accessor with a name that already exists on `OBBject`, `Extension.register_accessor` issues a `UserWarning` before overwriting the existing attribute. This allows extension authors to customize or replace built-in functionality while alerting users to potential conflicts.