plugin-spice
| Placement | runtime (out-of-process over gRPC) |
| Source | github.com/opencharly/charly/candy/plugin-spice |
| Version | 2026.174.1700 |
| Candy | plugin-spice |
This plugin is not listed in charly/charly.yml’s compiled_plugins:. It is not part of the shipped binary: charly builds and loads it out-of-process over gRPC when a plan references one of its words (the coexist path).
Providers
Section titled “Providers”The reserved words this plugin serves:
spice— verb class
What it does
Section titled “What it does”OUT-OF-TREE charly plugin serving the spice SPICE-wire display/input
check verb — a standalone Go module (go.mod + main.go) that speaks the
SPICE remote-desktop protocol over go-plugin gRPC via the charly plugin
SDK (github.com/opencharly/sdk). charly’s loader fetches this candy’s repo,
go-builds the provider binary on the HOST, and serves it OUT-OF-PROCESS
via LocalTransport — so the github.com/Shells-com/spice library lives
HERE (vendored under third_party/spice), out of charly’s core go.mod, with
its cgo audio channels (the opus/portaudio decoders) removed ENTIRELY so it
is unambiguously pure Go — no opus/portaudio/asound/jack (the fourth
dep-shed after candy/plugin-appium, candy/plugin-adb, candy/plugin-kube).
Since the schema-compaction cutover an authored spice: step desugars to
the internal plugin/plugin_input envelope, and every spice-exclusive
modifier (method/x/y/text/key/artifact/…) lives in the plugin’s OWN
#SpiceInput (schema/spice.cue); the verb
dispatches through the provider registry exactly like a built-in
(ResolveVerb → grpcProvider → invokeVerbProvider hands it the full #Op).
The host owns the go-libvirt VM resolution (vm_target.go’s ResolveVmTarget
- SpiceEndpoint) and any qemu+ssh:// side tunnel, pre-resolving the VM’s live SPICE endpoint to a DIALABLE address it ships in the check env — so this plugin needs no libvirt at all. Provides the full 7-method surface (status/screenshot/cursor/click/mouse/type/key). The R10 consumer is a disposable libvirt VM bed whose desktop check composes this plugin.
Parameter schema
Section titled “Parameter schema”The CUE schema below is the authoritative grammar for this plugin’s input. It is the same single source that generates the plugin’s Go parameter types and answers the runtime Describe RPC, so this page cannot disagree with either.
schema/spice.cue
Section titled “schema/spice.cue”// The `spice` plugin's OWN CUE schema — the typed plugin_input for the `spice`// SPICE-wire check verb. It is the SINGLE SOURCE for this plugin's params, used// two ways (the same contract core `spec` and the http plugin use)://// 1. GENERATE the Go param struct — `cue exp gengotypes` (driven by the cue:gen// pipeline, which wraps this with `package params` + `@go(params)`) emits// ../params/cue_types_gen.go, so the provider decodes plugin_input into a// TYPED struct, never a hand-parsed map.// 2. VALIDATE authored input AT RUNTIME — the plugin serves this source over the// Describe channel; the host splices it onto the base (base ++ plugin) and// validates every authored `spice:` step's plugin_input against #SpiceInput.//// Since the schema-compaction cutover the per-verb fields LEFT core #Op: an// authored `spice: <method>` step (scalar sugar) or `spice: {method: …, x: …}`// (map form) desugars to the INTERNAL plugin/plugin_input envelope, and every// spice-exclusive modifier lives HERE — the former core #SpiceMethod enum is// this def's `method` field. The shared assertion matchers// (exit_status/stdout/stderr) and the general `timeout` stay on core #Op, read// off the step Op by the provider.//// SELF-CONTAINED: it references NO base def, so it compiles standalone// (gengotypes + the load-gate compile) AND splices onto the base (base ++ plugin// is a def-name collision check, not a base-reference resolver).#SpiceInput: { // method — the spice method to dispatch (the former core #SpiceMethod enum; // also the scalar-sugar primary: `spice: <method>`). method: "status" | "screenshot" | "cursor" | "click" | "mouse" | "type" | "key" // x / y — guest-absolute coordinates (click/mouse). x?: int @go(,type=int) y?: int @go(,type=int) // button — the mouse button for click (left/right/middle; default left). button?: string // text — the text `type` types (PC-AT scancode sequence). text?: string // key — the named key `key` presses. key?: string @go(KeyName) // artifact — the host path `screenshot`/`cursor` writes the PNG to. artifact?: string // artifact_min_bytes / artifact_min_dimensions / artifact_not_uniform — the // post-run artifact-reality assertions (sdk.RunArtifactValidators). artifact_min_bytes?: int & >=0 @go(ArtifactMinBytes,type=int) artifact_min_dimensions?: string & =~"^[0-9]+x[0-9]+$" @go(ArtifactMinDimensions) artifact_not_uniform?: bool @go(ArtifactNotUniform)}See also the candy reference for this candy’s install surface.