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

# Extensibility Overview

Charm separates a **small stable core** from **community-owned extensions**. Not every extension works the same way — some are runtime Python plugins, some are store contributions, and some are manifest PRs.

Use this page to pick the right path before you start building.

## Extension paths at a glance

| What you want to add                              | Registration                         | Runs where      | Needs `custom_image` on cloud?     | Needs store deploy?                    |
| ------------------------------------------------- | ------------------------------------ | --------------- | ---------------------------------- | -------------------------------------- |
| [Custom adapter plugin](/guides/custom-adapters)  | `charm.adapters` entry point         | Agent container | **Yes**                            | No                                     |
| [Custom runtime only](/guides/custom-runtimes)    | `runtime.custom_image` in YAML       | Agent container | **Yes**                            | No                                     |
| [Telemetry exporter](/guides/telemetry-exporters) | `charm.telemetry` entry point        | Agent container | **Typically No** (dynamic install) | No                                     |
| [Memory backend](/guides/state-and-memory)        | `charm.memory` entry point           | Agent container | **Typically No** (dynamic install) | No                                     |
| [Input form widgets](/guides/interface)           | `interface.ui` in YAML               | Store UI        | No                                 | **Typically No** (dynamic ESM install) |
| [Output renderers](/guides/output-renderers)      | `_charm_render_type` in agent output | Store UI        | No                                 | **Typically No** (dynamic ESM install) |
| [Starter templates](/guides/community-templates)  | PR to `charm-community-plugin`       | `charm init`    | No                                 | No (manifest merge)                    |

## Two kinds of “custom” (important)

These names overlap — they are **not** the same thing:

| Term                               | Meaning                                                                                                                       |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **`runtime.adapter.type: custom`** | Built-in Charm adapter for plain Python agents (`CharmCustomAdapter` in core). Good default for `charm init` projects.        |
| **`runtime.custom_image`**         | Docker image override for the cloud runner. Required for heavy dependencies, custom system packages, or third-party adapters. |
| **Third-party adapter plugin**     | New adapter name (e.g. `ag2`, `plugin_test`) registered via `[project.entry-points."charm.adapters"]`.                        |

Scenario: you can use **`type: custom`** with **`custom_image`** (extra deps, no new adapter class).\
Scenario: you can use **`type: ag2`** with **`custom_image`** (new adapter plugin + image that installs it).

## Recommended workflow for plugin authors

1. **Start from a normal agent** — `charm init my-agent --template python`
2. **Add a pip package** with your adapter/telemetry/memory classes and `pyproject.toml` entry points
3. **Point `charm.yaml` at your plugin** — `runtime.adapter.type: your_plugin_name`
4. **Add to requirements.txt** (if lightweight like Telemetry or Memory) **OR** Build a `custom_image` (if heavy like Adapters)
5. **Set `runtime.custom_image`** in `charm.yaml` (if you built a Docker image)
6. **`charm validate`** → **`charm push`** → run on the Store

> **Note:** The cloud runner **will** execute `uv pip install -r requirements.txt` at runtime. For lightweight plugins, this is all you need. For heavy plugins (like third-party adapters), you must bake them into a `custom_image` to avoid boot timeouts.

## Built-in vs third-party

| Layer              | Built-in (no plugin package)                               | Third-party (plugin author)       |
| ------------------ | ---------------------------------------------------------- | --------------------------------- |
| Python agent logic | `charm init` + `type: custom`                              | Same                              |
| Adapter type       | `custom`, `langchain`, `openclaw`, …                       | New name via entry points         |
| Runtime image      | Official `runner-*` images                                 | Your `custom_image`               |
| Store form widgets | `text`, `textarea`, `file`, `select`, `checkbox`, `slider` | New widgets → community plugin PR |
| Rich output UI     | Built-in `_charm_render_type` values                       | New types → community plugin PR   |

## Cloud prerequisites

For any **custom image** on production:

1. Push the image to a registry the runner can pull (Artifact Registry, GHCR, etc.)
2. Grant the runner service account **read** access to that registry (if private)
3. Declare `runtime.custom_image` in `charm.yaml` — the runner selects it over default adapter images

See [Base Images](/platform/base-images) and [Custom Runtimes](/guides/custom-runtimes).

## Next steps

* [Custom Adapters](/guides/custom-adapters) — third-party framework integration
* [Custom Runtimes](/guides/custom-runtimes) — Docker image overrides
* [Telemetry Exporters](/guides/telemetry-exporters)
* [State & Memory](/guides/state-and-memory)
* [Input Forms (UI Schema)](/guides/interface)
* [Output Renderers](/guides/output-renderers)
* [Community Templates](/guides/community-templates)

For core contributors merging adapters into the official SDK, see [Write a Custom Adapter](/oss/adapter) (in-repo process).
