For the complete documentation index, see llms.txt. This page is also available as Markdown.

Rendezvous Reference

Complete reference for Rendezvous CLI commands, configuration options, and advanced usage.

This reference explains how to use Rendezvous in different situations. By the end, you'll know when and how to use its features effectively.

What's Inside

Running Rendezvous

Understanding Rendezvous

The Rendezvous Context

Custom Manifest Files

Library API


Running Rendezvous

To run Rendezvous, use the following command:

Let's break down each part of the command.

Positional Arguments

Consider this example Clarinet project structure:

1. Path to the Clarinet Project

The <path-to-clarinet-project> is the relative or absolute path to the root directory of the Clarinet project. This is where the Clarinet.toml file exists. It is not the path to the Clarinet.toml file itself.

For example, if you're in the parent directory of root, the correct relative path would be:

2. Contract Name

The <contract-name> is the name of the contract to be tested, as defined in Clarinet.toml.

For example, if Clarinet.toml contains:

To test the contract named contract, you would run:

3. Testing Type

The <type> argument specifies the testing technique to use. The available options are:

  • test – Runs property-based tests.

  • invariant – Runs invariant tests.

For a deeper understanding of these techniques and when to use each, see the Testing Methodologies chapter of the Rendezvous Docs.

Running property-based tests

Property-based testing requires one or more test functions (e.g. test-xyz) in the contract file (contract.clar), annotated with ;; #[env(simnet)].

Then, execute:

This tells Rendezvous to:

  • Load the Clarinet project located in ./root.

  • Target the contract named contract as defined in Clarinet.toml by executing property-based tests defined within the contract.

Running invariant tests

Invariant testing requires two things in the contract file (contract.clar), both annotated with ;; #[env(simnet)]:

  1. One or more invariant functions (e.g. invariant-xyz).

  2. The Rendezvous context — the context map and update-context function (see The Rendezvous Context).

To run invariant tests, use:

With this command, Rendezvous will:

  • Randomly execute public function calls in the contract contract.

  • Randomly check the defined invariants to ensure the contract's internal state remains valid.

If an invariant check fails, it means the contract's state has deviated from expected behavior, revealing potential bugs.

Options

Rendezvous also provides additional options to customize test execution:

1. Customizing the Number of Runs

By default, Rendezvous runs 100 test iterations. You can modify this using the --runs option:

This increases the number of test cases to 500.

2. Replaying a Specific Sequence of Events

To reproduce a previous test sequence, you can use the --seed option. This ensures that the same random values are used across test runs:

How to Find the Replay Seed

When Rendezvous detects an issue, it includes the seed needed to reproduce the test in the failure report. Here’s an example of a failure report with the seed:

In this case, the seed is 426141810. You can use it to rerun the exact same test scenario:

3. Stop After First Failure

By default, Rendezvous will start the shrinking process after finding a failure. To stop immediately when the first failure is detected, use the --bail option:

This is useful when you want to examine the first failure without waiting for the complete test run and shrinking process to finish.

4. Using Dialers

Dialers allow you to define pre- and post-execution functions using JavaScript during invariant testing. To use a custom dialer file, run:

A good example of a dialer can be found in the Rendezvous repository, within the example Clarinet project, inside the sip010.cjs file.

In that file, you’ll find a post-dialer designed as a sanity check for SIP-010 token contracts. It ensures that the transfer function correctly emits the required print event containing the memo, as specified in SIP-010.

How Dialers Work

During invariant testing, Rendezvous picks up dialers when executing public function calls:

  • Pre-dialers run before each public function call.

  • Post-dialers run after each public function call.

Both have access to an object containing:

  • selectedFunction – The function being executed.

  • functionCall – The result of the function call (undefined for pre-dialers).

  • clarityValueArguments – The generated Clarity values used as arguments.

Example: Post-Dialer for SIP-010

Below is a post-dialer that verifies SIP-010 compliance by ensuring that the transfer function emits a print event containing the memo.

This dialer ensures that any SIP-010 token contract properly emits the memo print event during transfers, helping to catch deviations from the standard.

5. Regression Testing

Rendezvous automatically saves failing test cases to prevent regressions. When a test fails, its seed and configuration are persisted to disk. On subsequent runs, you can replay these failures to ensure bugs stay fixed.

By default, Rendezvous runs fresh random tests:

To verify that previously discovered bugs remain fixed, use the --regr flag:

Rendezvous loads all saved failures for the contract and replays them using their original seeds.

How Failure Persistence Works

When Rendezvous detects a failure, it automatically saves the test configuration to:

For example, failures in the counter contract deployed by ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM would be saved to:

The regression file stores failures grouped by test type (test vs invariant). Each failure record includes:

  • seed – The random seed that triggered the failure.

  • numRuns – Number of test iterations needed for the failure to occur.

  • timestamp – When the failure was discovered (Unix timestamp in milliseconds).

  • dial (optional) – Path to the dialer file used during the test.

