Skip to main content
Tracking issue: #1102 · Milestone: v0.22.0 — Agent Hub Platform [OSS] · Status: In Progress

Migration status

Step 1 (mixin promotion) and the registry’s installed-agent discovery are landed. Production agents are migrating to hub/agents/<id>/python/ in batches. The pending set is deferred because of deeper coupling: chat/doc/file sit on the Agent UI hot path (13+ callsites), email has a large API/MCP/eval surface, coderouting are interdependent, and docqa depends on chat.tools. They migrate once their callsites are rewired through the registry. gaia-code stays as a core console script until code moves. Migrated agents install as standalone wheels (pip install gaia-agent-<id> or pip install -e hub/agents/<id>/python) and are discovered via the gaia.agent entry-point group. The core amd-gaia wheel no longer ships them; in-core callsites lazy-import each agent and fail loudly when the wheel is absent.

Problem

Production agents (chat, code, jira, blender, etc.) currently live inside src/gaia/agents/ and ship as part of the core amd-gaia wheel. This couples every agent to the framework’s release cycle, prevents independent versioning, and gives third-party contributors no pattern to follow — their agents would have to live inside the AMD source tree.

Goal

Move production agents to hub/agents/ as standalone packages that depend on the published amd-gaia PyPI package — not the source tree. The core wheel ships only the framework. Third-party contributors follow the identical pattern AMD uses for its own agents.

