Skip to content

A2A team directory: unified, queryable agent discovery + publish @relaycast/a2a as the shared card contract #294

Description

@khaliqgant

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.tsPOST /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.tsGET/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

  • @relaycast/a2a is importable by external repos as the canonical card schema; README/openapi note it as the shared contract.
  • New directory endpoint returns native + registered A2A agents in one response with skills/tags/url/kind/status.
  • Skill/tag/text filter returns only matching agents; empty match returns [], not an error.
  • README.md + openapi.yaml updated (repo rule: keep them aligned).
  • Unit tests: directory merges both sources; filter narrows correctly.

✅ 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 e2escripts/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:

  1. Create a native relay agent (with a persona/skills) in a workspace.
  2. POST /v1/a2a/register an external A2A agent card (skills e.g. ["infra-watch"]).
  3. GET /v1/a2a/directory → assert both appear, each with skills, url, kind (native vs a2a), status.
  4. GET /v1/a2a/directory?skill=infra-watch → assert only the matching agent(s) return; a bogus ?skill=nope[].
  5. 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

  • A checked-in E2E (in/beside scripts/e2e.ts) that runs steps 1–5 against a booted gateway with a single command, asserting directory contents, filter behavior, and a successful message/send to a discovered agent.
  • The E2E fails if the directory endpoint or filter is removed (no false green).

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions