Skip to documentation
Documentation navigation

Documentation navigation

Documentation / guides

Limits and authority

Bound depth, concurrency, and authority across delegation.

developer

Delegation has separate safety caps for nesting and lifetime fan-out. The controller also enforces parent authority on every operation. These limits are session-scoped and do not turn a child into a session-wide worker pool.

Depth and quota

// Zero uses the runtime defaults. Positive values override them.
runtime, err := rig.Define(
	rig.WithLoops(parent, child),
	rig.WithPrimers(parent.Name()),
	rig.WithSessionStore(store),
	rig.WithDelegationLimits(rig.DelegationLimits{Depth: 2, Quota: 8}),
)
API or fieldContract
rig.DelegationLimits.DepthMaximum spawn-chain nesting. A spawn whose parent chain is already at the cap is refused.
rig.DelegationLimits.QuotaMaximum total sub-Loops spawned by one session lifetime. The primary Loop is not counted.
rig.WithDelegationLimitsRejects negative values with DefinitionInvalidDelegationLimits; zero adopts defaults.
Default depth3, allowing a primary plus two sub-Loop levels.
Default quota64 sub-Loops over the session lifetime.

Quota is reserved transactionally. Invalid target or mode checks happen before quota consumption, and a failed admission rolls its reservation back. Restore counts durable non-root LoopStarted records so a restart cannot mint a fresh quota.

Proof: Rig delegation limits, runtime defaults, and spawn tests.

Concurrency and turn ownership

There is no public delegation concurrency field. Depth and quota bound the tree; each child Loop owns its actor and its turn queue. Native messages may fold into a busy child turn, while foreign delivery uses no-fold admission. QueuedMessages in DelegateAgent reports a bounded snapshot, not a promise of parallel execution. DelegateStatus returns direct children sorted by UUID and caps the list at 256, setting Truncated when more exist.

The separate Hustle blocking/background lanes are not delegation lanes. A compaction or classifier Hustle consumes rig.HustleLimits; a child Loop consumes delegation depth/quota and its own turn machinery.

Proof: delegate status and ownership and loop queue tests.

Parent-scoped authority

The controller is constructed with the parent’s frozen Delegates() set and Delegation().Style. It checks the target name against that set, validates a declared target mode, and checks that the child ID is a direct child whose parent Loop ID matches the controller. Siblings, ancestors, unrelated IDs, and tombstoned children are refused. Status can inspect a closed direct child; start, send, and interrupt cannot act on one.

Runtime selection is also parent-scoped. A supplied tool.DelegateRuntime is re-resolved against the parent catalog and must match the declared target entry. Missing catalog entries and invalid selections both render the bounded model-facing text runtime selection is unavailable.

%%{init: {"theme":"dark"}}%%
flowchart TD
    T[tool request] --> S[parent-scoped controller]
    S --> A{target in frozen Delegates?}
    A -->|no| E[DelegateUnauthorizedAgent]
    A -->|yes| O{direct child owned?}
    O -->|no| N[DelegateNotOwned]
    O -->|yes| M{mode and runtime valid?}
    M -->|no| X[typed refusal]
    M -->|yes| D[session-owned dispatch]

Proof: scoped controller checks and authority tests.

Refusal kinds

DelegateError.Kind is the typed refusal surface. Relevant values are DelegateActionUnavailable, DelegateUnknownAgent, DelegateUnauthorizedAgent, DelegateUnknownMode, DelegateNotOwned, DelegateSessionUnavailable, DelegateMissingDelegateID, DelegateUnknownOperation, DelegateInterruptPending, DelegateRuntimeUnavailable, DelegateRuntimeInvalid, and DelegateClosed. Inspect it with errors.As; do not parse the message.

Proof: DelegateError definition and bounded messages and tool authority tests.

Source and proof

← back to documentation