<!--
SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->

# Define a Plugin

Use this guide when you want to package reusable NeMo Flow behavior as a plugin that can be activated from configuration.

## What You Build

You will define the plugin's purpose, stable kind name, configuration boundary, runtime surfaces, and activation lifecycle. The result is a small plugin contract that can be validated and registered through the more focused follow-on guides.

:::{note}
NeMo Flow plugin configuration keys use `snake_case` in every language and file
format. Node.js helper function names are `camelCase`, but the objects passed to
`plugin.initialize(...)` use the same canonical `snake_case` keys as Python,
Rust, JSON, and TOML plugin configuration.
:::

## Before You Start

You need:

- A reusable behavior that belongs outside one application call site.
- A stable plugin kind name.
- A JSON-compatible config shape.
- A decision about which runtime surfaces the plugin installs.
- A teardown plan for tests and applications that need to clear active configuration.

## Plugin Shape and Requirements

A plugin needs a stable shape before operators can activate it from config:

| Requirement | Why It Matters |
|---|---|
| Stable `kind` | The plugin registry uses this string to match config to implementation. |
| JSON-compatible config | Config must move across Python, Node.js, Rust, files, tests, and deployment systems. |
| Validation hook | Operators need diagnostics before runtime behavior changes. |
| Registration hook | Runtime behavior should be installed through `PluginContext` for name qualification and rollback. |
| Runtime ownership | The plugin should clearly own subscribers, middleware, adaptive behavior, or a small bundle of related surfaces. |

Keep runtime objects out of config. Provider clients, callbacks, file handles, caches, and credentials should be created inside plugin code or resolved from safe references during registration.

## What a Plugin Can Install

A plugin can install one or more of these runtime surfaces:

- Subscribers
- Tool sanitize-request guardrails
- Tool sanitize-response guardrails
- Tool conditional-execution guardrails
- Tool request intercepts
- Tool execution intercepts
- LLM sanitize-request guardrails
- LLM sanitize-response guardrails
- LLM conditional-execution guardrails
- LLM request intercepts
- LLM execution intercepts
- LLM stream execution intercepts

Start with one surface. Add a bundle only when one configuration document clearly controls related behavior, such as a subscriber plus the request intercepts needed to add correlation metadata.

## Registration Lifecycle

The diagram below shows how plugin configuration turns into registered runtime behavior.

```{mermaid}
flowchart TB
    Kind[Plugin kind<br/>registered once]
    Config[Plugin config<br/>version + components + policy]
    Validate{{Validate component config}}
    Diagnostics[/Structured diagnostics/]
    Initialize[Initialize enabled components]
    Context[PluginContext<br/>component-scoped registrar]
    Runtime[Runtime registrations<br/>subscribers + middleware]
    Rollback[Rollback partial setup<br/>if initialization fails]

    Kind --> Validate
    Config --> Validate
    Validate --> Diagnostics
    Validate -->|valid or warning-only| Initialize
    Initialize --> Context
    Context --> Runtime
    Initialize -->|error| Rollback
    Context -->|registration error| Rollback
```

The lifecycle is staged: register the plugin kind, validate component config, initialize enabled components, and let `PluginContext` install runtime behavior. If registration fails partway through, the plugin system can roll back partial setup.

## Keep the First Plugin Small

The easiest first plugin is one of these:

- A subscriber-oriented plugin that exports events.
- A request-intercept plugin that adds one provider header.
- A sanitize guardrail plugin that redacts one field family.
- A policy plugin that registers one conditional-execution guardrail.

Avoid a first plugin that combines unrelated subscribers, request transforms, policy checks, and adaptive behavior. Multi-surface bundles are useful later, but they need stronger validation and rollout controls.

## Minimal Config Contract

The top-level config document has `version`, `components`, and `policy`. Each component chooses a plugin kind and passes component-local JSON config to that plugin.

```json
{
  "version": 1,
  "components": [
    {
      "kind": "header-plugin",
      "enabled": true,
      "config": {
        "header_name": "x-tenant",
        "value": "tenant-a"
      }
    }
  ],
  "policy": {
    "unknown_component": "warn",
    "unknown_field": "warn",
    "unsupported_value": "error"
  }
}
```

Use this document as the boundary between operator intent and plugin implementation. Keep business logic in the plugin code, not in the config parser.

## Design Checklist

Before you write the plugin implementation, answer these questions:

- What is the stable plugin `kind`?
- What runtime surface does it install first?
- Which config fields are required?
- Which fields are safe to expose as JSON?
- What diagnostic should appear when each required field is missing?
- What should happen when the component is disabled?
- What should happen when registration fails halfway through?

## Next Steps

Use these links to continue from this workflow into the next related task.

- Define validation behavior with [Validate Plugin Configuration](validate-configuration.md).
- Register runtime behavior with [Register Plugin Behavior](register-behavior.md).
- Add rollout controls with [Design Plugin Configuration](advanced-configuration.md).
- Review complete examples in [Code Examples](code-examples.md).
