Skip to main content
[ DOCS · PERSONAS ]

Personas

Pick from shipped archetypes when riptide-config prepares a repo, use the advanced init wizard, or write your own when none of them match the actor class you need to model. Each route produces the same [personas.<slug>] block in the adapter.

Overview

A persona is a deterministic behavior policy assigned to one class of simulated actor. The shipped catalog covers the failure modes Riptide's protocol fixtures and generic resource-grinder adapter care about. The riptide-config skill and riptide init --wizard can use the catalog for the protocol you picked plus a cross-protocol generic pool, then embed selected archetypes as [personas.<slug>] blocks in the adapter. Scenario run configs reference those slugs.

For the persona schema (label, action_rate_multiplier, action_weights, triggers) see Personas in the adapter spec. This page is the catalog and authoring guide.

Lending

Action vocab: deposit, borrow, repay, withdraw, liquidate.

  • steady-lp · Steady LP — patient liquidity provider who compounds over time and only reacts to severe health-factor deterioration.
  • cautious-yield-farmer · Cautious Yield Farmer — conservative depositor seeking stable yield who reduces exposure quickly when volatility rises.
  • degen-borrower · Degen Borrower — max leverage, prefers more borrowing over safety, rarely exits voluntarily.
  • aggressive-arb-bot · Aggressive Arb Bot — latency-focused; uses leverage aggressively and rotates capital when utilization spikes.
  • panic-whale · Panic Whale — large holder who exits abruptly when the tape weakens. Canonical driver for the bad-debt failure mode.
  • whale · Whale — outsized single-agent borrow with fixed-amount sizing; holds into the shock instead of unwinding.

AMM / DEX

Action vocab: swap, add_liquidity, remove_liquidity.

  • swapper · Vanilla Swapper — baseline user swapping at a steady rate with no optimization.
  • arbitrageur · Arbitrageur — swaps A→B aggressively when pool.last_swap_price drifts below a reference. Drives reserve_depletion.
  • lp-provider · Liquidity Provider — adds liquidity when reserves look healthy; pulls some back when the pool looks stressed.
  • sandwich-attacker · Sandwich Attacker (approximate) — bursty one-directional swap activity around volume surges. Approximates the on-chain footprint (Riptide does not model mempool ordering).
  • rug-puller · Rug-Puller — large LP burns all accumulated shares when the pool drifts to a favorable state or volume spikes. Probes the JIT-liquidity hook.

Perpetuals

Today's generic-path executable actions are deposit and withdraw; semantic flavor is encoded in weights and triggers referencing perp-specific observations.

  • leveraged-long · Leveraged Long — heavy deposit weighting; rare withdraw; trigger boosts deposit when collateral falls below a band.
  • leveraged-short · Leveraged Short — mirror of leveraged-long on the short side. Trigger fires on detectable open-interest skew.
  • delta-neutral-farmer · Delta-Neutral Farmer — rebalances between deposit and withdraw to keep free collateral near a target band.
  • funding-arbitrageur · Funding Arbitrageur (proxy) — uses market.total_oi_long vs total_oi_short as a stand-in for funding-rate observations.
  • liquidator · Liquidator — waits for a liquidated victim, then withdraws the seized balance.

Liquid Staking

Action vocab: stake, request_unstake, claim_unstake.

  • steady-staker · Steady Staker — quiet majority that holds LST through volatility. Reference population; no triggers.
  • yield-maxi · Yield Maximizer — high-rate, stake-heavy. Trigger flips it briefly into profit-take redemption when exchange rate drifts up.
  • panic-exiter · Panic Exiter — fires hard at request_unstake when exchange rate falls below 9_500 bps. Kelp / rsETH-style panic shape.
  • arb-redeemer · Arb Redeemer — queue-aware churner. Boosts claim_unstake when the pending queue refills.

Stablecoin

Action vocab: deposit_collateral, mint_stable, request_redeem, claim_redeem.

  • cautious-minter · Cautious Minter — overcollateralizes well above the mint target. Reference population; no triggers.
  • leverage-looper · Leverage Looper — yield-seeking minter who keeps pressing mint to maximize outstanding stable liability.
  • panic-redeemer · Panic Redeemer — rushes request_redeem when pool.effective_collateral_ratio_bps falls under par. UXD-style backing-stress shape.
  • arb-redeemer · Arb Redeemer — mirror of the LST arb-redeemer with the trigger flipped to pool.pending_redemption_count.

