Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .claude/skills/gaia-build-agent/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
name: "gaia-build-agent"
description: "Build a new GAIA agent with the SDK end-to-end: scaffold the package, write the Agent subclass, register @tool functions, compose reusable tool mixins, set the model + system prompt, and test it locally — then hand off to publishing. Use when creating a NEW agent (a Python class inheriting from the base Agent) for the GAIA repo or a user-authored package, not for tuning an existing agent's prompt (prompt-engineer), adding one tool to an existing class (python-developer), or shipping/releasing an already-built agent (use the agent-hub-release skill + docs/guides/hub-publishing.mdx). Pairs with the agent-hub-release skill: this one BUILDS, that one PUBLISHES."
---

# Building a GAIA Agent

How to take an idea to a working, testable GAIA agent — a Python class that runs
locally on AI PCs. This skill covers **build**; publishing is its sibling
[`agent-hub-release`](../agent-hub-release/SKILL.md) skill and the author guide
[`docs/guides/hub-publishing.mdx`](../../../docs/guides/hub-publishing.mdx). The
full prose walkthrough is [`docs/guides/custom-agent.mdx`](../../../docs/guides/custom-agent.mdx).

> Read [`CLAUDE.md`](../../../CLAUDE.md) first — the "No Silent Fallbacks", code-reuse,
> testing, and eval rules all apply to a new agent.

## The mental model

A GAIA agent is **one Python class** that inherits from the base `Agent`
(`src/gaia/agents/base/agent.py`) and exposes capabilities as `@tool`-decorated
methods. The base class owns the agent loop, tool registry, state, error recovery,
and (via mixins) MCP / OpenAI-API exposure — you write the prompt + the tools, not
the plumbing. There are no YAML agent manifests for in-core agents (removed in
v0.17.5); a *publishable hub package* adds a `gaia-agent.yaml` manifest on top (see
the publish skill).

## Steps

1. **Scaffold.** `gaia agent init my-agent` generates a starter package. For a
publishable hub package, scaffold into the hub tree —
`gaia agent init <id> -o hub/agents/python/` — and mirror an existing one
(e.g. `analyst`, `browser`).

2. **Write the `Agent` subclass.** Inherit from `Agent` (or a closer base like the
chat/docqa agents). Set the model with `model_id` — omit it only if the
`Qwen3.5-35B-A3B-GGUF` base default is right; chat-style agents use
`Gemma-4-E4B-it-GGUF` (`DEFAULT_MODEL_NAME`). Keep the constructor thin.

3. **Register tools with `@tool`.** Each `@tool` method is a capability the LLM can
call; its **docstring is the schema the model sees**, so write it for the model
(one line of intent + each arg). Return structured data or an actionable error —
never swallow exceptions into a placeholder (No Silent Fallbacks).

4. **Reuse, don't reinvent — compose mixins.** Before writing file/web/RAG/shell/SQL
logic, check `KNOWN_TOOLS` in [`src/gaia/agents/registry.py`](../../../src/gaia/agents/registry.py):
`rag`, `file_io`, `file_search`, `shell`, `browser`, `scratchpad`, `code_index`,
`vlm`, `sd`, … Compose them by name instead of duplicating. New shared logic →
add a mixin and register it in `KNOWN_TOOLS`.

5. **System prompt.** Implement `_get_system_prompt()` — state the agent's job, when
to use which tool, and the output contract. This is an LLM-affecting surface, so
it's covered by the eval rule below.

