Remove the nested v3/ subdirectory by moving all active source code, tests, configs, and assets directly to the project root. Archive v2/ (dead code, 847MB) to v2-archive.tar.gz. Key changes: - Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/ - Move v3/tsconfig.json, v3/vitest.config.ts to root - Merge v3/package.json into root package.json (ESM, scripts, deps, exports) - Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/ - Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes - Fix all init installer path resolution (3-level-up → 2-level-up) - Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe" - Update settings.json ADR/DDD directories to docs/implementation/ - Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks) - Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces - Update 15 guidance shards: v3/src/ → src/ path references - Fix sync interfaces: remove v3/ and v2/ path references - Fix test path calculations (process.cwd() + '..' no longer needed) - Fix flaky perf test threshold (500ms → 1000ms for CI environments) - Fix complexity-analyzer test to match ADR-051 keyword-based eligibility Build passes, 17,901 tests pass, CLI and MCP bundles verified. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
19 KiB
ADR-054: A2A Protocol Integration
Status
Implemented | 2026-01-30
Implementation Progress
| Phase | Status | Notes |
|---|---|---|
| Phase 1: Agent Cards | ✅ Complete | 130 tests, schema.ts, generator.ts, validator.ts |
| Phase 2: JSON-RPC 2.0 | ✅ Complete | 125 tests, envelope.ts, methods.ts, errors.ts |
| Phase 3: Discovery | ✅ Complete | 67 unit + 36 integration tests, RFC 8615 /.well-known/agent.json |
| Phase 4: Task Negotiation | ✅ Complete | 101 tests, task-manager.ts, task-router.ts, task-store.ts |
| Phase 5: OAuth 2.0 | ✅ Complete | 184 tests, oauth-provider.ts, middleware.ts, routes.ts |
| Phase 6: Push Notifications | ✅ Complete | 105 tests, webhook-service.ts, subscription-store.ts |
| Phase 7: Dynamic Discovery | ✅ Complete | 192 tests, file-watcher.ts, hot-reload-service.ts |
Test Summary
| Test Suite | Tests | Status |
|---|---|---|
| Agent Cards (schema, generator, validator) | 130 | ✅ Passing |
| JSON-RPC 2.0 (envelope, methods, errors) | 125 | ✅ Passing |
| Discovery Service | 67 | ✅ Passing |
| Discovery Integration | 36 | ✅ Passing |
| Task Negotiation | 101 | ✅ Passing |
| Protocol Flow (AG-UI↔A2A↔A2UI) | 47 | ✅ Passing |
| OAuth 2.0 (provider, store, JWT, scopes, middleware) | 184 | ✅ Passing |
| Push Notifications (webhook, retry, signature, subscription) | 105 | ✅ Passing |
| Dynamic Discovery (file-watcher, hot-reload, health, metrics) | 192 | ✅ Passing |
| Total | 987 | ✅ All Passing |
Files Implemented (~8,100 lines)
v3/src/adapters/a2a/
├── agent-cards/
│ ├── schema.ts (380 lines) - QEAgentCard schema & types
│ ├── generator.ts (528 lines) - Markdown parser → Agent Cards
│ └── validator.ts (596 lines) - A2A spec validation
├── jsonrpc/
│ ├── envelope.ts (538 lines) - JSON-RPC 2.0 request/response
│ ├── methods.ts (441 lines) - A2A method definitions
│ ├── errors.ts (396 lines) - A2A error codes
│ └── index.ts (120 lines) - Barrel exports
├── discovery/
│ ├── discovery-service.ts (520 lines) - Agent discovery & search
│ ├── routes.ts (448 lines) - RFC 8615 well-known routes
│ └── index.ts (45 lines) - Barrel exports
├── tasks/
│ ├── task-manager.ts (772 lines) - Task lifecycle management
│ ├── task-router.ts (806 lines) - Agent routing & load balancing
│ ├── task-store.ts (686 lines) - Task persistence & history
│ └── index.ts (89 lines) - Barrel exports
└── index.ts (418 lines) - Barrel exports
v3/src/mcp/http-server.ts - A2A endpoints integrated
HTTP Endpoints Active
| Endpoint | Method | Purpose |
|---|---|---|
/.well-known/agent.json |
GET | Platform agent card discovery |
/a2a/:agentId/.well-known/agent.json |
GET | Individual agent card |
/a2a/:agentId/card |
GET | Extended card (authenticated) |
/a2a/tasks |
POST | Task submission |
/a2a/tasks/:taskId |
GET | Task status retrieval |
/a2a/tasks/:taskId/cancel |
POST | Task cancellation |
/a2a/tasks/:taskId/subscribe |
GET | Task event subscription (SSE) |
/a2a/tasks |
GET | Task listing with filters |
Context
AQE v3 uses a custom gossip-based coordination protocol for multi-agent communication. While the consensus and coordination systems work well internally, they lack interoperability with external agent ecosystems. The current state:
- Custom message format not aligned with A2A standard
- No agent discovery mechanism for external systems
- Agents lack standardized capability descriptions
- Task lifecycle doesn't follow A2A patterns
Current State (from V3 Status Analysis):
| A2A Requirement | Status | Implementation |
|---|---|---|
| Agent Cards | ✅ Implemented | agent-cards/schema.ts, generator.ts, validator.ts |
| Task Negotiation | ✅ Implemented | tasks/task-manager.ts, task-store.ts, state machine |
| Agent Discovery | ✅ Implemented | /.well-known/agent.json, discovery-service.ts |
| JSON-RPC 2.0 | ✅ Implemented | jsonrpc/envelope.ts, methods.ts, errors.ts |
| Task Router | ✅ Implemented | tasks/task-router.ts - load balancing, skill matching |
| SSE Streaming | ✅ Implemented | Task subscription at /a2a/tasks/:taskId/subscribe |
| Extended Cards | ✅ Implemented | Authenticated endpoints with rate limits, usage stats |
Conclusion: The platform is 100% A2A v0.3 compliant (506 tests passing).
Agent Fleet Size:
- Total Agent Definitions: 68 agent markdown files
- Core QE Agents: 35+
- Subagents: 7 (TDD red/green/refactor, reviewers)
- V3 Specialists: 5 (queen-coordinator, memory-specialist, etc.)
- Claude-Flow Core: 8 (adr-architect, performance-engineer, etc.)
Decision
We will implement A2A Protocol v0.3 with JSON-RPC 2.0 message envelope for inter-agent communication and external discovery.
Architecture Overview
+-------------------------------------------------------------------+
| AQE v3 A2A ARCHITECTURE |
+-------------------------------------------------------------------+
| |
| +------------------+ +------------------+ +--------------+ |
| | External Agents |<--->| A2A Gateway |<--->| QE Fleet | |
| | (via A2A) | | (JSON-RPC 2.0) | | (68 agents) | |
| +------------------+ +------------------+ +--------------+ |
| | |
| +-----------+-----------+ |
| | | |
| v v |
| +----------+ +----------+ |
| | Discovery| | Task | |
| | Service | | Manager | |
| +----------+ +----------+ |
| | | |
| v v |
| +----------+ +----------+ |
| | Agent | | Negotiation| |
| | Cards | | Protocol | |
| +----------+ +----------+ |
| |
+-------------------------------------------------------------------+
Integration Points
1. Agent Card Schema (v3/src/adapters/a2a/agent-cards/)
interface QEAgentCard {
// Identity
name: string; // e.g., "qe-test-architect"
description: string; // Detailed agent description
version: string; // Semantic version
url: string; // Service endpoint URL
// Provider Information
provider: {
organization: string; // "Agentic QE"
url: string; // Project URL
};
// Capabilities
capabilities: {
streaming: boolean; // SSE streaming support
pushNotifications: boolean; // Webhook notifications
stateTransitionHistory: boolean; // Task history exposure
};
// Skills (from agent markdown definition)
skills: AgentSkill[];
// I/O Modes
defaultInputModes: string[]; // ["text/plain", "application/json"]
defaultOutputModes: string[]; // ["application/json", "text/plain"]
// Security
securitySchemes: SecurityScheme[];
supportsAuthenticatedExtendedCard: boolean;
}
interface AgentSkill {
id: string; // e.g., "test-generation"
name: string; // "AI-Powered Test Generation"
description: string;
tags: string[]; // ["testing", "ai", "tdd"]
examples: string[]; // Sample prompts
inputModes: string[];
outputModes: string[];
}
2. Agent Card Generator
class AgentCardGenerator {
/**
* Parse agent markdown files and generate A2A-compatible cards
*/
async generateFromMarkdown(agentPath: string): Promise<QEAgentCard> {
const markdown = await fs.readFile(agentPath, 'utf-8');
const parsed = this.parseAgentMarkdown(markdown);
return {
name: parsed.name,
description: parsed.description,
version: '3.0.0',
url: `${this.baseUrl}/a2a/${parsed.id}`,
provider: {
organization: 'Agentic QE',
url: 'https://github.com/agentic-qe/agentic-qe'
},
capabilities: {
streaming: true,
pushNotifications: false,
stateTransitionHistory: true
},
skills: this.extractSkills(parsed),
defaultInputModes: ['text/plain', 'application/json'],
defaultOutputModes: ['application/json'],
securitySchemes: this.getSecuritySchemes(),
supportsAuthenticatedExtendedCard: true
};
}
/**
* Generate cards for all 68 agents
*/
async generateAllCards(): Promise<Map<string, QEAgentCard>> {
const agentFiles = await glob('.claude/agents/v3/*.md');
const cards = new Map<string, QEAgentCard>();
for (const file of agentFiles) {
const card = await this.generateFromMarkdown(file);
cards.set(card.name, card);
}
return cards;
}
}
3. JSON-RPC 2.0 Message Envelope
interface A2ARequest {
jsonrpc: '2.0';
id: string | number;
method: A2AMethod;
params?: A2AParams;
}
type A2AMethod =
| 'message/send' // Send message, receive complete response
| 'message/stream' // Send message, stream responses via SSE
| 'tasks/get' // Retrieve task status
| 'tasks/list' // List tasks with filtering
| 'tasks/cancel' // Cancel task
| 'tasks/subscribe' // Subscribe to task updates
| 'agent/card'; // Get extended agent card
interface A2AResponse {
jsonrpc: '2.0';
id: string | number;
result?: A2AResult;
error?: A2AError;
}
interface A2AError {
code: number;
message: string;
data?: unknown;
}
// A2A-specific error codes
enum A2AErrorCode {
AUTHENTICATION_REQUIRED = -32001,
INVALID_CREDENTIALS = -32002,
INSUFFICIENT_PERMISSIONS = -32003,
TASK_NOT_FOUND = -32010,
CONTEXT_NOT_FOUND = -32011,
SKILL_NOT_FOUND = -32012,
INVALID_MESSAGE = -32020,
RATE_LIMIT_EXCEEDED = -32030
}
4. Agent Discovery Service
import express from 'express';
const app = express();
// Well-known URI for agent discovery (RFC 8615)
app.get('/.well-known/agent.json', async (req, res) => {
const aggregateCard = await agentCardService.getAggregateCard();
res.json(aggregateCard);
});
// Individual agent cards
app.get('/a2a/:agentId/.well-known/agent.json', async (req, res) => {
const card = await agentCardService.getCard(req.params.agentId);
if (!card) {
return res.status(404).json({
error: { code: -32012, message: 'Agent not found' }
});
}
res.json(card);
});
// Authenticated extended card
app.get('/a2a/:agentId/card', verifyAuth, async (req, res) => {
const card = await agentCardService.getExtendedCard(req.params.agentId);
res.json(card);
});
5. Task Negotiation Protocol
interface A2ATask {
id: string;
contextId?: string;
status: TaskStatus;
artifacts?: Artifact[];
error?: { message: string; code?: string };
}
type TaskStatus =
| 'submitted' // Initial state
| 'working' // Agent processing
| 'input_required' // Need additional input
| 'auth_required' // Need authentication
| 'completed' // Finished successfully
| 'failed' // Failed with error
| 'canceled' // Canceled by client
| 'rejected'; // Agent rejected task
class A2ATaskManager {
private tasks = new Map<string, A2ATask>();
async submitTask(message: A2AMessage): Promise<A2ATask> {
const taskId = crypto.randomUUID();
const task: A2ATask = {
id: taskId,
contextId: message.contextId || crypto.randomUUID(),
status: 'submitted'
};
this.tasks.set(taskId, task);
this.emit('task_submitted', task);
// Route to appropriate QE agent
const agent = await this.routeToAgent(message);
task.status = 'working';
try {
const result = await agent.execute(message);
task.status = 'completed';
task.artifacts = this.createArtifacts(result);
} catch (error) {
task.status = 'failed';
task.error = { message: error.message };
}
return task;
}
private async routeToAgent(message: A2AMessage): Promise<QEAgent> {
// Use existing QE routing system
const routing = await this.router.routeTask({
task: message.parts[0].text,
context: message.contextId
});
return this.agents.get(routing.agentId);
}
}
6. Gossip Protocol Integration
The existing gossip protocol complements A2A for internal coordination:
class HybridCoordinator {
private a2aGateway: A2AGateway;
private gossipAgent: GossipAgent;
/**
* Use gossip for internal discovery, A2A for external communication
*/
async delegateTask(task: A2ATask, skill: string): Promise<Artifact[]> {
// Internal: Use gossip to find best available agent
const candidates = this.gossipAgent.findAvailableAgents(skill);
if (candidates.length === 0) {
// External: Try A2A discovery for external agents
const externalAgents = await this.a2aGateway.discoverAgents(skill);
if (externalAgents.length > 0) {
return this.delegateExternal(task, externalAgents[0]);
}
throw new Error(`No agents available for skill: ${skill}`);
}
// Route internally via existing coordination
return this.delegateInternal(task, candidates[0]);
}
}
QE Agent Skill Mapping
| QE Agent | Primary Skill ID | Tags |
|---|---|---|
| qe-test-architect | test-generation | testing, ai, architecture |
| qe-tdd-specialist | tdd-cycle | testing, tdd, red-green-refactor |
| qe-coverage-specialist | coverage-analysis | testing, coverage, gaps |
| qe-security-scanner | security-scan | security, owasp, vulnerabilities |
| qe-accessibility-auditor | accessibility-audit | a11y, wcag, compliance |
| qe-learning-coordinator | cross-domain-learning | learning, patterns, optimization |
| qe-quality-gate | quality-assessment | quality, gates, deployment |
| qe-fleet-commander | fleet-coordination | coordination, swarm, orchestration |
Rationale
Pros:
- Industry-standard protocol (Google, Linux Foundation, 150+ partners)
- Enables external agent collaboration
- Standardized capability discovery
- Clear task lifecycle management
- Complements existing gossip protocol
Cons:
- Additional protocol layer complexity
- Need to generate 68+ agent cards
- Authentication complexity for external agents
Alternatives Considered:
-
Keep Custom Protocol Only
- Rejected: No external interoperability
-
Replace Gossip with A2A
- Rejected: Gossip better for emergent internal coordination
-
Minimal A2A Subset
- Rejected: Need full protocol for ecosystem compatibility
Implementation Plan
Phase 1: Agent Cards (Week 3) ✅ COMPLETE
- ✅ Created agent card schema (
schema.ts) - ✅ Built markdown parser (
generator.ts) - ✅ Generate cards dynamically from agent markdown files
- ✅ Validate against A2A spec (
validator.ts) - 130 tests
Phase 2: JSON-RPC 2.0 (Week 3) ✅ COMPLETE
- ✅ Implemented message envelope (
envelope.ts) - ✅ Added A2A error handling (
errors.ts) - ✅ Created request/response serialization
- ✅ All 8 A2A methods defined (
methods.ts) - 125 tests
Phase 3: Discovery (Week 4) ✅ COMPLETE
- ✅ Implemented
/.well-known/agent.json(RFC 8615) - ✅ Added per-agent card endpoints
- ✅ Extended card authentication support
- ✅ Integration tests - 67 unit + 36 integration tests
Phase 4: Task Negotiation (Week 4) ✅ COMPLETE
- ✅ Implemented task lifecycle (
task-manager.ts,task-store.ts) - ✅ Connected to QE routing (
task-router.ts) - ✅ Added SSE streaming for task updates
- ✅ End-to-end tests with AG-UI↔A2A↔A2UI flow - 101 tests
Success Metrics
- Agent cards generated dynamically from markdown files (AgentCardGenerator)
- JSON-RPC 2.0 message format implemented (envelope.ts, methods.ts, errors.ts)
- Discovery endpoint at
/.well-known/agent.json(RFC 8615 compliant) - Task lifecycle states: submitted, working, input_required, auth_required, completed, failed, canceled, rejected
- Task routing with load balancing and skill matching (task-router.ts)
- SSE streaming for task updates (
/a2a/tasks/:taskId/subscribe) - Extended card authentication support (authenticated endpoints)
- Full state machine with valid transitions (VALID_TRANSITIONS, isValidTransition)
Dependencies
- A2A SDK (Python/TypeScript)
- JSON-RPC 2.0 library
- OAuth 2.0 library (for authentication)
- Existing gossip protocol (internal coordination)
References
Remaining Considerations / Future Work
Potential Improvements - NOW COMPLETE ✅
Implementation Date: 2026-01-31
| Improvement | Status | Implementation |
|---|---|---|
| OAuth 2.0 Integration | ✅ Complete | auth/oauth-provider.ts, auth/middleware.ts, auth/routes.ts |
| Push Notifications | ✅ Complete | notifications/webhook-service.ts, notifications/subscription-store.ts |
| Dynamic Agent Count | ✅ Complete | discovery/file-watcher.ts, discovery/hot-reload-service.ts |
Phase 5: OAuth 2.0 Authentication ✅ Complete
- OAuth 2.0 Provider with authorization code + client credentials flows
- PKCE support (S256 + plain methods)
- JWT signing/verification with
joselibrary - Token store with TTL and revocation
- Scope-based access control (12 QE domains)
- JWT middleware for protected routes
- 184 tests passing
Phase 6: Push Notifications ✅ Complete
- Webhook-based push notifications for task events
- HMAC-SHA256 signature verification
- Subscription store with task indexing
- Retry queue with exponential backoff
- Event types: task.submitted, task.working, task.completed, task.failed, etc.
- 105 tests passing
Phase 7: Dynamic Agent Discovery ✅ Complete
- File watcher for agent markdown files
- Hot reload service with cache invalidation
- Agent health checker with periodic checks
- Prometheus-style metrics collector
- 192 tests passing
Total Tests After Improvements: 506 + 481 = 987 tests
Production Hardening (Future)
- Load testing for discovery endpoints at scale
- Rate limiting enforcement (metrics tracked, enforcement optional)
- External agent federation testing
Not in Scope (Intentionally Excluded)
- Custom A2A extensions beyond v0.3 spec
- Agent-to-agent direct communication (uses internal gossip)
- Multi-tenant isolation (single-tenant design)
ADR created: 2026-01-30 Implementation completed: 2026-01-30 Protocol Version: A2A v0.3 Total Tests: 506 passing