Register a service class
When a service has several related operations, register the whole class or instance — each instrumented method becomes a VPoint.- Python —
vz.register()takes one function, class, or instance per call;@vz.componentregisters a class at definition time;vz.discover()scans the calling module and registers everything. Registration blocks until the registry confirms the schema (up to 5s, fail-open). - Go — method names convert PascalCase → kebab-case, prefixed by the
varianz:"..."struct tag (CalculatePrice→pricing/calculate-price). Call through the returned proxy (proxy.Call(ctx, "CalculatePrice", req)) or generate typed proxies withvarianz-gen. - Java/Kotlin — the annotation processor generates a
<ClassName>VPointsaggregate at compile time; thevarianz-agentintercepts calls to the annotated methods at class-load time, so ordinary calls (service.calculate(...)) route through the pipeline with no code changes.RegistryBinding.init()is idempotent and must run before your server starts serving. - TypeScript — for plain objects instead of classes, use
createVPoints(namespace, api); call through the returnedinstrumentedproxy (or pass{ patch: 'mutate' }to instrument the object in place). Calls made on the original object with the defaultwrapmode are not intercepted.
Migrate an existing function
Rename the original, wrap it, keep every caller working:gRPC handlers
Don’t instrument gRPC handler methods that takeStreamObserver or servicer plumbing directly — the schema would be polluted with transport types. Extract the business logic into a plain-typed method and instrument that:
ChargeResponse, not hipstershop.ChargeResponse). In Go, CEL struct literals handle nested proto messages directly — Money { currency_code: "USD", units: 42 } inside a parent literal works without flattening.
Remember to add the session interceptor to your server — without it, test sessions never reach these VPoints.
Field names in schemas
Schemas use each language’s natural field naming, so CEL expressions match what your API already looks like:- Go — precedence:
varianz:"name"tag →protobuftag →jsontag →snake_caseof the Go name. Codegen types (oapi-codegen, sqlc, protoc) work automatically via theirjsontags.varianz:"-"excludes a field;varianz:"note,opaque"passes it through without exposing it to CEL. - Python — annotation-derived; dataclasses, Pydantic models, attrs classes, and proto messages are introspected.
opaque=[...]marks parameters that pass through uninspected. - Java/Kotlin — fields discovered from getters or public fields, converted camelCase → snake_case for CEL (
basePrice→base_price). Kotlinvalmaps to read-only,varto read-write. - TypeScript — the scanner derives fields from your TS types;
@field({ kind: ... })overrides individual kinds.
Context functions
Register helper functions your CEL expressions can call asctx.<name>(...) — useful for domain logic tests shouldn’t have to re-implement:
ctx.applyTax(invoke(), 0.1). Functions can be global (available to every VPoint) or scoped to a profile.
Verify it worked
Start the service withVARIANZ_ENABLED=true and a registry endpoint, and watch the startup log for the single [varianz] ENABLED (...) line. Then confirm registration from the test side: insert a stage with await_sync_or_fail and check it reports one confirmed subscriber, or query the catalog with the list_vpoints MCP tool. A sync result of “0 of 0 subscribers” means the service isn’t connected — see How tests work.