> ## 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.

# Custom Adapters

Use this guide when you are a **plugin author** integrating a new Python framework (AG2, AutoGen, an internal runtime, etc.) — not when you only need a plain Python function agent.

> **Using plain Python only?** You probably want the built-in **`custom`** adapter from `charm init --template python`. See [Custom Python Adapter](/adapters/custom). This guide is for registering a **new adapter name** via entry points.

## How discovery works

Charm loads adapters from Python **`entry_points`** in the `charm.adapters` group. The name you register becomes a valid `runtime.adapter.type` in `charm.yaml`.

Official adapters (`langchain`, `crewai`, `openclaw`, `custom`, …) use the same mechanism in the `charmos` package. Third-party packages add more names without forking core.

### 1. Get the Boilerplate

> \[!TIP]
> **Fastest Path:** You do not need to write this from scratch. Use the official **[charm-adapter-template](https://github.com/CharmAIOS/charm-adapter-template)** repository on GitHub. Click **Use this template**, rename the folder, and jump straight to implementing your `invoke` method.

If you are doing it manually, start by scaffolding a plain project:

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
charm init my-ag2-agent --template python
cd my-ag2-agent
```

This scaffolds `charm.yaml`, `src/main.py`, and `.charmignore`. You will add a **separate installable package** (or a `pyproject.toml` in the same repo) for the adapter plugin.

### 2. Implement `BaseAdapter`

Your class must inherit from `charm.adapters.base.BaseAdapter` and implement `invoke`.

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
from typing import Any, Dict, List, Optional
from charm.adapters.base import BaseAdapter

class Ag2Adapter(BaseAdapter):
    def invoke(
        self, inputs: Dict[str, Any], callbacks: Optional[List[Any]] = None
    ) -> Dict[str, Any]:
        # self.agent is the object imported from runtime.adapter.entry_point
        result = self.agent.run(**inputs)
        return {
            "status": "success",
            "output": result,
        }
```

The loader constructs your adapter as `AdapterClass(agent_instance=..., config=...)` after importing the user's entry point from `charm.yaml`.

Return a dict with `"status": "success"` and `"output"` for standard Store rendering, or include structured keys like `_charm_render_type` (see [Output Renderers](/guides/output-renderers)).

### 3. Register via entry points

In your plugin package's `pyproject.toml`:

```toml theme={"theme":{"light":"min-light","dark":"min-dark"}}
[project]
name = "charm-adapter-ag2"
version = "0.1.0"
dependencies = ["charmos"]

[project.entry-points."charm.adapters"]
ag2 = "charm_adapter_ag2.adapter:Ag2Adapter"
```

Install locally while developing:

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
pip install -e ./path/to/charm-adapter-ag2
pip install -e ./path/to/my-ag2-agent   # if separate
```

Verify discovery:

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
python -c "from importlib.metadata import entry_points; print([e.name for e in entry_points(group='charm.adapters')])"
```

`charm validate` should accept `runtime.adapter.type: ag2` after your package is installed.

### 4. Configure `charm.yaml`

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
version: "0.4.2"

persona:
  name: "My AG2 Agent"
  description: "Agent using a third-party adapter plugin"
  version: "0.1.0"

interface:
  input:
    type: object
    required: [message]
    properties:
      message: { type: string }
  output:
    type: string

runtime:
  adapter:
    type: ag2
    entry_point: src.main:my_agent
  lifecycle: serverless
```

### 5. Cloud execution requires a custom image

The cloud runner **will automatically `uv pip install` your adapter if it is listed in the user's `requirements.txt`**. However, if your adapter depends on massive libraries (like PyTorch or large LLM frameworks), `uv pip install` might timeout during Cloud Run startup.

For heavy adapters, you should provide a custom image:

1. Build a Docker image based on [charm-base](https://github.com/CharmAIOS/Charm/pkgs/container/charm-base) or an official runner image
2. `RUN uv pip install charm-adapter-ag2` (or `pip install`) inside the Dockerfile
3. Set `runtime.custom_image` to the pushed image URI

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
runtime:
  custom_image: "ghcr.io/your-org/my-ag2-runtime:prod"
  adapter:
    type: ag2
    entry_point: src.main:my_agent
```

### 6. Submit to the Charm Store

To make your adapter discoverable by the global Charm community:

1. Fork the [charm-community-plugin](https://github.com/CharmAIOS/charm-community-plugin) repository.
2. Edit `adapters/registry.json` to add your package name (`charm-adapter-ag2`).
3. Submit a Pull Request.

Once merged, your adapter will instantly appear in the **Charm Store Plugins Gallery**, allowing users to one-click copy the install command.

See [Custom Runtimes](/guides/custom-runtimes) for registry and IAM notes.

## Local testing

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
# Validates adapter type (plugin must be installed in local env)
charm validate .

# Runs agent logic locally (uses local env, not necessarily your custom image)
charm run . --input "hello"

# Simulates cloud container (uses custom_image from charm.yaml)
charm run . --docker --input "hello"
```

## Related

* [Extensibility Overview](/guides/extensibility)
* [Custom Runtimes](/guides/custom-runtimes)
* [Custom Python Adapter](/adapters/custom) — built-in path, no entry points
* [Write a Custom Adapter](/oss/adapter) — contributing official adapters to the SDK repo
