Documentation
¶
Overview ¶
Pure structural methods on the generated/aliased spec types, relocated here from package main by the CUE-single-source cutover (WF-B THE REPOINT). A method on an aliased type (e.g. type BoxConfig = spec.Box in package main) cannot be declared in package main — the type is foreign — so every method that touches ONLY the type's own fields + the stdlib lives here, beside the type it acts on. Methods that reach package-main internals (VerbCatalog, Phase/Venue, EmitOpts, the readiness/preempt consts, …) stay in package main as free functions taking a *spec.X — they are NOT here. STANDALONE: this package imports nothing from package main.
Charly-name aliases for the generated `spec` types.
WF-B repoints package main onto this package via zero-churn `type <CharlyName> = spec.<CharlyName>` aliases. For that to compile the spec package must EXPOSE every param type under its charly name. The DEFMAP names the (cue-def → charly) mapping.
MECHANISM (RDD finding): `cue exp gengotypes` v0.16.1 does NOT propagate a def-level `@go(CharlyName)` rename to the FIELDS that reference that def — the referencing field keeps the original def name and the emitted Go dangles (uncompilable). Verified on a live spike. So the charly NAME is exposed here as a Go type alias (`type BoxConfig = Box`) instead of via a def-level attribute: identical drop-in semantics (the alias and the generated type are the SAME type), zero generated-file churn, and no broken references. The field-level `@go(GoName,…)` attributes (which DO work) carry the per-field name + pointer + type overrides in schema/*.cue.
HAND-WRITTEN — not emitted by `task cue:gen`; the reproducibility gate (gen_repro_test.go) only covers cue_types_gen.go + vocab_gen.go.
Hand-written types for shapes `cue exp gengotypes` cannot express faithfully:
- PortSpec — the candy `port:` element is a (int | "proto:port") disjunction the Go normalizer canonicalizes to {port, protocol}; gengotypes degrades the disjunction to `any`.
- VmDeployState — MACHINE-WRITTEN runtime deploy state. Its CUE def carries an open `...` tail (forward-evolving state record), which makes gengotypes degrade the whole def to `map[string]any`. The hand Go field is a CONCRETE struct, so #VmDeployState is @go(-)'d and the faithful struct (+ its nested state sub-types) is mirrored HERE.
Ported from the package-main param structs (the source of truth); keep in lockstep until WF-B repoints package main onto this package. STANDALONE — no package-main symbol is referenced.
Scalar collapses for the CUE-single-source cutover (WF-B THE REPOINT).
CUE validates these named scalars (CalVer/EntityRef/CandyRef pattern strings, VmSize/Size/PortPin/Duration patterns, the 11 live-verb method enums, the build-format/-type enums) at load — so the Go side gains nothing from a DISTINCT named string type, and package-main code uses plain string/[]string throughout. The matching CUE defs are `@go(-)` (no generated named type); the referencing fields keep the def name, which these Go ALIASES resolve to the builtin. An alias (not a defined type) is load-bearing: `&op.Cdp` is a `*string`, `[]PortPin` IS `[]string`, and an untyped/string assignment to a CalVer/EntityRef field just works — exactly the charly drop-in semantics.
MECHANISM (RDD finding, mirrors spec/charly_names.go): `cue exp gengotypes` v0.16.1 does NOT propagate a def-level rename/suppression to the FIELDS that reference the def, so a bare `@go(-)` leaves the field dangling on the deleted name. Exposing the name as a Go alias here makes every reference compile while collapsing the Go type to the builtin.
HAND-WRITTEN — not emitted by `task cue:gen`.
Hand-written union / shorthand types for the generated `spec` package.
`cue exp gengotypes` degrades every CUE disjunction to `any` / `map[string]any` / an empty struct (the Go type system cannot express a disjunction). For the handful of schema defs whose Go shape charly relies on, the matching CUE def is annotated `@go(-)` in schema/*.cue (suppressing the lossy generated type) and the faithful type is hand-written HERE, in the SAME package, so the generated structs reference these by name. These are ported from the hand-written charly param types (the source of truth named in each comment); keep them in lockstep until WF-B repoints package main onto this package.
STANDALONE: this package builds on its own (`go build ./spec/...`) and reaches into NO package-main symbol — every method here is self-contained.
Index ¶
- Constants
- Variables
- func NormalizePCIVendor(s string) string
- type AUR
- type AdbEndpoint
- type Agent
- type AliasConfig
- type AliasYAML
- type AlpineBootstrap
- type Android
- type AndroidDeployVenue
- type AndroidSpec
- type ApkPackageSpec
- type ArbiterBoolReply
- type ArbiterErrReply
- type ArbiterGatherReply
- type ArbiterGpuCDIReply
- type ArbiterHolderReq
- type ArbiterInvokeInput
- type ArbiterInvokeReply
- type ArbiterResourcesReply
- type ArbiterSwitchReply
- type ArbiterSwitchReq
- type ArtifactView
- type BaseUser
- type Bootloader
- type Bootstrap
- type Box
- type BoxAlias
- type BoxConfig
- type BoxMerge
- type BuildEnv
- type BuildFormat
- type BuildReply
- type BuildRequest
- type BuildType
- type Builder
- type BuilderCollectInput
- type BuilderCollectReply
- type BuilderDef
- type BuilderResolveInput
- type BuilderResolveReply
- type BuilderReverseInput
- type BuilderReverseReply
- type BundleNode
- type CacheMount
- type CacheMountView
- type CalVer
- type Candy
- type CandyAlias
- type CandyArtifact
- type CandyArtifactRewrite
- type CandyCapabilities
- type CandyCapability
- type CandyData
- type CandyExtract
- type CandyHook
- type CandyMCPProvide
- type CandyRef
- type CandyRoute
- type CandySecret
- type CandyService
- type CandyServiceOverrides
- type CandyVolume
- type CandyYAML
- type Check
- type CliReply
- type CliRequest
- type Context
- type Copy
- type CredentialHealth
- type CredentialMount
- type DataYAML
- type Debootstrap
- type DebootstrapRepo
- type Deploy
- func (n *Deploy) HasChildren() bool
- func (c Deploy) IsDisposable() bool
- func (c Deploy) IsEphemeral() bool
- func (c Deploy) IsGroup() bool
- func (c Deploy) IsPreemptible() bool
- func (c Deploy) LifecycleTag() string
- func (c Deploy) PreemptionHolds() []string
- func (c Deploy) RequiredExclusive() []string
- func (c Deploy) RequiredShared() []string
- type DeployExpose
- type DeployProbes
- type DeployReply
- type DeployReplyRecord
- type DeployResources
- type DeploySecret
- type DeployShellOverlay
- type DeployStorage
- type DeployVenue
- type DeployVolume
- type DetectedDevices
- type Diagnostic
- type Diagnostics
- type Distro
- type DistroDef
- type DistroPackages
- type Dnf
- type Duration
- type EmitReply
- type EncExecInput
- type EncExecReply
- type EncVolumePlan
- type EntityRef
- type EnvDependency
- type EnvVar
- type EphemeralLifetime
- type EphemeralRuntime
- type ExtractYAML
- type FeatureEntity
- type FeatureReply
- type FeatureRequest
- type FeatureStep
- type Format
- type FormatRule
- type GoogleAccount
- type GpuProbeInput
- type GpuProbeReply
- type GpuSelector
- type GpuSwitchInput
- type GpuSwitchReply
- type HolderAddr
- type HolderDescriptor
- type HooksConfig
- type HostEnv
- type HostProbeDevice
- type HostProbeDistro
- type HostProbeReply
- type HostProbeRequest
- type Init
- type InitDef
- type InitServiceSchema
- type InstallOpts
- type InstallOptsConfig
- type InstallPlanView
- type InstallStepView
- type Iterate
- type IterateConfig
- type K8s
- type K8sDeploy
- type K8sDeployVenue
- type K8sGatewayAPI
- type K8sGenFile
- type K8sGenInput
- type K8sGenReply
- type K8sHostname
- type K8sImagesDefaults
- type K8sIngressDefaults
- type K8sObservability
- type K8sPatch
- type K8sPodDefaults
- type K8sResourceDefaults
- type K8sResourceValues
- type K8sResources
- type K8sSecretsBackend
- type K8sSpec
- type K8sStorage
- type LibvirtAudio
- type LibvirtCPU
- type LibvirtCPUCache
- type LibvirtCPUFeature
- type LibvirtCPUTopology
- type LibvirtCPUTune
- type LibvirtChannel
- type LibvirtClock
- type LibvirtConsole
- type LibvirtDevices
- type LibvirtDisk
- type LibvirtDomain
- type LibvirtEmulatorPin
- type LibvirtFeatures
- type LibvirtFilesystem
- type LibvirtGraphics
- type LibvirtGraphicsListen
- type LibvirtGraphicsListeners
- type LibvirtHostdev
- type LibvirtHub
- type LibvirtHugepages
- type LibvirtHyperV
- type LibvirtIOMMU
- type LibvirtIOThreadPin
- type LibvirtInput
- type LibvirtInterface
- type LibvirtKVM
- type LibvirtLaunchSecurity
- type LibvirtListenOne
- type LibvirtMemBalloon
- type LibvirtMemTune
- type LibvirtMemnode
- type LibvirtMemoryBacking
- type LibvirtNUMACell
- type LibvirtNUMAMemory
- type LibvirtNUMATune
- type LibvirtPCIHex
- type LibvirtPanic
- type LibvirtParallel
- type LibvirtPortForward
- type LibvirtRNG
- type LibvirtRedirDev
- type LibvirtResource
- type LibvirtSecLabel
- type LibvirtSerial
- type LibvirtShmem
- type LibvirtSmartcard
- type LibvirtSound
- type LibvirtSpinlocks
- type LibvirtSysInfo
- type LibvirtTPM
- type LibvirtTimer
- type LibvirtUSB
- type LibvirtVCPUPin
- type LibvirtVendorID
- type LibvirtVideo
- type LibvirtVsock
- type LibvirtWatchdog
- type LifecycleOpts
- type LifecyclePrepareInput
- type Local
- type LocalPkg
- type LocalSpec
- type MCPServerYAML
- type MatchOpMap
- type Matcher
- type MatcherList
- type MergeConfig
- type Op
- type OverlayBuildReply
- type OverlayBuildRequest
- type PackageItem
- type Pacstrap
- type PacstrapRepo
- type PhaseSet
- type PhaseTemplates
- type Plugin
- type PluginCapability
- type Pod
- type PodSidecar
- type PodSpec
- type PortPin
- type PortScope
- type PortSpec
- type PostTeardownReply
- type PreemptLease
- type PreemptLedger
- type PreemptedHolder
- type PreemptibleConfig
- type PrepareVenueReply
- type Readiness
- type ReadinessConfig
- type RepoBlock
- type Resource
- type ResourceDef
- type RetentionReply
- type RetentionRequest
- type ReverseOp
- type ReverseOpKind
- type RouteYAML
- type Scope
- type SecretYAML
- type Security
- type SecurityConfig
- type ServiceEntry
- type SettingsEntry
- type SettingsReply
- type SettingsRequest
- type Shell
- type ShellSpec
- type Sidecar
- type SidecarDef
- type SidecarSecret
- type SidecarVolume
- type Size
- type StandaloneLoad
- type Step
- type StepEmitRequest
- type StepKeyword
- type StrMap
- type StrVal
- type StructuralKindLoadEnv
- type TunnelYAML
- type VFIOGpu
- type VFIOPCIDevice
- type VFIOReport
- type VenueDescriptor
- type Vm
- type VmCharlyInstall
- type VmChecksum
- type VmCloudInit
- type VmCloudInitFile
- type VmCloudInitMirrors
- type VmCloudInitNetwork
- type VmCloudInitUser
- type VmDeployState
- type VmKeyInjection
- type VmKeyInjectionResolved
- type VmNetwork
- type VmSSH
- type VmSize
- type VmSnapshot
- type VmSnapshotDecl
- type VmSnapshotState
- type VmSource
- type VmSpec
- type VolumeYAML
Constants ¶
const ( // PreemptStopShutdown is the only supported stop mechanism (graceful ACPI // shutdown / podman stop; disk preserved). PreemptStopShutdown = "shutdown" // PreemptRestoreAlways restarts the holder regardless of the claim's outcome // (the default). PreemptRestoreAlways = "always" // PreemptRestoreSuccess restarts the holder only if the claim released cleanly; // on a failed claim it is left stopped for operator inspection. PreemptRestoreSuccess = "on-success" )
const ( ArbiterSeamGather = "gather" // -> ArbiterGatherReply (preemptible holders, projected) ArbiterSeamResources = "resources" // -> ArbiterResourcesReply (gpu-backed tokens -> vendor) ArbiterSeamRunning = "running" // ArbiterHolderReq -> ArbiterBoolReply ArbiterSeamStop = "stop" // ArbiterHolderReq -> ArbiterErrReply (stop + wait-until-stopped) ArbiterSeamStart = "start" // ArbiterHolderReq -> ArbiterErrReply ArbiterSeamSwitch = "switchMode" // ArbiterSwitchReq -> ArbiterErrReply (routes to plugin-gpu) ArbiterSeamEnsureCDI = "ensureCDI" // (no payload) -> (no reply) ArbiterSeamGpuCDI = "gpuCDI" // (no payload) -> ArbiterGpuCDIReply (running charly GPU-CDI pods) )
const ( ArbiterActionAcquireExclusive = "acquire-exclusive" ArbiterActionRelease = "release-claimant" ArbiterActionStatus = "status" ArbiterActionReconcile = "reconcile-stranded" ArbiterActionClearPoison = "clear-poison" ArbiterActionResourcePoisoned = "resource-poisoned" )
const ( EncMethodMount = "mount" // mount the not-yet-mounted volumes (init must already exist) EncMethodUnmount = "unmount" // fusermount3 -u + stop the scope unit EncMethodEnsure = "ensure" // auto-init then mount (charly start transparent setup) EncMethodPasswd = "passwd" // gocryptfs -passwd for every initialized volume )
EncMethod selects which gocryptfs operation plugin-enc runs.
const ( // GpuModeVfio — EVERY function of the GPU's IOMMU group bound to vfio-pci // (free for VM passthrough; the boot default on a passthrough host). GpuModeVfio = "vfio" // GpuModeNvidia — each function on its correct host driver (display -> nvidia // for CDI-shared pods, HDMI-audio -> snd_hda_intel). GpuModeNvidia = "nvidia" // NvidiaVendorID is the normalized PCI vendor of NVIDIA cards (the device_lock // wedge is an nvidia-driver concept). NvidiaVendorID = "0x10de" // HostDriverDisplay / HostDriverAudio / HostDriverVfio are the host drivers a // group function binds to: the display (VGA/3D, class 0x03xx) takes nvidia in // host mode; the HDMI-audio (class 0x0403) takes snd_hda_intel; everything takes // vfio-pci for passthrough. HostDriverDisplay = "nvidia" HostDriverAudio = "snd_hda_intel" HostDriverVfio = "vfio-pci" )
const ( GpuSwitchActionMode = "switch-mode" // GpuSwitchInput{Gpu?,Vendor?,Mode} -> flip the group's driver mode (Gpu set = exact card; Vendor set = tolerant vendor-select) GpuSwitchActionEnsureCDI = "ensure-cdi-root" // regenerate /etc/cdi/nvidia.yaml as ROOT (distinct from the C11 user-scope "ensure-cdi" detection action) GpuSwitchActionWedgeDetected = "wedge-detected" // read-only D-state probe -> Bool GpuSwitchActionGroupInMode = "group-in-mode" // GpuSwitchInput{Gpu,Mode} -> Bool GpuSwitchActionCurrentMode = "current-mode" // GpuSwitchInput{Gpu} -> Str (vfio|nvidia) GpuSwitchActionDisplayDriver = "display-driver" // GpuSwitchInput{Addr} -> Str (live driver of a PCI function) GpuSwitchActionPlan = "switch-plan" // GpuSwitchInput{Gpu,Mode} -> Plan (DRY-RUN commands; NO sysfs write) — the C9 cred/hw-free dispatch proof )
GPU driver-switch actions served by verb:gpu (cutover C9).
const ReverseOpPluginScriptKey = "script"
ReverseOpPluginScriptKey is the Extra map key carrying a ReverseOpPluginScript's shell-script body. Exported so both the host handler and the SDK builder name the one key (R3 — no magic-string drift across the process boundary).
const SchemaFloor = "2026.174.1100"
SchemaFloor is the oldest schema version `charly migrate` can migrate FROM (schema/version.cue #SchemaFloor).
const SchemaVersion = "2026.186.2323"
SchemaVersion is the HEAD schema CalVer (schema/version.cue #SchemaVersion).
Variables ¶
var AuthoringVerbs = []string{
"build",
"cache",
"caps",
"comment",
"content",
"context",
"copy",
"depends_on",
"description",
"download",
"env",
"eventually",
"exclude_distro",
"exit_status",
"extract",
"extract_include",
"id",
"link",
"mkdir",
"mode",
"retry_interval",
"run_as",
"setcap",
"skip",
"stderr",
"stdout",
"strip_components",
"tag",
"target",
"timeout",
"to",
"uninstall",
"write",
}
AuthoringVerbs is the AUTHORABLE #Op field vocabulary (#Op fields minus the never-authored origin/venue/intent_do/plugin/plugin_input/command).
var ContextWords = []string{
"build",
"deploy",
"runtime",
}
ContextWords is the plan-step execution contexts (#Context).
var DocDirectives = []string{
"compiled_plugins",
"context_ignore_baseline",
"defaults",
"device_descriptions",
"device_patterns",
"discover",
"distro_family_map",
"distro_package_managers",
"gpu_vendors",
"import",
"install_hints",
"ovmf_distro_aliases",
"ovmf_paths",
"pci_class_labels",
"providers",
"provides",
"repo",
"version",
}
DocDirectives is the reserved document directives (#NodeDoc top-level keys).
var ErrGPUSwitchWedged = errors.New("GPU driver switch wedged: nvidia .remove stuck holding the device_lock — host reboot required")
ErrGPUSwitchWedged signals that a GPU driver switch did not complete because the nvidia `.remove` is stuck holding the device_lock (deadline exceeded, or a self-detected D-state task in nv_pci_remove). candy/plugin-gpu carries the wedge as a bool over the wire (GpuSwitchReply.Wedged); the core gpu shim maps that bool back to this sentinel so callers (vm_gpu_cmd) keep matching it with errors.Is. Recovery is a host reboot.
var KindValueDefs = map[string]string{
"android": "#AndroidValue",
"candy": "#CandyValue",
"k8s": "#K8sValue",
"local": "#LocalValue",
"pod": "#PodValue",
"vm": "#VmValue",
}
KindValueDefs is the word→#<Kind>Value CUE-def map the host uses to closedness-gate a substrate/candy node's authored VALUE (validateKindValueCUE). DERIVED from the #<X>Value defs themselves (every one except the shared #DeployValue disjunct), so a new value-gated kind needs no hand-maintained map.
var KindWords = []string{}
KindWords is the reserved kind keywords (the #Node disjunction discriminators).
var OpFields = []string{
"build",
"cache",
"caps",
"command",
"comment",
"content",
"context",
"copy",
"depends_on",
"description",
"download",
"env",
"eventually",
"exclude_distro",
"exit_status",
"extract",
"extract_include",
"id",
"intent_do",
"link",
"mkdir",
"mode",
"origin",
"plugin",
"plugin_input",
"retry_interval",
"run_as",
"setcap",
"skip",
"stderr",
"stdout",
"strip_components",
"tag",
"target",
"timeout",
"to",
"uninstall",
"venue",
"write",
}
OpFields is every #Op verb/modifier field name (the flat Op vocabulary).
var OpVerbs = []string{
"mkdir",
"copy",
"write",
"link",
"download",
"setcap",
"build",
"plugin",
}
OpVerbs is the verb DISCRIMINATOR vocabulary (#OpVerb) — the exactly-one-set verb subset of #Op fields (Op.Kind() + the VerbCatalog dispatch table gate against it).
var ResourceKinds = []string{
"pod",
"vm",
"k8s",
"local",
"android",
"group",
}
ResourceKinds is the DEPLOYABLE subset of the kind keywords — the kinds whose #Node arm nests a sub-ENTITY (resource) child (#ResourceKind).
var StepKeywords = []string{
"agent-check",
"agent-run",
"check",
"include",
"run",
}
StepKeywords is the plan-step intent keywords (#Step arms minus #Op fields).
Functions ¶
func NormalizePCIVendor ¶
NormalizePCIVendor lowercases a PCI vendor id and ensures the "0x" prefix, so "10DE" / "0X10de" / "0x10de" all compare equal to the sysfs form ("0x10de").
Types ¶
type AUR ¶
type AUR struct {
Package []PackageItem `yaml:"package,omitempty" json:"package,omitempty"`
Options []string `yaml:"option,omitempty" json:"option,omitempty"`
Replaces []string `yaml:"replace,omitempty" json:"replace,omitempty"`
}
type AdbEndpoint ¶
type AdbEndpoint struct {
Host string `yaml:"host,omitempty" json:"host"`
}
adb endpoint host is "host:port" but MAY carry a ${HOST_PORT:N} var-ref (resolved at deploy time), so only non-emptiness is enforced.
type Agent ¶
type Agent struct {
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Command []string `yaml:"command,omitempty" json:"command"`
PromptVia string `yaml:"prompt_via,omitempty" json:"prompt_via"`
VersionCommand []string `yaml:"version_command,omitempty" json:"version_command,omitempty"`
Timeout Duration `yaml:"timeout,omitempty" json:"timeout,omitempty"`
Env StrMap `yaml:"env,omitempty" json:"env,omitempty"`
WorkingDir string `yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
Credential []CredentialMount `yaml:"credential,omitempty" json:"credential,omitempty"`
ProgressCheckInterval Duration `yaml:"progress_check_interval,omitempty" json:"progress_check_interval,omitempty"`
ProgressNoImprovementTimeout Duration `yaml:"progress_no_improvement_timeout,omitempty" json:"progress_no_improvement_timeout,omitempty"`
OutputFormat string `yaml:"output_format,omitempty" json:"output_format"`
}
type AlpineBootstrap ¶
type AlpineBootstrap struct {
MirrorURL string `yaml:"mirror_url,omitempty" json:"mirror_url,omitempty"`
}
type Android ¶
type Android struct {
Serial string `yaml:"serial,omitempty" json:"serial,omitempty"`
Device string `yaml:"device,omitempty" json:"device,omitempty"`
ApiLevel int `yaml:"api_level,omitempty" json:"api_level,omitempty"`
GoogleAccount *GoogleAccount `yaml:"google_account,omitempty" json:"google_account,omitempty"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
// Device source — exactly one of box/adb (enforced in Go, see header).
Box string `yaml:"box,omitempty" json:"box,omitempty"`
Adb *AdbEndpoint `yaml:"adb,omitempty" json:"adb,omitempty"`
}
CUE schema for the `android` kind. #Android validates ONE kind:android entity (a device). A device is EITHER an in-pod emulator hosted by a kind:box (box) XOR a remote/physical adb endpoint (adb) — never both, never neither. Shared #Step from _common.cue.
CLOSED: the base struct (no trailing `...`) models every authored key, so an unknown key is still a typo. The box⊻adb exactly-one mutual-exclusion is enforced in GO (validateAndroidDevices in unified.go, the load-time sibling of validateCheckBeds) — NOT by a trailing `& ({box:_} | {adb:_})` disjunction: `cue exp gengotypes` collapses an entity-level top-level disjunction to an EMPTY `struct{}`, which would make spec.Android useless as a drop-in for AndroidSpec. The plain closed struct below generates the full field set, and the Go rule restores the exactly-one-of-box/adb XOR.
func (*Android) EffectiveSerial ¶
EffectiveSerial returns the device serial, defaulting to the emulator serial.
func (*Android) IsEndpoint ¶
IsEndpoint reports whether the device targets a remote adb endpoint.
type AndroidDeployVenue ¶
type AndroidDeployVenue struct {
AdbAddr string `json:"adb_addr"`
Engine string `json:"engine,omitempty"`
Container string `json:"container,omitempty"`
Serial string `json:"serial,omitempty"`
GoogleEmail string `json:"google_email,omitempty"`
GoogleToken string `json:"google_token,omitempty"`
Installs []ApkPackageSpec `json:"installs,omitempty"`
// BootTimeout / InstallDeadline / InstallInterval are the readiness +
// install-retry windows the host ships (no magic numbers in the plugin):
// boot gates sys.boot_completed; the install retries past PackageManager
// post-boot init (a real synchronization condition, not a fixed sleep).
BootTimeout string `json:"boot_timeout,omitempty"`
InstallDeadline string `json:"install_deadline,omitempty"`
InstallInterval string `json:"install_interval,omitempty"`
}
AndroidDeployVenue is the preresolved deploy:android substrate payload the host's android deploy preresolver produces (in DeployVenue.Substrate) and the candy/plugin-adb deploy:android provider decodes. The host resolves the device endpoint (adb-server addr / in-pod engine+container / serial / google-play creds) and collects the apk install specs from the deploy's compiled plans (committed-APK Apk fields rewritten to ABSOLUTE host paths the plugin reads; package entries carry package/source/arch/app_version), so the plugin needs no project context and no goadb-less host resolution — it only drives the device.
type ApkPackageSpec ¶
type ApkPackageSpec struct {
Package string `yaml:"package,omitempty" json:"package,omitempty"`
Apk string `yaml:"apk,omitempty" json:"apk,omitempty"`
Source string `yaml:"source,omitempty" json:"source,omitempty"`
Arch string `yaml:"arch,omitempty" json:"arch,omitempty"`
AppVersion string `yaml:"app_version,omitempty" json:"app_version,omitempty"`
}
--------------------------------------------------------------------------- ApkPackageSpec — #CandyApk (android_spec.go). package XOR apk. ---------------------------------------------------------------------------
func (ApkPackageSpec) EffectiveArch ¶
func (s ApkPackageSpec) EffectiveArch() string
EffectiveArch returns the APK ABI, defaulting to x86_64.
func (ApkPackageSpec) EffectiveSource ¶
func (s ApkPackageSpec) EffectiveSource() string
EffectiveSource returns the APK source store, defaulting to apk-pure.
type ArbiterBoolReply ¶
type ArbiterBoolReply struct {
Bool bool `json:"bool"`
}
ArbiterBoolReply is the running-seam reply.
type ArbiterErrReply ¶
type ArbiterErrReply struct {
Error string `json:"error,omitempty"`
}
ArbiterErrReply carries a seam's operation error ("" = success) — the reverse-channel convention (the RPC itself succeeds; the op error rides here).
type ArbiterGatherReply ¶
type ArbiterGatherReply struct {
Holders []HolderDescriptor `json:"holders"`
}
ArbiterGatherReply is the host's projection of every RUNNING-or-not preemptible holder the arbiter may stop: PreemptionHolds() + holderAddrFor() + preemptEffectiveRestore() are applied host-side so the plugin's holdersToStop is pure config-free coordination.
type ArbiterGpuCDIReply ¶ added in v0.2026187.747
type ArbiterGpuCDIReply struct {
Holders []HolderAddr `json:"holders"`
}
ArbiterGpuCDIReply lists every RUNNING charly pod container that holds the nvidia GPU as a CDI device. The arbiter reclaims the ones NOT covered by an active lease (leaked/kept eval beds whose transient owner-PID-tied lease died with the check-runner process) before a nvidia->vfio flip, so a stray container's open GPU handle can never wedge `modprobe -r nvidia`.
type ArbiterHolderReq ¶
type ArbiterHolderReq struct {
Addr HolderAddr `json:"addr"`
}
ArbiterHolderReq addresses one deployment for the running/stop/start seams.
type ArbiterInvokeInput ¶
type ArbiterInvokeInput struct {
Action string `json:"action"`
Claimant string `json:"claimant,omitempty"`
Tokens []string `json:"tokens,omitempty"`
ClaimAddr HolderAddr `json:"claim_addr,omitempty"`
Transient bool `json:"transient,omitempty"`
Success bool `json:"success,omitempty"` // release-claimant
Token string `json:"token,omitempty"` // clear-poison / resource-poisoned
}
ArbiterInvokeInput is the action-multiplexed input the proxy ships to verb:arbiter. Each action populates only the field(s) it needs.
type ArbiterInvokeReply ¶
type ArbiterInvokeReply struct {
Active bool `json:"active,omitempty"` // acquire-* : the lease is active (env must be marked)
Bool bool `json:"bool,omitempty"` // resource-poisoned
Ledger *PreemptLedger `json:"ledger,omitempty"` // status
Stranded []string `json:"stranded,omitempty"` // status
Error string `json:"error,omitempty"`
}
ArbiterInvokeReply is the action-multiplexed reply from verb:arbiter.
type ArbiterResourcesReply ¶
ArbiterResourcesReply maps each GPU-BACKED arbitration token to its PCI vendor (e.g. "nvidia-gpu" -> "0x10de"). A token ABSENT from the map is arbitration-only (no device to flip; applyMode skips it, firstPoisonedToken ignores it).
type ArbiterSwitchReply ¶
type ArbiterSwitchReply struct {
Error string `json:"error,omitempty"`
Wedged bool `json:"wedged,omitempty"`
}
ArbiterSwitchReply is the switchMode-seam reply: the op error plus whether the flip WEDGED the device_lock (the sentinel can't cross the process boundary, so the bool carries it — the plugin's applyMode poisons the resource on Wedged).
type ArbiterSwitchReq ¶
ArbiterSwitchReq flips a GPU-backed token's whole IOMMU group to a driver mode.
type ArtifactView ¶
type ArtifactView struct {
ContainerPath string `json:"container_path,omitempty"`
HostPath string `json:"host_path,omitempty"`
Chown bool `json:"chown,omitempty"`
}
ArtifactView is the wire mirror of package main's ArtifactRef (a BuilderStep output path to extract back to the venue / final image).
type Bootloader ¶
type Bootloader struct {
InstallTemplate string `yaml:"install_template,omitempty" json:"install_template,omitempty"`
InitramfsTemplate string `yaml:"initramfs_template,omitempty" json:"initramfs_template,omitempty"`
FstabTemplate string `yaml:"fstab_template,omitempty" json:"fstab_template,omitempty"`
}
type Bootstrap ¶
type Bootstrap struct {
InstallCmd string `yaml:"install_cmd,omitempty" json:"install_cmd"`
Package []string `yaml:"package,omitempty" json:"package,omitempty"`
CacheMount []CacheMount `yaml:"cache_mount,omitempty" json:"cache_mount,omitempty"`
}
install_cmd is the bootstrap command; ubuntu sets it to "" (kept WITHOUT `& !=""` so the empty-string base case validates).
type Box ¶
type Box struct {
Name EntityRef `yaml:"name,omitempty" json:"name,omitempty"`
Version CalVer `yaml:"version,omitempty" json:"version,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
Base string `yaml:"base,omitempty" json:"base,omitempty"`
From string `yaml:"from,omitempty" json:"from,omitempty"`
BootstrapBuilderImage string `yaml:"bootstrap_builder_image,omitempty" json:"bootstrap_builder_image,omitempty"`
Platforms []string `yaml:"platform,omitempty" json:"platform,omitempty"`
Tag string `yaml:"tag,omitempty" json:"tag,omitempty"`
Registry string `yaml:"registry,omitempty" json:"registry,omitempty"`
Distro []string `yaml:"distro,omitempty" json:"distro,omitempty"`
// BuildFormats: a scalar OR a list on the wire (#BuildFormats UnmarshalYAML
// normalizes "rpm" → ["rpm"]); the Go field is []string. gengotypes degrades
// the disjunction to `any`, so pin the Go shape explicitly (the typed enum is
// a future enhancement — collapse for now).
Build []string `yaml:"build,omitempty" json:"build,omitempty"`
Candy []CandyRef `yaml:"candy,omitempty" json:"candy,omitempty"`
User string `yaml:"user,omitempty" json:"user,omitempty"`
UID *int `yaml:"uid,omitempty" json:"uid,omitempty"`
GID *int `yaml:"gid,omitempty" json:"gid,omitempty"`
UserPolicy string `yaml:"user_policy,omitempty" json:"user_policy,omitempty"`
Builder map[string]string `yaml:"builder,omitempty" json:"builder,omitempty"`
Produce []BuildType `yaml:"produce,omitempty" json:"produce,omitempty"`
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
EnvFile string `yaml:"env_file,omitempty" json:"env_file,omitempty"`
Security *Security `yaml:"security,omitempty" json:"security,omitempty"`
Network string `yaml:"network,omitempty" json:"network,omitempty"`
Init string `yaml:"init,omitempty" json:"init,omitempty"`
DataImage bool `yaml:"data_image,omitempty" json:"data_image,omitempty"`
Bootc bool `yaml:"bootc,omitempty" json:"bootc,omitempty"`
Readiness *Readiness `yaml:"readiness,omitempty" json:"readiness,omitempty"`
Jobs *int `yaml:"jobs,omitempty" json:"jobs,omitempty"`
PodmanJobs *int `yaml:"podman_jobs,omitempty" json:"podman_jobs,omitempty"`
PodmanJobsCap *int `yaml:"podman_jobs_cap,omitempty" json:"podman_jobs_cap,omitempty"`
ContextIgnore []string `yaml:"context_ignore,omitempty" json:"context_ignore,omitempty"`
Cache string `yaml:"cache,omitempty" json:"cache,omitempty"`
KeepImages *int `yaml:"keep_images,omitempty" json:"keep_images,omitempty"`
KeepCheckRuns *int `yaml:"keep_check_runs,omitempty" json:"keep_check_runs,omitempty"`
Merge *BoxMerge `yaml:"merge,omitempty" json:"merge,omitempty"`
Alias []BoxAlias `yaml:"alias,omitempty" json:"alias,omitempty"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
CheckLevel string `yaml:"check_level,omitempty" json:"check_level,omitempty"`
Shell *Shell `yaml:"shell,omitempty" json:"shell,omitempty"`
}
base and from are mutually exclusive; neither is also valid (scratch box). The entity-level base⊻from mutual-exclusion is enforced in GO (BoxConfig.HasBaseFromConflict, surfaced by validateBoxBaseFrom in validate.go and resolveBase in config.go) — NOT by a trailing `& ({from?: _|_} | {base?: _|_})` disjunction. `cue exp gengotypes` collapses an entity-level top-level disjunction to an EMPTY `struct{}`, which would make spec.Box useless as a drop-in for BoxConfig; the plain closed struct below generates the full field set, and the Go rule restores the XOR. The struct stays CLOSED (no `...`) so an unknown key is still a typo.
func (*Box) HasBaseFromConflict ¶
HasBaseFromConflict reports whether the box authored BOTH base: and from:.
type BoxAlias ¶
type BoxAlias struct {
Name string `yaml:"name,omitempty" json:"name"`
Command string `yaml:"command,omitempty" json:"command,omitempty"`
}
AliasConfig (config.go). CLOSED. command defaults to name when omitted.
type BoxMerge ¶
type BoxMerge struct {
Auto bool `yaml:"auto,omitempty" json:"auto,omitempty"`
MaxMB int `yaml:"max_mb,omitempty" json:"max_mb,omitempty"`
MaxTotalMB int `yaml:"max_total_mb,omitempty" json:"max_total_mb,omitempty"`
}
MergeConfig (config.go). CLOSED.
type BuildEnv ¶
type BuildEnv struct {
Distros []string `json:"distros,omitempty"`
Image string `json:"image,omitempty"`
}
BuildEnv is the build-context descriptor the host puts in op.Env for an OpEmit Invoke at image-generation time: the image's distro tags + name, so a plugin can tailor its emitted Containerfile fragment per distro/arch. The build-time analogue of DeployVenue (deploy) / the verb check-env. Placement-agnostic: a builtin reads it in-proc, an external over gRPC.
type BuildReply ¶
type BuildReply struct {
Written []string `json:"written,omitempty"`
Error string `json:"error,omitempty"`
}
BuildReply is what a build:box / build:generate plugin echoes back from its HostBuild call: the opaque list of artifacts the engine wrote (image refs for build, Containerfile paths for generate) plus a build error string (empty on success). A build FAILURE rides Error (the RPC itself succeeds — the reply-error convention), so the dispatcher surfaces it to the CLI.
type BuildRequest ¶
type BuildRequest struct {
Boxes []string `json:"boxes,omitempty"` // positional box selection ("" → all enabled)
Tag string `json:"tag,omitempty"` // --tag override (empty → CalVer)
Dir string `json:"dir,omitempty"` // project dir the host reconstructs config from
IncludeDisabled bool `json:"include_disabled,omitempty"` // --include-disabled
DevLocalPkg bool `json:"dev_local_pkg,omitempty"` // --dev-local-pkg (localpkg from local source; build only)
Push bool `json:"push,omitempty"` // --push (build only)
Platform string `json:"platform,omitempty"` // --platform (build only)
Cache string `json:"cache,omitempty"` // --cache mode (build only)
NoCache bool `json:"no_cache,omitempty"` // --no-cache (build only)
Jobs int `json:"jobs,omitempty"` // --jobs outer concurrency (build only)
PodmanJobs int `json:"podman_jobs,omitempty"` // --podman-jobs inner concurrency (build only)
}
BuildRequest is the BUILD-ENGINE DISPATCH envelope (F10 HostBuild seam): what `charly box build` / `charly box generate` marshal into a build:box / build:generate plugin's Invoke (op.Params), which the plugin forwards VERBATIM to the host via Executor.HostBuild. The heavy engine (Generator / OCITarget / the runtime Candy graph) STAYS host-side in-proc — only this small envelope crosses the seam. Everything the engine reads (Config / ResolvedBox / Candy) is reconstructed HOST-SIDE from Dir inside the registered host-builder (exactly as pod_deploy_lifecycle re-runs NewGenerator(dir,…)); the fields here are the CLI-supplied inputs that are NOT reconstructable from Dir alone. The generate path reads only Boxes/Tag/Dir/ IncludeDisabled; the build path additionally reads DevLocalPkg + the buildImages knobs (Push/Platform/Cache/NoCache/Jobs/PodmanJobs).
type Builder ¶
type Builder struct {
DetectFiles []string `yaml:"detect_file,omitempty" json:"detect_file,omitempty"`
DetectConfig string `yaml:"detect_config,omitempty" json:"detect_config,omitempty"`
RequiresSrcDir bool `yaml:"requires_src_dir,omitempty" json:"requires_src_dir,omitempty"`
Inline bool `yaml:"inline,omitempty" json:"inline,omitempty"`
CacheMount []CacheMount `yaml:"cache_mount,omitempty" json:"cache_mount,omitempty"`
Env StrMap `yaml:"env,omitempty" json:"env,omitempty"`
RuntimeEnv StrMap `yaml:"runtime_env,omitempty" json:"runtime_env,omitempty"`
InstallTemplate string `yaml:"install_template,omitempty" json:"install_template,omitempty"`
ManylinuxFix string `yaml:"manylinux_fix,omitempty" json:"manylinux_fix,omitempty"`
BuildScript string `yaml:"build_script,omitempty" json:"build_script,omitempty"`
Phases *PhaseSet `yaml:"phase,omitempty" json:"phase,omitempty"`
InstallCommands map[string]string `yaml:"install_command,omitempty" json:"install_command,omitempty"`
CopyArtifacts []Copy `yaml:"copy_artifact,omitempty" json:"copy_artifact,omitempty"`
CopyBinary *Copy `yaml:"copy_binary,omitempty" json:"copy_binary,omitempty"`
PathContributions []string `yaml:"path_contribution,omitempty" json:"path_contribution,omitempty"`
Kind string `yaml:"kind,omitempty" json:"kind"`
Privileged bool `yaml:"privileged,omitempty" json:"privileged"`
OutputArtifact string `yaml:"output_artifact,omitempty" json:"output_artifact,omitempty"`
}
func (*Builder) IsBootstrap ¶
IsBootstrap reports whether the builder is a bootstrap builder.
type BuilderCollectInput ¶
type BuilderCollectInput struct {
Candy string `json:"candy"`
Builder string `json:"builder"`
Home string `json:"home,omitempty"`
Packages []string `json:"packages,omitempty"` // the builder's detect-config section packages (aur)
Replaces []string `json:"replaces,omitempty"` // aur `replaces:` — repo packages removed before pacman -U
}
BuilderCollectInput is the OpCollectContext params: the host-supplied candy descriptor an external builder plugin reads to produce its per-candy stage context. The host fills the generic fields it can derive without builder-specific knowledge (Candy/Builder/Home always; Packages/Replaces from the builder's detect-config package section, used today only by aur). A builder reads the subset it needs (pixi uses none → a constant env; cargo/npm none).
type BuilderCollectReply ¶
BuilderCollectReply is the OpCollectContext reply: the builder-specific stage-context keys the host merges onto the base context ({layer,builder,home}) to form the BuilderStep.RawStageContext (e.g. pixi → {env_name}, aur → {packages,replaces}).
type BuilderResolveInput ¶
type BuilderResolveInput struct {
Candy string `json:"candy"`
Builder string `json:"builder,omitempty"`
BuilderRef string `json:"builder_ref,omitempty"`
StageName string `json:"stage_name,omitempty"`
LayerStage string `json:"layer_stage,omitempty"`
CopySrc string `json:"copy_src,omitempty"`
UID int `json:"uid,omitempty"`
GID int `json:"gid,omitempty"`
Home string `json:"home,omitempty"`
User string `json:"user,omitempty"`
Manifest string `json:"manifest,omitempty"`
HasLockFile bool `json:"has_lock_file,omitempty"`
InstallCmd string `json:"install_cmd,omitempty"`
ManylinuxFix string `json:"manylinux_fix,omitempty"`
HasBuildScript bool `json:"has_build_script,omitempty"`
BuildScript string `json:"build_script,omitempty"`
Packages []string `json:"packages,omitempty"`
Options []string `json:"options,omitempty"`
CacheMountsOwned string `json:"cache_mounts_owned,omitempty"`
CacheMountsAuto string `json:"cache_mounts_auto,omitempty"`
Inline bool `json:"inline,omitempty"`
}
BuilderResolveInput is the OpResolve params: the RENDER CONTEXT the host computes and hands a builder plugin so it can render its build-time multi-stage self-contained. The host owns DETECTION (which candy triggers which builder — filesystem probes) and the serializable render context (the resolved builder image ref, the target user identity, the pre-rendered cache-mount flag strings); the plugin (via kit.BuilderResolve) owns the multi-stage TEMPLATE + the COPY-artifact/binary shape. The `external_builder:` path sends a MINIMAL input (Candy only — an out-of-tree builder renders a self-contained stage that reads none of the detection fields); the DETECTION path (pixi/npm/aur/cargo) sends the full context. Cache mounts arrive PRE-RENDERED (CacheMountsOwned/CacheMountsAuto) because the host owns the cache_mount vocab + the RenderCacheMounts helper — so the plugin needs no cache-mount render engine and the emitted bytes stay byte-identical to the former embedded-vocabulary render.
type BuilderResolveReply ¶
type BuilderResolveReply struct {
Stage string `json:"stage,omitempty"`
CopyArtifacts []string `json:"copy_artifacts,omitempty"`
CopyBinary string `json:"copy_binary,omitempty"`
InlineFragment string `json:"inline_fragment,omitempty"`
}
BuilderResolveReply is what a builder plugin returns from an OpResolve Invoke at image-generation time — the build-time BUILDER leg, the multi-stage counterpart of a verb/step's EmitReply. It serves BOTH the `external_builder:`-SELECTED out-of-tree builders AND the four DETECTION-builders (pixi/npm/aur/cargo, whose build-time multi-stage moved out of the embedded builder: vocabulary into their plugins — see kit.BuilderResolve). Stage is the `FROM <ref> AS <name>` block (its RUN/COPY body included) spliced PRE-main-FROM (emitExternalBuilderStages for external_builder; emitBuilderStages for detection builders); CopyArtifacts are the `COPY --from=<stage> …` directives spliced POST-main-FROM to pull the built artifacts into the final image; CopyBinary is the single builder-BINARY copy line (pixi → /usr/local/bin/pixi) the host emits ONCE per builder (deduped across candies, mirroring the former emitBuilderArtifacts copy_binary handling); InlineFragment is the in-candy RUN an INLINE builder (cargo) emits IN the main image (no separate FROM stage) — Stage/CopyArtifacts are empty for an inline builder, InlineFragment empty for a multi-stage one. All fields are egress-validated with the rest of the Containerfile before it hits disk.
type BuilderReverseInput ¶
type BuilderReverseInput struct {
Candy string `json:"candy"`
Builder string `json:"builder"`
Context map[string]any `json:"context,omitempty"`
}
BuilderReverseInput is the OpReverse params: the candy + its resolved stage-context keys (the BuilderCollectReply.Context). The plugin maps these to its teardown ops — the builder-specific reverse-op KIND (pixi-env-remove / package-remove / …) is exactly the per-builder Go logic this externalization moves out-of-process.
type BuilderReverseReply ¶
type BuilderReverseReply struct {
ReverseOps []ReverseOp `json:"reverse_ops,omitempty"`
}
BuilderReverseReply is the OpReverse reply: the builder's teardown ops, stashed by the host onto BuilderStep.PreResolvedReverse so BuilderStep.Reverse() is a pure getter (no RPC at its host-side call sites). For aur the host renders UninstallCmd later via fillReverseUninstallCmds (the format's uninstall_template), the same as a built-in package-remove op — the plugin names only Kind/Format/Targets/Scope.
type CacheMount ¶
type CacheMount struct {
Dst string `yaml:"dst,omitempty" json:"dst"`
Sharing string `yaml:"sharing,omitempty" json:"sharing,omitempty"`
Owned bool `yaml:"owned,omitempty" json:"owned,omitempty"`
}
A BuildKit cache mount. dst is the absolute in-builder cache path; sharing is the BuildKit sharing mode; owned renders a uid/gid-owned cache.
type CacheMountView ¶
type CacheMountView struct {
Dst string `json:"dst,omitempty"`
Sharing string `json:"sharing,omitempty"`
}
CacheMountView is the wire mirror of package main's CacheMountSpec (a BuildKit cache-mount config carried on a SystemPackagesStep). Kept tiny + spec-homed so the step view is fully self-describing on the SDK side.
type Candy ¶
type Candy struct {
// --- identity (required: ADE mandates version+name+description+plan) ---
Version CalVer `yaml:"version,omitempty" json:"version"`
Name EntityRef `yaml:"name,omitempty" json:"name,omitempty"`
Description string `yaml:"description,omitempty" json:"description"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
// --- maturity / engine ---
Status string `yaml:"status,omitempty" json:"status,omitempty"`
// engine — a candy's required run engine; per-image resolution walks the
// candy chain (engine.go ResolveBoxEngine) and cross-candy conflicts are a
// validate error. RETAINED by the schema-compaction consumer audit.
Engine string `yaml:"engine,omitempty" json:"engine,omitempty"`
// `from:` is NOT a candy field — EDGE-INHERIT cutover D: a candy: node carrying
// `base:` or `from:` is a full IMAGE (#Box, the former box:), routed there by the
// loader; a LAYER fragment has neither. So `from:` lives only on #Box.
Reboot bool `yaml:"reboot,omitempty" json:"reboot,omitempty"`
// --- composition ---
Candy []CandyRef `yaml:"candy,omitempty" json:"candy,omitempty"`
Require []CandyRef `yaml:"require,omitempty" json:"require,omitempty"`
// bake_plugin — the OUT-OF-TREE plugin candies whose pre-built provider binary
// this candy BAKES into every composing image at /usr/lib/charly/plugins/, so a
// DEPLOYED container (no candy source, no go toolchain) can run an external plugin
// its in-container charly needs at runtime — e.g. charly-mcp bakes plugin-mcp so
// `charly mcp serve` resolves the external `mcp` command in-container. The S0
// baked-plugin BUILD-side seam, the deploy-time counterpart of resolvePluginBinary's
// bakedPluginBinary fallback (plugin_loader.go). See generate.go emitBakedPlugins.
BakePlugin []CandyRef `yaml:"bake_plugin,omitempty" json:"bake_plugin,omitempty"`
RequiresCapability []string `yaml:"requires_capability,omitempty" json:"requires_capability,omitempty"`
Capability *CandyCapability `yaml:"capability,omitempty" json:"capability,omitempty"`
// plugin — declaring this block makes the candy a PLUGIN: it provides
// reserved-word Providers (built-in OR out-of-tree). The candy is otherwise
// authored, validated, built, deployed, and checked like any candy (R3 — one
// authoring surface). See provider.go / plugin_loader.go.
Plugin *Plugin `yaml:"plugin,omitempty" json:"plugin,omitempty"`
// external_builder — the reserved word of an EXTERNAL builder plugin
// (`builder:<word>`, an out-of-tree grpcProvider) this candy SELECTS to produce
// a multi-stage build artifact. At image build the generator resolves the word,
// Invokes the provider's OpResolve, and splices the returned BuilderResolveReply
// (the FROM…AS stage pre-main-FROM + the COPY --from artifacts post-main-FROM).
// The build-time BUILDER leg — the counterpart of a `run:` step's `plugin:` verb
// (the STEP leg). A builtin builder (pixi/cargo/npm/aur) is selected by detection
// files, NOT this field. See generate.go emitExternalBuilderStages.
ExternalBuilder string `yaml:"external_builder,omitempty" json:"external_builder,omitempty"`
// --- runtime env / local vars / PATH ---
// env forbids PATH (validate.go: use path_append instead). Values are
// Go-coerced scalars (#StrVal) — an unquoted `PORT: 8080` is a string. The Go
// field is map[string]string (yaml.v3 coerces the scalar), so pin the shape
// (gengotypes degrades the #StrVal value to `any`).
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
// var: Go field is `Vars map[string]string`; gengotypes degrades the
// pattern-keyed map to an empty struct, so pin name + shape.
Vars map[string]string `yaml:"var,omitempty" json:"var,omitempty"`
PathAppend []string `yaml:"path_append,omitempty" json:"path_append,omitempty"`
// --- package surface (Calamares-aligned) ---
Package []PackageItem `yaml:"package,omitempty" json:"package,omitempty"`
Distro map[string]*DistroPackages `yaml:"distro,omitempty" json:"distro,omitempty"`
Apk []ApkPackageSpec `yaml:"apk,omitempty" json:"apk,omitempty"`
// localpkg maps a native package FORMAT to a bundled source dir; a scalar
// form is rejected by Go. Closed to the three known formats.
// localpkg Go field is `LocalPkg map[string]string` (a per-format → source-dir
// map); pin name + shape (gengotypes would emit an inline struct named
// `Localpkg`).
LocalPkg map[string]string `yaml:"localpkg,omitempty" json:"localpkg,omitempty"`
// --- networking / routing ---
// PortSpec: a plain int OR a "proto:port" string (proto ∈ http/https/tcp/…);
// the Go normalizer canonicalizes either form to the {port, protocol}
// PortSpec struct, so the Go field is []PortSpec (gengotypes degrades the
// scalar|string disjunction element to `any`).
Port []PortSpec `yaml:"port,omitempty" json:"port,omitempty"`
PortRelay []int `yaml:"port_relay,omitempty" json:"port_relay,omitempty"`
Route *CandyRoute `yaml:"route,omitempty" json:"route,omitempty"`
// --- services / volumes / aliases / extract / data ---
Service []CandyService `yaml:"service,omitempty" json:"service,omitempty"`
Volume []CandyVolume `yaml:"volume,omitempty" json:"volume,omitempty"`
Alias []CandyAlias `yaml:"alias,omitempty" json:"alias,omitempty"`
Extract []CandyExtract `yaml:"extract,omitempty" json:"extract,omitempty"`
Data []CandyData `yaml:"data,omitempty" json:"data,omitempty"`
// --- security / libvirt / hooks ---
Security *Security `yaml:"security,omitempty" json:"security,omitempty"`
Libvirt []string `yaml:"libvirt,omitempty" json:"libvirt,omitempty"`
Hook *CandyHook `yaml:"hook,omitempty" json:"hook,omitempty"`
// --- env/secret/mcp dependency + provides surface ---
// All six env/secret/mcp dependency lists decode into the ONE Go type
// []EnvDependency (pinned via @go(...,type=[]EnvDependency)); the per-context
// CUE refinements (env-var name regex; the charly/ secret-key prefix) only
// TIGHTEN validation — they don't change the emitted Go type (an inline
// `#EnvDependency & {…}` would otherwise make gengotypes emit an anonymous
// struct). mcp_* keep the base shape (an MCP server name is not env-var-
// constrained).
EnvProvides StrMap `yaml:"env_provide,omitempty" json:"env_provide,omitempty"`
EnvRequire []EnvDependency `yaml:"env_require,omitempty" json:"env_require,omitempty"`
EnvAccept []EnvDependency `yaml:"env_accept,omitempty" json:"env_accept,omitempty"`
SecretAccept []EnvDependency `yaml:"secret_accept,omitempty" json:"secret_accept,omitempty"`
SecretRequire []EnvDependency `yaml:"secret_require,omitempty" json:"secret_require,omitempty"`
MCPProvide []CandyMCPProvide `yaml:"mcp_provide,omitempty" json:"mcp_provide,omitempty"`
MCPRequire []EnvDependency `yaml:"mcp_require,omitempty" json:"mcp_require,omitempty"`
MCPAccept []EnvDependency `yaml:"mcp_accept,omitempty" json:"mcp_accept,omitempty"`
SecretYAML []CandySecret `yaml:"secret,omitempty" json:"secret,omitempty"`
// --- shell init (same shape as box shell) ---
Shell *Shell `yaml:"shell,omitempty" json:"shell,omitempty"`
// --- operator-facing artifacts ---
Artifact []CandyArtifact `yaml:"artifact,omitempty" json:"artifact,omitempty"`
}
type CandyAlias ¶
type CandyAlias struct {
Name string `yaml:"name,omitempty" json:"name"`
Command string `yaml:"command,omitempty" json:"command"`
}
AliasYAML — for a CANDY alias `command` is REQUIRED (validateAliases); the box-level #BoxAlias keeps it optional (defaults to name).
type CandyArtifact ¶
type CandyArtifact struct {
Name string `yaml:"name,omitempty" json:"name"`
Path string `yaml:"path,omitempty" json:"path"`
RetrieveTo string `yaml:"retrieve_to,omitempty" json:"retrieve_to"`
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
Optional bool `yaml:"optional,omitempty" json:"optional,omitempty"`
WaitSeconds int `yaml:"wait_second,omitempty" json:"wait_second,omitempty"`
Rewrite []CandyArtifactRewrite `yaml:"rewrite,omitempty" json:"rewrite,omitempty"`
}
CandyArtifact — a file the candy publishes back to the operator post-setup.
type CandyArtifactRewrite ¶
type CandyCapability ¶
type CandyCapability struct {
PreserveUser bool `yaml:"preserve_user,omitempty" json:"preserve_user,omitempty"`
NeedsRootAfterInit bool `yaml:"needs_root_after_init,omitempty" json:"needs_root_after_init,omitempty"`
InitSystemHint string `yaml:"init_system_hint,omitempty" json:"init_system_hint,omitempty"`
DataOnly bool `yaml:"data_only,omitempty" json:"data_only,omitempty"`
OCILabels map[string]string `yaml:"oci_label,omitempty" json:"oci_label,omitempty"`
}
CandyCapabilities — image-level facts a candy contributes (aggregated at resolve time). oci_label is a genuine open string→string passthrough.
type CandyData ¶
type CandyData struct {
Src string `yaml:"src,omitempty" json:"src"`
Volume string `yaml:"volume,omitempty" json:"volume"`
Dest string `yaml:"dest,omitempty" json:"dest,omitempty"`
}
DataYAML — stage candy-dir data into a volume at build, provision at deploy.
type CandyExtract ¶
type CandyExtract struct {
Source string `yaml:"source,omitempty" json:"source"`
Path string `yaml:"path,omitempty" json:"path"`
Dest string `yaml:"dest,omitempty" json:"dest"`
}
ExtractYAML — copy a path out of another OCI image into this one. source is an image ref; path (in the source image) and dest (in this image) are absolute (validateCandyContents).
type CandyHook ¶
type CandyHook struct {
PostEnable string `yaml:"post_enable,omitempty" json:"post_enable,omitempty"`
PreRemove string `yaml:"pre_remove,omitempty" json:"pre_remove,omitempty"`
}
HooksConfig — lifecycle hook scripts.
type CandyMCPProvide ¶
type CandyMCPProvide struct {
Name string `yaml:"name,omitempty" json:"name"`
URL string `yaml:"url,omitempty" json:"url"`
Transport string `yaml:"transport,omitempty" json:"transport,omitempty"`
}
MCPServerYAML — mcp_provide entry exposed to peer containers.
type CandyRoute ¶
type CandyRoute struct {
Host string `yaml:"host,omitempty" json:"host"`
Port int `yaml:"port,omitempty" json:"port"`
}
RouteYAML — generic service-route metadata (traefik / tunnel).
type CandySecret ¶
type CandySecret struct {
Name string `yaml:"name,omitempty" json:"name"`
Target string `yaml:"target,omitempty" json:"target,omitempty"`
Env string `yaml:"env,omitempty" json:"env,omitempty"`
}
SecretYAML — a candy-owned secret (target defaults to /run/secrets/<name>).
type CandyService ¶
type CandyService struct {
Name string `yaml:"name,omitempty" json:"name"`
UsePackaged string `yaml:"use_packaged,omitempty" json:"use_packaged,omitempty"`
Exec string `yaml:"exec,omitempty" json:"exec,omitempty"`
// distro restricts this entry to the named distros — a bare distro name
// ("debian") or a versioned tag ("debian:13"). Empty = every distro (the
// backward-compatible default). The service analogue of a check step's
// exclude_distros: — it lets ONE candy carry per-distro-DIVERGENT packaged
// units / exec daemons (the modular virtqemud.socket + virtnetworkd.socket
// on Fedora/Arch vs the monolithic libvirtd.socket on Debian/Ubuntu, whose
// libvirt is built without the split daemons) WITHOUT a <name>-host sibling
// candy (CLAUDE.md "Init-system polymorphism"; R3). Filtered at render time
// against the target distro tag chain (compileServiceSteps + generate.go).
Distro []string `yaml:"distro,omitempty" json:"distro,omitempty"`
Env StrMap `yaml:"env,omitempty" json:"env,omitempty"`
Restart string `yaml:"restart,omitempty" json:"restart,omitempty"`
WorkingDirectory string `yaml:"working_directory,omitempty" json:"working_directory,omitempty"`
User string `yaml:"user,omitempty" json:"user,omitempty"`
After []string `yaml:"after,omitempty" json:"after,omitempty"`
Before []string `yaml:"before,omitempty" json:"before,omitempty"`
WantedBy []string `yaml:"wanted_by,omitempty" json:"wanted_by,omitempty"`
Stdout string `yaml:"stdout,omitempty" json:"stdout,omitempty"`
StopTimeout string `yaml:"stop_timeout,omitempty" json:"stop_timeout,omitempty"`
Scope string `yaml:"scope,omitempty" json:"scope,omitempty"`
Enable bool `yaml:"enable,omitempty" json:"enable,omitempty"`
Overrides *CandyServiceOverrides `yaml:"overrides,omitempty" json:"overrides,omitempty"`
Kind string `yaml:"kind,omitempty" json:"kind,omitempty"`
Events string `yaml:"event,omitempty" json:"event,omitempty"`
AutoStart *bool `yaml:"auto_start,omitempty" json:"auto_start,omitempty"`
StartRetries int `yaml:"start_retry,omitempty" json:"start_retry,omitempty"`
StartSecs int `yaml:"start_sec,omitempty" json:"start_sec,omitempty"`
StopSignal string `yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
ExitCode string `yaml:"exit_code,omitempty" json:"exit_code,omitempty"`
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
}
ServiceEntry (service_render.go). use_packaged XOR exec is a Go cross-field rule (mixed-entry polymorphism allows the SAME name twice: one packaged form, one exec form) — neither is required at the CUE layer.
func (*CandyService) EffectiveScope ¶
func (e *CandyService) EffectiveScope() string
EffectiveScope returns the service scope, defaulting to "system".
func (*CandyService) IsPackaged ¶
func (e *CandyService) IsPackaged() bool
IsPackaged reports whether the service is the packaged (use_packaged) form.
type CandyServiceOverrides ¶
type CandyVolume ¶
type CandyVolume struct {
Name string `yaml:"name,omitempty" json:"name"`
Path string `yaml:"path,omitempty" json:"path"`
}
VolumeYAML — name is lowercase-hyphen (validateVolume); path may be home-relative (~/…) or absolute, so not anchored to /.
type Check ¶
type Check Deploy
#Check — a kind:check bed. Structurally IDENTICAL to #Deploy (same BundleNode Go struct), so it is a plain reference (R3 — no field duplication; stays CLOSED because #Deploy is closed). The bed-mode invariants the former `& (A|B|C)` disjunction expressed — disposable required + bed-legal target ∈ {pod,vm,local, android} for the deterministic/ephemeral modes, the iterate AI-benchmark mode, and the ephemeral⇒disposable promotion — are enforced in GO at load time (validateCheckBeds + validateEphemeralUnified in unified.go), which is the SINGLE source of truth for the actual bundle-form beds (a node-form check bed is a `bundle:` node validated via #BundleValue=#Deploy, so the disjunction was only ever applied to the legacy root-shape `check:` collection). Relaxing it to the alias removes that divergent parallel spec and lets gengotypes emit a real Check struct instead of an empty `struct{}`.
type CliReply ¶ added in v0.2026186.239
type CliReply struct {
Stdout string `json:"stdout,omitempty"`
ExitCode int `json:"exit_code,omitempty"`
Error string `json:"error,omitempty"`
}
CliReply is the "cli" host-builder reply: captured stdout (Capture=true), the exit code, and an error string on a non-zero exit that was not BestEffort-swallowed.
type CliRequest ¶ added in v0.2026186.239
type CliRequest struct {
Argv []string `json:"argv"`
Capture bool `json:"capture,omitempty"`
BestEffort bool `json:"best_effort,omitempty"`
}
CliRequest is the "cli" host-builder envelope (M4): a lifecycle plugin asks the HOST to run a `charly <argv>` subcommand — Capture=false inherits stdin/out/err (interactive: charly shell, logs -f), Capture=true captures stdout (a status parse). BestEffort swallows a non-zero exit.
type CredentialHealth ¶ added in v0.2026186.1117
type CredentialHealth struct {
BackendName string `json:"backend_name"`
ConfiguredBackend string `json:"configured_backend"`
KeyringAvailable bool `json:"keyring_available"`
KeyringLocked bool `json:"keyring_locked"`
PlaintextCount int `json:"plaintext_count"`
NoSession bool `json:"no_session"`
CollErr string `json:"coll_err,omitempty"`
HealthyColls []string `json:"healthy_colls,omitempty"`
BrokenColls []string `json:"broken_colls,omitempty"`
IndexTotal int `json:"index_total"`
IndexMissing []string `json:"index_missing,omitempty"`
}
CredentialHealth is the credential-store health snapshot (moved here from charly core — it now has core + plugin-doctor consumers, R3). Rendered into the doctor "secret storage" checks by the plugin.
type CredentialMount ¶
type Debootstrap ¶
type Debootstrap struct {
Suite string `yaml:"suite,omitempty" json:"suite,omitempty"`
Mirror string `yaml:"mirror,omitempty" json:"mirror,omitempty"`
Variant string `yaml:"variant,omitempty" json:"variant,omitempty"`
Components string `yaml:"components,omitempty" json:"components,omitempty"`
IncludePackages []string `yaml:"include_package,omitempty" json:"include_package,omitempty"`
BasePackages []string `yaml:"base_package,omitempty" json:"base_package,omitempty"`
ExtraRepos []DebootstrapRepo `yaml:"extra_repo,omitempty" json:"extra_repo,omitempty"`
}
type DebootstrapRepo ¶
type Deploy ¶
type Deploy struct {
Version CalVer `yaml:"version,omitempty" json:"version,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
// target is DERIVED from the node's discriminator kind + cross-ref at load
// (buildBundleNode/inferBundleTarget) — NOT authored in node-form. Optional
// here so #Check's arms can pin it; the #BundleValue arm (node.cue) rejects an
// authored `target:` outright. The former default `*"pod"` is dropped (Go's
// classifyTarget supplies the empty→pod default). Generated as a plain Go
// `string` (the loader stamps it; the CUE enum still validates a pinned value).
Target string `yaml:"target,omitempty" json:"target,omitempty"`
// member_of + inside are loader-DERIVED runtime fields (never authored;
// rejected by #BundleValue): member_of marks a folded sibling-member entry,
// inside names the venue a nested resource deploys into. Generated for the Go
// tree-walker, forbidden in authoring.
MemberOf string `yaml:"member_of,omitempty" json:"member_of,omitempty"`
Inside string `yaml:"inside,omitempty" json:"inside,omitempty"`
// agent_provisioned marks a resource member/child the AI deploys at run time
// (the iterate-benchmark contract): image-less (no box:), not folded to a
// top-level entry, exempt from the box-required validators. See deploy.go.
AgentProvisioned bool `yaml:"agent_provisioned,omitempty" json:"agent_provisioned,omitempty"`
// EDGE-INHERIT cutover B: the substrate kind is the EDGE discriminator (pod:/vm:/
// k8s:/local:/android:/group:), so the deploy carries only NON-kind cross-refs:
//
// from — inherit a SAME-kind template by name (vm/k8s/local/android deploys).
// image — the box/OCI artifact a pod/k8s/android RUNS (the former `box:`).
//
// Per-substrate validity (image⊻from, source⊻from) is enforced in Go
// (classifyTarget / validateDeploy), not CUE, so a `vm:` node is a VmSpec template
// (source:) OR a deploy (from:) under ONE arm — the disjunction #Vm|#Deploy.
From EntityRef `yaml:"from,omitempty" json:"from,omitempty"`
Image string `yaml:"image,omitempty" json:"image,omitempty"`
Kind string `yaml:"kind,omitempty" json:"kind,omitempty"`
Replica int `yaml:"replica,omitempty" json:"replica,omitempty"`
Restart string `yaml:"restart,omitempty" json:"restart,omitempty"`
Schedule string `yaml:"schedule,omitempty" json:"schedule,omitempty"`
Tunnel *TunnelYAML `yaml:"tunnel,omitempty" json:"tunnel,omitempty"`
DNS string `yaml:"dns,omitempty" json:"dns,omitempty"`
AcmeEmail string `yaml:"acme_email,omitempty" json:"acme_email,omitempty"`
Port []PortPin `yaml:"port,omitempty" json:"port,omitempty"`
ResolvedPort []PortPin `yaml:"resolved_port,omitempty" json:"resolved_port,omitempty"`
// resolved_image: the concrete image ref the pod deploy's add_candy: overlay
// build produced (`<deploy-key>-overlay:<hash>`), persisted by PrepareVenue so
// config/start deploy EXACTLY that overlay (carrying the add_candy layers)
// instead of re-resolving the base image: short-name by a CalVer sort that the
// overlay alias can lose to the base on a same-minute build. charly-written
// state (like resolved_port), never authored; empty for a plain pod.
ResolvedImage string `yaml:"resolved_image,omitempty" json:"resolved_image,omitempty"`
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
EnvFile string `yaml:"env_file,omitempty" json:"env_file,omitempty"`
Network string `yaml:"network,omitempty" json:"network,omitempty"`
Engine string `yaml:"engine,omitempty" json:"engine,omitempty"`
Security *Security `yaml:"security,omitempty" json:"security,omitempty"`
Secret []DeploySecret `yaml:"secret,omitempty" json:"secret,omitempty"`
Volume []DeployVolume `yaml:"volume,omitempty" json:"volume,omitempty"`
Sidecar map[string]Sidecar `yaml:"sidecar,omitempty" json:"sidecar,omitempty"`
ForwardGpgAgent *bool `yaml:"forward_gpg_agent,omitempty" json:"forward_gpg_agent,omitempty"`
ForwardSshAgent *bool `yaml:"forward_ssh_agent,omitempty" json:"forward_ssh_agent,omitempty"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
Iterate *Iterate `yaml:"iterate,omitempty" json:"iterate,omitempty"`
Shell []DeployShellOverlay `yaml:"shell,omitempty" json:"shell,omitempty"`
AddCandy []string `yaml:"add_candy,omitempty" json:"add_candy,omitempty"`
InstallOpts *InstallOpts `yaml:"install_opts,omitempty" json:"install_opts,omitempty"`
Host string `yaml:"host,omitempty" json:"host,omitempty"`
User string `yaml:"user,omitempty" json:"user,omitempty"`
SSHArgs []string `yaml:"ssh_arg,omitempty" json:"ssh_arg,omitempty"`
Cpus int `yaml:"cpus,omitempty" json:"cpus,omitempty"`
Ram VmSize `yaml:"ram,omitempty" json:"ram,omitempty"`
DiskSize VmSize `yaml:"disk_size,omitempty" json:"disk_size,omitempty"`
Kubernetes *K8sDeploy `yaml:"kubernetes,omitempty" json:"kubernetes,omitempty"`
Resources *DeployResources `yaml:"resources,omitempty" json:"resources,omitempty"`
Expose *DeployExpose `yaml:"expose,omitempty" json:"expose,omitempty"`
Storage []DeployStorage `yaml:"storage,omitempty" json:"storage,omitempty"`
Probes *DeployProbes `yaml:"probes,omitempty" json:"probes,omitempty"`
FromSnapshot string `yaml:"from_snapshot,omitempty" json:"from_snapshot,omitempty"`
CloudInitClean bool `yaml:"cloud_init_clean,omitempty" json:"cloud_init_clean,omitempty"`
VmState *VmDeployState `yaml:"vm_state,omitempty" json:"vm_state,omitempty"`
Disposable *bool `yaml:"disposable,omitempty" json:"disposable,omitempty"`
Lifecycle string `yaml:"lifecycle,omitempty" json:"lifecycle,omitempty"`
Ephemeral *EphemeralLifetime `yaml:"ephemeral,omitempty" json:"ephemeral,omitempty"`
Preemptible *PreemptibleConfig `yaml:"preemptible,omitempty" json:"preemptible,omitempty"`
RequiresExclusive []string `yaml:"requires_exclusive,omitempty" json:"requires_exclusive,omitempty"`
// nested/peer map keys carry no dots (validateDeploymentName). Loader-built
// runtime tree maps (Children = nested-inside venue; Members = brought-up
// alongside on the shared network) — gengotypes can't express a pattern-keyed
// self-referential map, so the Go type is pinned explicitly.
Children map[string]*Deploy `yaml:"nested,omitempty" json:"nested,omitempty"`
Members map[string]*Deploy `yaml:"peer,omitempty" json:"peer,omitempty"`
}
func (*Deploy) HasChildren ¶
HasChildren reports whether this node has any nested deployments.
func (Deploy) IsDisposable ¶
IsDisposable reports whether the deploy is safe to destroy + rebuild.
func (Deploy) IsEphemeral ¶
IsEphemeral reports whether this deploy is marked ephemeral.
func (Deploy) IsGroup ¶
IsGroup reports whether this is a GROUP bundle — no workload cross-ref but with sibling members (the cross-deployment subject+driver shape).
func (Deploy) IsPreemptible ¶
IsPreemptible reports whether this deploy holds a preemptible exclusive resource (graceful-stop side).
func (Deploy) LifecycleTag ¶
LifecycleTag returns the deploy's lifecycle tag.
func (Deploy) PreemptionHolds ¶
PreemptionHolds returns the exclusive-resource token(s) this deploy occupies.
func (Deploy) RequiredExclusive ¶
RequiredExclusive returns the exclusive-resource token(s) this deploy claims.
func (Deploy) RequiredShared ¶
RequiredShared returns the shared-mode resource token(s) this deploy claims.
type DeployExpose ¶
type DeployProbes ¶
type DeployProbes struct {
Liveness *Op `yaml:"liveness,omitempty" json:"liveness,omitempty"`
Readiness *Op `yaml:"readiness,omitempty" json:"readiness,omitempty"`
Startup *Op `yaml:"startup,omitempty" json:"startup,omitempty"`
}
DeployProbes (deploy.go) — each probe is an inline Op (the check verb vocab).
type DeployReply ¶
type DeployReply struct {
ReverseOps []ReverseOp `json:"reverse_ops,omitempty"`
Record DeployReplyRecord `json:"record"`
}
DeployReply is the structured result an external deploy provider returns from an OpExecute Invoke: the teardown ops the host records into the ledger, plus a provenance record. The host writes both via the SAME install_ledger.go path a built-in Add uses — identical persistence, record-and-replay preserved.
type DeployReplyRecord ¶
type DeployReplyRecord struct {
Candy string `json:"candy"`
Version string `json:"version,omitempty"`
}
DeployReplyRecord names the ledger CandyRecord the host writes for an external deploy: the logical candy whose ReverseOps drive teardown, plus its version.
type DeployResources ¶
type DeploySecret ¶
type DeployShellOverlay ¶
type DeployShellOverlay struct {
ID string `yaml:"id,omitempty" json:"id,omitempty"`
Init string `yaml:"init,omitempty" json:"init,omitempty"`
Origin string `yaml:"origin,omitempty" json:"origin,omitempty"`
PathAppend []string `yaml:"path_append,omitempty" json:"path_append,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
Bash *ShellSpec `yaml:"bash,omitempty" json:"bash,omitempty"`
Skip bool `yaml:"skip,omitempty" json:"skip,omitempty"`
Zsh *ShellSpec `yaml:"zsh,omitempty" json:"zsh,omitempty"`
Fish *ShellSpec `yaml:"fish,omitempty" json:"fish,omitempty"`
Sh *ShellSpec `yaml:"sh,omitempty" json:"sh,omitempty"`
}
DeployShellOverlay (deploy.go) — per-deploy shell-rc overlay: the shared #Shell body extended with the overlay identity/skip keys (id-keyed replace / skip merge semantics, MergeDeployShell).
func (*DeployShellOverlay) ByShell ¶
func (o *DeployShellOverlay) ByShell() map[string]*ShellSpec
ByShell returns the per-shell overlay map (nil when none authored).
type DeployStorage ¶
type DeployStorage struct {
Name string `yaml:"name,omitempty" json:"name"`
Size string `yaml:"size,omitempty" json:"size,omitempty"`
ClassHint string `yaml:"class_hint,omitempty" json:"class_hint,omitempty"`
Access string `yaml:"access,omitempty" json:"access,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
}
type DeployVenue ¶
type DeployVenue struct {
DeployName string `json:"deploy_name"`
Env map[string]string `json:"env,omitempty"`
Substrate json.RawMessage `json:"substrate,omitempty"`
}
DeployVenue is the venue descriptor the host puts in op.Env for an external deploy Invoke: the deploy's name plus the merged deploy-node env (KEY=VALUE lines flattened to a map). The plugin reads it to locate where to apply its effects (e.g. a scratch dir) — the analogue of snapshotCheckEnv for a verb.
Substrate carries a substrate-SPECIFIC preresolved payload a registered host-side deploy preresolver produced for the external substrate word (e.g. AndroidDeployVenue for deploy:android — the resolved adb endpoint + the apk install specs). It is OPAQUE to the generic externalDeployTarget (which never branches on the substrate); only the matching plugin decodes it. nil for an external substrate with no preresolver (the marker-only example).
type DeployVolume ¶
type DeployVolume struct {
Name string `yaml:"name,omitempty" json:"name"`
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Host string `yaml:"host,omitempty" json:"host,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
DataSeeded bool `yaml:"data_seeded,omitempty" json:"data_seeded,omitempty"`
DataSource string `yaml:"data_source,omitempty" json:"data_source,omitempty"`
}
type DetectedDevices ¶
type DetectedDevices struct {
GPU bool `json:"gpu"` // NVIDIA GPU detected AND CDI achievable (driver + (spec OR nvidia-ctk))
AMDGPU bool `json:"amd_gpu"` // AMD GPU detected (/dev/kfd + video/render groups)
AMDGFXVersion string `json:"amd_gfx_version"` // AMD GFX version for HSA_OVERRIDE_GFX_VERSION (e.g. "10.3.0")
RenderNode string `json:"render_node"` // First /dev/dri/renderD* path for DRINODE/DRI_NODE
Devices []string `json:"devices"` // Other device paths to pass via --device
}
DetectedDevices holds the results of host device auto-detection.
type Diagnostic ¶
type Diagnostic struct {
Severity string `json:"severity,omitempty"` // "error" | "warning" (empty → error)
Message string `json:"message"`
Path string `json:"path,omitempty"`
}
Diagnostic is one finding from a plugin kind's deep OpValidate check (F7/C8) — a message, an optional dotted field PATH within the entity body, and a severity ("error" fails validation; "warning" is surfaced but non-fatal; empty is treated as "error").
type Diagnostics ¶
type Diagnostics struct {
Items []Diagnostic `json:"items,omitempty"`
}
Diagnostics is the OpValidate reply: the structured findings a plugin kind returns when the host asks it to validate an authored entity body BEYOND the static CUE input-def gate. An empty Diagnostics (no items) means the body is valid.
func (Diagnostics) HasErrors ¶
func (d Diagnostics) HasErrors() bool
HasErrors reports whether any item is error-severity (empty severity counts as error).
type Distro ¶
type Distro struct {
Inherits string `yaml:"inherits,omitempty" json:"inherits,omitempty"`
InheritPackages bool `yaml:"inherit_packages,omitempty" json:"inherit_packages,omitempty"`
Version string `yaml:"version,omitempty" json:"version,omitempty"`
Bootstrap Bootstrap `yaml:"bootstrap,omitempty" json:"bootstrap,omitempty"`
Workarounds []string `yaml:"workaround,omitempty" json:"workaround,omitempty"`
Format map[string]*Format `yaml:"format,omitempty" json:"format,omitempty"`
BaseUser *BaseUser `yaml:"base_user,omitempty" json:"base_user,omitempty"`
Pacstrap *Pacstrap `yaml:"pacstrap,omitempty" json:"pacstrap,omitempty"`
Debootstrap *Debootstrap `yaml:"debootstrap,omitempty" json:"debootstrap,omitempty"`
AlpineBootstrap *AlpineBootstrap `yaml:"alpine_bootstrap,omitempty" json:"alpine_bootstrap,omitempty"`
Bootloader *Bootloader `yaml:"bootloader,omitempty" json:"bootloader,omitempty"`
Dnf *Dnf `yaml:"dnf,omitempty" json:"dnf,omitempty"`
}
func (*Distro) LocalPkgFormat ¶
LocalPkgFormat picks the format whose local_pkg block to build the charly toolchain from: the caller's primary format, then the distro's own PrimaryFormat, then any localpkg-capable format (deterministic).
func (*Distro) PrimaryFormat ¶
PrimaryFormat returns the distro's primary (non-secondary) package format.
type DistroPackages ¶
type DistroPackages struct {
Package []PackageItem `yaml:"package,omitempty" json:"package,omitempty"`
Copr []string `yaml:"copr,omitempty" json:"copr,omitempty"`
Repo []RepoBlock `yaml:"repo,omitempty" json:"repo,omitempty"`
Exclude []string `yaml:"exclude,omitempty" json:"exclude,omitempty"`
Options []string `yaml:"option,omitempty" json:"option,omitempty"`
Module []string `yaml:"module,omitempty" json:"module,omitempty"`
AUR *AUR `yaml:"aur,omitempty" json:"aur,omitempty"`
}
type EmitReply ¶
type EmitReply struct {
Fragment string `json:"fragment"`
}
EmitReply is what a plugin verb/builder returns from an OpEmit Invoke at build time: a verbatim Containerfile FRAGMENT (RUN/COPY/… directives) the generator splices into the emitted .build/<image>/Containerfile (egress-validated with the rest of the Containerfile before it hits disk). This is the build-context counterpart of a builtin verb's ProvisionActor.RenderProvisionScript (a shell RUN) generalized to any directive an external plugin owns. The host appends a trailing newline if absent.
type EncExecInput ¶
type EncExecInput struct {
Method string `json:"method"`
ImageID string `json:"image_id"`
BoxName string `json:"box_name"`
Passphrase string `json:"passphrase,omitempty"`
OldPass string `json:"old_pass,omitempty"`
NewPass string `json:"new_pass,omitempty"`
Volumes []EncVolumePlan `json:"volumes"`
}
EncExecInput is the self-contained gocryptfs-execution request the host ships to plugin-enc over OpExecute. ImageID is the systemd-ask-password / extpass id ("charly-<box>"); BoxName is the bare box name for remediation messages; Passphrase drives mount/ensure (gocryptfs init/mount via GOCRYPTFS_PASSWORD); OldPass/NewPass drive passwd. Volumes carries the host-resolved per-volume plan.
type EncExecReply ¶
type EncExecReply struct {
Error string `json:"error"`
}
EncExecReply is the execution verdict: Error == "" means success. The host shim turns a non-empty Error into a Go error.
type EncVolumePlan ¶
type EncVolumePlan struct {
Name string `json:"name"`
CipherDir string `json:"cipher_dir"`
PlainDir string `json:"plain_dir"`
ScopeUnit string `json:"scope_unit"` // "charly-enc-<dir>-<name>" (no .scope suffix)
Initialized bool `json:"initialized"`
Mounted bool `json:"mounted"`
}
EncVolumePlan is one encrypted volume, fully resolved HOST-SIDE: its charly name (for messages), the on-disk cipher/plain dirs, the systemd scope-unit name, and the host-probed initialized/mounted state. The plugin acts on these flags — it never re-derives a charly path convention nor re-probes state.
type EnvDependency ¶
type EnvDependency struct {
Name string `yaml:"name,omitempty" json:"name"`
Description string `yaml:"description,omitempty" json:"description"`
Default string `yaml:"default,omitempty" json:"default,omitempty"`
Key string `yaml:"key,omitempty" json:"key,omitempty"`
}
EnvDependency (layers.go) — ONE Go type reused for env_require/env_accept, secret_accept/secret_require, AND mcp_require/mcp_accept. The hand struct is a single SUPERSET {name, description, default, key}; the three former CUE defs (#CandyEnvDep/#CandySecretDep/#CandyMCPDep) were distinct only in their per-context name regex (env-var name vs mcp-server name) and the secret-only `key` override — all of which Go validate.go enforces. gengotypes cannot emit THREE shapes for ONE Go type, and a faithful drop-in for []EnvDependency requires every usage to carry all four fields (mcp_require's former 2-field def is missing default/key), so the three collapse to ONE shared #EnvDependency (R3 — one shared abstraction; per-context strictness stays in Go).
type EphemeralLifetime ¶
type EphemeralLifetime struct {
TTL string `yaml:"ttl,omitempty" json:"ttl,omitempty"`
KeepOnFailure bool `yaml:"keep_on_failure,omitempty" json:"keep_on_failure,omitempty"`
NamingPattern string `yaml:"naming_pattern,omitempty" json:"naming_pattern,omitempty"`
// contains filtered or unexported fields
}
EphemeralLifetime parameterizes the auto-destruction lifecycle for a deploy.
func (*EphemeralLifetime) EffectiveNamingPattern ¶
func (e *EphemeralLifetime) EffectiveNamingPattern() string
EffectiveNamingPattern returns the configured naming pattern, or the default.
func (*EphemeralLifetime) EffectiveTTL ¶
func (e *EphemeralLifetime) EffectiveTTL() time.Duration
EffectiveTTL returns the configured TTL, or the 1h default.
func (*EphemeralLifetime) IsBoolForm ¶
func (e *EphemeralLifetime) IsBoolForm() bool
IsBoolForm reports whether the field was authored as a bare boolean.
func (*EphemeralLifetime) UnmarshalJSON ¶
func (e *EphemeralLifetime) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts the boolean shorthand and the block form (the loader is JSON-based via cue.Value.Decode). `ephemeral: false` is rejected.
type EphemeralRuntime ¶
type EphemeralRuntime struct {
ID string `yaml:"id" json:"id"`
ParentVm string `yaml:"parent_vm,omitempty" json:"parent_vm,omitempty"`
ParentSnapshot string `yaml:"parent_snapshot,omitempty" json:"parent_snapshot,omitempty"`
ParentEphemeral string `yaml:"parent_ephemeral,omitempty" json:"parent_ephemeral,omitempty"`
ChildRefcount int `yaml:"child_refcount,omitempty" json:"child_refcount,omitempty"`
TimerUnit string `yaml:"timer_unit,omitempty" json:"timer_unit,omitempty"`
TtlDeadline string `yaml:"ttl_deadline,omitempty" json:"ttl_deadline,omitempty"`
Status string `yaml:"status,omitempty" json:"status,omitempty"`
InstanceName string `yaml:"instance_name,omitempty" json:"instance_name,omitempty"`
}
EphemeralRuntime is the live runtime state of an active ephemeral instantiation. Source: charly/deploy.go EphemeralRuntime.
type FeatureEntity ¶ added in v0.2026186.1143
type FeatureEntity struct {
Kind string `json:"kind"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Summary string `json:"summary,omitempty"`
Steps []FeatureStep `json:"steps,omitempty"`
ValidationErrors []string `json:"validation_errors,omitempty"`
}
FeatureEntity is one enumerated kind: entity + its plan data. Summary/Steps/ValidationErrors are populated only for entities WITH content (a non-empty description or plan) — an empty candy layer is still listed (as "(no description)") but not summarized or validated, matching the former engine.
type FeatureReply ¶ added in v0.2026186.1143
type FeatureReply struct {
Entities []FeatureEntity `json:"entities,omitempty"`
Error string `json:"error,omitempty"`
}
FeatureReply is the "feature" HostBuild kind reply — the enumerated entities the plugin formats into the list/pending/validate output. Error is a human-facing message on a load failure.
type FeatureRequest ¶ added in v0.2026186.1143
type FeatureRequest struct {
Filter string `json:"filter,omitempty"`
}
FeatureRequest is the "feature" HostBuild kind request. Filter (empty | a kind "candy"/"box" | an entity id "candy:redis") narrows the enumeration.
type FeatureStep ¶ added in v0.2026186.1143
type FeatureStep struct {
Index int `json:"index"`
Keyword string `json:"keyword"`
Text string `json:"text,omitempty"`
IsAgent bool `json:"is_agent,omitempty"`
IsCheck bool `json:"is_check,omitempty"`
}
FeatureStep is one enumerated plan step flattened to plain data (no core Step model in the plugin).
type Format ¶
type Format struct {
CacheMount []CacheMount `yaml:"cache_mount,omitempty" json:"cache_mount,omitempty"`
SectionFields map[string]string `yaml:"section_field,omitempty" json:"section_field,omitempty"`
InstallTemplate string `yaml:"install_template,omitempty" json:"install_template,omitempty"`
UninstallTemplate string `yaml:"uninstall_template,omitempty" json:"uninstall_template,omitempty"`
Phases *PhaseSet `yaml:"phase,omitempty" json:"phase,omitempty"`
Validate []FormatRule `yaml:"validate,omitempty" json:"validate,omitempty"`
Secondary bool `yaml:"secondary,omitempty" json:"secondary,omitempty"`
LocalPkg *LocalPkg `yaml:"local_pkg,omitempty" json:"local_pkg,omitempty"`
}
type FormatRule ¶
type GoogleAccount ¶
type GpuProbeInput ¶
type GpuProbeInput struct {
Action string `json:"action"` // detect-gpu | detect-amd-gpu | detect-vfio | detect-host-devices | ensure-cdi | memlock | vfio-group-accessible | amd-gfx-version
Group int `json:"group,omitempty"` // vfio-group-accessible
DevicePatterns []string `json:"device_patterns,omitempty"` // detect-host-devices
GpuVendors map[string]string `json:"gpu_vendors,omitempty"` // detect-host-devices (pickRenderNode)
PCIClassLabels map[string]string `json:"pci_class_labels,omitempty"` // detect-vfio (readPCIDevice)
}
GpuProbeInput is the action-multiplexed input the host ships to verb:gpu over OpRun. Action selects the host probe; the three data tables are threaded in from charly's embedded charly.yml (they stay in core for `charly doctor`, R3).
type GpuProbeReply ¶
type GpuProbeReply struct {
Bool bool `json:"bool,omitempty"` // detect-gpu / detect-amd-gpu / vfio-group-accessible
Str string `json:"str,omitempty"` // amd-gfx-version
Vfio *VFIOReport `json:"vfio,omitempty"` // detect-vfio
HostDevices *DetectedDevices `json:"host_devices,omitempty"` // detect-host-devices
MemlockSoft uint64 `json:"memlock_soft,omitempty"` // memlock (RLIMIT_MEMLOCK soft)
MemlockHard uint64 `json:"memlock_hard,omitempty"` // memlock (RLIMIT_MEMLOCK hard)
}
GpuProbeReply is the action-multiplexed reply from verb:gpu. Each action populates only the field(s) it produces.
type GpuSelector ¶
type GpuSelector struct {
Vendor string `yaml:"vendor,omitempty" json:"vendor"`
}
vendor required + non-empty; NOT regex-pinned (normalizePCIVendor accepts "10DE"/"0X10de"/"0x10de" — a strict regex would reject Go-valid input).
type GpuSwitchInput ¶
type GpuSwitchInput struct {
Action string `json:"action"` // switch-mode | ensure-cdi | wedge-detected | group-in-mode | current-mode | display-driver | switch-plan
Gpu *VFIOGpu `json:"gpu,omitempty"` // switch-mode / group-in-mode / current-mode / switch-plan
Mode string `json:"mode,omitempty"` // switch-mode / group-in-mode / switch-plan
Addr string `json:"addr,omitempty"` // display-driver (a single PCI function)
Vendor string `json:"vendor,omitempty"` // switch-mode (tolerant vendor-select) / ensure-cdi-N/A
}
GpuSwitchInput is the action-multiplexed input the core driver-switch shims ship to verb:gpu over OpRun for the DRIVER-SWITCH actions (cutover C9). It rides the SAME verb:gpu provider as the C11 detection actions (GpuProbeInput); the action vocabularies are disjoint, so the plugin's Invoke dispatches by which envelope decodes — detection actions decode GpuProbeInput, switch actions decode this.
type GpuSwitchReply ¶
type GpuSwitchReply struct {
Bool bool `json:"bool,omitempty"` // wedge-detected / group-in-mode
Str string `json:"str,omitempty"` // current-mode / display-driver
Plan []string `json:"plan,omitempty"` // switch-plan: the exact rebind commands (DRY-RUN, no sysfs touched)
Wedged bool `json:"wedged,omitempty"` // switch-mode: the switch wedged the device_lock (errGPUSwitchWedged)
Error string `json:"error,omitempty"` // switch-mode / ensure-cdi op failure
}
GpuSwitchReply is the action-multiplexed reply for the DRIVER-SWITCH actions.
type HolderAddr ¶
type HolderAddr struct {
Name string `yaml:"name" json:"name"` // full deploy key (for messages)
Target string `yaml:"target" json:"target"` // "vm" | "pod"
Base string `yaml:"base" json:"base"` // parseDeployKey base (pod container basis / vm fallback)
Instance string `yaml:"instance,omitempty" json:"instance,omitempty"` // parseDeployKey instance
Vm string `yaml:"vm,omitempty" json:"vm,omitempty"` // vm entity (target:vm)
}
HolderAddr is the self-contained address of a deployment (holder or claimant) — enough for the host seams to probe/stop/start it WITHOUT re-reading config, so a lease loaded after a crash can act on it. Carries BOTH yaml (the persisted ledger) AND json (the Invoke/reverse-channel envelope) tags.
type HolderDescriptor ¶
type HolderDescriptor struct {
Name string `json:"name"`
Holds []string `json:"holds"`
Addr HolderAddr `json:"addr"`
Restore string `json:"restore"`
}
HolderDescriptor is one candidate preemptible holder, pre-projected host-side.
type HostEnv ¶ added in v0.2026186.239
type HostEnv struct {
CharlyBin string `json:"charly_bin,omitempty"`
Home string `json:"home,omitempty"`
// Version is the host charly's CalVer (CharlyVersion()) — the delivery-decision authority for
// EnsureCharlyInGuest, so the plugin need not exec `<CharlyBin> version` to learn it.
Version string `json:"version,omitempty"`
}
HostEnv is the generic host identity a lifecycle plugin (running ON the host) needs but cannot derive: the host charly binary path (os.Args[0] of the CHARLY process — NOT the plugin's own binary) and the host home. Rides op.Env for every lifecycle Op so the plugin's cli legs run `<CharlyBin> …`.
type HostProbeDevice ¶ added in v0.2026186.1117
type HostProbeDevice struct {
Pattern string `json:"pattern"`
Path string `json:"path"`
Present bool `json:"present"`
Description string `json:"description"`
}
HostProbeDevice is one host device-pattern probe result (the doctor "devices" section).
type HostProbeDistro ¶ added in v0.2026186.1117
type HostProbeDistro struct {
ID string `json:"id"`
Name string `json:"name"`
Manager string `json:"manager"`
}
HostProbeDistro is the host distro identity + package manager (drives install-hint rendering).
type HostProbeReply ¶ added in v0.2026186.1117
type HostProbeReply struct {
GPU bool `json:"gpu"`
AMDGPU bool `json:"amd_gpu"`
AMDGFXVersion string `json:"amd_gfx_version,omitempty"`
GPUFlags []string `json:"gpu_flags,omitempty"`
Vfio *VFIOReport `json:"vfio,omitempty"`
MemlockSoft uint64 `json:"memlock_soft"`
MemlockHard uint64 `json:"memlock_hard"`
VfioPciAvailable bool `json:"vfio_pci_available"`
GroupAccessible map[int]bool `json:"group_accessible,omitempty"`
Devices []HostProbeDevice `json:"devices,omitempty"`
Distro HostProbeDistro `json:"distro"`
InstallHints map[string]map[string]string `json:"install_hints,omitempty"`
DistroFamilyMap map[string]string `json:"distro_family_map,omitempty"`
ConfigPath string `json:"config_path,omitempty"`
Credential *CredentialHealth `json:"credential,omitempty"`
CredentialErr string `json:"credential_err,omitempty"`
Error string `json:"error,omitempty"`
}
HostProbeReply is the "hostprobe" HostBuild kind reply — RAW host facts the plugin renders into the report. All fields are best-effort (a probe failure leaves its field zero/empty, mirroring the shims).
type HostProbeRequest ¶ added in v0.2026186.1117
type HostProbeRequest struct {
Engine string `json:"engine,omitempty"`
}
HostProbeRequest is the "hostprobe" HostBuild kind request. Engine hints which container engine's GPU run-flags to compute (empty → the host resolves it).
type Init ¶
type Init struct {
CandyFields []string `yaml:"candy_field,omitempty" json:"candy_field,omitempty"`
CandyFiles []string `yaml:"candy_file,omitempty" json:"candy_file,omitempty"`
DependsCandy string `yaml:"depends_candy,omitempty" json:"depends_candy,omitempty"`
RequiresCapability []string `yaml:"requires_capability,omitempty" json:"requires_capability,omitempty"`
// The one mandatory field: the build model.
Model string `yaml:"model,omitempty" json:"model"`
HeaderFile string `yaml:"header_file,omitempty" json:"header_file,omitempty"`
FragmentDir string `yaml:"fragment_dir,omitempty" json:"fragment_dir,omitempty"`
RelayTemplate string `yaml:"relay_template,omitempty" json:"relay_template,omitempty"`
StageName string `yaml:"stage_name,omitempty" json:"stage_name,omitempty"`
StageHeaderCopy string `yaml:"stage_header_copy,omitempty" json:"stage_header_copy,omitempty"`
StageFragmentCopy string `yaml:"stage_fragment_copy,omitempty" json:"stage_fragment_copy,omitempty"`
AssemblyTemplate string `yaml:"assembly_template,omitempty" json:"assembly_template,omitempty"`
SystemEnableTemplate string `yaml:"system_enable_template,omitempty" json:"system_enable_template,omitempty"`
PostAssemblyTemplate string `yaml:"post_assembly_template,omitempty" json:"post_assembly_template,omitempty"`
Entrypoint []string `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"`
FallbackEntrypoint []string `yaml:"fallback_entrypoint,omitempty" json:"fallback_entrypoint,omitempty"`
ManagementTool string `yaml:"management_tool,omitempty" json:"management_tool,omitempty"`
ManagementCommands map[string]string `yaml:"management_command,omitempty" json:"management_command,omitempty"`
LabelKey string `yaml:"label_key,omitempty" json:"label_key,omitempty"`
ServiceSchema *InitServiceSchema `yaml:"service_schema,omitempty" json:"service_schema,omitempty"`
}
type InitServiceSchema ¶
type InitServiceSchema struct {
ServiceTemplate string `yaml:"service_template,omitempty" json:"service_template,omitempty"`
UnitPathTemplate string `yaml:"unit_path_template,omitempty" json:"unit_path_template,omitempty"`
DropinTemplate string `yaml:"dropin_template,omitempty" json:"dropin_template,omitempty"`
DropinPathTemplate string `yaml:"dropin_path_template,omitempty" json:"dropin_path_template,omitempty"`
SupportsPackaged bool `yaml:"supports_packaged,omitempty" json:"supports_packaged,omitempty"`
}
type InstallOpts ¶
type InstallOpts struct {
WithServices bool `yaml:"with_service,omitempty" json:"with_service,omitempty"`
AllowRepoChanges bool `yaml:"allow_repo_changes,omitempty" json:"allow_repo_changes,omitempty"`
AllowRootTasks bool `yaml:"allow_root_tasks,omitempty" json:"allow_root_tasks,omitempty"`
SkipIncompatible bool `yaml:"skip_incompatible,omitempty" json:"skip_incompatible,omitempty"`
Verify bool `yaml:"verify,omitempty" json:"verify,omitempty"`
BuilderImage string `yaml:"builder_image,omitempty" json:"builder_image,omitempty"`
}
install_opts gates (deploy.go InstallOptsConfig) — shared by local + deploy.
type InstallPlanView ¶
type InstallPlanView struct {
DeployID string `json:"deploy_id,omitempty"`
Box string `json:"box,omitempty"`
Version string `json:"version,omitempty"`
Distro string `json:"distro,omitempty"`
Candy string `json:"candy,omitempty"`
CandiesIncluded []string `json:"candies_included,omitempty"`
AddCandies []string `json:"add_candies,omitempty"`
BuilderImage string `json:"builder_image,omitempty"`
Meta map[string]string `json:"meta,omitempty"`
// Steps is the serializable per-step IR — the ordered InstallStep sequence the
// in-core InstallPlan carries, projected onto the wire union below. An external
// deploy/step plugin walks it and EXECUTES each step on the venue (the out-of-proc
// twin of the local deploy target's in-proc walk), pushing files via the ExecutorService
// PutFile leg and running shell via RunSystem/RunUser.
Steps []InstallStepView `json:"steps,omitempty"`
}
InstallPlanView is the JSON-roundtrippable wire VIEW of an InstallPlan. The rich in-core InstallPlan (package main) carries a `Steps []InstallStep` interface slice; the host serializes it into the Steps field below via the SINGLE stepToView / stepFromView converter (package main charly/step_view.go), so an EXTERNAL deploy/step plugin that EXECUTES the plan walks the same ordered step IR the in-proc DeployTargets walk — the wire path and the in-proc path carry identical data (R3; proven by the step-IR round-trip test). The remaining fields are the plan's identity + provenance.
type InstallStepView ¶
type InstallStepView struct {
Kind string `json:"kind"` // the StepKind discriminator ("File","ShellHook","Op",…)
// Derived ADVISORY fields — the step's Scope()/Venue()/RequiresGate() method
// results, populated by stepToView so an executing plugin knows where the effect
// lands (system → sudo / root-owned PutFile, user → no sudo), where it runs, and
// which opt-in gate it needs, WITHOUT recomputing the rule (R3 — the rule lives on
// the concrete step's methods, called once in stepToView). stepFromView IGNORES
// them: the reconstructed concrete step recomputes the same values from its stored
// fields, so these never participate in step round-trip identity.
Scope Scope `json:"scope,omitempty"`
Venue int `json:"venue,omitempty"`
Gate string `json:"gate,omitempty"`
// Payload is the OPAQUE per-kind input for an EXTERNAL (plugin-contributed) step kind
// (F3 — Kind == "external:<word>"): the bytes the host forwards verbatim as the serving
// class:step plugin's OpExecute params. For an external kind the Scope/Venue/Gate fields
// above are AUTHORITATIVE, not advisory — the host carries the plugin-DECLARED contract
// (it cannot recompute it from a concrete step, there being no compiled-in case), so
// stepFromView rebuilds the external step from these carried values + this Payload. nil
// for every builtin (compiled-in) step kind.
Payload json.RawMessage `json:"payload,omitempty"`
// ReverseOps is the step's host-computed teardown ops — step.Reverse() called ONCE
// host-side in stepToView. An OUT-OF-PROCESS plugin that EXECUTES a plugin-renderable
// step itself (via RunSystem/RunUser/PutFile) cannot call the package-main Reverse()
// method, so it ECHOES these into its DeployReply for record-and-replay teardown — the
// Reverse() rule stays ONCE in package main (R3); the plugin gains zero reverse logic.
// For the two deploy-time-stateful kinds (ServicePackaged.PriorEnabled,
// ShellHook.EnvFile), the host captures that state on the live venue BEFORE projecting
// the view, so the recorded ops are faithful. The HOST-ENGINE kinds (Builder /
// LocalPkgInstall / SystemPackages / act-Op / ExternalPlugin) ride RunHostStep, which
// returns their reverse ops separately, so the plugin ignores this field for the kinds
// it routes to RunHostStep. Like the Scope/Venue/Gate advisory fields, stepFromView
// IGNORES it (round-trip identity is unaffected).
ReverseOps []ReverseOp `json:"reverse_ops,omitempty"`
// Shared identity / provenance.
CandyName string `json:"candy_name,omitempty"` // every kind
CandyDir string `json:"candy_dir,omitempty"` // Builder / Op / ApkInstall / LocalPkgInstall
// SystemPackagesStep + RepoChangeStep + LocalPkgInstallStep.
Format string `json:"format,omitempty"`
// SystemPackagesStep + BuilderStep three-phase tag (int Phase: prepare/install/cleanup).
Phase int `json:"phase,omitempty"`
// SystemPackagesStep.
Packages []string `json:"packages,omitempty"`
Repos []map[string]any `json:"repos,omitempty"` // each = a RepoSpec.Raw map
Options []string `json:"options,omitempty"`
Copr []string `json:"copr,omitempty"`
Modules []string `json:"modules,omitempty"`
Exclude []string `json:"exclude,omitempty"`
Keys []string `json:"keys,omitempty"`
CacheMount []CacheMountView `json:"cache_mount,omitempty"`
RawInstallContext map[string]any `json:"raw_install_context,omitempty"`
// BuilderStep.
Builder string `json:"builder,omitempty"`
BuilderImage string `json:"builder_image,omitempty"`
Artifacts []ArtifactView `json:"artifacts,omitempty"`
RawStageContext map[string]any `json:"raw_stage_context,omitempty"`
BuilderDef *BuilderDef `json:"builder_def,omitempty"`
// LocalPkg is shared by BuilderStep (aur) + LocalPkgInstallStep.
LocalPkg *LocalPkg `json:"local_pkg,omitempty"`
// OpStep + ExternalPluginStep (Op + the shared user/ctx/distro fields).
Op *Op `json:"op,omitempty"`
CtxPath string `json:"ctx_path,omitempty"`
ResolvedUser string `json:"resolved_user,omitempty"`
To string `json:"to,omitempty"`
CandyVars map[string]string `json:"candy_vars,omitempty"`
Distros []string `json:"distros,omitempty"`
// FileStep.
Source string `json:"source,omitempty"`
Dest string `json:"dest,omitempty"`
Mode uint32 `json:"mode,omitempty"` // os.FileMode underlying value
Owner string `json:"owner,omitempty"`
// ServicePackagedStep + ServiceCustomStep.
Unit string `json:"unit,omitempty"` // packaged unit name
Name string `json:"name,omitempty"` // custom service name
TargetScope Scope `json:"target_scope,omitempty"` // both
Enable bool `json:"enable,omitempty"` // both
OverridesText string `json:"overrides_text,omitempty"` // packaged drop-in
OverridesPath string `json:"overrides_path,omitempty"` // packaged drop-in
PriorEnabled bool `json:"prior_enabled,omitempty"` // packaged
UnitText string `json:"unit_text,omitempty"` // custom unit body
UnitPath string `json:"unit_path,omitempty"` // custom unit path
// ShellHookStep.
EnvVars map[string]string `json:"env_vars,omitempty"`
PathAdd []string `json:"path_add,omitempty"`
EnvFile string `json:"env_file,omitempty"`
// ShellSnippetStep.
Origin string `json:"origin,omitempty"`
Shell string `json:"shell,omitempty"`
Snippet string `json:"snippet,omitempty"`
PathAppend []string `json:"path_append,omitempty"`
Destination string `json:"destination,omitempty"`
Marker string `json:"marker,omitempty"`
UseDropin bool `json:"use_dropin,omitempty"`
Priority int `json:"priority,omitempty"`
// RepoChangeStep.
File string `json:"file,omitempty"`
Content string `json:"content,omitempty"`
Checksum string `json:"checksum,omitempty"`
// ApkInstallStep.
ApkPackages []ApkPackageSpec `json:"apk_packages,omitempty"`
// LocalPkgInstallStep.
PkgbuildRef string `json:"pkgbuild_ref,omitempty"`
ProjectDir string `json:"project_dir,omitempty"`
}
InstallStepView is the JSON-roundtrippable wire form of ONE InstallStep. The in-core IR (package main install_plan.go) has 13 concrete step types behind the InstallStep interface; this is their tagged-union projection, discriminated by Kind (the StepKind string). It is a SUPERSET struct: each kind populates the subset of fields it carries, all `omitempty` so the wire stays compact.
What it deliberately does NOT carry: Scope() / Venue() / RequiresGate() / Reverse(). Those are METHODS computed from the stored fields on the concrete step, not stored data — so stepFromView reconstructs the SAME concrete Go step type and all four methods (and therefore the step's execute semantics + ordering) are byte-identical to the in-proc path. The wire view carries only the stored data; the behaviour rides along for free. That is the structural guarantee the in-proc and wire paths cannot diverge (R3).
The package-main↔view mapping lives in ONE place — stepToView / stepFromView (charly/step_view.go) — and the step-IR round-trip test proves every kind survives stepFromView(stepToView(s)) DeepEqual-intact.
type Iterate ¶
type Iterate struct {
Agent []string `yaml:"agent,omitempty" json:"agent,omitempty"`
Sandbox string `yaml:"sandbox,omitempty" json:"sandbox"`
PlateauIteration int `yaml:"plateau_iteration,omitempty" json:"plateau_iteration,omitempty"`
Prompt string `yaml:"prompt,omitempty" json:"prompt,omitempty"`
Note *bool `yaml:"note,omitempty" json:"note,omitempty"`
Env StrMap `yaml:"env,omitempty" json:"env,omitempty"`
MCPEndpoint *string `yaml:"mcp_endpoint,omitempty" json:"mcp_endpoint,omitempty"`
}
func (*Iterate) NotesEnabled ¶
NotesEnabled reports whether the iteration NOTES.md memory is on (default on).
type K8s ¶
type K8s struct {
// May be empty (a cluster-policy-only template runs no workload itself).
Box string `yaml:"box,omitempty" json:"box"`
Replica *int `yaml:"replica,omitempty" json:"replica,omitempty"`
Resources *K8sResources `yaml:"resources,omitempty" json:"resources,omitempty"`
Hostnames []K8sHostname `yaml:"hostnames,omitempty" json:"hostnames,omitempty"`
KubeconfigContext string `yaml:"kubeconfig_context,omitempty" json:"kubeconfig_context,omitempty"`
AdmissionPolicy string `yaml:"admission_policy,omitempty" json:"admission_policy,omitempty"`
DefaultNamespace string `yaml:"default_namespace,omitempty" json:"default_namespace,omitempty"`
Storage K8sStorage `yaml:"storage,omitempty" json:"storage,omitempty"`
Ingress K8sIngressDefaults `yaml:"ingress,omitempty" json:"ingress,omitempty"`
GatewayAPI K8sGatewayAPI `yaml:"gateway_api,omitempty" json:"gateway_api,omitempty"`
Secret K8sSecretsBackend `yaml:"secret,omitempty" json:"secret,omitempty"`
ImageDefault K8sImagesDefaults `yaml:"image_default,omitempty" json:"image_default,omitempty"`
PodDefault K8sPodDefaults `yaml:"pod_default,omitempty" json:"pod_default,omitempty"`
Observability K8sObservability `yaml:"observability,omitempty" json:"observability,omitempty"`
NetworkPolicy string `yaml:"network_policy,omitempty" json:"network_policy,omitempty"`
Defaults K8sResourceDefaults `yaml:"defaults,omitempty" json:"defaults,omitempty"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
}
type K8sDeployVenue ¶
type K8sDeployVenue struct {
OverlayPath string `json:"overlay_path"` // <root>/overlays/<inst> — the `kubectl apply -k` argument
TreeRoot string `json:"tree_root,omitempty"` // <root> = .opencharly/k8s/<name> — removed at teardown
KubeContext string `json:"kube_context,omitempty"` // kind:k8s template's kubeconfig_context → `kubectl --context` (empty → current-context)
DeployName string `json:"deploy_name,omitempty"` // for plugin-side log messages
}
K8sDeployVenue is the preresolved deploy:k8s substrate payload the host's k8s deploy preresolver (charly/k8s_deploy_preresolve.go) produces in DeployVenue.Substrate and the candy/plugin-kube deploy:k8s provider decodes.
Unlike deploy:android — where the plugin DRIVES the device and the host only resolves the endpoint + apk specs — the k8s Kustomize GENERATOR moved into the compiled-in candy/plugin-k8sgen (verb:k8sgen, C8/M13), fronted by the in-core GenerateK8sKustomize shim: the shim lifts the image Capabilities (read from the OCI labels via ExtractMetadata) to ports/uid/gid, Invokes the generator's OpEmit, then applies the host-side egress gate (#K8sObject / #Kustomization) + disk I/O. It has a SECOND in-core consumer (`charly bundle from-box --target k8s`, k8s_deploy_from_box.go). So the host generates the egress-validated Kustomize tree under .opencharly/k8s/<name>/ and ships only the resolved overlay path + tree root. The plugin owns the LIVE cluster I/O — `kubectl apply -k <OverlayPath>` at deploy, and the recorded teardown (`kubectl delete -k` + remove the tree) replayed at `charly bundle del` — the k8s analogue of plugin-adb installing apps after the host resolves the specs. The host generates what needs core machinery; the plugin does the live external-system I/O it owns.
type K8sGatewayAPI ¶
type K8sGenFile ¶
type K8sGenFile struct {
RelPath string `json:"rel_path"`
Doc json.RawMessage `json:"doc"`
EgressKind string `json:"egress_kind"`
}
K8sGenFile is one generated manifest the plugin returns: its RELATIVE path (under OutputDir/DeploymentName, e.g. "base/deployment.yaml"), the manifest as JSON (the host unmarshals it back to a value, egress-validates, and writes it as YAML), and the egress kind that gates it ("k8s_object" or "kustomization").
type K8sGenInput ¶
type K8sGenInput struct {
DeploymentName string `json:"deployment_name"`
Instance string `json:"instance"`
ImageRef string `json:"image_ref"`
Deploy Deploy `json:"deploy"` // = the former BundleNode
Cluster K8s `json:"cluster"` // = the former K8sSpec
Ports []string `json:"ports"` // from BoxMetadata.Port
UID int `json:"uid"` // from BoxMetadata.UID
GID int `json:"gid"` // from BoxMetadata.GID
OutputDir string `json:"output_dir"` // provenance; the host owns disk paths
}
K8sGenInput is the pure-generation input the host ships to plugin-k8sgen over OpEmit. Deploy is the deployment node (the former BundleNode = spec.Deploy); Cluster is the kind:k8s cluster template (the former K8sSpec = spec.K8s); Ports / UID / GID are lifted from the image's OCI-label Capabilities host-side so the plugin needs no access to the package-main BoxMetadata type.
type K8sGenReply ¶
type K8sGenReply struct {
OverlayRelPath string `json:"overlay_rel_path"`
Files []K8sGenFile `json:"files"`
}
K8sGenReply is the pure-generation output: the RELATIVE overlay path the host joins onto OutputDir/DeploymentName to form the `kubectl apply -k` argument, and the collected manifest files (base resources + base/overlay kustomizations).
type K8sHostname ¶
type K8sImagesDefaults ¶
type K8sIngressDefaults ¶
type K8sIngressDefaults struct {
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
Class string `yaml:"class,omitempty" json:"class,omitempty"`
CertIssuer string `yaml:"cert_issuer,omitempty" json:"cert_issuer,omitempty"`
PathTypeDefault string `yaml:"path_type_default,omitempty" json:"path_type_default,omitempty"`
}
type K8sObservability ¶
type K8sPatch ¶
type K8sPatch struct {
Target struct {
Kind string `yaml:"kind,omitempty" json:"kind,omitempty"`
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Namespace string `yaml:"namespace,omitempty" json:"namespace,omitempty"`
} `yaml:"target,omitempty" json:"target"`
Patch string `yaml:"patch,omitempty" json:"patch"`
}
type K8sPodDefaults ¶
type K8sPodDefaults struct {
PriorityClass string `yaml:"priority_class,omitempty" json:"priority_class,omitempty"`
// Raw Kubernetes Toleration objects (Go []map[string]any) — genuine
// passthrough, so each element stays OPEN.
Tolerations []map[string]any `yaml:"tolerations,omitempty" json:"tolerations,omitempty"`
NodeSelector map[string]string `yaml:"node_selector,omitempty" json:"node_selector,omitempty"`
}
type K8sResourceDefaults ¶
type K8sResourceValues ¶
type K8sResources ¶
type K8sResources struct {
Requests K8sResourceValues `yaml:"requests,omitempty" json:"requests,omitempty"`
Limits K8sResourceValues `yaml:"limits,omitempty" json:"limits,omitempty"`
}
type K8sSecretsBackend ¶
type K8sStorage ¶
type K8sStorage struct {
ClassDefault string `yaml:"class_default,omitempty" json:"class_default,omitempty"`
ClassCheap string `yaml:"class_cheap,omitempty" json:"class_cheap,omitempty"`
ClassEncrypted string `yaml:"class_encrypted,omitempty" json:"class_encrypted,omitempty"`
ClassFast string `yaml:"class_fast,omitempty" json:"class_fast,omitempty"`
AccessModeDefault string `yaml:"access_mode_default,omitempty" json:"access_mode_default,omitempty"`
}
type LibvirtAudio ¶
type LibvirtCPU ¶
type LibvirtCPU struct {
// mode is REQUIRED-with-default (renderer default host-passthrough) so the
// custom⇒model if-guard below can reference it (optional fields error when
// absent). #LibvirtCPU only instantiates when `cpu:` is present.
Mode string `yaml:"mode,omitempty" json:"mode"`
Model string `yaml:"model,omitempty" json:"model,omitempty"`
Check string `yaml:"check,omitempty" json:"check,omitempty"`
Migratable string `yaml:"migratable,omitempty" json:"migratable,omitempty"`
Topology *LibvirtCPUTopology `yaml:"topology,omitempty" json:"topology,omitempty"`
Features []LibvirtCPUFeature `yaml:"features,omitempty" json:"features,omitempty"`
Cache *LibvirtCPUCache `yaml:"cache,omitempty" json:"cache,omitempty"`
NUMA []LibvirtNUMACell `yaml:"numa,omitempty" json:"numa,omitempty"`
}
type LibvirtCPUCache ¶
type LibvirtCPUFeature ¶
type LibvirtCPUTopology ¶
type LibvirtCPUTune ¶
type LibvirtCPUTune struct {
Period int `yaml:"period,omitempty" json:"period,omitempty"`
Quota int `yaml:"quota,omitempty" json:"quota,omitempty"`
GlobalPeriod int `yaml:"global_period,omitempty" json:"global_period,omitempty"`
GlobalQuota int `yaml:"global_quota,omitempty" json:"global_quota,omitempty"`
EmulatorPeriod int `yaml:"emulator_period,omitempty" json:"emulator_period,omitempty"`
EmulatorQuota int `yaml:"emulator_quota,omitempty" json:"emulator_quota,omitempty"`
IOThreadPeriod int `yaml:"iothread_period,omitempty" json:"iothread_period,omitempty"`
IOThreadQuota int `yaml:"iothread_quota,omitempty" json:"iothread_quota,omitempty"`
VCPUPin []LibvirtVCPUPin `yaml:"vcpupin,omitempty" json:"vcpupin,omitempty"`
EmulatorPin *LibvirtEmulatorPin `yaml:"emulatorpin,omitempty" json:"emulatorpin,omitempty"`
IOThreadPin []LibvirtIOThreadPin `yaml:"iothreadpin,omitempty" json:"iothreadpin,omitempty"`
}
type LibvirtChannel ¶
type LibvirtClock ¶
type LibvirtClock struct {
Offset string `yaml:"offset,omitempty" json:"offset,omitempty"`
Timezone string `yaml:"timezone,omitempty" json:"timezone,omitempty"`
Adjustment string `yaml:"adjustment,omitempty" json:"adjustment,omitempty"`
Basis string `yaml:"basis,omitempty" json:"basis,omitempty"`
Timers []LibvirtTimer `yaml:"timers,omitempty" json:"timers,omitempty"`
}
type LibvirtConsole ¶
type LibvirtDevices ¶
type LibvirtDevices struct {
Emulator string `yaml:"emulator,omitempty" json:"emulator,omitempty"`
Disks []LibvirtDisk `yaml:"disks,omitempty" json:"disks,omitempty"`
Interfaces []LibvirtInterface `yaml:"interfaces,omitempty" json:"interfaces,omitempty"`
Channels []LibvirtChannel `yaml:"channels,omitempty" json:"channels,omitempty"`
Serial []LibvirtSerial `yaml:"serial,omitempty" json:"serial,omitempty"`
Console []LibvirtConsole `yaml:"console,omitempty" json:"console,omitempty"`
Parallel []LibvirtParallel `yaml:"parallel,omitempty" json:"parallel,omitempty"`
Graphics []LibvirtGraphics `yaml:"graphics,omitempty" json:"graphics,omitempty"`
Video []LibvirtVideo `yaml:"video,omitempty" json:"video,omitempty"`
Audio []LibvirtAudio `yaml:"audio,omitempty" json:"audio,omitempty"`
Sound []LibvirtSound `yaml:"sound,omitempty" json:"sound,omitempty"`
Inputs []LibvirtInput `yaml:"inputs,omitempty" json:"inputs,omitempty"`
USB []LibvirtUSB `yaml:"usb,omitempty" json:"usb,omitempty"`
RedirDev []LibvirtRedirDev `yaml:"redirdev,omitempty" json:"redirdev,omitempty"`
Hostdevs []LibvirtHostdev `yaml:"hostdevs,omitempty" json:"hostdevs,omitempty"`
Filesystems []LibvirtFilesystem `yaml:"filesystems,omitempty" json:"filesystems,omitempty"`
RNG []LibvirtRNG `yaml:"rng,omitempty" json:"rng,omitempty"`
TPM []LibvirtTPM `yaml:"tpm,omitempty" json:"tpm,omitempty"`
Watchdog []LibvirtWatchdog `yaml:"watchdog,omitempty" json:"watchdog,omitempty"`
MemBalloon *LibvirtMemBalloon `yaml:"memballoon,omitempty" json:"memballoon,omitempty"`
Shmem []LibvirtShmem `yaml:"shmem,omitempty" json:"shmem,omitempty"`
IOMMU *LibvirtIOMMU `yaml:"iommu,omitempty" json:"iommu,omitempty"`
Vsock *LibvirtVsock `yaml:"vsock,omitempty" json:"vsock,omitempty"`
Panic []LibvirtPanic `yaml:"panic,omitempty" json:"panic,omitempty"`
Smartcard []LibvirtSmartcard `yaml:"smartcard,omitempty" json:"smartcard,omitempty"`
Hub []LibvirtHub `yaml:"hub,omitempty" json:"hub,omitempty"`
}
type LibvirtDisk ¶
type LibvirtDisk struct {
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Device string `yaml:"device,omitempty" json:"device,omitempty"`
Source map[string]string `yaml:"source,omitempty" json:"source,omitempty"`
Target map[string]string `yaml:"target,omitempty" json:"target,omitempty"`
Driver map[string]string `yaml:"driver,omitempty" json:"driver,omitempty"`
Readonly *bool `yaml:"readonly,omitempty" json:"readonly,omitempty"`
Serial string `yaml:"serial,omitempty" json:"serial,omitempty"`
WWN string `yaml:"wwn,omitempty" json:"wwn,omitempty"`
Boot int `yaml:"boot,omitempty" json:"boot,omitempty"`
}
type LibvirtDomain ¶
type LibvirtDomain struct {
Snippets []string `yaml:"snippets,omitempty" json:"snippets,omitempty"`
XMLPassthrough string `yaml:"xml_passthrough,omitempty" json:"xml_passthrough,omitempty"`
Features *LibvirtFeatures `yaml:"features,omitempty" json:"features,omitempty"`
CPU *LibvirtCPU `yaml:"cpu,omitempty" json:"cpu,omitempty"`
Clock *LibvirtClock `yaml:"clock,omitempty" json:"clock,omitempty"`
MemoryBacking *LibvirtMemoryBacking `yaml:"memory_backing,omitempty" json:"memory_backing,omitempty"`
MemTune *LibvirtMemTune `yaml:"memtune,omitempty" json:"memtune,omitempty"`
NUMATune *LibvirtNUMATune `yaml:"numatune,omitempty" json:"numatune,omitempty"`
CPUTune *LibvirtCPUTune `yaml:"cputune,omitempty" json:"cputune,omitempty"`
IOThreads int `yaml:"iothreads,omitempty" json:"iothreads,omitempty"`
Devices *LibvirtDevices `yaml:"devices,omitempty" json:"devices,omitempty"`
SecLabel *LibvirtSecLabel `yaml:"seclabel,omitempty" json:"seclabel,omitempty"`
LaunchSecurity *LibvirtLaunchSecurity `yaml:"launch_security,omitempty" json:"launch_security,omitempty"`
Resource *LibvirtResource `yaml:"resource,omitempty" json:"resource,omitempty"`
SysInfo *LibvirtSysInfo `yaml:"sysinfo,omitempty" json:"sysinfo,omitempty"`
}
--------------------------------------------------------------------------- libvirt: LibvirtDomain (libvirt_yaml.go). CLOSED, every sub-type modeled as a #Libvirt<Name> def. Genuine passthroughs stay typed (NOT blanket `{...}`): snippets/xml_passthrough (raw XML) and every map[string]string Go field as `{[string]: string}`. ---------------------------------------------------------------------------
type LibvirtEmulatorPin ¶
type LibvirtEmulatorPin struct {
CPUSet string `yaml:"cpuset,omitempty" json:"cpuset"`
}
type LibvirtFeatures ¶
type LibvirtFeatures struct {
ACPI *bool `yaml:"acpi,omitempty" json:"acpi,omitempty"`
APIC *bool `yaml:"apic,omitempty" json:"apic,omitempty"`
PAE *bool `yaml:"pae,omitempty" json:"pae,omitempty"`
SMM *bool `yaml:"smm,omitempty" json:"smm,omitempty"`
HAP *bool `yaml:"hap,omitempty" json:"hap,omitempty"`
VMPort *bool `yaml:"vmport,omitempty" json:"vmport,omitempty"`
PMU *bool `yaml:"pmu,omitempty" json:"pmu,omitempty"`
HyperV *LibvirtHyperV `yaml:"hyperv,omitempty" json:"hyperv,omitempty"`
KVM *LibvirtKVM `yaml:"kvm,omitempty" json:"kvm,omitempty"`
IBS string `yaml:"ibs,omitempty" json:"ibs,omitempty"`
}
type LibvirtFilesystem ¶
type LibvirtFilesystem struct {
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
AccessMode string `yaml:"accessmode,omitempty" json:"accessmode,omitempty"`
Source string `yaml:"source,omitempty" json:"source"`
Target string `yaml:"target,omitempty" json:"target"`
Readonly *bool `yaml:"readonly,omitempty" json:"readonly,omitempty"`
Binary map[string]string `yaml:"binary,omitempty" json:"binary,omitempty"`
}
type LibvirtGraphics ¶
type LibvirtGraphics struct {
Type string `yaml:"type,omitempty" json:"type"`
Port int `yaml:"port,omitempty" json:"port,omitempty"`
AutoPort string `yaml:"autoport,omitempty" json:"autoport,omitempty"`
Listen LibvirtGraphicsListeners `yaml:"listen,omitempty" json:"listen,omitempty"`
Passwd string `yaml:"passwd,omitempty" json:"passwd,omitempty"`
Keymap string `yaml:"keymap,omitempty" json:"keymap,omitempty"`
GL string `yaml:"gl,omitempty" json:"gl,omitempty"`
}
type LibvirtGraphicsListen ¶
type LibvirtGraphicsListen struct {
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Address string `yaml:"address,omitempty" json:"address,omitempty"`
Network string `yaml:"network,omitempty" json:"network,omitempty"`
Socket string `yaml:"socket,omitempty" json:"socket,omitempty"`
}
--------------------------------------------------------------------------- LibvirtGraphicsListen / LibvirtGraphicsListeners — #LibvirtListen (libvirt_yaml_listen.go). scalar | map | list of listeners. ---------------------------------------------------------------------------
type LibvirtGraphicsListeners ¶
type LibvirtGraphicsListeners []LibvirtGraphicsListen
LibvirtGraphicsListeners is the YAML-shaped list of listeners for one <graphics> element.
func (LibvirtGraphicsListeners) First ¶
func (ll LibvirtGraphicsListeners) First() LibvirtGraphicsListen
First returns the first listener, or the zero value if empty.
type LibvirtHostdev ¶
type LibvirtHostdev struct {
Type string `yaml:"type" json:"type"`
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
Managed string `yaml:"managed,omitempty" json:"managed,omitempty"`
Source map[string]string `yaml:"source" json:"source"`
ROM map[string]string `yaml:"rom,omitempty" json:"rom,omitempty"`
Driver map[string]string `yaml:"driver,omitempty" json:"driver,omitempty"`
}
--------------------------------------------------------------------------- LibvirtHostdev — #LibvirtHostdev (libvirt_yaml.go). The `if type=="pci"` source-redefine degrades the generated def to `any`. ---------------------------------------------------------------------------
type LibvirtHub ¶
type LibvirtHub struct {
Type string `yaml:"type,omitempty" json:"type"`
}
type LibvirtHugepages ¶
type LibvirtHyperV ¶
type LibvirtHyperV struct {
Relaxed string `yaml:"relaxed,omitempty" json:"relaxed,omitempty"`
VAPIC string `yaml:"vapic,omitempty" json:"vapic,omitempty"`
Spinlocks *LibvirtSpinlocks `yaml:"spinlocks,omitempty" json:"spinlocks,omitempty"`
VPIndex string `yaml:"vpindex,omitempty" json:"vpindex,omitempty"`
Runtime string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
Synic string `yaml:"synic,omitempty" json:"synic,omitempty"`
STimer string `yaml:"stimer,omitempty" json:"stimer,omitempty"`
Reset string `yaml:"reset,omitempty" json:"reset,omitempty"`
VendorID *LibvirtVendorID `yaml:"vendor_id,omitempty" json:"vendor_id,omitempty"`
Frequencies string `yaml:"frequencies,omitempty" json:"frequencies,omitempty"`
Reenlightenment string `yaml:"reenlightenment,omitempty" json:"reenlightenment,omitempty"`
TLBFlush string `yaml:"tlbflush,omitempty" json:"tlbflush,omitempty"`
IPI string `yaml:"ipi,omitempty" json:"ipi,omitempty"`
EVMCS string `yaml:"evmcs,omitempty" json:"evmcs,omitempty"`
}
HyperV enlightenment toggles — all "on"/"off"-ish strings; no Go validator, kept plain string to avoid false-rejecting valid libvirt values.
type LibvirtIOMMU ¶
type LibvirtIOThreadPin ¶
type LibvirtInput ¶
type LibvirtInterface ¶
type LibvirtInterface struct {
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Source map[string]string `yaml:"source,omitempty" json:"source,omitempty"`
Model string `yaml:"model,omitempty" json:"model,omitempty"`
MAC string `yaml:"mac,omitempty" json:"mac,omitempty"`
MTU int `yaml:"mtu,omitempty" json:"mtu,omitempty"`
Driver map[string]string `yaml:"driver,omitempty" json:"driver,omitempty"`
Boot int `yaml:"boot,omitempty" json:"boot,omitempty"`
PortForwards []LibvirtPortForward `yaml:"port_forwards,omitempty" json:"port_forwards,omitempty"`
}
type LibvirtKVM ¶
type LibvirtKVM struct {
Hidden string `yaml:"hidden,omitempty" json:"hidden,omitempty"`
HintDedicated string `yaml:"hint_dedicated,omitempty" json:"hint_dedicated,omitempty"`
PollControl string `yaml:"poll_control,omitempty" json:"poll_control,omitempty"`
PVIPI string `yaml:"pv_ipi,omitempty" json:"pv_ipi,omitempty"`
DirtyRingSize int `yaml:"dirty_ring_size,omitempty" json:"dirty_ring_size,omitempty"`
}
type LibvirtLaunchSecurity ¶
type LibvirtLaunchSecurity struct {
Type string `yaml:"type,omitempty" json:"type,omitempty"`
CBitPos int `yaml:"cbitpos,omitempty" json:"cbitpos,omitempty"`
ReducedPhysBits int `yaml:"reduced_phys_bits,omitempty" json:"reduced_phys_bits,omitempty"`
Policy string `yaml:"policy,omitempty" json:"policy,omitempty"`
DhCert string `yaml:"dh_cert,omitempty" json:"dh_cert,omitempty"`
Session string `yaml:"session,omitempty" json:"session,omitempty"`
KernelHashes string `yaml:"kernel_hashes,omitempty" json:"kernel_hashes,omitempty"`
}
type LibvirtListenOne ¶
type LibvirtMemBalloon ¶
type LibvirtMemTune ¶
type LibvirtMemTune struct {
HardLimit string `yaml:"hard_limit,omitempty" json:"hard_limit,omitempty"`
SoftLimit string `yaml:"soft_limit,omitempty" json:"soft_limit,omitempty"`
SwapHardLimit string `yaml:"swap_hard_limit,omitempty" json:"swap_hard_limit,omitempty"`
MinGuarantee string `yaml:"min_guarantee,omitempty" json:"min_guarantee,omitempty"`
}
type LibvirtMemnode ¶
type LibvirtMemoryBacking ¶
type LibvirtMemoryBacking struct {
Hugepages *LibvirtHugepages `yaml:"hugepages,omitempty" json:"hugepages,omitempty"`
Locked *bool `yaml:"locked,omitempty" json:"locked,omitempty"`
Source string `yaml:"source,omitempty" json:"source,omitempty"`
Access string `yaml:"access,omitempty" json:"access,omitempty"`
Allocation string `yaml:"allocation,omitempty" json:"allocation,omitempty"`
Discard *bool `yaml:"discard,omitempty" json:"discard,omitempty"`
}
type LibvirtNUMACell ¶
type LibvirtNUMACell struct {
ID int `yaml:"id,omitempty" json:"id,omitempty"`
CPUs string `yaml:"cpus,omitempty" json:"cpus,omitempty"`
Memory string `yaml:"memory,omitempty" json:"memory,omitempty"`
Unit string `yaml:"unit,omitempty" json:"unit,omitempty"`
MemAccess string `yaml:"memaccess,omitempty" json:"memaccess,omitempty"`
}
type LibvirtNUMAMemory ¶
type LibvirtNUMATune ¶
type LibvirtNUMATune struct {
Memory *LibvirtNUMAMemory `yaml:"memory,omitempty" json:"memory,omitempty"`
MemNodes []LibvirtMemnode `yaml:"memnodes,omitempty" json:"memnodes,omitempty"`
}
type LibvirtPCIHex ¶
type LibvirtPCIHex string
PCI source address component: 0x-hex OR bare decimal (hexUintPtr accepts both).
type LibvirtPanic ¶
type LibvirtParallel ¶
type LibvirtPortForward ¶
type LibvirtRNG ¶
type LibvirtRedirDev ¶
type LibvirtResource ¶
type LibvirtSecLabel ¶
type LibvirtSecLabel struct {
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Model string `yaml:"model,omitempty" json:"model,omitempty"`
Relabel string `yaml:"relabel,omitempty" json:"relabel,omitempty"`
Label string `yaml:"label,omitempty" json:"label,omitempty"`
BaseLabel string `yaml:"baselabel,omitempty" json:"baselabel,omitempty"`
ImageLabel string `yaml:"imagelabel,omitempty" json:"imagelabel,omitempty"`
}
type LibvirtSerial ¶
type LibvirtShmem ¶
type LibvirtShmem struct {
Name string `yaml:"name,omitempty" json:"name"`
Role string `yaml:"role,omitempty" json:"role,omitempty"`
Model map[string]string `yaml:"model,omitempty" json:"model,omitempty"`
Size string `yaml:"size,omitempty" json:"size,omitempty"`
Server map[string]string `yaml:"server,omitempty" json:"server,omitempty"`
}
type LibvirtSmartcard ¶
type LibvirtSound ¶
type LibvirtSound struct {
Model string `yaml:"model,omitempty" json:"model"`
}
type LibvirtSpinlocks ¶
type LibvirtSysInfo ¶
type LibvirtSysInfo struct {
Type string `yaml:"type,omitempty" json:"type,omitempty"`
BIOS map[string]string `yaml:"bios,omitempty" json:"bios,omitempty"`
System map[string]string `yaml:"system,omitempty" json:"system,omitempty"`
BaseBoard []map[string]string `yaml:"baseboard,omitempty" json:"baseboard,omitempty"`
Chassis map[string]string `yaml:"chassis,omitempty" json:"chassis,omitempty"`
Processor []map[string]string `yaml:"processor,omitempty" json:"processor,omitempty"`
OEMStrings []string `yaml:"oem_strings,omitempty" json:"oem_strings,omitempty"`
}
type LibvirtTPM ¶
type LibvirtTimer ¶
type LibvirtTimer struct {
Name string `yaml:"name,omitempty" json:"name"`
Present string `yaml:"present,omitempty" json:"present,omitempty"`
Track string `yaml:"track,omitempty" json:"track,omitempty"`
TickPolicy string `yaml:"tickpolicy,omitempty" json:"tickpolicy,omitempty"`
Frequency int `yaml:"frequency,omitempty" json:"frequency,omitempty"`
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
}
type LibvirtUSB ¶
type LibvirtVCPUPin ¶
type LibvirtVendorID ¶
type LibvirtVideo ¶
type LibvirtVideo struct {
Model string `yaml:"model,omitempty" json:"model"`
VRAM int `yaml:"vram,omitempty" json:"vram,omitempty"`
Heads int `yaml:"heads,omitempty" json:"heads,omitempty"`
Accel3D *bool `yaml:"accel3d,omitempty" json:"accel3d,omitempty"`
Primary *bool `yaml:"primary,omitempty" json:"primary,omitempty"`
}
type LibvirtVsock ¶
type LibvirtWatchdog ¶
type LifecycleOpts ¶ added in v0.2026186.239
type LifecycleOpts struct {
DryRun bool `json:"dry_run,omitempty"`
AllowRepoChanges bool `json:"allow_repo_changes,omitempty"`
AllowRootTasks bool `json:"allow_root_tasks,omitempty"`
WithServices bool `json:"with_services,omitempty"`
AssumeYes bool `json:"assume_yes,omitempty"`
Verify bool `json:"verify,omitempty"`
Pull bool `json:"pull,omitempty"`
SkipIncompatible bool `json:"skip_incompatible,omitempty"`
BuilderImageOverride string `json:"builder_image_override,omitempty"`
}
LifecycleOpts is the serializable subset of the host's EmitOpts shipped in a lifecycle Op's params. The two LIVE EmitOpts fields (ParentExec, ParentNode) cannot cross the []byte wire — they re-attach host-side via the reverse channel's live host-build inputs, never serialized.
type LifecyclePrepareInput ¶ added in v0.2026186.739
type LifecyclePrepareInput struct {
Entity string `json:"entity"` // the kind:vm entity name (node.From-resolved)
VM *VmSpec `json:"vm,omitempty"` // the resolved VmSpec (uf.VM[entity])
SSHUser string `json:"ssh_user"` // resolveVmSshUser(spec)
SSHPort int `json:"ssh_port"` // resolveVmSshPort(spec, entity) — auto-alloc + persisted-port idempotency
Alias string `json:"alias"` // VmSshAlias(entity)
SSHKeyPath string `json:"ssh_key_path"` // <stateDir>/id_ed25519
KnownHostsPath string `json:"known_hosts_path"` // <stateDir>/known_hosts
StateDir string `json:"state_dir"` // ~/.local/share/charly/vm/charly-<entity>
PriorState *VmDeployState `json:"prior_state,omitempty"` // the persisted VmDeployState (nil on first apply)
}
LifecyclePrepareInput is the host-resolved DATA a vm substrate's OpPrepareVenue needs but cannot derive itself (the plugin cannot LoadUnified — it has no project): the resolved kind:vm entity, its ssh coordinates, and the prior runtime state. The host ships it on the lifecycle Op's params under the "prepare" key (the same generic threading the proxy uses for image/version), so PrepareVenue is NOT a hollow forward — the plugin does the full venue lifecycle (ssh-config, auto-boot, the guest waits, charly delivery, nested pods) itself over generic seams, consuming only this resolved data.
type Local ¶
type Local struct {
// Ordered candy stack applied to the host. Required (empty list permitted —
// a staged name-reservation stub; the loader warns, not errors).
Candy []CandyRef `yaml:"candy,omitempty" json:"candy"`
InstallOpts *InstallOpts `yaml:"install_opts,omitempty" json:"install_opts,omitempty"`
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
}
type LocalPkg ¶
type LocalPkg struct {
PkgGlob string `yaml:"pkg_glob,omitempty" json:"pkg_glob"`
SourceSentinel string `yaml:"source_sentinel,omitempty" json:"source_sentinel"`
BuildTemplate string `yaml:"build_template,omitempty" json:"build_template"`
InstallTemplate string `yaml:"install_template,omitempty" json:"install_template"`
Probe string `yaml:"probe,omitempty" json:"probe"`
DepBuilder string `yaml:"dep_builder,omitempty" json:"dep_builder,omitempty"`
DownloadTemplate string `yaml:"download_template,omitempty" json:"download_template,omitempty"`
}
type MatchOpMap ¶
Matcher operators (validMatcherOps, validate_check.go). A matcher is a scalar (implicit equals), or a single-operator map; #MatcherList accepts a single matcher OR a list. (The base no longer carries a contains-default list def — that shape left with the `file` verb's `contains` field and is now reproduced standalone in the file plugin's #FileContains, decoded with the substring default via decodeContainsList; no base #Op field uses it anymore.)
type Matcher ¶
Matcher is a goss-style matcher: a scalar (implicit equality) or an operator map ({equals: X}, {contains: […]}, {matches: R}, {lt: N}, …).
func (Matcher) MarshalJSON ¶
MarshalJSON makes the JSON write path the exact inverse of UnmarshalJSON. A ZERO (absent) matcher — Op=="" — marshals to `null`, which UnmarshalJSON maps back to the zero value; without this, the default struct marshal emitted `{"op":""}`, which UnmarshalJSON's single-key-map branch misread as Op="op" (an asymmetry that corrupted every zero matcher round-tripped through JSON — e.g. the all-zero check-matcher fields of an install Op carried in the per-step IR, or a baked-label Plan step). A NON-zero matcher marshals to the SAME canonical `{"op":...,"value":...}` form the default marshaler produced, so real matchers (and existing baked labels) are byte-unchanged.
func (Matcher) MarshalYAML ¶
MarshalYAML emits the canonical operator-map form so round-tripping is stable.
func (*Matcher) UnmarshalJSON ¶
UnmarshalJSON accepts the canonical `{"op":"...","value":...}` form, an operator-map (`{"equals": X}`), a bare scalar (`"PONG"` → equals), and `null` / empty (→ the zero matcher, the inverse of MarshalJSON's zero case).
type MatcherList ¶
type MatcherList []Matcher
MatcherList lets users write scalar/single-map shorthand where a list of Matchers is expected. `stdout: PONG` and `stdout: [PONG]` decode identically.
func (*MatcherList) UnmarshalJSON ¶
func (ml *MatcherList) UnmarshalJSON(data []byte) error
UnmarshalJSON mirrors the scalar-shorthand behavior for the JSON read path.
type Op ¶
type Op struct {
// --- verb discriminators (exactly one set; Go Kind() enforces) ---
Mkdir string `yaml:"mkdir,omitempty" json:"mkdir,omitempty"`
Copy string `yaml:"copy,omitempty" json:"copy,omitempty"`
Write string `yaml:"write,omitempty" json:"write,omitempty"`
Link string `yaml:"link,omitempty" json:"link,omitempty"`
Download string `yaml:"download,omitempty" json:"download,omitempty"`
Setcap string `yaml:"setcap,omitempty" json:"setcap,omitempty"`
Build string `yaml:"build,omitempty" json:"build,omitempty"`
// plugin — the generic PLUGIN-VERB discriminator, INTERNAL-ONLY: the
// parse-time desugar rewrites every authored `<word>: <input>` sugar key
// into this plugin/plugin_input pair, and authoring plugin:/plugin_input:
// directly in a step is a hard load error (run: charly migrate). The pair
// stays on #Op because it is the wire/label form (the desugared tree this
// def validates, the ai.opencharly.description JSON) and the Go dispatch
// surface (providerRegistry.ResolveVerb). plugin_input is validated by the
// PLUGIN's own served CUE schema (not base #Op).
Plugin string `yaml:"plugin,omitempty" json:"plugin,omitempty"`
// --- shared modifiers ---
ID string `yaml:"id,omitempty" json:"id,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Skip bool `yaml:"skip,omitempty" json:"skip,omitempty"`
Timeout Duration `yaml:"timeout,omitempty" json:"timeout,omitempty"`
// command — INTERNAL-ONLY rehydration target (never authored): the `command`
// plugin verb's INSTALL-EMIT copies plugin_input.command here for emitCmd
// (build) / renderOpCommand (deploy). Authored `command:` on a step IS the
// command plugin's sugar key (scalar = the primary shorthand), consumed by
// the parse-time desugar before this def validates; the wl/libvirt argv
// moved into those plugins' own input defs.
Command string `yaml:"command,omitempty" json:"command,omitempty"`
Context []Context `yaml:"context,omitempty" json:"context,omitempty"`
// `pod:` (per-step container venue) is RETIRED — a step's execution venue is
// derived ENTIRELY from its position in the bundle tree (flattenBundleVenues
// → Op.venue, yaml:"-"). Authoring it is a closed-schema rejection (run:
// charly migrate).
DependsOn []string `yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
// plugin_input — generic params for a `plugin:` verb. Opaque to base #Op
// (accepts any shape); the plugin's own spliced CUE schema validates it.
PluginInput map[string]any `yaml:"plugin_input,omitempty" json:"plugin_input,omitempty"`
// --- install/build modifiers ---
RunAs string `yaml:"run_as,omitempty" json:"run_as,omitempty"`
To string `yaml:"to,omitempty" json:"to,omitempty"`
Target string `yaml:"target,omitempty" json:"target,omitempty"`
Caps string `yaml:"caps,omitempty" json:"caps,omitempty"`
Content string `yaml:"content,omitempty" json:"content,omitempty"`
Extract string `yaml:"extract,omitempty" json:"extract,omitempty"`
ExtractInclude []string `yaml:"extract_include,omitempty" json:"extract_include,omitempty"`
StripComponents int `yaml:"strip_components,omitempty" json:"strip_components,omitempty"`
Uninstall []string `yaml:"uninstall,omitempty" json:"uninstall,omitempty"`
Comment string `yaml:"comment,omitempty" json:"comment,omitempty"`
Cache []string `yaml:"cache,omitempty" json:"cache,omitempty"`
Env StrMap `yaml:"env,omitempty" json:"env,omitempty"`
// --- step modifiers ---
Eventually Duration `yaml:"eventually,omitempty" json:"eventually,omitempty"`
RetryInterval Duration `yaml:"retry_interval,omitempty" json:"retry_interval,omitempty"`
// `on:` (cross-member driver dispatch) is RETIRED — a step that drives a
// peer/driver is authored as a step CHILD of that member node; its venue is
// derived from position (flattenBundleVenues → Op.venue). Authoring `on:` is
// a closed-schema rejection (run: charly migrate).
Tag []string `yaml:"tag,omitempty" json:"tag,omitempty"`
// Origin is populated at collection time (candy:<name>/box:<name>/deploy-*),
// NEVER authored (Go yaml:"-"), but it TRAVELS in the ai.opencharly.description
// OCI-label JSON (Go json:"origin") — so the generated spec.Op MUST carry it
// for a faithful drop-in (do NOT @go(-) it). gengotypes emits
// `yaml:"origin,omitempty" json:"origin,omitempty"`, matching the hand tag.
Origin string `yaml:"origin,omitempty" json:"origin,omitempty"`
// venue + intent_do are RUNTIME-DERIVED, never authored: venue is stamped
// from a step's bundle-tree position (flattenBundleVenues), intent_do from
// the enclosing Step's keyword (run→act / check→assert / agent→instruct).
// They are generated onto the Go struct (the check runner persists them on
// the Op-by-value passed to runOne / EffectiveDo), but the #Step authoring
// arms forbid them (`venue?: _|_, intent_do?: _|_`) so authoring either is a
// closed-schema rejection — exactly the contract the retired `pod:`/`on:`
// fields enforced. yaml:"-" (never read from YAML); json omits them when
// empty (the bake-time state, so they never leak into the description label).
Venue string `yaml:"venue,omitempty" json:"venue,omitempty"`
IntentDo string `yaml:"intent_do,omitempty" json:"intent_do,omitempty"`
// --- file/copy/write SHARED modifier ---
// `mode` is the SHARED octal-permission modifier: the copy/write install verbs read
// Op.Mode at deploy (the external local/vm deploy walk via kit.ParseTaskMode),
// so it STAYS in #Op. The file-EXCLUSIVE fields (file/exists/owner/group_of/filetype/
// contains/sha256) LEFT #Op — they are read ONLY by the `file` plugin verb and now live
// in its #FileInput (candy/plugin-file, with the contains-default semantic
// reproduced via the candy's decodeContainsList). The state-provision migrator MOVES `mode` into a
// file step's plugin_input while LEAVING it here for copy/write (the shared-companion
// pattern, like gid between unix_group and user).
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
// exclude_distro — a SHARED step-level skip filter read by the generic runOne for
// EVERY verb (skip the step when any image distro tag intersects the list), NOT a
// package-exclusive field, so it STAYS on #Op. The `package`-exclusive fields
// (installed/version/package_map) MOVED into #PackageInput when `package` extracted.
ExcludeDistros []string `yaml:"exclude_distro,omitempty" json:"exclude_distro,omitempty"`
// --- shared assertion matchers (SHARED via matchAll: the command/http probe
// plugins + every live-verb plugin assert exit_status/stdout/stderr off the
// marshalled step Op, so they STAY in #Op; verb-exclusive request/input
// fields live in each plugin's input def) ---
ExitStatus *int `yaml:"exit_status,omitempty" json:"exit_status,omitempty"`
Stdout MatcherList `yaml:"stdout,omitempty" json:"stdout,omitempty"`
Stderr MatcherList `yaml:"stderr,omitempty" json:"stderr,omitempty"`
}
#Op is the unified operation vocabulary (Go: charly/checkspec.go Op) AFTER the parse-time desugar: the builtin install verbs + the genuinely SHARED step modifiers + the internal plugin/plugin_input pair every plugin-verb sugar key desugars into. CLOSED: an unknown key on the desugared step is a typo (a plugin word never reaches this def — the desugar consumed it). Per-verb fields live in each plugin's own input def, served over Describe.
func (*Op) Kind ¶
Kind returns the single verb set on the Op, or an error when zero or multiple are set (the exactly-one-verb rule).
func (*Op) PluginInputStr ¶
PluginInputStr returns the string value of plugin_input[verb] when this Op is a `plugin: <verb>` op carrying that key — "" otherwise. The ONE home (R3) for the host check runner (checkrun.go) AND the k8sgen plugin's probe builder (candy/plugin-k8sgen), both of which read a migrated `plugin: http`/`addr`/`file`/`command` check subject.
func (*Op) StringFields ¶
StringFields returns pointers to every string-valued modifier field, for the in-place ${VAR} expansion driven by ExpandVars (free function in main).
type OverlayBuildReply ¶
type OverlayBuildReply struct {
OverlayRef string `json:"overlay_ref,omitempty"`
BaseImage string `json:"base_image,omitempty"`
DeployName string `json:"deploy_name,omitempty"`
Error string `json:"error,omitempty"`
}
OverlayBuildReply is what the "overlay" host-builder returns: the built overlay image ref (== BaseImage when there was no add_candy overlay to synthesize), the resolved base image ref, and the flattened deploy name. The caller (PrepareVenue) uses these to print the start hint and persist the concrete overlay ref (saveDeployState) so config/start deploy exactly this overlay. A build FAILURE rides Error (the reply-error convention, like BuildReply).
type OverlayBuildRequest ¶
type OverlayBuildRequest struct {
Dir string `json:"dir,omitempty"` // project dir (build-context root) the host reconstructs config from
DeployName string `json:"deploy_name,omitempty"` // the raw deploy name (dotted for a nested pod; flattened engine-side)
Image string `json:"image,omitempty"` // the base box the overlay inherits FROM (node.Image; "" → DeployName)
Version string `json:"version,omitempty"` // the base image CalVer pin (node.Version; "" → newest-local)
DryRun bool `json:"dry_run,omitempty"` //
AssumeYes bool `json:"assume_yes,omitempty"` //
AllowRepoChanges bool `json:"allow_repo_changes,omitempty"` //
AllowRootTasks bool `json:"allow_root_tasks,omitempty"` //
WithServices bool `json:"with_services,omitempty"` //
}
OverlayBuildRequest is the BUILD-ENGINE DISPATCH envelope for the pod-overlay build — the F10 "overlay" host-builder, the pod-substrate sibling of BuildRequest. It carries only the SERIALIZABLE scalars the host engine cannot reconstruct from Dir; everything heavy the engine reads (Config / ResolvedBox / Candy / DistroDef) is reconstructed HOST-SIDE from Dir via NewGenerator, exactly as runBoxBuild / the prior inline PrepareVenue body did.
The overlay build's LIVE inputs — the deployment's compiled InstallPlans and, for a nested pod-in-pod overlay, the parent venue executor + node — do NOT ride this envelope: a live DeployExecutor is not serializable. The overlay build is dispatched IN-PROCESS host-side by podSubstrateLifecycle.PrepareVenue (a direct hostBuilders lookup, no gRPC hop), so those live inputs ride the ctx instead (the SAME pattern sdk.ContextWithExecutor uses to thread a live executor across the placement-invisible reverse channel). See package main overlayBuildInputs.
type PackageItem ¶
type PackageItem struct {
Name string `yaml:"name" json:"name"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
}
--------------------------------------------------------------------------- PackageItem — #PackageItem (calamares_types.go). Bare scalar XOR object form; the bare-scalar shorthand is canonicalized to {name} by the loader normalizer. ---------------------------------------------------------------------------
type Pacstrap ¶
type Pacstrap struct {
BasePackages []string `yaml:"base_package,omitempty" json:"base_package,omitempty"`
KeyringInitCmd string `yaml:"keyring_init_cmd,omitempty" json:"keyring_init_cmd,omitempty"`
MirrorlistURL string `yaml:"mirrorlist_url,omitempty" json:"mirrorlist_url,omitempty"`
ExtraRepos []PacstrapRepo `yaml:"extra_repo,omitempty" json:"extra_repo,omitempty"`
RuntimePacmanConf string `yaml:"runtime_pacman_conf,omitempty" json:"runtime_pacman_conf,omitempty"`
}
type PacstrapRepo ¶
type PhaseSet ¶
type PhaseSet struct {
Prepare *PhaseTemplates `yaml:"prepare,omitempty" json:"prepare,omitempty"`
Install *PhaseTemplates `yaml:"install,omitempty" json:"install,omitempty"`
Cleanup *PhaseTemplates `yaml:"cleanup,omitempty" json:"cleanup,omitempty"`
}
Three-phase template set: prepare → install → cleanup, each with a container (Containerfile) and host (shell) rendering. Template bodies are Go text/template — strings, never parsed here.
type PhaseTemplates ¶
type Plugin ¶
type Plugin struct {
// providers: the "<class>:<word>" reserved-word capabilities this plugin
// serves (e.g. "verb:exampleprobe", "kind:my-thing"). Each is registered into
// providerRegistry — built-in (init()) or out-of-tree (gRPC).
Providers []PluginCapability `yaml:"providers,omitempty" json:"providers"`
// source: "builtin" (Go compiled into the charly binary, init()-registered) OR
// a git ref (github.com/org/repo[/sub][@tag]) fetched via the @github resolver +
// built into a provider binary. Default builtin.
Source string `yaml:"source,omitempty" json:"source"`
// primary: verb word → the input field its scalar sugar shorthand targets
// (`file: /x` → plugin_input: {<primary>: "/x"}). Declared in the MANIFEST so
// the byte-gated prescan registers it BEFORE the out-of-process provider
// connects (the parse-time desugar needs it pre-parse); the served
// ProvidedCapability.Primary mirrors it for the compiled-in placement.
Primary map[string]string `yaml:"primary,omitempty" json:"primary,omitempty"`
}
#Plugin — the candy's plugin declaration. Its presence makes the candy a plugin (Go: charly/checkspec.go via the generated Candy.Plugin field, consumed by plugin_loader.go). CLOSED.
type PluginCapability ¶
type PluginCapability string
#PluginCapability — a "<class>:<word>" capability string. class ∈ the closed ProviderClass set; word is lowercase-hyphenated.
type Pod ¶
type Pod struct {
// References a kind:box (bare lowercase-hyphenated name or remote ref).
// Optional: the Go field has no non-empty validator.
Box CandyRef `yaml:"box,omitempty" json:"box,omitempty"`
// Each entry is a SidecarConfig wrapper: a single-key map of named
// sidecar templates (PodSpec.Sidecar []SidecarConfig).
Sidecar []PodSidecar `yaml:"sidecar,omitempty" json:"sidecar,omitempty"`
Secret []DeploySecret `yaml:"secret,omitempty" json:"secret,omitempty"`
EnvDefaults map[string]string `yaml:"env_default,omitempty" json:"env_default,omitempty"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
}
type PodSidecar ¶
#PodSidecar mirrors Go SidecarConfig: a single-key wrapper around a map of named sidecar templates. CLOSED (the struct has exactly one field).
type PortScope ¶
type PortScope struct {
All bool
Ports []int
PortMap map[int]string // port → hostname (cloudflare only)
}
PortScope handles three YAML forms for public/private port specification: "all" → All; [443, 8443] → Ports; {18789: "host"} → PortMap.
func (PortScope) MarshalJSON ¶
func (PortScope) MarshalYAML ¶
func (*PortScope) UnmarshalJSON ¶
type PortSpec ¶
PortSpec is the canonical {port, protocol} form of a candy `port:` entry. Source: charly/layers.go PortSpec (no struct tags — yaml.v3 lowercases the field name).
type PostTeardownReply ¶ added in v0.2026186.239
type PostTeardownReply struct {
RemoveEntries []string `json:"remove_entries,omitempty"`
}
PostTeardownReply is the OpPostTeardown reply: the host removes each named charly.yml deploy-entry key AFTER the plugin's teardown (the plugin cannot mutate the host config — vm ships its resolved entry keys here; pod ships none).
type PreemptLease ¶
type PreemptLease struct {
Claimant string `yaml:"claimant" json:"claimant"`
Claim HolderAddr `yaml:"claim" json:"claim"` // the claimant DEPLOYMENT addr (persistent-lease liveness)
Tokens []string `yaml:"tokens" json:"tokens"`
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"` // driver MODE: "nvidia" (shared) | "vfio" (exclusive); "" = legacy/none
Transient bool `yaml:"transient" json:"transient"` // check-bed claims auto-release; persistent claims don't
Preempted []PreemptedHolder `yaml:"preempted" json:"preempted"` // holders/pods THIS claim stopped + must restore on release
Created string `yaml:"created" json:"created"` // RFC3339 UTC
// OwnerPID/OwnerStart identify the OUTERMOST process that created the lease —
// the liveness signal a concurrent charly process's reconcile uses (leaseLive).
OwnerPID int `yaml:"owner_pid,omitempty" json:"owner_pid,omitempty"`
OwnerStart string `yaml:"owner_start,omitempty" json:"owner_start,omitempty"`
}
PreemptLease is one active resource claim — exclusive (a VM with sole use) OR shared (a refcounted pod claim; many coexist on one token).
type PreemptLedger ¶
type PreemptLedger struct {
Leases []PreemptLease `yaml:"leases" json:"leases"`
}
PreemptLedger is the on-disk lease set (~/.local/share/charly/preemption/leases.yml).
type PreemptedHolder ¶
type PreemptedHolder struct {
Addr HolderAddr `yaml:"addr" json:"addr"`
Holds []string `yaml:"holds" json:"holds"`
Restore string `yaml:"restore" json:"restore"` // always | on-success
}
PreemptedHolder records one holder a lease stopped, its declared exclusive tokens, and its restore policy — so ReleaseClaimant/reconcile restart exactly what was stopped.
type PreemptibleConfig ¶
type PreemptibleConfig struct {
Holds []string `yaml:"holds,omitempty" json:"holds,omitempty"`
Stop string `yaml:"stop,omitempty" json:"stop,omitempty"`
Restore string `yaml:"restore,omitempty" json:"restore,omitempty"`
}
PreemptibleConfig is the HOLDER side of the resource-arbitration axis.
type PrepareVenueReply ¶ added in v0.2026186.239
type PrepareVenueReply struct {
Venue VenueDescriptor `json:"venue"`
State json.RawMessage `json:"state,omitempty"`
Notes []string `json:"notes,omitempty"`
}
PrepareVenueReply is the OpPrepareVenue reply. Venue is re-materialized host-side into a live DeployExecutor (the live executor never crosses the wire); State is an opaque deploy-entry patch the host persists (pod: {"ResolvedImage": ref}; vm: VmDeployState JSON); Notes are human-facing lines the host prints. Replaces the bare VenueDescriptor OpPrepareVenue reply.
type Readiness ¶
type Readiness struct {
PollIntervalLocal Duration `yaml:"poll_interval_local,omitempty" json:"poll_interval_local,omitempty"`
PollIntervalRemote Duration `yaml:"poll_interval_remote,omitempty" json:"poll_interval_remote,omitempty"`
PollIntervalHeavy Duration `yaml:"poll_interval_heavy,omitempty" json:"poll_interval_heavy,omitempty"`
PerAttempt Duration `yaml:"per_attempt,omitempty" json:"per_attempt,omitempty"`
PerAttemptHeavy Duration `yaml:"per_attempt_heavy,omitempty" json:"per_attempt_heavy,omitempty"`
NoProgress Duration `yaml:"no_progress,omitempty" json:"no_progress,omitempty"`
AbsoluteCap Duration `yaml:"absolute_cap,omitempty" json:"absolute_cap,omitempty"`
StopGrace Duration `yaml:"stop_grace,omitempty" json:"stop_grace,omitempty"`
}
ReadinessConfig (config.go / readiness_config.go) — the `defaults.readiness:` bounds for the unified pollUntil readiness primitive (poll.go). CLOSED. Every field is a Go time.ParseDuration string; absent → the named fallback const in poll.go. Defaults-only (reuses the BoxConfig type), but modeled here per the #Box completeness invariant in this file's header. The Resolve()-time ordering invariants (interval <= no_progress <= absolute_cap; poll_interval_local <= stop_grace <= absolute_cap) are cross-field and stay in Go (validateOrdering).
type Resource ¶
type Resource struct {
Gpu *GpuSelector `yaml:"gpu,omitempty" json:"gpu,omitempty"`
}
func (*Resource) HasSelector ¶
HasSelector reports whether the resource carries a GPU selector.
type RetentionReply ¶ added in v0.2026186.928
type RetentionReply struct {
ImageRefs []string `json:"image_refs,omitempty"`
BuildDirs []string `json:"build_dirs,omitempty"`
CheckPaths []string `json:"check_paths,omitempty"`
KeepImages int `json:"keep_images,omitempty"`
KeepCheckRuns int `json:"keep_check_runs,omitempty"`
Error string `json:"error,omitempty"`
}
RetentionReply is the "retention" HostBuild kind reply: the removed (or would-remove, under DryRun) image refs, build-candy dirs, and check-run paths, plus the effective retention counts, for the plugin to present. Error is a human-facing message on a non-recoverable failure.
type RetentionRequest ¶ added in v0.2026186.928
type RetentionRequest struct {
Dir string `json:"dir"`
DryRun bool `json:"dry_run,omitempty"`
Images bool `json:"images,omitempty"`
Check bool `json:"check,omitempty"`
Keep int `json:"keep,omitempty"`
Invalidate string `json:"invalidate,omitempty"`
}
RetentionRequest is the "retention" HostBuild kind request: the plugin asks the host to run the shared prune engine host-side (the engine needs the core image inventory + label parsing that stays in core). Dir is the project directory (os.Getwd() in the plugin). Keep=0 means "use the resolved defaults"; Invalidate (non-empty) runs ONLY the targeted image-tag invalidation.
type ReverseOp ¶
type ReverseOp struct {
Kind ReverseOpKind `json:"kind"`
Format string `json:"format,omitempty"` // package format for package-remove (rpm/deb/pac)
Targets []string `json:"targets,omitempty"` // package names, file paths, env names, …
Scope Scope `json:"scope,omitempty"` // system vs user for disambiguation
Extra map[string]string `json:"extra,omitempty"` // op-specific details (e.g. unit name, layer name, plugin-script body)
// UninstallCmd is the rendered host-venue package-removal command for a
// ReverseOpPackageRemove op, filled at record time from the format's
// uninstall_template (the embedded build vocabulary, charly/charly.yml) by
// fillReverseUninstallCmds — the deploy target has the DistroConfig at
// install time, the teardown (which reads the persisted ledger) does not, so
// the command is rendered up front and persisted. reverse_ops.go runs it
// verbatim, so there is NO hardcoded per-format removal switch in the
// teardown path.
UninstallCmd string `json:"uninstall_cmd,omitempty"`
}
ReverseOp is a single teardown action. Serialized into the ledger so uninstall can reverse a deploy without re-reading the candy manifest.
type ReverseOpKind ¶
type ReverseOpKind string
ReverseOpKind discriminates the kinds of teardown actions Reverse() produces. Ledger entries serialize these verbatim so a later `charly bundle del` can walk them without re-compiling the plan.
const ( ReverseOpPackageRemove ReverseOpKind = "package-remove" ReverseOpCargoUninstall ReverseOpKind = "cargo-uninstall" ReverseOpNpmUninstallG ReverseOpKind = "npm-uninstall-g" ReverseOpPixiEnvRemove ReverseOpKind = "pixi-env-remove" ReverseOpRmFileSystem ReverseOpKind = "rm-file-system" ReverseOpRmFileUser ReverseOpKind = "rm-file-user" ReverseOpRmDirRecursive ReverseOpKind = "rm-dir-recursive" ReverseOpServiceDisable ReverseOpKind = "service-disable" ReverseOpServiceRemove ReverseOpKind = "service-remove" ReverseOpRemoveDropin ReverseOpKind = "remove-dropin" ReverseOpRestoreEnabled ReverseOpKind = "restore-enabled" ReverseOpRemoveManaged ReverseOpKind = "remove-managed-block" ReverseOpRemoveEnvdFile ReverseOpKind = "remove-envd-file" ReverseOpRemoveRepoFile ReverseOpKind = "remove-repo-file" ReverseOpCoprDisable ReverseOpKind = "copr-disable" // ReverseOpPluginScript is the GENERIC recordable reverse op an external // (out-of-process) deploy/step/builder plugin returns: a shell script + its // scope, run verbatim at teardown via the ReverseExecutor (system → sudo, // user → no sudo). The script lives in Extra["script"]; Scope picks the // privilege. It preserves the record-and-replay invariant — only RECORDED // ops are replayed, never recomputed — without any new struct shape. ReverseOpPluginScript ReverseOpKind = "plugin-script" )
type Scope ¶
type Scope int
Scope classifies what kind of filesystem mutation a step makes. Steps are grouped by scope (and venue) when the host target batches into sudo vs user heredocs — mixing scopes in one batch would need per-command sudo. It is the integer-valued enum the ledger serializes (omitempty omits ScopeSystem=0), so the wire form is UNCHANGED by the move into spec.
const ( // ScopeSystem mutates global host state: /etc, /usr, /var, systemd system // units, package DB. Requires sudo on host; emitted as USER root in the // Containerfile. ScopeSystem Scope = iota // ScopeUser mutates the invoking user's home or user-owned paths: // $HOME/.pixi, $HOME/.cargo, $HOME/.npm-global, $HOME/.local, systemd // user units, etc. No sudo needed on host; emitted as USER ${UID} in the // Containerfile. ScopeUser // ScopeUserProfile writes to the user's shell init surface: // ~/.bashrc / ~/.zshenv / fish conf.d + ~/.config/opencharly/env.d/. // Separate from ScopeUser because the host target has special handling // (managed blocks, shell detection) and the OCI target renders these as // ENV directives + path additions rather than file writes. ScopeUserProfile )
type Security ¶
type Security struct {
Privileged bool `yaml:"privileged,omitempty" json:"privileged,omitempty"`
CgroupNS string `yaml:"cgroupns,omitempty" json:"cgroupns,omitempty"`
CapAdd []string `yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
Devices []string `yaml:"devices,omitempty" json:"devices,omitempty"`
SecurityOpt []string `yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
IpcMode string `yaml:"ipc_mode,omitempty" json:"ipc_mode,omitempty"`
ShmSize Size `yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
GroupAdd []string `yaml:"group_add,omitempty" json:"group_add,omitempty"`
Mounts []string `yaml:"mount,omitempty" json:"mount,omitempty"`
MemoryMax Size `yaml:"memory_max,omitempty" json:"memory_max,omitempty"`
MemoryHigh Size `yaml:"memory_high,omitempty" json:"memory_high,omitempty"`
MemorySwapMax Size `yaml:"memory_swap_max,omitempty" json:"memory_swap_max,omitempty"`
Cpus string `yaml:"cpus,omitempty" json:"cpus,omitempty"`
}
--------------------------------------------------------------------------- Container security (SecurityConfig) — shared by box / candy / deploy / sidecar. ---------------------------------------------------------------------------
type SettingsEntry ¶ added in v0.2026186.948
type SettingsEntry struct {
Key string `json:"key"`
Value string `json:"value"`
Source string `json:"source"` // "env" | "config" | "default"
}
SettingsEntry is one resolved config key (the `charly settings list` row).
type SettingsReply ¶ added in v0.2026186.948
type SettingsReply struct {
Value string `json:"value,omitempty"`
Entries []SettingsEntry `json:"entries,omitempty"`
Error string `json:"error,omitempty"`
}
SettingsReply is the "settings" HostBuild kind reply: Value for get/path, Entries for list; set/reset return neither. Error is a human-facing message on failure (e.g. an unknown config key).
type SettingsRequest ¶ added in v0.2026186.948
type SettingsRequest struct {
Op string `json:"op"`
Key string `json:"key,omitempty"`
Value string `json:"value,omitempty"`
}
SettingsRequest is the "settings" HostBuild kind request: one config-subsystem op. Op ∈ {get, set, list, reset, path}. Key/Value carry the op's arguments (get/reset: Key; set: Key+Value; list/path: neither; reset with empty Key resets all).
type Shell ¶
type Shell struct {
Init string `yaml:"init,omitempty" json:"init,omitempty"`
PathAppend []string `yaml:"path_append,omitempty" json:"path_append,omitempty"`
Path string `yaml:"path,omitempty" json:"path,omitempty"`
Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
Bash *ShellSpec `yaml:"bash,omitempty" json:"bash,omitempty"`
Zsh *ShellSpec `yaml:"zsh,omitempty" json:"zsh,omitempty"`
Fish *ShellSpec `yaml:"fish,omitempty" json:"fish,omitempty"`
Sh *ShellSpec `yaml:"sh,omitempty" json:"sh,omitempty"`
}
--------------------------------------------------------------------------- Shell-rc config (ShellConfig/ShellSpec) — shared by box + candy. CLOSED: the Go UnmarshalYAML rejects any key outside the 4 intrinsic + 4 shell names. ---------------------------------------------------------------------------
type Sidecar ¶
type Sidecar struct {
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Image string `yaml:"image,omitempty" json:"image,omitempty"`
// env / parameter are map[string]string — values MUST be strings (quote
// YAML bools/numbers). parameter "" is the "deploy must supply" sentinel.
Env StrMap `yaml:"env,omitempty" json:"env,omitempty"`
Parameter StrMap `yaml:"parameter,omitempty" json:"parameter,omitempty"`
Secret []SidecarSecret `yaml:"secret,omitempty" json:"secret,omitempty"`
Volume []SidecarVolume `yaml:"volume,omitempty" json:"volume,omitempty"`
Security *Security `yaml:"security,omitempty" json:"security,omitempty"`
}
type SidecarSecret ¶
type SidecarVolume ¶
type StandaloneLoad ¶
type StandaloneLoad struct {
Shape string `json:"shape"` // "deploy" | "template" | "candy-image" | "candy-layer"
Deploy *Deploy `json:"deploy,omitempty"` // Shape=="deploy": the full pre-decoded BundleNode
Template json.RawMessage `json:"template,omitempty"` // Shape=="template": the pre-decoded typed template value's JSON
Box *Box `json:"box,omitempty"` // Shape=="candy-image": the pre-decoded IMAGE (spec.Box)
Candy *Candy `json:"candy,omitempty"` // Shape=="candy-layer": the pre-decoded LAYER (spec.Candy)
}
StandaloneLoad carries a structural kind's host-pre-decoded canonical node. Shape names which fold the host performs on the plugin's echo:
- "deploy" → Deploy (the full BundleNode) folds into uf.Bundle (C2-substrate);
- "template" → Template (the per-substrate typed value's JSON, e.g. a spec.Vm) folds into the typed template map by kind (C2-substrate);
- "candy-image" → Box (a full IMAGE, base:/from:) folds into uf.Box (C2-candy);
- "candy-layer" → Candy (a LAYER fragment) folds into uf.Candy (C2-candy).
Exactly one of Deploy / Template / Box / Candy is set, matching Shape. Both candy shapes are pre-decoded HOST-SIDE by the core candyIsImage + buildCandy (the bootstrap-critical box⊻layer routing that STAYS core — the discovered-candy pre-check calls it directly), so the plugin is a pure ECHO exactly like substrate. RDD proved a canonical spec.Box / spec.Candy round-trips through JSON byte-faithfully.
type Step ¶
type Step struct {
Run string `yaml:"run,omitempty" json:"run,omitempty"`
Check string `yaml:"check,omitempty" json:"check,omitempty"`
AgentRun string `yaml:"agent-run,omitempty" json:"agent-run,omitempty"`
AgentCheck string `yaml:"agent-check,omitempty" json:"agent-check,omitempty"`
Include string `yaml:"include,omitempty" json:"include,omitempty"`
Op `yaml:",inline" json:",inline"`
}
Step is a single plan step. Exactly one of Run/Check/AgentRun/AgentCheck/Include is non-empty (validated by StepKind()). The embedded Op (generated) is inline-promoted.
func (*Step) KeywordText ¶
KeywordText returns the populated keyword's prose regardless of which discriminator holds it.
func (*Step) Mutates ¶
Mutates reports whether the step changes system state (run / agent-run). `charly check live` (verify-only mode) skips mutating steps.
func (*Step) StepKind ¶
func (s *Step) StepKind() (StepKeyword, error)
StepKind returns the step's intent keyword and an error if zero or multiple keyword discriminators are set.
type StepEmitRequest ¶
type StepEmitRequest struct {
Word string `json:"word"`
Payload json.RawMessage `json:"payload,omitempty"`
Distros []string `json:"distros,omitempty"`
}
StepEmitRequest is the F-STEP-EMIT HostBuild envelope for a HOST-COUPLED external step kind's build-context fragment. A class:step plugin whose OpEmit needs the host build ENGINE (the DistroDef format templates, the Generator's task/builder rendering — the machinery a []byte can't carry across the process boundary) calls back Executor.HostBuild("step-emit", StepEmitRequest{…}) during its OpEmit; the host's registered "step-emit" host-builder dispatches by Word to a per-word emitter that renders the fragment IN-CORE and returns it as an EmitReply (the reply reuses EmitReply — R3). Word is the step reserved word; Payload is the step's opaque per-kind input (the SAME bytes the plugin received in op.Params); Distros carries the image's distro tags (BuildEnv). A PURE step never sends this — it returns its EmitReply.Fragment directly from OpEmit. The host's per-word emitter registry holds one renderer per relocated host-coupled step kind (C1.2 registered system-packages).
type StepKeyword ¶
type StepKeyword string
StepKeyword is the intent discriminator on a Step.
const ( KwRun StepKeyword = "run" KwCheck StepKeyword = "check" KwAgentRun StepKeyword = "agent-run" KwAgentCheck StepKeyword = "agent-check" KwInclude StepKeyword = "include" )
type StrMap ¶
StrMap is the Go shape of #StrMap (`{[string]: #StrVal}`). charly decodes every env / var / parameter / oci_label map into map[string]string — yaml.v3 coerces an unquoted scalar (`PORT: 8080`) to its literal text, so the map stays string→string. Source: the StrMap usage across charly/*.go.
type StrVal ¶
type StrVal any /* CUE disjunction: (bool|string|number) */
An env entry: KEY=VALUE (value may be empty / contain =). A YAML scalar Go decodes into a string (map[string]string / string field): yaml.v3 coerces an unquoted int/bool/float to its literal text, so an idiomatic `PORT: 8080` is a valid string value. #StrMap is the matching map.
type StructuralKindLoadEnv ¶
type StructuralKindLoadEnv struct {
Members map[string]*Deploy `json:"members,omitempty"`
// Standalone is the host-pre-decoded CANONICAL node channel the host threads to a structural
// kind plugin whose value is RICH + core-referencing: candy/plugin-substrate (C2-substrate,
// serving pod/vm/k8s/local/android → deploy/template shapes) AND candy/plugin-candy (C2-candy,
// serving candy → candy-image/candy-layer shapes, folding into uf.Box/uf.Candy). Unlike group
// — whose small scalar value is decoded from
// op.Params against a self-contained #GroupInput and whose members ride Members above —
// a substrate value is RICH + core-referencing (#Vm/#Deploy/#LibvirtDomain/… with
// host-canonicalized shorthand like tunnel:/port:), so it cannot be re-decoded soundly
// from op.Params by a plugin nor validated by a self-contained plugin schema. The host
// therefore decodes the WHOLE node via the core buildBundleNode (deploy shape) /
// decodeNodeValue (template shape) — the SINGLE decode source of truth (R3) — validates
// it host-side against the KEPT #<Kind>Value def, and threads the canonical result here.
// The plugin ECHOES it in its reply; the host folds the echo into uf.Bundle (deploy) or
// the typed template map uf.Pod/uf.VM/… (template — the C2-substrate TEMPLATE fold arm
// that extends F5's deploy-only fold). nil for group (which uses Members). RDD proved a
// canonical spec.Deploy / spec.Vm / spec.Pod / … round-trips through JSON byte-faithfully,
// so this thread-echo-fold is byte-equivalent to the former in-proc standaloneKind decode.
Standalone *StandaloneLoad `json:"standalone,omitempty"`
}
StructuralKindLoadEnv is the OpLoad invocation context (op.Env) the host threads to a STRUCTURAL class:kind plugin (F5 authored-member input-threading). A structural kind's authored RESOURCE-MEMBER children (pod/vm/k8s/local/android/group sub-entities) cannot ride op.Params — that JSON is unified against the plugin's CLOSED #<Kind>Input def, which the member subtree would violate. So the host PRE-DECODES the authored member children HOST-SIDE, via the SAME core buildBundleNode recursion the builtin path uses (buildResourceMemberChildren — one member-decode source of truth, R3), and threads the decoded subtree HERE. The plugin decodes only its KIND-SPECIFIC scalar config from op.Params and ATTACHES these members to its spec.Deploy reply — Members for a targetless kind (group), Children for a workload kind — so runPluginKind folds a COMPLETE Bundle (with members) into uf.Bundle, identical to the builtin decode. Cross-member `${HOST:…}` refs survive as literal strings resolved later by tree position (check_members.go), so host-side pre-decode is structure-preserving.
type TunnelYAML ¶
type TunnelYAML struct {
Provider string `yaml:"provider" json:"provider"`
Tunnel string `yaml:"tunnel,omitempty" json:"tunnel,omitempty"`
Public PortScope `yaml:"public,omitempty" json:"public"`
Private PortScope `yaml:"private,omitempty" json:"private"`
}
TunnelYAML supports both bare string and expanded form (the `tunnel:` field).
type VFIOGpu ¶
type VFIOGpu struct {
VFIOPCIDevice
GroupMembers []VFIOPCIDevice `json:"group_members"` // includes the GPU function itself; sorted by Addr
}
VFIOGpu is a display-class device plus every other function sharing its IOMMU group. Passthrough must move the whole group together, so the renderer emits one <hostdev> per GroupMember.
func SelectGPUByVendor ¶
func SelectGPUByVendor(rep VFIOReport, vendor string) (VFIOGpu, bool)
SelectGPUByVendor returns the first passthrough-capable GPU whose PCI vendor matches (case/prefix-insensitive). ok=false when no GPU matches.
type VFIOPCIDevice ¶
type VFIOPCIDevice struct {
Addr string `json:"addr"` // 0000:01:00.0 (sysfs device-directory name = libvirt domain:bus:slot.function)
VendorID string `json:"vendor_id"` // 0x10de
DeviceID string `json:"device_id"` // 0x2704
Class string `json:"class"` // 0x0300 (high 16 bits of the PCI class code)
ClassLabel string `json:"class_label"` // human label, e.g. "VGA controller"
Driver string `json:"driver"` // nvidia | nouveau | vfio-pci | "" (unbound)
IOMMUGroup int `json:"iommu_group"` // -1 when the device has no iommu_group (IOMMU disabled)
}
VFIOPCIDevice is a single PCI function discovered under sysfs.
type VFIOReport ¶
type VFIOReport struct {
IOMMUEnabled bool `json:"iommu_enabled"` // /sys/kernel/iommu_groups is populated
IOMMUKind string `json:"iommu_kind"` // intel | amd | "" (from kernel cmdline)
GPUs []VFIOGpu `json:"gpus"`
}
VFIOReport summarizes host readiness for VFIO GPU passthrough.
type VenueDescriptor ¶
type VenueDescriptor struct {
Kind string `json:"kind"` // "shell" | "ssh"
User string `json:"user,omitempty"`
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
Args []string `json:"args,omitempty"`
ConnectTimeout int `json:"connect_timeout,omitempty"`
}
VenueDescriptor is the SELF-CONTAINED, serializable description of a deploy venue's executor that a substrate LIFECYCLE plugin's OpPrepareVenue / OpTeardownExecutor returns (F6). A live DeployExecutor (ShellExecutor / *SSHExecutor) cannot cross the wire, so the plugin returns this descriptor and the HOST re-materializes the real executor from it — independently, AFTER the lifecycle Invoke returns — then serves THAT over the existing ExecutorService to the deploy-walk plugin. Kind "shell" → a host-local ShellExecutor (the SSH fields are ignored); Kind "ssh" → an *SSHExecutor built from User/Host/Port/Args/ConnectTimeout (the guest venue). Empty → no venue.
type Vm ¶
type Vm struct {
Source VmSource `yaml:"source,omitempty" json:"source"`
DiskSize string `yaml:"disk_size,omitempty" json:"disk_size,omitempty"`
Ram string `yaml:"ram,omitempty" json:"ram,omitempty"`
Cpus int `yaml:"cpu,omitempty" json:"cpu,omitempty"`
Machine string `yaml:"machine,omitempty" json:"machine,omitempty"`
// firmware is REQUIRED-with-default (not optional): an if-guard can only
// reference a field that always resolves to a concrete value, and an
// OPTIONAL field — even one carrying a default — errors with "cannot
// reference optional field" when absent. Required-with-default materializes
// "bios" on omission (matching the Go empty→bios behavior) AND stays
// referenceable by the uefi-secure cross-rule below.
Firmware string `yaml:"firmware,omitempty" json:"firmware"`
Backend string `yaml:"backend,omitempty" json:"backend"`
Autostart bool `yaml:"autostart,omitempty" json:"autostart"`
Network *VmNetwork `yaml:"network,omitempty" json:"network,omitempty"`
SSH *VmSSH `yaml:"ssh,omitempty" json:"ssh,omitempty"`
CloudInit *VmCloudInit `yaml:"cloud_init,omitempty" json:"cloud_init,omitempty"`
Libvirt *LibvirtDomain `yaml:"libvirt,omitempty" json:"libvirt,omitempty"`
Plan []Step `yaml:"plan,omitempty" json:"plan,omitempty"`
Snapshots []VmSnapshot `yaml:"snapshot,omitempty" json:"snapshot,omitempty"`
}
type VmCharlyInstall ¶
type VmCharlyInstall struct {
// VmCharlyInstall has ONLY `strategy` (the vm-spec skill's url/checksum are
// STALE — the Go struct dropped them). auto: scp host binary post-boot;
// scp: explicit form; skip: user-managed.
Strategy string `yaml:"strategy,omitempty" json:"strategy,omitempty"`
}
type VmChecksum ¶
type VmCloudInit ¶
type VmCloudInit struct {
Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
Timezone string `yaml:"timezone,omitempty" json:"timezone,omitempty"`
Locale string `yaml:"locale,omitempty" json:"locale,omitempty"`
Users []VmCloudInitUser `yaml:"users,omitempty" json:"users,omitempty"`
Package []string `yaml:"package,omitempty" json:"package,omitempty"`
RunCmd []string `yaml:"runcmd,omitempty" json:"runcmd,omitempty"`
BootCmd []string `yaml:"bootcmd,omitempty" json:"bootcmd,omitempty"`
WriteFiles []VmCloudInitFile `yaml:"write_files,omitempty" json:"write_files,omitempty"`
Network *VmCloudInitNetwork `yaml:"network,omitempty" json:"network,omitempty"`
Mirrors *VmCloudInitMirrors `yaml:"mirrors,omitempty" json:"mirrors,omitempty"`
CharlyInstall *VmCharlyInstall `yaml:"charly_install,omitempty" json:"charly_install,omitempty"`
Extra string `yaml:"extra,omitempty" json:"extra,omitempty"`
}
--------------------------------------------------------------------------- cloud_init: VmCloudInit. CLOSED. Genuine passthroughs: extra (raw cloud-config string) and network.ethernets (network-config v2, map[string]map[string]any → {[string]: {[string]: _}}). ---------------------------------------------------------------------------
type VmCloudInitFile ¶
type VmCloudInitFile struct {
Path string `yaml:"path,omitempty" json:"path"`
Content string `yaml:"content,omitempty" json:"content,omitempty"`
Owner string `yaml:"owner,omitempty" json:"owner,omitempty"`
Perms string `yaml:"perms,omitempty" json:"perms,omitempty"`
Encoding string `yaml:"encoding,omitempty" json:"encoding,omitempty"`
}
type VmCloudInitMirrors ¶
type VmCloudInitNetwork ¶
type VmCloudInitUser ¶
type VmCloudInitUser struct {
Name string `yaml:"name,omitempty" json:"name"`
Sudo bool `yaml:"sudo,omitempty" json:"sudo,omitempty"`
Groups []string `yaml:"groups,omitempty" json:"groups,omitempty"`
Shell string `yaml:"shell,omitempty" json:"shell,omitempty"`
LockPasswd *bool `yaml:"lock_passwd,omitempty" json:"lock_passwd,omitempty"`
}
type VmDeployState ¶
type VmDeployState struct {
InstanceID string `yaml:"instance_id,omitempty" json:"instance_id,omitempty"`
DiskPath string `yaml:"disk_path,omitempty" json:"disk_path,omitempty"`
SeedIso string `yaml:"seed_iso,omitempty" json:"seed_iso,omitempty"`
SshPort int `yaml:"ssh_port,omitempty" json:"ssh_port,omitempty"`
SshUser string `yaml:"ssh_user,omitempty" json:"ssh_user,omitempty"`
Backend string `yaml:"backend,omitempty" json:"backend,omitempty"`
KeyInjectionResolved *VmKeyInjectionResolved `yaml:"key_injection_resolved,omitempty" json:"key_injection_resolved,omitempty"`
CharlyInstallStrategy string `yaml:"charly_install_strategy,omitempty" json:"charly_install_strategy,omitempty"`
CloudInitRenderedDigest string `yaml:"cloud_init_rendered_digest,omitempty" json:"cloud_init_rendered_digest,omitempty"`
Snapshots []VmSnapshotState `yaml:"snapshot,omitempty" json:"snapshot,omitempty"`
Ephemeral *EphemeralRuntime `yaml:"ephemeral,omitempty" json:"ephemeral,omitempty"`
}
VmDeployState is the runtime state the vm lifecycle hook's PrepareVenue writes on first apply. Source: charly/deploy.go VmDeployState.
type VmKeyInjection ¶
type VmKeyInjectionResolved ¶
type VmKeyInjectionResolved struct {
SMBIOS bool `yaml:"smbios" json:"smbios"`
CloudInit bool `yaml:"cloud_init" json:"cloud_init"`
}
VmKeyInjectionResolved is the effective key-injection state. Source: charly/deploy.go VmKeyInjectionResolved.
type VmNetwork ¶
type VmNetwork struct {
Model string `yaml:"model,omitempty" json:"model,omitempty"`
Mode string `yaml:"mode,omitempty" json:"mode"`
Bridge string `yaml:"bridge,omitempty" json:"bridge,omitempty"`
MAC string `yaml:"mac,omitempty" json:"mac,omitempty"`
PortForwards []string `yaml:"port_forwards,omitempty" json:"port_forwards,omitempty"`
}
type VmSSH ¶
type VmSSH struct {
User string `yaml:"user,omitempty" json:"user,omitempty"`
Port int `yaml:"port,omitempty" json:"port,omitempty"`
PortAuto bool `yaml:"port_auto,omitempty" json:"port_auto,omitempty"`
KeySource string `yaml:"key_source,omitempty" json:"key_source,omitempty"`
KeyInjection *VmKeyInjection `yaml:"key_injection,omitempty" json:"key_injection,omitempty"`
}
VmSSH is the guest SSH access config (port XOR port_auto is a Go cross-field rule). KeyInjection references the generated VmKeyInjection.
type VmSnapshot ¶
type VmSnapshot struct {
Name string `yaml:"name,omitempty" json:"name"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
Quiesce bool `yaml:"quiesce,omitempty" json:"quiesce,omitempty"`
From string `yaml:"from,omitempty" json:"from,omitempty"`
}
type VmSnapshotState ¶
type VmSnapshotState struct {
Name string `yaml:"name" json:"name"`
Mode string `yaml:"mode" json:"mode"`
LibvirtName string `yaml:"libvirt_name,omitempty" json:"libvirt_name,omitempty"`
DiskPath string `yaml:"disk_path,omitempty" json:"disk_path,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Created string `yaml:"created,omitempty" json:"created,omitempty"`
Parent string `yaml:"parent,omitempty" json:"parent,omitempty"`
Refcount int `yaml:"refcount" json:"refcount"`
}
VmSnapshotState mirrors one snapshot in the charly.yml vm_state record. Source: charly/deploy.go VmSnapshotState.
type VmSource ¶
type VmSource struct {
Kind string `yaml:"kind" json:"kind"`
URL string `yaml:"url,omitempty" json:"url,omitempty"`
Checksum VmChecksum `yaml:"checksum,omitempty" json:"checksum,omitempty"`
Cache string `yaml:"cache,omitempty" json:"cache,omitempty"`
BaseUser string `yaml:"base_user,omitempty" json:"base_user,omitempty"`
Box string `yaml:"box,omitempty" json:"box,omitempty"`
Transport string `yaml:"transport,omitempty" json:"transport,omitempty"`
Rootfs string `yaml:"rootfs,omitempty" json:"rootfs,omitempty"`
RootSize string `yaml:"root_size,omitempty" json:"root_size,omitempty"`
KernelArgs string `yaml:"kernel_args,omitempty" json:"kernel_args,omitempty"`
FromVm string `yaml:"from_vm,omitempty" json:"from_vm,omitempty"`
FromSnapshot string `yaml:"from_snapshot,omitempty" json:"from_snapshot,omitempty"`
CloudInitClean bool `yaml:"cloud_init_clean,omitempty" json:"cloud_init_clean,omitempty"`
LibvirtName string `yaml:"libvirt_name,omitempty" json:"libvirt_name,omitempty"`
DiskPath string `yaml:"disk_path,omitempty" json:"disk_path,omitempty"`
DiskFormat string `yaml:"disk_format,omitempty" json:"disk_format,omitempty"`
AdoptedAt string `yaml:"adopted_at,omitempty" json:"adopted_at,omitempty"`
LastSyncedAt string `yaml:"last_synced_at,omitempty" json:"last_synced_at,omitempty"`
Builder string `yaml:"builder,omitempty" json:"builder,omitempty"`
BuilderImage string `yaml:"builder_image,omitempty" json:"builder_image,omitempty"`
Distro string `yaml:"distro,omitempty" json:"distro,omitempty"`
Package []string `yaml:"package,omitempty" json:"package,omitempty"`
BootstrapArch string `yaml:"bootstrap_arch,omitempty" json:"bootstrap_arch,omitempty"`
BootstrapVariant string `yaml:"bootstrap_variant,omitempty" json:"bootstrap_variant,omitempty"`
}
VmSource is the discriminated-union source for a VM disk image (Kind selects the active branch: cloud_image / bootc / clone / imported / bootstrap).