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 tohub/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, code↔routing 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 insidesrc/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 tohub/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
- Framework-only core wheel.
pip install amd-gaiaprovidesAgent,@tool,MCPAgent,AgentConsole, registry, LLM clients, RAG, MCP. No production agents. - Agents are separate wheels.
gaia-agent-chat,gaia-agent-jira,gaia-agent-code, etc. — installable viagaia agent install <id>,pip install gaia-agent-{id}, oramd-gaia[agents]for all of them. One wheel per codebase, not per registry ID: thechatpackage ships multiple prompt profiles (doc,file,data,web) and model presets (lite variants) selectable via config — they are not separate wheels (see #1162). - 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. - Entry-point discovery. Agents register via the
gaia.agententry point group. The registry discovers installed agent wheels at startup — no hardcoded agent list. - Framework-provided generic server.
src/gaia/agents/base/server.pywraps any Agent into an OpenAI-compatible REST API + MCP stdio server. Agents don’t implement server logic. - Inherited init. An agent declares what it needs — a model id, a minimum backend version — and the framework serves
GET/POST /v1/<id>/initfor 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
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 andAgentServer serves both verbs at /v1/<id>/init:
Declare requirements in
gaia-agent.yaml (models: and
requirements.min_lemonade_version), or pass them explicitly:
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 withgaia 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 streamed200 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
/healthbut its model list cannot be read,present:falsemeans 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, nevertrue.
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 tohub/agents/ is not enough — they must also be modernized to the Agent Hub package standard.
Modernization per legacy agent (tracked in #1397):
- Add modern class attributes:
AGENT_ID,AGENT_NAME,AGENT_DESCRIPTION,CONVERSATION_STARTERS, andREQUIRED_CONNECTORSwhere applicable (e.g. jira → Atlassian OAuth). - Author the
gaia-agent.yamlmanifest (category, icon, tags, requirements, interfaces) so the agent renders as a Hub card. - Register via the
gaia.agententry point — discoverable in the web UI, not just standalone CLI. - Adopt the conversational/streaming response mode so the agent works in the chat surface.
- Keep the standalone CLI/app as a thin wrapper over the registry-created agent (no duplicate logic).
dockerinheritsMCPAgent— confirm it composes with the framework server (Step 8) or document why it diverges.
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
Related
- Agent Hub UI — the display + distribution platform plan
- Agent Hub — original hub vision
- #1091 —
gaia-agent.yamlmanifest parser (unblocked by this restructure) - #1162 — consolidate regular/lite agent variants