Rulvar API reference / @rulvar/rulvar / RunOptions
Interface: RunOptions
Defined in: packages/core/dist/index.d.ts
Properties
| Property | Type | Description | Defined in |
|---|---|---|---|
budgetPolicy? | "immutable-lifetime" | "segment" | The ceiling-override posture of the run's whole life (RV3902, the fourth comparison experiment). Default 'segment', today's behavior byte for byte: B0 and the exposure cap are immutable WITHIN a segment, and the explicit, validated, journaled ResumeOptions.run override (RV2208) may change them by opening a new segment. 'immutable-lifetime' welds that one door shut: the posture is recorded in RunMeta at genesis and restored on every resume, and a resume carrying ANY ResumeOptions.run value refuses with a typed ConfigError BEFORE ownership, meta writes, or any append, raise and lower alike; no journaled override exists in this mode, and the emergency lever for a run that must stop spending is cancel, not a ceiling edit. Degradation is honest: a store that drops the optional RunMeta field resumes as 'segment' (the override door works again), never as an invented refusal. Declared at genesis only; the policy itself has no override. | packages/core/dist/index.d.ts |
budgetUsd? | number | Run ceiling B0; immutable within a segment (RV2511): no API tops up a live run's ceiling, and the ONE explicit door after genesis is the validated, journaled ResumeOptions.run override (RV2208), which takes effect only by opening a new segment. Enforced by projected admission (a spawn whose reserve does not fit is denied before any dispatch), the per-turn guard with a budget-derived maxOutputTokens clamp, and live stream cuts on crossing; the residual provider-dependent overshoot is bounded by one in-flight turn per concurrent agent. Under RunOptions.budgetPolicy 'immutable-lifetime' even the override door refuses typed. Contract: https://docs.rulvar.com/guide/budgets. | packages/core/dist/index.d.ts |
clampTurnToExposure? | boolean | Layer 2b against the exposure ceiling (RV2503), opt-in and meaningful only beside maxInFlightExposureUsd. Armed, a dispatch with NOTHING else in flight has its planned output clamped to the tokens the remaining exposure room affords instead of being refused outright, exactly as the budget ceiling has always clamped it. The 1.226.0 comparison run is the case: nothing was live, the budget still held 0.8642 USD, the mandatory repair turn's FULL 18000 token plan priced 0.7066 USD against 0.5642 USD of room, and the dispatch was refused before any provider call; the same work, re-issued after an operator raised the ceiling, wrote 12840 output tokens for 0.4788 USD. A refusal with nothing live buys nothing, because no hold will ever release to fund the full plan. Deliberately scoped and deliberately off by default. With siblings in flight the refusal is transient and the RV1902/RV2002 waits park on it, so the wave keeps the full-length turn RV711 promised and nothing here applies. When the room cannot even fund the serving model's output floor, the clamp stands aside and the dispatch refuses through the usual typed in-flight-exposure path, so the drained-refusal terminals (RV1902, RV2002, RV2003) keep their shapes. Absent, every byte of dispatch behavior is historical. Like strictPricing, this is a per-segment posture: it is not recorded in RunMeta and a resumed segment carries only what its own options declare. | packages/core/dist/index.d.ts |
configFingerprint? | string | An opaque host-declared identity over the config the workflow body CLOSES OVER (RV3210, the honest answer to hashWorkflowBody's closure blindness: the body-text hash cannot see captured values, so two byte-identical bodies over different closures pin identically). Recorded in RunMeta at genesis and compared on every resume that supplies one: a mismatch refuses the resume typed BEFORE ownership, meta writes, and appends, because the host itself asserted the identity; a recorded fingerprint the resume does not supply warns (RULVAR_RESUME_FINGERPRINT_UNCHECKED), and a supplied fingerprint the run never recorded warns (RULVAR_RESUME_FINGERPRINT_UNRECORDED) instead of failing, because absence means NOT RECORDED. The preferred pattern is still to close over nothing and pass config through args; the fingerprint is the pin for what must stay closed over. A non-empty string of at most 512 characters. | packages/core/dist/index.d.ts |
deadlineAt? | string | Run-level deadline: an ISO 8601 date-time with an explicit UTC designator or offset (e.g. 2026-07-21T10:00:00Z or 2026-07-21T12:00:00+02:00); crossing it cancels the run. Any other string is a typed ConfigError thrown synchronously by engine.run, before any journal entry or provider dispatch (v1.34.0 review P2-1). A deadline already in the past cancels immediately: a crossed deadline is a valid deadline. Deadlines beyond the Node timer maximum are honored through sliced timers, never truncated (v1.34.0 review P2-2). | packages/core/dist/index.d.ts |
lease? | Lease | A lease the caller already holds for this run (the genesis side of the ResumeOptions.lease contract): the engine carries it on EVERY durable mutation of the fresh segment (every journal append, every putMeta, every transcript blob write) and never acquires, renews, or releases it itself; lifecycle stays with the caller. Passing it disables the engine's own ownership acquisition for this run regardless of the ownership mode. Hosts that admit runs through an external queue acquire the lease at admission time and hand it here, so admission and the first dispatch are covered by ONE fencing epoch. | packages/core/dist/index.d.ts |
limits? | UsageLimits | Run-level defaults merged over engine defaults. | packages/core/dist/index.d.ts |
maxInFlightExposureUsd? | number | The opt-in in-flight exposure cap (RV711): bounds spent money plus the summed worst-case estimates of live dispatches. The per-turn guard checks money already SPENT, so under budgetUsd alone N concurrent turns each pass it before any settles and together can cross the ceiling by up to one whole turn each (preflight's 'overshoot-exposure' finding prices that hole). With the cap, the admission holds each turn's own estimate (the prompt estimate plus the request's output allowance, priced by the same rows as settlement) from right before the provider call until the attempt settles, and the dispatch whose estimate does not fit spent + finalize/synthesis reserves + live estimates is refused with a typed BudgetExhaustedError (data.reason 'in-flight-exposure'). A plain agent settles the refusal as a budget error; an orchestrate-owned root dispatch waits it out (RV1902): it parks until a live hold releases, retries pre-wire, and emits budget:exposure-wait, while a drained refusal settles the documented forced-finish partial instead of tearing the run down. Worst concurrent overshoot past the cap is thereby the estimate error of the in-flight turns, not one whole turn per agent. Absent by default: wire traffic, journals, and hooks stay byte-identical. Recorded in RunMeta at genesis (RV1504) and restored on every resume, the budgetUsd rule: the cap used to be per-invocation and unrecorded, so a resumed segment silently ran without the bound the original invocation declared (the seventeenth comparison benchmark's top FinOps gap). A run started without the cap stays uncapped for its whole life unless a host changes the posture through the explicit, validated, journaled ResumeOptions.run override (RV2208); nothing changes it silently. | packages/core/dist/index.d.ts |
name? | string | - | packages/core/dist/index.d.ts |
runId? | string | Explicit id; otherwise the engine mints a ULID. | packages/core/dist/index.d.ts |
scope? | ExecutionScope | The bounded execution scope (RV4007): recorded at genesis into RunMeta and a journal decision, immutable for the run's life (no resume door), lifted onto the invoice header and carried by the export bundle. Attribution only: the library never interprets it, with one declared exception since RV4205: a quota config with tenantFrom: 'scope' reads the scope's tenant into its reservations. | packages/core/dist/index.d.ts |
scopePolicy? | ScopePolicy | What an unknown scope field does (RV4205): 'drop' (the default, the historical bytes, pinned) or 'reject' (typed refusal by name). compileRegulatedProfile enforces 'reject'. | packages/core/dist/index.d.ts |
signal? | AbortSignal | Host-initiated cancellation. | packages/core/dist/index.d.ts |
strictPricing? | | boolean | { allowUnpriced?: readonly string[]; maxRatesAgeDays?: number; } | The opt-in strict pre-egress pricing gate (RV1508): every paid dispatch must resolve a well-formed price row for its serving model BEFORE the wire call, or the dispatch refuses typed (ConfigError naming the model and the defect). true demands presence and well-formedness; the object form adds maxRatesAgeDays (a row must carry a fresh ratesVerifiedAt) and allowUnpriced (exact model refs the host KNOWS are free, the explicit exception). Recorded in RunMeta at genesis and restored on every resume, the exposure cap's rule (RV1504): a FinOps posture a resumed segment silently drops is not a posture (and unlike the two ceilings, ResumeOptions.run has no field for this gate: pricing hygiene is not a per-segment decision). Absent by default: dispatch behavior stays byte identical, and an unpriced model keeps debiting nothing, the documented ceiling hole this mode exists to close. | packages/core/dist/index.d.ts |
tags? | string[] | - | packages/core/dist/index.d.ts |