TheVisual Analytics Context Protocol (VACP)gives an agent a semantic account of a visual-analytics application: what views and interactions exist, what state they are in, and which named actions are safe to execute. Theofficial repositorydescribes this as a small in-app contract. Semiotic's experimental bridge translates its existing chart grounding, LinkedCharts state, and accessible navigation into that contract.
Compatibility statusThis is dependency-free structural compatibility with VACP schema 0.1.0, not official provider certification. At the time this bridge was developed, the officialworkspace and@vacp/core packageare versioned 0.1.0 but marked private, so Semiotic does not add an unpublished package dependency. Theunstable_ prefix remains until the public packages, conformance surface, and integration patterns settle.
The translation boundary
Grounding + config → capabilitiesReader grounding, serializable ChartConfig, encodings, annotations, and bounded data handles become nodes and edges in the VACP semantic graph.
Selections + navigation → stateLinkedCharts named selections, observations, and the accessible navigation tree become state keyed by durablevacp:// refs.
Bindings → semantic actionsNamed selection mutations and navigation activation are advertised only when the host provides a callback. Action parameters are validated against declared refs, modes, fields, and datum keys.
Data stays boundedConfig snapshots omit raw collections. Agents receive data handles and schema summaries; row sampling is a separate, explicitly enabled, size-limited action.
Live bridge lab
This chart installs the documented window.__vacp bridge. Use the buttons to exercise its validated action boundary, or open DevTools and call await window.__vacp.getCapabilities(),await window.__vacp.getState(), andawait window.__vacp.execute(...). The capability graph carries the Operations review audience profile used by the outreach exercise.
Installing the live bridge…
Active navigation id: root. The same bridge is available in DevTools, so the outreach exercise can inspect capabilities, audience metadata, state, and actions directly.
A protocol exchange
Step through fixed explanatory payloads for the same chart. The live lab above is the executable bridge; these panels make its three calls easier to compare.
bridge.getCapabilities()Grounding and serializable chart config become a semantic graph. Actions appear only when the host supplies a matching binding.
Representative 0.1.0 response
JSON
{ "version": "0.1.0", "createdAt": "2026-07-25T12:00:00.000Z", "graph": { "version": "0.1.0", "nodes": [ { "ref": "vacp://revenue-console/view/main/visualization/regional-revenue", "kind": "Visualization", "layer": "VisualizationLayer", "title": "Revenue by region", "data": { "component": "BarChart", "grounding": { "intent": "Compare regional revenue", "physics": "Bar length encodes revenue" } } }, { "ref": "vacp://revenue-console/view/main/selection/region-focus", "kind": "Selection", "layer": "InteractionFeedbackLayer", "data": { "name": "region-focus", "fields": [ "region" ], "modes": [ "point" ] } } ], "edges": [ { "from": "vacp://revenue-console/view/main/selection/region-focus", "to": "vacp://revenue-console/view/main/visualization/regional-revenue", "kind": "controls" } ], "actions": [ { "name": "semiotic.set_point_selection", "description": "Set a named LinkedCharts point selection using allowlisted fields.", "targetRef": "vacp://revenue-console/view/main", "parameters": { "type": "object", "required": [ "selectionRef", "fields" ] } } ] } }
React: bind the bridge to LinkedCharts
Render the bridge inside the same LinkedCharts provider as the charts it describes. The component renders no DOM; it reads current selection and observation stores and installs an ownership-safe in-page bridge after the client commits.
JSX
import { BarChart, LinkedCharts } from "semiotic" import { unstable_SemioticVACPBridge as SemioticVACPBridge, } from "semiotic/experimental" const chartProps = { data, categoryAccessor: "region", valueAccessor: "revenue", title: "Revenue by region", } <LinkedCharts> <SemioticVACPBridge appId="revenue-console" charts={[{ chartId: "regional-revenue", component: "BarChart", props: chartProps, grounding: { includeStructure: true }, selections: [{ name: "region-focus", fields: ["region"], mode: "point", }], navigation: { tree: navigationTree, matchFields: ["region"], activeId, onActiveChange: setActiveNode, }, }]} /> <BarChart {...chartProps} selection={{ name: "region-focus" }} /> </LinkedCharts>
Framework-free: construct the same contract
For a non-React host, SSR preparation, or a custom store, construct the bridge directly and provide live getters plus the mutations the agent may invoke.
TS
import { unstable_createSemioticVACPBridge, } from "semiotic/experimental/vacp" const bridge = unstable_createSemioticVACPBridge({ appId: "revenue-console", charts: () => chartDescriptors, getSelections: () => serializedSelections, selectionActions: { setPointSelection(name, clientId, fields) { selectionController.setPoint(name, clientId, fields) }, clearSelection(name) { selectionController.clear(name) }, }, }) const capabilities = bridge.getCapabilities() const state = await bridge.getState() const result = await bridge.execute({ callId: "agent-call-17", name: "semiotic.set_point_selection", params: { selectionRef: bridge.refs.selection("region-focus"), fields: { region: ["North"] }, }, })
Protocol, transport, and visual verification
The officialtool contractdefines the stable transport-facing surface asvacp_capabilities, vacp_state, andvacp_execute. A transport adapter can map those tools to the in-page getCapabilities, getState, andexecute methods. MCP is one possible transport; it is not the bridge itself.
Likewise, a screenshot can verify that an action produced the intended visual outcome, but pixels are not required for discovery, state reading, or control. The semantic graph and validated action bridge are the primary contract; vision remains optional evidence rather than an inferred DOM or click API.
What the unstable contract promises
- VACP
0.1.0 envelopes, semantic graph layers, stable refs, state snapshots, and call-correlated action results. - No synthesized clicks, DOM-order identity, arbitrary callback access, or raw-row exposure by default.
- No claim that structural compatibility is official VACP conformance while its packages and conformance suite are unpublished.
See alsoReader Grounding for the semantic source material andPortability Spec for Semiotic's library-neutral chart metadata.