TestMesh
Deployment

Site Agent

Run the TestMesh site agent inside your private network to execute flows against internal services — no inbound firewall rules, no VPN, no exposed ports.

The TestMesh site agent runs inside your network and executes flows against your internal services. It connects outbound to the TestMesh control plane via WebSocket — no inbound ports, no firewall changes, no VPN required.

TestMesh Control Plane                Your Private Network
┌──────────────────────┐             ┌──────────────────────────────┐
│  Dashboard           │             │  testmesh-agent              │
│  Scheduling          │◄── WSS ────│  (executes flows locally)    │
│  AI Analysis         │── jobs ───►│                              │
│  PR Write-Back       │◄─ results ─│                              │
└──────────────────────┘             └──────────┬───────────────────┘
                                                │ direct access
                                     ┌──────────┴───────────────────┐
                                     │ internal-api:8080             │
                                     │ postgres:5432                 │
                                     │ kafka:9092                    │
                                     │ redis:6379                    │
                                     └──────────────────────────────┘

Quick Start

1. Get an Agent Token

In the TestMesh dashboard, go to Settings → Agents → New Agent. Copy the generated token — it is shown only once.

You can also create a token via the API:

curl -X POST https://app.testmesh.io/api/v1/agent-tokens \
  -H "Authorization: Bearer <jwt>" \
  -H "Content-Type: application/json" \
  -d '{"workspace_id": "<workspace-id>", "name": "prod-agent"}'

2. Start the Agent

docker run -d \
  -e AGENT_TOKEN=<your-token> \
  -e CLOUD_URL=https://app.testmesh.io \
  --name testmesh-agent \
  --restart unless-stopped \
  testmesh/agent:latest
curl -fsSL https://testmesh.io/install-agent.sh | sh
testmesh-agent start --token <your-token>

Add to your existing docker-compose.yml:

services:
  testmesh-agent:
    image: testmesh/agent:latest
    environment:
      AGENT_TOKEN: <your-token>
      CLOUD_URL: https://app.testmesh.io
    restart: unless-stopped
    # No ports needed — outbound only

3. Verify

The agent appears in Settings → Agents with a green status indicator once connected. Flow runs targeting this agent's workspace will now execute inside your network.


How It Works

  1. Agent dials wss://app.testmesh.io/api/v1/agent/connect with its token
  2. Control plane authenticates the token and registers the agent
  3. When a flow run is triggered (schedule, webhook, manual), the control plane sends the job to the agent over the WebSocket
  4. Agent executes the flow using the embedded runner — the same engine as the open-source API
  5. Step results stream back in real-time; each step is persisted and visible in the dashboard as it completes
  6. On disconnect, the agent retries with exponential backoff; unacknowledged jobs are requeued

Message Protocol

agent → cloud:  { "type": "register", "payload": { "workers": 4, "version": "0.1.0" } }
cloud → agent:  { "type": "job",      "payload": { "id": "...", "definition": {...} } }
agent → cloud:  { "type": "result",   "payload": { "job_id": "...", "type": "step_completed", ... } }
cloud → agent:  { "type": "ping" }
agent → cloud:  { "type": "pong" }

Result types per job: step_startedstep_completed | step_failed (per step) → flow_completed | flow_failed.


Supported Actions

The agent embeds the full OSS runner. Any action that works in local or cloud execution also works via the agent.

Protocol Actions

ActionDescription
http_requestHTTP/HTTPS calls — any method, headers, body, auth
grpc / grpc_call / grpc_streamgRPC unary and streaming calls
websocketConnect, send, and assert on WebSocket messages
kafka_producerPublish messages to Kafka topics
kafka_consumerConsume messages and assert on their content

Data Store Actions

ActionDescription
database_queryRaw SQL against any PostgreSQL-compatible database
db_pollPoll a query until a condition is true (async verification)
redis.*GET, SET, DEL, EXISTS operations on Redis keys
postgresql.*Extended PostgreSQL operations via the native plugin
kafka.*Extended Kafka operations via the native plugin

Flow Control Actions

ActionDescription
conditionBranch steps based on runtime values
for_eachLoop over a list and run sub-steps per item
parallelRun multiple sub-steps concurrently
run_flowEmbed another flow as a sub-flow
wait_forWait for an HTTP endpoint or condition to become true
wait_untilWait with a timeout and expression assertion
delayFixed sleep between steps

Utility Actions

ActionDescription
assertStandalone assertion step using expr-lang expressions
transformReshape or extract data from previous step output
logEmit structured log messages visible in execution output
contract_generateGenerate API contracts from observed traffic
contract_verifyVerify a service against a contract
docker_run / docker_stopStart/stop Docker containers as test fixtures
browserPlaywright-based browser automation

All step results — outputs, assertions, durations, errors — are streamed back to the control plane in real-time and stored in the execution history. You see the same level of detail in the dashboard as you would for a direct cloud execution.


Configuration

FlagEnvironment VariableDefaultDescription
--tokenAGENT_TOKEN(required)Agent token from dashboard
--cloud-urlCLOUD_URLhttps://app.testmesh.ioControl plane URL
--workers4Max concurrent flow executions

