Skip to content

[A2A] Core A2A/ACP Protocol Implementation #332

Closed as not planned
Closed as not planned

Description

@tamirdresher

Overview

Implement the core A2A (Agent-to-Agent) protocol server and client for Squad CLI, enabling cross-repo squad communication.

Reference

  • PRD: See tamresearch1 repo, branch squad/296-cross-repo-a2a, file .squad/research/cross-repo-a2a-prd.md
  • Related Issue: tamirdresher_microsoft/tamresearch1#296

Scope

  • Embed A2A server in Squad CLI (JSON-RPC 2.0 over HTTP)
  • Implement Agent Card generation (JSON schema)
  • Core RPC endpoints: decisions, tasks, research
  • A2A client library for outbound calls
  • Protocol versioning and compatibility

Technical Requirements

  • Stack: Node.js + Express + JSON-RPC middleware
  • Endpoints:
    • \POST /a2a/rpc\ — Main JSON-RPC endpoint
    • \GET /a2a/card\ — Agent Card
    • \GET /a2a/health\ — Health check
  • Message Format: JSON-RPC 2.0
  • Transport: HTTP/1.1 (Phase 1), optional gRPC (Phase 3)
  • Security: Local-only binding (127.0.0.1) for MVP

Key Capabilities

  1. \squad.queryDecisions\ — Search decisions in .squad/decisions/\
  2. \squad.delegateTask\ — Create GitHub issue from remote squad
  3. \squad.shareResearch\ — Share research documents

Deliverables

  • A2A server module (\src/a2a/server.ts)
  • JSON-RPC handler (\src/a2a/rpc-handler.ts)
  • Agent Card generator (\src/a2a/agent-card.ts)
  • A2A client library (\src/a2a/client.ts)
  • Unit tests (coverage >80%)
  • Integration tests (2 squads communicating)
  • API documentation

Dependencies

Success Criteria

  • ✅ Two squads can communicate via A2A protocol
  • ✅ Query decisions from remote squad <200ms
  • ✅ Agent Card conforms to A2A spec
  • ✅ All tests passing

Timeline

Phase 1 (MVP): 3 weeks

Notes

Align with A2A v0.3.0 specification for future interoperability with Google ADK, AWS, Azure agents.

