Skip to main content
Plugins extend the GitAgent runtime itself. While skills add capabilities to an agent, plugins add capabilities to the runtime — new skill discovery methods, output processors, authentication providers, memory backends, and more.

Plugin types

Plugin typeWhat it extends
SkillLoaderHow skills are discovered and loaded
OutputProcessorHow skill outputs are processed before the LLM sees them
AuthProviderAuthentication for outbound HTTP requests in skills
MemoryBackendCustom memory storage (database, API, etc.)
TracerCustom telemetry export

Writing a plugin

Plugins live in the plugins/ directory. Each plugin is a Python class that inherits from the appropriate base class:
# plugins/my_output_processor.py
from gitagent.plugins import OutputProcessor

class TruncatePlugin(OutputProcessor):
    """Truncate long skill outputs to keep context size manageable."""

    def __init__(self, max_chars: int = 2000):
        self.max_chars = max_chars

    def process(self, skill_name: str, output: any) -> any:
        if isinstance(output, str) and len(output) > self.max_chars:
            return output[:self.max_chars] + f"\n\n[Truncated — {len(output)} total chars]"
        return output
Register the plugin in agent.yaml:
plugins:
  - class: TruncatePlugin
    config:
      max_chars: 3000

SkillLoader plugin

Load skills from non-standard sources (a database, a remote URL, a compiled package):
# plugins/db_skill_loader.py
from gitagent.plugins import SkillLoader
from gitagent import skill
import json

class DatabaseSkillLoader(SkillLoader):
    """Load skill definitions stored in a database."""

    def load_skills(self) -> list:
        skills = []
        for row in db.query("SELECT * FROM agent_skills WHERE active = true"):
            # Dynamically create skill functions
            fn = self._make_skill_function(row)
            skills.append(fn)
        return skills

    def _make_skill_function(self, row):
        @skill(name=row["name"], description=row["description"])
        def dynamic_skill(**kwargs):
            return call_api(row["endpoint"], kwargs)
        return dynamic_skill

AuthProvider plugin

Inject authentication into outbound HTTP requests made by skills:
# plugins/bearer_auth.py
from gitagent.plugins import AuthProvider
import os

class BearerAuthPlugin(AuthProvider):
    """Inject a bearer token into requests to internal APIs."""

    def get_headers(self, url: str) -> dict:
        if "internal.example.com" in url:
            return {"Authorization": f"Bearer {os.environ['INTERNAL_API_TOKEN']}"}
        return {}
Register in agent.yaml:
plugins:
  - class: BearerAuthPlugin
The http_request built-in tool automatically calls get_headers() before each request.

MemoryBackend plugin

Implement a custom memory storage layer:
# plugins/postgres_memory.py
from gitagent.plugins import MemoryBackend
import psycopg2

class PostgresMemory(MemoryBackend):
    def __init__(self, dsn: str):
        self.conn = psycopg2.connect(dsn)

    def read(self, key: str) -> str | None:
        with self.conn.cursor() as cur:
            cur.execute("SELECT value FROM agent_memory WHERE key = %s", (key,))
            row = cur.fetchone()
            return row[0] if row else None

    def write(self, key: str, value: str) -> None:
        with self.conn.cursor() as cur:
            cur.execute(
                "INSERT INTO agent_memory (key, value) VALUES (%s, %s) "
                "ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value",
                (key, value)
            )
        self.conn.commit()

    def delete(self, key: str) -> None:
        with self.conn.cursor() as cur:
            cur.execute("DELETE FROM agent_memory WHERE key = %s", (key,))
        self.conn.commit()
Register in agent.yaml:
memory:
  provider: custom
  plugin: PostgresMemory
  config:
    dsn: ${DATABASE_URL}

Tracer plugin

Send telemetry to a custom backend:
# plugins/my_tracer.py
from gitagent.plugins import Tracer

class SplunkTracer(Tracer):
    def on_run_start(self, run_id: str, input: str): ...
    def on_skill_call(self, run_id: str, skill_name: str, input: dict): ...
    def on_skill_result(self, run_id: str, skill_name: str, output: any): ...
    def on_run_end(self, run_id: str, output: str, duration_ms: int): ...

Plugin configuration

Full agent.yaml plugin configuration:
plugins:
  - class: TruncatePlugin          # local file: plugins/truncate_plugin.py
    config:
      max_chars: 3000

  - class: gitagent_slack.SlackNotifier  # installed package
    config:
      webhook_url: ${SLACK_WEBHOOK}
      notify_on: [run_complete, run_error]
Plugins can be:
  • Local files in plugins/ (referenced by class name)
  • Installed Python packages (referenced by fully-qualified dotted path)

Publishing a plugin

Plugins can be packaged and published to PyPI for reuse across projects:
# setup.py (or pyproject.toml)
entry_points = {
    "gitagent.plugins": [
        "my-plugin = my_package.plugin:MyPlugin"
    ]
}
Once installed, reference by entry point name in agent.yaml:
plugins:
  - class: my-plugin
    config: ...