Failures are sorted by timestamp in descending order, with the most recent first. To clear saved regressions for a contract, delete its regression file (or edit it to remove specific failures while keeping others).

6. Using a Config File

Instead of passing options as CLI flags, you can provide a JSON config file with --config. When a config file is used, all run options come from the file exclusively — CLI flags like --seed or --runs are ignored.

A config file is a JSON object with optional fields:

Field
Type
Description

accounts

array of objects

Custom accounts (name and address fields required).

accounts_mode

string

"overwrite" (default) or "concatenate".

seed

integer

Seed for replay functionality.

runs

positive integer

Number of test iterations.

bail

boolean

Stop on first failure.

regr

boolean

Run regression tests only.

dial

string

Path to custom dialers file.

The accounts field lets you define custom accounts (for example, mainnet "whale" addresses) for testing. By default ("overwrite" mode), these replace the Devnet.toml accounts entirely. With "concatenate" mode, config accounts are merged with the existing Devnet accounts — if a name appears in both, the config account's address takes precedence.

Rendezvous warns if the config file contains unrecognized keys (e.g. a typo like "sedd" instead of "seed"), and also warns if CLI flags are passed alongside --config.

Summary

Argument/Option
Description
Example

<path-to-clarinet-project>

Path to the Clarinet project (where Clarinet.toml is located).

rv root contract test

<contract-name>

Name of the contract to test (as in Clarinet.toml).

rv root contract test

<type>

Type of test (test for property-based tests, invariant for invariant tests).

rv root contract test

--runs=<num>

Sets the number of test iterations (default: 100).

rv root contract test --runs=500

--seed=<num>

Uses a specific seed for reproducibility.

rv root contract test --seed=12345

--dial=<file>

Loads JavaScript dialers from a file for pre/post-processing.

rv root contract test --dial=./custom-dialer.js

--regr

Run regression tests only (replay saved failures).

rv root contract test --regr

--bail

Stop after the first failure.

rv root contract test --bail

--config=<file>

Uses a JSON config file for all run options.

rv root contract test --config=rv.config.json


Understanding Rendezvous

Rendezvous makes property-based tests and invariant tests first-class. Tests are written in the same language as the system under test. This helps developers master the contract language. It also pushes boundaries—programmers shape their thoughts first, then express them using the language's tools.

When Rendezvous initializes a Simnet session using a given Clarinet project, it deploys the contracts as defined in Clarinet.toml. The contract source, its test functions, and the context all live in the same file — the test code is marked simnet-only with the ;; #[env(simnet)] annotation, so it is included during Simnet testing but stripped on deployment to real networks.

Example

Let’s say we have a contract named checker. The contract source, test functions, and context all live in the same checker.clar file:

The ;; #[env(simnet)] annotation ensures the test functions and context are only deployed during Simnet testing. While the contract source and test functions are familiar, the context is new. Let's take a closer look at it.

The Rendezvous Context

Rendezvous uses a context to track function calls and execution details during invariant testing. This allows for better tracking of execution details and invariant validation.

How the Context Works

When a function is successfully executed during a test, Rendezvous records its execution details in a Clarity map. This map helps track how often specific functions are called successfully and can be extended for additional tracking in the future.

Here’s how the context is structured:

Breaking it down

  • context map → Keeps track of execution data, storing how many times each function has been called successfully.

  • update-context function → Updates the context map whenever a function executes, ensuring accurate tracking.

Using the context to write invariants

By tracking function calls, the context helps invariants ensure stronger correctness guarantees. For example, an invariant can verify that a counter stays above zero by checking the number of successful increment and decrement calls.

Example invariant using the context

By embedding execution tracking into the contract, Rendezvous enables more effective smart contract testing, making it easier to catch bugs and check the contract correctness.

Discarding Property-Based Tests

Rendezvous generates a wide range of inputs, but not all inputs are valid for every test. To skip tests with invalid inputs, there are two approaches:

Discard Function

A separate function determines whether a test should run.

Rules for a Discard Function:

  • Must be read-only.

  • Name must match the property test function, prefixed with "can-".

  • Parameters must mirror the property test’s parameters.

  • Must return true only if inputs are valid, allowing the test to run.

Discard function example

Here, can-test-add ensures that the test never executes for n <= 1.

In-Place Discarding

Instead of using a separate function, the test itself decides whether to run. If the inputs are invalid, the test returns (ok false), discarding itself.

In-place discarding example

In this case, if n <= 1, the test discards itself by returning (ok false), skipping execution.

Discarding summary

Discard Mechanism

When to Use

Discard Function

When skipping execution before running the test is necessary.

In-Place Discarding

When discarding logic is simple and part of the test itself.

