Part of the cross-repo epic Agent-to-agent discoverability via A2A agent cards. Relaycast is the canonical A2A implementation and the directory/message-bus; this issue makes it the queryable "team directory" that a Factory agent asks "who can I ask?", and confirms @relaycast/a2a as the shared card contract other repos import.
Context (already in place)
@relaycast/a2a — canonical A2aAgentCardSchema.
packages/engine/src/routes/a2a.ts — POST /v1/a2a/register, GET /v1/a2a/agents, GET /v1/a2a/agents/:name/card, POST /a2a/rpc, POST /a2a/webhook/..., workspace GET /.well-known/agent-card.json (builds a card whose skills[] = each workspace agent — see getWorkspaceAgentCard in packages/engine/src/engine/a2a.ts).
packages/engine/src/routes/directory.ts — GET/POST /directory/agents.
- Certification (
/v1/certify) + A2A health (packages/engine/src/engine/a2a-health.ts).
The pieces exist but are split across three surfaces, and none lets a peer agent search agents by skill/capability. A Factory worker needs: given a question/skill, return the agents that can handle it, with how to reach them.
What to build
1. Publish @relaycast/a2a as the shared card contract. Ensure the package is consumable by cloud + nightcto as the sole card-shape source (export schema + types; confirm it's published/versioned, no engine-internal imports).
2. Unified agent directory query. Add a discovery endpoint (e.g. GET /v1/a2a/directory) that returns one list merging native relay workspace agents (from agents, as getWorkspaceAgentCard enumerates) and registered A2A agents (a2a_agents), each entry carrying { name, description, skills[], tags[], url, kind: 'native'|'a2a', status, certification }.
3. Find-by-skill/tag. Support ?skill= / ?tag= / ?q= filtering over the card skills[]/tags.
4. Keep addressing intact. Each entry must include how to engage the agent (the /a2a/rpc message/send target name, or relay DM identity) so discovery → engagement is one hop.
Acceptance
✅ End-to-end verification — Factory success criteria (REQUIRED)
"Compiles" is not done. The Factory must boot the real gateway, register agents, query the directory over HTTP, and message a discovered agent — observing the round trip — then check in the harness that proves it. This repo already has a live E2E harness (npm run e2e → scripts/e2e.ts) that boots the gateway; extend it (or add scripts/e2e-a2a-directory.ts, run via npx tsx).
Run it
turbo test # engine unit suite (includes packages/engine/src/engine/__tests__/a2a.test.ts)
npm run e2e # boots the gateway end-to-end (scripts/e2e.ts)
The E2E must, against the booted gateway:
- Create a native relay agent (with a persona/skills) in a workspace.
POST /v1/a2a/register an external A2A agent card (skills e.g. ["infra-watch"]).
GET /v1/a2a/directory → assert both appear, each with skills, url, kind (native vs a2a), status.
GET /v1/a2a/directory?skill=infra-watch → assert only the matching agent(s) return; a bogus ?skill=nope → [].
POST /a2a/rpc message/send addressed to a discovered agent by its directory identity → assert the message is accepted/delivered (the discover→engage hop actually works).
Observe (must pass — sample)
curl -s $GW/v1/a2a/directory?skill=infra-watch -H "Authorization: Bearer $KEY" | jq '.[].name'
# → includes the registered agent; excludes non-matching agents
Deliverable
Anchor files
packages/a2a/src/index.ts (canonical schema)
packages/engine/src/routes/a2a.ts, packages/engine/src/routes/directory.ts
packages/engine/src/engine/a2a.ts (getWorkspaceAgentCard, listA2aAgents)
packages/engine/src/engine/__tests__/a2a.test.ts, scripts/e2e.ts
README.md, openapi.yaml
Part of the cross-repo epic Agent-to-agent discoverability via A2A agent cards. Relaycast is the canonical A2A implementation and the directory/message-bus; this issue makes it the queryable "team directory" that a Factory agent asks "who can I ask?", and confirms
@relaycast/a2aas the shared card contract other repos import.Context (already in place)
@relaycast/a2a— canonicalA2aAgentCardSchema.packages/engine/src/routes/a2a.ts—POST /v1/a2a/register,GET /v1/a2a/agents,GET /v1/a2a/agents/:name/card,POST /a2a/rpc,POST /a2a/webhook/..., workspaceGET /.well-known/agent-card.json(builds a card whoseskills[]= each workspace agent — seegetWorkspaceAgentCardinpackages/engine/src/engine/a2a.ts).packages/engine/src/routes/directory.ts—GET/POST /directory/agents./v1/certify) + A2A health (packages/engine/src/engine/a2a-health.ts).The pieces exist but are split across three surfaces, and none lets a peer agent search agents by skill/capability. A Factory worker needs: given a question/skill, return the agents that can handle it, with how to reach them.
What to build
1. Publish
@relaycast/a2aas the shared card contract. Ensure the package is consumable by cloud + nightcto as the sole card-shape source (export schema + types; confirm it's published/versioned, no engine-internal imports).2. Unified agent directory query. Add a discovery endpoint (e.g.
GET /v1/a2a/directory) that returns one list merging native relay workspace agents (fromagents, asgetWorkspaceAgentCardenumerates) and registered A2A agents (a2a_agents), each entry carrying{ name, description, skills[], tags[], url, kind: 'native'|'a2a', status, certification }.3. Find-by-skill/tag. Support
?skill=/?tag=/?q=filtering over the cardskills[]/tags.4. Keep addressing intact. Each entry must include how to engage the agent (the
/a2a/rpcmessage/sendtarget name, or relay DM identity) so discovery → engagement is one hop.Acceptance
@relaycast/a2ais importable by external repos as the canonical card schema; README/openapi note it as the shared contract.skills/tags/url/kind/status.[], not an error.README.md+openapi.yamlupdated (repo rule: keep them aligned).✅ End-to-end verification — Factory success criteria (REQUIRED)
"Compiles" is not done. The Factory must boot the real gateway, register agents, query the directory over HTTP, and message a discovered agent — observing the round trip — then check in the harness that proves it. This repo already has a live E2E harness (
npm run e2e→scripts/e2e.ts) that boots the gateway; extend it (or addscripts/e2e-a2a-directory.ts, run vianpx tsx).Run it
The E2E must, against the booted gateway:
POST /v1/a2a/registeran external A2A agent card (skills e.g.["infra-watch"]).GET /v1/a2a/directory→ assert both appear, each withskills,url,kind(nativevsa2a),status.GET /v1/a2a/directory?skill=infra-watch→ assert only the matching agent(s) return; a bogus?skill=nope→[].POST /a2a/rpcmessage/sendaddressed to a discovered agent by its directory identity → assert the message is accepted/delivered (the discover→engage hop actually works).Observe (must pass — sample)
Deliverable
scripts/e2e.ts) that runs steps 1–5 against a booted gateway with a single command, asserting directory contents, filter behavior, and a successfulmessage/sendto a discovered agent.Anchor files
packages/a2a/src/index.ts(canonical schema)packages/engine/src/routes/a2a.ts,packages/engine/src/routes/directory.tspackages/engine/src/engine/a2a.ts(getWorkspaceAgentCard,listA2aAgents)packages/engine/src/engine/__tests__/a2a.test.ts,scripts/e2e.tsREADME.md,openapi.yaml