# Building plugins

> How plugins are structured, registered, and distributed (advanced).

_Updated: 2026-06-07_

Plugins are how functionality is packaged and sold on top of Railbase. This page
is an overview of the plugin model for developers; it's an advanced topic — most
apps are built directly on the core (see the rest of this section).

## A plugin is a Go module with a `Register(app)` entry point

A plugin is a Go module that declares collections, verbs, and roles and exposes a
`Register(app)` function. It ships in two forms:

- **Build-time (today):** an embedder imports the module and calls `Register(app)`
  in their `main`, compiling the plugin into their app binary. This is how
  first-party plugins are installed into a self-hosted build right now — see
  [Installing plugins](installing-plugins).
- **Distribution (hosted):** the same module is built as a standalone artifact,
  signed, and run by the core's plugin manager as a managed **subprocess** it
  talks to over HTTP — giving crash isolation, cross-platform artifacts, and
  runtime install/update/remove without rebuilding. That runtime is described in
  [How plugins work](how-plugins-work).

A plugin:

- declares its **collections** with the same [schema DSL](schema) your app uses,
- registers them with the core and reads/writes through the core's REST API under
  a service-identity token the plugin manager mints on install,
- exposes its own HTTP **verbs**, which the core reverse-proxies at
  `/papi/<slug>/…`,
- declares the **roles** it needs (the core learns them at install — it doesn't
  hardcode plugin roles), which is what drives per-seat billing.

## The register handshake

On startup a plugin announces itself to the core over loopback. The handshake
carries:

```text
slug, url, colls[], provides[], consumes{}, subscribes[],
min_core, roles[], requires{}, actions[]
```

The core enforces `min_core` (it refuses a plugin that needs a newer core) and
learns the plugin's collections, capabilities, and roles. A small harness reduces
a plugin's entry point to a few lines — register the schema, declare verbs and
roles, and serve — handling the handshake, the service token, the health probe,
and the verb mux for you.

## Inter-plugin communication

- **Capabilities** — a plugin `provides` a named capability (e.g. a stock
  provider) and another `consumes` it; the core mediates and runs detach hooks
  before a provider is removed.
- **Events** — plugins publish and subscribe to bus topics for loosely-coupled
  workflows.
- **Atomic reservations** — for cross-process consistency without a shared
  database transaction, the core offers a conditional decrement/release primitive
  (`/api/_tx/reserve` · `/api/_tx/release`).

## Distribution

Plugins reach customers only through the marketplace, as **signed artifacts**:

1. The artifact is published to railbase.app (the vendor's distribution server) with its
   version, content hash, and Ed25519 signature.
2. A customer buys a subscription; railbase.app issues a `lic1` license.
3. The customer's core pulls the artifact, verifies sha256 + signature against the
   **pinned vendor key**, and runs it.

There is no sideloading — see [How plugins work](how-plugins-work) and
[Licensing & seats](licensing-and-seats) for the full trust and billing model.

> [!NOTE]
> Authoring and publishing plugins to the marketplace is a vendor/partner process.
> If you want to distribute a plugin, get in touch via [Support](../support).
