Skip to main content

A lightweight plugin injection framework for Python.

Project description

FrameX logo

FrameX

A plugin-first Python framework for building modular FastAPI services with optional Ray Serve support.

Docs CI Coverage Release PyPI License

Overview

FrameX helps split a Python service into independently developed plugins while exposing one consistent HTTP and internal API surface. It is useful when a service needs clear module ownership, plugin loading, optional proxy integration, and a path from local execution to Ray-backed serving.

Core capabilities:

  • plugin registration and discovery
  • FastAPI route generation from plugin methods
  • internal plugin API calls
  • optional Ray Serve execution
  • built-in example and proxy plugins
  • configuration from environment variables, TOML, and pyproject.toml

FrameX architecture

What Problem It Solves

FrameX is most useful when multiple teams need to ship capabilities in parallel, call each other through stable service interfaces, and keep implementation details private so each team can work without understanding or depending on other teams' codebases.

Use it when you need to:

  • build service capabilities as plug-and-play modules
  • let multiple engineers or teams ship in parallel with clearer ownership boundaries
  • split a growing service into independently evolving capability units
  • call other teams' capabilities without depending on their codebases
  • expose local plugins and upstream APIs behind one consistent service surface
  • integrate third-party or internal HTTP services with minimal client-side changes
  • start with simple local execution and scale to Ray when needed
  • keep the system extensible as capabilities, teams, and traffic grow

Why FrameX Instead Of Plain FastAPI

Plain FastAPI is a good choice for a single cohesive application. FrameX is better when the real problem is not route handling, but service decomposition, team boundaries, and cross-service integration.

Compared with plain FastAPI, FrameX gives you:

  • plugin boundaries for clearer ownership between capabilities and teams
  • a better development model for plug-and-play modules and parallel delivery
  • one consistent surface for local capabilities and upstream HTTP services
  • internal callable APIs in addition to normal HTTP routes
  • explicit dependency declarations between capabilities
  • the ability to start locally and move to Ray-backed execution without rewriting plugin code

If you only need a small application with a stable route surface and one codebase, plain FastAPI is usually simpler.

Installation

pip install framex-kit

Install Ray Serve support when needed:

pip install "framex-kit[ray]"

FrameX requires Python 3.11 or newer.

Quick Start

Create a plugin module:

from pydantic import BaseModel

from framex.consts import VERSION
from framex.plugin import BasePlugin, PluginMetadata, on_register, on_request

__plugin_meta__ = PluginMetadata(
    name="foo",
    version=VERSION,
    description="A minimal FrameX plugin",
    author="you",
    url="https://github.com/touale/FrameX-kit",
)


class EchoBody(BaseModel):
    text: str


@on_register()
class FooPlugin(BasePlugin):
    @on_request("/foo", methods=["GET"])
    async def echo(self, message: str) -> str:
        return f"foo: {message}"

    @on_request("/foo_model", methods=["POST"])
    async def echo_model(self, model: EchoBody) -> dict[str, str]:
        return {"text": model.text}

Run the service:

PYTHONPATH=. framex run --load-plugins foo

Call the API:

curl "http://127.0.0.1:8080/api/v1/foo?message=hello"

Open the generated API docs:

  • http://127.0.0.1:8080/docs
  • http://127.0.0.1:8080/redoc
  • http://127.0.0.1:8080/api/v1/openapi.json

You can also run the built-in example plugin:

framex run --load-builtin-plugins echo

Calling Other Plugins

A plugin can call another plugin through FrameX instead of importing the other plugin's implementation directly. Declare the APIs it depends on in required_remote_apis, then call them with self._call_remote_api(...).

from framex.consts import VERSION
from framex.plugin import BasePlugin, PluginMetadata, on_register, on_request

__plugin_meta__ = PluginMetadata(
    name="consumer",
    version=VERSION,
    description="Call another FrameX plugin",
    author="you",
    url="https://github.com/touale/FrameX-kit",
    required_remote_apis=["/api/v1/foo"],
)


@on_register()
class ConsumerPlugin(BasePlugin):
    @on_request("/consumer", methods=["GET"])
    async def call_foo(self, message: str) -> str:
        return await self._call_remote_api("/api/v1/foo", message=message)

