agentcfg

package
v1.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package agentcfg owns Harbor's agent-config control plane: a durable, identity-scoped, versioned desired-state registry where every edit to an agent's configuration (skills membership now; tool/MCP exposure and prompt layers as later consumers extend the envelope) is an immutable, content-addressed revision. The active configuration is a pointer to a revision; rollback is a repoint; diff is a server-side revision compare.

The seam (CLAUDE.md §4.4)

The Registry interface lives here; drivers live under internal/agentcfg/drivers/<driver>/; a factory + registry dispatches by name. The StateStore-backed driver reuses the §9 persistence triad for identity isolation, exactly as the governance tenant-override policy does — no new persistence subsystem.

Identity (CLAUDE.md §6)

Every record is scoped by the full (tenant, user, session) triple. The registry is KEYED by agent_id (the agent's registration identity), but agent_id is NEVER an isolation filter: the driver keys each agent's config under a synthetic identity whose tenant is the caller's verified tenant, so a tenant's config is invisible to another tenant.

Concurrent reuse (the concurrent-reuse contract)

A constructed Registry is a compiled artifact: immutable after construction and safe to share across N concurrent goroutines. Per-run state lives in ctx and the supplied arguments, never on the Registry.

Index

Constants

View Source
const (
	// EventTypeConfigRevised — emitted when a new agent-config revision is
	// written (any successful SetRevision, including the skills-control
	// consumer). Carries the agent id, the new + parent revision ids, the
	// content hash, and the author identity.
	EventTypeConfigRevised events.EventType = "agent.config.revised"

	// EventTypeConfigReverted — emitted when an admin rolls the active
	// pointer back to an existing revision. Carries the agent id, the
	// revision rolled back TO, the previously-active revision id, and the
	// author identity. Rollback never mutates a revision; the event marks
	// the active-pointer repoint.
	EventTypeConfigReverted events.EventType = "agent.config.reverted"

	// EventTypeMCPConnectionPaused — emitted when a tool-exposure edit newly
	// pauses an MCP server (the server is added to the active revision's
	// paused set). The transport stays warm — pause is projection-time, so
	// the server's tools are excluded from the next run and its App callbacks
	// are rejected against current state. Carries the agent id, the paused
	// server id, the recording revision id, and the author identity — never a
	// secret. Drives the operator-legible "paused by a system administrator"
	// overlay (the client renders the canonical event; it never reaches into
	// the App).
	EventTypeMCPConnectionPaused events.EventType = "mcp.connection.paused"

	// EventTypeMCPConnectionResumed — emitted when a tool-exposure edit newly
	// resumes an MCP server (the server is removed from the active revision's
	// paused set). Resume is an instant flag flip — no re-dial. Carries the
	// same operator-visible audit metadata as the paused event.
	EventTypeMCPConnectionResumed events.EventType = "mcp.connection.resumed"

	// EventTypeMCPConnectionPending — emitted when an admin add of a NEW MCP
	// server connection begins the attach lifecycle (dial → initialize →
	// discover → register). Marks the `pending` lifecycle transition before
	// the terminal added / failed / auth_required event. Carries the agent
	// id, the server name, and the author identity — never a secret.
	EventTypeMCPConnectionPending events.EventType = "mcp.connection.pending"

	// EventTypeMCPConnectionAdded — emitted when an admin add of a NEW MCP
	// server connection completes the attach lifecycle successfully: the
	// transport dialled, the initialize handshake succeeded, discovery ran,
	// and the server's tools were registered on the live catalog. Carries
	// the agent id, the server name, the recording revision id, and the
	// author identity — never a secret header / token / credential.
	EventTypeMCPConnectionAdded events.EventType = "mcp.connection.added"

	// EventTypeMCPConnectionFailed — emitted when an admin add of a NEW MCP
	// server connection FAILS at any attach step (unreachable, handshake /
	// version mismatch, malformed discovery). A half-attached server is NEVER
	// registered (fail loud, no silent drop). Carries the agent id, the
	// server name, and a SAFE failure reason — never a secret. No revision is
	// recorded for a failed add (the broken connection is not desired state).
	EventTypeMCPConnectionFailed events.EventType = "mcp.connection.failed"

	// EventTypeMCPConnectionAuthRequired — emitted when an admin add of a NEW
	// MCP server connection requires authorization: the attach parks on the
	// unified pause/resume primitive (the tool-side OAuth lineage) and a
	// resume completes the attach. Carries the agent id, the server name, the
	// recording revision id, the pause token, and the author identity — never
	// a secret / credential / auth code.
	EventTypeMCPConnectionAuthRequired events.EventType = "mcp.connection.auth_required"

	// EventTypeMCPConnectionRemoved — emitted when an admin removes a
	// runtime-added MCP server connection (agent_config.remove_mcp_connection):
	// a new revision drops the named descriptor and prunes that server's
	// tool-exposure residue. The physical teardown (deregister the server's
	// tools + close its transport) happens at the NEXT run's projection
	// boundary — this event marks the desired-state removal, not the transport
	// close. Carries the agent id, the removed server id, the recording
	// revision id, and the author identity — never a secret.
	EventTypeMCPConnectionRemoved events.EventType = "mcp.connection.removed"

	// EventTypeMCPDiscoveryOriginsSet — emitted when an admin FULL-REPLACES a
	// runtime-added MCP connection's OAuth-discovery cross-origin allow-list
	// (agent_config.set_mcp_discovery_origins). Carries the agent id, the
	// connection id, the recording revision id, and the granted / revoked origin
	// deltas — all NON-SECRET (public https origins are an allow-list, never a
	// credential). This is the admin-scope audit event the write emits as one
	// fail-closed unit with the mutation (CLAUDE.md §7).
	EventTypeMCPDiscoveryOriginsSet events.EventType = "mcp.connection.discovery_origins_set"

	// EventTypeOAuthProviderInstalled — emitted when an admin installs (upserts)
	// a Protocol-installed OAuth provider (agent_config.set_oauth_provider): a
	// new revision records the ZERO-URL descriptor AND the provider is installed
	// live into the owner-tagged provider set. Carries the agent id, the provider
	// name, the credential-broker name, the recording revision id, and the author
	// identity — all NON-SECRET. NO URL, NO env-var name, NO secret is ever
	// carried (there is none on the descriptor). Emitted as one fail-closed unit
	// with the mutation (CLAUDE.md §7).
	EventTypeOAuthProviderInstalled events.EventType = "agent_config.oauth_provider.installed"

	// EventTypeOAuthProviderRemoved — emitted when an admin uninstalls a
	// Protocol-installed OAuth provider (agent_config.remove_oauth_provider): a
	// new revision drops the descriptor AND the provider is uninstalled live
	// (CLOSED). Carries the agent id, the provider name, the recording revision
	// id, and the author identity — all NON-SECRET. Emitted as one fail-closed
	// unit with the mutation.
	EventTypeOAuthProviderRemoved events.EventType = "agent_config.oauth_provider.removed"
)

agent-config canonical event types. Registered via init() so the canonical events registry stays the single source of truth (register at declaration time, publish at use time).

Both payloads are SafePayload (compose events.SafeSealed): the agent id, revision ids, content hash, and author identity are operator-visible audit metadata, never secret-shaped. The payload carries NO config content (no skill names, no prompt text) — only the revision identity — so the audit trail never leaks the desired-state body (CLAUDE.md §7).

View Source
const DefaultDriver = "statestore"

DefaultDriver is the production driver name. The StateStore-backed driver registers under it; it inherits the StateStore's own driver triad (in-mem / SQLite / Postgres) for identity isolation.

Variables

View Source
var (
	// ErrIdentityRequired — a method was called with an incomplete
	// identity triple or an empty agent id. Fails closed (CLAUDE.md §6).
	ErrIdentityRequired = errors.New("agentcfg: identity triple incomplete")
	// ErrInvalidConfig — a factory was called with a missing mandatory
	// dependency (a nil StateStore or EventBus).
	ErrInvalidConfig = errors.New("agentcfg: invalid configuration")
	// ErrUnknownDriver — Open was asked for a driver name no registered
	// factory handles.
	ErrUnknownDriver = errors.New("agentcfg: unknown driver")
	// ErrClosed — a method was called after Close.
	ErrClosed = errors.New("agentcfg: registry is closed")
	// ErrRevisionNotFound — Get / Diff / Rollback referenced a revision
	// id that has no record. Fails loud (CLAUDE.md §13 — no silent drop).
	ErrRevisionNotFound = errors.New("agentcfg: revision not found")
	// ErrStateUnavailable — a StateStore read/write failed.
	ErrStateUnavailable = errors.New("agentcfg: state store unavailable")
	// ErrInvalidPayload — the supplied ConfigPayload failed validation.
	ErrInvalidPayload = errors.New("agentcfg: invalid config payload")
	// ErrReservedUser — a user-scoped call carried a verified user id equal
	// to the reserved internal sentinel ("__agentcfg__"); fails closed so the
	// per-user key space can never alias onto the agent-level chain.
	ErrReservedUser = errors.New("agentcfg: user id collides with the reserved internal slot")
)

Sentinel errors. Callers compare via errors.Is.

Functions

func ContentHash

func ContentHash(p ConfigPayload) (string, error)

ContentHash computes the full hex-encoded SHA-256 over the canonical (sorted-key) JSON encoding of the normalised payload. Computing over a canonical form means an unrelated re-ordering of a set does not change the hash, and the idempotent re-set check is exact.

func Register

func Register(name string, factory Factory)

Register installs a driver factory under name. Drivers self-register from their package init(); the production driver aggregator blank-imports them. Re-registering the same name panics — the registration model is write-once-at-init.

func RegisteredDrivers

func RegisteredDrivers() []string

RegisteredDrivers returns a sorted list of registered driver names.

Types

type Config

type Config struct {
	// Driver names the registered factory. Empty → DefaultDriver.
	Driver string
}

Config selects the agentcfg driver. The StateStore-backed driver takes its persistence from Deps.State and ignores any DSN — the registry reuses the runtime's StateStore rather than opening its own.

type ConfigPayload

type ConfigPayload struct {
	PromptLayers   *PromptLayers          `json:"prompt_layers,omitempty"`
	ToolExposure   *ToolExposure          `json:"tool_exposure,omitempty"`
	Skills         *SkillsSelection       `json:"skills,omitempty"`
	Connections    *ConnectionsSection    `json:"connections,omitempty"`
	OAuthProviders *OAuthProvidersSection `json:"oauth_providers,omitempty"`
	LLMParams      *LLMParams             `json:"llm_params,omitempty"`
	Hooks          *HooksSection          `json:"hooks,omitempty"`
	Naming         *NamingSection         `json:"naming,omitempty"`
}

ConfigPayload is the forward-compatible config envelope. Every section is an optional pointer so later consumers extend the envelope without a schema break; only Skills is wired in the first wave.

func NormalizePayload

func NormalizePayload(p ConfigPayload) ConfigPayload

NormalizePayload returns a defensive, canonicalised copy of payload: the skills membership and the tool-exposure sets (paused servers, disabled tools) are sorted and de-duplicated so a re-ordering does not perturb the content hash and the stored form is stable. The prompt-layer section is copied verbatim (no nested mutation). It is exported so consumers (the skills + tool-exposure services) and the driver share one canonical form.

func (ConfigPayload) BasePrompt

func (p ConfigPayload) BasePrompt() (string, bool)

BasePrompt returns the agent's base prompt layer from a payload and whether it is set. A nil prompt-layer section or a nil Base returns ("", false). A convenience for the layered-prompt run-start projection.

func (ConfigPayload) ConnectionDescriptors

func (p ConfigPayload) ConnectionDescriptors() []MCPConnectionDescriptor

ConnectionDescriptors returns the agent's runtime-added MCP connection descriptors from a payload, or nil when the payload pins no connections section. A convenience for the add-connection consumer + the diff.

func (ConfigPayload) DisabledTools

func (p ConfigPayload) DisabledTools() []string

DisabledTools returns the agent's disabled tool set from a payload, or nil when the payload pins no tool-exposure section.

func (ConfigPayload) LLMParamsView

func (p ConfigPayload) LLMParamsView() (*LLMParams, bool)

LLMParamsView returns the agent's per-agent LLM-parameter section from a payload and whether it is set. A nil section returns (nil, false). The returned pointer is the payload's own (read-only) section — callers that mutate must copy first.

func (ConfigPayload) NamingView added in v1.12.0

func (p ConfigPayload) NamingView() (*NamingSection, bool)

NamingView returns the agent's session auto-naming section from a payload and whether it is set. A nil section returns (nil, false). The returned pointer is the payload's own (read-only) section — callers that mutate must copy first. A convenience for the auto-naming run-start projection.

func (ConfigPayload) OAuthProviderDescriptors added in v1.14.0

func (p ConfigPayload) OAuthProviderDescriptors() []OAuthProviderDescriptor

OAuthProviderDescriptors returns the installed OAuth-provider descriptors from a payload, or nil when the payload pins no OAuth-providers section. A convenience for the install/uninstall consumer, the reconcile leg, and the diff.

func (ConfigPayload) PausedServers

func (p ConfigPayload) PausedServers() []string

PausedServers returns the agent's paused MCP server set from a payload, or nil when the payload pins no tool-exposure section. A convenience for the tool-exposure consumer + the run-start projection.

func (ConfigPayload) RunCompletionHookView added in v1.10.0

func (p ConfigPayload) RunCompletionHookView() (*RunCompletionHook, bool)

RunCompletionHookView returns the agent's run-completion hook from a payload and whether it is set. A nil hooks section or a nil RunCompletion returns (nil, false). The returned pointer is the payload's own (read-only) section — callers that mutate must copy first. A convenience for the run-completion-hook run-start projection.

func (ConfigPayload) ServerLoadingModes added in v1.10.0

func (p ConfigPayload) ServerLoadingModes() map[string]string

ServerLoadingModes returns the agent's per-server loading-mode override map from a payload, or nil when the payload pins no tool-exposure section. A convenience for the tool-exposure consumer + the run-start projection.

func (ConfigPayload) SkillNames

func (p ConfigPayload) SkillNames() []string

SkillNames returns the agent's active skills membership from a payload, or nil when the payload pins no skills section. A convenience for the skills consumer.

func (ConfigPayload) ToolLoadingModes added in v1.10.0

func (p ConfigPayload) ToolLoadingModes() map[string]string

ToolLoadingModes returns the agent's per-tool loading-mode override map from a payload, or nil when the payload pins no tool-exposure section.

func (ConfigPayload) UserPrompt

func (p ConfigPayload) UserPrompt() (string, bool)

UserPrompt returns the agent's user prompt layer from a payload and whether it is set. A nil prompt-layer section or a nil User returns ("", false).

type ConfigRevertedPayload

type ConfigRevertedPayload struct {
	events.SafeSealed
	// Author is the identity that performed the rollback.
	Author identity.Quadruple
	// AgentID is the agent whose active pointer was repointed.
	AgentID string
	// RevisionID is the revision the active pointer now points to.
	RevisionID string
	// FromRevisionID is the previously-active revision id (empty when the
	// agent had no active pointer before the rollback).
	FromRevisionID string
	// OccurredAt is the rollback instant.
	OccurredAt time.Time
}

ConfigRevertedPayload is the typed payload for EventTypeConfigReverted. SafePayload — operator-visible audit metadata only.

type ConfigRevisedPayload

type ConfigRevisedPayload struct {
	events.SafeSealed
	// Author is the identity that wrote the revision.
	Author identity.Quadruple
	// AgentID is the agent whose config was revised (a registration
	// identity, NOT an isolation principal).
	AgentID string
	// RevisionID is the new revision's id.
	RevisionID string
	// ParentRevisionID is the revision the new one descends from (empty
	// for the first revision).
	ParentRevisionID string
	// ContentHash is the new revision's content hash (for diff/audit
	// correlation; never the content itself).
	ContentHash string
	// OccurredAt is the revision's creation instant.
	OccurredAt time.Time
}

ConfigRevisedPayload is the typed payload for EventTypeConfigRevised. SafePayload — every field is operator-visible audit metadata; no config content is carried.

type ConfigScope added in v1.6.0

type ConfigScope uint8

ConfigScope is the durable-config ownership discriminator. One Registry implementation serves two keyings: the admin/tenant durable config (keyed under a synthetic per-agent slot) and the per-user durable config variant (keyed under the caller's real (tenant, user) with the agent id as a key).

It is named with the ConfigScope prefix to disambiguate from the unrelated tools/auth.BindingScope constants (ScopeAgent / ScopeUser = OAuth token binding) and from the Protocol JWT scope auth.ScopeAgentConfigUser. The isolation tuple is never widened: the real user is the isolation principal for the user variant; the agent id stays a key, never a WHERE-clause isolation filter (RFC §6.16 / CLAUDE.md §6 clarifying note).

const (
	// ConfigScopeAgent is the admin/tenant durable config, keyed under the
	// synthetic per-agent identity slot and the agentcfg.* record kinds. The
	// default (zero value).
	ConfigScopeAgent ConfigScope = iota
	// ConfigScopeUser is the per-user durable config variant, keyed under the
	// caller's real (tenant, user) with the agent id in the session slot and a
	// DISTINCT agentcfg.user.* record-kind prefix. The distinct prefix is the
	// structural guarantee the two key spaces can never alias.
	ConfigScopeUser
)

type ConnectionsDiff

type ConnectionsDiff struct {
	// Added are the connection names present in the to-revision but not the
	// from-revision.
	Added []string
	// Removed are the connection names present in the from-revision but not
	// the to-revision.
	Removed []string
}

ConnectionsDiff is the structured set-diff of the runtime-added MCP connection descriptors across two revisions, by name. Deterministic: every slice is sorted.

func DiffConnections

func DiffConnections(from, to ConfigPayload) ConnectionsDiff

DiffConnections computes the structured set-diff (by name) of two connection states. Exported so the diff is one canonical implementation shared by the driver and tests.

func (ConnectionsDiff) Changed

func (d ConnectionsDiff) Changed() bool

Changed reports whether the connections set differs between the two revisions.

type ConnectionsSection

type ConnectionsSection struct {
	// Servers is the set of runtime-added MCP connection descriptors,
	// keyed by Name. Canonicalised sorted-by-name with a name-unique
	// invariant so a re-ordering does not perturb the content hash.
	Servers []MCPConnectionDescriptor `json:"servers,omitempty"`
}

ConnectionsSection is the runtime-added MCP-connection section of the config envelope: the set of NON-SECRET connection descriptors an admin has added over the control plane. Declared as its own section so an add REPLACES only this section, preserving Skills / ToolExposure / PromptLayers (the bidirectional section-merge invariant).

type Deps

type Deps struct {
	State state.StateStore
	Bus   events.EventBus
	Clock func() time.Time
}

Deps carries the runtime dependencies an agentcfg driver needs. State (the persistence floor) and Bus (the audit/observability bus) are mandatory; a nil either fails the factory loud with ErrInvalidConfig. Clock is optional (defaults to time.Now).

type Diff

type Diff struct {
	// FromRevisionID / ToRevisionID name the compared revisions.
	FromRevisionID string
	ToRevisionID   string
	// Skills is the structured set-diff of the skills membership.
	Skills SkillsDiff
	// ToolExposure is the structured set-diff of the MCP-exposure /
	// per-tool policy.
	ToolExposure ToolExposureDiff
	// PromptLayers is the text delta of the base + user prompt layers.
	PromptLayers PromptLayersDiff
	// Connections is the structured set-diff of the runtime-added MCP
	// connection descriptors (by name).
	Connections ConnectionsDiff
	// OAuthProviders is the structured set-diff of the Protocol-installed
	// OAuth-provider descriptors (by name).
	OAuthProviders OAuthProvidersDiff
	// LLMParams is the per-field delta of the per-agent LLM-parameter
	// section (model / temperature / max-tokens / reasoning-effort).
	LLMParams LLMParamsDiff
	// Hooks is the per-field delta of the run-lifecycle-hook section
	// (the run-completion hook's tool + timeout).
	Hooks HooksDiff
	// Naming is the per-field delta of the session auto-naming policy
	// section.
	Naming NamingDiff
}

Diff is the server-side compare of two revision payloads. The first wave carries the structured skills set-diff; later consumers add a text diff for the prompt layer and structured diffs for tool exposure.

type Factory

type Factory func(cfg Config, deps Deps) (Registry, error)

Factory builds a Registry from a Config + Deps. Drivers expose one Factory each via init() → Register.

type HooksDiff added in v1.10.0

type HooksDiff struct {
	// SectionPresentChanged reports whether the hooks-section PRESENCE differs
	// (absent vs present). A present-but-empty section (the explicit per-agent
	// no-hook) renders no tool and no timeout, so WITHOUT this dimension
	// a yaml-hook-on agent toggling to an explicit `{}` opt-out would be an
	// invisible revision in agent_config.diff (a phantom revision in the
	// Console diff view). Mirrors NamingDiff's tri-state Auto. Present renders
	// "present"; absent renders "".
	SectionPresentChanged bool
	SectionPresentFrom    string
	SectionPresentTo      string
	// RunCompletionToolChanged reports whether the hook's target tool differs.
	RunCompletionToolChanged bool
	RunCompletionToolFrom    string
	RunCompletionToolTo      string
	// RunCompletionTimeoutChanged reports whether the hook's timeout differs.
	RunCompletionTimeoutChanged bool
	RunCompletionTimeoutFrom    string
	RunCompletionTimeoutTo      string
}

HooksDiff is the per-field delta of the run-lifecycle-hook section across two revisions. Reports whether the run-completion hook's tool / timeout changed plus their from / to display values (an unset hook renders "").

func DiffHooks added in v1.10.0

func DiffHooks(from, to ConfigPayload) HooksDiff

DiffHooks computes the per-field delta of two run-lifecycle-hook states. Exported so the diff is one canonical implementation shared by the driver and tests. An ABSENT section renders no presence + empty tool/timeout; a PRESENT-but-empty section (explicit no-hook) renders presence "present" with empty tool/timeout — so absent→`{}` (and its inverse) registers as a change even though tool and timeout are empty on both sides.

func (HooksDiff) Changed added in v1.10.0

func (d HooksDiff) Changed() bool

Changed reports whether the run-lifecycle-hook section differs between the two revisions.

type HooksSection added in v1.10.0

type HooksSection struct {
	// RunCompletion pins the agent's run-completion hook when non-nil with a
	// non-empty tool. Nil in a PRESENT section is the explicit no-hook.
	RunCompletion *RunCompletionHook `json:"run_completion,omitempty"`
}

HooksSection is the run-lifecycle-hook section of the config envelope. Declared as its own section so a set REPLACES only this section, preserving the sibling sections (the section-merge invariant).

Section PRESENCE is authoritative (mirrors NamingSection): a NIL section means "no per-agent hook policy" (the yaml `runtime.hooks.run_completion` fleet default, then no hook, resolves at run start). A PRESENT section with a non-nil RunCompletion (non-empty tool) pins the agent's hook; a PRESENT section with a nil / empty-tool RunCompletion is an explicit per-agent NO-HOOK that OVERRIDES a yaml-on fleet default — normalization preserves any non-nil section (never an inert-drop).

type LLMParams

type LLMParams struct {
	// Model, when set, is the model the agent's next run requests
	// (overriding the tenant-wide baseline / config default). An empty
	// string normalises to unset.
	Model *string `json:"model,omitempty"`
	// Temperature, when set, is the sampling temperature for the next run.
	Temperature *float64 `json:"temperature,omitempty"`
	// MaxTokens, when set, is the per-message output-token ceiling.
	MaxTokens *int `json:"max_tokens,omitempty"`
	// ReasoningEffort, when set, is the reasoning-effort hint
	// ("off" | "low" | "medium" | "high"). An empty string normalises to
	// unset.
	ReasoningEffort *string `json:"reasoning_effort,omitempty"`
}

LLMParams pins an agent's sampling defaults as a versioned config section. Every field is pointer-optional: an unset field falls through to the next resolution layer (the tenant-wide baseline, then the config default) — the per-agent layer overrides ONLY the dimensions it sets. This is sampling parameters only; additive system-prompt text lives in PromptLayers (there is one home for prompt text).

type LLMParamsDiff

type LLMParamsDiff struct {
	ModelChanged bool
	ModelFrom    string
	ModelTo      string

	TemperatureChanged bool
	TemperatureFrom    string
	TemperatureTo      string

	MaxTokensChanged bool
	MaxTokensFrom    string
	MaxTokensTo      string

	ReasoningEffortChanged bool
	ReasoningEffortFrom    string
	ReasoningEffortTo      string
}

LLMParamsDiff is the per-field delta of the per-agent LLM-parameter section across two revisions. Each dimension reports whether it changed plus its from / to values (formatted for display; an unset dimension is the empty string). Deterministic.

func DiffLLMParams

func DiffLLMParams(from, to ConfigPayload) LLMParamsDiff

DiffLLMParams computes the per-field delta of two per-agent LLM-parameter states. Exported so the diff is one canonical implementation shared by the driver and tests. An unset dimension is compared as the empty string; numeric dimensions are formatted canonically (so 0.7 vs unset registers a change to/from "").

func (LLMParamsDiff) Changed

func (d LLMParamsDiff) Changed() bool

Changed reports whether any LLM-parameter dimension differs between the two revisions.

type LoadingModeChange added in v1.10.0

type LoadingModeChange struct {
	Key  string
	From string
	To   string
}

LoadingModeChange is one entry in a loading-mode override diff: the override at Key (a catalog name for a ToolLoadingChanges entry, a ToolSourceID for a ServerLoadingChanges entry) changed from From to To. An empty From/To means the override was absent (unset) on that side of the compare — a set→unset or unset→set transition still registers as a change.

type MCPConnectionDescriptor

type MCPConnectionDescriptor struct {
	// Name is the unique MCP source id (the tool-name prefix the planner
	// sees). Required.
	Name string `json:"name"`
	// Transport is the wire transport — "stdio" or "http".
	Transport MCPTransport `json:"transport"`
	// Command is the stdio argv (argv[0] is the binary; no shell). Set for
	// the stdio transport; empty for http.
	Command []string `json:"command,omitempty"`
	// URL is the http(s) endpoint. Set for the http transport; empty for
	// stdio.
	URL string `json:"url,omitempty"`
	// OAuthProvider names a declared OAuth provider to bind for per-identity
	// southbound bearer injection on this connection's calls. NON-SECRET — a
	// provider NAME selecting a config-declared acquisition strategy; the
	// secret stays on the provider. Empty leaves the connection on its static
	// (attach-time) headers. Set only for the http transport.
	OAuthProvider string `json:"oauth_provider,omitempty"`
	// MetaAnnotations is a static, NON-SECRET set of operator-declared
	// key/values merged verbatim into the MCP `_meta` on every
	// identity-stamped per-call RPC (the deployment's attribution
	// vocabulary). Reserved / spec-prefixed keys are rejected at attach.
	MetaAnnotations map[string]string `json:"meta_annotations,omitempty"`
	// OAuthDiscoveryAllowedOrigins is the explicit per-connection cross-origin
	// allow-list of public https origins the MCP OAuth-requirement discovery
	// walker may fetch authorization-server metadata from. NON-SECRET (an origin
	// allow-list, never a secret) — it rides the revision spine (versioned /
	// diffable / rollback-able) and is writable live over
	// `agent_config.set_mcp_discovery_origins`. Empty leaves the
	// authorization-server hop needs-allowance (partial discovery), never a
	// network hole: a granted origin is still refused at dial time if it
	// resolves private / loopback. Set only for the http transport.
	OAuthDiscoveryAllowedOrigins []string `json:"oauth_discovery_allowed_origins,omitempty"`
}

MCPConnectionDescriptor is the NON-SECRET shape of one runtime-added MCP server connection, recorded in a config revision so the connection is part of the agent's versioned desired state (diff / rollback). It carries ONLY the non-secret descriptor — the server name, the transport, the stdio argv command or the http URL, the non-secret OAuth provider NAME, and the non-secret operator `_meta` annotations. Secret auth material (bearer headers, OAuth tokens, credentials, the minted downstream token) is NEVER part of this descriptor: it flows through the live attach + the tool-side OAuth / pause-resume path and is never persisted in a revision, a diff, or an event (CLAUDE.md §7). The `oauth_provider` field is a NAME, not a secret — it selects a config-declared acquisition strategy.

type MCPConnectionLifecyclePayload

type MCPConnectionLifecyclePayload struct {
	events.SafeSealed
	// Author is the identity that drove the add.
	Author identity.Quadruple
	// AgentID is the agent the connection was added to (a registration
	// identity, NOT an isolation principal).
	AgentID string
	// ServerID is the MCP source id (name) of the connection being added.
	ServerID string
	// Transport is the connection transport ("stdio" / "http") — non-secret.
	Transport string
	// State is the lifecycle state the event marks ("pending" / "online" /
	// "failed" / "auth_required").
	State string
	// RevisionID is the recording revision id (set for online / auth_required;
	// empty for pending and for a failed add, which records no revision).
	RevisionID string
	// PauseToken is the unified-pause/resume token the auth_required attach
	// parked on (set only for the auth_required state); empty otherwise. It
	// is an opaque runtime handle, NOT a credential.
	PauseToken string
	// Reason is a SAFE, operator-facing failure reason (set only for the
	// failed state); never a secret or raw transport payload.
	Reason string
	// OccurredAt is the lifecycle-transition instant.
	OccurredAt time.Time
}

MCPConnectionLifecyclePayload is the typed payload for the runtime MCP-attach lifecycle events (pending / added / failed / auth_required). SafePayload — every field is operator-visible audit metadata; NO secret header / token / credential / auth code is ever carried (CLAUDE.md §7).

type MCPConnectionPausedPayload

type MCPConnectionPausedPayload struct {
	events.SafeSealed
	// Author is the identity that recorded the pause.
	Author identity.Quadruple
	// AgentID is the agent whose MCP exposure changed (a registration
	// identity, NOT an isolation principal).
	AgentID string
	// ServerID is the MCP source id newly paused.
	ServerID string
	// RevisionID is the tool-exposure revision that recorded the pause.
	RevisionID string
	// OccurredAt is the pause instant.
	OccurredAt time.Time
}

MCPConnectionPausedPayload is the typed payload for EventTypeMCPConnectionPaused. SafePayload — every field is operator-visible audit metadata; no secret-shaped content is carried.

type MCPConnectionRemovedPayload added in v1.11.0

type MCPConnectionRemovedPayload struct {
	events.SafeSealed
	// Author is the identity that recorded the removal.
	Author identity.Quadruple
	// AgentID is the agent whose MCP connection was removed (a registration
	// identity, NOT an isolation principal).
	AgentID string
	// ServerID is the MCP source id that was removed.
	ServerID string
	// RevisionID is the revision that dropped the descriptor + pruned residue.
	RevisionID string
	// OccurredAt is the removal instant.
	OccurredAt time.Time
}

MCPConnectionRemovedPayload is the typed payload for EventTypeMCPConnectionRemoved. SafePayload — every field is operator-visible audit metadata; no secret-shaped content is carried. It mirrors the paused/resumed payload shape (the removal is the same class of desired-state edit).

type MCPConnectionResumedPayload

type MCPConnectionResumedPayload struct {
	events.SafeSealed
	// Author is the identity that recorded the resume.
	Author identity.Quadruple
	// AgentID is the agent whose MCP exposure changed.
	AgentID string
	// ServerID is the MCP source id newly resumed.
	ServerID string
	// RevisionID is the tool-exposure revision that recorded the resume.
	RevisionID string
	// OccurredAt is the resume instant.
	OccurredAt time.Time
}

MCPConnectionResumedPayload is the typed payload for EventTypeMCPConnectionResumed. SafePayload — operator-visible audit metadata only.

type MCPDiscoveryOriginsSetPayload added in v1.14.0

type MCPDiscoveryOriginsSetPayload struct {
	events.SafeSealed
	// Author is the identity that performed the write.
	Author identity.Quadruple
	// AgentID is the agent whose connection allow-list changed (a registration
	// identity, NOT an isolation principal).
	AgentID string
	// ServerID is the MCP source id whose allow-list was replaced.
	ServerID string
	// RevisionID is the revision that recorded the new allow-list.
	RevisionID string
	// Granted is the set of origins newly present versus the prior live set.
	Granted []string
	// Revoked is the set of origins dropped versus the prior live set.
	Revoked []string
	// OccurredAt is the write instant.
	OccurredAt time.Time
}

MCPDiscoveryOriginsSetPayload is the typed payload for EventTypeMCPDiscoveryOriginsSet. SafePayload — every field is operator-visible audit metadata; the origin deltas are PUBLIC https origins (an allow-list), never a secret.

type MCPTransport

type MCPTransport string

MCPTransport is the closed set of transports a runtime-added MCP connection descriptor may declare. The control-plane add path supports MCP over stdio (an operator-supplied argv command) and http (a URL); other transports are out of scope for the runtime add.

const (
	// MCPTransportStdio — the server is an operator-supplied subprocess,
	// launched argv-form (NEVER via a shell). The most privileged add (an
	// RCE surface) — allowlist-gated at the control-plane edge.
	MCPTransportStdio MCPTransport = "stdio"
	// MCPTransportHTTP — the server is reachable over an HTTP(S) endpoint.
	MCPTransportHTTP MCPTransport = "http"
)

The canonical runtime-add MCP transports.

type NamingDiff added in v1.12.0

type NamingDiff struct {
	AutoChanged bool
	AutoFrom    string
	AutoTo      string

	AfterTurnsChanged bool
	AfterTurnsFrom    string
	AfterTurnsTo      string

	RepeatEveryChanged bool
	RepeatEveryFrom    string
	RepeatEveryTo      string

	MaxRepetitionsChanged bool
	MaxRepetitionsFrom    string
	MaxRepetitionsTo      string

	MaxTitleLenChanged bool
	MaxTitleLenFrom    string
	MaxTitleLenTo      string

	ModelChanged bool
	ModelFrom    string
	ModelTo      string
}

NamingDiff is the per-field delta of the session auto-naming policy section across two revisions. Each dimension reports whether it changed plus its from / to display values (an unset section renders every field as ""). Deterministic.

Auto is a TRI-STATE display string — "" (section ABSENT) / "false" / "true" — because section PRESENCE is semantic: a present bare `{auto: false}` section is an explicit per-agent opt-out that overrides a yaml-on fleet default, while an absent section falls through to yaml. A two-state bool would render absent and bare-opt-out identically, making exactly that revision invisible to `agent_config.diff` (a phantom revision in the Console diff view).

func DiffNaming added in v1.12.0

func DiffNaming(from, to ConfigPayload) NamingDiff

DiffNaming computes the per-field delta of two session auto-naming states. Exported so the diff is one canonical implementation shared by the driver and tests. An ABSENT section renders every dimension "" — including Auto (the tri-state), so absent→bare-`{auto:false}` ("" → "false") and its inverse register as changes even though every OTHER dimension is zero-valued on both sides.

func (NamingDiff) Changed added in v1.12.0

func (d NamingDiff) Changed() bool

Changed reports whether any auto-naming dimension differs between the two revisions.

type NamingSection added in v1.12.0

type NamingSection struct {
	// Auto enables session auto-naming for the agent. False (the zero value)
	// in a PRESENT section is an explicit off that overrides the yaml fleet
	// default.
	Auto bool `json:"auto,omitempty"`
	// AfterTurns is the completed-run count at which the FIRST auto-name
	// fires (fire on the Nth completed run). Zero resolves to the default
	// (1) at run start; a negative value is rejected at set time.
	AfterTurns int `json:"after_turns,omitempty"`
	// RepeatEvery, when > 0, re-names every N completed turns after the
	// first; 0 (the default) names once only. Negative is rejected at set
	// time.
	RepeatEvery int `json:"repeat_every,omitempty"`
	// MaxRepetitions is the hard cap on the TOTAL number of auto-namings
	// (including the first). It is REQUIRED ≥ 1 whenever RepeatEvery > 0 —
	// no unlimited value exists, so unbounded periodic re-naming is
	// unrepresentable. Ignored when RepeatEvery == 0 (naming happens once).
	MaxRepetitions int `json:"max_repetitions,omitempty"`
	// MaxTitleLen bounds the auto title (runes). Zero resolves to the
	// default (80) at run start; a set value must be in [8, 200].
	MaxTitleLen int `json:"max_title_len,omitempty"`
	// Model, when set, is the model the auto-naming Complete call requests
	// (validated against ModelProfiles at set time); empty uses the run's
	// effective model.
	Model string `json:"model,omitempty"`
}

NamingSection is the session auto-naming policy section of the config envelope. Declared as its own optional section so a set REPLACES only this section, preserving the sibling sections (the section-merge invariant). Opt-in, default off: a NIL section means "no per-agent policy" (the yaml `runtime.naming` fleet default, then off, resolves at run start). A PRESENT section is authoritative either way: Auto=true enables, Auto=false is an explicit per-agent OPT-OUT that overrides a yaml-on fleet default — section presence is the operator's signal, and normalization preserves any non-nil section verbatim (never an inert-drop).

type OAuthProviderDescriptor added in v1.14.0

type OAuthProviderDescriptor struct {
	// Name is the unique provider name (the binding a connection's
	// oauth_provider references). Required.
	Name string `json:"name"`
	// Driver is the OAuth flow driver — validated to be exactly
	// "tokenexchange" (the only writable driver; the non-interactive PULL
	// exchange). Required.
	Driver string `json:"driver"`
	// CredentialSource is the credential-source seam — validated to be exactly
	// "remote" (broker-pull). An empty value is a LOUD reject (in config
	// "" means the `env` source, which this shape forbids). Required.
	CredentialSource string `json:"credential_source"`
	// CredentialBroker names a boot-declared credential broker that
	// pins every credential sink. Required; an unknown name fails loud.
	CredentialBroker string `json:"credential_broker"`
	// Scopes is the requested OAuth scope subset. NON-SECRET. Clamped to the
	// broker's boot scope ceiling at build time — a scope outside the ceiling is
	// dropped, never honoured (an installed descriptor can never widen scope).
	// Optional.
	Scopes []string `json:"scopes,omitempty"`
}

OAuthProviderDescriptor is the ZERO-URL, Protocol-installed OAuth provider descriptor recorded in a config revision so the provider is part of the agent's versioned desired state (diff / rollback). It carries NO URL of any kind, NO env-var name, and NO literal secret: the credential-plane invariant is that no admin-writable field may determine where a credential is sent, so every credential-sink-determining value (the token endpoint, the credential-pull endpoint, the allowed downstream hosts, the audience, and the scope ceiling) is pinned at boot on the NAMED credential broker (the boot broker's broker list) the descriptor references by non-secret NAME. The wire struct exposes NO field that is a URL or an env-var name; a decode carrying `token_url` / `auth_url` / `client_id_env` / `client_secret_env` / `remote` is rejected BY NAME (DisallowUnknownFields — the field cannot exist).

type OAuthProviderSetPayload added in v1.14.0

type OAuthProviderSetPayload struct {
	events.SafeSealed
	// Author is the identity that performed the install / uninstall.
	Author identity.Quadruple
	// AgentID is the agent whose installed-provider set changed (a registration
	// identity, NOT an isolation principal).
	AgentID string
	// ProviderName is the installed / uninstalled provider name.
	ProviderName string
	// CredentialBroker is the boot-declared broker the installed provider
	// references by name (empty on uninstall). NON-SECRET.
	CredentialBroker string
	// RevisionID is the recording revision id.
	RevisionID string
	// OccurredAt is the write instant.
	OccurredAt time.Time
}

OAuthProviderSetPayload is the typed payload for the Protocol-installed OAuth-provider install / uninstall audit events. SafePayload — every field is operator-visible audit metadata; NO URL, NO env-var name, NO secret is ever carried (there is none on the zero-URL descriptor). The credential-broker name is a non-secret boot reference.

type OAuthProvidersDiff added in v1.14.0

type OAuthProvidersDiff struct {
	// Added are the provider names present in the to-revision but not the
	// from-revision.
	Added []string
	// Removed are the provider names present in the from-revision but not the
	// to-revision.
	Removed []string
}

OAuthProvidersDiff is the structured set-diff of the Protocol-installed OAuth-provider descriptors across two revisions, by name. Deterministic: every slice is sorted.

func DiffOAuthProviders added in v1.14.0

func DiffOAuthProviders(from, to ConfigPayload) OAuthProvidersDiff

DiffOAuthProviders computes the structured set-diff (by name) of two installed-provider states. Exported so the diff is one canonical implementation shared by the driver and tests.

func (OAuthProvidersDiff) Changed added in v1.14.0

func (d OAuthProvidersDiff) Changed() bool

Changed reports whether the installed-provider set differs between the two revisions.

type OAuthProvidersSection added in v1.14.0

type OAuthProvidersSection struct {
	// Providers is the set of installed provider descriptors, keyed by Name.
	// Canonicalised sorted-by-name with a name-unique invariant so a
	// re-ordering does not perturb the content hash.
	Providers []OAuthProviderDescriptor `json:"providers,omitempty"`
}

OAuthProvidersSection is the Protocol-installed OAuth-provider section of the config envelope: the set of ZERO-URL provider descriptors an admin has installed over the control plane. Declared as its own section so an install / uninstall REPLACES only this section, preserving every sibling (the section-merge invariant).

type PromptLayers

type PromptLayers struct {
	// Base is the admin-owned, versioned base prompt layer. When set it is
	// the run's base system prompt (overriding the agent's configured
	// default base); unset inherits the configured default.
	Base *string `json:"base,omitempty"`
	// User is the optional higher user-instruction layer that composes
	// ABOVE the base without mutating it (the composition order is the
	// security boundary — the agent-config authorization model).
	User *string `json:"user,omitempty"`
}

PromptLayers is the prompt-layer section of the config envelope: an operator-owned, versioned base prompt layer plus an optional user layer that composes ABOVE the base without mutating it. The composition order is the structural security boundary — because Base and User are distinct fields and the user layer is always appended below the base, a writer of only User can extend the operator's guidance but can never precede, replace, or weaken the operator base.

type PromptLayersDiff

type PromptLayersDiff struct {
	// BaseChanged reports whether the base layer text differs.
	BaseChanged bool
	// BaseFrom / BaseTo are the base layer text in the from / to revision.
	BaseFrom string
	BaseTo   string
	// UserChanged reports whether the user layer text differs.
	UserChanged bool
	// UserFrom / UserTo are the user layer text in the from / to revision.
	UserFrom string
	UserTo   string
}

PromptLayersDiff is the text delta of the base + user prompt layers across two revisions. An unset layer compares as the empty string, so a set→unset change registers as a change to "".

func DiffPromptLayers

func DiffPromptLayers(from, to ConfigPayload) PromptLayersDiff

DiffPromptLayers computes the text delta of two prompt-layer states. Exported so the diff is one canonical implementation shared by the driver and tests. An unset layer is compared as the empty string.

func (PromptLayersDiff) Changed

func (d PromptLayersDiff) Changed() bool

Changed reports whether either prompt layer differs between the two revisions.

type Registry

type Registry interface {
	// SetRevision writes a NEW immutable revision pinning payload and
	// advances the active pointer to it. An idempotent re-set of
	// byte-identical canonical content (relative to the current active
	// revision) is a no-op that returns the existing active revision.
	SetRevision(ctx context.Context, id identity.Quadruple, agentID string, scope ConfigScope, payload ConfigPayload) (Revision, error)
	// Active returns the agent's current active revision and whether one
	// exists. No active pointer returns (zero, false, nil).
	Active(ctx context.Context, id identity.Quadruple, agentID string, scope ConfigScope) (Revision, bool, error)
	// Get returns the revision identified by revisionID. A missing
	// revision fails loud with ErrRevisionNotFound.
	Get(ctx context.Context, id identity.Quadruple, agentID, revisionID string, scope ConfigScope) (Revision, error)
	// ListRevisions returns the agent's revision chain newest-first,
	// capped at limit (0 = no cap). Enumeration uses the elevated
	// maintenance scan and filters to the agent's identity slot.
	ListRevisions(ctx context.Context, id identity.Quadruple, agentID string, scope ConfigScope, limit int) ([]Revision, error)
	// Rollback writes a new active pointer to an existing revision
	// WITHOUT mutating or deleting any revision. A missing target fails
	// loud with ErrRevisionNotFound.
	Rollback(ctx context.Context, id identity.Quadruple, agentID, revisionID string, scope ConfigScope) (Revision, error)
	// Diff returns the deterministic compare of two existing revisions.
	Diff(ctx context.Context, id identity.Quadruple, agentID, fromRev, toRev string, scope ConfigScope) (Diff, error)
	// Close releases resources. Idempotent.
	Close(ctx context.Context) error
}

Registry is the durable, identity-scoped, versioned desired-state store. It is a compiled artifact: immutable after construction and safe for concurrent reuse (the concurrent-reuse contract).

func Open

func Open(_ context.Context, cfg Config, deps Deps) (Registry, error)

Open returns the Registry built by the factory whose name matches cfg.Driver (defaults to DefaultDriver when empty). Deps are validated: a missing StateStore or EventBus returns a wrapped ErrInvalidConfig before the factory runs — fail loudly, never silently degrade.

type Revision

type Revision struct {
	// RevisionID is the unique, time-ordered id of this revision.
	RevisionID string
	// ParentRevisionID is the revision this one descends from (the
	// previously-active revision). Empty for the first revision.
	ParentRevisionID string
	// ContentHash is the full hex-encoded SHA-256 over the revision's
	// canonical (sorted-key) payload encoding.
	ContentHash string
	// Author is the identity that wrote the revision (the audit anchor).
	Author identity.Quadruple
	// CreatedAt is the revision's creation instant (UTC).
	CreatedAt time.Time
	// Payload is the config envelope this revision pins.
	Payload ConfigPayload
}

Revision is an immutable, content-addressed agent-config record with a parent pointer. SetRevision never mutates an existing Revision; it writes a new one and advances the active pointer.

type RunCompletionHook added in v1.10.0

type RunCompletionHook struct {
	// Tool is the catalog tool name the transcript is dispatched to. An empty
	// tool normalises the RunCompletion to nil BUT preserves the enclosing
	// hooks section (a present section with no tool is the explicit per-agent
	// no-hook that overrides a yaml fleet hook at run start).
	Tool string `json:"tool"`
	// TimeoutMS is the dispatch timeout in milliseconds. Zero falls through
	// to the runtime default at run start. Negative is rejected at set time.
	TimeoutMS int `json:"timeout_ms,omitempty"`
}

RunCompletionHook is the durable, versioned run-completion hook configuration in a config revision: the catalog tool the run transcript is dispatched to at the run loop's terminal boundary, plus an optional dispatch timeout. It mirrors the static `runtime.hooks.run_completion` yaml; resolution at run start is agent-config over yaml over no hook.

type SkillsDiff

type SkillsDiff struct {
	// Added are the skill names present in the to-revision but not the
	// from-revision.
	Added []string
	// Removed are the skill names present in the from-revision but not
	// the to-revision.
	Removed []string
}

SkillsDiff is the structured set-diff of the skills membership across two revisions. Deterministic: Added / Removed are sorted.

func DiffSkills

func DiffSkills(from, to []string) SkillsDiff

DiffSkills computes the structured set-diff of two skills memberships. Exported so the diff is one canonical implementation shared by the driver and tests.

func (SkillsDiff) Changed

func (d SkillsDiff) Changed() bool

Changed reports whether the skills membership differs between the two revisions.

type SkillsSelection

type SkillsSelection struct {
	// Names is the set of skill names active for the agent in this
	// revision. Order is not significant — the content hash is computed
	// over a canonical sorted, de-duplicated form so a re-ordering does
	// not perturb the hash.
	Names []string `json:"names"`
}

SkillsSelection is the membership set of skill names active for an agent in a revision. The revision records skill MEMBERSHIP (names), never skill bodies — the bodies stay in the SkillStore. Resolved at run start; applied next-turn.

type ToolExposure

type ToolExposure struct {
	// PausedServers names MCP servers excluded from the next run's
	// projection (resume is a flag flip, not a re-dial).
	PausedServers []string `json:"paused_servers,omitempty"`
	// DisabledTools names tools the per-tool policy excludes.
	DisabledTools []string `json:"disabled_tools,omitempty"`
	// ServerLoadingModes overrides the default LoadingMode ("always" |
	// "deferred") for a server's TOOL-form descriptors, keyed by the
	// catalog's ToolSourceID. See the precedence order above.
	ServerLoadingModes map[string]string `json:"server_loading_modes,omitempty"`
	// ToolLoadingModes overrides the effective LoadingMode for one exact
	// catalog name ("always" | "deferred"), unconditionally. See the
	// precedence order above.
	ToolLoadingModes map[string]string `json:"tool_loading_modes,omitempty"`
}

ToolExposure is the forward-compatible tool/MCP-exposure section of the config envelope: the exclusion-based pause/disable sets (PausedServers / DisabledTools) plus the runtime loading-mode override maps (ServerLoadingModes / ToolLoadingModes).

Loading-mode precedence (pinned)

Per descriptor, the effective LoadingMode resolves in this order:

  1. ToolLoadingModes[name] — exact, unconditional (works on tool / resource / prompt forms alike).
  2. ServerLoadingModes[source] — the server-wide default, applied ONLY to TOOL-form descriptors (tools.Tool.Form == tools.ToolFormTool); a server-level override never blanket-flips that server's wrapped resource/prompt descriptors.
  3. The boot `tools.entries[].loading_mode` (already materialized into the catalog's Tool.Loading at boot).
  4. The driver/registration default.

Layers 3-4 are already baked into the catalog's boot-effective tools.Tool.Loading, so a projection consumer applies exactly the top two layers over that boot-effective value (see internal/runtime/agentcfg/projection). Values are the closed set "always" | "deferred" — validated at the `agent_config.set_tool_exposure` wire edge BEFORE any registry write (CLAUDE.md §13: no invalid value is ever persisted). Loading is NOT capability-narrowing (a deferred tool stays reachable via `tool_search`), so it lives in the ADMIN tier only — the narrow-only user/session tiers gain no loading field.

type ToolExposureDiff

type ToolExposureDiff struct {
	// PausedAdded / PausedResumed are the MCP servers newly paused / newly
	// resumed (present-in-to-but-not-from / present-in-from-but-not-to).
	PausedAdded   []string
	PausedResumed []string
	// DisabledAdded / DisabledEnabled are the tools newly disabled / newly
	// re-enabled.
	DisabledAdded   []string
	DisabledEnabled []string
	// ServerLoadingChanges / ToolLoadingChanges are the structured deltas of
	// the per-server / per-tool loading-mode override maps. Sorted by Key.
	ServerLoadingChanges []LoadingModeChange
	ToolLoadingChanges   []LoadingModeChange
}

ToolExposureDiff is the structured set-diff of the MCP-exposure / per-tool policy across two revisions. Deterministic: every slice is sorted.

func DiffToolExposure

func DiffToolExposure(from, to ConfigPayload) ToolExposureDiff

DiffToolExposure computes the structured set-diff of two tool-exposure states. Exported so the diff is one canonical implementation shared by the driver and tests.

func (ToolExposureDiff) Changed

func (d ToolExposureDiff) Changed() bool

Changed reports whether the tool exposure differs between the two revisions.

Directories

Path Synopsis
Package conformance is the shared agentcfg.Registry driver conformance suite: a single set of behaviour assertions every driver must pass, so a future driver inherits the contract verbatim (the §11 conformance-suite pattern).
Package conformance is the shared agentcfg.Registry driver conformance suite: a single set of behaviour assertions every driver must pass, so a future driver inherits the contract verbatim (the §11 conformance-suite pattern).
drivers
statestore
Package statestore implements the StateStore-backed agentcfg Registry driver — the default driver for the agent-config control plane.
Package statestore implements the StateStore-backed agentcfg Registry driver — the default driver for the agent-config control plane.
Package sessionoverlay owns the SESSION-scoped safe-subset overlay of the agent-config control plane: the lower tier of the authorization matrix.
Package sessionoverlay owns the SESSION-scoped safe-subset overlay of the agent-config control plane: the lower tier of the authorization matrix.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL