Skip to main content
Prerequisites: Complete the Setup guide and have the Agent UI running before you start.

Overview

GAIA’s agent registry lets you extend the Agent UI with your own custom agents. Each agent lives in its own directory under ~/.gaia/agents/ as a Python module. Once placed there, the agent appears automatically in the agent selector dropdown of the Gaia Agent UI. Custom agents can have their own:
  • Personality and instructions (system prompt)
  • Tools (RAG, file search, shell, image generation, vision, plus your own @tool functions)
  • Preferred models (override the server default)
  • Conversation starters (suggestion chips in the UI)
  • MCP servers (any Model Context Protocol server)
  • Connectors (Google, GitHub, and more) — give your agent permission to read your real email, calendar, repos, etc.

Quick Start: Gaia Builder Agent

The fastest way to create an agent is to use the built-in Gaia Builder Agent.
1

Open the Agent UI

Start the GAIA Agent UI: gaia chat --ui
2

Click the + button

In the chat input footer, click the + icon (to the left of the agent picker). On the welcome screen, click Build a Custom Agent Template.
3

Follow the prompts

The Builder (an alpha feature) greets you, asks what to name the agent and what it should do, and asks whether you want MCP support — then scaffolds a starter agent with a personality and conversation starters tailored to your description.
4

Use your new agent

Your agent is immediately available in the agent selector dropdown — no restart needed.
The Builder creates a starter template at ~/.gaia/agents/<your-agent-name>/agent.py — a tailored persona and conversation starters (plus MCP wiring if you asked for it). It’s a starting point you extend, not a turnkey agent: it won’t fetch data or perform complex tasks on its own until you add tools. Open the file to refine the instructions and add capabilities (see Python Agent below).
Need your agent to read real data — Gmail, GitHub, your calendar? Skip ahead to Using GAIA connectors.

Python Agent

For full control — custom tools, built-in tool mixins, MCP servers, or complex logic — write a Python module.

Directory structure

~/.gaia/agents/
└── my-agent/
    ├── agent.py          # required — defines the Agent subclass
    └── agent.yaml        # optional sidecar — only the `models:` list is read

Minimal Python agent

from gaia.agents.base.agent import Agent
from gaia.agents.base.console import AgentConsole
from gaia.agents.base.tools import _TOOL_REGISTRY, tool


class MyPythonAgent(Agent):
    AGENT_ID = "my-python-agent"
    AGENT_NAME = "My Python Agent"
    AGENT_DESCRIPTION = "An agent with a custom tool"

    def _get_system_prompt(self) -> str:
        return "You are a helpful assistant with a custom greet tool."

    def _create_console(self) -> AgentConsole:
        return AgentConsole()

    def _register_tools(self) -> None:
        _TOOL_REGISTRY.clear()
        self._register_custom_tools()

    def _register_custom_tools(self) -> None:
        @tool
        def greet(name: str) -> str:
            """Greet a person by name."""
            return f"Hello, {name}! Welcome to GAIA."
The three required methods are:
MethodPurpose
_get_system_prompt()Returns the system prompt string
_create_console()Returns an AgentConsole instance
_register_tools()Registers tools into _TOOL_REGISTRY

Adding built-in tools

GAIA ships with ready-to-use tool mixins. To enable them, inherit the mixin and call its register_*_tools() method from _register_tools():
ToolMixinRegister call
raggaia.agents.tools.rag_tools.RAGToolsMixinself.register_rag_tools()
file_searchgaia.agents.tools.file_tools.FileSearchToolsMixinself.register_file_search_tools()
file_iogaia.agents.tools.file_io_tools.FileIOToolsMixinself.register_file_io_tools()
shellgaia.agents.tools.shell_tools.ShellToolsMixinself.register_shell_tools()
screenshotgaia.agents.tools.screenshot_tools.ScreenshotToolsMixinself.register_screenshot_tools()
sdgaia.sd.mixin.SDToolsMixinself.register_sd_tools()
vlmgaia.vlm.mixin.VLMToolsMixinself.register_vlm_tools()
To call out to external services (Gmail, GitHub, Slack, etc.) without baking API keys into your code, use GAIA connectors instead of writing your own auth.

Overriding the default model (optional)

If your agent needs a specific model, set model_id in __init__():
def __init__(self, **kwargs):
    kwargs.setdefault("model_id", "Gemma-4-E4B-it-GGUF")
    super().__init__(**kwargs)
Alternatively, create a companion agent.yaml next to agent.py with a models: list — the registry reads that list as an ordered preference. The sidecar only honours the models: key; any other top-level key is ignored.

Using GAIA connectors

If your agent needs to act on your behalf — read your inbox, list your calendar events, query GitHub, post to Slack, etc. — wire it up to a GAIA connector rather than asking users to paste API tokens into your code. A connector lets users:
  1. Authenticate once in Settings → Connections (OAuth flow for Google-style providers, paste-an-API-key for MCP servers).
  2. Grant scopes per agent so each agent only sees the data it actually needs. The Agent UI surfaces this when a user first picks your agent.
  3. Trust that secrets stay in the OS keyring, never in plaintext files or env vars baked into your code.
Declare what your agent needs by setting REQUIRED_CONNECTORS on the class, and call get_credential_sync(connector_id, agent_id, required_scopes=[...]) from inside a tool to get a usable token. The connectors-demo agent is a working reference for both oauth_pkce (Google) and mcp_server (GitHub) connectors.

Read the connectors guide

Walks through what connectors are, how the OAuth + MCP flows differ, per-agent grants, and a step-by-step setup for Google and GitHub.

Export and import agents

Custom agents can be packaged into a single .zip bundle and shared between machines, teammates, or environments. GAIA supports export and import from both the Agent UI and the CLI.

From the Agent UI

Open Settings → Custom Agents.
  • Export All — packages every custom agent under ~/.gaia/agents/ into a single .zip file and downloads it. Disabled when you have no custom agents.
  • Import — opens a file picker for a .zip bundle and shows a confirmation dialog listing the agent IDs that will be installed. Imported agents register into the live registry; in most cases no restart is required.

From the CLI

# Export every custom agent to ~/.gaia/export.zip
gaia agent export

# Export to a specific path
gaia agent export --output ./my-agents.zip

# Import a bundle (shows IDs and prompts for confirmation)
gaia agent import ./my-agents.zip

# Import non-interactively (CI / scripts)
gaia agent import ./my-agents.zip --yes
See the CLI reference for full option details.

What’s in the bundle

Each .zip contains a bundle.json manifest at the root and one directory per agent:
my-agents.zip
├── bundle.json                  # { format_version, exported_at, gaia_version, agent_ids[] }
├── my-research-bot/
│   ├── agent.py
│   └── agent.yaml               # if present
└── my-greeter/
    └── agent.py
Bundles are validated on import. The receiving end enforces conservative limits (max 1000 entries, 500 MB uncompressed, 50 MB per file, 100 MB upload via the UI) and rejects symlinks or path-traversal entries.

Security

Bundles ship your agent source as-is. Any API keys, hardcoded tokens, or secrets embedded in agent.py will be included in the export. Review the bundle — or better, move secrets to GAIA connectors — before sharing.
Importing runs third-party code. A bundle’s agent.py files execute inside your GAIA process. Both the CLI (gaia agent import without --yes) and the UI surface the agent IDs and require explicit confirmation before installing. Only import bundles from sources you trust.
The UI endpoints (POST /api/agents/export and POST /api/agents/import) are localhost-only, CSRF-guarded with the X-Gaia-UI header, and disabled while a tunnel is active.

Examples

from gaia.agents.base.agent import Agent
from gaia.agents.base.console import AgentConsole
from gaia.agents.base.tools import _TOOL_REGISTRY


class ZooAgent(Agent):
    AGENT_ID = "zoo-agent"
    AGENT_NAME = "Zoo Agent"
    AGENT_DESCRIPTION = "A zookeeper who loves animals"
    CONVERSATION_STARTERS = [
        "Hello! What's happening at the zoo today?",
        "Tell me a fun fact about one of your animals.",
    ]

    def _get_system_prompt(self) -> str:
        return (
            "You are a funny and enthusiastic zookeeper! You work at the world's "
            "best zoo and every response you give includes a fun fact or a playful "
            "reference to one of your beloved zoo animals."
        )

    def _create_console(self) -> AgentConsole:
        return AgentConsole()

    def _register_tools(self) -> None:
        _TOOL_REGISTRY.clear()
from gaia.agents.base.agent import Agent
from gaia.agents.base.console import AgentConsole
from gaia.agents.base.tools import _TOOL_REGISTRY
from gaia.agents.tools.shell_tools import ShellToolsMixin
from gaia.agents.tools.file_io_tools import FileIOToolsMixin


class CodeReviewAgent(Agent, FileIOToolsMixin, ShellToolsMixin):
    AGENT_ID = "code-review-agent"
    AGENT_NAME = "Code Review Agent"
    AGENT_DESCRIPTION = "Reviews code and runs linters"

    def _get_system_prompt(self) -> str:
        return (
            "You are an expert code reviewer. You read files, run linters, "
            "and provide actionable feedback. Be specific about file names "
            "and line numbers. Prioritize correctness and security."
        )

    def _create_console(self) -> AgentConsole:
        return AgentConsole()

    def _register_tools(self) -> None:
        _TOOL_REGISTRY.clear()
        self.register_file_io_tools()
        self.register_shell_tools()

Troubleshooting

  • Ensure the directory is under ~/.gaia/agents/<id>/ and contains agent.py.
  • The directory name does not need to match the AGENT_ID class attribute, but it helps.
  • Check the server logs for warnings like Failed to load agent from ....
  • If you created the agent manually (not via the Builder), restart the GAIA server — discovery runs at boot. Agents created via the Builder Agent are loaded immediately without a restart.
Check the server logs for load errors. Ensure AGENT_ID, AGENT_NAME, and AGENT_DESCRIPTION are set as class attributes, and that the three required methods (_get_system_prompt, _create_console, _register_tools) are implemented.
  • The import response (UI status banner or CLI output) lists per-agent errors under errors[] — check those first.
  • Confirm each agent directory in the bundle contains an agent.py at its root. Bundles missing agent.py are rejected.
  • If requires_restart: true is reported, restart the GAIA server to pick up the new agent.
  • Bundles produced on a different GAIA version may reference imports that don’t exist locally — check the server logs for ImportError.
  • Ensure npx or the MCP server command is installed and accessible in $PATH.
  • Check the server logs for MCP connection errors.
  • Test the MCP server standalone before adding it to your agent.
If your preferred model isn’t loaded on the Lemonade server, GAIA falls back to the server default. Run gaia init to download additional models.

Next Steps

Agent System SDK

Deep dive into the base Agent class, tool registry, and state machine

MCP Integration

Connect any MCP server to extend your agent with external tools

GAIA Connectors

Give your agent permission to read Gmail, GitHub, Slack, and more — without baking API keys into code

RAG SDK

Add document Q&A to your agent with the RAG SDK

Agent UI Guide

Learn about the GAIA Agent UI and how agents are surfaced there

Custom Installer

Ship your agent pre-loaded in a branded, signed GAIA installer