Key Decisions

  1. Framework-only core wheel. pip install amd-gaia provides Agent, @tool, MCPAgent, AgentConsole, registry, LLM clients, RAG, MCP. No production agents.
  2. Agents are separate wheels. gaia-agent-chat, gaia-agent-jira, gaia-agent-code, etc. — installable via gaia agent install <id>, pip install gaia-agent-{id}, or amd-gaia[agents] for all of them. One wheel per codebase, not per registry ID: the chat package ships multiple prompt profiles (doc, file, data, web) and model presets (lite variants) selectable via config — they are not separate wheels (see #1162).
  3. Shared tool mixins promoted to framework. RAG, FileIO, Shell, CodeIndex mixins move into src/gaia/agents/tools/ so agents don’t depend on each other for tools.
  4. Entry-point discovery. Agents register via the gaia.agent entry point group. The registry discovers installed agent wheels at startup — no hardcoded agent list.
  5. Framework-provided generic server. src/gaia/agents/base/server.py wraps any Agent into an OpenAI-compatible REST API + MCP stdio server. Agents don’t implement server logic.
  6. Inherited init. An agent declares what it needs — a model id, a minimum backend version — and the framework serves GET/POST /v1/<id>/init for it. Agents don’t hand-write readiness or provisioning endpoints. See Inherited init.

Pre-requisite: Promote shared tool mixins

The current codebase has cross-agent tool dependencies that block independent packaging: After promotion, every KNOWN_TOOLS entry in registry.py points to gaia.agents.tools.*. No agent-specific tool paths remain. Old paths get deprecated re-exports for backward compatibility.

Package Format

gaia-agent.yaml

Non-agent packages

Not every hub package is an agent. type discriminates them, and two ship today: Their manifests live in hub/components/<id>/gaia-agent.yaml and publish through the same POST /publish path as an agent — release_components.yml builds (or collects) the per-platform artifacts and posts them with the manifest. Both host or drive agents rather than being one, so they declare tools_count: 0 and no models. A catalog consumer that lists agents must filter on type; treating every entry as an agent would offer gaia agent install terminal-hub, which is not how either is installed.

The skills lane

skill is a fourth type (#2467) — a reusable capability any agent composes, not a package that runs on its own. It is the one lane that is not published from a gaia-agent.yaml: a skill’s manifest is the YAML front matter of its SKILL.md (Skill Format), so it goes to POST /publish/skill instead, and a gaia-agent.yaml that declares type: skill is rejected with a pointer to that route. Skill artifacts live under their own R2 prefix (skills/<name>/…) and are served at GET /skills/<name>/manifest.json. Everything else is shared: skills appear in the same index.json agents array, carry the same security_tier / permissions keys, and are versioned and made immutable by the same rules. Ids are one namespace across every lane — a skill may not shadow an agent id, and vice versa (409 id_conflict). The same filtering rule applies, harder: a skill installs with gaia skill install <name> into ~/.gaia/skills/, so a consumer that renders every entry as an installable agent would offer an install path that cannot work.

pyproject.toml

Agents with cross-agent dependencies (e.g. RoutingAgent uses CodeAgent) declare them as package dependencies: dependencies = ["amd-gaia>=0.18.0", "gaia-agent-code>=0.1.0"].

Inherited init

An agent that needs a model before it can answer anything should not have to hand-write a readiness endpoint to say so. It declares the requirement and AgentServer serves both verbs at /v1/<id>/init: Declare requirements in gaia-agent.yaml (models: and requirements.min_lemonade_version), or pass them explicitly:
An agent that declares nothing gets no init routes — a readiness endpoint that reports “ready” without having checked anything is worse than a 404, because a consumer would trust it.

Where the boundary sits

Inherited init makes this agent’s requirements ready: its model, against a backend that is already running. Installing the backend stays with gaia init. An agent process cannot bootstrap the server it depends on, so when Lemonade is unreachable both verbs fail loudly and name whose job the fix is rather than hanging or half-succeeding:

Reading a provisioning result

Once a streamed 200 is committed the HTTP status can no longer change, so a pull that fails half-way still arrives as 200 OK. The final line is the verdict success, failure, succeeded-but-unverified. Consumers must read it rather than the status code; the TUI’s preflight gate (tui/internal/ui/preflight) already does. Two distinctions the contract preserves deliberately, because each has a different remedy:
  • “Could not tell” is not “missing.” If the backend answers /health but its model list cannot be read, present:false means unknown — reporting it as missing would send the user to re-download a model they may already have.
  • Indeterminate is not a pass. A backend that advertises no version yields compatible: null, never true.

Implementation Steps

1

Promote shared tool mixins (#1396)

Move RAG, FileIO, Shell, CodeIndex mixins to src/gaia/agents/tools/. Update all imports and KNOWN_TOOLS. Add deprecated re-exports. Run full test suite — no behavior change.
2

Create agent package skeletons

For each of the 16 agents, create hub/agents/{id}/python/ with gaia-agent.yaml, pyproject.toml, gaia_agent_{id}/ package dir, tests/, and README.md.
3

Move first agent (summarize)

Start with summarize — simplest, fewest dependencies. Proves the pattern end-to-end before bulk migration.
4

Move remaining agents in batches

Migrate the other 15 agents. Rewrite internal imports (gaia.agents.{name}gaia_agent_{name}). Framework imports stay. Cross-agent deps become package deps.
5

Strip the core wheel

Remove agent packages from setup.py. Remove gaia-emr/gaia-code console scripts. Add amd-gaia[agents] and per-agent extras.
6

Update the registry

_register_builtin_agents() keeps only builder. Add _discover_installed_agents() using the gaia.agent entry point group.
7

Update CLI / UI / API callsites

Replace ~16 direct agent imports in cli.py, ui/_chat_helpers.py, ui/agent_loop.py, and apps with registry.create_agent(id).
8

Add framework generic server

src/gaia/agents/base/server.py wraps any Agent into REST API + MCP server. Enables gaia agent run <id> --api and --mcp, and serves the agent’s inherited init routes.
9

Add CI/CD workflow

.github/workflows/build_agents.yml matrix-builds the C++ agent binaries; .github/workflows/publish_agents.yml matrix-builds every Python agent wheel (matrix derived from setup.py’s agents extra via util/list_agent_packages.py) and publishes it to PyPI on a v* tag using pypa/gh-action-pypi-publish with skip-existing: true (PyPI-native version immutability). R2 publishing is handled at author time by gaia agent publish.
10

Relocate tests

Move agent-specific tests to hub/agents/{id}/python/tests/. Framework tests stay in tests/.

Legacy Agent Modernization

Several agents predate the Agent UI and the connectors framework. They work only via standalone CLI/app entry points, aren’t in the registry, lack the modern class attributes, and have no web UI presence. Moving them to hub/agents/ is not enough — they must also be modernized to the Agent Hub package standard. Modernization per legacy agent (tracked in #1397):
  1. Add modern class attributes: AGENT_ID, AGENT_NAME, AGENT_DESCRIPTION, CONVERSATION_STARTERS, and REQUIRED_CONNECTORS where applicable (e.g. jira → Atlassian OAuth).
  2. Author the gaia-agent.yaml manifest (category, icon, tags, requirements, interfaces) so the agent renders as a Hub card.
  3. Register via the gaia.agent entry point — discoverable in the web UI, not just standalone CLI.
  4. Adopt the conversational/streaming response mode so the agent works in the chat surface.
  5. Keep the standalone CLI/app as a thin wrapper over the registry-created agent (no duplicate logic).
  6. docker inherits MCPAgent — confirm it composes with the framework server (Step 8) or document why it diverges.
Not modernized: routing stays a utility dispatcher (not user-discoverable). docqa/fileio/summarize are example/building-block agents — summarize becomes the migration pilot (Step 3); docqa/fileio may collapse into the chat profiles (see #1162).

Cross-Agent Dependencies

The exploration found these agent-to-agent couplings that must be resolved:

Risks

Verification

  • Agent Hub UI — the display + distribution platform plan
  • Agent Hub — original hub vision
  • #1091gaia-agent.yaml manifest parser (unblocked by this restructure)
  • #1162 — consolidate regular/lite agent variants