Documentation
¶
Index ¶
- Constants
- func AnnotatePlanOverride(diff *PlanDiff, proposed *Stack)
- func AppendMutableRefIssues(result *ValidationResult, issues []ValidationIssue)
- func ApplyOverride(stack *Stack, ov *Override, path string) error
- func ApplyOverrideWarnUnknown(stack *Stack, ov *Override, path string) ([]string, error)
- func CheckRequires(constraint string) error
- func ConfigsRevision(ctx context.Context, configs []ConfigFile) (string, error)
- func ContainsExpansion(s string) bool
- func CoverageLimitationMessage() string
- func DiscoverOverride(stackPath string, sel OverrideSelection) (path string, found bool, err error)
- func ExecutionEqual(a, b MCPServer) bool
- func ExecutionOnlyChange(a, b MCPServer) bool
- func ExpandStackVarsWithEnv(s *Stack)
- func ExpandStackVarsWithEnvChecked(s *Stack) error
- func ExpandString(s string, resolve Resolver) (expanded string, unresolvedVault []string, emptyEnvVars []string)
- func ExpandStringRefs(s string, resolve Resolver) (expanded string, storeRefs []string, unresolvedVault []string, ...)
- func ExpandStringResolved(s string, store VaultLookup) (expanded string, unresolvedVault []string, emptyEnvVars []string, ...)
- func ExportNotices(stack *Stack) string
- func ExportOverrideNotice(path string) string
- func IsHiddenToolReference(err ValidationError) bool
- func MCPServerEqual(a, b MCPServer) bool
- func MaintenanceRefFinding(issue ValidationIssue) bool
- func OverridableServerFields() []string
- func ParseSecretRefKey(key string) (provider, path string, ok bool)
- func PolicyMatchLiteral(match string) bool
- func ReadConfigEntry(ctx context.Context, cfg ConfigFile) (mode int64, uid, gid int, body []byte, err error)
- func ReferencedConfigFiles(stack *Stack, stackDir string) ([]string, error)
- func RenderComposed(stack *Stack, layers []Layer) ([]byte, error)
- func ResetRunningVersion()
- func SecretRefKey(provider, path string) string
- func SetRunningVersion(v string)
- func SourceEqual(a, b *Source) bool
- func SubstituteSecretRefs(s *Stack, values map[string]string)
- func SupportedLinkClientsForTest() []string
- func Validate(s *Stack) error
- func ValidateStackFile(path string, opts ...LoadOption) (*Stack, *ValidationResult, error)
- func VaultNeeds(s *Stack) []string
- func WriteComposed(path string, stack *Stack, layers []Layer) error
- type A2AAuth
- type A2AConfig
- type AuthConfig
- type AutoscaleConfig
- type BuildAction
- type BuildIdentity
- type ClientProfile
- type ClientsConfig
- type ConfigFile
- type Consumer
- type DeclarationDiagnostic
- type DependencyStatus
- type DiffAction
- type DiffItem
- type DriftStatus
- type ExecutionConfig
- type ExecutionContract
- type ExecutionMount
- type ExecutionTmpfs
- type GatewayConfig
- type GatewaySecurityConfig
- type GroupConfig
- type GroupOverride
- type IssueSeverity
- type Layer
- type LimitsConfig
- type LinkEntry
- type LoadOption
- type LoggingConfig
- type MCPServer
- func (s *MCPServer) IsA2A() bool
- func (s *MCPServer) IsContainerBased() bool
- func (s *MCPServer) IsEnabled() bool
- func (s *MCPServer) IsExternal() bool
- func (s *MCPServer) IsLocalProcess() bool
- func (s *MCPServer) IsOpenAPI() bool
- func (s *MCPServer) IsSSH() bool
- func (s *MCPServer) PersistLogs(stack *Stack) bool
- func (s *MCPServer) PersistMetrics(stack *Stack) bool
- func (s *MCPServer) PersistTraces(stack *Stack) bool
- func (s *MCPServer) ResolvedPingTimeout() time.Duration
- func (s *MCPServer) ResolvedReadyTimeout() time.Duration
- func (s *MCPServer) ResolvedRestartPolicy() RestartPolicy
- type MCPServerPersistence
- type MCPServerTelemetry
- type MetricsConfig
- type ModelPreferenceScope
- type ModelPreferencesConfig
- type Network
- type OTLPMetricsConfig
- type OpenAPIAuth
- type OpenAPIConfig
- type OpenAPITLS
- type OperationsFilter
- type Override
- type OverrideSelection
- type PlanDiff
- type PolicyConfig
- type PolicyRule
- type RateLimit
- type ReferenceIndex
- type ReferenceKind
- type ReplicaHealth
- type RequiresConfig
- type RequiresError
- type ResolutionResult
- type ResolutionVerdict
- type Resolver
- type Resource
- type RestartPolicy
- type RetentionConfig
- type RunsConfig
- type RunsRetention
- type SSHConfig
- type SchemaPinningConfig
- type SecretProvider
- type SecretRef
- type SecretSetRef
- func (r SecretSetRef) InjectsIntoResource(name string) bool
- func (r SecretSetRef) InjectsIntoServer(name string) bool
- func (r SecretSetRef) IsShorthand() bool
- func (r SecretSetRef) MarshalJSON() ([]byte, error)
- func (r SecretSetRef) MarshalYAML() (any, error)
- func (r SecretSetRef) Scoped() bool
- func (r *SecretSetRef) UnmarshalJSON(data []byte) error
- func (r *SecretSetRef) UnmarshalYAML(value *yaml.Node) error
- type Secrets
- type ServerAuth
- type ServerOverride
- type SkillsPolicyConfig
- type Source
- type SourceAuth
- type SpecHealth
- type Stack
- func Compose(base Layer, fragments []Layer) (*Stack, error)
- func DecodeStack(data []byte) (*Stack, error)
- func ExportStack(ctx context.Context, path string) (*Stack, []string, error)
- func ExportWithOverride(ctx context.Context, path, overridePath string) (*Stack, []string, error)
- func LoadStack(path string, opts ...LoadOption) (*Stack, error)
- func LoadStackData(data []byte, path string, opts ...LoadOption) (*Stack, error)
- func ParseStackIndex(ctx context.Context, path string) (*Stack, error)
- func ReadUnresolved(ctx context.Context, path string) (*Stack, error)
- func ValidateFragment(path string) (*Stack, error)
- func (s *Stack) ActiveMCPServers() []MCPServer
- func (s *Stack) ActiveResources() []Resource
- func (s *Stack) Clone() *Stack
- func (s *Stack) ContainerWorkloads() []string
- func (s *Stack) ModelPolicies() (skills, agents *registry.ModelPolicy)
- func (s *Stack) NeedsContainerRuntime() bool
- func (s *Stack) NonContainerWorkloads() []string
- func (s *Stack) SetDefaults()
- type TelemetryConfig
- type TelemetryPersistence
- type ToolDiscoveryConfig
- type TracingConfig
- type ValidationError
- type ValidationErrors
- type ValidationIssue
- type ValidationResult
- type ValidationStatus
- type VariableDeclaration
- type VariableMetadata
- type VaultLookup
- type VaultSecret
- type VaultSetLookup
Constants ¶
const ExportConfigFilesNotice = "Referenced config files are not bundled; copy them alongside the exported stack."
ExportConfigFilesNotice is appended when the export contains file-backed configs.
const ExportNotice = "" /* 147-byte string literal not displayed */
ExportNotice describes the bounded policy, not a guarantee about arbitrary text.
const OverrideFileName = "stack.override.yaml"
OverrideFileName is the override discovered beside a stack file when neither --override nor --no-override is set.
Variables ¶
This section is empty.
Functions ¶
func AnnotatePlanOverride ¶
AnnotatePlanOverride marks diff items whose changed details come from overridden fields and records the override path on the plan.
func AppendMutableRefIssues ¶
func AppendMutableRefIssues(result *ValidationResult, issues []ValidationIssue)
AppendMutableRefIssues copies advisory findings onto result without changing validity. Warnings increment WarningCount; informational findings do not.
func ApplyOverride ¶
ApplyOverride merges ov onto stack. Unknown server names are errors. The function does not expand variables or read stores. Scalars and lists replace; env and headers merge by key with the override winning.
func ApplyOverrideWarnUnknown ¶
ApplyOverrideWarnUnknown merges ov and reports unknown server names as warnings instead of errors. ValidateStackFile uses this when the file has an extends chain that this parser does not resolve.
func CheckRequires ¶
CheckRequires reports whether the running version satisfies constraint. An empty constraint is not a constraint. A string that does not parse is an error even when the running version is not a release. Satisfaction is skipped for a dev, empty, or non-semver running version, and one warning is logged per process.
func ConfigsRevision ¶
func ConfigsRevision(ctx context.Context, configs []ConfigFile) (string, error)
ConfigsRevision returns the hex sha256 of the resolved config entries. An empty list returns an empty revision and no label. File entries are read. Entries are ordered by target so YAML order does not change the digest.
func ContainsExpansion ¶
ContainsExpansion reports whether s includes a recognized $VAR or ${...} form, including default and replacement operands.
func CoverageLimitationMessage ¶
func CoverageLimitationMessage() string
CoverageLimitationMessage is the opt-in human-output coverage note.
func DiscoverOverride ¶
func DiscoverOverride(stackPath string, sel OverrideSelection) (path string, found bool, err error)
DiscoverOverride resolves the override path for stackPath. A missing discovered file is not an error. An explicit path that does not exist is an error only when Required is set; otherwise found is false and the path is still returned so a watcher can arm on it.
func ExecutionEqual ¶
ExecutionEqual compares normalized execution intent without losing omission.
func ExecutionOnlyChange ¶
ExecutionOnlyChange identifies boundary/pool recreation without changed tool launch inputs. Pool tuning must not turn a boundary change into a trust reset.
func ExpandStackVarsWithEnv ¶
func ExpandStackVarsWithEnv(s *Stack)
ExpandStackVarsWithEnv expands environment variable references in stack fields.
func ExpandStackVarsWithEnvChecked ¶
ExpandStackVarsWithEnvChecked expands environment references and returns a typed error when a reserved internal credential is referenced.
func ExpandString ¶
func ExpandString(s string, resolve Resolver) (expanded string, unresolvedVault []string, emptyEnvVars []string)
ExpandString expands variable references in a string using the given resolver. All patterns are matched in a single pass to prevent double-expansion of values that contain dollar signs.
Returns the expanded string, any unresolved vault references, and env vars that resolved to empty.
func ExpandStringRefs ¶
func ExpandStringRefs(s string, resolve Resolver) (expanded string, storeRefs []string, unresolvedVault []string, emptyEnvVars []string)
ExpandStringRefs is ExpandString plus storeRefs: the variable-store keys (the KEY in ${var:KEY} / ${vault:KEY}) referenced by s, in first-seen order.
storeRefs is captured from the parsed grammar *before* resolution, so it records what s references regardless of whether each key resolves — this is the basis for usage tracing and is why the index can never drift from what expansion actually recognizes. Bare $VAR / ${VAR} env-style references are NOT store references and are deliberately excluded.
func ExpandStringResolved ¶
func ExpandStringResolved(s string, store VaultLookup) (expanded string, unresolvedVault []string, emptyEnvVars []string, problems []error)
ExpandStringResolved expands with store-aware resolution and returns typed problems for denied internal credentials. It preserves ordinary environment interpolation while applying the reserved namespace to store references.
func ExportNotices ¶
ExportNotices returns the stderr and REST notice for an exported stack.
func ExportOverrideNotice ¶
ExportOverrideNotice is appended when an override exists and was not merged.
func IsHiddenToolReference ¶
func IsHiddenToolReference(err ValidationError) bool
IsHiddenToolReference reports whether err is a group reference to a tool hidden by a non-empty server whitelist.
func MCPServerEqual ¶
MCPServerEqual reports whether two MCP server declarations have the same effective configuration.
func MaintenanceRefFinding ¶
func MaintenanceRefFinding(issue ValidationIssue) bool
MaintenanceRefFinding reports whether an advisory finding must be pinned or excepted by example CI. Local-development command wrappers and local paths are inventoried separately and do not fail the gate.
func OverridableServerFields ¶
func OverridableServerFields() []string
OverridableServerFields returns a copy of the allowlist, sorted.
func ParseSecretRefKey ¶
ParseSecretRefKey splits a secret:<provider>/<path> key. The path may contain slashes.
func PolicyMatchLiteral ¶
PolicyMatchLiteral reports whether match contains none of the path.Match metacharacters `*`, `?`, and `[`. A literal must name a declared server. A glob is not checked against server names.
func ReadConfigEntry ¶
func ReadConfigEntry(ctx context.Context, cfg ConfigFile) (mode int64, uid, gid int, body []byte, err error)
ReadConfigEntry resolves mode, ownership, and bytes for one config entry. file entries are read here. The returned error does not include file contents; a read error is the wrapped OS error, whose text may include the path.
func ReferencedConfigFiles ¶
ReferencedConfigFiles returns absolute paths for file-backed config entries. Values that need variable expansion or a tilde are refused. Absolute paths are returned as written. Relative paths are joined to stackDir.
func RenderComposed ¶
RenderComposed returns the bytes WriteComposed would write, without I/O.
func ResetRunningVersion ¶
func ResetRunningVersion()
ResetRunningVersion clears the recorded version and the once-per-process skip warning. Tests call it from t.Cleanup. Requires checks share this process-wide state, so those tests must not run in parallel with each other.
func SecretRefKey ¶
SecretRefKey returns the index key for a provider and path.
func SetRunningVersion ¶
func SetRunningVersion(v string)
SetRunningVersion records the gridctl version used by requires.gridctl checks. cmd/gridctl calls it once from PersistentPreRunE with the ldflags version. The daemon child re-enters main, so that one call covers the controller. An empty value, "dev", or any string that is not a semver skips satisfaction checks after the constraint string is syntax-checked.
func SourceEqual ¶
SourceEqual reports whether two source declarations have the same effective configuration.
func SubstituteSecretRefs ¶
SubstituteSecretRefs rewrites ${secret:} tokens in every field expandStackVarsResolved covers. Missing keys stay literal. The walk matches the loader so a newly expandable field is substituted when it is indexed.
func SupportedLinkClientsForTest ¶
func SupportedLinkClientsForTest() []string
SupportedLinkClientsForTest exposes the copied slug list to the external parity test (links_parity_test.go), mirroring NormalizedClientModelKeyForTest. Not for production use.
func ValidateStackFile ¶
func ValidateStackFile(path string, opts ...LoadOption) (*Stack, *ValidationResult, error)
ValidateStackFile loads a stack file and validates it without deploying. Returns the parsed stack (for further use) and the validation result. Optional LoadOption values select or suppress an override file. The override is merged after decode and before environment expansion. This parser does not resolve extends, so an override that names a server only a parent declares is an error when the file has no extends and a warning when it does.
func VaultNeeds ¶
VaultNeeds reports why a stack cannot start against a locked variable store. The list is sorted and deduplicated, and empty when a locked store is enough.
It does not use UnresolvedRefs. ResolveVariable falls back to the process environment, secrets.sets is injected as an empty map when the store is locked, and credential_ref is left literal until clone time. Those three sites are invisible to an unresolved-ref check and still fail, or silently do nothing, once the service starts with a locked store.
func WriteComposed ¶
WriteComposed writes a provenance header and the marshaled stack. The marshal path is yaml.Marshal, the same one gridctl export uses, so explicit false values survive. The write is atomic. layers[0] is the base.
Types ¶
type A2AConfig ¶
type A2AConfig struct {
Card string `yaml:"card"`
Endpoint string `yaml:"endpoint,omitempty"`
Dialect string `yaml:"dialect,omitempty"`
Profile string `yaml:"profile,omitempty"`
Include []string `yaml:"include,omitempty"`
Timeout string `yaml:"timeout,omitempty"`
Auth *A2AAuth `yaml:"auth,omitempty"`
}
A2AConfig declares an experimental outbound Agent Card source.
type AuthConfig ¶
type AuthConfig struct {
// Type is the auth mechanism: "bearer", "api_key", or "oauth".
Type string `yaml:"type"`
// Token is the expected token value (supports env var references via $VAR or ${VAR}).
// Rejected when type is oauth.
Token string `yaml:"token,omitempty"`
// Header is the header name for api_key auth (default: "Authorization").
// Rejected when type is oauth.
Header string `yaml:"header,omitempty"`
// Issuer is the authorization server issuer URL. Required when type is oauth.
Issuer string `yaml:"issuer,omitempty"`
// Audience is the expected aud value. Required when type is oauth.
Audience string `yaml:"audience,omitempty"`
// JWKSURL skips discovery and uses this key set. Optional.
JWKSURL string `yaml:"jwks_url,omitempty"`
// RequiredScopes lists scopes that must be present on an accepted token.
RequiredScopes []string `yaml:"required_scopes,omitempty"`
// IdentityClaim is the top-level string claim used as the access identifier.
// Empty means "sub".
IdentityClaim string `yaml:"identity_claim,omitempty"`
}
AuthConfig configures gateway authentication. When configured, operational routes require a credential. bearer and api_key compare a shared secret. oauth validates issuer-minted JWT access tokens and does not store a gateway token.
func (*AuthConfig) Configured ¶
func (a *AuthConfig) Configured() bool
Configured reports whether inbound authentication is active. OAuth mode is configured when type is oauth, even though token is empty. bearer and api_key stay configured only when a token is set.
func (*AuthConfig) IdentityClaimOrDefault ¶
func (a *AuthConfig) IdentityClaimOrDefault() string
IdentityClaimOrDefault returns the configured identity claim, or "sub".
func (*AuthConfig) IssuerHost ¶
func (a *AuthConfig) IssuerHost() string
IssuerHost returns the issuer URL's host, including a port when one is present. The result has no scheme, path, query, or userinfo. It carries no credential.
type AutoscaleConfig ¶
type AutoscaleConfig struct {
// Min is the minimum number of healthy replicas to maintain.
// >= 0. Must be >= 1 when IdleToZero is false.
Min int `yaml:"min" json:"min"`
// Max is the upper bound on replica count. >= 1, >= Min, <= 32.
Max int `yaml:"max" json:"max"`
// TargetInFlight is the per-replica in-flight request count the scaler
// tries to hold the median at or below. >= 1.
TargetInFlight int `yaml:"target_in_flight" json:"target_in_flight"`
// ScaleUpAfter is how long the window median must exceed the target
// before spawning a replica. Default 30s. Minimum 10s.
ScaleUpAfter string `yaml:"scale_up_after,omitempty" json:"scale_up_after,omitempty"`
// ScaleDownAfter is how long the window median must be below the target
// before reaping a replica. Default 5m. Minimum 1m.
ScaleDownAfter string `yaml:"scale_down_after,omitempty" json:"scale_down_after,omitempty"`
// WarmPool keeps this many extra idle-ready replicas above the load-derived
// target at all times. Default 0. Must satisfy Min + WarmPool <= Max.
WarmPool int `yaml:"warm_pool,omitempty" json:"warm_pool,omitempty"`
// IdleToZero allows the scaler to reap every replica after a sustained
// idle. Min may be 0 only when IdleToZero is true. Default false.
IdleToZero bool `yaml:"idle_to_zero,omitempty" json:"idle_to_zero,omitempty"`
}
AutoscaleConfig controls reactive autoscaling of a ReplicaSet. All fields are optional at the YAML layer only in the sense that SetDefaults fills missing timings; Min, Max, and TargetInFlight are required for the block to validate.
func (*AutoscaleConfig) ResolvedScaleDownAfter ¶
func (a *AutoscaleConfig) ResolvedScaleDownAfter() time.Duration
ResolvedScaleDownAfter parses ScaleDownAfter; returns 5m when unset or invalid.
func (*AutoscaleConfig) ResolvedScaleUpAfter ¶
func (a *AutoscaleConfig) ResolvedScaleUpAfter() time.Duration
ResolvedScaleUpAfter parses ScaleUpAfter; returns 30s when unset or invalid.
type BuildAction ¶
type BuildAction struct {
Server string `json:"server"`
SourceType string `json:"sourceType"`
DeclaredIdentity BuildIdentity `json:"declaredIdentity"`
ResolvedIdentity BuildIdentity `json:"resolvedIdentity,omitempty"`
ImageTag string `json:"imageTag"`
Cached bool `json:"cached"`
CacheState string `json:"cacheState"`
Error string `json:"error,omitempty"`
MutableRef bool `json:"mutableRef,omitempty"`
GeneratedDockerfile string `json:"generatedDockerfile,omitempty"`
}
BuildAction describes the resolved image work associated with a source server. CLI and API planners may populate these after resolving external source identity; ComputePlan itself remains a pure config comparison.
type BuildIdentity ¶
type BuildIdentity struct {
Type string `json:"type"`
URL string `json:"url,omitempty"`
Ref string `json:"ref,omitempty"`
Path string `json:"path,omitempty"`
ProjectPath string `json:"projectPath,omitempty"`
Dockerfile string `json:"dockerfile,omitempty"`
Commit string `json:"commit,omitempty"`
Package string `json:"package,omitempty"`
Version string `json:"version,omitempty"`
Artifact string `json:"artifact,omitempty"`
ArtifactSHA256 string `json:"artifactSha256,omitempty"`
}
BuildIdentity is the non-secret source identity exposed by stack plans.
type ClientProfile ¶
type ClientProfile struct {
// Aliases are raw clientInfo.name values that should resolve to this
// profile, for reconciling a wire identity that differs from the profile
// key without relying on the built-in normalization heuristic.
Aliases []string `yaml:"aliases,omitempty"`
// Servers is an allow-list of MCP server names. Empty means all servers.
Servers []string `yaml:"servers,omitempty"`
// Tools is an allow-list of prefixed tool names. Empty means all tools
// within the allowed servers.
Tools []string `yaml:"tools,omitempty"`
}
ClientProfile is one client's tool access allow-list. Servers and Tools are both allow-lists; an empty Servers list means "all servers" and an empty Tools list means "all tools within the allowed servers". Tools are matched against the router's prefixed names (e.g. "github__search-repos").
type ClientsConfig ¶
type ClientsConfig struct {
// Default is the policy for clients that match no profile: "deny" (the
// default when empty) or "allow".
Default string `yaml:"default,omitempty"`
// Profiles maps a stable client identifier to its access allow-list.
Profiles map[string]ClientProfile `yaml:"profiles,omitempty"`
}
ClientsConfig is the optional top-level per-client access scoping block. Its presence opts a stack into NetworkPolicy semantics:
- Omitting the entire `clients:` block preserves legacy behavior — every connecting client sees every tool (Article IX back-compat).
- With the block present, a connecting client that matches a profile is restricted to that profile's allow-list; a client matching no profile is governed by Default ("deny" unless set to "allow").
The map key in Profiles is the stable client identifier assigned at `gridctl link` time, which is also the identifier shown in the UI and carried on the wire (the `client` query parameter / X-Gridctl-Client-Id header). It is reconciled with the connecting client's normalized identity, so the same string keys configuration, enforcement, and the Stack view.
Scope coverage for v1 is tools only: skills (served as MCP prompts) and resources remain globally visible. This is an explicit, documented decision; extending scope to prompts/resources is deferred.
type ConfigFile ¶
type ConfigFile struct {
Target string `yaml:"target" json:"target"`
File string `yaml:"file,omitempty" json:"file,omitempty"`
Content string `yaml:"content,omitempty" json:"content,omitempty"`
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
UID *int `yaml:"uid,omitempty" json:"uid,omitempty"`
GID *int `yaml:"gid,omitempty" json:"gid,omitempty"`
}
ConfigFile is one file materialized into a container server at create time.
type Consumer ¶
type Consumer struct {
Kind ReferenceKind `json:"kind"`
Name string `json:"name,omitempty"`
Field string `json:"field"`
Source string `json:"source,omitempty"`
// Target names the workload a scoped secrets.sets entry injects into, and
// TargetKind says whether that is a server or a resource. Both are set only
// on RefKindSecretsSet consumers built from a scoped set: one such consumer
// is synthesized per receiving workload, so the UI can name and navigate to
// each one. An unscoped set fans out to everything and produces a single
// consumer with both fields empty.
//
// Name keeps holding the set name in every case. Callers that ask "is this
// variable's own set actively injected" compare against Name, so widening
// that field to mean the workload would silently break them.
Target string `json:"target,omitempty"`
TargetKind ReferenceKind `json:"targetKind,omitempty"`
}
Consumer is a single site that references a variable: the kind of stack element, its name (server/resource/network name; empty for stack- and gateway-level sites), and the field where the reference appears.
Field mirrors the YAML key path the user actually wrote (e.g. "env.GITHUB_TOKEN", "image", "command[2]", "ssh.identityFile", "openapi.baseUrl") so it can be used verbatim to locate the reference in the stack file. Casing therefore tracks the schema's own YAML tags, which mix camelCase (identityFile, baseUrl) and snake_case (build_args, ssh_key_path).
func SetConsumersFor ¶
func SetConsumersFor(ref SecretSetRef, spec *Stack) []Consumer
SetConsumersFor returns the synthetic consumers contributed by one set ref.
type DeclarationDiagnostic ¶
type DeclarationDiagnostic struct {
Key string `json:"key"`
Code string `json:"code"`
Message string `json:"message"`
Consumers int `json:"consumers"`
}
DeclarationDiagnostic is one value-free advisory result.
func DiagnoseDeclarations ¶
func DiagnoseDeclarations(stack *Stack, records map[string]VariableMetadata, locked bool) []DeclarationDiagnostic
DiagnoseDeclarations compares declarations with available variable metadata.
type DependencyStatus ¶
type DependencyStatus struct {
Status string `json:"status"` // "resolved", "missing"
Missing []string `json:"missing,omitempty"`
}
DependencyStatus summarizes skill dependency resolution.
type DiffAction ¶
type DiffAction string
DiffAction describes what changed.
const ( DiffAdd DiffAction = "add" DiffRemove DiffAction = "remove" DiffChange DiffAction = "change" )
type DiffItem ¶
type DiffItem struct {
Action DiffAction `json:"action"`
Kind string `json:"kind"` // "mcp-server", "resource", "gateway", "network"
Name string `json:"name"`
Details []string `json:"details,omitempty"` // human-readable change descriptions
// Override is true when a changed detail comes from an override file.
Override bool `json:"override,omitempty"`
}
DiffItem represents a single change in the plan.
type DriftStatus ¶
type DriftStatus struct {
Status string `json:"status"` // "in-sync", "drifted", "unknown"
Added []string `json:"added,omitempty"`
Removed []string `json:"removed,omitempty"`
Changed []string `json:"changed,omitempty"`
}
DriftStatus summarizes drift between spec and running state.
type ExecutionConfig ¶
type ExecutionConfig = execution.ExecutionConfig
type ExecutionContract ¶
type ExecutionContract = execution.ExecutionContract
func ResolveExecution ¶
func ResolveExecution(server MCPServer) (*ExecutionContract, error)
ResolveExecution validates execution against the final server configuration.
type ExecutionMount ¶
type ExecutionMount = execution.ExecutionMount
type ExecutionTmpfs ¶
type ExecutionTmpfs = execution.ExecutionTmpfs
type GatewayConfig ¶
type GatewayConfig struct {
// Name overrides the identity the gateway announces to MCP clients in the
// initialize response (serverInfo.name). Some clients (VS Code / GitHub
// Copilot) display this value rather than the entry key from their own
// config file, so distinct gateways need distinct names to be told apart.
// Empty keeps the default "gridctl-gateway".
Name string `yaml:"name,omitempty" json:"name,omitempty"`
// AllowedOrigins lists origins for CORS. On a loopback bind, empty
// defaults to ["*"]. A non-loopback bind requires an explicit list that
// does not contain "*", or the insecure override. "*" is not an allowlist.
AllowedOrigins []string `yaml:"allowed_origins,omitempty"`
// Bind is the address the gateway's HTTP listener binds. When not set,
// defaults to 127.0.0.1 (loopback only), so the API, web UI, and gateway
// are unreachable from other hosts. Set "0.0.0.0" to listen on every
// interface; the --bind and --bind-all flags override this field.
// gridctl refuses to start on a widened bind without auth and an origin
// allowlist unless the insecure override is set.
Bind string `yaml:"bind,omitempty"`
// InsecureAllowUnauthenticated permits a non-loopback bind without auth
// and without an explicit origin allowlist. One override covers both
// refusals. Without it gridctl refuses to start in either combination.
// Exists alongside the --insecure-allow-unauthenticated flag because a
// flag can be dropped by whatever wraps the process; a config field
// survives that.
InsecureAllowUnauthenticated bool `yaml:"insecure_allow_unauthenticated,omitempty"`
// Description is an optional Server Card description, 1 to 100 characters
// when set. Unset keeps the generated default. Read only by the card builder.
Description string `yaml:"description,omitempty"`
// PublicURL is the absolute http(s) origin the Server Card advertises,
// with an optional port and path prefix and no userinfo, query, or
// fragment. Unset leaves the card to a trusted Host, or omits remotes.
// Read only by the card builder.
PublicURL string `yaml:"public_url,omitempty"`
// AllowedHosts lists additional Host header values accepted on the MCP
// endpoint when a request arrives over loopback. Loopback hosts
// (localhost, 127.0.0.0/8, ::1) are always accepted, so the default of
// unset means loopback-only and needs no configuration. Set this only
// when a reverse proxy or container hostname fronts the gateway.
AllowedHosts []string `yaml:"allowed_hosts,omitempty"`
Auth *AuthConfig `yaml:"auth,omitempty"`
// ToolDiscovery controls whether tools/list returns the full catalog
// (full, the default) or search_tools, call_tool, and the pinned set
// (deferred). A nil block preserves today's behavior.
ToolDiscovery *ToolDiscoveryConfig `yaml:"tool_discovery,omitempty" json:"tool_discovery,omitempty"`
// CodeMode controls whether the gateway replaces individual tool definitions
// with two meta-tools (search + execute). Values: "off" (default), "on".
CodeMode string `yaml:"code_mode,omitempty"`
// CodeModeTimeout is the execution timeout in seconds (default: 30).
CodeModeTimeout int `yaml:"code_mode_timeout,omitempty"`
// OutputFormat sets the default output format for tool call results.
// Values: "json" (default), "toon", "csv", "text".
// Per-server output_format overrides this value.
OutputFormat string `yaml:"output_format,omitempty"`
// MaxToolResultBytes sets the maximum size of a tool result in bytes before truncation.
// Results exceeding this limit are truncated with a suffix indicating the original size.
// Default: 65536 (64KB). Set to 0 to use the default.
MaxToolResultBytes int `yaml:"maxToolResultBytes,omitempty" json:"maxToolResultBytes,omitempty"`
// Tracing configures distributed tracing. When nil, tracing is enabled with defaults.
// The block, including headers, is read at startup. A change requires a restart.
Tracing *TracingConfig `yaml:"tracing,omitempty" json:"tracing,omitempty"`
// Metrics configures optional OTLP metrics export. When nil, no metrics are exported.
// The block is read at startup, same as tracing. A change requires a restart.
Metrics *MetricsConfig `yaml:"metrics,omitempty" json:"metrics,omitempty"`
// Security configures security features such as schema pinning. When nil, defaults apply.
Security *GatewaySecurityConfig `yaml:"security,omitempty" json:"security,omitempty"`
// Tokenizer selects the token counting strategy.
// Values: "embedded" (default) uses the cl100k_base BPE vocabulary (pure Go, no network).
// "api" uses Anthropic's count_tokens endpoint for exact counts — Anthropic-specific,
// requires network access and an API key, wrong for non-Anthropic model routing.
Tokenizer string `yaml:"tokenizer,omitempty"`
// TokenizerAPIKey overrides ANTHROPIC_API_KEY for the api tokenizer mode.
// When unset, the api tokenizer falls back to the ANTHROPIC_API_KEY environment variable.
TokenizerAPIKey string `yaml:"tokenizer_api_key,omitempty"`
}
GatewayConfig holds optional gateway-level configuration.
type GatewaySecurityConfig ¶
type GatewaySecurityConfig struct {
// SchemaPinning configures TOFU schema pinning for MCP tool definitions.
SchemaPinning *SchemaPinningConfig `yaml:"schema_pinning,omitempty" json:"schema_pinning,omitempty"`
}
GatewaySecurityConfig holds gateway-level security settings.
type GroupConfig ¶
type GroupConfig struct {
Description string `yaml:"description,omitempty" json:"description,omitempty"`
// Servers includes every tool of the named stack servers.
Servers []string `yaml:"servers,omitempty" json:"servers,omitempty"`
// Tools includes specific prefixed tool names ("github__create_issue").
Tools []string `yaml:"tools,omitempty" json:"tools,omitempty"`
// Exclude subtracts prefixed tool names, applied after inclusion.
Exclude []string `yaml:"exclude,omitempty" json:"exclude,omitempty"`
// Overrides customizes individual member tools, keyed by canonical
// prefixed name. Renames and rewrites exist only at this group's
// exposure boundary; dispatch, scoping, limits, pins, and telemetry
// always operate on canonical names.
Overrides map[string]GroupOverride `yaml:"overrides,omitempty" json:"overrides,omitempty"`
}
GroupConfig is one entry of the optional top-level `groups:` block: a named cross-server tool bundle served at its own MCP endpoint (/groups/{name}/mcp). Groups are the curation axis; per-client scoping (`clients:`) remains the access axis and still applies on group sessions. Membership resolves as: all tools of Servers, plus Tools, minus Exclude (exclusion always last). Omitting the whole block preserves legacy behavior (Article IX): no group endpoints exist and /mcp is unchanged.
type GroupOverride ¶
type GroupOverride struct {
// Name renames the tool at the exposure boundary (a flat alias, no
// "__"). The canonical name still routes and is still accepted on call.
Name string `yaml:"name,omitempty" json:"name,omitempty"`
// Description replaces the tool's description verbatim. Empty keeps
// the original.
Description string `yaml:"description,omitempty" json:"description,omitempty"`
ReadOnlyHint *bool `yaml:"read_only_hint,omitempty" json:"read_only_hint,omitempty"`
DestructiveHint *bool `yaml:"destructive_hint,omitempty" json:"destructive_hint,omitempty"`
IdempotentHint *bool `yaml:"idempotent_hint,omitempty" json:"idempotent_hint,omitempty"`
OpenWorldHint *bool `yaml:"open_world_hint,omitempty" json:"open_world_hint,omitempty"`
}
GroupOverride customizes one member tool of a group. Hint fields are pointers: nil passes the downstream server's own annotation through, a set value overrides it. An operator-set hint is the operator vouching for the tool's behavior to clients that consume annotations.
type IssueSeverity ¶
type IssueSeverity string
IssueSeverity represents the severity level of a validation issue.
const ( SeverityError IssueSeverity = "error" SeverityWarning IssueSeverity = "warning" SeverityInfo IssueSeverity = "info" )
type Layer ¶
type Layer struct {
Pack string `json:"pack"`
Commit string `json:"commit"`
Path string `json:"file"`
Dir string `json:"-"`
Stack *Stack `json:"-"`
}
Layer is one input to Compose. Dir is the checkout directory and Stack is the decoded document; neither is safe to encode (a plan DTO carries pack, commit, and file only).
type LimitsConfig ¶
type LimitsConfig struct {
RateLimits []RateLimit `yaml:"rate_limits,omitempty" json:"rate_limits,omitempty"`
}
LimitsConfig is the optional top-level `limits:` block: declarative rate limits enforced on the tool-call dispatch path. Omitting the block preserves legacy behavior — nothing is ever limited (Article IX).
Entries scope to exactly one of client, server, or tool. The client key is the stable client identifier used by clients.profiles; server is the stack server name; tool is the router's prefixed name ("github__search_code").
type LinkEntry ¶
type LinkEntry struct {
Client string `yaml:"client" json:"client"`
Group string `yaml:"group,omitempty" json:"group,omitempty"`
ClientID string `yaml:"client_id,omitempty" json:"client_id,omitempty"`
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Discovery string `yaml:"discovery,omitempty" json:"discovery,omitempty"`
}
LinkEntry is one declared client connection in the optional top-level `link:` block. The block lists LLM clients that `gridctl apply` should link to this stack's gateway once it is healthy. Reconciliation is additive and idempotent: declared clients are linked if installed, already-linked clients are a no-op, and removing an entry never unlinks anything (removal stays explicit via `gridctl unlink` or `gridctl destroy --unlink`). Omitting the block preserves legacy behavior: nothing is auto-linked.
An entry is either a bare client slug ("- claude-code") or a mapping:
link:
- claude
- client: cursor
group: dev # link the group endpoint; entry name defaults to gridctl-dev
client_id: cursor # stable identifier for per-client access scoping
name: gridctl # server entry name override in the client config
func (LinkEntry) EffectiveName ¶
EffectiveName resolves the server entry name this link writes into the client config: an explicit name wins, a group link defaults to "gridctl-<group>" (matching `gridctl link --group`), everything else uses "gridctl".
func (LinkEntry) IsShorthand ¶
IsShorthand reports whether the entry carries nothing beyond the client slug, so YAML emitters can round-trip it back to the scalar form.
type LoadOption ¶
type LoadOption func(*loadConfig)
LoadOption configures LoadStack behavior.
func RequireOverride ¶
func RequireOverride() LoadOption
RequireOverride makes a WithOverride path mandatory. An explicit --override flag uses this so a missing file fails the load.
func WithOverride ¶
func WithOverride(path string) LoadOption
WithOverride selects an override file instead of discovering stack.override.yaml beside the stack. A missing file is not an error unless RequireOverride is also set.
func WithQuietLoad ¶
func WithQuietLoad() LoadOption
WithQuietLoad suppresses optional variable hints for value-free callers.
func WithVault ¶
func WithVault(v VaultLookup) LoadOption
WithVault enables ${vault:KEY} resolution during stack loading.
func WithVaultSets ¶
func WithVaultSets(v VaultSetLookup) LoadOption
WithVaultSets enables secrets.sets injection during stack loading.
func WithoutOverride ¶
func WithoutOverride() LoadOption
WithoutOverride suppresses override discovery and merge.
type LoggingConfig ¶
type LoggingConfig struct {
// File is the path to the log file. When set, logs are written to both the
// in-memory ring buffer (web UI) and this file simultaneously.
File string `yaml:"file,omitempty" json:"file,omitempty"`
// MaxSizeMB is the maximum log file size in megabytes before rotation (default: 100).
MaxSizeMB int `yaml:"maxSizeMB,omitempty" json:"maxSizeMB,omitempty"`
// MaxAgeDays is the maximum number of days to retain old log files (default: 7).
MaxAgeDays int `yaml:"maxAgeDays,omitempty" json:"maxAgeDays,omitempty"`
// MaxBackups is the maximum number of compressed old log files to keep (default: 3).
MaxBackups int `yaml:"maxBackups,omitempty" json:"maxBackups,omitempty"`
}
LoggingConfig configures log file output with automatic rotation.
type MCPServer ¶
type MCPServer struct {
Execution *ExecutionConfig `yaml:"execution,omitempty" json:"execution,omitempty"`
Name string `yaml:"name"`
Image string `yaml:"image,omitempty"`
Source *Source `yaml:"source,omitempty"`
URL string `yaml:"url,omitempty"` // External server URL (no container)
Port int `yaml:"port,omitempty"` // For HTTP transport (container-based)
Transport string `yaml:"transport,omitempty"` // "http" (default), "stdio", or "sse"
Command []string `yaml:"command,omitempty"` // Override container command or remote command for SSH
Env map[string]string `yaml:"env,omitempty"`
BuildArgs map[string]string `yaml:"build_args,omitempty"`
Volumes []string `yaml:"volumes,omitempty"` // Container mounts: host:container[:mode]
Configs []ConfigFile `yaml:"configs,omitempty" json:"configs,omitempty"`
Network string `yaml:"network,omitempty"` // Network to join (for multi-network mode)
SSH *SSHConfig `yaml:"ssh,omitempty"` // SSH connection config for remote servers
OpenAPI *OpenAPIConfig `yaml:"openapi,omitempty"` // OpenAPI spec config for API-backed servers
A2A *A2AConfig `yaml:"a2a,omitempty"` // Experimental outbound Agent Card source
Tools []string `yaml:"tools,omitempty"` // Tool whitelist (empty = all tools exposed)
OutputFormat string `yaml:"output_format,omitempty"` // Output format override: "json", "toon", "csv", "text"
PinSchemas *bool `yaml:"pin_schemas,omitempty"` // Override gateway schema pinning for this server (nil = inherit)
// ReadyTimeout overrides the HTTP/SSE readiness wait for container-based servers.
// Accepts any time.Duration string (e.g. "60s", "2m"). Empty/"0" inherits the gateway default (30s).
// Ignored for stdio, local process, SSH, OpenAPI, and external transports.
ReadyTimeout string `yaml:"ready_timeout,omitempty"`
// PingTimeout overrides the per-ping deadline used by the gateway health monitor.
// Accepts any time.Duration string (e.g. "10s"). Empty/"0" inherits DefaultPingTimeout (5s).
// Tune this for slow upstreams (e.g. HTTP servers with many tools) where the
// 5s default can flake under autoscale spawn load.
PingTimeout string `yaml:"ping_timeout,omitempty"`
// Restart controls whether the health monitor restarts a managed stdio
// container that inspect reports as not running. Empty means always.
// on-failure:N requires N from 1 through 4294967295.
// Accepted and unused on non-container servers.
Restart string `yaml:"restart,omitempty" json:"restart,omitempty"`
// ProtocolGeneration overrides MCP protocol-generation resolution for
// this server: "auto" (default, same as empty) probes server/discover
// and falls back to the initialize handshake; "handshake" and
// "stateless" skip the probe and force one generation. An escape
// hatch for peers the probe misclassifies; absent means today's
// auto-negotiation exactly.
ProtocolGeneration string `yaml:"protocol_generation,omitempty"`
// ProtocolExtensions declares client extensions the gateway sends on
// its downstream initialize. The only accepted value is
// "io.modelcontextprotocol/ui". Empty preserves today's handshake.
ProtocolExtensions []string `yaml:"protocol_extensions,omitempty"`
// Replicas is the number of independent processes to spawn for this server.
// Defaults to 1. Values >1 load-balance JSON-RPC tool calls across replicas
// using ReplicaPolicy. Not supported for external URL or OpenAPI transports.
Replicas int `yaml:"replicas,omitempty" json:"replicas,omitempty"`
// ReplicaPolicy selects the dispatch policy when Replicas > 1.
// Valid values: "round-robin" (default), "least-connections".
ReplicaPolicy string `yaml:"replica_policy,omitempty" json:"replica_policy,omitempty"`
// Autoscale, when set, replaces the static Replicas count with reactive
// autoscaling bounded by Min and Max. Mutually exclusive with Replicas.
// Not supported on external URL or OpenAPI transports.
Autoscale *AutoscaleConfig `yaml:"autoscale,omitempty" json:"autoscale,omitempty"`
// Telemetry, when set, overrides stack-global telemetry persistence for
// this server. nil fields inherit; *bool fields explicitly opt in or out.
Telemetry *MCPServerTelemetry `yaml:"telemetry,omitempty" json:"telemetry,omitempty"`
// Auth configures downstream authentication for external URL servers:
// a static bearer token, a static custom header, or OAuth 2.1 brokering
// handled by the gateway. nil (the default) preserves the existing
// unauthenticated behavior. Only valid on external URL servers.
Auth *ServerAuth `yaml:"auth,omitempty" json:"auth,omitempty"`
// Headers are extra HTTP headers sent on every downstream request for
// external URL and OpenAPI servers. Absent or empty preserves today's
// behavior. Values are treated as sensitive.
Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
// Description is an operator note. It is accepted on every server kind,
// preserved by export, and shown in status JSON. It is not a credential.
Description string `yaml:"description,omitempty" json:"description,omitempty"`
// Enabled controls whether this server is started and registered.
// Nil and true are equivalent. False parks the server: it is still
// validated, but it is not built, started, registered, health-checked,
// or pinned. Absent preserves today's behavior (Article IX).
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
}
MCPServer defines an MCP server (container-based or external).
func DecodeMCPServer ¶
DecodeMCPServer decodes one server snippet with the same strict rules.
func (*MCPServer) IsA2A ¶
IsA2A reports whether this is an outbound A2A source without another source.
func (*MCPServer) IsContainerBased ¶
IsContainerBased returns true if this MCP server requires a container runtime.
func (*MCPServer) IsEnabled ¶
IsEnabled reports whether the server should be started and registered. A nil receiver and a nil Enabled pointer are enabled.
func (*MCPServer) IsExternal ¶
IsExternal returns true if this is an external MCP server (URL-only, no container).
func (*MCPServer) IsLocalProcess ¶
IsLocalProcess returns true if this is a local process MCP server (command-only, no container).
func (*MCPServer) IsSSH ¶
IsSSH returns true if this is an SSH-based MCP server (ssh config with command).
func (*MCPServer) PersistLogs ¶
PersistLogs reports whether log persistence is effectively enabled for this server. An explicit per-server *bool override wins; otherwise the stack- global default is returned. Returns false when both stack and server are nil.
func (*MCPServer) PersistMetrics ¶
PersistMetrics — see PersistLogs for inheritance semantics.
func (*MCPServer) PersistTraces ¶
PersistTraces — see PersistLogs for inheritance semantics.
func (*MCPServer) ResolvedPingTimeout ¶
ResolvedPingTimeout parses PingTimeout; returns 0 when unset or invalid so the gateway falls back to DefaultPingTimeout (5s).
func (*MCPServer) ResolvedReadyTimeout ¶
ResolvedReadyTimeout parses ReadyTimeout; returns 0 when unset or invalid so the gateway falls back to its default.
func (*MCPServer) ResolvedRestartPolicy ¶
func (s *MCPServer) ResolvedRestartPolicy() RestartPolicy
ResolvedRestartPolicy parses Restart. An empty value is always. Invalid values return Mode "" so validation can reject them; callers that already passed validation can treat Mode "" as unset.
type MCPServerPersistence ¶
type MCPServerPersistence struct {
Logs *bool `yaml:"logs,omitempty" json:"logs,omitempty"`
Metrics *bool `yaml:"metrics,omitempty" json:"metrics,omitempty"`
Traces *bool `yaml:"traces,omitempty" json:"traces,omitempty"`
}
MCPServerPersistence is the *bool tri-state mirror of TelemetryPersistence.
type MCPServerTelemetry ¶
type MCPServerTelemetry struct {
Persist MCPServerPersistence `yaml:"persist,omitempty" json:"persist,omitempty"`
}
MCPServerTelemetry holds per-server telemetry persistence overrides. Each *bool field uses tri-state semantics: nil = inherit stack-global, &true = explicitly persist, &false = explicitly do not persist (overrides stack global). Never default these to &false in SetDefaults — that would collapse inherit and explicit-off into the same value.
type MetricsConfig ¶
type MetricsConfig struct {
// OTLP is the HTTP/protobuf exporter. Required fields are validated when
// the block is present.
OTLP *OTLPMetricsConfig `yaml:"otlp,omitempty" json:"otlp,omitempty"`
}
MetricsConfig configures gateway metrics export.
type ModelPreferenceScope ¶
type ModelPreferenceScope struct {
// Rewrite opts the scope into projection rewrite: projected files
// carry the resolved preference, and affected skill projections are
// forced to copy channel (status names the reason). Default false =
// pure pass-through.
Rewrite bool `yaml:"rewrite,omitempty" json:"rewrite,omitempty"`
// Default applies where the author declared nothing.
Default string `yaml:"default,omitempty" json:"default,omitempty"`
// Overrides maps exact registry names (case-sensitive, no globs) to
// the preference applied regardless of the author's declaration.
// Unknown names warn at validate time but never error: the skill may
// arrive later via pack.
Overrides map[string]string `yaml:"overrides,omitempty" json:"overrides,omitempty"`
}
ModelPreferenceScope is one kind's model preference policy.
Resolution order: Overrides beats the author's declaration beats Default. Overrides apply in either direction (raising to a stronger model or lowering to a cheaper one). With Rewrite false (the default), the scope is surfacing-only: nothing on disk changes.
func (*ModelPreferenceScope) Compile ¶
func (s *ModelPreferenceScope) Compile() *registry.ModelPolicy
Compile converts one model_preferences scope into the policy form the projection engines consume. A nil scope compiles to a non-nil empty policy: on a loaded stack, an absent scope is a KNOWN absence (the documented off switch, reconciling rewritten projections back to pass-through), never the unknown-policy preserve state, which is reserved for call sites with no stack at all.
type ModelPreferencesConfig ¶
type ModelPreferencesConfig struct {
// Skills is the policy for skill projections (pkg/skillsync).
Skills *ModelPreferenceScope `yaml:"skills,omitempty" json:"skills,omitempty"`
// Agents is the policy for agent projections (pkg/agentsync).
Agents *ModelPreferenceScope `yaml:"agents,omitempty" json:"agents,omitempty"`
}
ModelPreferencesConfig is the optional top-level `model_preferences:` block. Each scope carries a projection-time model preference policy for its kind. A preference is a durable default the client may still override (env vars and per-invocation parameters outrank projected frontmatter); nothing here enforces, measures, or costs anything.
type OTLPMetricsConfig ¶
type OTLPMetricsConfig struct {
// Endpoint is the OTLP endpoint URL. Required when the block is present.
// A pathless URL is posted to /v1/metrics. Any other path is used as-is.
Endpoint string `yaml:"endpoint" json:"endpoint"`
// Headers are sent on the export request. Values expand and are redacted
// the same way as tracing headers.
Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
// Interval is how often the reader exports. Go duration string. Default 60s.
// Minimum 1s.
Interval string `yaml:"interval,omitempty" json:"interval,omitempty"`
// Timeout is the export timeout. Go duration string. Default 10s.
Timeout string `yaml:"timeout,omitempty" json:"timeout,omitempty"`
}
OTLPMetricsConfig is the gateway.metrics.otlp block. HTTP/protobuf only; there is no protocol field.
type OpenAPIAuth ¶
type OpenAPIAuth struct {
Type string `yaml:"type"` // "bearer", "header", "query", "oauth2", or "basic"
TokenEnv string `yaml:"tokenEnv,omitempty"` // Env var name containing bearer token (for type: bearer)
Header string `yaml:"header,omitempty"` // Header name (for type: header, e.g., "X-API-Key")
ValueEnv string `yaml:"valueEnv,omitempty"` // Env var name containing header value (for type: header or query)
// Query param auth (type: query)
ParamName string `yaml:"paramName,omitempty"` // Query parameter name (for type: query)
// OAuth2 client credentials (type: oauth2)
ClientIdEnv string `yaml:"clientIdEnv,omitempty"` // Env var name containing OAuth2 client ID
ClientSecretEnv string `yaml:"clientSecretEnv,omitempty"` // Env var name containing OAuth2 client secret
TokenUrl string `yaml:"tokenUrl,omitempty"` // OAuth2 token endpoint URL
Scopes []string `yaml:"scopes,omitempty"` // OAuth2 scopes to request
// Basic auth (type: basic)
UsernameEnv string `yaml:"usernameEnv,omitempty"` // Env var name containing username
PasswordEnv string `yaml:"passwordEnv,omitempty"` // Env var name containing password
}
OpenAPIAuth defines authentication for OpenAPI HTTP requests.
type OpenAPIConfig ¶
type OpenAPIConfig struct {
Spec string `yaml:"spec"` // URL or local file path to OpenAPI spec (JSON or YAML)
BaseURL string `yaml:"baseUrl,omitempty"` // Override the server URL from the spec
Auth *OpenAPIAuth `yaml:"auth,omitempty"` // Authentication configuration
TLS *OpenAPITLS `yaml:"tls,omitempty"` // TLS/mTLS configuration (transport-layer)
Operations *OperationsFilter `yaml:"operations,omitempty"` // Filter which operations become tools
}
OpenAPIConfig defines an MCP server backed by an OpenAPI specification. The spec is parsed and each operation becomes an MCP tool.
type OpenAPITLS ¶
type OpenAPITLS struct {
CertFile string `yaml:"certFile,omitempty"` // Client certificate file path (required for mTLS)
KeyFile string `yaml:"keyFile,omitempty"` // Client private key file path (required for mTLS)
CaFile string `yaml:"caFile,omitempty"` // Custom CA certificate file path
InsecureSkipVerify bool `yaml:"insecureSkipVerify,omitempty"` // Skip server certificate verification (dangerous)
}
OpenAPITLS defines TLS/mTLS configuration for OpenAPI HTTP connections. This is transport-layer config and can be combined with any auth type.
type OperationsFilter ¶
type OperationsFilter struct {
Include []string `yaml:"include,omitempty"` // Operation IDs to include (whitelist)
Exclude []string `yaml:"exclude,omitempty"` // Operation IDs to exclude (blacklist)
}
OperationsFilter defines which OpenAPI operations to include or exclude. Only one of Include or Exclude should be specified.
type Override ¶
type Override struct {
MCPServers map[string]ServerOverride `yaml:"mcp-servers"`
}
Override is the decoded override document. Only mcp-servers is allowed at the top level, and only the allowlisted server fields decode.
type OverrideSelection ¶
type OverrideSelection struct {
// Path is an explicit override file. Empty means discover
// stack.override.yaml beside the stack file.
Path string
// Suppress ignores every override, including a discovered sibling.
Suppress bool
// Required makes a missing explicit Path an error. A discovered
// sibling that is absent is never an error.
Required bool
}
OverrideSelection chooses which override file a parser merges.
type PlanDiff ¶
type PlanDiff struct {
HasChanges bool `json:"hasChanges"`
Items []DiffItem `json:"items"`
Summary string `json:"summary"`
VariableDiagnostics []DeclarationDiagnostic `json:"variableDiagnostics,omitempty"`
Builds []BuildAction `json:"builds,omitempty"`
// Override is the override file merged into the proposed stack.
Override string `json:"override,omitempty"`
}
PlanDiff is the complete diff between two stack specs.
func ComputePlan ¶
ComputePlan compares a new spec against the currently running spec and returns a structured diff.
type PolicyConfig ¶
type PolicyConfig struct {
// Default is the fate of a call matching no rule and not caught by
// block_destructive: "allow" (the default when empty) or "block".
Default string `yaml:"default,omitempty" json:"default,omitempty"`
// BlockDestructive denies tools whose downstream annotations set
// destructiveHint. It does not read group override hints. Default false.
BlockDestructive bool `yaml:"block_destructive,omitempty" json:"block_destructive,omitempty"`
// Rules are evaluated in order. The last matching rule wins.
Rules []PolicyRule `yaml:"rules,omitempty" json:"rules,omitempty"`
}
PolicyConfig is the optional top-level `policy:` block. Nil means the key was omitted. A non-nil value, including `policy: {}`, is a declared policy: zero rules, `default` allow, and `block_destructive` false change no dispatch outcome, but the block is still configured.
Default is "allow" (the Article IX default when empty) or "block". BlockDestructive denies a tool whose downstream annotations set destructiveHint, after explicit rules and before default. Rules are path.Match globs over the canonical prefixed name (`server__tool`); the last match wins. Group exposure renames are resolved before the gate, so rules never see an alias.
type PolicyRule ¶
type PolicyRule struct {
// Match is a path.Match glob over the canonical prefixed tool name,
// or a literal `server__tool` name.
Match string `yaml:"match" json:"match"`
// Action is "allow", "block", or "require_approval".
Action string `yaml:"action" json:"action"`
}
PolicyRule is one ordered match. Action is "allow", "block", or "require_approval". require_approval is parsed and reported as authored, and enforced as block until call approvals exist.
type RateLimit ¶
type RateLimit struct {
Client string `yaml:"client,omitempty" json:"client,omitempty"`
Server string `yaml:"server,omitempty" json:"server,omitempty"`
Tool string `yaml:"tool,omitempty" json:"tool,omitempty"`
// CallsPerMinute is the sustained rate. Must be positive.
CallsPerMinute int `yaml:"calls_per_minute" json:"calls_per_minute"`
// Burst is the bucket capacity; 0 selects the default.
Burst int `yaml:"burst,omitempty" json:"burst,omitempty"`
}
RateLimit is a token-bucket call rate for one scope. Burst is the bucket capacity: how many calls may land at once before the sustained rate applies. Zero means a default of max(5, calls_per_minute/6).
type ReferenceIndex ¶
ReferenceIndex maps a variable-store key to the consumers that reference it.
It is built by expandStackVars from the same grammar used for expansion (ExpandStringRefs), so it can never drift from what gridctl actually recognizes as a ${var:KEY}/${vault:KEY} reference. It carries only keys and reference-site metadata — never variable values — so it is safe to expose even while the vault is locked.
Scope:
- One-hop only: a variable referenced inside another variable's *value* is not followed. This is intentional — values live in the vault, outside the static stack, so resolving transitive references would require reading secrets at index time. v1 indexes only references written in the stack.
- Known gap: secrets injected via secrets.sets (see injectSetSecrets) are added to server env *after* expansion without ${var:KEY} syntax, so they are not recorded here. The usage API compensates by synthesizing RefKindSecretsSet consumers from vault set membership; the index itself stays explicit-references-only.
func BuildVariableUsage ¶
func BuildVariableUsage(spec *Stack, setMembers map[string][]string) (ReferenceIndex, bool)
BuildVariableUsage combines explicit references with synthetic set consumers. setMembers maps set names to value-free variable keys.
type ReferenceKind ¶
type ReferenceKind string
ReferenceKind identifies what kind of stack element references a variable.
const ( RefKindMCPServer ReferenceKind = "mcp-server" RefKindResource ReferenceKind = "resource" RefKindGateway ReferenceKind = "gateway" RefKindNetwork ReferenceKind = "network" RefKindStack ReferenceKind = "stack" // RefKindSecretsSet marks a synthetic consumer for a variable injected in // bulk through the stack's secrets.sets block (see injectSetSecrets). These // never appear in Stack.References — the API layer synthesizes them from // vault set membership so usage reporting covers injected keys too. RefKindSecretsSet ReferenceKind = "secrets-set" )
type ReplicaHealth ¶
type ReplicaHealth struct {
Execution *execution.Report `json:"execution,omitempty"`
ReplicaID int `json:"replicaId"`
State string `json:"state"` // "healthy" | "unhealthy" | "restarting"
InFlight int64 `json:"inFlight"`
UptimeSeconds int64 `json:"uptimeSeconds,omitempty"`
LastError string `json:"lastError,omitempty"`
NextRetrySeconds int64 `json:"nextRetrySeconds,omitempty"`
RestartAttempts uint32 `json:"restartAttempts,omitempty"`
PID int `json:"pid,omitempty"`
ContainerID string `json:"containerId,omitempty"`
RestartPolicy string `json:"restartPolicy,omitempty"`
RestartExhausted bool `json:"restartExhausted,omitempty"`
ContainerRestarts uint32 `json:"containerRestarts,omitempty"`
}
ReplicaHealth describes the live state of one replica in a server's ReplicaSet. Durations use seconds so the JSON representation does not depend on Go's time formatting.
type RequiresConfig ¶
type RequiresConfig struct {
// Gridctl is a semver constraint the running gridctl must satisfy.
// Empty means no constraint.
Gridctl string `yaml:"gridctl,omitempty" json:"gridctl,omitempty"`
}
RequiresConfig is the optional top-level requires block. Omitted means no constraint (Article IX). A booster fragment cannot carry it; the fragment allowlist rejects the key before decode.
type RequiresError ¶
type RequiresError struct {
Constraint string
Running string
// Floor is the highest >= clause that satisfies Constraint, with no v
// prefix. Empty when Constraint uses ||, or when no such clause exists.
Floor string
Syntax bool
}
RequiresError is a requires.gridctl failure. Syntax is true when the constraint string does not parse. Otherwise the running version does not satisfy Constraint. Error returns the stack validation message. Pack callers format their own text from the fields.
func (*RequiresError) Error ¶
func (e *RequiresError) Error() string
type ResolutionResult ¶
type ResolutionResult struct {
Value string
Verdict ResolutionVerdict
Error error
}
ResolutionResult carries a value only when resolution succeeded. Denied results include a typed error suitable for errors.As.
func ResolveVariable ¶
func ResolveVariable(store VaultLookup, name string) ResolutionResult
ResolveVariable applies store-first, environment-second precedence while denying internal credential keys without environment fallback.
type ResolutionVerdict ¶
type ResolutionVerdict string
ResolutionVerdict identifies where a variable lookup resolved.
const ( ResolutionStore ResolutionVerdict = "store" ResolutionEnvFallback ResolutionVerdict = "env_fallback" ResolutionUnset ResolutionVerdict = "unset" ResolutionDenied ResolutionVerdict = "denied" )
type Resolver ¶
Resolver looks up a variable by name. Returns value and whether it exists.
func EnvResolver ¶
func EnvResolver() Resolver
EnvResolver returns a resolver that checks os.LookupEnv.
func VaultResolver ¶
func VaultResolver(vault VaultLookup) Resolver
VaultResolver returns a resolver that checks vault first, then env.
type Resource ¶
type Resource struct {
Name string `yaml:"name"`
Image string `yaml:"image"`
Env map[string]string `yaml:"env,omitempty"`
Ports []string `yaml:"ports,omitempty"`
Volumes []string `yaml:"volumes,omitempty"`
Network string `yaml:"network,omitempty"` // Network to join (for multi-network mode)
// Enabled controls whether this resource is started. Nil and true are
// equivalent. False parks the resource: it is still validated, but it
// is not started. Absent preserves today's behavior (Article IX).
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
}
Resource defines a supporting container (database, cache, etc).
func DecodeResource ¶
DecodeResource decodes one resource snippet with the same strict rules.
type RestartPolicy ¶
RestartPolicy is the parsed restart: value. Max is zero when the policy does not bound monitor-initiated attempts. Raw is the canonical display form; empty input resolves to always.
type RetentionConfig ¶
type RetentionConfig struct {
MaxSizeMB int `yaml:"max_size_mb,omitempty" json:"max_size_mb,omitempty"`
MaxBackups int `yaml:"max_backups,omitempty" json:"max_backups,omitempty"`
MaxAgeDays int `yaml:"max_age_days,omitempty" json:"max_age_days,omitempty"`
}
RetentionConfig controls lumberjack rotation for persisted telemetry files. One block per stack — per-signal retention is intentionally out of scope at MVP. Defaults: 100MB / 5 backups / 7d. YAML tags use snake_case to match the AutoscaleConfig precedent for control-plane structs (LoggingConfig uses camelCase, but is closer to a runtime-rotation knob than a control-plane resource).
type RunsConfig ¶
type RunsConfig struct {
Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
OmitLabels bool `yaml:"omit_labels,omitempty" json:"omit_labels,omitempty"`
Retention *RunsRetention `yaml:"retention,omitempty" json:"retention,omitempty"`
}
RunsConfig enables metadata-only persisted records of returning tool dispatch attempts. Omitted (the default) leaves recording disabled and preserves existing stack behavior. Recording does not inherit tracing or metrics persistence switches.
type RunsRetention ¶
type RunsRetention struct {
MaxSizeMB int `yaml:"max_size_mb,omitempty" json:"max_size_mb,omitempty"`
MaxAgeDays int `yaml:"max_age_days,omitempty" json:"max_age_days,omitempty"`
}
RunsRetention is the finite age and total logical-byte budget for one stack's run records (active file plus rotated segments). Defaults apply only when recording is enabled.
type SSHConfig ¶
type SSHConfig struct {
Host string `yaml:"host"` // Required: hostname or IP address
User string `yaml:"user"` // Required: SSH username
Port int `yaml:"port,omitempty"` // Optional: SSH port (default 22)
IdentityFile string `yaml:"identityFile,omitempty"` // Optional: path to SSH private key
KnownHostsFile string `yaml:"knownHostsFile,omitempty"` // Optional: path to known_hosts file; enables StrictHostKeyChecking=yes
JumpHost string `yaml:"jumpHost,omitempty"` // Optional: bastion/jump host ([user@]host[:port])
}
SSHConfig defines SSH connection parameters for remote MCP servers.
type SchemaPinningConfig ¶
type SchemaPinningConfig struct {
// Enabled controls whether schema pinning is active. Default: true.
// A pointer so an omitted `enabled:` inherits the default-on behavior
// rather than YAML's zero value (false); set it explicitly to false to
// disable pinning for the whole stack.
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
// Action is the response when drift is detected: "warn" (default) or "block".
// warn: log a structured diff and continue serving.
// block: reject all tool calls from the drifted server until approved.
Action string `yaml:"action,omitempty" json:"action,omitempty"`
// Scan controls the poisoning heuristics run over tool definitions at
// pin and drift time. Default: true. Findings are always advisory; this
// toggle never affects hashing, drift detection, or the approve flow.
Scan *bool `yaml:"scan,omitempty" json:"scan,omitempty"`
// ScanIgnore suppresses scan findings by code (e.g. ["P004"]). Useful
// for silencing a heuristic that false-positives on a legitimate stack.
ScanIgnore []string `yaml:"scan_ignore,omitempty" json:"scan_ignore,omitempty"`
}
SchemaPinningConfig controls the schema pinning feature.
type SecretProvider ¶
type SecretProvider struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type"`
Command []string `yaml:"command,omitempty" json:"command,omitempty"`
Timeout string `yaml:"timeout,omitempty" json:"timeout,omitempty"`
TokenFile string `yaml:"token_file,omitempty" json:"token_file,omitempty"`
}
SecretProvider is one entry in secrets.providers. Resolution runs at apply and reload, not at load. token_file is a path, not a credential, and is not joined to the stack directory.
func (SecretProvider) ProviderTimeout ¶
func (p SecretProvider) ProviderTimeout() (time.Duration, error)
ProviderTimeout returns the configured timeout or the 10s default.
type SecretRef ¶
type SecretRef struct {
Provider string `yaml:"-" json:"-"`
Path string `yaml:"-" json:"-"`
Key string `yaml:"-" json:"-"`
}
SecretRef is one distinct ${secret:<provider>/<path>} site group. Key is secret:<provider>/<path> and matches the References index key.
type SecretSetRef ¶
type SecretSetRef struct {
Name string `yaml:"name" json:"name"`
Servers []string `yaml:"servers,omitempty" json:"servers,omitempty"`
Resources []string `yaml:"resources,omitempty" json:"resources,omitempty"`
// contains filtered or unexported fields
}
SecretSetRef is one entry in the `secrets.sets` block: a variable set whose members are injected into container environments at load time (see injectSetSecrets).
An entry is either a bare set name or a mapping that narrows which workloads receive the set:
secrets:
sets:
- shared # unscoped: injected into every server and resource
- name: github-creds # scoped: only the listed workloads receive it
servers: [github]
- name: db
resources: [postgres]
Scoping is opt-in and per entry (Article IX). An entry with neither servers nor resources keeps the historic fan-out, so a stack written before scoping existed behaves identically. Naming either list makes the entry scoped, and a scoped entry reaches only what it names: `servers: [github]` injects into the github server and into no resources at all. That is the least-privilege reading, and it keeps one rule ("scoped entries reach exactly what they name") rather than two axes with different defaults.
func (SecretSetRef) InjectsIntoResource ¶
func (r SecretSetRef) InjectsIntoResource(name string) bool
InjectsIntoResource reports whether this entry's secrets reach the named resource. Unscoped entries reach every resource.
func (SecretSetRef) InjectsIntoServer ¶
func (r SecretSetRef) InjectsIntoServer(name string) bool
InjectsIntoServer reports whether this entry's secrets reach the named MCP server. Unscoped entries reach every server.
func (SecretSetRef) IsShorthand ¶
func (r SecretSetRef) IsShorthand() bool
IsShorthand reports whether the entry carries nothing beyond the set name, so YAML emitters can round-trip it back to the scalar form.
func (SecretSetRef) MarshalJSON ¶
func (r SecretSetRef) MarshalJSON() ([]byte, error)
MarshalJSON retains explicit empty scopes instead of broadening delivery.
func (SecretSetRef) MarshalYAML ¶
func (r SecretSetRef) MarshalYAML() (any, error)
MarshalYAML emits the scalar shorthand for unscoped entries so a stack that was written as `- shared` survives a load/save cycle unchanged. Scoped entries marshal as mappings, keeping an explicitly empty scope explicit.
func (SecretSetRef) Scoped ¶
func (r SecretSetRef) Scoped() bool
Scoped reports whether the entry narrows injection to named workloads. Unscoped entries fan out to every server and resource. An entry that declared an empty scope is scoped (to nothing), not unscoped.
func (*SecretSetRef) UnmarshalJSON ¶
func (r *SecretSetRef) UnmarshalJSON(data []byte) error
UnmarshalJSON preserves explicit scope presence in exported JSON.
func (*SecretSetRef) UnmarshalYAML ¶
func (r *SecretSetRef) UnmarshalYAML(value *yaml.Node) error
UnmarshalYAML accepts the scalar shorthand ("- shared") or the mapping form. Any other node kind is rejected so a stray nested sequence fails loudly instead of decoding to an empty entry. Mirrors LinkEntry, with the addition of unknown-key rejection because a dropped key here fails open.
type Secrets ¶
type Secrets struct {
Sets []SecretSetRef `yaml:"sets,omitempty" json:"sets,omitempty"`
Providers []SecretProvider `yaml:"providers,omitempty" json:"providers,omitempty"`
}
Secrets configures automatic secret injection from variable sets and optional external secret providers. Omitting providers changes nothing. Each set entry is a set name (fan-out to every workload) or a mapping that scopes the set to named servers and resources. See SecretSetRef.
type ServerAuth ¶
type ServerAuth struct {
Type string `yaml:"type"` // "bearer", "header", or "oauth"
// Static bearer token (type: bearer). Sent as "Authorization: Bearer <token>".
// Use ${VAR} or ${var:KEY} references rather than literal secrets.
Token string `yaml:"token,omitempty"`
// Static header (type: header).
Header string `yaml:"header,omitempty"` // header name, e.g. "X-API-Key"
Value string `yaml:"value,omitempty"` // header value; use ${VAR} references
// OAuth 2.1 brokering (type: oauth). All fields optional: scopes default
// to what the server advertises, and a pre-registered client_id (plus
// client_secret when the provider issued one) bypasses dynamic client
// registration for authorization servers that do not support it.
Scopes []string `yaml:"scopes,omitempty"`
ClientID string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
}
ServerAuth defines downstream authentication for an external URL MCP server. Type selects the behavior; the other fields belong to exactly one type.
type ServerOverride ¶
type ServerOverride struct {
Enabled *bool `yaml:"enabled"`
Env map[string]string `yaml:"env"`
Tools []string `yaml:"tools"`
Replicas *int `yaml:"replicas"`
Restart *string `yaml:"restart"`
PingTimeout *string `yaml:"ping_timeout"`
ReadyTimeout *string `yaml:"ready_timeout"`
OutputFormat *string `yaml:"output_format"`
Headers map[string]string `yaml:"headers"`
// contains filtered or unexported fields
}
ServerOverride is one server's overridable fields. Pointers and nil maps distinguish omission from an explicit value. Decoding uses KnownFields so any other key fails.
type SkillsPolicyConfig ¶
type SkillsPolicyConfig struct {
// Default is the fate of a skill matching neither list: "allow" (the
// default when empty) or "deny".
Default string `yaml:"default,omitempty" json:"default,omitempty"`
// Allow lists skill-name globs admitted even under default: deny.
Allow []string `yaml:"allow,omitempty" json:"allow,omitempty"`
// Deny lists skill-name globs hidden from exposure; deny beats allow.
Deny []string `yaml:"deny,omitempty" json:"deny,omitempty"`
}
SkillsPolicyConfig is the optional top-level `skills:` block: a global exposure policy for registry skills, filtering which skills the gateway serves via prompts/resources and which the daemon projects into client skill directories. Omitting the block preserves legacy behavior — every active skill is exposed (Article IX).
Allow and Deny are skill-name globs (path.Match syntax). A Deny match always wins, then an Allow match admits, then Default decides ("deny" denies; anything else, including omitted, allows). Denial filters exposure only: denied skills keep their registry state, stay visible in the registry API and UI flagged with the matching rule, and `gridctl apply` warns for every active skill the policy hides.
The policy is global by design; per-client skill scoping remains the documented v1 deferral on ClientsConfig. Distinct from the "skill sources" config in ~/.gridctl/skills.yaml (pkg/skills.SkillsConfig), which declares where git-imported skills come from, not what is exposed.
type Source ¶
type Source struct {
Type string `yaml:"type"` // "git", "local", or "pypi"
URL string `yaml:"url,omitempty"`
Ref string `yaml:"ref,omitempty"`
Path string `yaml:"path,omitempty"`
ProjectPath string `yaml:"project_path,omitempty"`
Dockerfile string `yaml:"dockerfile,omitempty"`
Runtime string `yaml:"runtime,omitempty"`
Package string `yaml:"package,omitempty"`
Python string `yaml:"python,omitempty"`
Extras []string `yaml:"extras,omitempty"`
With []string `yaml:"with,omitempty"`
Packages []string `yaml:"packages,omitempty"`
Auth *SourceAuth `yaml:"auth,omitempty"`
}
Source defines how to build an MCP server from source code.
type SourceAuth ¶
type SourceAuth struct {
Method string `yaml:"method,omitempty"` // "", "none", "token", "ssh-agent", "ssh-key"
CredentialRef string `yaml:"credential_ref,omitempty"` // e.g. "${vault:GIT_TOKEN}" — resolved on every clone/fetch
SSHUser string `yaml:"ssh_user,omitempty"` // defaults to "git" when empty
SSHKeyPath string `yaml:"ssh_key_path,omitempty"` // required for method "ssh-key"
}
SourceAuth is the declarative auth block on an MCP server git source. Raw tokens must NOT appear here — use CredentialRef (e.g. "${vault:GIT_TOKEN}") which is resolved against the live vault at clone time. Never add a Token field to this struct: anything with a yaml tag here gets persisted to disk.
type SpecHealth ¶
type SpecHealth struct {
Validation ValidationStatus `json:"validation"`
Drift DriftStatus `json:"drift"`
Dependencies DependencyStatus `json:"dependencies"`
// Replicas reports live per-replica health for every server that has
// more than one replica registered. Servers with replicas <= 1 are
// omitted so the shape is backward compatible with single-replica
// deployments. Keyed by server name.
Replicas map[string][]ReplicaHealth `json:"replicas,omitempty"`
// Override is the override file active for this health check.
Override string `json:"override,omitempty"`
}
SpecHealth aggregates validation, drift, and dependency status.
type Stack ¶
type Stack struct {
Version string `yaml:"version"`
Name string `yaml:"name"`
Extends string `yaml:"extends,omitempty"` // Path to a parent stack file for composition
// Requires is an optional tool-version floor. Omitted means no
// constraint (Article IX). Both the parent and the child constraints
// apply across extends. Not accepted in an override file or a booster
// fragment.
Requires *RequiresConfig `yaml:"requires,omitempty" json:"requires,omitempty"`
Gateway *GatewayConfig `yaml:"gateway,omitempty"`
Logging *LoggingConfig `yaml:"logging,omitempty"`
Telemetry *TelemetryConfig `yaml:"telemetry,omitempty"` // Opt-in disk persistence for logs/metrics/traces
Runs *RunsConfig `yaml:"runs,omitempty"` // Opt-in metadata-only persisted dispatch records
Secrets *Secrets `yaml:"secrets,omitempty"` // Variable set references
Network Network `yaml:"network"` // Single network (simple mode)
Networks []Network `yaml:"networks,omitempty"` // Multiple networks (advanced mode)
MCPServers []MCPServer `yaml:"mcp-servers"`
Resources []Resource `yaml:"resources,omitempty"`
Clients *ClientsConfig `yaml:"clients,omitempty"` // Optional per-client access scoping (NetworkPolicy semantics)
Limits *LimitsConfig `yaml:"limits,omitempty" json:"limits,omitempty"` // Optional rate limits enforced at dispatch
// Policy is the optional top-level `policy:` block: ordered per-tool
// call rules enforced as a CallGate on every tools/call path. Omitting
// the block preserves legacy behavior: every listed tool is allowed
// (Article IX). An empty `policy: {}` is present and permissive
// (`default` allow, no rules) and still reports configured.
//
// Rules are evaluated in order and the last match wins. That differs
// from the `skills:` deny-then-allow order, so a later allow can carve
// an exception out of an earlier block. `block_destructive` applies
// only when no rule matched, and only to a tool whose downstream
// annotations set destructiveHint. `default` decides the rest ("block"
// denies; anything else, including omitted, allows).
//
// Not inherited across `extends` (matching clients/groups/limits/skills).
// Distinct from `gridctl validate --policy`, an offline declaration
// check that does not read this block.
Policy *PolicyConfig `yaml:"policy,omitempty" json:"policy,omitempty"`
Groups map[string]GroupConfig `yaml:"groups,omitempty" json:"groups,omitempty"` // Optional named tool bundles, each at /groups/{name}/mcp
Skills *SkillsPolicyConfig `yaml:"skills,omitempty" json:"skills,omitempty"` // Optional global skill exposure policy (allow/deny name globs)
// ModelPreferences is the optional top-level `model_preferences:`
// block: per-scope model preference defaults and overrides applied to
// skill and agent projections. Omitting the block preserves legacy
// behavior; projections are byte-identical pass-throughs (Article
// IX). Deliberately a sibling of Skills, never nested under it: the
// `skills:` block is gateway exposure policy, an unrelated domain.
// Not inherited across `extends` (matching clients/groups/limits).
ModelPreferences *ModelPreferencesConfig `yaml:"model_preferences,omitempty" json:"model_preferences,omitempty"`
// Link declares LLM clients that `gridctl apply` connects to this
// stack's gateway once it is healthy. See LinkEntry for entry forms and
// reconcile semantics. Empty (the default) preserves legacy behavior:
// linking stays a manual `gridctl link` step. Not inherited across
// `extends` (matching clients/groups/limits).
Link []LinkEntry `yaml:"link,omitempty" json:"link,omitempty"`
// Experimental enables registered experimental feature flags by name
// (see pkg/flags for the registry and lifecycle). Omitted (the default)
// enables nothing — Article IX by construction. Unknown, graduated, and
// removed names warn at validate and apply time but never block a
// deploy. Deliberately typed map[string]bool so YAML 1.1 boolean
// spellings (on/yes) decode as booleans.
Experimental map[string]bool `yaml:"experimental,omitempty" json:"experimental,omitempty"`
// Variables documents value-free prerequisites. Declarations are advisory
// and never participate in expansion or write to the variable store.
Variables map[string]VariableDeclaration `yaml:"variables,omitempty" json:"variables,omitempty"`
// References is the variable-usage index, derived during expandStackVars:
// which consumers reference each ${var:KEY}/${vault:KEY} key. Secret
// references are indexed under secret:<provider>/<path> as well. It is
// computed from the stack, not persisted with it. The yaml/json "-" tags
// keep it out of every existing serialization path. Nil until a stack is
// loaded/expanded.
References ReferenceIndex `yaml:"-" json:"-"`
// SecretRefs lists distinct ${secret:<provider>/<path>} references in
// first-seen order. Computed during expansion, never persisted. The
// reference text stays literal in the field until a later resolve pass.
SecretRefs []SecretRef `yaml:"-" json:"-"`
// UnresolvedRefs lists the ${var:KEY}/${vault:KEY} keys that the resolver
// used at expansion time could not satisfy and that carry no default
// operator, in first-seen order. It is the loader's own definition of
// "missing": a reference written as ${var:KEY:-fallback} resolves to its
// default and is deliberately absent here even though it still appears in
// References.
//
// The meaning depends on the resolver. LoadStack with a vault yields keys
// missing from vault and environment both, which is exactly what it refuses
// to deploy. ValidateStackFile expands with the environment alone, so its
// list is a superset that callers narrow by checking the vault themselves
// (see the drift endpoint). Computed, never persisted.
UnresolvedRefs []string `yaml:"-" json:"-"`
// Overrides records field names applied from an override file, keyed by
// server name. Computed during merge; never persisted.
Overrides map[string][]string `yaml:"-" json:"-"`
// OverridePath is the override file merged into this stack. Empty when
// no override was applied. Computed, never persisted.
OverridePath string `yaml:"-" json:"-"`
// DiscoveredOverride is an override file found beside an export source
// and not merged. ExportNotices reads it. Never persisted.
DiscoveredOverride string `yaml:"-" json:"-"`
// contains filtered or unexported fields
}
Stack represents the complete gridctl configuration.
func Compose ¶
Compose copies base and appends each fragment's servers, resources, and variables. Relative paths are rewritten against the layer checkout before the merge, because the composed file does not live beside any layer. A name already present is an error naming both owners. Pure: no stores, no expansion, no I/O.
func DecodeStack ¶
DecodeStack decodes user-authored stack YAML and rejects keys the schema does not declare. Empty input decodes to an empty stack, matching yaml.Unmarshal. Syntax errors are returned unchanged. Unknown keys and other type errors are ValidationErrors.
func ExportStack ¶
ExportStack reads an unresolved export projection and returns every source path for destination collision checks. It does not access stores or runtime values. A discovered override is not merged; ExportNotices names it.
func ExportWithOverride ¶
ExportWithOverride merges overridePath onto the unresolved projection after the extends read and before credential checks. It does not route through LoadStack, so authored references stay unresolved.
func LoadStack ¶
func LoadStack(path string, opts ...LoadOption) (*Stack, error)
LoadStack reads and parses a stack file.
func LoadStackData ¶
func LoadStackData(data []byte, path string, opts ...LoadOption) (*Stack, error)
LoadStackData runs the load pipeline on already-read stack bytes. path is the file those bytes belong to: extends and relative paths resolve against it. The pipeline is decode, extends, expand, defaults, relative paths, validate, then optional secret-set injection.
func ParseStackIndex ¶
ParseStackIndex parses typed stack YAML, resolves extends, and builds a value-free reference index without environment or store expansion.
func ReadUnresolved ¶
ReadUnresolved reads a stack the way ExportStack does, without discovering or merging an override and without expanding variables.
func ValidateFragment ¶
ValidateFragment rejects disallowed top-level keys, then decodes through the non-resolving export reader and checks export credentials. A fragment with no servers and no resources is an error. The path is included in error text; callers that want a repo-relative label should pass that label only when it is also the file to read, or rewrite the path in the message.
func (*Stack) ActiveMCPServers ¶
ActiveMCPServers returns enabled servers in declaration order.
func (*Stack) ActiveResources ¶
ActiveResources returns enabled resources in declaration order.
func (*Stack) Clone ¶
Clone returns a deep copy. Nil stays nil. A pointer to a zero value stays a non-nil pointer, and an empty slice stays distinct from a nil slice. Unexported fields are copied too. A nil stack returns nil.
func (*Stack) ContainerWorkloads ¶
ContainerWorkloads returns human-readable descriptions of enabled workloads that require a container runtime.
func (*Stack) ModelPolicies ¶
func (s *Stack) ModelPolicies() (skills, agents *registry.ModelPolicy)
ModelPolicies compiles the stack's model_preferences block into the per-scope policies for the skill and agent projection engines. A loaded stack always yields non-nil policies, block or no block: deleting the block is the same known-absent off switch as `rewrite: false`. Only a nil stack (no stack context at all) yields nil policies, which the engines treat as preserve-not-revert.
func (*Stack) NeedsContainerRuntime ¶
NeedsContainerRuntime returns true if the stack has enabled workloads requiring a container runtime. Disabled container servers and resources do not count: a stack whose only container workloads are parked demands no runtime and creates no network.
func (*Stack) NonContainerWorkloads ¶
NonContainerWorkloads returns human-readable descriptions of workloads that work without a container runtime.
func (*Stack) SetDefaults ¶
func (s *Stack) SetDefaults()
SetDefaults applies default values to the stack.
type TelemetryConfig ¶
type TelemetryConfig struct {
// Persist names which signals are written to disk by default. Per-server
// blocks can override individual signals.
Persist TelemetryPersistence `yaml:"persist,omitempty" json:"persist,omitempty"`
// Retention controls lumberjack rotation for every persisted signal file.
// SetDefaults fills sensible defaults when this block is omitted.
Retention *RetentionConfig `yaml:"retention,omitempty" json:"retention,omitempty"`
}
TelemetryConfig configures opt-in disk persistence for the three signals gridctl already captures (logs, metrics, traces). All fields are optional; when the block is omitted entirely, every signal stays ephemeral (today's behavior). Per-server overrides on MCPServer.Telemetry can flip individual signals on or off relative to these defaults.
Stack-global Persist fields are plain bool (binary on/off). Per-server MCPServerPersistence fields are *bool to express tri-state inheritance — see MCPServerTelemetry.
type TelemetryPersistence ¶
type TelemetryPersistence struct {
Logs bool `yaml:"logs,omitempty" json:"logs,omitempty"`
Metrics bool `yaml:"metrics,omitempty" json:"metrics,omitempty"`
Traces bool `yaml:"traces,omitempty" json:"traces,omitempty"`
}
TelemetryPersistence is the stack-global signal toggle. Stack-global is binary (a bool) — the per-server override carries the tri-state.
type ToolDiscoveryConfig ¶
type ToolDiscoveryConfig struct {
// Mode is "full" (default) or "deferred".
Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
// AlwaysExpose lists canonical server__tool names that stay on
// tools/list in deferred mode, after scope, group, and whitelist filters.
AlwaysExpose []string `yaml:"always_expose,omitempty" json:"always_expose,omitempty"`
}
ToolDiscoveryConfig is the gateway.tool_discovery block. A nil block, an empty mode, and mode full all mean today's tools/list behavior.
type TracingConfig ¶
type TracingConfig struct {
// Enabled controls whether tracing is active. Default: true.
// A pointer so an omitted `enabled:` inherits the default-on behavior
// rather than YAML's zero value (false); set it explicitly to false to
// disable tracing.
Enabled *bool `yaml:"enabled,omitempty" json:"enabled,omitempty"`
// Sampling is the head-based sampling rate [0.0, 1.0]. Default: 1.0.
Sampling float64 `yaml:"sampling,omitempty" json:"sampling,omitempty"`
// Retention is how long completed traces are kept in memory (e.g. "24h"). Default: "24h".
Retention string `yaml:"retention,omitempty" json:"retention,omitempty"`
// Export selects an exporter: "otlp" or "" (none).
Export string `yaml:"export,omitempty" json:"export,omitempty"`
// Endpoint is the OTLP endpoint URL (e.g. "http://localhost:4318").
// A pathless URL is posted to /v1/traces. Any other path is used as-is.
Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty"`
// Headers are sent on the OTLP trace export request. Values expand
// ${var:KEY} and ${secret:} and are registered for log redaction.
Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
// MaxTraces is the in-memory ring buffer capacity (number of traces). Default: 1000.
MaxTraces int `yaml:"max_traces,omitempty" json:"max_traces,omitempty"`
// IncludeInfra admits spans from non-gridctl instrumentation scopes (e.g.
// Docker SDK HTTP self-instrumentation) into the UI trace buffer. Default: false.
IncludeInfra bool `yaml:"include_infra,omitempty" json:"include_infra,omitempty"`
}
TracingConfig configures distributed tracing for the gateway.
type ValidationError ¶
ValidationError represents a configuration validation error.
func (ValidationError) Error ¶
func (e ValidationError) Error() string
func (ValidationError) ToIssue ¶
func (e ValidationError) ToIssue(severity IssueSeverity) ValidationIssue
ToIssue converts a validation error into an issue. Strict-decode messages that carry "(line N)" set Line.
type ValidationErrors ¶
type ValidationErrors []ValidationError
ValidationErrors is a collection of validation errors.
func (ValidationErrors) Error ¶
func (e ValidationErrors) Error() string
type ValidationIssue ¶
type ValidationIssue struct {
Field string `json:"field"`
Message string `json:"message"`
Severity IssueSeverity `json:"severity"`
// Line is the 1-based source line for strict-decode findings. Omitted
// when the checker cannot name a line.
Line int `json:"line,omitempty"`
}
ValidationIssue is a validation finding with severity level.
func DiagnoseMutableRefs ¶
func DiagnoseMutableRefs(stack *Stack) []ValidationIssue
DiagnoseMutableRefs inspects literal image and package selectors on an unexpanded stack. It performs no I/O, expansion, secret substitution, launcher execution, or rewriting.
type ValidationResult ¶
type ValidationResult struct {
Execution map[string]*execution.Report `json:"execution,omitempty"`
Valid bool `json:"valid"`
ErrorCount int `json:"errorCount"`
WarningCount int `json:"warningCount"`
Issues []ValidationIssue `json:"issues"`
// Override is the override file merged or discovered during validation.
Override string `json:"override,omitempty"`
}
ValidationResult holds the complete output of spec validation.
func ResultFromErrors ¶
func ResultFromErrors(errs ValidationErrors) *ValidationResult
ResultFromErrors builds a failed validation result from decode or validate errors.
func ValidateWithIssues ¶
func ValidateWithIssues(s *Stack) *ValidationResult
ValidateWithIssues runs full validation and returns structured issues with severity. This wraps the existing Validate() and adds warning-level checks.
type ValidationStatus ¶
type ValidationStatus struct {
Status string `json:"status"` // "valid", "warnings", "errors"
ErrorCount int `json:"errorCount"`
WarningCount int `json:"warningCount"`
}
ValidationStatus summarizes the spec validation state.
type VariableDeclaration ¶
type VariableDeclaration struct {
Required *bool `yaml:"required,omitempty" json:"required,omitempty"`
Secret *bool `yaml:"secret,omitempty" json:"secret,omitempty"`
Type string `yaml:"type,omitempty" json:"type,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Docs string `yaml:"docs,omitempty" json:"docs,omitempty"`
}
VariableDeclaration documents one stack or pack variable prerequisite. Pointer booleans distinguish an omitted default from an explicit value when declarations are merged through extends.
func (VariableDeclaration) IsRequired ¶
func (d VariableDeclaration) IsRequired() bool
IsRequired reports the declaration's effective required setting.
func (VariableDeclaration) IsSecret ¶
func (d VariableDeclaration) IsSecret() bool
IsSecret reports the declaration's effective sensitivity. Secret is the secure default when omitted.
func (VariableDeclaration) ValueType ¶
func (d VariableDeclaration) ValueType() string
ValueType reports the effective declared type.
type VariableMetadata ¶
type VariableMetadata struct {
Type string `json:"type"`
Secret bool `json:"secret"`
Deprecated string `json:"deprecated,omitempty"`
}
VariableMetadata is the value-free subset of a stored variable used by declaration diagnostics.
type VaultLookup ¶
VaultLookup is the interface the vault store must satisfy.
type VaultSecret ¶
VaultSecret is a minimal secret view for set lookups.
type VaultSetLookup ¶
type VaultSetLookup interface {
VaultLookup
GetSetSecrets(setName string) []VaultSecret
}
VaultSetLookup extends VaultLookup with set operations for secrets.sets support.