Skip to content

feat(a2a): shared A2A server + card generator - #87

Merged
izzywdev merged 6 commits into
mainfrom
feat/a2a-server
Jul 22, 2026
Merged

feat(a2a): shared A2A server + card generator#87
izzywdev merged 6 commits into
mainfrom
feat/a2a-server

Conversation

@izzywdev

Copy link
Copy Markdown
Owner

Backend slice of A2A Phase 2 (keystone). Implements the CALLEE side of the FROZEN contract at agent-templates/contracts/a2a/v1:

  • A2A server — JSON-RPC 2.0 over HTTP + SSE (POST /rpc, well-known card path), per binding.md.
  • Adapter onto providers/base.py (thin translation; no new task engine) per state-mapping.md.
  • Card generator — projects .fuze/manifest.json + roles/*/role.json -> Agent Card per card-projection.md; validates against schema/.
  • AuthZ — callee-enforced allowlist (providesTo), fail-closed, per authz.md.

Plus its own unit tests. WIP — pushing continuously.

OUT OF SCOPE (sibling agents): image/Dockerfile/Helm/Argo (devops), conformance/negative tests (test-engineer), handoff-MCP-over-A2A client routing (mcp-engineer), docs (docs-maintainer).

🤖 Generated with Claude Code

izzywdev and others added 5 commits July 22, 2026 19:16
Contract-import shim + package skeleton for the A2A server slice.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
… green) [skip ci]

Projects .fuze/manifest.json + roles/*/role.json -> Agent Card per
card-projection.md, for product and exec-tier roles. Validates against
agent-card.schema.json + fuze-profile.schema.json. Deterministic, signed
(placeholder signer; real JWS injected by devops).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
…it tests) [skip ci]

- task_mapper: run_until_block -> A2A Task; INPUT vs AUTH_REQUIRED classifier.
- wire_errors: A2AError -> JSON-RPC error object with ProtoJSON data array.
- authz: fail-closed providesTo allowlist; dependsOn grants nothing.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
…skip ci]

Thin translation over providers/base.py seam: SendMessage(+streaming),
GetTask/ListTasks/CancelTask/SubscribeToTask, continuation via confirm_tool/
resume_session, per-caller extended card, callee-enforced authz, caller-scoped
session store (reflection cache, not a task engine). 64 unit tests green so far.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
…sts green)

- server.py: JSON-RPC 2.0 over HTTP + SSE per binding.md (POST /rpc, well-known
  card, extendedAgentCard, version header, push-method -32003, method dispatch).
- identity.py: OIDC bearer -> trusted caller identity, fail-closed.
- runtime.py: compose config->adapter->server with provider + JWKS verifier.
- config/identity/server tests; a2a-unit.yml runs the suite in CI.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
Comment thread .github/workflows/a2a-unit.yml Fixed
Comment thread .github/workflows/a2a-unit.yml Fixed
…(B104)

- a2a-unit.yml: pin actions/checkout@v4.2.2 and actions/setup-python@v5.3.0 to
  full commit SHAs (supply-chain: no mutable action tags).
- runtime.main: default HOST to 127.0.0.1; chart sets HOST=0.0.0.0 explicitly.
  Fixes the one bandit B104 finding introduced in agent-templates/a2a.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
@izzywdev
izzywdev marked this pull request as ready for review July 22, 2026 17:13
@izzywdev
izzywdev merged commit 718a021 into main Jul 22, 2026
34 of 35 checks passed
izzywdev added a commit that referenced this pull request Jul 22, 2026
…t, values doc)

Rebased onto main (server PR #87 + mcp #86 merged). Reconciled the deploy slice
with the now-real server (agent-templates/a2a/):

- requirements.txt: took main's canonical (server-owned) set; ADDED cryptography
  (runtime._build_verifier decodes RS256/ES256 JWKS tokens; PyJWT needs it).
- Dockerfile: entrypoint python -m a2a.runtime (was a2a.server); vendor providers/
  + sync/ (runtime imports 'providers'; anthropic adapter delegates to sync/);
  env = the 4 vars runtime.build_from_env actually reads (A2A_VALUES_FILE,
  A2A_REPOS_DIR, AGENT_PROVIDER, HOST) + FUZE_STATE_DIR; drop unread PORT/OIDC/
  card-signing envs.
- chart: replace tenants.yaml ConfigMap with values.json (the whole a2a block via
  toJson) that the server reads via A2A_VALUES_FILE; add repo-sync init container
  cloning each enabled tenant's repo at its ref into /repos (LocalRepoResolver);
  optional ANTHROPIC_API_KEY / git token / id-state ConfigMap wiring; probes now
  hit the server's real GET /healthz.

Verified:
- helm lint clean (default/prod/ci); kubeconform 4/4 valid (k8s 1.29.0).
- gated overlays render empty (enabled:false).
- rendered values.json parses through the MERGED server's a2a.config.load_config
  (both tenants, auth, keyId resolved).
- docker build green; in-image import of a2a.*/providers/fuze_a2a_client + cryptography;
  build_from_env() composes the Starlette app (routes /rpc, /.well-known/agent-card.json,
  /extendedAgentCard, /healthz) from the chart's values.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
izzywdev added a commit that referenced this pull request Jul 22, 2026
…t, values doc)

