Documentation
¶
Overview ¶
Package rig is the public composition root for defining an agent rig and creating or restoring its sessions. It owns design-time topology and lifecycle policy while the returned session contracts expose live runtime behavior.
Index ¶
- Constants
- func FingerprintFrom(definition loop.BoundDefinition) event.ConfigFingerprint
- type ConfigFingerprintFields
- type DefinitionError
- type DefinitionErrorKind
- type DelegationLimits
- type GateCaps
- type HustleLimits
- type InvalidOffloadGCIntervalError
- type InvalidOffloadGCTimeoutError
- type LifecycleError
- type LifecycleErrorKind
- type OffloadGCPolicy
- type Option
- func WithActivePrimer(name string) Option
- func WithAllowConfigMismatch() Option
- func WithDelegationLimits(limits DelegationLimits) Option
- func WithExclusiveWorkspace(store *workspacestore.Store, root string, leaser storage.Leaser) Option
- func WithFingerprintFields(fields ConfigFingerprintFields) Option
- func WithForeignBuilders(builder foreign.Builder, restored foreign.RestoredBuilder) Option
- func WithForeignServicesBuilders(builder foreign.ServicesBuilder, restored foreign.ServicesRestoredBuilder) Option
- func WithGateCaps(caps GateCaps) Option
- func WithHooks(set hook.Set) Option
- func WithHustleLimits(limits HustleLimits) Option
- func WithHustles(definitions ...hustle.Definition) Option
- func WithLoops(definitions ...loop.Definition) Option
- func WithOffloadGC(policy OffloadGCPolicy) Option
- func WithPermissionClassifiers(classifiers gate.PermissionClassifierSet) Option
- func WithPermissionReviewEvidence(access gate.EvidenceAccessEvaluator, ...) Option
- func WithPermissionReviewLimits(limits PermissionReviewLimits) Option
- func WithPermissionReviewObservations(verifier gate.EvidenceObservationVerifier) Option
- func WithPermissionReviewPolicy(policy gate.PermissionReviewPolicy) Option
- func WithPermissionReviewSecurityCeiling(ceiling string) Option
- func WithPrimers(names ...string) Option
- func WithRestoreDecider(decider session.RestoreDecider) Option
- func WithRestoreFailurePolicy(options ...RestoreFailureOption) Option
- func WithRuntimeCatalog(catalog loop.RuntimeCatalog) Option
- func WithRuntimeRestoreResolver(resolver session.RuntimeRestoreResolver) Option
- func WithSessionResourceStorage(provider SessionResourceStorageProvider) Option
- func WithSessionStore(store *sessionstore.Store) Option
- func WithSessionWorkspaces(store *workspacestore.Store, baseDir string) Option
- func WithSharedWorkspace(store *workspacestore.Store, root string) Option
- func WithSnapshots(policy SnapshotPolicy) Option
- func WithToolResultCapture(objects loop.ToolResultObjectStore, spillBase string) Option
- type PermissionReviewLimits
- type PermissionReviewSessionLimits
- type PersistenceOverlapError
- type RestoreFailureOption
- func AllowAdapterDrift() RestoreFailureOption
- func AllowAgentKindDrift() RestoreFailureOption
- func AllowAgentNameDrift() RestoreFailureOption
- func AllowConfinementDrift() RestoreFailureOption
- func AllowCredentialDrift() RestoreFailureOption
- func AllowEffortDrift() RestoreFailureOption
- func AllowExternalCapabilityDrift() RestoreFailureOption
- func AllowHookPolicyDrift() RestoreFailureOption
- func AllowModelDrift() RestoreFailureOption
- func AllowNativePermissionDrift() RestoreFailureOption
- func AllowPermissionDrift() RestoreFailureOption
- func AllowPermissionPostureDrift() RestoreFailureOption
- func AllowPermissionReviewDrift() RestoreFailureOption
- func AllowRuntimeCatalogDrift() RestoreFailureOption
- func AllowRuntimeProfileDrift() RestoreFailureOption
- func AllowRuntimeSkillsDrift() RestoreFailureOption
- func AllowTrustDrift() RestoreFailureOption
- func AllowWorkspaceDrift() RestoreFailureOption
- type Rig
- type SessionOption
- type SessionOptionError
- type SessionOptionErrorKind
- type SessionResourceStorage
- type SessionResourceStorageProvider
- type SnapshotPolicy
- type SnapshotPolicyError
- type SnapshotPolicyErrorKind
- type SnapshotPriority
- type SnapshotTrigger
- type WorkspacePlacementError
- type WorkspacePlacementErrorKind
- type WorkspaceRecoveryError
- type WorkspaceRootBusyError
- type WorkspaceRootLeaseLostError
Constants ¶
const DefaultPermissionReviewBreakerThreshold = 20
DefaultPermissionReviewBreakerThreshold is the default numeric circuit-breaker threshold Define() resolves for every turn-scoped and session-scoped counter (resolvePermissionReviewLimits in definition.go) when classifiers are configured but WithPermissionReviewLimits was never explicitly called.
const MaxHustleQueued = 10_000
MaxHustleQueued is the largest configured waiting capacity for either hustle lane. The execution controller may allocate no queue larger than this bound.
Variables ¶
This section is empty.
Functions ¶
func FingerprintFrom ¶
func FingerprintFrom(definition loop.BoundDefinition) event.ConfigFingerprint
FingerprintFrom derives the stable, secret-free behavior fingerprint of a bound loop.
Types ¶
type ConfigFingerprintFields ¶
type ConfigFingerprintFields struct {
AgentKind string
RuntimeSkills bool
WorkspaceRoot string
// AdapterID identifies a foreign-agent adapter. Empty means native.
AdapterID string
// Posture identifies a foreign agent's non-interactive permission posture.
Posture string
// NativePermissionPolicyRev is the digest of native permission configuration.
NativePermissionPolicyRev string
// ExternalCapabilityRev is the digest of the identity of external capabilities
// the composition root attached to the session — tools served by processes
// Harness does not own, such as MCP servers. Empty means none, which is what
// keeps it additive for every rig that attaches nothing.
//
// The rig neither computes nor interprets it: only the composition root knows
// what it attached. The canonical producer is github.com/looprig/mcp's
// mcpharness.Manager.ConfigDigest, taken after the Manager has started.
ExternalCapabilityRev string
// WorkspaceTrust is an opaque, secret-free label for the workspace's trust
// posture (e.g. "trusted"/"untrusted"). Empty means unspecified.
WorkspaceTrust string
// PermissionStrictness is the ordered native-permission posture level; higher is
// stricter. Zero means unknown (drift assessment fails secure). It complements
// NativePermissionPolicyRev, which is the digest-only identity.
PermissionStrictness event.StrictnessLevel
// ConfinementRev is a content digest of the confinement (sandbox) configuration.
// Empty means none. Harness compares it, never parses it.
ConfinementRev string
// ConfinementStrictness is the ordered confinement posture level; higher is
// stricter. Zero means unknown.
ConfinementStrictness event.StrictnessLevel
// AppFields are application-defined, secret-free compatibility fields the
// composition root attaches. Canonically encoded in sorted key order by the
// manifest. Nil means none.
AppFields map[string]string
RuntimeProfile string
RuntimeCatalogRev string
RuntimeIdentityRev string
}
ConfigFingerprintFields are immutable rig-level behavior inputs that are not part of a loop.Definition. Define freezes them for both session creation and restoration.
type DefinitionError ¶
type DefinitionError struct {
Kind DefinitionErrorKind
Name string
Cause error
}
func (*DefinitionError) Error ¶
func (e *DefinitionError) Error() string
func (*DefinitionError) Unwrap ¶
func (e *DefinitionError) Unwrap() error
type DefinitionErrorKind ¶
type DefinitionErrorKind string
const ( DefinitionNilOption DefinitionErrorKind = "nil_option" DefinitionMissingLoop DefinitionErrorKind = "missing_loop" DefinitionInvalidLoop DefinitionErrorKind = "invalid_loop" DefinitionDuplicateLoop DefinitionErrorKind = "duplicate_loop" DefinitionMissingPrimer DefinitionErrorKind = "missing_primer" DefinitionInvalidPrimer DefinitionErrorKind = "invalid_primer" DefinitionInvalidActivePrimer DefinitionErrorKind = "invalid_active_primer" DefinitionMissingSessionStore DefinitionErrorKind = "missing_session_store" DefinitionInvalidSessionStore DefinitionErrorKind = "invalid_session_store" DefinitionInvalidDelegationLimits DefinitionErrorKind = "invalid_delegation_limits" DefinitionInvalidForeignBuilders DefinitionErrorKind = "invalid_foreign_builders" DefinitionInvalidGateCaps DefinitionErrorKind = "invalid_gate_caps" DefinitionInvalidRestoreDecider DefinitionErrorKind = "invalid_restore_decider" DefinitionInvalidRuntimeRestoreResolver DefinitionErrorKind = "invalid_runtime_restore_resolver" DefinitionInvalidRestoreFailurePolicy DefinitionErrorKind = "invalid_restore_failure_policy" DefinitionDuplicateOption DefinitionErrorKind = "duplicate_option" DefinitionInvalidHustle DefinitionErrorKind = "invalid_hustle" DefinitionDuplicateHustle DefinitionErrorKind = "duplicate_hustle" DefinitionMissingHustleLimits DefinitionErrorKind = "missing_hustle_limits" DefinitionUnusedHustleLimits DefinitionErrorKind = "unused_hustle_limits" DefinitionInvalidHustleLimits DefinitionErrorKind = "invalid_hustle_limits" DefinitionInvalidHooks DefinitionErrorKind = "invalid_hooks" DefinitionMissingResourceStorage DefinitionErrorKind = "missing_resource_storage" DefinitionInvalidResourceStorage DefinitionErrorKind = "invalid_resource_storage" DefinitionMissingCompactionHustle DefinitionErrorKind = "missing_compaction_hustle" DefinitionIncompatibleCompactionHustle DefinitionErrorKind = "incompatible_compaction_hustle" DefinitionInvalidPermissionClassifiers DefinitionErrorKind = "invalid_permission_classifiers" DefinitionInvalidPermissionReviewPolicy DefinitionErrorKind = "invalid_permission_review_policy" DefinitionIncompletePermissionReview DefinitionErrorKind = "incomplete_permission_review" DefinitionUnusedPermissionReviewLimits DefinitionErrorKind = "unused_permission_review_limits" DefinitionInvalidPermissionReviewEvidence DefinitionErrorKind = "invalid_permission_review_evidence" DefinitionMissingPermissionReviewEvidence DefinitionErrorKind = "missing_permission_review_evidence" DefinitionUnusedPermissionReviewEvidence DefinitionErrorKind = "unused_permission_review_evidence" // DefinitionInvalidPermissionReviewSecurityCeiling: WithPermissionReviewSecurityCeiling // was called with an empty (or all-whitespace) ceiling string. Rejected at // Define()-time rather than deferred to a later, harder-to-diagnose // review-context-capture failure (gate.ReviewContext's own non-empty // SecurityCeiling validation rule). DefinitionInvalidPermissionReviewSecurityCeiling DefinitionErrorKind = "invalid_permission_review_security_ceiling" // DefinitionMissingPermissionReviewSecurityCeiling: at least one permission // classifier is configured (WithPermissionClassifiers) but // WithPermissionReviewSecurityCeiling was never called. SecurityCeiling is a // consumer-owned value Harness cannot originate (Finding 2, Phase 6 // spec-compliance review): a classifier-registered session with no ceiling // would otherwise fail every real evidence-tool containment check closed, // silently, at runtime. DefinitionMissingPermissionReviewSecurityCeiling DefinitionErrorKind = "missing_permission_review_security_ceiling" // DefinitionUnusedPermissionReviewSecurityCeiling: WithPermissionReviewSecurityCeiling // was called but no permission classifier is configured, mirroring // DefinitionUnusedPermissionReviewEvidence's "config X requires config Y" // symmetric check. DefinitionUnusedPermissionReviewSecurityCeiling DefinitionErrorKind = "unused_permission_review_security_ceiling" // DefinitionInvalidPermissionReviewObservations: WithPermissionReviewObservations // was called with a nil verifier. DefinitionInvalidPermissionReviewObservations DefinitionErrorKind = "invalid_permission_review_observations" // DefinitionUnusedPermissionReviewObservations: WithPermissionReviewObservations // was called but either no permission classifier is configured at all, or // no WithPermissionReviewEvidence was configured (design §13.4's // observation-recheck mechanism lives entirely inside the evidence // runtime — a verifier with no evidence runtime to ever record an // observation into is dead configuration). There is deliberately no // symmetric "missing" error the way DefinitionMissingPermissionReviewEvidence // pairs with WithPermissionReviewEvidence: see WithPermissionReviewObservations' // own doc comment for why "a classifier's evidence tools need this" // cannot be determined at Define()-time today, and how runtime instead // fails closed (internal/sessionruntime/gates.go's // verifyPermissionReviewObservations) if that ever turns out to matter // for a given session. DefinitionUnusedPermissionReviewObservations DefinitionErrorKind = "unused_permission_review_observations" // DefinitionInvalidToolResultCapture: WithToolResultCapture was called with a // nil object store, or with a spill base that is not an absolute path (which // includes empty and all-whitespace). Name is a FIELD LABEL — exactly // "objects" or "spill_base" — and never the rejected value, so the error can // be logged or returned without treating it as caller-supplied data. // Rejected at Define rather than at the first oversized tool result, because // the failure mode otherwise is a turn that ends on a retention error long // after the misconfiguration. DefinitionInvalidToolResultCapture DefinitionErrorKind = "invalid_tool_result_capture" // DefinitionToolResultSpillOverlapsWorkspace: the capture spill base is equal // to, inside, or an ancestor of the configured workspace region. A workspace // checkpoint archives the whole region, so a spill inside it would be // captured into every checkpoint — and a region inside the spill base would // be deleted with it at session shutdown. Name carries the canonical base. DefinitionToolResultSpillOverlapsWorkspace DefinitionErrorKind = "tool_result_spill_overlaps_workspace" )
type DelegationLimits ¶
type HustleLimits ¶
type HustleLimits struct {
BlockingConcurrent int
BlockingQueued int
BackgroundConcurrent int
BackgroundQueued int
AuditTimeout time.Duration
FinalizationTimeout time.Duration
WorkerDrainTimeout time.Duration
}
HustleLimits bounds the two independent execution lanes and their audit, finalization, and worker-drain operations.
type InvalidOffloadGCIntervalError ¶
InvalidOffloadGCIntervalError reports a non-positive OffloadGCPolicy.Interval. A GC cadence must be a positive duration, so the rig fails closed at definition time rather than wiring a runner that would never (or continuously) tick.
func (*InvalidOffloadGCIntervalError) Error ¶
func (e *InvalidOffloadGCIntervalError) Error() string
type InvalidOffloadGCTimeoutError ¶
InvalidOffloadGCTimeoutError reports a non-positive OffloadGCPolicy.Timeout. A per-pass deadline must be a positive duration, so the rig fails closed at definition time.
func (*InvalidOffloadGCTimeoutError) Error ¶
func (e *InvalidOffloadGCTimeoutError) Error() string
type LifecycleError ¶
type LifecycleError struct {
Kind LifecycleErrorKind
Cause error
}
func (*LifecycleError) Error ¶
func (e *LifecycleError) Error() string
func (*LifecycleError) Unwrap ¶
func (e *LifecycleError) Unwrap() error
type LifecycleErrorKind ¶
type LifecycleErrorKind string
const ( LifecycleContextDone LifecycleErrorKind = "context_done" LifecycleIDGenerationFailed LifecycleErrorKind = "id_generation_failed" LifecycleLeaseFailed LifecycleErrorKind = "lease_failed" LifecycleJournalFailed LifecycleErrorKind = "journal_failed" LifecycleAppenderFailed LifecycleErrorKind = "appender_failed" LifecycleSessionFailed LifecycleErrorKind = "session_failed" LifecycleProcessNotificationsUnsupported LifecycleErrorKind = "process_notifications_unsupported" )
type OffloadGCPolicy ¶
OffloadGCPolicy configures session offload-blob GC: how often a GC pass runs (Interval) and the per-pass deadline (Timeout). It reaps orphaned content-addressed offload blobs — a blob left durable with no in-ledger blobptr pointer (the crash gap of the writer's blob-durable-before-pointer discipline). This is SESSION OFFLOAD GC only, never workspace-snapshot GC. Both fields must be positive.
type Option ¶
type Option func(*definitionState) error
func WithActivePrimer ¶
func WithAllowConfigMismatch ¶
func WithAllowConfigMismatch() Option
func WithDelegationLimits ¶
func WithDelegationLimits(limits DelegationLimits) Option
func WithExclusiveWorkspace ¶
WithExclusiveWorkspace declares one canonical fixed root fenced by a single exclusive root lease from leaser. The session lease is acquired first, then the root lease named workspace-roots/<sha256(canonical-root)>, so lexical/symlink aliases of the root contend.
func WithFingerprintFields ¶
func WithFingerprintFields(fields ConfigFingerprintFields) Option
func WithForeignBuilders ¶
func WithForeignBuilders(builder foreign.Builder, restored foreign.RestoredBuilder) Option
func WithForeignServicesBuilders ¶
func WithForeignServicesBuilders(builder foreign.ServicesBuilder, restored foreign.ServicesRestoredBuilder) Option
WithForeignServicesBuilders opts a rig into the additive foreign-engine seam. Each live/restored foreign origin receives a fresh loop-scoped broker descriptor and delivery hook at session construction; no capability is part of the immutable rig configuration. The legacy WithForeignBuilders option remains supported and receives zero services.
func WithGateCaps ¶
func WithHooks ¶
WithHooks installs one immutable operation-hook set. Define validates and compiles the captured set after every option has resolved.
func WithHustleLimits ¶
func WithHustleLimits(limits HustleLimits) Option
WithHustleLimits configures the required singleton lane bounds.
func WithHustles ¶
func WithHustles(definitions ...hustle.Definition) Option
WithHustles adds immutable hustle definitions to the rig.
func WithLoops ¶
func WithLoops(definitions ...loop.Definition) Option
func WithOffloadGC ¶
func WithOffloadGC(policy OffloadGCPolicy) Option
WithOffloadGC arms periodic session offload-blob GC. It validates the policy (both fields positive; typed errors on failure) and compiles to the sessionruntime lifecycle option that wires the journal-admission gate + GC runner onto both new and restored sessions. It is an at-most-once rig option.
func WithPermissionClassifiers ¶
func WithPermissionClassifiers(classifiers gate.PermissionClassifierSet) Option
WithPermissionClassifiers installs the already-validated, ordered permission classifier registry. Registration order is behavioral and therefore remains significant in the rig fingerprint.
func WithPermissionReviewEvidence ¶
func WithPermissionReviewEvidence(access gate.EvidenceAccessEvaluator, containment gate.EvidenceContainmentVerifier, allowedKinds []string) Option
WithPermissionReviewEvidence installs the consumer-supplied read-only evidence-tool access boundary every registered permission classifier's evidence tools run under (design §13.1). access answers the configured access state for one prepared evidence Requirement; containment independently performs the trusted-caller containment check (resolving symlinks, rejecting ambiguous scopes, enforcing the review's own security ceiling); allowedKinds is the explicit consumer-consent allowlist of Requirement.Kind values evidence tools may declare. Both access and containment are read-only, headless, trusted-caller seams — neither receives session, gate, mutation, grant, rule, or loop-control capability (design §13.1's Access/Containment split; Access alone was omitted from the design sketch of this option's signature, but the same fail-closed requirement applies to it: hustleruntime refuses to bind an evidence catalog with a nil Access evaluator exactly as it refuses a nil Containment verifier).
Required whenever any registered classifier's definition needs evidence tools; Define fails closed (DefinitionMissingPermissionReviewEvidence) if omitted in that case, and rejects it (DefinitionUnusedPermissionReviewEvidence) when supplied but no registered classifier needs it — mirroring the existing MissingHustleLimits/UnusedHustleLimits "config X requires config Y" pairing already used elsewhere in this file.
func WithPermissionReviewLimits ¶
func WithPermissionReviewLimits(limits PermissionReviewLimits) Option
WithPermissionReviewLimits installs the circuit-breaker thresholds (design §18) applied to automatic permission review. It is only meaningful paired with WithPermissionClassifiers; Define() enforces that pairing (DefinitionUnusedPermissionReviewLimits) rather than this Option, because option application order is not guaranteed (classifiers may be registered before or after this call in the Define() argument list).
Omitting this option while classifiers ARE configured resolves a default of DefaultPermissionReviewBreakerThreshold on every one of the 8 numeric thresholds (resolvePermissionReviewLimits, definition.go); an explicit call always replaces that default wholesale — all 8 fields at once, never merged per-field.
func WithPermissionReviewObservations ¶
func WithPermissionReviewObservations(verifier gate.EvidenceObservationVerifier) Option
WithPermissionReviewObservations installs the consumer-supplied, read-only TOCTOU-recheck seam (design §13.4) every classifier-originated auto-approval's recorded observations are verified against immediately before the gate is claimed. verifier independently re-derives each previously recorded gate.ObservationRequirement's current token and fails closed (leaving the human gate open) on any mismatch or unverifiable target — see gate.EvidenceObservationVerifier's own doc comment for the full trusted-caller contract, which deliberately reuses gate.EvidenceContainmentPolicy rather than introducing a parallel policy type (the security context — canonical read root plus the review's own non-widenable ceiling — is identical to WithPermissionReviewEvidence's own Containment collaborator).
A separate option, deliberately NOT folded into WithPermissionReviewEvidence's signature: the two are independent concerns (an evidence-tool access boundary a session needs whenever ANY registered classifier declares evidence tools, versus a TOCTOU recheck a session needs only when at least one of those evidence tools is target-sensitive). Folding Observations in as a fourth WithPermissionReviewEvidence parameter would force every existing and future caller with no target-sensitive evidence tools — the common case today, since no evidence tool in this codebase declares itself target-sensitive yet — to pass an explicit nil at that call site for a concern it will never use, which is exactly the Interface Segregation violation this package's own CLAUDE.md guidance warns against.
Required (rejected as DefinitionUnusedPermissionReviewObservations) unless BOTH at least one permission classifier is registered AND WithPermissionReviewEvidence is also configured — mirroring the "config X requires config Y" pairing precedent, but ONLY in the unused direction. There is deliberately NO symmetric "missing" pairing error the way WithPermissionReviewEvidence itself is required whenever anyClassifierNeedsEvidence(state.permissionClassifiers) reports true: that check is possible because hustle.Definition.EvidenceToolPolicy() already gives Define() a real, static, per-classifier "does this need an evidence runtime at all" signal. Nothing analogous exists for "is any of THIS classifier's evidence tools target-sensitive" — no evidence tool definition in this codebase declares that today (it is a per-concrete-tool capability, tool.EvidenceObservation, probed only at runtime after a call executes, not a static Definition-level property Define() could inspect ahead of time the way it inspects EvidenceToolPolicy). Manufacturing a parallel static declarer purely to unlock a Define()-time "missing" check, before any real tool exists that would ever set it, would be speculative generality with no consumer to validate it against. Instead, runtime fails closed: internal/sessionruntime/gates.go's verifyPermissionReviewObservations treats "an observation WAS recorded but no verifier is configured" identically to a genuine mismatch — stale, human gate stays open, never a silent pass — so a consumer who adds a target-sensitive evidence tool later without also wiring this option gets an always-safe (if initially confusing, and always correctable) runtime outcome rather than a false sense of protection. If a future evidence-tool capability gives Define() a real static signal, tightening this to a "missing" pairing error too is a natural, non-breaking follow-up — see this addendum's plan section for the explicit flag.
func WithPermissionReviewPolicy ¶
func WithPermissionReviewPolicy(policy gate.PermissionReviewPolicy) Option
WithPermissionReviewPolicy installs the immutable local decision policy (design §20) every session forwards into the review runtime. Only the policy's Revision feeds rig identity (permissionReviewFingerprintFrom in fingerprint.go); the full value is what sessionruntime actually applies.
A policy that was never built through gate.NewPermissionReviewPolicy or gate.DefaultPermissionReviewPolicy (a hand-built literal gate.PermissionReviewPolicy{}, whose zero seal makes it fail closed at EvaluatePermissionAssessment regardless) is rejected here immediately, rather than silently accepted and left to fail closed later with a confusing runtime symptom. This is a developer-experience improvement: the security property already holds without it.
func WithPermissionReviewSecurityCeiling ¶
WithPermissionReviewSecurityCeiling installs the consumer-supplied, effective security posture (design §13.1/§21) every registered permission classifier's ReviewContext/ReviewBasis carries as SecurityCeiling, and every evidence-tool containment check (WithPermissionReviewEvidence's Containment collaborator) is run against.
SecurityCeiling is architecturally the SAME KIND of value as the Containment/AllowedKinds collaborators WithPermissionReviewEvidence installs — a consumer-owned concept Harness structurally cannot and should not originate (this module has no first-class "effective access posture" notion; the product composition root binds its own AccessProfile name here). It is NOT like a workspace root, which Harness genuinely owns and auto-derives. A plain string, not a provider func: a consumer's ceiling is fixed for the session's lifetime by design (YAGNI — see the design consult this option was written from).
Required whenever any permission classifier is registered (WithPermissionClassifiers); Define fails closed (DefinitionMissingPermissionReviewSecurityCeiling) if omitted in that case — before this option existed, every session instead stamped a fixed Harness-side sentinel that could never equal a real consumer's own ceiling, so every real evidence-tool containment check failed closed unconditionally (Finding 2, Phase 6 spec-compliance review). It is rejected (DefinitionUnusedPermissionReviewSecurityCeiling) when supplied but no classifiers are configured, mirroring WithPermissionReviewEvidence's own "config X requires config Y" pairing. An empty (or all-whitespace) ceiling is rejected here, immediately, at Define() time — never deferred to a later, harder-to-diagnose review-context-capture failure (gate.ReviewContext's own non-empty SecurityCeiling validation rule already fails closed on an empty value, but silently and much later).
func WithPrimers ¶
func WithRestoreDecider ¶
func WithRestoreDecider(decider session.RestoreDecider) Option
WithRestoreDecider installs the application policy that decides whether a configuration-drifted restore proceeds. It is the successor to WithAllowConfigMismatch: rather than a blanket override, the decider inspects the typed drift assessment and accepts or rejects. Omitting it leaves restore on the fail-secure session.DefaultPolicyDecider (reject on any Warn). A nil decider is rejected at definition time so the option cannot silently disarm the default.
func WithRestoreFailurePolicy ¶ added in v0.27.0
func WithRestoreFailurePolicy(options ...RestoreFailureOption) Option
WithRestoreFailurePolicy installs one fail-closed declarative restore policy. Each Allow…Drift option exempts only its named fact; unlisted warnings remain fatal and exact runtime reconstruction remains the first restore attempt.
func WithRuntimeCatalog ¶
func WithRuntimeCatalog(catalog loop.RuntimeCatalog) Option
WithRuntimeCatalog installs the immutable parent-scoped runtime catalog forwarded to every new and restored session.
func WithRuntimeRestoreResolver ¶ added in v0.27.0
func WithRuntimeRestoreResolver(resolver session.RuntimeRestoreResolver) Option
WithRuntimeRestoreResolver installs the composition-owned policy used only when exact durable runtime reconstruction fails. Omitting it preserves the fail-closed Harness default.
func WithSessionResourceStorage ¶
func WithSessionResourceStorage(provider SessionResourceStorageProvider) Option
WithSessionResourceStorage installs the singleton durable-storage provider used by session-owned resources.
func WithSessionStore ¶
func WithSessionStore(store *sessionstore.Store) Option
func WithSessionWorkspaces ¶
func WithSessionWorkspaces(store *workspacestore.Store, baseDir string) Option
WithSessionWorkspaces declares per-session roots derived as baseDir/<sessionID>, isolated by construction (no root lease).
func WithSharedWorkspace ¶
func WithSharedWorkspace(store *workspacestore.Store, root string) Option
WithSharedWorkspace declares one canonical fixed root shared with concurrent harness sessions, humans, and external tools — deliberately NO root lease; every checkpoint is stamped fuzzy.
func WithSnapshots ¶
func WithSnapshots(policy SnapshotPolicy) Option
func WithToolResultCapture ¶ added in v0.31.0
func WithToolResultCapture(objects loop.ToolResultObjectStore, spillBase string) Option
WithToolResultCapture wires durable tool-result retention: the session object store each loop retains an oversized tool result into, and the ABSOLUTE base directory each session's local capture spill root is created under.
Both are required together. A store with no spill base would hold every capture's retained prefix in host memory up to the capture ceiling, which is exactly the residency a pooled host cannot budget; a spill base with no store would write local files nothing ever uploads. The base must be absolute because a relative one resolves against the process working directory, which is neither session-scoped nor stable for a pooled host, and because it must be comparable against the workspace region at Define time.
The base must ALREADY EXIST, be owner-writable only, and be a directory rather than a symlink, by the time a session is created — harness refuses to create it, because creating it would mean creating through whatever intermediate components the path has, and os.MkdirAll follows a symlinked one silently. Define checks only that the path is absolute, since the base may legitimately be created after the rig is defined; the session's own establishment is the authoritative check and a failure there ends the turn at the spill stage.
The base is a BASE, not a root: each session creates <base>/<sessionID>, owner-only, and removes it at shutdown. Define refuses a base that overlaps the configured workspace region in either direction, which is what keeps a capture spill out of every workspace checkpoint — a checkpoint archives the whole region, so the exclusion has to be a placement invariant rather than a filter some future snapshot path might not consult.
type PermissionReviewLimits ¶
type PermissionReviewLimits struct {
MaxConsecutiveNeedsHuman int
MaxInvalidOrFailed int
MaxIdenticalSubjects int
MaxStaleResponses int
InterruptOnTrip bool
Session PermissionReviewSessionLimits
}
PermissionReviewLimits are the consumer-configurable bounded per-turn and per-session circuit-breaker thresholds (design §18) — the rig-level mirror of sessionruntime.PermissionReviewBreakerLimits. They are deliberately EXCLUDED from the rig fingerprint (fingerprint.go): these are operational tuning knobs, not behavioral identity, so two rigs that agree on classifiers and policy but differ only in these thresholds compare equal.
type PermissionReviewSessionLimits ¶
type PermissionReviewSessionLimits struct {
MaxConsecutiveNeedsHuman int
MaxInvalidOrFailed int
MaxIdenticalSubjects int
MaxStaleResponses int
}
PermissionReviewSessionLimits is PermissionReviewLimits' session-scoped counterpart (design §18: "per-turn AND per-session").
type PersistenceOverlapError ¶
PersistenceOverlapError reports that a discoverable persistence path is equal to or beneath the managed workspace root, so appending a boundary or checkpoint event would mutate the very tree being captured. Persistence must live OUTSIDE the workspace. PersistencePath is the offending canonical path; Root is the canonical workspace root (or per-session base dir) it overlaps.
func (*PersistenceOverlapError) Error ¶
func (e *PersistenceOverlapError) Error() string
type RestoreFailureOption ¶ added in v0.27.0
type RestoreFailureOption interface {
// contains filtered or unexported methods
}
RestoreFailureOption is one declarative exception to Harness's fail-closed restore policy. Implementations are sealed so every option retains bounded, versioned semantics owned by Harness.
func AllowAdapterDrift ¶ added in v0.27.0
func AllowAdapterDrift() RestoreFailureOption
func AllowAgentKindDrift ¶ added in v0.27.0
func AllowAgentKindDrift() RestoreFailureOption
func AllowAgentNameDrift ¶ added in v0.27.0
func AllowAgentNameDrift() RestoreFailureOption
func AllowConfinementDrift ¶ added in v0.27.0
func AllowConfinementDrift() RestoreFailureOption
func AllowCredentialDrift ¶ added in v0.27.0
func AllowCredentialDrift() RestoreFailureOption
func AllowEffortDrift ¶ added in v0.27.0
func AllowEffortDrift() RestoreFailureOption
func AllowExternalCapabilityDrift ¶ added in v0.27.0
func AllowExternalCapabilityDrift() RestoreFailureOption
func AllowHookPolicyDrift ¶ added in v0.27.0
func AllowHookPolicyDrift() RestoreFailureOption
func AllowModelDrift ¶ added in v0.27.0
func AllowModelDrift() RestoreFailureOption
func AllowNativePermissionDrift ¶ added in v0.27.0
func AllowNativePermissionDrift() RestoreFailureOption
func AllowPermissionDrift ¶ added in v0.27.0
func AllowPermissionDrift() RestoreFailureOption
func AllowPermissionPostureDrift ¶ added in v0.27.0
func AllowPermissionPostureDrift() RestoreFailureOption
func AllowPermissionReviewDrift ¶ added in v0.27.0
func AllowPermissionReviewDrift() RestoreFailureOption
func AllowRuntimeCatalogDrift ¶ added in v0.27.0
func AllowRuntimeCatalogDrift() RestoreFailureOption
func AllowRuntimeProfileDrift ¶ added in v0.27.0
func AllowRuntimeProfileDrift() RestoreFailureOption
func AllowRuntimeSkillsDrift ¶ added in v0.27.0
func AllowRuntimeSkillsDrift() RestoreFailureOption
func AllowTrustDrift ¶ added in v0.27.0
func AllowTrustDrift() RestoreFailureOption
func AllowWorkspaceDrift ¶ added in v0.27.0
func AllowWorkspaceDrift() RestoreFailureOption
type Rig ¶
type Rig struct {
// contains filtered or unexported fields
}
Rig is an immutable design-time assembly that creates and restores sessions.
func (*Rig) CaptureSafety ¶ added in v0.31.0
func (r *Rig) CaptureSafety() tool.CaptureSafetyDescriptor
CaptureSafety reports whether this rig's tools are safe to place where a tool result's residency matters: every high-output tool either streams its raw result into the capture sink, or the runtime's finite materialized maximum bounds the fallback.
It is a plain value naming only pkg/tool types, so a placement decision can be taken from it without importing anything that runs a loop — and Harness never imports the consumer that reads it. It is projected at Define time from the tool DEFINITIONS, not from bound tools, because a placement decision has to be takeable before a session exists.
func (*Rig) NewSession ¶
func (r *Rig) NewSession(ctx context.Context, opts ...SessionOption) (session.SessionController, error)
NewSession brings up a brand-new live session. WithSeedSnapshot optionally materializes and commits a seed before any loop starts.
func (*Rig) RestoreSession ¶
type SessionOption ¶
type SessionOption func(*sessionOptions) error
SessionOption configures a single Rig.NewSession call.
func WithSeedSnapshot ¶
func WithSeedSnapshot(ref workspacestore.Ref) SessionOption
WithSeedSnapshot materializes ref into the new session's workspace before constructing loops and journals it as the first workspace checkpoint (design §"Seeding"). It is valid only for per-session roots and an EMPTY exclusive root, never for a shared root, and the ref must resolve in the configured workspace store — all enforced at NewSession, which fails closed on a bad seed.
func WithSessionID ¶ added in v0.33.0
func WithSessionID(id uuid.UUID) SessionOption
WithSessionID makes the new session adopt an externally-minted id instead of minting its own. NewSession then runs its whole per-session durable build under that id: the single-writer lease is acquired for it, the journal is bound to it and stamps its opening LeaseFence, and RestoreSession answers to it afterwards.
WHY A CALLER WOULD WANT THIS. An orchestrator that records the runtime session id in a durable record written BEFORE launch — a catalog binding that is immutable once created — cannot use an id the runtime mints during launch, because the record naming it is already written. The id has to be decidable in advance or the binding cannot name the session at all.
IT DOES NOT CREATE A NEW ORDERING PROBLEM. rig already mints the id first and builds the lease, journal and appenders from it before the session exists — the journal chicken-and-egg the internal sessionruntime.WithSessionID option resolves. This option only replaces that minting step with the caller's value, strictly earlier in the same order; nothing about the id is observable to the caller before NewSession returns that was not already.
THE CALLER OWNS UNIQUENESS, AND THE LEASE IS NOT A SUBSTITUTE FOR IT. Freshness is NOT verified. Passing the id of a session that already exists does not fail and does not create a second session: it re-opens THAT session's durable stream under a fresh grant and appends to it, so a stream can end up with two SessionStarted records and a restore afterwards replays both. The single-writer lease refuses only a LIVE holder, so it stops a concurrent second resident and says nothing at all about a session that has ended or been released. Mint the id with uuid.New (or another source with the same collision properties) and use it once.
A zero id is REFUSED rather than quietly replaced by a minted one, because a caller that reached here with the zero UUID believed it was naming a session and was not, and silently substituting a different id would put a name in its durable record that resolves to nothing. Supplying the option twice is refused for the same reason, including with the same id both times: two calls mean two beliefs about which id this is, and picking one of them is a guess.
It is REQUIRED for NewSession only. RestoreSession takes the id positionally and never consults this.
type SessionOptionError ¶
type SessionOptionError struct {
Kind SessionOptionErrorKind
}
SessionOptionError reports an invalid NewSession option.
func (*SessionOptionError) Error ¶
func (e *SessionOptionError) Error() string
type SessionOptionErrorKind ¶
type SessionOptionErrorKind string
SessionOptionErrorKind classifies a NewSession option failure.
const ( // SessionOptionNil: a nil NewSession option was supplied. SessionOptionNil SessionOptionErrorKind = "nil_option" // SessionOptionDuplicateSeed: WithSeedSnapshot was supplied more than once. SessionOptionDuplicateSeed SessionOptionErrorKind = "duplicate_seed" // SessionOptionEmptySeed: WithSeedSnapshot was given an empty ref. SessionOptionEmptySeed SessionOptionErrorKind = "empty_seed" // SessionOptionDuplicateSessionID: WithSessionID was supplied more than once. SessionOptionDuplicateSessionID SessionOptionErrorKind = "duplicate_session_id" // SessionOptionZeroSessionID: WithSessionID was given the zero UUID. SessionOptionZeroSessionID SessionOptionErrorKind = "zero_session_id" )
type SessionResourceStorage ¶
SessionResourceStorage identifies the durable storage assigned to one session's shared resources. Path and Identity are opaque to Rig definition; the session lifecycle validates and consumes them when it resolves storage.
type SessionResourceStorageProvider ¶
type SessionResourceStorageProvider interface {
StorageForSession(context.Context, uuid.UUID) (SessionResourceStorage, error)
}
SessionResourceStorageProvider resolves durable storage for a session.
A provider is retained by the immutable Rig and may be called concurrently for multiple sessions, so implementations must be safe for concurrent use. Repeated calls for the same non-zero session ID, including after process restart, must resolve the same durable storage identity. The provider retains ownership of its own state; the harness receives only the returned value and does not mutate the provider.
type SnapshotPolicy ¶
type SnapshotPolicy struct {
Trigger SnapshotTrigger
Priority SnapshotPriority
Timeout time.Duration
}
type SnapshotPolicyError ¶
type SnapshotPolicyError struct {
Kind SnapshotPolicyErrorKind
Value int
}
func (*SnapshotPolicyError) Error ¶
func (e *SnapshotPolicyError) Error() string
type SnapshotPolicyErrorKind ¶
type SnapshotPolicyErrorKind string
const ( SnapshotPolicyRequired SnapshotPolicyErrorKind = "required" SnapshotPolicyWithoutWorkspace SnapshotPolicyErrorKind = "without_workspace" SnapshotPolicyInvalidTrigger SnapshotPolicyErrorKind = "invalid_trigger" SnapshotPolicyInvalidPriority SnapshotPolicyErrorKind = "invalid_priority" SnapshotPolicyInvalidTimeout SnapshotPolicyErrorKind = "invalid_timeout" )
type SnapshotPriority ¶
type SnapshotPriority uint8
const ( SnapshotBestEffort SnapshotPriority = iota SnapshotRequired )
type SnapshotTrigger ¶
type SnapshotTrigger uint8
const ( SnapshotTriggerUnset SnapshotTrigger = iota SnapshotManual SnapshotOnIdle SnapshotOnTurnDone SnapshotOnStepDone )
type WorkspacePlacementError ¶
type WorkspacePlacementError struct {
Kind WorkspacePlacementErrorKind
Name string
Cause error
}
WorkspacePlacementError reports an invalid workspace placement declaration at rig.Define.
func (*WorkspacePlacementError) Error ¶
func (e *WorkspacePlacementError) Error() string
func (*WorkspacePlacementError) Unwrap ¶
func (e *WorkspacePlacementError) Unwrap() error
type WorkspacePlacementErrorKind ¶
type WorkspacePlacementErrorKind string
WorkspacePlacementErrorKind classifies a workspace placement validation failure.
const ( // WorkspaceMultiplePlacements: more than one placement option was supplied. Exactly // one of WithExclusiveWorkspace / WithSessionWorkspaces / WithSharedWorkspace may be used. WorkspaceMultiplePlacements WorkspacePlacementErrorKind = "multiple_placements" // WorkspaceNilStore: a placement was given a nil workspace store. WorkspaceNilStore WorkspacePlacementErrorKind = "nil_store" // WorkspaceNilLeaser: an exclusive placement was given a nil root leaser. WorkspaceNilLeaser WorkspacePlacementErrorKind = "nil_leaser" // WorkspaceEmptyRoot: a placement root/base dir was empty or whitespace. WorkspaceEmptyRoot WorkspacePlacementErrorKind = "empty_root" // WorkspaceCanonicalizeFailed: a root/base dir could not be canonicalized. WorkspaceCanonicalizeFailed WorkspacePlacementErrorKind = "canonicalize_failed" // WorkspaceLeaseNameInvalid: the derived root lease name violated the storage grammar. WorkspaceLeaseNameInvalid WorkspacePlacementErrorKind = "lease_name_invalid" // WorkspaceToolWithoutPlacement: a workspace-requiring tool definition with no placement. WorkspaceToolWithoutPlacement WorkspacePlacementErrorKind = "workspace_tool_without_placement" )
type WorkspaceRecoveryError ¶
type WorkspaceRecoveryError = session.WorkspaceRecoveryError
type WorkspaceRootBusyError ¶
type WorkspaceRootBusyError = session.WorkspaceRootBusyError
WorkspaceRootBusyError and WorkspaceRootLeaseLostError are re-exported at the rig composition surface while remaining canonical session lifecycle errors.
type WorkspaceRootLeaseLostError ¶
type WorkspaceRootLeaseLostError = session.WorkspaceRootLeaseLostError