Skip to content

Architecture: From Shared Filesystem to A2A

In the local system, all agents share an output directory. Each agent writes its decisions to files and the next one reads them directly:

OUTPUT_DIR = os.getenv('ADK_OUTPUT_DIR', '/app/outputs')

This works because they all run in the same Docker container with access to the same filesystem. On Cloud Run, each service has its own isolated container — there is no shared /app/outputs/.

Options like GCS FUSE or Filestore NFS exist for mounting shared volumes. However, Google does not recommend them for inter-service communication. The correct pattern in serverless architectures is: state travels in the messages, not in the filesystem.

Agent-to-Agent (A2A) is an open protocol under the Linux Foundation. Each agent exposes itself as an independent HTTP server with its own URL. Communication is via JSON messages — the orchestrator sends a task and receives a response.

The orchestrator chains the 7 agents and accumulates context from each one. Each agent receives everything that the previous ones generated:

Orchestrator
├──→ Platform Architect (receives: task)
├──→ Infrastructure (receives: task + PA context)
├──→ Security (receives: task + PA + Infra context)
├──→ CI/CD (receives: task + PA + Infra + Sec context)
├──→ Observability (receives: task + PA + Infra + Sec + CICD)
├──→ DevEx (receives: task + PA + Infra + Sec + CICD + Obs)
└──→ Web Portal (receives: task + all 6 previous)

The context grows with each step. Web Portal receives the accumulated output from all 6 previous agents to build the portal with the full IDP information.

The main change is in how each agent obtains context from the previous ones.

Before (local system) — reads from disk:

def get_platform_config() -> dict:
"""Reads platform-config.yaml from the shared filesystem."""
config_path = os.path.join(OUTPUT_DIR, 'platform-config.yaml')
with open(config_path) as f:
return yaml.safe_load(f)

After (Cloud Run) — reads from the message, with disk fallback:

def get_platform_config(context_json: str = "") -> dict:
"""Reads context from the A2A message. Falls back to disk if empty."""
if context_json:
return json.loads(context_json)
# Fallback for local execution
config_path = os.path.join(OUTPUT_DIR, 'platform-config.yaml')
with open(config_path) as f:
return yaml.safe_load(f)

This pattern is repeated in 6 of the 7 agents. Platform Architect doesn’t need it because it’s the first in the chain — it has no previous context to receive.


Next step: The 7 Agents — Dockerfile, agent.json and tools →