plugkit

A plugin and dependency-injection kernel for Python.

Your components are plain classes. plugkit constructs them in dependency order, passes each one what it asked for, and makes them reachable by name. When a component unloads, everything it registered is removed — including registrations it made inside other components.

That last part is the one thing no other Python framework does, and everything else here follows from it.

pip install plugkit
from plugkit import Context, provide

class Greeter:                       # a plain class. imports nothing.
    def __init__(self, database, prefix="hello"):
        self.database, self.prefix = database, prefix
    def hello(self, name):
        return f"{self.prefix} {name}"

root = Context()
await root.plugin(provide(Database, "database"))
await root.plugin(provide(Greeter, "greeter", needs=["database"]))
root.greeter.hello("world")          # "hello world"

Start here

Why plugkit exists the route that outlives the component that added it, and the invariant that fixes it
Your first plugin inject, effects, and watching unload be total
Plain components provide(), and a ctx your type checker understands
Tools and permission the five-stage pipeline, and why a guard has no allow
Extension points many plugins filling one role, and the rebinding rule
Config and reactivity values that change while the program runs
Composition from a file an application as a YAML list
Testing what plain components buy you

Before you adopt it

plugkit ships fewer features than dependency-injector, pluggy or iPOPO. It replaces one thing in each: who owns a component’s side effects. What plugkit does not replace compares them feature by feature.

The one idea

A component adds a route to a shared server, then unloads. The route stays, because nothing recorded who added it. That is not a missing feature, it is a missing invariant — so plugkit has one: a registration returns its undo, and the fiber that owns your plugin’s lifetime holds it.

Hot reload, dependency-driven activation, and safe implementation swapping are all consequences of that, not separate features.

Provenance

The kernel in src/plugkit/cordis/ derives from Cordis, the plugin framework underneath DeepSeek Harness, by way of geohotstan/cordis-py. Both are MIT.

What is plugkit’s own: binding.py (provide() and @plugin), Protocol-driven injection, the signals library, supervision, the tool pipeline, the file loader, subscript access, and the conformance suite whose assertions are traced to the TypeScript rather than to either implementation.

src/plugkit/VENDORED.md lists every local change to the vendored kernel and the reason for it.