Rebased onto main (server PR #87 + mcp #86 merged). Reconciled the deploy slice
with the now-real server (agent-templates/a2a/):

- requirements.txt: took main's canonical (server-owned) set; ADDED cryptography
  (runtime._build_verifier decodes RS256/ES256 JWKS tokens; PyJWT needs it).
- Dockerfile: entrypoint python -m a2a.runtime (was a2a.server); vendor providers/
  + sync/ (runtime imports 'providers'; anthropic adapter delegates to sync/);
  env = the 4 vars runtime.build_from_env actually reads (A2A_VALUES_FILE,
  A2A_REPOS_DIR, AGENT_PROVIDER, HOST) + FUZE_STATE_DIR; drop unread PORT/OIDC/
  card-signing envs.
- chart: replace tenants.yaml ConfigMap with values.json (the whole a2a block via
  toJson) that the server reads via A2A_VALUES_FILE; add repo-sync init container
  cloning each enabled tenant's repo at its ref into /repos (LocalRepoResolver);
  optional ANTHROPIC_API_KEY / git token / id-state ConfigMap wiring; probes now
  hit the server's real GET /healthz.

Verified:
- helm lint clean (default/prod/ci); kubeconform 4/4 valid (k8s 1.29.0).
- gated overlays render empty (enabled:false).
- rendered values.json parses through the MERGED server's a2a.config.load_config
  (both tenants, auth, keyId resolved).
- docker build green; in-image import of a2a.*/providers/fuze_a2a_client + cryptography;
  build_from_env() composes the Starlette app (routes /rpc, /.well-known/agent-card.json,
  /extendedAgentCard, /healthz) from the chart's values.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549
izzywdev added a commit that referenced this pull request Jul 22, 2026
* chore(a2a): scaffold a2a-shared chart dir [skip ci]

* feat(a2a): a2a-shared Helm chart (enabled-gated, contract-conformant) [skip ci]

* feat(a2a): Dockerfile + release image build + Argo app + helm-validate wiring [skip ci]

* docs(a2a): a2a-shared deploy runbook (go-live via GitOps)

Validated locally:
- helm lint clean on default/prod/ci overlays (helm v4.2.1)
- helm template renders Deployment/Service/ConfigMap + per-external-tenant Ingress
- default+prod overlays render empty (enabled:false gate)
- kubeconform -strict -ignore-missing-schemas: 4/4 valid (k8s 1.29.0)
- docker build of agent-templates/a2a/Dockerfile succeeds

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549

* fix(a2a): run image as non-root USER + pod securityContext

Resolves Semgrep OSS dockerfile.security.missing-user finding on PR #85.
Non-root uid 10001 in the image + matching runAsNonRoot/drop-ALL-caps in the
Deployment. Re-validated: helm lint clean, kubeconform 4/4, docker build green.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549

* fix(a2a): reconcile chart+image with merged server (runtime entrypoint, values doc)

Rebased onto main (server PR #87 + mcp #86 merged). Reconciled the deploy slice
with the now-real server (agent-templates/a2a/):

- requirements.txt: took main's canonical (server-owned) set; ADDED cryptography
  (runtime._build_verifier decodes RS256/ES256 JWKS tokens; PyJWT needs it).
- Dockerfile: entrypoint python -m a2a.runtime (was a2a.server); vendor providers/
  + sync/ (runtime imports 'providers'; anthropic adapter delegates to sync/);
  env = the 4 vars runtime.build_from_env actually reads (A2A_VALUES_FILE,
  A2A_REPOS_DIR, AGENT_PROVIDER, HOST) + FUZE_STATE_DIR; drop unread PORT/OIDC/
  card-signing envs.
- chart: replace tenants.yaml ConfigMap with values.json (the whole a2a block via
  toJson) that the server reads via A2A_VALUES_FILE; add repo-sync init container
  cloning each enabled tenant's repo at its ref into /repos (LocalRepoResolver);
  optional ANTHROPIC_API_KEY / git token / id-state ConfigMap wiring; probes now
  hit the server's real GET /healthz.

Verified:
- helm lint clean (default/prod/ci); kubeconform 4/4 valid (k8s 1.29.0).
- gated overlays render empty (enabled:false).
- rendered values.json parses through the MERGED server's a2a.config.load_config
  (both tenants, auth, keyId resolved).
- docker build green; in-image import of a2a.*/providers/fuze_a2a_client + cryptography;
  build_from_env() composes the Starlette app (routes /rpc, /.well-known/agent-card.json,
  /extendedAgentCard, /healthz) from the chart's values.json.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session-Id: 17fb89fd-3579-433b-a6c4-9c9e7f3ec549

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants