← Documentation home

Build an Add-on

Add-ons extend the Agent Code host application. They are distinct from Skills, which add tools for the AI agent to call.

1. What the current Add-on API can do

The Add-on API is an explicit extension API, not unrestricted monkey-patching. A service replacement works only when the relevant Agent Code core code calls resolve_service() for that service name. The currently wired integration in this source includes the Skill Store service. Do not assume every URL or backend (Skills Forge, updates, repositories, etc.) is replaceable unless the host release exposes that service point.

2. Install location and folder structure

~/.local/share/agent-code/addons/
└── sample-addon/
    ├── addon.json
    ├── addon.py
    ├── README.md
    └── helpers.py

Windows: %LOCALAPPDATA%\AgentCode\addons\. Add-ons are per-user. The Add-ons page can create a starter template and discover installed add-on folders.

3. Manifest

{
  "name": "sample-addon",
  "version": "1.0.0",
  "description": "Adds a project utility panel",
  "author": "Your Name"
}

The folder must contain addon.json and addon.py. The manifest name must be a valid identifier (letters, numbers, dot, underscore or hyphen; it must begin with a letter or number).

4. Minimal Add-on

def register(api):
    api.register_action(
        "Say hello",
        lambda: "Hello from my add-on",
        description="A simple action"
    )

    api.register_command(
        "status",
        lambda args, log: log("Add-on is active", "dim"),
        "Show add-on status"
    )

Commands are namespaced automatically. For an add-on named sample-addon, invoke /sample-addon:status.

5. Add an agent tool

def get_project_label(label="my project"):
    return {"label": label, "source": "sample-addon"}


def register(api):
    api.register_tool({
        "type": "function",
        "function": {
            "name": "sample_project_label",
            "description": "Return a project label.",
            "parameters": {
                "type": "object",
                "properties": {
                    "label": {"type": "string"}
                }
            }
        }
    }, get_project_label)

Tool names must be unique across loaded Add-ons. Tools are added to the agent tool registry and follow the application's existing permission and Plan Mode handling.

6. Add UI components

def build_workspace_panel(parent, app):
    import customtkinter as ctk
    frame = ctk.CTkFrame(parent)
    title = ctk.CTkLabel(frame, text="My workspace panel")
    title.pack(padx=12, pady=8)
    button = ctk.CTkButton(
        frame,
        text="Show project path",
        command=lambda: app.log_line(str(app.project_dir), "dim")
    )
    button.pack(padx=12, pady=8)
    return frame


def register(api):
    api.register_ui(
        "workspace-panel",
        build_workspace_panel,
        location="workspace",
        label="Workspace panel",
        description="An example workspace widget"
    )

The API accepts sidebar, addons, settings, toolbar and workspace as location labels. In this release, the host currently mounts registered widgets in the sidebar and addons locations; the other labels are accepted by the registration API but are not yet mounted by the main UI. A builder receives (parent, app) and must return a Tk/CustomTkinter widget. Keep widget construction quick; do not perform blocking network or filesystem work on the UI thread.

7. Replace a supported application service

class AlternateSkillStore:
    base_url = "https://store.example.invalid/api"

    def list_skills(self):
        # Implement the interface expected by the host's Skill Store caller.
        return []


def register(api):
    api.register_service(
        "skill_store",
        AlternateSkillStore(),
        replaces=True,
        priority=50,
        description="Use our compatible Skill Store backend"
    )

Service resolution selects the registered implementation with the highest replacement/priority ordering. The implementation must match the interface expected by the specific core integration. Read the host source for the current service contract before replacing it.

8. Lifecycle hooks

def task_started(app=None, task=None, **context):
    # Keep this fast. Do not block the GUI thread.
    return None


def register(api):
    api.on("task_started", task_started)

Events currently emitted include tools_loaded, task_started, task_finished, before_tool_call and after_tool_call. Hook callback exceptions are isolated by the manager. Do not assume event payload fields beyond those supplied by the host implementation; inspect the matching call site.

9. Helper modules and dependencies

Place helper modules beside addon.py. The loader adds the add-on folder to Python's import path while loading the add-on, so local imports can work. The current manager does not provide a dependency resolver or install dependencies automatically. Document dependencies in your README and install them in a controlled environment before enabling the add-on.

10. Test and package

  1. Run python -m py_compile addon.py.
  2. Install the folder in the Add-ons directory.
  3. Restart/reload the application as required by the current UI; then inspect the Add-ons page for load errors.
  4. Verify each UI location, command, tool and service replacement you registered.
  5. Test with the default service selected and with the add-on disabled to confirm fallback behavior.
cd ~/.local/share/agent-code/addons
zip -r sample-addon-1.0.0.zip sample-addon \
  -x '*/__pycache__/*' '*.pyc' '*.env' '*.key'

11. Trust, compatibility and limitations

Add-ons are trusted Python programs. They run with the current user's OS permissions and are not sandboxed. Disabling an add-on prevents it from being imported on the next load; it does not undo filesystem, network or process side effects that already occurred.

The current framework does not include a public signed marketplace, automatic dependency management, arbitrary core monkey-patching, or universal replacement points for every server. Those require additional host APIs and security work.

Read the Skill author guide →