Skip to main content
@reticlehq/test turns an interactive session into a suite that runs on every pull request, without an agent and without paying model tokens to re-derive the same checks. Version 2.8.0. Licensed under SEE LICENSE IN LICENSE. Depends on @reticlehq/core and @reticlehq/server. Optional peer dependency: vitest ^3.2.6.

Why it exists

Driving interactively is reconnaissance. At some point you want the same checks to run unattended. This package invokes the tool layer directly, so a spec is the same evidence an agent would have gathered, minus the model.

Booting a session

BootOptions

bootSession resolves to BootedRun: { invoke: ToolInvoker; close: () => Promise<void> }.

Writing specs

reticleTest(name: string, fn: SpecFn): void registers into a module-level registry. register, getRegistered and clearRegistry are exported for anyone driving it themselves.

The test context

createTestContext(invoke: ToolInvoker, options?: TestContextOptions): TestContext, where TestContextOptions is { sessionId?: string; defaultTimeoutMs?: number } and the timeout defaults to DEFAULT_ASSERT_TIMEOUT_MS.

Running and reporting

RunnerOptions is { invoke; buildContext; now; print?; specs? }. RunSummary is { total, passed, failed, skipped, ok }.

Saved flows as specs

A recorded flow becomes a spec without being rewritten: flowToSpec, flowsAsSpecs, registerFlowSpecs, with assertSuccess, successToPredicate, and the FlowSpec, FlowSpecOptions and FlowsAsSpecsOptions types. Malformed flows raise FlowMalformedError.

Errors and control flow

ReticleSkip and isSkip for skipping, ReticleAssertionError with an AssertionDetail, ReticleQueryEmptyError when a query matched nothing. Constants: TestStatus, SpecKind, SpecOutcome, SpecMessage, PredicateKind, STATUS_GLYPH, JUnit, SKIP_REASON_REAL_INPUT, PROBE_TESTID.

Turning a session into a suite

Writing specs that bind to signals rather than DOM structure.
Last modified on August 15, 2026