Files
Profa 2253d05618 feat: flatten project structure — archive v2, promote v3 to root
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>
2026-03-01 11:35:41 +00:00

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:

  1. Keep Custom Protocol Only

    • Rejected: No external interoperability
  2. Replace Gossip with A2A

    • Rejected: Gossip better for emergent internal coordination
  3. 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 jose library
  • 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