plugin

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

Plugin protocol — structural typing for reusable Chirp plugins.

A plugin is any object with aregister(app, prefix)method. No base class required.

Usage (plugin author)::

class BlogPlugin: def register(self, app: App,…

Plugin protocol — structural typing for reusable Chirp plugins.

A plugin is any object with aregister(app, prefix)method. No base class required.

Usage (plugin author)::

class BlogPlugin:
    def register(self, app: App, prefix: str) -> None:
        @app.route(f"{prefix}/")
        async def blog_index():
            return Template("blog/index.html")

Usage (plugin consumer)::

app = App()
app.mount("/blog", BlogPlugin())

Fail-soft at boot


If a plugin's ``register()`` *raises*, ``app.mount`` **quarantines** it: the
exception is caught, the plugin is skipped, and the app keeps booting so one
broken plugin cannot abort startup. The quarantine is never silent — a WARNING
is logged at mount time and ``app.check()`` reports it as an ERROR in category
``plugin_quarantine`` (deploy-blocking under ``chirp check --deploy``). A plugin
that registers some routes before raising leaves that partial state behind;
quarantine does not roll it back. Passing a non-plugin object (no callable
``register``) is a programmer error and stays fail-loud with
``ConfigurationError``.

Contract checks
~~~~~~~~~~~~~~~

Plugins that ship custom contract validation rules should register them
inside their ``register()`` method using ``app.register_contract_check()``.
This keeps discovery explicit — no magic entry-points or auto-import.

Example::

    class BlogPlugin:
        def register(self, app: App, prefix: str) -> None:
            app.register_contract_check(check_blog_templates)
            ...

    def check_blog_templates(snapshot, result):
        for name, source in snapshot.template_sources.items():
            if name.startswith("blog/") and "{% block title %}" not in source:
                result.issues.append(ContractIssue(
                    severity=Severity.WARNING,
                    category="blog",
                    message=f"Blog template missing title block",
                    template=name,
                ))

See ``chirp.ext.chirp_ui`` for a real-world example.

plugin

Name Type Default Description
type
qualified_name
element_type
description
source_file
line_number
is_autodoc
autodoc_element
_autodoc_template
_autodoc_url_path
_autodoc_page_type
title
doc_content_hash

Symbols on this page

ChirpPlugin
class

Protocol for Chirp plugins.

Any object with aregistermethod matching this signature is a valid plugin — no inheritance required.

View source · /home/runner/work/chirp/chirp/site/../src/chirp/plugin.py:1