> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pylonsync.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Plugins overview

> How Pylon composes: installable TS packages plus a small set of auto-wired runtime built-ins. There is no manifest plugin array.

"Plugins" in Pylon means two concrete things — and neither is a `manifest.plugins: [...]` list. There is no such array today.

1. **TS packages** (`@pylonsync/*`) — installable npm packages that return a manifest **fragment** (entities, actions, queries, policies) plus handler factories. You compose the fragment into your `buildManifest()` call. Use these to add features the framework binary doesn't already cover.
2. **Built-in runtime plugins** — a small set compiled into the `pylon` binary and wired **automatically** from your schema or environment. You don't name them anywhere; they activate when the relevant signal is present (a `tenantId` field, a `.owner()` annotation, an env var).

Features that are built into the framework binary already (no package, no plugin needed):

* **API keys** — `/api/auth/api-keys` routes for mint / list / revoke. See [Auth → API keys](/auth/api-keys).
* **TOTP / 2FA** — `/api/auth/totp/*` routes for enroll / verify / disable + backup codes. See [Auth → TOTP](/auth/totp).
* **Transactional email** — `PYLON_EMAIL_PROVIDER` env (sendgrid / resend / stack0 / webhook) + `ctx.email.send()`. See [Integrations → email](/plugins/integrations#email).
* **Audit log** — `/api/auth/audit` + `/api/auth/audit/tenant` routes.
* **Organizations** — `Org` / `OrgMember` / `OrgInvite` entities + `/api/auth/orgs/*` routes. See [Auth → Organizations](/auth/organizations).

## TS packages

Install with `bun add`, then spread the manifest fragment into `buildManifest()`:

| Package                                                | Purpose                                                                                                          |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| **[@pylonsync/stripe](/plugins/stripe)**               | Declarative billing — plans, checkout, portal, cancel/restore, signature-verified webhook, subscription entity.  |
| **[@pylonsync/feature-flags](/plugins/feature-flags)** | Local-eval flags — boolean + multivariate, percentage rollouts, targeting predicates, per-variant JSON payloads. |
| **[@pylonsync/webhooks](/plugins/webhooks)**           | Outbound webhook delivery — Svix-compatible HMAC signatures, retry schedule, secret rotation.                    |

Each package exports a factory (e.g. `stripe({...})`, `webhooks({...})`) that returns `{ manifest, handlers, ... }`. Pylon loads function handlers one-per-file, so you also add one-line wrapper files under `functions/` — see each package's page for the exact list.

## Built-in runtime plugins

These live in `crates/plugin/src/builtin/` and are registered by the runtime at boot. They are **auto-wired**, not enabled through a manifest list.

| Built-in               | How it turns on                                                         | Reference                                            |
| ---------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------- |
| `tenant_scope`         | Automatic on any entity with a `tenantId` field                         | [Data hygiene](/plugins/data#tenant_scope)           |
| `owner_stamp`          | Automatic on any field declared `field.X().owner()`                     | [Data hygiene](/plugins/data#owner_stamp)            |
| `rate_limit`           | Always on; tuned via `PYLON_RATE_LIMIT_MAX*` env                        | [Security](/plugins/security#rate_limit)             |
| `csrf`                 | Always on; allowlist from `manifest.auth.trustedOrigins` / env          | [Security](/plugins/security#unified-trustedorigins) |
| LLM proxy (`ai_proxy`) | Env-configured; powers `/api/llm/complete`, `/api/ai/stream`, `ctx.llm` | [Search & AI](/plugins/search-ai#llm-proxy)          |
| In-process cache       | Internal; backs SSR / ISR response caching                              | —                                                    |

## How built-ins hook in

Built-ins observe the request and data path at fixed points. The exact Rust hooks (see [Writing your own](/plugins/writing-your-own)):

```
HTTP request
     │
     ▼
   on_request ──── rate_limit (reject if over budget)
     │       ──── csrf (origin check on cookie-authed writes)
     │
     ▼
   entity write (insert / update / delete)
     │   ──── before_insert / before_update / before_delete
     │        (tenant_scope injects + validates tenantId;
     │         owner_stamp stamps ownerId from the session)
     │
     ▼
   after_insert / after_update / after_delete
```

A built-in can inspect or reject a request (`on_request`), mutate or reject a write (`before_*`), react after a write lands (`after_*`), add HTTP routes (`routes()`), or contribute manifest entities (`entities()`).

## There is no `plugins: []` array

Older drafts of these docs described enabling plugins through a `pylon.manifest.json` `plugins` list with per-plugin `config`. **That mechanism does not exist.** Built-ins are automatic; you influence them through your schema (add a `tenantId` field, annotate a field `.owner()`) and environment variables. App-specific cross-cutting logic goes in [server functions](/concepts/functions) and [policies](/concepts/policies), not a plugin config block.

`pylon plugins list` prints a **roadmap catalog** of plugin names (validation, slugify, versioning, cascade, MCP, and more). These are planned, not installable today — treat the list as a preview, not an API.

## Plugins vs functions

| Plugins / built-ins                                            | Functions                                 |
| -------------------------------------------------------------- | ----------------------------------------- |
| Implicit — fire on every relevant op                           | Explicit — called by name                 |
| Auto-wired from schema/env, or composed from a TS package      | Defined in TS files under `functions/`    |
| Can mutate data in-flight (built-ins)                          | Run inside a transaction; return a result |
| Cross-cutting concerns (tenant scope, owner stamp, rate limit) | Business logic                            |
| Compiled into the binary, or shipped as a package              | Hot-reloaded by the dev server            |

Use a built-in when the behavior should apply to **every** call. Use a function when callers opt in by name.

## Writing your own

There is no dynamic plugin loading yet. To add a Rust built-in you build a custom runtime that registers it; for TypeScript-side logic, use functions and policies. The SDK ships a `definePlugin({ name, entities, hooks })` helper, but the runtime does not consume its output yet. See [Writing your own plugin](/plugins/writing-your-own) for the real `Plugin` trait and the honest state of extensibility.
