Skip to documentation
Documentation navigation

Documentation navigation

Documentation / guides

Workspaces and Snapshots

Describe workspace placement and snapshot policy in a Rig.

developer

Workspace placement is optional at Rig level, but required when any bound tool declares tool.RequiresWorkspace. Exactly one placement option may be supplied:

func WithExclusiveWorkspace(
	store *workspacestore.Store,
	root string,
	leaser storage.Leaser,
) Option
func WithSessionWorkspaces(store *workspacestore.Store, baseDir string) Option
func WithSharedWorkspace(store *workspacestore.Store, root string) Option
ModeRoot ownershipLeaseConcurrent sessionsTypical use
exclusiveone fixed canonical rootsession lease plus hashed root leaseone writera checkout that must be fenced
sessionbaseDir/<sessionID>session lease onlyisolated rootsindependent ephemeral sessions
sharedone fixed canonical rootno root leaseconcurrent owners allowedhumans/external tools share the tree

Placement and canonicalization

Define canonicalizes root or baseDir with absolute clean paths and symlink-aware resolution. Nonexistent tails are joined to the longest existing resolved ancestor. Exclusive roots derive the lease name workspace-roots/<sha256(canonical-root)>, so lexical and symlink aliases contend on the same lease.

The workspace store must be nonnil. Empty roots, multiple placement options, missing exclusive leasers, and canonicalization failures return typed *rig.WorkspacePlacementError. Harness also checks that session-store and workspace-store persistence paths are not equal to or below the managed region; an overlap returns *rig.PersistenceOverlapError.

%%{init: {"theme":"dark"}}%%
flowchart TD
    P[placement option] --> C[Abs + Clean + EvalSymlinks]
    C --> D{exactly one and dependencies valid?}
    D -->|no| E[WorkspacePlacementError]
    D -->|yes| O{persistence overlaps region?}
    O -->|yes| E2[PersistenceOverlapError]
    O -->|no| S[snapshot policy required]

Snapshot policy

type SnapshotTrigger uint8
const (
	SnapshotTriggerUnset SnapshotTrigger = iota
	SnapshotManual
	SnapshotOnIdle
	SnapshotOnTurnDone
	SnapshotOnStepDone
)

type SnapshotPriority uint8
const (
	SnapshotBestEffort SnapshotPriority = iota
	SnapshotRequired
)

type SnapshotPolicy struct {
	Trigger  SnapshotTrigger
	Priority SnapshotPriority
	Timeout  time.Duration
}

func WithSnapshots(policy SnapshotPolicy) Option

An unset trigger resolves to SnapshotOnIdle; zero timeout resolves to 60 seconds. Negative timeout and unknown trigger/priority values are rejected. Placement without WithSnapshots returns SnapshotPolicyRequired. WithSnapshots without placement returns SnapshotPolicyWithoutWorkspace. SnapshotRequired is forbidden for shared placement because concurrent writers cannot promise a stable required snapshot boundary.

Source and proof

← back to documentation