In general, in-place discarding is preferred because it keeps test logic together and is easier to maintain. Use a discard function only when it's important to prevent execution entirely.

Custom Manifest Files

Some smart contracts need a special Clarinet.toml file to allow Rendezvous to create state transitions in the contract. Rendezvous supports this feature by automatically searching for Clarinet-<target-contract-name>.toml first. This allows you to use test doubles while keeping tests easy to manage.

Why use a custom manifest?

A great example is the sBTC contract suite.

For testing the sbtc-token contract, the sbtc-registry authorization function is-protocol-caller is too restrictive. Normally, it only allows calls from protocol contracts, making it impossible to directly test certain state transitions in sbtc-token.

To work around this, you need two things:

A test double for sbtc-registry

You can create an sbtc-registry test double called sbtc-registry-double.clar:

This loosens the restriction just enough for testing by allowing the deployer to act as a protocol caller, while still enforcing an access check.

A Custom Manifest File

Next, create Clarinet-sbtc-token.toml to tell Rendezvous to use the test double only when targeting sbtc-token:

How It Works

  • When testing sbtc-token, Rendezvous first checks if Clarinet-sbtc-token.toml exists.

  • If found, it uses this file to initialize Simnet.

  • If not, it falls back to the standard Clarinet.toml.

This ensures that the test double is only used when testing sbtc-token, keeping tests realistic while allowing necessary state transitions.

Trait Reference Parameters

Rendezvous automatically generates arguments for function calls. It handles most Clarity types without any setup from you. However, trait references require special handling since Rendezvous cannot generate them automatically.

How Trait Reference Selection Works

When your functions accept trait reference parameters, you must include at least one trait implementation in your Clarinet project. This can be either a project contract or a requirement.

Here's how Rendezvous handles trait references:

  1. Project Scanning – Before testing begins, Rendezvous scans your project for functions that use trait references.

  2. Implementation Discovery – It searches the contract AST for matching trait implementations and adds them to a selection pool.

  3. Random Selection – During test execution, Rendezvous randomly picks an implementation from the pool and uses it as a function argument.

This process allows Rendezvous to create meaningful state transitions and validate your invariants or property-based tests.

Example

The example Clarinet project demonstrates this feature. The send-tokens contract contains one public function and one property-based test that both accept trait references.

To enable testing, the project includes rendezvous-token, which implements the required trait.

Adding More Implementations

You can include multiple eligible trait implementations in your project. Adding more implementations allows Rendezvous to introduce greater randomness during testing and increases behavioral diversity. If a function that accepts a trait implementation parameter is called X times, those calls are distributed across the available implementations. As the number of implementations grows, Rendezvous has more options to choose from on each call, producing a wider range of behaviors — and uncovering edge cases that may be missed when relying on a single implementation.

Library API

Beyond the rv CLI, Rendezvous can be used as a TypeScript library for building custom property-based testing strategies. You import its argument-generation capabilities directly and compose your own fast-check properties — useful when you need full control over the testing loop (custom assertions, stateful setups, multi-contract interactions, or integration with Vitest/Jest).

Rendezvous ships with TypeScript declarations. It relies on fast-check and @stacks/clarinet-sdk (both already dependencies).

getContractFunction

getContractFunction(simnet, contractName, functionName, deployer?)

Retrieves a function interface from a deployed contract, enriched with trait-reference data when applicable. Throws if the contract or function is not found.

Parameter
Type
Description

simnet

Simnet

The simnet instance from initSimnet.

contractName

string

The contract name (e.g., "counter").

functionName

string

The function name (e.g., "increment").

deployer

string

Optional. Deployer address. Defaults to simnet.deployer.

Returns: EnrichedContractInterfaceFunction

strategyFor

strategyFor(simnet, fn, allAddresses?, projectTraitImplementations?)

Returns an fc.Arbitrary<ClarityValue[]> ready for use with simnet.callPublicFn, simnet.callReadOnlyFn, or simnet.callPrivateFn. It handles all Clarity types automatically: uint, int, bool, principal, buff, string-ascii, string-utf8, list, tuple, optional, response, and trait_reference (including recursive and nested structures such as a list of tuples or an optional of a response).

Parameter
Type
Description

simnet

Simnet

The simnet instance.

fn

EnrichedContractInterfaceFunction

Function interface from getContractFunction.

allAddresses

string[]

Optional. Addresses for principal-typed arguments. Defaults to every account in the simnet.

projectTraitImplementations

Record<string, ImplementedTraitType[]>

Optional. Trait implementations keyed by trait. Defaults to extracting them from the simnet.

Returns: fc.Arbitrary<ClarityValue[]>

Example

For the full Library API reference — including custom deployers, restricting the principal pool, and the complete supported-type table — see the Library API chapter of the Rendezvous Book.

Last updated

Was this helpful?