Cross-Protocol Generic Pool

Every protocol bucket also offers these archetypes. Their action vocab came from whichever protocol they were authored against — re-bind action_weights to your adapter's real action names before using them outside that protocol.

  • swapper, arbitrageur, lp-provider, sandwich-attacker, rug-puller — AMM-flavored.
  • leveraged-long, leveraged-short, delta-neutral-farmer, funding-arbitrageur, liquidator — perps-flavored.
  • whale — lending-flavored.

Writing Your Own Persona

None of the shipped archetypes are mandatory. When the catalog doesn't cover the actor class you want to model, add a new [personas.<slug>] block to your adapter and reference that slug from any run-config.json that should use it. The adapter block is both the reviewer-facing source of truth and the engine runtime input.

1. Start from the schema

Four declared fields, plus an optional persona_args:

  • label — display name in reports and the dashboard.
  • action_rate_multiplier — how often this persona acts per tick relative to baseline (1.0 = baseline). Use 0.5 for a quiet majority, 1.5–2.0 for hot agents.
  • action_weights — relative likelihood of each adapter action. Keys must exactly match names declared in [actions.*]; lint rejects unknown keys.
  • triggers optional — conditional weight boosts. Each entry is { if = "<observation expr>", then = "<action>", weight_boost = <float> }.
  • persona_args optional — named values referenced from [instructions.<ix>].args via "@persona.<key>". Use this when one action has discrete variants (swap direction, long vs short side) and you want different personas to commit to different choices.

2. Pick a behavior shape

Three shapes cover most of what the shipped catalog uses; copying one is usually faster than designing from scratch.

  • Reference population — single high-weight action, no triggers. Used to set a baseline the stress personas push against. Examples: steady-lp, steady-staker, cautious-minter.
  • Single-trigger panic — modest baseline weights with one aggressive trigger that flips behavior when an observation crosses a threshold. Examples: panic-exiter, panic-redeemer, panic-whale.
  • Queue / opportunity sweeper — weights split across two related actions, with a trigger that boosts the second when a queue or counter refills. Examples: arb-redeemer (LST and stablecoin variants).

3. Worked example — drafting a "leveraged-loop-unwinder"

Suppose you have a lending program and want a persona that levers up while utilization is low but unwinds aggressively the moment utilization climbs past 8000 bps. The shape is single-trigger panic with two non-trivial action keys:

[personas.leveraged-loop-unwinder]
label = "Leveraged loop unwinder"
action_rate_multiplier = 1.2
action_weights = { deposit = 0.4, borrow = 0.5, repay = 0.05, withdraw = 0.05 }
triggers = [
  { if = "pool.utilization > 8000", then = "repay",    weight_boost = 6.0 },
  { if = "pool.utilization > 8000", then = "withdraw", weight_boost = 4.0 },
]

What's happening:

  • Below the threshold, weights bias toward levering up — 90% deposit/borrow.
  • When pool.utilization crosses 8000 bps, both unwind actions get boosted; the runtime multiplies the boost into the weight, so repay jumps from 0.05 to 0.30 and withdraw from 0.05 to 0.20. The net effect: aggressive unwinding while the trigger holds.
  • The trigger keys (pool.utilization) must be declared as observations on the adapter — see Observations.

4. Validate before running

Two cheap checks catch most authoring mistakes:

  • riptide lint <program> — flags action_weights keys that don't match any [actions.*] declaration on the adapter. Common after copying a persona between protocols.
  • One-seed smoke — for adapter-only programs, riptide adapt --adapter .riptide/adapters/<program>.toml is enough. For harnessed programs, run riptide run --adapter .riptide/adapters/<program>.toml --harness .riptide/harness --seeds 1 so persona actions encode and dispatch against real setup state.

5. Iterate from a real run

First-pass weights are guesses. Run the baseline scenario with the new persona active, watch the report's per-action counts, and tune from there. The riptide-config skill can also propose starter scenarios that exercise a new persona — see the Quickstart.