6. **Make it discoverable.** An **in-core** agent is added to
[`src/gaia/agents/registry.py`](../../../src/gaia/agents/registry.py) (and a
`gaia <cmd>` subparser in `src/gaia/cli.py` if it's a CLI command). A **hub
package** is **auto-discovered from its `gaia-agent.yaml` manifest** — no
`registry.py` edit; just make sure the manifest's `python.entry_module` /
`entry_class` point at your class.

7. **Test it — actually run it.** Unit tests with a mocked LLM for tool logic
(`tests/`), then run the **real CLI** a user would (`gaia <cmd> ...` or
`python my_agent.py`) — never only the Python module. Follow the
[`gaia-testing`](../gaia-testing/SKILL.md) skill for real-world evidence.

8. **Eval if it touches LLM behavior.** If you wrote/changed a system prompt, tool
docstrings, the tool schema, the model, or error classification, you MUST run
`gaia eval agent` against the relevant category and compare to the committed
baseline before calling it done (CLAUDE.md eval rule). Unit tests don't catch LLM
regressions.

## Then publish

Once it runs and is documented (README/SPEC/SKILL per the doc-sync rule), ship it:

- **Standard wheel → Hub + PyPI** (PR route, no token): the
[`hub-publishing.mdx`](../../../docs/guides/hub-publishing.mdx) guide.
- **Frozen-binary + npm sidecar** (like the email agent): the
[`agent-hub-release`](../agent-hub-release/SKILL.md) skill.

## Reference

- [`docs/guides/custom-agent.mdx`](../../../docs/guides/custom-agent.mdx) — the full build walkthrough.
- [`src/gaia/agents/base/`](../../../src/gaia/agents/base/) — `Agent`, `MCPAgent`, `ApiAgent`, `@tool`, console, errors.
- [`src/gaia/agents/registry.py`](../../../src/gaia/agents/registry.py) — agent registry + `KNOWN_TOOLS`.
- The `gaia-agent-builder` agent (`.claude/agents/`) — a specialist for this work.
54 changes: 54 additions & 0 deletions docs/guides/custom-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ Custom agents can have their own:
- **MCP servers** (any Model Context Protocol server)
- **Connectors** ([Google, GitHub, and more](/connectors)) — give your agent permission to read your real email, calendar, repos, etc.

<Note>
This guide builds a **local** custom agent in `~/.gaia/agents/` for your own Agent UI.
When it's ready to **share** — so anyone can install it from the [Agent Hub](https://amd-gaia.ai/hub) —
jump to [Publish and share your agent](#publish-and-share-your-agent).
</Note>

<Tip>
**Using Claude Code in the GAIA repo?** Invoke the **`gaia-build-agent`** skill — it
walks scaffolding → tools → model → test end-to-end, then hands off to the
**`agent-hub-release`** skill for shipping.
</Tip>

---

## Quick Start: Gaia Builder Agent
Expand Down Expand Up @@ -389,6 +401,48 @@ The UI endpoints (`POST /api/agents/export` and `POST /api/agents/import`) are l

---

## Publish and share your agent

The agent you built lives in `~/.gaia/agents/` — yours, on your machine. To let
**anyone install it** from the [Agent Hub](https://amd-gaia.ai/hub) (and PyPI/npm), package it as a hub
agent and publish it through the curated PR route:

<Steps>
<Step title="Package it">
`gaia agent init <id>` scaffolds a publishable package under
`hub/agents/python/<id>/` — a `gaia-agent.yaml` manifest, your agent code, a
README, and `pyproject.toml`. Move your `agent.py` logic in and fill the manifest.
</Step>
<Step title="Validate it">
`gaia agent test --lint` checks the manifest and that the agent loads. Add tests
and a README — both are required for review.
</Step>
<Step title="Open a PR">
Commit the package under `hub/agents/python/<id>/` and open a PR to
[`amd/gaia`](https://github.com/amd/gaia). The **PR route needs no token** —
maintainers review, and the automated pipeline publishes it to the Hub + PyPI on
merge. (A direct-publish token route exists too, for maintainers.)
</Step>
</Steps>

**What's required:** a valid manifest, a README, tests, and passing review. The full
contract — manifest fields, the four package parts, versioning + immutability, and
both publish routes — is in the publishing guide.

<CardGroup cols={2}>
<Card title="Publishing guide → Hub + PyPI" icon="upload" href="/guides/hub-publishing">
The complete walkthrough: package layout, manifest, the no-token PR route vs
direct token publish, requirements, and verification.
</Card>
<Card title="Claude Code skills" icon="robot" href="https://github.com/amd/gaia/tree/main/.claude/skills">
In the GAIA repo, the **`gaia-build-agent`** skill builds and the
**`agent-hub-release`** skill cuts a frozen-binary + npm sidecar release (like the
email agent). Invoke them with the Skill tool.
</Card>
</CardGroup>

---

## Next Steps

<CardGroup cols={2}>
Expand Down
8 changes: 8 additions & 0 deletions docs/guides/hub-publishing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ Publishing your agent to the Hub does two things:
This guide takes you from an empty folder to a published agent, and then shows how
to ship updates. No prior packaging experience assumed.

<Tip>
**New to building agents?** Start with [Custom Agents](/guides/custom-agent) to
write the agent itself, then come back here to publish it. **Using Claude Code in
the GAIA repo?** The **`gaia-build-agent`** skill builds and the
**`agent-hub-release`** skill cuts a frozen-binary + npm sidecar release (like the
email agent) — invoke them with the Skill tool.
</Tip>

## Two ways to publish

To publish to the Hub you normally need a **publish token** — a secret credential
Expand Down
75 changes: 46 additions & 29 deletions website/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,38 @@ const featured = agents.filter((a) => !a.deprecated).slice(0, 3);
const DOCS = 'https://amd-gaia.ai/docs';
const QUICKSTART = `${DOCS}/quickstart`;

// The factory pipeline — the spine of the page.
const pipeline = [
// The three ways to use GAIA, easiest → hardest. Equal billing — each is a real
// front door, not a funnel step.
const paths = [
{
step: 'Build',
icon: 'wrench',
body: 'Write an agent in a few dozen lines of Python — a system prompt and a few @tool functions. Reuse built-in toolsets, or scaffold a new package with one command.',
code: 'gaia agent init my-agent',
},
{
step: 'Run',
n: '01',
level: 'No code',
icon: 'cpu',
body: 'It runs locally on AI PCs — AMD Ryzen AI first-class, via Lemonade. Private by default, no API keys required; cloud models are opt-in.',
code: 'python my_agent.py',
title: 'Run agents',
body: 'Install the Agent UI desktop app, pick an agent from the Hub, and go — a local AI that sees your files and never calls the cloud.',
code: 'npm install -g @amd-gaia/agent-ui',
cta: { label: 'Get the Agent UI', href: `${DOCS}/guides/agent-ui` },
secondary: { label: 'Browse agents →', href: '/hub' },
},
{
step: 'Distribute',
n: '02',
level: 'Integrate',
icon: 'package',
badge: 'Coming soon',
body: 'Publish to the Agent Hub — versioned, checksummed, immutable. Users install in one click, or one command. Distribute openly on PyPI and npm too.',
code: 'gaia agent publish',
title: 'Embed agents in your app',
body: 'Drop a published agent into your own product — a local REST sidecar, an MCP server, or the OpenAI-compatible API. No Python for your users.',
code: 'npm i @amd-gaia/agent-email',
cta: { label: 'Browse the Agent Hub', href: '/hub' },
secondary: { label: 'Integration SDK →', href: `${DOCS}/sdk` },
},
{
n: '03',
level: 'Build',
icon: 'wrench',
title: 'Build & publish your own',
body: 'Write an agent with the SDK in a few dozen lines of Python, then publish it to the Hub via a PR so anyone can install it.',
code: 'gaia agent init my-agent',
cta: { label: 'Build & publish guide', href: `${DOCS}/guides/custom-agent` },
secondary: { label: 'Publishing →', href: `${DOCS}/guides/hub-publishing` },
},
];

Expand Down Expand Up @@ -99,27 +111,32 @@ const sidecar = await startSidecar({ binaryPath, port: 8131 });`;
</div>
</section>

<!-- 2. The pipeline: Build → Run → Distribute -->
<!-- 2. Three ways to use GAIA — equal front doors, easiest → hardest -->
<section class="max-w-6xl mx-auto px-6 py-24">
<div class="text-center mb-12">
<Eyebrow class="mb-3">The factory floor</Eyebrow>
<h2 class="text-2xl sm:text-3xl font-bold tracking-tight">Build → Run → Distribute.</h2>
<p class="mt-3 text-g-muted max-w-xl mx-auto">From an idea to an installable agent — entirely on local hardware.</p>
<Eyebrow class="mb-3">Three ways to use GAIA</Eyebrow>
<h2 class="text-2xl sm:text-3xl font-bold tracking-tight">Run it, integrate it, or build it.</h2>
<p class="mt-3 text-g-muted max-w-xl mx-auto">Pick your level — from a one-click desktop app to building and publishing your own agent. All local, all private.</p>
</div>
<div class="grid md:grid-cols-3 gap-5">
{pipeline.map((p) => (
<div class="rounded-xl border border-g-border bg-g-surface p-6">
<span class="flex w-10 h-10 rounded-lg border border-g-border items-center justify-center text-g-gold-text">
<AgentIcon name={p.icon} class="w-5 h-5" />
</span>
<div class="mt-4 flex items-center gap-2">
<h3 class="text-lg font-semibold text-g-text">{p.step}</h3>
{p.badge && (
<span class="rounded border border-g-border px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-g-muted">{p.badge}</span>
)}
{paths.map((p) => (
<div class="flex flex-col rounded-xl border border-g-border bg-g-surface p-6">
<div class="flex items-center justify-between">
<span class="flex w-10 h-10 rounded-lg border border-g-border items-center justify-center text-g-gold-text">
<AgentIcon name={p.icon} class="w-5 h-5" />
</span>
<span class="font-mono text-[12px] text-g-muted">{p.n}</span>
</div>
<div class="mt-4 text-[11px] font-bold uppercase tracking-wide text-g-gold-text">{p.level}</div>
<h3 class="mt-1 text-lg font-semibold text-g-text">{p.title}</h3>
<p class="mt-2 text-[14px] text-g-muted leading-relaxed">{p.body}</p>
<CodeBlock code={p.code} lang="bash" class="mt-4" />
<div class="mt-auto pt-5 flex flex-wrap items-center gap-x-4 gap-y-2">
<a href={p.cta.href} class="rounded-md bg-g-gold px-4 py-2 text-[13px] font-semibold text-black hover:brightness-110 transition">
{p.cta.label}
</a>
<a href={p.secondary.href} class="text-[13px] font-medium text-g-gold-text hover:underline">{p.secondary.label}</a>
</div>
</div>
))}
</div>
Expand Down
Loading