Activity

  1. 16 remaining items

  2. bradygaster commented on Mar 16, 2026

    @bradygaster
    Collaborator

    Status: Shelved (2026-03-16)

    Decision: A2A is shelved for now. Too risky in the short term. The proposal, architecture work, and 5-agent UX impact analysis are preserved below and on branch squad/332-a2a-core-protocol.

    We'd love community feedback on whether multi-squad orchestration is something you'd use. If you have thoughts, drop them here.


    UX Impact Assessment (5-Agent Verdict)

    The team ran a full impact analysis with Flight (architecture), EECOM (runtime), PAO (DevRel), FIDO (testing), and Network (security).

    Consensus: GO with conditions — but the conditions are significant:

    Agent Verdict Key Concern
    Flight GO if multi-squad is a product pillar Product-market fit risk
    EECOM GO with static Agent Card Maintenance tax
    PAO GO but Wave 2 for docs/demos 20% feature for 20% users
    FIDO GO with 200+ tests as gate Port conflicts + flake risk
    Network GO with trust model + approval flows Security gap without allowlist

    Key numbers: ~2,500 new lines of code, 200-300 new tests, +10-15% CI time, 5 new doc pages

    The strategic question: Is multi-squad orchestration a core product pillar, or exploratory? If nobody builds on it within 6 months, archive it.

    Preserved artifacts

    What would unblock this

    1. Community demand (3+ people asking for multi-squad)
    2. A concrete use case beyond a cool demo
    3. Security model designed (trust allowlist, approval flows)
  3. tamirdresher commented on Mar 16, 2026

    @tamirdresher
    CollaboratorAuthor

    Squad, a few things to think about for the .squad/proposals/a2a-core-protocol.md.
    1.now that aspire goes polyglot and AI friendly, should we adopt it to run the disturbated test g for multiple squads?

    1. What would be the squads protocol when squad A reach squad B and then B calls C. And the result comes from C? What if A B and C need to work together as a clique on specific task which could be long running with pause and resume
  4. deleted a comment from github-actions on Mar 18, 2026
  5. deleted a comment from github-actions on Mar 18, 2026
  6. diberry commented on Mar 22, 2026

    @diberry
    Contributor

    🏗️ Flight's Architecture Proposal — Team-Reviewed

    squad obo dina — Flight (Lead) wrote an A2A architecture proposal and the team reviewed it. Below are three review comments from EECOM (Core Dev), CONTROL (TypeScript), and RETRO (Security). Each contains findings that must be addressed before Phase 1 code is written.

    Architecture Summary (Flight)

    • cross-squad.ts is the foundation — 70% of the data model exists (SquadManifest, discovery, delegation). 0% of the network/protocol layer.
    • TypeSpec: defer to Phase 2 — design the protocol first in TypeScript, formalize with TypeSpec after it stabilizes.
    • RemoteBridge: do NOT extend for A2A — existing team decision stands. A2A is a separate HTTP/JSON-RPC layer.
    • Google A2A: compatible, not coupled — serve Squad-native format at /a2a/card, optional Google format at /.well-known/agent-card later.
    • MVP = 3 operations: discovery (GET /a2a/card), queryDecisions (POST /a2a/rpc), delegateTask (POST /a2a/rpc)
    • Phasing: Phase 0 (document what exists) → Phase 1 (HTTP server MVP, ~1 week) → Phase 2 (TypeSpec, TLS, mDNS) → Phase 3 (OAuth, RBAC, streaming)
    • Recommendation: stay shelved at P2 until community demand materializes. Phase 0 documentation can start now.

    Full proposal: .squad/decisions/inbox/flight-a2a-protocol-architecture.md on dev branch.

  7. diberry commented on Mar 22, 2026

    @diberry
    Contributor

    🔧 EECOM (Core Dev) — Runtime Feasibility Review

    Must-Address Before Phase 1

    • Registry atomic writes. active-squads.json needs write-to-tmp + rename pattern. Two squad instances starting simultaneously will clobber each other's registration without this. (~50 lines, highest-risk item)
    • Process deregistration on crash. SIGINT/SIGTERM handlers must deregister from active-squads.json. Ghost entries from crashed processes make squad discover unreliable. PID liveness check (process.kill(pid, 0)) on read handles stale entries.
    • PID reuse guard. PID check alone is insufficient — add a lock file at squadDir/.squad/.a2a-lock with PID to verify the live process is actually a squad process.
    • A2AServer must be a class (like RemoteBridge) with start()/stop() lifecycle methods. This is a prerequisite for testable integration tests — top-level scripts can't be tested without child processes.
    • Test strategy. Cross-process RPC testing needs an explicit plan: unit tests for pure functions (envelope parsing, handler logic), integration tests using in-process A2AServer on random port.

    Corrections to the Proposal

    • 70% claim is misleading. 70% of the data model exists. 0% of the network layer. Don't create false confidence — the remaining work is harder than the data model work.
    • DiscoveredSquad needs a2aEndpoint field. Current type has no network address — only contact.repo (a GitHub URL). Add a2aEndpoint?: string and a 'runtime' source type.
    • Registry schema mismatch. Existing squad-registry.json (static file paths) vs new active-squads.json (runtime PID+port) are different schemas solving different problems. Name them distinctly: call the new one runtime-registry.ts to avoid confusion.
    • Use node:http, not Express. RemoteBridge already uses node:http directly. Three endpoints don't justify adding Express (~50KB dependency). Follow the existing pattern.
    • Hand-write JSON-RPC envelope, don't use vscode-jsonrpc. That library is for bidirectional streams (LSP transport), not HTTP POST/response. The envelope is ~20 lines of TypeScript.

    Recommended Scope Changes

    • Drop /.well-known/agent-card from Phase 1. The capability→skill translation is lossy (Squad capabilities are string tags, Google skills need {id, name, description}). A technically incorrect Agent Card is worse than none. Defer to Phase 2.
    • squad serve should be a foreground blocking command (like squad start), not a daemon. Register on start, deregister on SIGINT/SIGTERM.
    • queryDecisions needs a scope limit. decisions.md is 280KB+. Limit to last N bytes or max 5 matches per query. Keep response times under 200ms.
    • delegateTask needs opt-in capability declaration in manifest: "a2aCapabilities": ["queryDecisions", "delegateTask"]. Only registered capabilities appear in RPC dispatch table. 5-line change that avoids a security footgun.

    Estimate Correction

    Flight says 500–700 lines. Actual estimate: 800–1000 lines — registry write safety, process lifecycle, and tests are more code than the proposal accounts for. Still 1 week.

  8. diberry commented on Mar 22, 2026

    @diberry
    Contributor

    ⚙️ CONTROL (TypeScript) — Type System and SDK Surface Review

    Must-Address Before Phase 1

    • AgentCard must NOT extend SquadManifest. They are related by a toAgentCard() translation function, not type inheritance. Manifest is Squad-internal (versioned with manifest.json). AgentCard is wire format (versioned with A2A_PROTOCOL_VERSION). They evolve independently.
    • Write TypeSpec-compatible types from day 1. All fields readonly, no any, arrays as readonly T[], discriminated unions via string literal fields, no intersection types in wire shapes, JSDoc on every export. This makes Phase 2 TypeSpec migration mechanical, not a rewrite.
    • A2A_PROTOCOL_VERSION constant must live in protocol.ts, independent of SDK semver. Wire format breaking changes increment this version, not necessarily the package version.
    • Typed A2ARequest union discriminated on method literal field ('squad.queryDecisions' | 'squad.delegateTask'). Compiler enforces exhaustive handling.

    SDK Export Strategy (Decided)

    • Add "./a2a" subpath export to packages/squad-sdk/package.json. A2A types are optional — they should NOT go in the main types.ts barrel. Import as import type { AgentCard } from '@bradygaster/squad-sdk/a2a'.
    • A2AServerConfig does NOT go in SquadSDKConfig. A2A config is a runtime concern (how the server binds), not a team topology concern (what agents exist). Separate lifetimes, separate owners.
    • No separate client package for Phase 1. src/a2a/client.ts stays in the SDK. Extract to standalone package only if demonstrated demand exists.

    Concrete Type Definitions Provided

    CONTROL wrote complete MVP type definitions ready for Phase 1 kickoff:

    • src/a2a/protocol.ts — JSON-RPC 2.0 envelopes (JsonRpcRequest, JsonRpcResponse, JsonRpcError), error codes (A2A_ERROR_CODES), method params/results (QueryDecisionsParams, DelegateTaskParams), typed request union, serialize/parse helpers
    • src/a2a/types.ts — AgentCard, A2AServerConfig, A2AClientConfig, ActiveSquadEntry
    • src/a2a/index.ts — public barrel (runtime exports + type-only re-exports)
    • src/a2a/agent-card.ts — toAgentCard(manifest) translation function

    These definitions follow remote/protocol.ts patterns exactly (version constant, discriminated unions, serialize/parse helpers).

    Google A2A Compatibility (Decided)

    • Squad-native AgentCard at /a2a/card (Phase 1)
    • Separate GoogleAgentCard type in src/a2a/google-compat.ts (Phase 2)
    • Separate toGoogleAgentCard() function — never merge the two card types into one
  9. diberry commented on Mar 22, 2026

    @diberry
    Contributor

    🔒 RETRO (Security) — Threat Model and Security Requirements

    🚫 Phase 1 Hard Blockers (must ship with Phase 1)

    • Shared secret auth required. Generate a random 32-byte bearer token at squad serve startup. Store in registry. Require Authorization: Bearer {token} on ALL requests. Without this, any local process (including malicious npm postinstall scripts) can call the A2A server. ~20 lines of code.
    • delegateTask guards required. This endpoint calls gh issue create — it's the highest-severity item. Requires: label allowlist (only manifest-defined labels), body length cap (2000 chars), rate limit (max 5 calls/minute), target repo fixed to manifest repo (not caller-configurable).
    • Host header validation. Accept only 127.0.0.1:{port} or localhost:{port}. Reject all other Host headers with 403. This defeats DNS rebinding attacks (a documented, real attack class against localhost services).
    • queryDecisions scope limits. Only search decisions.md, NOT inbox/ (contains unapproved proposals). Max 10KB response. Min 10-char query (prevents query: "" full-dump). Max 5 results.
    • Registry file permissions. ~/.squad/registry/active-squads.json must be 0600 on Unix (icacls restricted on Windows). A2A server must validate permissions at startup and refuse to operate if world-readable.
    • Health endpoint with session UUID. GET /a2a/health returns a random UUID generated at startup. Client validates UUID matches registry entry before trusting it. This defeats PID reuse attacks.
    • Rate limiting. Max 60 requests/minute total across all endpoints.
    • Audit log. All A2A requests logged to .squad/log/a2a-access.log (timestamp, method, source IP).
    • Container/WSL/Codespaces warning. Print startup warning when detected — 127.0.0.1 binding doesn't isolate in these environments.

    ⚠️ Phase 2 Blockers (must ship with --network mode)

    • TLS mandatory for network mode. --network without --tls must be a startup error, not a warning.
    • No rejectUnauthorized: false anywhere. CI lint rule to enforce.
    • OAuth2/OIDC required for network mode. Bearer-only auth remains acceptable for localhost. Network exposure requires identity-based auth.
    • TOFU with explicit user confirmation for self-signed certs. No auto-accept. Ever.
    • Private key permissions. Key files 0400 (owner read only), enforced at startup.

    🔴 Red Team Scenario: Malicious npm postinstall

    RETRO walked through a complete attack:

    1. Attacker publishes popular-looking npm package with postinstall script
    2. Script scans localhost ports (< 2 seconds) → finds A2A server
    3. GET /a2a/card → gets squad name, repo URL, capabilities
    4. squad.queryDecisions with query "auth token secret credential" → exfiltrates architecture decisions
    5. 50x squad.delegateTask → creates 50 GitHub issues, exhausts gh token rate limit for 60 minutes
    6. npm install reports success. Developer has no idea.

    The Phase 1 security requirements above defeat this attack at Step 3 (bearer token required → 401). Even if token is somehow obtained, rate limiting and scope limits cap the blast radius.

    What RETRO Is NOT Blocking

    The architecture is sound. The phasing is correct. The stay-shelved recommendation is right. What RETRO requires is that these security acceptance criteria exist on the Phase 1 issue BEFORE that issue is opened for implementation. Specify auth before writing code, not after.

  10. diberry commented on Mar 31, 2026

    @diberry
    Contributor

    🔄 Ralph status: A2A — core protocol implementation. Parent of #333-#336 suite. No PR. Long-term backlog.

  11. bradygaster commented on Apr 12, 2026

    @bradygaster
    Collaborator

    Shelving the A2A initiative for now. Agent-to-agent communication is something we want to get right — we need to take it really slowly and deliberately when we do tackle it. Not pursuing short-term, but we'll revisit when we have a clearer picture of the right patterns. Thanks for the thorough spike @tamirdresher!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    go:needs-researchNeeds investigationpriority:p2Next sprintshelvedParked — revisit when conditions changesquadSquad triage inbox — Lead will assign to a membertype:spikeResearch/investigation — produces a plan, not code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions