Skip to content

Quickstart

This guide will show you how to integrate Xcore into a FastAPI application, load a simple plugin, and call its methods.

1. Project Structure

Create a new project directory with the following structure:

1
2
3
4
5
6
7
8
my_app/
├── main.py
├── xcore.yaml
└── plugins/
    └── hello_plugin/
        ├── plugin.yaml
        └── src/
            └── main.py

2. Configuration

Create an xcore.yaml file to configure the framework:

1
2
3
4
5
6
7
app:
  name: "demo-app"
  env: "development"
  secret_key: "debug-key"

plugins:
  directory: "./plugins"

3. Create a Plugin

Manifest (plugin.yaml)

Define your plugin's metadata and entry point.

1
2
3
4
5
name: "hello_plugin"
version: "1.0.0"
mode: "trusted"  # (1)!
entry_point: "src/main.py"
permissions: []  # (2)!
  1. Trusted Mode: Runs in the main process with full access.
  2. Fail-closed: An empty list means no special permissions are granted.

Logic (src/main.py)

Implement the TrustedBase contract.

1
2
3
4
5
6
7
8
9
from xcore import TrustedBase, ok

class Plugin(TrustedBase):
    async def handle(self, action: str, payload: dict) -> dict:
        if action == "greet":
            name = payload.get("name", "World")
            return ok(message=f"Hello, {name}!")

        return {"status": "error", "msg": "Unknown action"}

4. Integrate with FastAPI

In your main.py, initialize and boot the Xcore kernel.

from fastapi import FastAPI
from xcore import Xcore
from contextlib import asynccontextmanager

# 1. Initialize the Kernel
xcore = Xcore(config_path="xcore.yaml")

@asynccontextmanager
async def lifespan(app: FastAPI):
    # 2. Boot Xcore (loads services and plugins)
    await xcore.boot(app)
    yield
    # 3. Graceful shutdown
    await xcore.shutdown()

app = FastAPI(lifespan=lifespan)

@app.get("/hello/{name}")
async def hello(name: str):
    # 4. Call the plugin
    result = await xcore.plugins.call("hello_plugin", "greet", {"name": name})
    return result

5. Run the Application

Start the server using Uvicorn:

uvicorn main:app --reload

Now, visit http://127.0.0.1:8000/hello/Xcore in your browser. You should see:

1
2
3
4
{
  "status": "ok",
  "message": "Hello, Xcore!"
}

Common Pitfalls

Production Boot Failure

If you set app.env: "production", Xcore will raise a RuntimeError if your secret_key is set to the default value (b"change-me-in-production"). Always use a secure, unique key in production.

Permissions are fail-closed

If your plugin needs to access certain services or perform restricted actions, you must explicitly declare them in the plugin.yaml manifest.


Next Steps