faceplant
Build a faceplant platform service in ~30 lines. Identity, the 30-second broker heartbeat, dashboards, the runtime plugin host, the daily garbage collector, and MCP tool serving are all under the hood — you write domain code.
pip install faceplant
Quickstart — a whole service
from faceplant import Service, Table, Column
svc = Service(
"billing",
description="Track usage bills.",
icon="receipt",
category="tools",
)
@svc.get("/data")
async def bills(user): # user.email, user.slug, user.dir
rows = load_bills(user.dir) # per-user private storage, created for you
return Table(
title="Bills",
columns=[Column(key="month", header="Month"),
Column(key="amount", header="Amount")],
rows=rows,
)
@svc.responder("billing.total") # a broker API other services can call
async def total(data):
return {"total": sum_bills()}
app = svc.app # uvicorn src.main:app
That's the entire service. Service(...) already gave you:
- a gateway card heartbeated every 30s (stop the pod → the card disappears);
/health,/manifest,/_pluginsand CORS;- identity:
useris injected from the platform JWT (401 when absent), withuser.dirfor per-user storage anduser.tags/user.services; - the runtime plugin host: other services can extend this one with signed
wheels, with zero code here (
svc.registryif you want to add hook points); - the daily GC that reclaims a user's data ~10 days after they're gone.
More surfaces (each one decorator)
@svc.consumer("CHAT", filter_keys=["chat.>"]) # subscribe to broker events
async def on_chat(data): ...
@svc.mcp_tool() # a tool for coding agents (pip install faceplant[mcp])
async def get_bill(month: str) -> str: ...
svc.announce_wheel(target="faceplant-users", # ship an extension wheel AT another service
wheel="plugin", entrypoint="billing_gate.plugin:register")
@svc.manifest # compute the dashboard per request
def dash(user): return Stack(children=[...])
Escape hatches, always available: svc.app is a real FastAPI app (add
WebSockets, SSE, middleware); svc.broker.request(key, data) / .publish(...);
await svc.provision(fn) for blocking work off the DNS-critical event loop;
@svc.background for startup loops; @svc.on_purge / @svc.gc_verdict to
customize GC.
Testing is safe by default
Service only starts its heartbeat when a broker is actually configured
(BROKER_URL set). A bare pytest or with TestClient(app) runs offline —
no accidental registration against a live gateway. To test online behavior, use
the in-process stub:
from fastapi.testclient import TestClient
from faceplant.testing import StubBroker, dev_jwt
def test_bills():
with TestClient(svc.app) as client: # offline: no heartbeat
r = client.get("/data", headers={"authorization": f"Bearer {dev_jwt('a@b.co')}"})
assert r.status_code == 200
async def test_registration():
stub = StubBroker(); stub.install(svc)
await stub.beat(svc)
assert "billing.total" in stub.responders
Docs
One page per concept in docs/: identity,
widgets, plugin-host,
providers,
consumers & responders, mcp,
gc, escape hatches,
testing, and
migrating from the template.
License
MIT.
Metadata
Release files for faceplant 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| faceplant-0.3.0.tar.gz | 142.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| faceplant-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 189.2 kB
Release files / faceplant-0.3.0.tar.gz
| Download URL | faceplant-0.3.0.tar.gz |
|---|---|
| Size | 142.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f889cdb1f585bdffdc34ff0ece32cfd36a2a4da8a15290aea74fcf2dc5c43e05
|
|
BLAKE2b-256 checksum How to use checksums |
025da991a12ba6a6fd0a4d8711b342dd59be75a946a3c2b96fdae19cf2f28937
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|
Release files / faceplant-0.3.0-py3-none-any.whl
| Download URL | faceplant-0.3.0-py3-none-any.whl |
|---|---|
| Size | 46.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2faa5a160531e9a8fac444560d824e9273e1f9bd85cbe8cc297d19af87c2df3e
|
|
BLAKE2b-256 checksum How to use checksums |
ec1a36594ec5e24b7079e352d0489725fb5ff1e6392746362220c0b6dad2cb25
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.6
|