vastlint-grpc
vastlint-grpc is the network surface of the same Rust catalog the CLI, WASM validator, and MCP server already use. It serves openadtech.vastlint.v1 over HTTP/2 with server reflection and grpc.health.v1. Image: aleksuix/vastlint-grpc:0.13.0, FROM scratch.
A validator that can only be called from a shell runs in CI and nowhere else. This is the transport for callers that need a verdict inside a request budget, on a language that cannot load the core in-process, or on a pipeline that already speaks gRPC.
Which surface to pick
| Caller | Surface | Why |
|---|---|---|
| Go / Rust / Python / Erlang | In-process (ad server guide) | No network hop. Bid-path QPS. |
| JVM (Prebid Server Java, Spring, Vert.x) | gRPC + vastlint-java | No JNI on the event loop. Sidecar owns the catalog. |
| Chat / IDE agents (Claude, Cursor) | MCP | Tool calling, hosted SSE at vastlint.org/mcp. |
| ARTF host, SSAI stitcher, bulk catalog | gRPC Validate / ValidateStream | Already on gRPC. Streaming for thousands of tags. |
| CI / pre-commit | CLI | Exit code, no daemon. |
Run it
Published image, no local Rust toolchain:
docker run --rm -p 50051:50051 -p 9090:9090 aleksuix/vastlint-grpc:0.13.0Local build from the repo:
docker compose up grpc
# from https://github.com/aleksUIX/vastlintKubernetes starter: deploy/k8s/vastlint-grpc.yaml. Readiness and liveness are native gRPC probes on 50051. Metrics on 9090.
Reflection is on, so grpcurl needs no local proto:
grpcurl -plaintext localhost:50051 list
grpcurl -plaintext localhost:50051 describe openadtech.vastlint.v1.VastlintService
grpcurl -plaintext -d '{"document":"<VAST version=\"4.1\"></VAST>"}' \
localhost:50051 openadtech.vastlint.v1.VastlintService/Validate
grpcurl -plaintext -d '{}' localhost:50051 grpc.health.v1.Health/CheckRPCs
| RPC | Shape | Use |
|---|---|---|
Validate | Unary | One document. Bid, stitch, upload gate. |
Fix | Unary | Deterministic repairs (HTTP to HTTPS, dropped deprecated attrs). |
ListRules | Unary | The 228-rule catalog. Cache it; it is static per binary. |
ValidateStream | Bidi stream | Bulk. Responses can arrive out of order; correlate on request_id. |
Contract: proto/openadtech/vastlint/v1/vastlint.proto. buf breaking runs against main on every PR. Rule IDs are strings, not a proto enum, so a new rule is not a wire-contract change. Unknown IDs in rule_overrides return INVALID_ARGUMENT, not a silent no-op. Every verdict carries Provenance (catalog version, digest, engine).
Java
Go embeds the core through CGo. Java does not. A JNI load on Vert.x or Netty is a crash domain. vastlint-java is a blocking stub over this server.
implementation("io.openadtech:vastlint:0.13.0")GitHub Packages: io.openadtech:vastlint:0.13.0. JitPack: com.github.aleksUIX:vastlint-java:v0.13.0. Setup: vastlint-java README.
try (VastlintClient client = VastlintClient.connect("localhost:50051")) {
Verdict verdict = client.validate(xml);
if (!verdict.getValid()) {
// reject the bid, quarantine the creative, or return rule IDs upstream
}
}Default deadline is 5 seconds. Against a load balancer that terminates TLS, use VastlintClient.connectTls(target). The server itself speaks plaintext; put TLS on the ingress.
ARTF and agent pipelines
ARTF (Agentic Real Time Framework) puts a container beside an SSP or exchange and lets an agent mutate the OpenRTB auction object before any buyer sees it. Named uses: identity, deal and segment activation, fraud pre-impression. That hop is a different document from VAST. RTBlint checks the envelope and the applied OpenRTB. VASTlint does not.
After the auction clears, the creative still has to play. adm, a wrapper chain, an SSAI stitch, a trafficking upload: those are VAST documents. An agent that already speaks gRPC into the host can call VastlintService.Validate on that hop with the same catalog the trafficker used in CI. MCP stays the right interface for chat agents; gRPC is the right interface for the pipeline that already has a channel, a deadline, and a sidecar mesh.
ARTF host
OpenRTB bid request → RTBlint gRPC → forward or drop
VAST in adm / stitch → vastlint-grpc → quarantine or serve
Chat / IDE agent
validate_vast → vastlint-mcp (SSE or stdio)Full agentic setup (MCP, AAMP Buyer SDK, AdCP): Agentic ad delivery.
Load behaviour
Adaptive concurrency (AIMD) sheds with RESOURCE_EXHAUSTED rather than queueing. Health and reflection are exempt, so a busy instance does not look dead to the load balancer. Client grpc-timeout is honoured. Streams are admitted per message, not per call: a long-lived ValidateStream must not occupy one concurrency slot for its whole lifetime.
Method, ramp, and SLO: LOAD-TEST.md. Operator notes: crate README.
See also
- Ad server integration (in-process Go / Rust / Erlang)
- MCP server (chat and IDE agents)
- Agentic ad delivery (AAMP, ARTF, AdCP)
- Validate VAST in CI
- vastlint-java