The --workers flag currently has no corresponding environment variable. Set it explicitly when starting the agent if you need a value other than the default of 4.


Security Model

The site agent is designed for zero-trust network environments.

PropertyDetail
Outbound-onlyAgent initiates all connections. Your firewall never needs an inbound rule.
Token-scopedEach token is tied to one workspace. Compromising a token does not affect other workspaces.
Secrets stay localEnvironment variables and connection strings are resolved inside the agent and never sent to the control plane.
No raw data leavesOnly execution results and assertion outcomes are sent — not your database records or full API response bodies (unless explicitly captured in output: mappings).
TLS by defaultThe WebSocket connection uses wss:// (TLS) when connecting to the cloud control plane.

For maximum isolation, run the agent in a dedicated network segment with access only to the services it needs to test. The agent does not need internet access — only outbound TCP to the control plane URL and access to your internal services.


Self-Hosted Mode

If you run the full TestMesh stack on your own infrastructure, point the agent at your self-hosted cloud API (port 5017 by default):

testmesh-agent start \
  --token <token> \
  --cloud-url http://testmesh-cloud:5017

The agent relay WebSocket endpoint (/api/v1/agent/connect) lives in the cloud API, which handles token validation, job dispatch, and result persistence. The cloud API proxies everything else to the OSS API.

See Cloud vs Self-Hosted for a full comparison of deployment models.


Programmatic Dispatch

You can dispatch a flow directly to a connected agent via the control plane API — useful for CI pipelines or custom orchestration:

# 1. Get a JWT
TOKEN=$(curl -s -X POST https://app.testmesh.io/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","password":"..."}' | jq -r .access_token)

# 2. Fetch the flow definition
FLOW=$(curl -s "https://app.testmesh.io/api/v1/workspaces/<ws-id>/flows/<flow-id>")
DEFINITION=$(echo $FLOW | jq .definition)

# 3. Dispatch to the agent
curl -X POST https://app.testmesh.io/api/v1/agent/dispatch \
  -H "Content-Type: application/json" \
  -d "{
    \"workspace_id\": \"<ws-id>\",
    \"flow_id\":      \"<flow-id>\",
    \"definition\":   $DEFINITION,
    \"variables\":    { \"env\": \"staging\" }
  }"

The response includes an execution_id you can poll for results:

{
  "job_id": "job-abc123",
  "execution_id": "e1d2c3b4-...",
  "status": "dispatched"
}

Providing flow_id is optional but recommended — it links the execution to the flow in history, pass/fail tracking, and the dashboard.


Scaling

Multiple Agents per Workspace

Deploy agents across environments or regions. Each agent connects independently:

# Staging agent
docker run -d \
  -e AGENT_TOKEN=$STAGING_TOKEN \
  --name testmesh-agent-staging \
  testmesh/agent:latest

# Production agent (read-only tests)
docker run -d \
  -e AGENT_TOKEN=$PROD_TOKEN \
  --name testmesh-agent-prod \
  testmesh/agent:latest

When multiple agents are connected for the same workspace, the control plane dispatches to the first available one.

Worker Concurrency

Each agent runs a fixed number of workers (default 4). Increase for higher throughput:

testmesh-agent start --token <token> --workers 8

Workers execute flows concurrently. A 4-worker agent can run 4 flows simultaneously.

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: testmesh-agent
spec:
  replicas: 2
  selector:
    matchLabels:
      app: testmesh-agent
  template:
    metadata:
      labels:
        app: testmesh-agent
    spec:
      containers:
        - name: agent
          image: testmesh/agent:latest
          env:
            - name: AGENT_TOKEN
              valueFrom:
                secretKeyRef:
                  name: testmesh-agent
                  key: token
            - name: CLOUD_URL
              value: "https://app.testmesh.io"
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: "1"
              memory: 512Mi

Building from Source

cd agent
go build -o testmesh-agent .

# Or with Docker (from repo root)
docker build -f agent/Dockerfile -t testmesh/agent:local .

Troubleshooting

Agent not connecting

  • Verify the token is correct and not revoked (Settings → Agents)
  • Check outbound connectivity: curl -I https://app.testmesh.io/health
  • If behind a corporate proxy, set HTTPS_PROXY before starting the agent
  • Check logs: docker logs testmesh-agent

Flows failing on the agent

  • If a flow works locally via testmesh run, it should work on the agent — both use the same runner
  • Verify the agent can reach your internal services: docker exec testmesh-agent curl http://internal-api:8080/health
  • Environment variables and connection strings must be set on the agent container, not on the control plane
  • Check that service URLs in your flow use the hostnames the agent can resolve, not localhost

Agent disconnects frequently

  • The agent auto-reconnects with exponential backoff (starts at 5s)
  • Frequent disconnects may indicate network instability or a proxy terminating long-lived WebSocket connections
  • Configure your proxy or load balancer to allow long-lived WebSocket connections (no idle timeout) on the control plane URL

What's Next

On this page