Skip to main content

Remote Protocol Verification

This page documents the exact HTTP contract that the AgentXchain verifier uses when running --remote. If you are building a conformance server that proves your protocol implementation over HTTP, this is the normative reference.

If you are building a local stdio adapter instead, start with the Protocol Implementor Guide. If you want the CLI flags, see the CLI Reference.

Architecture

The verifier always owns the fixture corpus. In remote mode, the verifier reads fixtures from its local .agentxchain-conformance/fixtures/ directory, sends each fixture to the remote endpoint one at a time, and collects the result. The remote server materializes the fixture, executes the operation against its implementation, and returns a single result object.

This means:

  • The server does not need to host or know about the fixture corpus.
  • The server receives one complete fixture JSON document per request.
  • The server returns one result JSON document per response.
  • The execution model is identical to stdio: one fixture in, one result out.

Endpoints

Your conformance server must expose exactly two endpoints under a base URL:

MethodPathPurpose
GET/conform/capabilitiesReturn the implementation's capabilities document
POST/conform/executeExecute one fixture and return the result

The verifier constructs these by appending the fixed paths to the base URL passed via --remote. If the operator passes --remote https://example.com/myrunner, the verifier calls https://example.com/myrunner/conform/capabilities and https://example.com/myrunner/conform/execute.

GET /conform/capabilities

Request

GET /conform/capabilities HTTP/1.1
Host: example.com
Connection: close
Authorization: Bearer <token>

The Authorization header is only sent when the operator passes --token. If no token is provided, the header is omitted entirely.

Response

Return 200 OK with a JSON body:

{
"implementation": "my-runner",
"version": "1.0.0",
"protocol_version": "v6",
"adapter": {
"protocol": "http-fixture-v1"
},
"tiers": [1, 2, 3],
"surfaces": {
"state_machine": true,
"turn_result_validation": true,
"gate_semantics": true,
"decision_ledger": true,
"history": true,
"config_schema": true
},
"metadata": {
"name": "My Runner",
"url": "https://example.com"
}
}

Required fields

FieldTypeConstraint
implementationstringNon-empty
adapter.protocolstringMust be exactly "http-fixture-v1"
tiersarrayNon-empty, elements must be 1, 2, or 3

Optional fields

FieldTypeNotes
versionstringHuman-readable implementation version
protocol_versionstringProtocol version the implementation targets
surfacesobjectMap of surface names to true. When present, enables surface enforcement
metadataobjectDisplay metadata only

Validation rules

  • adapter.protocol must be "http-fixture-v1". Any other value (including "stdio-fixture-v1") is rejected with: capabilities.adapter.protocol must be 'http-fixture-v1'.
  • adapter.command is not required and is ignored for remote adapters.
  • If surfaces is present and the operator passes --surface X, the verifier fails fast with exit code 2 if X is not declared. If surfaces is omitted, surface filtering works without enforcement.

Error responses

ConditionVerifier behavior
Non-200 HTTP statusError: Failed to fetch remote capabilities: HTTP {status}
Body is not valid JSONError: Invalid capabilities response: {parse error}
Schema validation failsError: Invalid capabilities.json: {details}
Network timeoutError: Failed to fetch remote capabilities timeout after {ms}ms
Connection refused / DNS failureError: Failed to fetch remote capabilities network error: {details}

All of these are fatal. The verifier exits with code 2.

POST /conform/execute

Request

POST /conform/execute HTTP/1.1
Host: example.com
Connection: close
Content-Type: application/json
Content-Length: 1234
Authorization: Bearer <token>

The request body is the full fixture JSON document — the same object that a stdio adapter receives on stdin. The Content-Length header is computed automatically from the serialized body.

Example body:

{
"fixture_id": "SM-001",
"tier": 1,
"surface": "state_machine",
"description": "Completed state rejects assignment",
"type": "reject",
"setup": {
"state": { "status": "completed", "phase": "qa", "run_id": "run_001" },
"config": { "roles": { "dev": { "runtime": "manual" } } }
},
"input": {
"operation": "assign_turn",
"args": { "role_id": "dev" }
},
"expected": {
"result": "error",
"error_type": "invalid_state_transition",
"state_unchanged": true
}
}

Your server must:

  1. Parse the fixture JSON.
  2. Materialize the setup state in your implementation's test workspace.
  3. Execute input.operation against your implementation.
  4. Compare the result against expected.
  5. Return a result JSON document.

Response

Return 200 OK with a JSON body:

{
"status": "pass",
"message": "optional human-readable note",
"actual": null
}

Valid status values

StatusMeaning
passFixture behavior matched expectation
failFixture executed but the behavior was wrong
errorServer could not evaluate the fixture correctly
not_implementedFixture surface is intentionally unsupported

The message field is optional but useful for debugging. The actual field should contain any observed state that differs from expected, or null if not applicable.

Error handling

ConditionVerifier behavior
Non-200 HTTP status, JSON body with messageFixture error: HTTP {status}: {message}
Non-200 HTTP status, non-JSON bodyFixture error: HTTP {status}: {body}
200 but body is not valid JSONFixture error: Malformed response: {parse error}
200 but status field missing or invalidFixture error: Adapter response missing valid "status"
Network timeoutFixture error: HTTP fixture execution timeout after {ms}ms
Connection errorFixture error: HTTP fixture execution network error: {details}

Fixture-level errors do not abort the run. The verifier records them as error status for that fixture and continues with the remaining fixtures.

Authentication

Slice 1 supports a single auth mechanism: optional Bearer token.

When the operator passes --token, the verifier sends Authorization: Bearer {token} on both the capabilities request and every fixture execution request. When no token is provided, the header is omitted.

No other auth mechanisms are supported in the current implementation: no OAuth, no mTLS, no credential stores.

Timeout

The --timeout flag (default: 30000 ms) sets a per-fixture timeout for remote HTTP requests. It applies to each individual POST /conform/execute call and to the initial GET /conform/capabilities call.

When a request exceeds the timeout, the underlying TCP socket is destroyed and the verifier records a timeout error for that fixture (or exits with code 2 for capabilities fetch).

Runnable example

The canonical runnable example lives at examples/remote-conformance-server/.

That example is stronger than an inline snippet because it:

  • wraps the shipped reference fixture engine
  • exposes the exact /conform/capabilities and /conform/execute contract
  • is covered by a contract test that runs real remote verification against it

Start it locally:

cd examples/remote-conformance-server
node server.js

Verify against it:

agentxchain verify protocol --tier 1 --remote http://127.0.0.1:8788 --format json

Optional Bearer auth:

CONFORMANCE_TOKEN=secret123 node server.js
agentxchain verify protocol --tier 1 --remote http://127.0.0.1:8788 --token secret123 --format json

Verify with:

agentxchain verify protocol --tier 1 --remote http://localhost:8080 --format json

Fixture corpus ownership

The verifier ships and owns the canonical fixture corpus. Remote servers never need to host fixtures. The sequence is:

  1. Verifier loads fixtures from its local .agentxchain-conformance/fixtures/ directory.
  2. Verifier sends each selected fixture to POST /conform/execute.
  3. Server materializes, executes, compares, responds.
  4. Verifier collects results into the report.

This means the fixture corpus evolves with the verifier, not with your server. When the verifier adds new fixtures (new tiers, new surfaces, new edge cases), your server gets tested against them automatically. You do not need to update your server to accept new fixtures — you only need to handle the operations they describe.

Report shape in remote mode

When verifying remotely, the JSON report includes:

FieldValue
target_rootnull
remoteThe normalized base URL

All other report fields (implementation, protocol_version, tier_requested, results, overall) are identical to local verification. This means CI pipelines can consume the same report format regardless of verification mode.