Contributing

How to build Agent Mesh from source, run its tests, and bring up a local mesh to develop against. Contributions go through GitHub pull requests and need a signed Contributor License Agreement. CONTRIBUTING.md in the repository has the details.

Layout

PathContents
cmd/One directory per binary: agentmesh-node, agentmesh-control-plane, agentmesh-router, agentmesh-one, agentmesh-console, mcp-client, agentmesh-bench, and smaller tools.
api/The wire contract: agentmesh.proto and its generated code, plus the Go types for the JSON admin API and the validation and Datalog helpers both sides share.
internal/Implementation, one package per component (node, controlplane, router, standalone, console, identity, storage, …).
charts/The agentmesh-p2p and agentmesh-node Helm charts.
tests/integration/Go tests that start several components in one process.
tests/e2e/Bats tests that drive the built binaries and containers.
development/The kind environment and example services.
site/This documentation, a Hugo site.

Two rules from AGENTS.md shape most changes. Components talk to each other only through api/agentmesh.proto (protobuf for anything a mesh component speaks, protojson of the same messages for the operator API). And no new module may be added to go.mod without discussion. For the security model, token invariants, and scope boundaries of the mesh, see Security Architecture & Posture.

Build

You need Go 1.25 or later. Docker is needed for the container tests and the linter, and bats-core for the end-to-end tests.

git clone https://github.com/google/agentmesh.git && cd agentmesh
make build        # binaries in ./bin
make docker-build # container images tagged :local
make proto        # regenerate api/agentmesh.pb.go after editing agentmesh.proto

The repository has a dev container (.devcontainer/devcontainer.json) with Go, Node, Python and Docker, and make build runs when it is created. Open it in a GitHub codespace or with the VS Code Dev Containers extension to build and test with nothing installed locally. make testnet inside a codespace starts agentmesh-one on the codespace’s public URL, so you can point an SDK program or a phone at your branch; the Codespaces guide has the steps.

Node and router control-plane requests identify themselves as agentmesh-node/<version> and agentmesh-router/<version>, including the router inside agentmesh-one. These headers contain the software component and build version. They are diagnostic metadata that a caller can spoof and are never used for authentication or authorization. They do not include peer IDs, credentials, or authorization roles. Publishing a version lets an observer identify the software release; keeping dependencies patched remains necessary.

make derives the version from git describe --tags --always --dirty. You can override it with make build VERSION=v0.1.0-custom and inspect the node binary with bin/agentmesh-node --version. Release binaries use the release tag, and published node, router and agentmesh-one images use the tag or commit SHA. For direct Docker builds of those images, pass --build-arg VERSION=...; without it, the version is devel. Plain go build uses Go’s embedded module or VCS metadata when available and falls back to devel.

Test

The suite is layered so that most coverage lives where it runs fastest.

CommandWhat runsTime
make testEvery Go test with the race detector: the unit tests next to the code, and the integration tests under tests/integration/, which start a control plane, a router and nodes in one process. Each integration test is expected to finish within ten seconds. WHAT=TestName runs a subset.minutes
make e2e-testThe Bats suite under tests/e2e/, in parallel. It covers the CLI (agentmesh.bats), a containerised mesh with a mock identity provider (container_mesh.bats and the tests built on it), policy, services, A2A, the console, agentmesh-one, and the sandbox. It builds the binaries and images first. WHAT=pattern filters the tests.10 to 30 minutes
make test-e2e-containerOnly the containerised-mesh test.
make ui-testPlaywright against the console, on a stack of local processes with SQLite. make ui-dev starts the same stack and leaves it running for manual use.
make lintgo fmt, Helm lint, then golangci-lint in Docker and a dead-code check. Any exported identifier that no binary and no test reaches fails the check, so new exported API must land together with its tests.about a minute
make verifyChecks that generated code is current and that no secrets are committed.

Put coverage as low in this pyramid as possible. An edge case that a unit or integration test can cover should not become an end-to-end test. The e2e suite exists for a small number of critical user journeys and is slow by nature.

The container tests build images only when they are absent. After you change a binary, run make docker-build before you run them again, or the tests run the old code.

A local mesh in kind

development/kind/ brings up a control plane, a router, a console and Dex in a local kind cluster with one command. It exposes them through Gateway API addresses served by cloud-provider-kind, which must be installed.

make kind-up            # create the cluster, build and load images, deploy; opens a tmux log view
make kind-up ARGS=-s    # the same without the log view
make kind-logs          # reattach the log view
make kind-down          # delete everything

The mesh comes up with no nodes. Put a service on it with the agentmesh-node chart and one of the examples:

./development/deploy-kind-service.sh development/examples/calc-mcp

The script builds the example’s image, loads it into the cluster, and installs a agentmesh-node release with the example’s values.yaml on top of development/kind/agentmesh-node.values.yaml. Any directory with a Dockerfile and a values.yaml works, and extra arguments are passed to Helm.

To use the mesh from a node built from your working tree:

make kind-local-node                   # mints a bootstrap token, runs ./bin/agentmesh-node, API on 127.0.0.1:9099 with token "devtoken"
make kind-local-node ARGS="--config my-node.yaml"

./bin/mcp-client -url http://127.0.0.1:9099/mcp -token devtoken -tool find_remote_tools -args '{}'

make kind-e2e-mesh runs the whole loop without interaction. It deploys calc-mcp, enrolls a local node, discovers mcp://calculator/add, calls it, and checks the answer.

The documentation

The site is Hugo with the Docsy theme, under site/. The deploy workflow pins Hugo 0.136.5, and newer Hugo releases do not build the current Docsy version, so use that release locally too. Run npm ci once in site/ for the CSS pipeline, then hugo server. The site deploys from main to google.github.io/agentmesh. When a page moves, keep its old URL with aliases in the front matter. tests/e2e/docs_snippets.bats runs the Python snippet under site/content/docs/snippets/ against a live node, so a change to that snippet is a change to a test.

Releases and testnets

A v* tag produces a GitHub release with binaries and images through goreleaser, and deploys to the hub.sam-mesh.dev testnet. Every push to main deploys to bananas.sam-mesh.dev. Testnets describes both.