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 registers automatically and is listed by the Agent UI backend’s GET /api/agents. 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.
This guide builds a local custom agent in ~/.gaia/agents/ for your own Agent UI.
Using Claude Code in the GAIA repo? Invoke the gaia-build-agent skill — it walks scaffolding → tools → model → test end-to-end.

Python Agent

A custom agent is a Python module — add custom tools, built-in tool mixins, MCP servers, or any logic you need.

Directory structure

Minimal Python agent

The only method a subclass must implement is _register_tools() (it’s abstract on the base Agent); the other two have sensible defaults you can override:

Adding built-in tools

GAIA ships with ready-to-use tool mixins. To enable most of them, inherit the mixin and call its register_*_tools() method from _register_tools(). The sd and vlm mixins are the exception — call init_sd() / init_vlm() (which set up the client and register the tools in one step):
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__():
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 with the gaia agent export and gaia agent import CLI commands. Exports include every ~/.gaia/agents/* directory with an agent.py — the installer-seeded bundled example included; imported copies land as user-owned agents the seeder never touches.
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:
Bundles are validated on import. The receiving end enforces conservative limits (max 1000 entries, 500 MB uncompressed, 50 MB per file) and rejects symlinks, device or other special files, and 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. gaia agent import (without --yes) lists the agent IDs and requires explicit confirmation before installing. Only import bundles from sources you trust.

Examples

RAGToolsMixin and FileSearchToolsMixin read state off the host agent — self.rag, self.indexed_files, self.max_chunks, self.current_session, self.session_manager — that nothing sets by default, so the agent must wire it up itself (see the RAG tools mixin contract for what each attribute is for). Pass documents pointing at wherever your documents actually live; the example never widens access beyond that.
FileIOToolsMixin reads self.path_validator off the host agent, which nothing sets by default, so the agent wires it up itself. Pass documents pointing at wherever the code to review actually lives — an unset PathValidator only allows the current directory, never widen it to a filesystem root or the home directory.

Why a custom RAG agent can’t see the Document Library

A custom agent’s documents list only ever contains what the caller passes in — not the Agent UI’s Document Library. If you index a folder of PDFs through the Library panel, then run a custom agent like ResearchAgent above with no documents argument, query_documents will honestly report "No documents are currently indexed" even though the Library shows them. That’s expected, not a bug — here’s why. The Agent UI passes each conversation only the documents explicitly attached to it (internally, the rag_documents list), never the whole Library. This is deliberate: earlier versions exposed every library document to every agent, which meant one session’s documents could leak into an unrelated session’s answers. If a session has no documents attached, rag_documents comes through empty — not the library — so you have to index what you want your custom agent to see. There’s also no persistent, shared vector index an agent can just attach to. The Document Library is file metadata plus files on disk; it caches extracted text per file so re-indexing skips redundant parsing, but the FAISS index itself is built in memory, per agent instance, from whatever paths that instance was constructed with — nothing is written to or read from disk as a vector index, and nothing carries over between agents. The flow that works: call index_document or index_directory (both from RAGToolsMixin) once your agent is constructed, then query. That’s the same index-then-query sequence the built-in agents use — there’s no shortcut that skips indexing.

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 ....
  • After adding or editing the agent, restart the GAIA server — discovery runs at boot.
Check the server logs for load errors. Ensure AGENT_ID, AGENT_NAME, and AGENT_DESCRIPTION are set as class attributes, and that the required _register_tools() method is implemented (_get_system_prompt() and _create_console() are optional overrides).
  • gaia agent import prints per-agent errors after Errors: — check those first.
  • Confirm each agent directory in the bundle contains an agent.py at its root. Bundles missing agent.py are rejected.
  • Restart the GAIA server so discovery picks up the imported agents.
  • 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