Part of the cross-repo epic #2785. This is the consumer issue — the one that makes the ecosystem come alive. Depends on the directory from relaycast#294 and the shared card contract from workforce#296.
Why
The Factory turns issues into reviewed PRs by spawning worker agents. Today, when a worker hits a question it can't answer, it has nowhere to turn — Factory only discovers fleet nodes/capabilities for placement (FleetClient.roster()), not agents by skill, and there's no path to actually ask another agent. Once every proactive agent publishes an A2A card and registers with the Relaycast directory, a Factory worker should be able to: "who can answer X?" → pick an agent by its card skills → send it the question and get a reply.
What
1. Directory-backed peer discovery
Add a card-aware lookup alongside roster() in FleetClient (src/ports/fleet.ts), implemented in RelayFleetClient (src/fleet/relay-fleet-client.ts) — query Relaycast's GET /v1/a2a/directory filtered by skill/tag, returning { name, skills[], url, kind } per candidate. Optionally cache via an in-package index like RelayflowPolicyRegistry (src/dispatch/relayflow-registry.ts).
2. "Ask a teammate" capability
Give a running worker a way to engage a discovered peer: resolve target via #1, then send over Relaycast — A2A POST /a2a/rpc message/send or the broker seam (FleetClient.sendMessage/waitForInjected/onAgentMessage). Reuse the existing DM/relay path; don't invent a new transport. Surface it as a discrete capability/tool the worker invokes mid-task, with a bounded wait for the reply.
3. Publish cards for factory-hosted personas
Generate an A2A card for factory-hosted personas (e.g. .agentworkforce/agents/factory-feature-guardian/persona.json) via @agentworkforce/persona-kit deriveAgentCard ([workforce#296]) and publish it when the persona-backed node comes online — createFactoryNodeDefinition (src/node/factory-node.ts) already assembles capabilities/tags/metadata and calls defineNode. Export the new surface from src/index.ts.
Acceptance
✅ End-to-end verification — Factory success criteria (REQUIRED)
This issue IS the "does the ecosystem come alive?" proof. "Compiles" is nowhere near done — the Factory must run a real discover → ask → reply round trip and observe the reply arrive, then check the harness in. Use agent-relay's in-process broker so this runs locally with no external services (src/fleet/internal-fleet-client.ts, src/fleet/ensure-relay-broker.ts).
Run it
npm run build
npm test # vitest run (add the E2E below)
The E2E (test/e2e/ask-a-teammate.test.ts, runnable via npm test) must:
- Stand up a local directory (mock the Relaycast
/v1/a2a/directory HTTP response, or seed the in-process broker) with two agents whose cards declare distinct skills (e.g. ["infra-watch"], ["code-review"]).
- Call the new Factory discovery method with
skill: "infra-watch" → assert it returns only the infra agent, with an address to reach it.
- Stand up a stub teammate agent on the in-process broker (
InternalFleetClient + ensureRelayBroker) that replies to an inbound question with a canned answer.
- From a simulated worker, invoke the new "ask a teammate" capability against the discovered agent → assert the question is delivered and the canned reply is received within the bounded wait.
- For persona cards: bring a factory-hosted persona node online via
createFactoryNodeDefinition, then assert its deriveAgentCard-derived card was published/registered and shows up in the directory lookup from step 2.
Observe (must pass)
- Discovery returns the right agent for a skill and
[] for an unknown skill.
- The worker actually receives the teammate's reply over the relay path (the round trip completes, not just "message sent").
- A factory-hosted persona is discoverable by its skill after its node comes online.
Deliverable
Anchor files
src/ports/fleet.ts (FleetClient, RosterEntry, sendMessage/waitForInjected/onAgentMessage)
src/fleet/relay-fleet-client.ts, src/fleet/internal-fleet-client.ts, src/fleet/ensure-relay-broker.ts
src/dispatch/relayflow-registry.ts (in-package registry precedent)
src/node/factory-node.ts (createFactoryNodeDefinition), src/index.ts (public barrel)
.agentworkforce/agents/factory-feature-guardian/persona.json (proto card / template)
planning/linear-issue-cloud-proactive-runtime-fleet-unification.md, planning/factory-unified-node-architecture-linear-issue.md
Part of the cross-repo epic #2785. This is the consumer issue — the one that makes the ecosystem come alive. Depends on the directory from relaycast#294 and the shared card contract from workforce#296.
Why
The Factory turns issues into reviewed PRs by spawning worker agents. Today, when a worker hits a question it can't answer, it has nowhere to turn — Factory only discovers fleet nodes/capabilities for placement (
FleetClient.roster()), not agents by skill, and there's no path to actually ask another agent. Once every proactive agent publishes an A2A card and registers with the Relaycast directory, a Factory worker should be able to: "who can answer X?" → pick an agent by its card skills → send it the question and get a reply.What
1. Directory-backed peer discovery
Add a card-aware lookup alongside
roster()inFleetClient(src/ports/fleet.ts), implemented inRelayFleetClient(src/fleet/relay-fleet-client.ts) — query Relaycast'sGET /v1/a2a/directoryfiltered by skill/tag, returning{ name, skills[], url, kind }per candidate. Optionally cache via an in-package index likeRelayflowPolicyRegistry(src/dispatch/relayflow-registry.ts).2. "Ask a teammate" capability
Give a running worker a way to engage a discovered peer: resolve target via #1, then send over Relaycast — A2A
POST /a2a/rpcmessage/sendor the broker seam (FleetClient.sendMessage/waitForInjected/onAgentMessage). Reuse the existing DM/relay path; don't invent a new transport. Surface it as a discrete capability/tool the worker invokes mid-task, with a bounded wait for the reply.3. Publish cards for factory-hosted personas
Generate an A2A card for factory-hosted personas (e.g.
.agentworkforce/agents/factory-feature-guardian/persona.json) via@agentworkforce/persona-kitderiveAgentCard([workforce#296]) and publish it when the persona-backed node comes online —createFactoryNodeDefinition(src/node/factory-node.ts) already assembles capabilities/tags/metadata and callsdefineNode. Export the new surface fromsrc/index.ts.Acceptance
FleetClientmethod returns teammate agents matching a skill/tag from the Relaycast directory (with how to reach each).deriveAgentCard-derived card when their node comes online; they appear in the directory.src/index.ts; card schema consumed from@relaycast/a2a(no hand-rolled shape).✅ End-to-end verification — Factory success criteria (REQUIRED)
This issue IS the "does the ecosystem come alive?" proof. "Compiles" is nowhere near done — the Factory must run a real discover → ask → reply round trip and observe the reply arrive, then check the harness in. Use
agent-relay's in-process broker so this runs locally with no external services (src/fleet/internal-fleet-client.ts,src/fleet/ensure-relay-broker.ts).Run it
The E2E (
test/e2e/ask-a-teammate.test.ts, runnable vianpm test) must:/v1/a2a/directoryHTTP response, or seed the in-process broker) with two agents whose cards declare distinct skills (e.g.["infra-watch"],["code-review"]).skill: "infra-watch"→ assert it returns only the infra agent, with an address to reach it.InternalFleetClient+ensureRelayBroker) that replies to an inbound question with a canned answer.createFactoryNodeDefinition, then assert itsderiveAgentCard-derived card was published/registered and shows up in the directory lookup from step 2.Observe (must pass)
[]for an unknown skill.Deliverable
test/e2e/ask-a-teammate.test.tsrunning the full discover→ask→reply round trip against the in-process broker + mock directory, one command (npm test).Anchor files
src/ports/fleet.ts(FleetClient,RosterEntry,sendMessage/waitForInjected/onAgentMessage)src/fleet/relay-fleet-client.ts,src/fleet/internal-fleet-client.ts,src/fleet/ensure-relay-broker.tssrc/dispatch/relayflow-registry.ts(in-package registry precedent)src/node/factory-node.ts(createFactoryNodeDefinition),src/index.ts(public barrel).agentworkforce/agents/factory-feature-guardian/persona.json(proto card / template)planning/linear-issue-cloud-proactive-runtime-fleet-unification.md,planning/factory-unified-node-architecture-linear-issue.md