Documentation
¶
Overview ¶
Package sdk is the importable surface an out-of-tree charly plugin builds against. An external plugin implements the proto Provider + PluginMeta services (github.com/opencharly/spec/proto) and calls sdk.Serve from its main; charly connects to it through the SAME handshake + dispense key. The handshake/glue live in spec/transport (NOT in charly's package main) so both charly and an external plugin share ONE definition — no drift, no duplication (R3).
#55 import-purity: the go-plugin serve/dispense surface (Serve/PluginMap/Conn, the handshake, the channel streaming types, the parent-death backstop) was relocated ADDITIVELY to github.com/opencharly/spec/transport by the spec leg. The sdk root now re-exports those symbols as thin shims so every candy call site compiles UNCHANGED; the definitions live once in spec/transport (the single source). The sdk root keeps its own SDK-facing authoring types (ProvidedCapability, the string-scope StepContract, SchemaValidator) that an out-of-tree plugin constructs.
Index ¶
- Constants
- Variables
- func BuildCLIModel(root any, name, version, prefix string, options ...kong.Option) (*spec.CLIModel, error)
- func BuildCapabilities(calver string, provided []ProvidedCapability, schemaFS fs.FS, dir string) (*pb.Capabilities, error)
- func BuildDeployReply(reverseOps []spec.ReverseOp, candy, version string) (*pb.InvokeReply, error)
- func CheckRequiredModifiers(method string, op *spec.Op, required map[string][]string, ...) error
- func DecodeDeployVenue(envJSON []byte) (spec.DeployVenue, error)
- func DecodeInstallPlans(paramsJSON []byte) ([]spec.InstallPlanView, error)
- func KongLeafToCLILeaf(leaf *kong.Node) spec.CLILeaf
- func MatchAll(value string, matchers []Matcher) error
- func MatchValueString(v any) string
- func MatchValueStrings(v any) []string
- func NewCheckContext(brokerID uint32, envJSON []byte) (kit.CheckContext, error)
- func NewMeta(calver string, caps []ProvidedCapability, schemaFS fs.FS) pb.PluginMetaServer
- func OpModifierZero(op *spec.Op, name string) bool
- func ParseInProcCLI(name string, cli any, args []string, opts ...kong.Option) (done bool, err error)
- func PluginScriptReverseOp(scope spec.Scope, script string) spec.ReverseOp
- func Preview(s string) string
- func RequireModifiers(method string, op *spec.Op, required map[string][]string) error
- func RunArtifactValidators(op *spec.Op) error
- func RunInProcCLI(name string, cli any, args []string, opts ...kong.Option) error
- func ServeCheckVerb(kv kit.CheckVerbProvider, meta pb.PluginMetaServer)
- func VerbVerdict(verb, method, out string, runErr error, op *spec.Op, artifact bool) (*pb.InvokeReply, error)
- type CLISubcommand
- type ChannelProvider
- type Conn
- type Executor
- type ExitCodeError
- type HostStepDeps
- type InvokeProviderOpts
- type Matcher
- type ProvidedCapability
- type ProviderChannel
- type ReplayBuffer
- type SchemaValidator
- type SequenceGate
- type StepContract
Constants ¶
const ( ChannelOpen = transport.ChannelOpen ChannelStdin = transport.ChannelStdin ChannelStdout = transport.ChannelStdout ChannelStderr = transport.ChannelStderr ChannelTerminal = transport.ChannelTerminal ChannelStatus = transport.ChannelStatus ChannelResize = transport.ChannelResize ChannelSignal = transport.ChannelSignal ChannelAck = transport.ChannelAck ChannelCancel = transport.ChannelCancel ChannelExit = transport.ChannelExit ChannelError = transport.ChannelError ChannelResync = transport.ChannelResync )
Channel frame kinds are transport vocabulary, not runtime semantics. Runtime- specific events travel as CUE-generated JSON in ChannelFrame.PayloadJson.
const ( CheckFailExitCode = exitcode.CheckFailExitCode CheckSkippedExitCode = exitcode.CheckSkippedExitCode )
The check-command exit-code convention (goss/pytest 0/1/2/3), single-sourced here so both the HOST (main()'s exit mapping + `charly box feature run`) and candy/plugin-check reference ONE contract:
0 all checks passed 1 infra / usage error — no pass/fail verdict was produced (the host default) 2 the check RAN and one or more checks FAILED 3 the bed was SKIPPED (a required host prerequisite — e.g. a GPU — is absent)
const ( // verb/kind/deploy/step/builder operation selectors. OpRun = ops.OpRun // verb: run a check / live-container probe → CheckResult OpLoad = ops.OpLoad // kind: decode a node into its typed entity OpValidate = ops.OpValidate // kind: closed/concrete CUE validation → Diagnostics OpEmit = ops.OpEmit // deploy/step: emit an InstallPlan / Containerfile fragment OpExecute = ops.OpExecute // deploy/step: execute against a venue (streamed) OpResolve = ops.OpResolve // builder: resolve a builder image + steps (build-time multi-stage) OpBuild = ops.OpBuild // build: dispatch the image-build / generate engine host-side (F10 HostBuild seam) // OpCompile is the K4-B deploy-COMPILE selector (command:bundle). OpCompile = ops.OpCompile // OpCollectContext + OpReverse are the DEPLOY-TIME builder-IR legs of an externalized detection-builder. OpCollectContext = ops.OpCollectContext // builder: per-candy stage-context keys → BuilderCollectReply OpReverse = ops.OpReverse // builder: teardown ops for a resolved stage context → BuilderReverseReply // F6 — the SUBSTRATE LIFECYCLE selectors (host→plugin on Provider.Invoke). OpPrepareVenue = ops.OpPrepareVenue // lifecycle: build the venue → VenueDescriptor (re-materialized host-side) OpArtifactKey = ops.OpArtifactKey // lifecycle: the per-deploy artifact ledger key OpPostApply = ops.OpPostApply // lifecycle: post-walk finalize on the venue OpTeardownExecutor = ops.OpTeardownExecutor // lifecycle: the executor for Del → VenueDescriptor OpPostTeardown = ops.OpPostTeardown // lifecycle: drop venue artifacts (image/domain) OpStart = ops.OpStart // lifecycle: start the venue OpStop = ops.OpStop // lifecycle: stop the venue OpStatus = ops.OpStatus // lifecycle: venue status → StatusInfo OpLogs = ops.OpLogs // lifecycle: stream venue logs OpShell = ops.OpShell // lifecycle: NON-interactive in-container exec CAPTURE; interactive shell is OpAttach OpAttach = ops.OpAttach // F12 lifecycle: LIVE-STDIO attach OpRebuild = ops.OpRebuild // lifecycle: rebuild the venue (charly update) // OpConfigWrite is the POD config-WRITE selector (P11, Q1=(a)). OpConfigWrite = ops.OpConfigWrite // OpConfigSetup / OpConfigRemove are the P13-KERNEL config-BODY selectors. OpConfigSetup = ops.OpConfigSetup OpConfigRemove = ops.OpConfigRemove // OpStatusCollect: programmatic status collection → []spec.DeploymentStatus (distinct from lifecycle OpStatus). OpStatusCollect = ops.OpStatusCollect // OpStatusCollectAll is the K6 whole-subsystem status FAN-OUT + deploy-cone ENRICHMENT selector. OpStatusCollectAll = ops.OpStatusCollectAll // OpPreresolve is the generalized host-side deploy preresolver (F6). OpPreresolve = ops.OpPreresolve // OpBootstrap is the BOOTSTRAP-PHASE hook (F9). OpBootstrap = ops.OpBootstrap // OpEphemeralRegister / OpEphemeralTeardown are the command:bundle EPHEMERAL-LIFECYCLE selectors (FINAL/K5 unit 6a). OpEphemeralRegister = ops.OpEphemeralRegister OpEphemeralTeardown = ops.OpEphemeralTeardown // OpDeployDispatch is the command:bundle S3b selector (ELEVEN former methods through ONE wire pair, R3). OpDeployDispatch = ops.OpDeployDispatch // OpVerifyChecks is the command:check selector for the DEPLOY-VERIFY drive (#55 CHECK-ENGINE cone, Unit 2). OpVerifyChecks = ops.OpVerifyChecks // EphemeralPanicMarker prefixes an error converted from a RECOVERED PANIC inside OpEphemeralRegister/OpEphemeralTeardown (RCA #5). EphemeralPanicMarker = ops.EphemeralPanicMarker )
const ( PhaseBootstrap = phase.PhaseBootstrap // before config validation/migration; compiled-in only (no validated config exists yet to discover an out-of-process source). PhaseSchema = phase.PhaseSchema // schema / migration phase PhaseLoad = phase.PhaseLoad // config-load phase (kind decode, etc.) PhaseBuild = phase.PhaseBuild // image-build phase (OpEmit / OpResolve) PhaseRuntime = phase.PhaseRuntime // deploy / runtime phase (OpExecute / OpRun) — the DEFAULT )
Plugin lifecycle PHASES (F9) — the ordered points at which a plugin participates in charly's lifecycle. A plugin DECLARES its phase via ProvidedCapability.Phase (default PhaseRuntime); the kernel loads/invokes plugins in phase order. The BOOTSTRAP phase runs BEFORE config validation/migration, so an early-running capability can itself be a plugin loaded at the right time (today only the no-op candy/plugin-example-bootstrap registers here — neither migrate nor egress is a bootstrap plugin; both are verb plugins invoked the normal way).
const DispenseKey = transport.DispenseKey
DispenseKey is the single go-plugin plugin name; charly serves/dispenses ONE gRPC plugin exposing the uniform Provider + PluginMeta services.
const ProtocolVersion = transport.ProtocolVersion
ProtocolVersion is the go-plugin/proto contract version — a thin secondary gate. CalVer (charly's version.go) is the authority; matching CalVer ⇒ matching proto.
Variables ¶
var ContextWithExecutor = exec.ContextWithExecutor
ContextWithExecutor returns ctx carrying an in-proc *Executor. The host's in-proc dispatch calls this before invoking a compiled-in plugin so the plugin's ExecutorForInvoke can reach the reverse channel without a broker.
var ContextWithHostStepDeps = exec.ContextWithHostStepDeps
ContextWithHostStepDeps threads the live host-step deps onto ctx for a compiled-in class:step plugin's OpExecute handler to recover via HostStepDepsFromCtx.
var CopyChannel = transport.CopyChannel
CopyChannel relays frames until EOF or cancellation. It is intentionally a byte-preserving transport primitive; it does not inspect agent or terminal payloads.
var DecodeGeneratedJSON = climodel.DecodeGeneratedJSON
DecodeGeneratedJSON strictly decodes one persisted or received JSON value into its generated Go type, then validates that typed value against the authoritative CUE definition. Typed decoding is required for fields such as []byte, whose standard JSON representation is base64 text but whose CUE value is bytes. Unknown fields and trailing JSON values are rejected before CUE validation so decoding cannot silently discard persisted input. Relocated to spec/climodel; re-exported here so candy call sites compile UNCHANGED.
var ExecutorForInvoke = exec.ExecutorForInvoke
ExecutorForInvoke resolves the host executor for a plugin's Invoke, transport-invisibly: an IN-PROC compiled-in plugin gets it from the context (ContextWithExecutor); an OUT-OF-PROCESS plugin falls back to the go-plugin broker id in its InvokeRequest.
var ExecutorFromContext = exec.ExecutorFromContext
ExecutorFromContext returns the in-proc *Executor carried on ctx, if any. The public counterpart to ContextWithExecutor.
var ExecutorFromInvoke = exec.ExecutorFromInvoke
ExecutorFromInvoke dials the host's ExecutorService using the broker id the host passed in InvokeRequest.executor_broker_id. Errors if this plugin was not served over go-plugin (no broker) or the id is 0 (no executor attached — a verb/kind op, or a deploy op the host ran in-proc).
var Handshake = transport.Handshake
Handshake is the magic-cookie handshake charly and every plugin MUST share. A plugin server refuses to serve unless launched with CHARLY_PLUGIN set, so a plugin binary run by hand prints the "not meant to be executed directly" notice instead of hanging.
var HostStepDepsFromCtx = exec.HostStepDepsFromCtx
HostStepDepsFromCtx recovers the threaded host-step deps (nil when absent — an out-of-process placement, or a ctx that never carried them).
var IsServeMode = transport.IsServeMode
IsServeMode reports whether this process was launched by charly as a go-plugin gRPC SERVER (the handshake magic-cookie env is present) rather than invoked directly as a CLI. The single switch a dual-mode plugin's main() pivots on.
var Main = transport.Main
Main is the dual-mode entry point a plugin's main() delegates to. In SERVE mode (charly launched it over go-plugin gRPC) it serves the plugin's Provider + PluginMeta (its verb/kind/deploy/step/builder capabilities). Otherwise the plugin was fork/exec'd by charly's COMMAND dispatch (or run by hand) and owns real terminal stdio/TTY: cli runs the command's work with os.Args[1:], its int return becoming the process exit code.
func main() { sdk.Main(&provider{}, &meta{}, cliMain) }
var NewInProcExecutor = exec.NewInProcExecutor
NewInProcExecutor wraps an in-proc pb.ExecutorServiceClient (an adapter delegating DIRECTLY to the host's executorReverseServer, no socket) as an *Executor — the IN-PROCESS twin of the go-plugin broker path in ExecutorFromInvoke.
var NewReplayBuffer = transport.NewReplayBuffer
NewReplayBuffer constructs a ReplayBuffer capped at maxFrames frames / maxBytes bytes.
var NewSequenceGate = transport.NewSequenceGate
NewSequenceGate constructs a SequenceGate whose next-expected sequence is first.
var NormalizePhase = phase.NormalizePhase
NormalizePhase maps an empty or unrecognized declared phase to the default (PhaseRuntime), so a plugin that declares no phase participates at the normal (runtime) time.
var OpenProviderChannel = transport.OpenProviderChannel
OpenProviderChannel starts a generated Provider.Channel stream and sends its mandatory open frame. The returned stream is ready for concurrent Send/Recv, as supported by gRPC.
var PhaseOrder = phase.PhaseOrder
PhaseOrder lists the phases in ascending load order; the kernel iterates plugins phase-ascending (bootstrap first). It is the authority for ordering + membership.
var PluginMap = transport.PluginMap
PluginMap builds the go-plugin PluginSet for the dispense key. Server side passes the two service impls; the client side (charly connecting) passes nil,nil and receives a *Conn from the dispense.
var ReceiveChannelOpen = transport.ReceiveChannelOpen
ReceiveChannelOpen reads and validates the mandatory first frame. The request id, provider class/word, and operation are required so every later frame can be correlated without inspecting runtime-specific payloads.
var RelayChannel = transport.RelayChannel
RelayChannel connects a controller-side ProviderChannel to a downstream gRPC channel with ordered half-close semantics. See spec/transport for the cancellation-ownership contract.
var ResultJSON = ops.ResultJSON
ResultJSON builds the InvokeReply an out-of-process check verb's Invoke returns — the SAME {status,message} shape every verb plugin (and ServeCheckVerb) emits (R3). Relocated to spec/ops; re-exported here so candy call sites compile UNCHANGED.
var Serve = transport.Serve
Serve exposes a plugin's Provider + PluginMeta services over go-plugin gRPC and blocks serving. The serve half of Main (a verb/kind/deploy/step/builder plugin with no CLI mode may call it directly):
func main() { sdk.Serve(&myProvider{}, &myMeta{}) }
var ValidateGenerated = climodel.ValidateGenerated
ValidateGenerated validates a generated SDK value against its authoritative CUE definition. Command plugins use the same embedded schema as core, so moving command ownership never creates a hand-maintained validation copy. Relocated to spec/climodel; re-exported here so candy call sites compile UNCHANGED.
Functions ¶
func BuildCLIModel ¶ added in v0.2026200.1312
func BuildCLIModel(root any, name, version, prefix string, options ...kong.Option) (*spec.CLIModel, error)
BuildCLIModel reflects a Kong command tree into the generated #CLIModel. Prefix is a dotted command path prepended to every leaf (for example "agent" when a command plugin reflects only its owned subtree).
func BuildCapabilities ¶
func BuildCapabilities(calver string, provided []ProvidedCapability, schemaFS fs.FS, dir string) (*pb.Capabilities, error)
BuildCapabilities is the serve-side half of the "every plugin ships its own CUE schema" contract. It concatenates the plugin's embedded schema/*.cue via the SAME schemaconcat contract charly uses for its base (R3 — one concat loop, no duplicate), compiles it STANDALONE to fail loudly on a broken or empty schema (a self-contained schema must compile alone — the same property that lets `cue exp gengotypes` generate the plugin's Go params), and assembles the Describe reply carrying the raw .cue source the host splices onto its base.
schemaFS is the plugin's `//go:embed schema/*.cue` FS; dir is the embedded subdirectory ("schema"). Both the SDK and charly's base reach the same internal schemaconcat because the SDK lives under charly/ — an external module imports only this SDK, never charly/internal directly.
func BuildDeployReply ¶
BuildDeployReply assembles the OpExecute reply: the teardown ops the host records + the ledger CandyRecord identity (candy name + version). The host decodes the same spec.DeployReply and persists it via install_ledger.go. A plugin's Invoke returns this directly as its *pb.InvokeReply.
func CheckRequiredModifiers ¶
func CheckRequiredModifiers(method string, op *spec.Op, required map[string][]string, isZero func(op *spec.Op, name string) bool) error
CheckRequiredModifiers verifies every modifier a method requires is present on op, returning a "missing required modifier(s): …" error naming the absent ones. required maps a method name to its required modifier field names, and isZero reports whether a named modifier is absent (zero) on op. RequireModifiers binds isZero to the generic OpModifierZero; this lower form stays for a verb whose zero-semantics genuinely differ from plain reflection (R3).
func DecodeDeployVenue ¶
func DecodeDeployVenue(envJSON []byte) (spec.DeployVenue, error)
DecodeDeployVenue decodes the venue descriptor the host put in an OpExecute Invoke's env_json (op.Env). The zero DeployVenue is returned for an empty payload (the common "no venue env" call, e.g. the e2e direct invoke).
func DecodeInstallPlans ¶
func DecodeInstallPlans(paramsJSON []byte) ([]spec.InstallPlanView, error)
DecodeInstallPlans decodes the host-marshalled InstallPlan VIEWS carried in an OpExecute Invoke's params_json (op.Params). Returns nil for an empty payload (a deploy with no candy plans — e.g. a marker-only example). The rich in-core Steps are NOT on the wire (see spec.InstallPlanView); the provenance fields prove the plan travelled.
func KongLeafToCLILeaf ¶ added in v0.2026200.1312
KongLeafToCLILeaf converts one Kong leaf into the generated wire shape.
func MatchAll ¶
MatchAll returns nil if every matcher succeeds against the value. The first failure wins (reports the specific unmet expectation).
Takes []Matcher rather than MatcherList so callers can pass any named slice type whose underlying element is Matcher (e.g. ContainsList) without an explicit conversion at every call site.
Shared by the core check runner and out-of-tree verb plugins.
func MatchValueString ¶
MatchValueString coerces a matcher's stored Value (any) to a string. For numeric types it renders canonically; for everything else it falls back to fmt.Sprint.
Shared by the core check runner and out-of-tree verb plugins.
func MatchValueStrings ¶
MatchValueStrings handles list-valued matchers like {contains: [a, b]}. A scalar value becomes a singleton list.
Shared by the core check runner and out-of-tree verb plugins.
func NewCheckContext ¶ added in v0.2026187.2110
func NewCheckContext(brokerID uint32, envJSON []byte) (kit.CheckContext, error)
NewCheckContext builds the out-of-process kit.CheckContext for a RAW pb.Provider (Invoke) that needs the reverse-channel legs (ResolveEndpoint / HTTPDo / Exec) but is NOT a kit.CheckVerbProvider (so the kit-verb serve path never built one for it). envJSON is the InvokeRequest.env_json (the host's CheckEnv snapshot). Dials the broker ONCE — do NOT also call ExecutorFromInvoke on the same Invoke (a second Dial hangs; use cc.Exec() instead).
func NewMeta ¶ added in v0.2026185.2311
func NewMeta(calver string, caps []ProvidedCapability, schemaFS fs.FS) pb.PluginMetaServer
NewMeta returns the shared PluginMetaServer for a plugin: its Describe reply carries caps + the CUE schema embedded at schemaFS's "schema" dir. It replaces the ~58 hand-rolled meta types + Describe bodies (R3) — a plugin's NewMeta() is now just `return sdk.NewMeta(calver, caps, schemaFS)`.
func OpModifierZero ¶ added in v0.2026185.2336
OpModifierZero reports whether the modifier named `name` is absent (zero) on the step. Since the schema-compaction cutover a verb's per-method fields live in the desugared plugin INPUT map (op.PluginInput), so the lookup is map-first: a key present in the input with a non-zero value is present. The handful of genuinely SHARED #Op fields a method contract may still name (target, caps) fall back to reflection over spec.Op's yaml tags. An unknown name is treated as absent. Asserted by TestOpModifierZeroMatchesFields.
func ParseInProcCLI ¶ added in v0.2026195.204
func ParseInProcCLI(name string, cli any, args []string, opts ...kong.Option) (done bool, err error)
ParseInProcCLI parses args into cli WITHOUT running any leaf — the entry for a command plugin that dispatches MANUALLY after parsing (it reads the populated struct itself rather than relying on kong's Run()). It returns done=true when kong printed --help/--version: the caller MUST return nil immediately and NOT proceed to its post-parse logic (otherwise `charly <cmd> --help` would run the command's action on default flags). A parse error is returned as err.
func PluginScriptReverseOp ¶
PluginScriptReverseOp builds the generic recordable teardown op an external deploy/step/builder plugin returns: a verbatim shell script run at `charly bundle del` time at the given scope (spec.ScopeSystem → root, spec.ScopeUser → deploy user). The host records it in the ledger and replays it via reverse_ops.go's reversePluginScript — record-and-replay, never recomputed.
func Preview ¶ added in v0.2026186.2
Preview truncates a string to 400 chars (adding an ellipsis) for verdict error messages — the shared truncation each live-verb plugin formerly copied.
func RequireModifiers ¶ added in v0.2026185.2336
RequireModifiers verifies every modifier a method requires is present on op, using the generic OpModifierZero — so a plugin keeps ONLY its requiredModifiers map (genuinely per-verb data) and drops both its copy-pasted modifierZero func and the CheckRequiredModifiers wrapper call (R3). It is CheckRequiredModifiers bound to OpModifierZero.
func RunArtifactValidators ¶
RunArtifactValidators runs every artifact assertion the step's plugin input declares against the file at the input's `artifact` path: artifact_min_bytes, artifact_min_dimensions (WxH), artifact_not_uniform, and artifact_min_cast_events. The artifact fields live in the desugared plugin input map (per-verb fields left core #Op in the schema-compaction cutover). Returns nil when every declared validator passes, or the first validator's error. A plugin that produces an artifact calls this after writing the file as the post-run validation pipeline.
func RunInProcCLI ¶ added in v0.2026195.204
RunInProcCLI parses args into the kong grammar cli and runs the selected leaf's Run() — the entry for a command plugin whose grammar carries Run() leaves (the common case). On `--help`/`--version` it prints and returns nil WITHOUT running any leaf; a non-zero kong exit becomes *ExitCodeError; a parse error propagates. Pass any extra kong.Option (kong.Description, kong.Bind, …) via opts — kong.Name + the exit-sentinel are supplied for you.
func ServeCheckVerb ¶
func ServeCheckVerb(kv kit.CheckVerbProvider, meta pb.PluginMetaServer)
ServeCheckVerb serves a HOST-COUPLED check verb (kit.CheckVerbProvider) OUT-OF-PROCESS (F2): it wraps the verb in a pb.ProviderServer whose Invoke reconstructs a kit.CheckContext from the host's reverse channel (ExecutorService for Exec + CheckContextService for HTTPDo/AddBackground, on the InvokeRequest broker) plus the env_json CheckEnv snapshot (Mode/Box/Instance/Distros/DialTimeout), runs RunVerb, and returns the verdict. The SAME kit verb compiles INTO charly in-process (registerCompiledCheckVerb passes the live *Runner as the CheckContext); this is the out-of-process placement, ZERO authoring change. A kit candy's cmd/serve is the SAME one-liner shape as every pb-provider plugin: sdk.ServeCheckVerb(pkg.NewCheckVerb(), pkg.NewMeta()) — meta is the ONE shared NewMeta the candy also exports, unifying kit candies with the pb-provider authoring shape (R3).
func VerbVerdict ¶ added in v0.2026186.2
func VerbVerdict(verb, method, out string, runErr error, op *spec.Op, artifact bool) (*pb.InvokeReply, error)
VerbVerdict is the shared exit/stdout/stderr/artifact verdict pipeline every live check verb runs after dispatching an op — the byte-identical block cdp/vnc/wl/dbus/record/… each carried, hoisted here (R3). It maps runErr → exit 1 + stderr, compares exit against the authored op.ExitStatus, runs the op.Stdout/op.Stderr MatchAll validators and (when artifact is true) the artifact validators, and returns the {status,message} reply — "fail" naming the first mismatch, "pass" with a non-empty body (out, else stderr, else a synthetic "<verb> <method>: exit=N"). `verb` prefixes every message ("cdp: screenshot: exit=…"); the caller passes whether THIS method produces an artifact (e.g. method == "screenshot").
Types ¶
type CLISubcommand ¶ added in v0.2026201.542
type CLISubcommand = climodel.CLISubcommand
CLISubcommand is one DECLARED child of a class="command" capability's own CLI word — see ProvidedCapability.Subcommands. Relocated to spec/climodel (#55 import-purity); re-exported here so candy call sites compile UNCHANGED.
func KongSubcommands ¶ added in v0.2026201.542
func KongSubcommands(v any) []CLISubcommand
KongSubcommands walks a Kong-tagged struct (or pointer to one) ONE level deep and returns its named `cmd:""` children as a CLISubcommand catalog: Name from the field's `name:` tag when present, otherwise the SAME kebab-cased field name Kong itself computes as the default command name (RDD-spiked: Kong's `cmd:"<value>"` tag VALUE is never read as a name — a `cmd` tag is a pure presence marker — so a value-carrying `cmd:"foo"` with no separate `name:` tag does NOT mean the command is named "foo"; replicating the fallback here keeps a declared subcommand's NAME byte-identical to what Kong actually dispatches). Help comes from the field's `help:` tag. A field tagged `hidden:""` is skipped — machinery subcommands stay invisible to `--help` and MCP exactly as in the plugin's own internal grammar. A field with no `cmd` tag key at all (kong requires the key to be PRESENT, regardless of value, to mark a subcommand) is skipped too.
type ChannelProvider ¶ added in v0.2026200.1312
type ChannelProvider = transport.ChannelProvider
ChannelProvider is the optional streaming extension to Provider. The first frame has already been validated as an open frame and remains available as open; subsequent controller frames arrive through stream. Domain payloads are generated from CUE and carried in open.PayloadJson.
type Executor ¶
Executor is the plugin-side handle to the host's live DeployExecutor over the E3b reverse channel. An out-of-process deploy/step/builder plugin runs shell/SSH ops on the real venue by calling these; the host executes them with the executor it stood up on the broker for this Invoke. The plugin never holds the (unmarshallable) executor itself.
type ExitCodeError ¶ added in v0.2026194.1605
type ExitCodeError = exitcode.ExitCodeError
ExitCodeError carries a specific PROCESS exit code from a command plugin's Invoke(OpRun) back to the host, which maps it to os.Exit(Code). A compiled-in command candy returns its error verbatim through the in-proc dispatch, but the host cannot classify the plugin's OWN error TYPES across the module boundary — so a command that must set a NON-1 exit code (the check 0/1/2/3 convention) wraps its failure in *ExitCodeError, which the host detects with errors.As and honors as the exit status. Code 0 falls back to the host's default error handling (no special code).
type HostStepDeps ¶ added in v0.2026213.1748
type HostStepDeps = exec.HostStepDeps
HostStepDeps carries the live, non-serializable inputs a compiled-in class:step plugin needs to run a deploy-leg host-engine step body (Builder / LocalPkgInstall / SystemPackages) on the host venue. IN-PROC-ONLY (the typed executor + closures cannot cross the wire).
type InvokeProviderOpts ¶ added in v0.2026203.438
type InvokeProviderOpts = ops.InvokeProviderOpts
InvokeProviderOpts carries the OPTIONAL extras to an InvokeProvider peer-dispatch call. The zero value is byte-identical to the pre-S1 behavior.
type Matcher ¶
Matcher is re-exported from charly/spec so an out-of-tree plugin reaches the matcher value type through the SDK alone (an external plugin imports no other charly package).
type ProvidedCapability ¶
type ProvidedCapability struct {
Class string // "verb" / "kind" / "deploy" / "step" / "builder"
Word string // the reserved word, e.g. "externalprobe"
InputDef string // the CUE def for this word's plugin_input, e.g. "#ExternalprobeInput"
// StepContract is set ONLY for Class=="step" (F3): the plugin-declared install-step
// contract (Scope/Venue/Gate) the host applies to the external step via the open default
// arm — no compiled-in case. nil for every other class.
StepContract *StepContract
// Structural is set ONLY for Class=="kind" (F5): the kind decodes a STRUCTURAL entity —
// its OpLoad returns a spec.Deploy member tree the host folds into uf.Bundle — rather than
// a FLAT body landed opaquely in uf.PluginKinds (F4). false for every other class/kind.
Structural bool
// Lifecycle is set ONLY for Class=="deploy" (F6): the substrate brings its OWN host-side
// venue lifecycle (PrepareVenue/Start/Stop/Status/Rebuild/...) served over the lifecycle Ops,
// so the host registers a wire-backed substrateLifecycle for it. false for every other
// class/deploy (local/android/k8s keep the generic host-venue behaviour).
Lifecycle bool
// Preresolve is set ONLY for Class=="deploy" (F6): the substrate declares a host-side
// PRERESOLVE step (OpPreresolve) the host runs before apply, shipping the opaque result in
// DeployVenue.Substrate — the wire-backed generalization of the in-core k8s/android
// preresolvers. false for every other class/deploy.
Preresolve bool
// Validates is set ONLY for Class=="kind" (F7/C8): the kind serves a deep OpValidate check
// (returns spec.Diagnostics) the host dispatches at load, BEYOND the static CUE input-def
// gate. false → only the static gate runs (every other class/kind).
Validates bool
// Phase is the plugin lifecycle PHASE (F9): one of the sdk.Phase* constants. "" → the kernel
// treats it as PhaseRuntime (the default). PhaseBootstrap runs BEFORE config validation —
// declare it for a capability that must load/run early (migrate, egress). The kernel loads +
// invokes plugins in PhaseOrder.
Phase string
// Primary is set ONLY for Class=="verb": the input field the scalar sugar
// shorthand targets (`file: /x` → plugin_input: {<Primary>: "/x"}). "" → the
// verb takes a map input only. The host registers it into the parse-time
// desugar's primary registry (compiled-in at init; an EXTERNAL plugin
// additionally declares it in its candy manifest's plugin.primary map so the
// byte-gated prescan knows it BEFORE the provider connects).
Primary string
// DeployTraits is set ONLY for Class=="kind" on a SUBSTRATE kind (P9): the kind's
// DECLARED deploy behaviour (venue + image_backed/image_context/machine_venue/
// exclusive_venue/leaf_only). kit.StampDescent stamps it onto every node's
// spec.DescentDescriptor so the kernel consults the substrate behaviour BY TRAIT
// (off node.Descent) — never by switching on the kind word. nil for every other
// capability (the zero-value → external-in-place semantics).
DeployTraits *spec.DeployTraits
// Subcommands is set ONLY for Class=="command" (F-CLI-NEST): the plugin's DECLARED
// one-level-deep CLI subcommand catalog (name+help). The host uses it to build a REAL
// nested Kong grammar — a named `cmd:""` child per entry, restoring `--help` fidelity
// and CLI-model (MCP) leaf discoverability — in place of the opaque `[<args>...]`
// pass-through holder every command-class capability otherwise gets. Empty (the
// default) preserves today's flat pass-through behavior byte-for-byte; use
// KongSubcommands to derive the catalog from an existing Kong-tagged struct instead of
// hand-duplicating it.
Subcommands []CLISubcommand
// CommandModel is set ONLY for Class=="command". Its generated #CLIModel
// describes the plugin-owned leaf grammar for host and MCP reflection.
CommandModel *spec.CLIModel
}
ProvidedCapability is one capability a plugin serves plus the CUE def that validates its plugin_input — the SDK-facing form of the proto ProvidedCapability. An external plugin lists these in its Describe; the host validates authored plugin_input for each word against its def in the served schema.
type ProviderChannel ¶ added in v0.2026200.1312
type ProviderChannel = transport.ProviderChannel
ProviderChannel is the common subset of the generated client and server streams. It lets in-process and gRPC providers share one channel handler.
type ReplayBuffer ¶ added in v0.2026200.1312
type ReplayBuffer = transport.ReplayBuffer
ReplayBuffer is a bounded, acknowledgement-aware frame history for detach / reconnect. Bounds are enforced by both frame count and protobuf byte size.
type SchemaValidator ¶ added in v0.2026200.1312
type SchemaValidator struct {
// contains filtered or unexported fields
}
SchemaValidator validates plugin-owned generated values against the same embedded CUE source that the plugin publishes through Describe.
func NewSchemaValidator ¶ added in v0.2026200.1312
func NewSchemaValidator(schemaFS fs.FS, dir string) (*SchemaValidator, error)
NewSchemaValidator compiles one self-contained embedded plugin schema.
func (*SchemaValidator) Validate ¶ added in v0.2026200.1312
func (v *SchemaValidator) Validate(definition string, value any) error
Validate checks a value against a named definition in the compiled schema.
func (*SchemaValidator) ValidateJSON ¶ added in v0.2026200.1312
func (v *SchemaValidator) ValidateJSON(definition string, payload []byte) error
ValidateJSON validates the original JSON bytes without first decoding JSON numbers through float64-backed map[string]any values.
type SequenceGate ¶ added in v0.2026200.1312
type SequenceGate = transport.SequenceGate
SequenceGate rejects duplicates, regressions, and gaps. A provider can turn a gap into ChannelResync using ReplayBuffer.ReplayFrom; it must never silently reorder process or terminal output.
type StepContract ¶
type StepContract struct {
Scope string // "system" | "user" | "user-profile"
Venue int // 0=host-native, 1=container-builder, 2=skip
Gate string // "" | "allow-repo-changes" | "allow-root-tasks" | "with-services"
// Emits declares that the step produces a build-context Containerfile FRAGMENT
// (the plugin serves Invoke(OpEmit) → EmitReply.Fragment). The pod-overlay OCITarget
// bakes it; false => a deploy-only step (no build fragment — OCITarget skips it, like
// apk on an image build). F-STEP-EMIT: the BUILD leg C1 needs to externalize a step
// kind whose EmitOCI produces a Containerfile fragment.
Emits bool
}
StepContract is the SDK-facing form of the proto StepContract — a class="step" plugin's declared install-step Scope/Venue/Gate. Reverse is NOT declared (an external step's teardown ops are recorded dynamically from its OpExecute reply).
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package agentkit implements transport-independent control-plane invariants.
|
Package agentkit implements transport-independent control-plane invariants. |
|
Package buildkit holds the pure Containerfile render/compute machinery that any build front-end (the charly host engine, an out-of-tree build plugin) can import — the SDK-library half of the "core is the kernel; every capability is a plugin" architecture.
|
Package buildkit holds the pure Containerfile render/compute machinery that any build front-end (the charly host engine, an out-of-tree build plugin) can import — the SDK-library half of the "core is the kernel; every capability is a plugin" architecture. |
|
quadlet.go — the POD config-WRITE mechanism, relocated out of charly core (P11a).
|
quadlet.go — the POD config-WRITE mechanism, relocated out of charly core (P11a). |
|
Package enginekit is the container-engine client mechanism: the single place in the status surface that shells out to podman/docker (ps + inspect + exec) and returns structured, batch-derived ContainerSnapshots.
|
Package enginekit is the container-engine client mechanism: the single place in the status surface that shells out to podman/docker (ps + inspect + exec) and returns structured, batch-derived ContainerSnapshots. |
|
Package kit is the importable contract a HOST-COUPLED plugin candy implements to run against charly's live check engine — the seam that lets a check verb whose logic needs the running deployment (exec-in-container, host TCP dial, host-vantage HTTP) live in its own candy module instead of charly's module.
|
Package kit is the importable contract a HOST-COUPLED plugin candy implements to run against charly's live check engine — the seam that lets a check verb whose logic needs the running deployment (exec-in-container, host TCP dial, host-vantage HTTP) live in its own candy module instead of charly's module. |
|
directives.go — the loaderkit-local WALK-only directives: MaxIncludeDepth, namespaceAliasRe, and validateNamespaceAlias.
|
directives.go — the loaderkit-local WALK-only directives: MaxIncludeDepth, namespaceAliasRe, and validateNamespaceAlias. |
|
Code-assisted alias surface for the CUE-single-source cutover (WF-B THE REPOINT).
|
Code-assisted alias surface for the CUE-single-source cutover (WF-B THE REPOINT). |