> For the complete documentation index, see [llms.txt](https://docs.kangal.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kangal.dev/sdks/plugin-sdk.md).

# Build a custom plugin

The Kangal Plugin SDK is for platform teams that need custom gateway policy.

## Install

```bash
python -m pip install kangal-plugin-sdk
```

Each release is published as a verified wheel and source archive. The matching GitHub release includes SHA-256 checksums and keyless Sigstore bundles. Its public runtime contract is `kangal.plugin/v1`; the canonical SDK currently targets Python 3.11 or newer.

## Implement a plugin

```python
from kangal_plugin_sdk import Plugin


class HeaderPolicy(Plugin):
    async def before_request(self, request, headers, tenant_id):
        updated = dict(headers)
        updated["X-Policy-Version"] = str(self.config.get("version", "1"))
        return updated
```

Implement only the hooks required by the policy:

| Protocol       | Hooks                                                    |
| -------------- | -------------------------------------------------------- |
| HTTP           | `before_request`, `after_response`, `on_error`           |
| Streaming HTTP | `before_request`, `stream`, `after_response`, `on_error` |
| WebSocket      | `before_request`, `stream`, `on_error`                   |
| gRPC           | `before_request`, `stream`, `after_response`, `on_error` |
| TCP            | `tcp`, `on_error`                                        |

## Package and sign

1. Start from `sdk/examples/header_policy/manifest.template.json`.
2. Declare the entrypoint, protocol stages, configuration schema, and runtime limits.
3. Build the immutable artifact and record its SHA-256 digest.
4. Sign the manifest with an Ed25519 publisher key.
5. Add the public key to the trusted signer configuration.
6. Publish the immutable version to an approved private registry.
7. Sync, install, configure, and enable the plugin through Kangal.

Before package installation, configure `PLUGIN_PACKAGE_TRUSTED_SIGNERS` on the Kangal control-plane process. The value must be a JSON object that maps each manifest `signer` ID to its Ed25519 public key:

```bash
export PLUGIN_PACKAGE_TRUSTED_SIGNERS='{"platform-publisher":"BASE64_RAW_ED25519_PUBLIC_KEY"}'
```

Each mapping value may be either a PEM public key beginning with `-----BEGIN PUBLIC KEY-----` (with newlines escaped inside JSON) or the Base64 encoding of the raw 32-byte Ed25519 public key. Configure the mapping and restart the process before syncing and installing the package; installation accepts only a package whose signer resolves to a valid trusted key.

## Runtime controls

Plugin configuration supports timeout, per-hook timeout, maximum concurrency, failure threshold, recovery timeout, and failure mode. Authentication and enforcement policies always fail closed on an indeterminate result.

The runtime does not execute arbitrary code downloaded during registry sync. Executable plugin code must be included in the approved gateway runtime image and registered with the exact package version, digest, and entrypoint.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kangal.dev/sdks/plugin-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