Run both plugins:

PYTHONPATH=. framex run \
  --load-plugins foo \
  --load-plugins consumer

Call the consumer API:

curl "http://127.0.0.1:8080/api/v1/consumer?message=hello"

required_remote_apis keeps plugin dependencies explicit. It can reference HTTP APIs such as /api/v1/foo, or internal function APIs such as echo.EchoPlugin.confess when a plugin exposes a function-only API.

CLI

framex run --host 0.0.0.0 --port 8080 --load-builtin-plugins echo

Common options:

  • --host
  • --port
  • --load-plugins
  • --load-builtin-plugins
  • --use-ray / --no-use-ray
  • --enable-proxy / --no-enable-proxy
  • --dashboard-host
  • --dashboard-port
  • --num-cpus

--load-plugins and --load-builtin-plugins are repeatable options:

framex run \
  --load-builtin-plugins echo \
  --load-plugins foo \
  --load-plugins your_project.plugins.bar

Use Proxy Plugin

Use the built-in proxy plugin when you already have an HTTP service and want FrameX to expose it as part of the same API surface without writing wrapper plugin methods.

For example, if an upstream service runs at http://127.0.0.1:9000 and exposes GET /api/v1/chat, FrameX can expose the same route at http://127.0.0.1:8080/api/v1/chat and forward matching requests to the upstream service.

Minimal configuration:

load_builtin_plugins = ["proxy"]

[server]
enable_proxy = true

[plugins.proxy]
timeout = 600

[plugins.proxy.proxy_urls."http://127.0.0.1:9000"]
enable = ["/*"]
disable = []

Start from the CLI:

framex run --load-builtin-plugins proxy --enable-proxy

Common uses:

  • bridge an existing FastAPI/OpenAPI service into FrameX
  • expose remote team services under one gateway
  • migrate APIs into plugins gradually instead of rewriting them all at once
  • forward query parameters, JSON bodies, multipart forms, file uploads, and configured streaming endpoints

Configuration

FrameX reads settings from environment variables, .env, .env.prod, config.toml, and [tool.framex] in pyproject.toml.

Minimal config.toml:

load_builtin_plugins = ["echo"]
load_plugins = ["your_project.plugins.foo"]

[server]
host = "127.0.0.1"
port = 8080
use_ray = false
enable_proxy = false

[plugins.foo]
debug = true

Nested environment variables are supported:

export SERVER__PORT=9000
export SERVER__ENABLE_PROXY=true

Documentation

See the online documentation for plugin APIs, proxy mode, Ray mode, authentication, and advanced configuration.

License

This project is licensed under the MIT License. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

framex_kit-0.4.0.tar.gz (306.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

framex_kit-0.4.0-py3-none-any.whl (68.5 kB view details)

Uploaded Python 3

File details

Details for the file framex_kit-0.4.0.tar.gz.

File metadata

  • Download URL: framex_kit-0.4.0.tar.gz
  • Upload date:
  • Size: 306.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for framex_kit-0.4.0.tar.gz
Algorithm Hash digest
SHA256 52f3a5e4e3e72434eeeaa0585519e65adf38170ba92a055fdf2666685843eb53
MD5 e2b6c9cc5eb47a468db52b01423851a9
BLAKE2b-256 c09dbac5f4bdb51a1871711afb8ae730b4d9ad975d4402a114a36025f9e6ab9f

See more details on using hashes here.

Provenance

The following attestation bundles were made for framex_kit-0.4.0.tar.gz:

Publisher: release.yml on touale/FrameX-kit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file framex_kit-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: framex_kit-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 68.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for framex_kit-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 72df20fa071f09d9b8be6636cef4a931b65b313d884f6ea604196e26d1c1cf6a
MD5 e8e55dfda1351d461aa6ce89f29bce5c
BLAKE2b-256 113989cdb2f90142d81534e36266cfdfe5d9a1b790d7988a05bb85af83e1822b

See more details on using hashes here.

Provenance

The following attestation bundles were made for framex_kit-0.4.0-py3-none-any.whl:

Publisher: release.yml on touale/FrameX-kit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page