Documentation
¶
Overview ¶
Package tool defines the dependency-free contract surface for the tools subsystem: the BaseTool/InvokableTool interfaces every tool implements, the ToolResult value tools return, the tool-owned preparation boundary (CallPreparer, Request, Requirement, RuleCandidate — see preparation.go), and the optional capability interfaces the runner probes for via type assertion. It imports only core packages (plus stdlib); it must never import pkg/loop, the runtime internals, or a concrete tools module, so all of them can depend on it without a cycle.
Ownership: tools own preparation — decoding untrusted arguments, normalizing commands/URLs/paths, resolving canonical resource identities — and produce the typed prepared Request. The three-state Deny/Gated/Allow decision, the single combined approval, and response routing belong to pkg/gate; sandbox profiles and OS enforcement belong to the enforcing consumer behind structural seams; durable rule persistence is consumer-provided.
Index ¶
- Constants
- func BoundModelFacingErrorDetail(value string) string
- func ModelFacingErrorDetail(err error) (detail string, marked bool)
- func SchemaDigest(schema json.RawMessage) (string, error)
- func ValidateRequest(request Request) error
- type AgentState
- type ArgvRunner
- type AsyncProcessRunner
- type Auditable
- type BaseTool
- type Bindings
- type CallPreparer
- type CommandRunner
- type Definition
- type DelegateAgent
- type DelegateArtifact
- type DelegateController
- type DelegateDeliveryStatus
- type DelegateOperation
- type DelegateRequest
- type DelegateResponseStatus
- type DelegateResult
- type DelegateRuntime
- type DelegateRuntimeExplicit
- type DelegateStatusValue
- type EvidenceFactory
- type EvidenceFactoryBindings
- type EvidenceKindDeclarer
- type EvidenceObservation
- type Factory
- type FileObservation
- type GrantedRunner
- type InvalidBindingsError
- type InvalidDefinitionError
- type InvalidRequirementsError
- type InvalidSchemaError
- type InvokableTool
- type MissingBindingError
- type ModelFacingError
- type MutationPreview
- type MutationPreviewer
- type NilBuiltToolError
- type PreparedArtifact
- type PreparedCall
- type PreparedProcess
- type Process
- type ProcessActivity
- type ProcessActivitySource
- type ProcessBinding
- type ProcessCompletionNotification
- type ProcessCompletionNotifier
- type ProcessError
- type ProcessErrorCode
- type ProcessLifecycleKind
- type ProcessLifecycleMetadata
- type ProcessLifecyclePublisher
- type ProcessLifecycleState
- type ProcessLifecycleValidationError
- type ProcessRequest
- type ProcessResult
- type ProcessSignal
- type ProcessStreamMode
- type ProcessTerminalReason
- type ProducedToolNamesError
- type ProducedToolNamesErrorKind
- type ReadWorkspaceBinding
- type Request
- type RequestValidationError
- type RequestValidationErrorKind
- type Requirement
- type Requirements
- type RuleCandidate
- type Sequential
- type SessionResource
- type SessionResourceRegistry
- type SessionResourceServices
- func (s SessionResourceServices) ProcessCompletionNotifier() ProcessCompletionNotifier
- func (s SessionResourceServices) ProcessLifecyclePublisher() ProcessLifecyclePublisher
- func (s SessionResourceServices) Validate() error
- func (s SessionResourceServices) WorkflowActivityPublisher() WorkflowActivityPublisher
- type SessionResourceServicesValidationError
- type SkillArtifact
- type TokenArtifact
- type ToolExecuteFunc
- type ToolInfo
- type ToolMiddleware
- type ToolResult
- type WorkflowActivityMetadata
- type WorkflowActivityPublisher
- type WorkspaceAccess
- type WorkspaceAccessKind
- type WorkspaceActivityKind
- type WorkspaceBinding
- type WorkspaceCoordinator
- type WorkspaceLifetimeCoordinator
- type WorkspaceObservations
- type WorkspaceOperation
- type WorkspacePermit
- type WriteTarget
Constants ¶
const ( // MaxProcessHandleBytes bounds the opaque URL-safe process identifier. MaxProcessHandleBytes = 128 // MaxProcessDiagnosticBytes bounds the only free-form process lifecycle // detail admitted to durable metadata. MaxProcessDiagnosticBytes = 512 )
const CapabilityCommandExecute = "command.execute"
CapabilityCommandExecute is the normalized capability kind for starting a command. Every prepared command.execute requirement is command-backed: it carries GrantClassCommandStart and the exact normalized command as its grant target.
const GrantClassCommandStart = "command.start.v1"
GrantClassCommandStart is the enforcement class of a single-spawn, exact-command start grant. A saved wildcard or family rule may satisfy the gate decision, but issuance under this class remains exact-command.
const MaxModelFacingErrorBytes = 256 << 10
MaxModelFacingErrorBytes bounds an explicitly model-facing error detail at every boundary where it can be persisted or rendered. It is deliberately shared by the event codec, session runtime, and agent-tool presentation layer.
Variables ¶
This section is empty.
Functions ¶
func BoundModelFacingErrorDetail ¶
BoundModelFacingErrorDetail normalizes invalid UTF-8 and returns a complete rune prefix no larger than MaxModelFacingErrorBytes.
func ModelFacingErrorDetail ¶
ModelFacingErrorDetail finds an explicitly marked error through ordinary Unwrap chains and errors.Join trees. It deliberately does not call errors.As: an error's custom As method is executable code and can fabricate a marker. Traversal is bounded and cycle-aware because errors are external boundary values in the session/runtime path.
func SchemaDigest ¶
func SchemaDigest(schema json.RawMessage) (string, error)
SchemaDigest returns the lowercase hex SHA-256 of a tool's argument JSON Schema, canonicalized with encoding/json's Compact so that insignificant whitespace cannot change a tool's recorded identity. It is the identity projection used for durable external-toolset records: the schema of an externally supplied tool may embed third-party text (descriptions, defaults, examples) that must never reach the journal, so only this digest crosses the boundary.
An empty or nil schema digests as the empty byte string rather than erroring: a schema-less tool is legal (a tool taking no arguments) and has a stable identity. Invalid JSON is a typed error — an unparseable schema has no canonical form, so fabricating a digest over raw bytes would let two different schemas that differ only in whitespace claim different identities while a caller believes the digest is canonical.
func ValidateRequest ¶
ValidateRequest validates all normalized request, requirement, candidate, and exact-command grant invariants.
Types ¶
type AgentState ¶
type AgentState string
AgentState is the bounded mechanical lifecycle state of a persistent child agent.
const ( AgentStateStarting AgentState = "starting" AgentStateWorking AgentState = "working" AgentStateIdle AgentState = "idle" )
type ArgvRunner ¶
type ArgvRunner interface {
RunArgv(ctx context.Context, dir string, argv []string) (output []byte, exitCode int, err error)
}
ArgvRunner runs a direct argv (no shell interpretation) — used by Grep, whose rg invocation is already a safe argv and must not gain a shell.
type AsyncProcessRunner ¶
type AsyncProcessRunner interface {
PrepareProcess(context.Context, ProcessRequest) (PreparedProcess, error)
}
AsyncProcessRunner prepares enforcement for an asynchronous process without spawning it. A successful preparation reserves any enforcement resources needed for the process lifetime.
type Auditable ¶
Auditable is implemented by tools that can emit a redacted, length-capped one-line summary of a call for the ToolCallStarted audit event. The summary must never contain secrets, full file contents, headers, or request bodies.
type BaseTool ¶
BaseTool is the minimal contract: every tool can describe itself. It is never widened — new behavior is added via separate optional capability interfaces, never folded into BaseTool (design Rule 1 / Open-Closed).
type Bindings ¶
type Bindings struct {
SessionID uuid.UUID
LoopID uuid.UUID
Workspace *WorkspaceBinding
ReadWorkspace *ReadWorkspaceBinding
Delegate DelegateController
Process *ProcessBinding
// ExtraTools are additional tool definitions the LOOP appends to every mode's
// toolset at Bind, beyond the definition's own WithTools. The composition root uses
// it to inject the derived, definition-scoped atomic agent-tool bundle (StartAgent,
// MessageAgent, ListAgents, and StopAgent) into a loop WITHOUT mutating the immutable
// loop definition. Per-tool factories never see it (attenuateBindings drops it); only
// loop.Bind consumes it.
ExtraTools []Definition
}
Bindings contains session-specific runtime capabilities supplied to a Definition. SessionID and LoopID must be non-zero. Definitions retain no Bindings between Build calls.
type CallPreparer ¶
type CallPreparer interface {
PrepareCall(ctx context.Context, executionID uuid.UUID, argsJSON string) (Request, PreparedArtifact, error)
}
CallPreparer is the tool-owned preparation boundary: decode and validate the untrusted argsJSON, normalize commands/URLs/paths, resolve canonical resource identities, and produce the typed access Request for this call plus an optional opaque per-call artifact the tool reads back at execution time.
The runner mints executionID once per call and invokes PrepareCall exactly once, before any permission evaluation; invalid input fails here and never reaches the gate. A pure tool returns an empty Request (no requirements). A tool that does NOT implement CallPreparer is treated as an unprepared effectful tool and fails closed: the call is never evaluated or executed.
type CommandRunner ¶
type CommandRunner interface {
RunCommand(ctx context.Context, dir, command string) (output []byte, exitCode int, err error)
}
CommandRunner runs a shell command in a confined environment. A nil runner means direct execution (bare-harness default). Implemented by the sandbox Executor; harness never imports sandbox — the coupling is structural (§10.1).
type Definition ¶
type Definition interface {
Name() string
ProducedToolNames() []string
ToolInfos() []ToolInfo
Requirements() Requirements
Build(context.Context, Bindings) ([]InvokableTool, error)
// contains filtered or unexported methods
}
Definition is immutable tool metadata plus a factory that builds concrete, session-bound tool instances.
func NewBundleDefinition ¶
func NewBundleDefinition(name string, producedToolNames []string, requirements Requirements, factory Factory) Definition
NewBundleDefinition returns an immutable factory-backed definition whose one build produces the declared concrete model-facing tool names. The metadata lets composition fingerprint a bundle without invoking its runtime-bound factory.
func NewDefinition ¶
func NewDefinition(name string, requirements Requirements, factory Factory) Definition
NewDefinition returns an immutable, factory-backed definition. Validation is performed by Build so the constructor remains composable in declarative rig configuration while still returning typed failures at the runtime boundary.
func NewEvidenceDefinition ¶
func NewEvidenceDefinition(name string, requirements Requirements, infos []ToolInfo, factory EvidenceFactory) Definition
NewEvidenceDefinition returns a sealed definition with immutable, model-facing metadata and a capability set limited to RequiresWorkspaceRead. Produced tool names are derived from infos so the two declarations cannot drift.
Validation is performed by Build, matching NewDefinition and NewBundleDefinition's declarative construction behavior.
type DelegateAgent ¶
type DelegateAgent struct {
AgentID uuid.UUID
Name string
AgentType string
State AgentState
QueuedMessages int
Runtime DelegateRuntime
AgentMode string
}
DelegateAgent is the bounded immutable identity and live mechanical state of one directly owned child agent.
type DelegateArtifact ¶
type DelegateArtifact struct {
Request DelegateRequest
Runtime *DelegateRuntime
}
DelegateArtifact is a prepared, fully validated agent-tool call. It is created once in PrepareCall and consumed once in execution by StartAgent, MessageAgent, ListAgents, or StopAgent.
type DelegateController ¶
type DelegateController interface {
Execute(ctx context.Context, request DelegateRequest) (DelegateResult, error)
}
DelegateController is the only delegation capability exposed to a built tool. The runtime binds it to the tool's parent; tools never receive a session controller.
type DelegateDeliveryStatus ¶
type DelegateDeliveryStatus string
DelegateDeliveryStatus identifies how a message reached (or failed to reach) its target. It is intentionally separate from the target response's terminal status.
const ( DelegateDeliveryAcceptedPending DelegateDeliveryStatus = "accepted_pending" DelegateDeliveryInjected DelegateDeliveryStatus = "injected" DelegateDeliveryQueued DelegateDeliveryStatus = "queued" DelegateDeliveryRejected DelegateDeliveryStatus = "rejected" DelegateDeliveryUnknown DelegateDeliveryStatus = "delivery_unknown" DelegateDeliveryUntrackable DelegateDeliveryStatus = "delivered_untrackable" )
type DelegateOperation ¶
type DelegateOperation uint8
DelegateOperation identifies an operation on a parent-scoped delegate.
const ( DelegateStart DelegateOperation = iota + 1 DelegateSend DelegateInterrupt DelegateStatus )
type DelegateRequest ¶
type DelegateRequest struct {
Operation DelegateOperation
AgentID uuid.UUID
AgentType string
Name string
AgentMode string
Message string
WaitForResponse bool
TimeoutSeconds *int
ParentToolUseID string
// Runtime is the prepared, catalog-resolved agent-harness/model/effort tuple
// for a DelegateStart; nil for every other operation and for a start with no
// runtime choice. The controller re-resolves it against its OWN parent-scoped
// RuntimeCatalog before applying it (defense in depth) rather than trusting
// this value as final.
Runtime *DelegateRuntime
}
DelegateRequest is the typed command passed to a parent-scoped delegate controller. Fields not used by the selected Operation remain zero-valued.
AgentMode is the requested initial mode for a DelegateStart; the empty string means "use the target definition's initial mode". AgentType and AgentMode carry the untrusted model selection as plain strings (this package does not import the loop/identity domain types); the controller resolves and validates them.
TimeoutSeconds bounds one response. nil means an interruptible, unbounded response (only the parent turn's own cancellation can end it); a non-nil value is a non-negative second count after which the controller returns a typed timed-out result. A negative value is invalid and rejected by the envelope boundary.
type DelegateResponseStatus ¶
type DelegateResponseStatus uint8
DelegateResponseStatus is the terminal status of one agent response. It is intentionally separate from the persistent agent's lifecycle state.
const ( DelegateResponseUnknown DelegateResponseStatus = iota DelegateResponseCompleted DelegateResponseInterrupted DelegateResponseFailed DelegateResponseTimedOut )
type DelegateResult ¶
type DelegateResult struct {
AgentID uuid.UUID
Name string
State AgentState
DeliveryStatus DelegateDeliveryStatus
Response string
ResponseStatus DelegateResponseStatus
// CorrelationID is an internal command/response identity used by session
// orchestration. Agent tools never encode or accept it.
CorrelationID uuid.UUID
PreviousState AgentState
Agents []DelegateAgent
Truncated bool
}
DelegateResult is the typed result of a delegate-controller operation.
type DelegateRuntime ¶
type DelegateRuntime struct {
Harness string
Profile string
Source string
SelectionKind string
Model string
SmallModel string
Effort string
Explicit DelegateRuntimeExplicit
}
DelegateRuntime is the dependency-safe representation of a resolved child runtime. The delegation package converts the loop catalog's named types into these stable aliases at the preparation boundary; pkg/tool deliberately does not import pkg/loop.
type DelegateRuntimeExplicit ¶
DelegateRuntimeExplicit records which selectors were supplied by the caller. Defaults are resolved into the same concrete runtime fields, but remain distinguishable for downstream pinning and audit decisions.
type DelegateStatusValue ¶
type DelegateStatusValue uint8
DelegateStatusValue is the pre-agent mechanical/terminal vocabulary retained temporarily inside session orchestration. It is not part of DelegateResult and cannot reach model-facing agent JSON. Phase 3 removes its wait collector.
const ( DelegateStatusUnknown DelegateStatusValue = iota DelegateStatusRunning DelegateStatusCompleted DelegateStatusInterrupted DelegateStatusFailed DelegateStatusTimedOut DelegateStatusQueued DelegateStatusIdle )
type EvidenceFactory ¶
type EvidenceFactory func(context.Context, EvidenceFactoryBindings) ([]InvokableTool, error)
EvidenceFactory builds concrete, read-only evidence tools for one invocation origin. It may be called concurrently and must not retain or mutate bindings after returning.
type EvidenceFactoryBindings ¶
type EvidenceFactoryBindings struct {
SessionID uuid.UUID
LoopID uuid.UUID
ReadWorkspace *ReadWorkspaceBinding
}
EvidenceFactoryBindings contains the complete capability set supplied to an evidence factory for one invocation origin. It deliberately has no generic workspace, mutation coordinator, observations, delegation, session, gate, grant, control, or extra-tool capability.
type EvidenceKindDeclarer ¶
type EvidenceKindDeclarer interface {
EvidenceRequirementKinds() []string
}
EvidenceKindDeclarer is an optional capability (probed by type assertion, mirroring Sequential/Auditable/WriteTarget) implemented by an evidence Definition that can enumerate — independent of any session, loop, or specific call's arguments — every Requirement.Kind value its built tools may ever produce via CallPreparer.PrepareCall. Evidence-policy construction (internal/hustleruntime) uses it to fail fast when a declared kind is outside the consumer's AllowedKinds allowlist, rather than discovering the mismatch lazily as an EvidenceFailureForbiddenCapability on the tool's first real evidence call. A Definition implementing none of this is still a fully valid evidence definition; its produced kinds are still checked per-call (unchanged).
type EvidenceObservation ¶
type EvidenceObservation interface {
ObservedRequirement(request Request, result *ToolResult) (target string, token string, ok bool)
}
EvidenceObservation is an optional capability (probed by type assertion, mirroring Sequential/Auditable/WriteTarget) implemented by a target-sensitive evidence tool that can derive the canonical-identity/token pair it observed for one completed call from that call's own prepared Request and produced ToolResult (design §13.4, TOCTOU). It is probed only AFTER a successful InvokableRun, from the evidence runtime's per-call loop (internal/hustleruntime/evidence_runner.go) — never before, and never for a call that failed.
Harness never computes, interprets, or canonicalizes target or token itself: deriving canonical identity and minting a stable token from observed metadata is entirely tool/consumer-owned, the same reasoning gate.EvidenceContainmentVerifier's own doc comment gives for why Harness does not own path canonicalization. This package cannot name that gate type directly (pkg/gate imports pkg/tool, so the reverse would cycle), which is why the method returns plain strings rather than a gate.ObservationRequirement — the evidence runtime, which already imports both packages, does that conversion (and validation) at the call site.
ok=false means this particular call made no target-sensitive observation (for example a glob/grep-style tool that matched many candidates rather than resolving one canonical target) — nothing is recorded, and evidence execution and authorization are completely unaffected either way. A tool implementing none of this capability simply never contributes an observation for any of its calls; it is still a fully valid evidence tool.
type Factory ¶
type Factory func(context.Context, Bindings) ([]InvokableTool, error)
Factory builds concrete tools for one runtime binding. It may be invoked concurrently by separate Build calls and must synchronize any shared captured state. Per-build mutable state belongs inside each invocation. A Factory must not return nil tools.
type FileObservation ¶
FileObservation is the private concurrency token standard file tools keep for one canonical path. It never appears in model output, events, or audit summaries.
type GrantedRunner ¶
type GrantedRunner interface {
RunCommandWithGrants(ctx context.Context, dir, command string, grants []string) (output []byte, exitCode int, err error)
}
GrantedRunner is an optional capability (probed by type assertion) for running a command with escalation grant tokens. Wiring the grant flow is a later task; the interface lives here with the others.
type InvalidBindingsError ¶
InvalidBindingsError reports a present but invalid runtime binding.
func (*InvalidBindingsError) Error ¶
func (e *InvalidBindingsError) Error() string
func (*InvalidBindingsError) Unwrap ¶
func (e *InvalidBindingsError) Unwrap() error
type InvalidDefinitionError ¶
type InvalidDefinitionError struct{ Field string }
InvalidDefinitionError reports invalid immutable definition metadata.
func (*InvalidDefinitionError) Error ¶
func (e *InvalidDefinitionError) Error() string
type InvalidRequirementsError ¶
type InvalidRequirementsError struct{ Unknown Requirements }
InvalidRequirementsError reports requirement bits unknown to this package.
func (*InvalidRequirementsError) Error ¶
func (e *InvalidRequirementsError) Error() string
type InvalidSchemaError ¶
type InvalidSchemaError struct{ Cause error }
InvalidSchemaError reports that a tool's advertised argument schema is not valid JSON, so it has no canonical form to digest. Callers errors.As it to distinguish a malformed tool self-description from a transport or build failure.
func (*InvalidSchemaError) Error ¶
func (e *InvalidSchemaError) Error() string
func (*InvalidSchemaError) Unwrap ¶
func (e *InvalidSchemaError) Unwrap() error
type InvokableTool ¶
type InvokableTool interface {
BaseTool
InvokableRun(ctx context.Context, argsJSON string) (*ToolResult, error)
}
InvokableTool is a BaseTool that can be executed with JSON-encoded arguments. argsJSON is the untrusted, model-supplied argument object; the implementation is responsible for parsing and validating it.
type MissingBindingError ¶
type MissingBindingError struct{ Requirement Requirements }
MissingBindingError reports a required runtime capability that was absent.
func (*MissingBindingError) Error ¶
func (e *MissingBindingError) Error() string
type ModelFacingError ¶
type ModelFacingError interface {
ModelFacingError() string
}
ModelFacingError is the narrow opt-in marker for an error detail that is safe to expose to the model. The marker is intentionally not inferred from Error, a stable error kind, or any other ordinary error text.
type MutationPreview ¶ added in v0.29.0
MutationPreview is the display-and-review payload for a pending filesystem mutation: what the human is being asked to authorize, rendered by the tool that prepared it. Its zero value means no preview.
UnifiedDiff is OPAQUE to harness. Harness carries it to the live event and to a permission classifier's review context and never parses, trims, or interprets it. Bounding is the producing tool's job, because only the tool knows where a hunk ends.
A MutationPreview is never journaled and never reaches the agent model. See docs/plans/2026-08-23-gate-diff-preview-design.md.
type MutationPreviewer ¶ added in v0.29.0
type MutationPreviewer interface {
MutationPreview() (MutationPreview, bool)
}
MutationPreviewer is implemented by a prepared artifact that can describe its pending change.
The implementation performs I/O and is called ONLY at gate-open, never during PrepareCall: a PrepareCall error reaches the model with no gate opening, so preview failures raised there would be an ungated oracle over arbitrary host files. ok is false for ANY failure, and a false ok must leave the prepared request, the tool result, and the model-visible error exactly as they were.
type NilBuiltToolError ¶
type NilBuiltToolError struct{ Index int }
NilBuiltToolError reports a nil factory result. Index is -1 when the returned slice itself is nil, otherwise it identifies the nil element.
func (*NilBuiltToolError) Error ¶
func (e *NilBuiltToolError) Error() string
type PreparedArtifact ¶
type PreparedArtifact interface {
// contains filtered or unexported methods
}
PreparedArtifact is the opaque, per-call artifact a CallPreparer produces — read by the producing tool at both PrepareCall and InvokableRun time, opaque to the runner. Sealed via an unexported marker so only deliberate types satisfy it (no bare any): a type in another package cannot supply the unexported method, so it cannot masquerade as a PreparedArtifact. Concrete artifacts therefore live in this package alongside the seal.
type PreparedCall ¶
type PreparedCall struct {
ExecutionID uuid.UUID
Request Request
Artifact PreparedArtifact
Grants []string
}
PreparedCall is the prepared execution contract for one tool call: the minted execution ID, the validated typed Request, the tool's opaque per-call artifact, and — after the combined gate resolves — the fresh execution-bound grant tokens issued for THIS call. Tokens travel only here, never in an ambient grant context, a prompt, a journal, or an audit record. The Grants slice is owned by the runner; readers must not mutate it.
type PreparedProcess ¶
type PreparedProcess interface {
EffectiveWorkspaceAccess() WorkspaceAccess
Start(context.Context) (Process, error)
Close() error
}
PreparedProcess is a validated, reserved process start. Its effective workspace access is authoritative and immutable. Start consumes the preparation at most once; Close releases an unstarted preparation. EffectiveWorkspaceAccess returns a deep value that shares no mutable backing storage with the preparation or with values returned by earlier calls.
The Start context governs setup through process handoff only. Once Start returns a Process, that process lives until Wait, Close, its deadline, or runner shutdown independently of the Start context.
type Process ¶
type Process interface {
Stdout() io.ReadCloser
Stderr() io.ReadCloser
Stdin() io.WriteCloser
StreamMode() ProcessStreamMode
Wait(context.Context) (ProcessResult, error)
Resize(context.Context, uint16, uint16) error
Signal(context.Context, ProcessSignal) error
Close(context.Context) error
}
Process is a running asynchronous process. Streams are available immediately after Start. StreamMode reports a valid, unambiguous pipe or PTY shape and must match the admitted ProcessRequest; implementations must never silently fall back to a different stream mode.
Methods other than Wait are safe to call concurrently with each other and with stream I/O. Signal targets the complete process tree. Close is idempotent. The supervising owner is the sole Wait caller and calls it exactly once; Wait confirms process-tree exit before returning.
The returned stdin supports concurrent Write and Close calls. Closing it is idempotent, delivers EOF to the process at most once, and causes later writes to fail.
Process deliberately exposes no OS process identifier. A model-facing process handle belongs in the supervising tool layer, not this runner layer.
type ProcessActivity ¶
type ProcessActivity struct {
Kind WorkspaceActivityKind
}
ProcessActivity reports workspace activity from a running process. Every activity invalidates the complete observation cache bound to that process; scoped observation paths are intentionally not represented.
func (ProcessActivity) EffectiveKind ¶
func (a ProcessActivity) EffectiveKind() WorkspaceActivityKind
EffectiveKind returns the conservative activity classification. Invalid activity always maps to broad invalidation and can never narrow the immutable lifetime workspace lease.
type ProcessActivitySource ¶
type ProcessActivitySource interface {
Activities() <-chan ProcessActivity
}
ProcessActivitySource is an optional capability implemented by a Process that can report workspace activity. The activity channel must close before Process.Wait returns.
type ProcessBinding ¶
type ProcessBinding struct {
Registry SessionResourceRegistry
}
ProcessBinding contains the session-scoped capabilities supplied to process tool definitions.
type ProcessCompletionNotification ¶
type ProcessCompletionNotification struct {
CommandID uuid.UUID `json:"command_id,omitzero"`
SessionID uuid.UUID `json:"session_id,omitzero"`
LoopID uuid.UUID `json:"loop_id,omitzero"`
ProcessHandle string `json:"process_handle"`
State ProcessLifecycleState `json:"state"`
Reason ProcessTerminalReason `json:"reason"`
}
ProcessCompletionNotification is the bounded terminal notification submitted to the owning loop.
func (ProcessCompletionNotification) Validate ¶
func (n ProcessCompletionNotification) Validate() error
Validate checks stable identity, the bounded process handle, and one of the terminal state/reason pairs accepted by completed or lost lifecycle records.
type ProcessCompletionNotifier ¶
type ProcessCompletionNotifier interface {
NotifyProcessCompletion(context.Context, ProcessCompletionNotification) error
}
ProcessCompletionNotifier submits a bounded process terminal notification to the process owner's loop.
type ProcessError ¶
type ProcessError struct {
Code ProcessErrorCode
Cause error
}
ProcessError reports a classified asynchronous-runner failure. Cause carries implementation detail for programmatic inspection and trusted logs; callers should expose only Code at untrusted boundaries.
func (*ProcessError) Error ¶
func (e *ProcessError) Error() string
func (*ProcessError) Is ¶
func (e *ProcessError) Is(target error) bool
Is matches ProcessError values by stable code.
func (*ProcessError) Unwrap ¶
func (e *ProcessError) Unwrap() error
Unwrap returns the underlying runner failure, if any.
type ProcessErrorCode ¶
type ProcessErrorCode string
ProcessErrorCode is a stable asynchronous-runner failure classification.
const ( ProcessErrorSpawnFailed ProcessErrorCode = "spawn_failed" ProcessErrorSetupFailed ProcessErrorCode = "process_setup_failed" ProcessErrorSignalFailed ProcessErrorCode = "signal_failed" ProcessErrorWaitFailed ProcessErrorCode = "wait_failed" ProcessErrorTeardownFailed ProcessErrorCode = "teardown_failed" )
func (ProcessErrorCode) Valid ¶
func (c ProcessErrorCode) Valid() bool
Valid reports whether c is a recognized asynchronous-runner error code.
type ProcessLifecycleKind ¶
type ProcessLifecycleKind uint8
ProcessLifecycleKind identifies one of the five durable process lifecycle record shapes.
const ( ProcessLifecycleStarted ProcessLifecycleKind = iota + 1 ProcessLifecycleBackgrounded ProcessLifecycleCompleted ProcessLifecycleStopRequested ProcessLifecycleLost )
func (ProcessLifecycleKind) Valid ¶
func (k ProcessLifecycleKind) Valid() bool
Valid reports whether k belongs to the closed lifecycle kind domain.
type ProcessLifecycleMetadata ¶
type ProcessLifecycleMetadata struct {
EventID uuid.UUID `json:"event_id,omitzero"`
Kind ProcessLifecycleKind `json:"kind"`
SessionID uuid.UUID `json:"session_id,omitzero"`
LoopID uuid.UUID `json:"loop_id,omitzero"`
ProcessHandle string `json:"process_handle"`
OriginExecutionID uuid.UUID `json:"origin_execution_id,omitzero"`
State ProcessLifecycleState `json:"state"`
ProcessCreatedAt time.Time `json:"process_created_at"`
ProcessStartedAt time.Time `json:"process_started_at,omitzero"`
ProcessFinishedAt time.Time `json:"process_finished_at,omitzero"`
HasExitCode bool `json:"has_exit_code,omitzero"`
ExitCode int32 `json:"exit_code,omitzero"`
Reason ProcessTerminalReason `json:"reason,omitzero"`
Diagnostic string `json:"diagnostic,omitzero"`
}
ProcessLifecycleMetadata is the bounded, neutral process lifecycle payload shared with Harness. It intentionally excludes commands, output, stdin, environment, host paths, spool paths, and OS process identifiers.
func (ProcessLifecycleMetadata) Validate ¶
func (m ProcessLifecycleMetadata) Validate() error
Validate checks the closed kind/state/reason matrix, stable identity, bounded strings, process-clock ordering, and exit-code presence contract.
type ProcessLifecyclePublisher ¶
type ProcessLifecyclePublisher interface {
PublishProcessLifecycle(context.Context, ProcessLifecycleMetadata) error
}
ProcessLifecyclePublisher durably publishes bounded, metadata-only process lifecycle transitions.
type ProcessLifecycleState ¶
type ProcessLifecycleState uint8
ProcessLifecycleState is the portable state carried by lifecycle records and process completion notifications.
const ( ProcessLifecycleStarting ProcessLifecycleState = iota + 1 ProcessLifecycleRunning ProcessLifecycleExited ProcessLifecycleFailed ProcessLifecycleTimedOut ProcessLifecycleInterrupted ProcessLifecycleTerminated ProcessLifecycleKilled ProcessLifecycleLostOnRestore )
func (ProcessLifecycleState) Valid ¶
func (s ProcessLifecycleState) Valid() bool
Valid reports whether s belongs to the closed lifecycle state domain.
type ProcessLifecycleValidationError ¶
type ProcessLifecycleValidationError struct {
Field string
}
ProcessLifecycleValidationError identifies the first invalid lifecycle or completion-notification field.
func (*ProcessLifecycleValidationError) Error ¶
func (e *ProcessLifecycleValidationError) Error() string
type ProcessRequest ¶
type ProcessRequest struct {
Command string
Directory string
Grants []string
OriginExecutionID uuid.UUID
Deadline time.Time
PTY bool
}
ProcessRequest describes one shell-agnostic asynchronous process admission. Grants are opaque, execution-bound tokens. Deadline is the process lifetime deadline. A zero Deadline means no process deadline and must never be replaced by a runner default; session or runner shutdown still terminates the process.
func (ProcessRequest) Clone ¶
func (r ProcessRequest) Clone() ProcessRequest
Clone returns a deep copy sharing no slice backing storage with the receiver.
func (ProcessRequest) HasDeadline ¶
func (r ProcessRequest) HasDeadline() bool
HasDeadline reports whether the request defines a process lifetime deadline.
type ProcessResult ¶
type ProcessResult struct {
ExitCode int
Reason ProcessTerminalReason
StartedAt time.Time
FinishedAt time.Time
}
ProcessResult is the terminal result of an asynchronous process. ExitCode is the portable executable exit status. StartedAt and FinishedAt are runner timestamps. OS process identifiers are intentionally excluded.
type ProcessSignal ¶
type ProcessSignal uint8
ProcessSignal is a portable process-tree signal request.
const ( ProcessSignalInterrupt ProcessSignal = iota + 1 ProcessSignalTerminate ProcessSignalKill )
func (ProcessSignal) Valid ¶
func (s ProcessSignal) Valid() bool
Valid reports whether s is a recognized portable signal.
type ProcessStreamMode ¶
type ProcessStreamMode uint8
ProcessStreamMode describes the running process's stream topology.
const ( // ProcessStreamModePipes exposes distinct non-nil Stdout and Stderr pipe // readers. ProcessStreamModePipes ProcessStreamMode = iota + 1 // ProcessStreamModePTY exposes combined terminal bytes through Stdout. // Stderr remains non-nil but is closed and empty. ProcessStreamModePTY )
func (ProcessStreamMode) Valid ¶
func (m ProcessStreamMode) Valid() bool
Valid reports whether m is a recognized process stream mode.
type ProcessTerminalReason ¶
type ProcessTerminalReason uint8
ProcessTerminalReason classifies why a process reached a terminal state.
const ( ProcessTerminalExited ProcessTerminalReason = iota + 1 ProcessTerminalTimedOut ProcessTerminalInterrupted ProcessTerminalTerminated ProcessTerminalKilled ProcessTerminalRunnerShutdown ProcessTerminalFailed ProcessTerminalOutputLimit ProcessTerminalLostOnRestore )
func (ProcessTerminalReason) Valid ¶
func (r ProcessTerminalReason) Valid() bool
Valid reports whether r is a recognized terminal reason.
type ProducedToolNamesError ¶
type ProducedToolNamesError struct {
Kind ProducedToolNamesErrorKind
Index int
Name string
Declared []string
Actual []string
Cause error
}
ProducedToolNamesError reports that immutable produced-name metadata is invalid or does not exactly describe the concrete tools returned by Build. Declared and Actual contain normalized, sorted names for a set mismatch.
func (*ProducedToolNamesError) Error ¶
func (e *ProducedToolNamesError) Error() string
func (*ProducedToolNamesError) Unwrap ¶
func (e *ProducedToolNamesError) Unwrap() error
type ProducedToolNamesErrorKind ¶
type ProducedToolNamesErrorKind string
ProducedToolNamesErrorKind identifies a fail-closed produced-name metadata violation discovered while binding a definition.
const ( ProducedToolNameEmpty ProducedToolNamesErrorKind = "declared_name_empty" ProducedToolNameDuplicate ProducedToolNamesErrorKind = "declared_name_duplicate" BuiltToolInfoInvalid ProducedToolNamesErrorKind = "built_tool_info_invalid" BuiltToolNameEmpty ProducedToolNamesErrorKind = "built_tool_name_empty" BuiltToolNameDuplicate ProducedToolNamesErrorKind = "built_tool_name_duplicate" ProducedToolNamesMismatch ProducedToolNamesErrorKind = "produced_names_mismatch" )
type ReadWorkspaceBinding ¶
type ReadWorkspaceBinding struct {
Root string
}
ReadWorkspaceBinding is the structurally read-only workspace capability supplied to evidence definitions. Root is absolute, clean, and canonicalized by the consumer before Build. This type intentionally exposes no mutation, observation, delegation, gate, grant, or control capability.
type Request ¶
type Request struct {
ToolName string `json:"tool_name,omitempty"`
Summary string `json:"summary,omitempty"`
ExecutionID string `json:"execution_id,omitempty"`
Command string `json:"command,omitempty"`
WorkingDirectory string `json:"working_directory,omitempty"`
ExpiresAtUnixMilli int64 `json:"expires_at_unix_milli,omitempty"`
Requirements []Requirement `json:"requirements,omitempty"`
}
Request is a prepared, validated access request. Execution binding fields are required whenever any requirement requests a grant. They are ordinary grant inputs, never minted token material. Pure tools may prepare an empty request with no requirements.
type RequestValidationError ¶
type RequestValidationError struct {
Kind RequestValidationErrorKind
Field string
}
RequestValidationError reports a prepared-request invariant violation.
func (*RequestValidationError) Error ¶
func (e *RequestValidationError) Error() string
type RequestValidationErrorKind ¶
type RequestValidationErrorKind string
RequestValidationErrorKind classifies an invalid prepared request.
const ( RequestFieldInvalid RequestValidationErrorKind = "field_invalid" RequestRequirementsDuplicate RequestValidationErrorKind = "requirement_duplicate" RequestCandidatesDuplicate RequestValidationErrorKind = "candidate_duplicate" RequestGrantPairInvalid RequestValidationErrorKind = "grant_pair_invalid" RequestCommandGrantInvalid RequestValidationErrorKind = "command_grant_invalid" RequestGrantBindingMissing RequestValidationErrorKind = "grant_binding_missing" )
type Requirement ¶
type Requirement struct {
Kind string `json:"kind"`
Scope string `json:"scope"`
Match string `json:"match"`
Description string `json:"description"`
GrantClass string `json:"grant_class,omitempty"`
GrantTarget string `json:"grant_target,omitempty"`
Candidates []RuleCandidate `json:"candidates,omitempty"`
}
Requirement describes one normalized capability needed by a prepared tool call. Scope is used only for access routing, Match only for stored-rule matching, and Description only for bounded display. GrantClass and GrantTarget are an optional pair: both empty means the direct tool enforces the approved resource itself, while a populated pair requests one post-decision executor grant.
func (Requirement) Clone ¶
func (r Requirement) Clone() Requirement
Clone returns a deep copy sharing no backing storage with the receiver.
type Requirements ¶
type Requirements uint8
Requirements is the set of runtime capabilities a Definition needs before it can build concrete tools.
const ( // RequiresWorkspace marks definitions that build workspace-bound tools. RequiresWorkspace Requirements = 1 << iota // RequiresDelegateController marks definitions that build delegation tools. RequiresDelegateController // RequiresWorkspaceRead marks definitions that only need the canonical // workspace root for read-only evidence collection. RequiresWorkspaceRead // RequiresProcessServices marks definitions that build session-supervised // process tools. RequiresProcessServices )
type RuleCandidate ¶
type RuleCandidate struct {
Kind string `json:"kind"`
Match string `json:"match"`
Description string `json:"description"`
GrantClass string `json:"grant_class,omitempty"`
GrantTarget string `json:"grant_target,omitempty"`
}
RuleCandidate is the exact reusable allow rule displayed to the user and offered for durable persistence after a workspace approval. It contains no grant or token material; GrantClass and GrantTarget describe only the structural enforcement contract a future match must preserve.
type Sequential ¶
type Sequential interface {
Sequential() bool
}
Sequential is implemented by tools that must not run concurrently with other tool calls in the same batch. Sequential() reports whether this call must be serialized.
type SessionResource ¶
type SessionResource interface {
Activate(context.Context, SessionResourceServices) error
Shutdown(context.Context) error
}
SessionResource is session-owned state shared by tool definitions. Activate late-binds live session services after construction and restore planning; Shutdown releases the resource during session teardown.
type SessionResourceRegistry ¶
type SessionResourceRegistry interface {
GetOrCreate(context.Context, string, func(string) (SessionResource, error)) (SessionResource, error)
}
SessionResourceRegistry atomically resolves one session-owned resource by key. The factory receives a private storage directory reserved for that key.
type SessionResourceServices ¶
type SessionResourceServices struct {
// contains filtered or unexported fields
}
SessionResourceServices is the immutable late-bound service set supplied to every session resource after the live session has been constructed. Its zero value is invalid; use NewSessionResourceServices.
func NewSessionResourceServices ¶
func NewSessionResourceServices( publisher ProcessLifecyclePublisher, notifier ProcessCompletionNotifier, workflowPublisher WorkflowActivityPublisher, ) (SessionResourceServices, error)
NewSessionResourceServices constructs an immutable, fully populated service set and rejects both nil interfaces and interfaces containing typed nils.
func (SessionResourceServices) ProcessCompletionNotifier ¶
func (s SessionResourceServices) ProcessCompletionNotifier() ProcessCompletionNotifier
ProcessCompletionNotifier returns the validated completion notifier.
func (SessionResourceServices) ProcessLifecyclePublisher ¶
func (s SessionResourceServices) ProcessLifecyclePublisher() ProcessLifecyclePublisher
ProcessLifecyclePublisher returns the validated lifecycle publisher.
func (SessionResourceServices) Validate ¶
func (s SessionResourceServices) Validate() error
Validate reports whether the service set is safe to give to a session resource.
func (SessionResourceServices) WorkflowActivityPublisher ¶
func (s SessionResourceServices) WorkflowActivityPublisher() WorkflowActivityPublisher
WorkflowActivityPublisher returns the validated trusted workflow publisher.
type SessionResourceServicesValidationError ¶
type SessionResourceServicesValidationError struct {
Field string
}
SessionResourceServicesValidationError reports a missing or typed-nil late-bound session service.
func (*SessionResourceServicesValidationError) Error ¶
func (e *SessionResourceServicesValidationError) Error() string
type SkillArtifact ¶
type SkillArtifact struct {
Workspace bool // true for an untrusted workspace snapshot
RelPath string // workspace-relative source path, e.g. ".skills/<name>/SKILL.md"
Size int64 // snapshot length in bytes
SHA256 string // full hex SHA-256 of the snapshot bytes
Body string // the parsed markdown body to inject (the approved bytes)
}
SkillArtifact is the concrete PreparedArtifact a workspace-skill preparation step produces: a single TOCTOU-safe snapshot of an untrusted `.skills/<name>/SKILL.md` taken ONCE — before the permission prompt — and bound to the call (design §7a). It satisfies the sealed PreparedArtifact interface via the unexported preparedArtifact marker, so it must live in this package alongside the seal; a type in another package cannot supply the marker and so cannot masquerade as a PreparedArtifact.
One artifact carries BOTH halves of the load:
- the snapshot Body — read at execution time so the bytes that run are EXACTLY the bytes that were approved (never a re-open, which a workspace writer could swap between prompt and execution);
- the metadata + hash (RelPath, Size, SHA256) — surfaced for the human gate, which renders the metadata but never the Body.
Workspace distinguishes a workspace (untrusted, gated) snapshot from any future trusted source; embedded skills are auto-approved and need no artifact.
type TokenArtifact ¶
type TokenArtifact struct{ Token string }
TokenArtifact is the minimal concrete PreparedArtifact: it carries a single opaque Token (e.g. a content hash or a callID-bound nonce) that the producing tool reads at both PrepareCall and InvokableRun time. It is the simplest artifact a CallPreparer can return when the bound value is a single string; richer CallPreparers declare their own concrete artifact type in this package.
type ToolExecuteFunc ¶
type ToolExecuteFunc func(ctx context.Context, argsJSON string) (*ToolResult, error)
ToolExecuteFunc is the terminal/next step in a middleware chain: it runs the tool against argsJSON and returns its result.
type ToolInfo ¶
type ToolInfo struct {
Name string
Desc string
Schema json.RawMessage
}
ToolInfo is a tool's self-description. Schema is a JSON Schema describing the tool's argument object; it maps 1:1 to inference.Tool.Schema.
type ToolMiddleware ¶
type ToolMiddleware func(ctx context.Context, t InvokableTool, argsJSON string, next ToolExecuteFunc) (*ToolResult, error)
ToolMiddleware wraps tool execution. It receives the tool, the (untrusted) argsJSON, and the next step in the chain; it may run logic before/after and must call next to proceed (or short-circuit by not calling it).
type ToolResult ¶
ToolResult is the value an InvokableTool returns. Content must hold at least one block; the runner injects an "error: empty result" block when it is nil or empty. There is intentionally no Terminate field in v1 — a turn ends only via the model emitting no more tool calls or an abort.
func TextResult ¶
func TextResult(s string) *ToolResult
TextResult is the convenience constructor for the common single-text-block result. It always returns a non-nil *ToolResult holding exactly one *content.TextBlock, even for the empty string.
type WorkflowActivityMetadata ¶
type WorkflowActivityMetadata struct {
EventID uuid.UUID `json:"event_id,omitzero"`
SessionID uuid.UUID `json:"session_id,omitzero"`
RunID uuid.UUID `json:"run_id"`
WorkflowName string `json:"workflow_name"`
WorkflowVersion string `json:"workflow_version"`
Kind string `json:"kind"`
Status string `json:"status"`
VertexID uuid.UUID `json:"vertex_id,omitzero"`
VertexLabel string `json:"vertex_label,omitempty"`
CompletedVertices uint32 `json:"completed_vertices,omitzero"`
TotalVertices uint32 `json:"total_vertices,omitzero"`
Message string `json:"message,omitempty"`
OccurredAt time.Time `json:"occurred_at"`
}
WorkflowActivityMetadata is the transport-neutral, bounded input to the trusted workflow publication seam. EventID is a stable source activity ID and must be preserved across retries; the session runtime uses the validated OccurredAt as the stable creation envelope when it stamps the sealed event.
type WorkflowActivityPublisher ¶
type WorkflowActivityPublisher interface {
PublishWorkflowActivity(context.Context, WorkflowActivityMetadata) error
}
WorkflowActivityPublisher durably publishes bounded workflow lifecycle metadata for one owning Harness session. The neutral DTO keeps pkg/tool below the sealed event package in the dependency graph; the session runtime converts it into event.WorkflowActivity and validates it before the Hub/journal path.
type WorkspaceAccess ¶
type WorkspaceAccess struct {
Kind WorkspaceAccessKind
// contains filtered or unexported fields
}
WorkspaceAccess is the runner's authoritative, immutable description of a prepared process's workspace access. WritePaths are canonical individual paths and WriteTrees are canonical directory trees. They are meaningful only for WorkspaceAccessScopedWrite.
func NewWorkspaceAccess ¶
func NewWorkspaceAccess( kind WorkspaceAccessKind, writePaths []string, writeTrees []string, ) WorkspaceAccess
NewWorkspaceAccess constructs an access description without retaining the caller's path slices.
func (WorkspaceAccess) Clone ¶
func (a WorkspaceAccess) Clone() WorkspaceAccess
Clone returns a deep copy sharing no slice backing storage with the receiver.
func (WorkspaceAccess) WritePaths ¶
func (a WorkspaceAccess) WritePaths() []string
WritePaths returns a defensive copy of the canonical individual write paths.
func (WorkspaceAccess) WriteTrees ¶
func (a WorkspaceAccess) WriteTrees() []string
WriteTrees returns a defensive copy of the canonical write directory trees.
type WorkspaceAccessKind ¶
type WorkspaceAccessKind uint8
WorkspaceAccessKind classifies authoritative process workspace access.
const ( // WorkspaceAccessReadOnly may coexist with readers and structured writes. WorkspaceAccessReadOnly WorkspaceAccessKind = iota + 1 // WorkspaceAccessScopedWrite writes only the canonical paths and trees // declared by WorkspaceAccess. WorkspaceAccessScopedWrite // WorkspaceAccessBroadWrite may write anywhere in the bound workspace. WorkspaceAccessBroadWrite )
func (WorkspaceAccessKind) Valid ¶
func (k WorkspaceAccessKind) Valid() bool
Valid reports whether k is a recognized workspace access classification.
type WorkspaceActivityKind ¶
type WorkspaceActivityKind uint8
WorkspaceActivityKind classifies process-reported filesystem activity.
const ( // WorkspaceActivityWrite reports filesystem activity within the immutable // access reserved by the prepared process. WorkspaceActivityWrite WorkspaceActivityKind = iota + 1 // WorkspaceActivityBroadWrite requests conservative broad invalidation. WorkspaceActivityBroadWrite )
func (WorkspaceActivityKind) Valid ¶
func (k WorkspaceActivityKind) Valid() bool
Valid reports whether k is a recognized workspace activity kind.
type WorkspaceBinding ¶
type WorkspaceBinding struct {
Root string
Coordinator WorkspaceCoordinator
Observations WorkspaceObservations
}
WorkspaceBinding contains the workspace capabilities supplied at build time.
Observations is the loop-scoped file-observation set shared by every workspace tool bound to the SAME loop (the file toolset and Bash). It is OPTIONAL: a nil value means "no shared set", in which case the file toolset builds its own private observation map and Bash performs no invalidation (the standalone/bare path). When present it is created once per loop binding so independent file definitions and Bash share exactly the same state.
type WorkspaceCoordinator ¶
type WorkspaceCoordinator interface {
Acquire(ctx context.Context, operation WorkspaceOperation, canonicalPath string) (WorkspacePermit, error)
Healthy() error
}
WorkspaceCoordinator is the narrow workspace-mutation coordination seam used by runtime-bound tools. Acquire expects WorkspaceOperationPathMutation with a non-empty canonical workspace-contained path, and WorkspaceOperationWholeMutation or WorkspaceOperationCheckpoint with an empty canonicalPath. Acquire blocks until the permit is granted or ctx is done (a done ctx returns a typed error and removes the waiter). Healthy reports whether the underlying workspace lease is healthy; a structured mutator MUST NOT commit when it returns an error (fail-secure).
type WorkspaceLifetimeCoordinator ¶
type WorkspaceLifetimeCoordinator interface {
AcquireLifetime(ctx context.Context, access WorkspaceAccess) (WorkspacePermit, error)
}
WorkspaceLifetimeCoordinator is the optional long-lived workspace coordination capability implemented by a WorkspaceCoordinator that can reserve a prepared process's authoritative access for its complete lifetime. AcquireLifetime blocks until the access is compatible with every active mutation and lifetime reservation, or ctx is done.
type WorkspaceObservations ¶
type WorkspaceObservations interface {
WithPath(canonicalPath string, fn func(*FileObservation) error) error
InvalidateAll()
}
WorkspaceObservations is the loop-scoped file-observation set shared between one loop's file tools and opaque workspace mutators such as Bash. WithPath holds the path's critical section for the callback, allowing a tool to compare filesystem state and commit atomically relative to other operations in the same Loop.
func NewWorkspaceObservations ¶
func NewWorkspaceObservations() WorkspaceObservations
NewWorkspaceObservations returns an empty concurrency-safe observation set for one Loop binding.
type WorkspaceOperation ¶
type WorkspaceOperation uint8
WorkspaceOperation identifies the scope of a workspace mutation permit.
const ( // WorkspaceOperationPathMutation permits mutation of canonicalPath. It is // SHARED across DIFFERENT canonical paths (many run concurrently) but // EXCLUSIVE on the SAME canonical path (per-path serialization), and is // wholly excluded by a WholeMutation or a Checkpoint permit. WorkspaceOperationPathMutation WorkspaceOperation = iota + 1 // WorkspaceOperationWholeMutation permits a whole-workspace mutation (Bash and // other unknown-path mutators). It is EXCLUSIVE against every PathMutation and // against other whole/checkpoint permits. WorkspaceOperationWholeMutation // WorkspaceOperationCheckpoint is the exclusive snapshot/restore gate. Like a // WholeMutation it is EXCLUSIVE against every mutation and every other exclusive // permit, and it likewise requires an empty canonicalPath; it is a DISTINCT // operation so a checkpoint/restore actor names its intent (the checkpoint // boundary Task 15 consumes) rather than masquerading as a Bash mutation. WorkspaceOperationCheckpoint )
type WorkspacePermit ¶
type WorkspacePermit interface {
Release()
}
WorkspacePermit is an acquired workspace mutation permit. Release is idempotent so callers may safely defer it immediately after acquisition.
type WriteTarget ¶
WriteTarget lets the runner group same-path mutations without importing the tools package: a write tool returns its resolved write path as key with ok=true, and the runner serializes calls sharing a key. ok=false means the call is not a write (no serialization). A non-nil err (e.g. unparseable args) is treated like invalid args: tool-result error, not executed, not grouped.