Source profileQuality 90/100Review permissions

nirholas/three.ws/pump-fun-skills/tokenized-agents/SKILL.md

tokenized-agents

Use when the user wants to charge users for actions. Use @three-ws/agent-payments, to build Solana payment transactions, verify on-chain invoice payments, or integrate Solana wallet adapters for agent payment flows.

Source repository stars
91
Declared platforms
0
Static risk flags
2
Last source update
2026-08-05
Source checked
2026-08-05

Decision brief

What it does—and where it fits

MANDATORY — Do NOT write or modify any code until every item below is answered by the user:

Best for

  • Use when the user wants to charge users for actions.

Not for

  • See https://raw.githubusercontent.com/pump-fun/pump-fun-skills/refs/heads/main/tokenized-agents/references/SCENARIOS.md for detailed test scenarios (happy path, duplicate rejection, expired invoices, etc.) and a trouble…

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/nirholas/three.ws --skill "pump-fun-skills/tokenized-agents"
Safe inspection promptEditorial

Inspect the Agent Skill "tokenized-agents" from https://github.com/nirholas/three.ws/blob/87e97e04e6c97f570a34dc2e5906bd6911db9312/pump-fun-skills/tokenized-agents/SKILL.md at commit 87e97e04e6c97f570a34dc2e5906bd6911db9312. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    SDK Setup

    PumpAgent is the main class. It can build payment instructions and verify invoices.

    PumpAgent is the main class. It can build payment instructions and verify invoices.Without connection — enough for building instructions and HTTP-based payment verification:With connection — also enables RPC-based verification fallback and balance queries:
  2. 02

    Building Payment Instructions

    Use buildAcceptPaymentInstructions to get all the instructions needed for a payment. This is the recommended method — it automatically derives the user's token account and handles native SOL wrapping/unwrapping.

    SetComputeUnitLimit is always prepended (default 100000 CU). Override via computeUnitLimit if your transactions fail with "compute exceeded".SetComputeUnitPrice is prepended only when computeUnitPrice is provided. Use this to set a priority fee for faster landing during congestion.For SPL tokens (USDC): The accept-payment instruction.
  3. 03

    Usage

    getInvoiceIdPDA returns [PublicKey, number]. The first element is the Invoice ID; the second is the PDA bump seed.

    getInvoiceIdPDA returns [PublicKey, number]. The first element is the Invoice ID; the second is the PDA bump seed.All numeric parameters (amount, memo, startTime, endTime) are plain number values. BN conversion is handled internally.
  4. 04

    Step 1: Generate Invoice Parameters (Server)

    Review the “Step 1: Generate Invoice Parameters (Server)” section in the pinned source before continuing.

    Review and apply the “Step 1: Generate Invoice Parameters (Server)” source section.
  5. 05

    Step 2: Build Transaction and Serialize as Base64 (Server)

    Build the payment instructions, assemble them into a full Transaction with a recent blockhash and fee payer, then serialize the unsigned transaction as a base64 string for the client.

    Build the payment instructions, assemble them into a full Transaction with a recent blockhash and fee payer, then serialize the unsigned transaction as a base64 string for the client.Return the base64 transaction string (and the invoice params like memo, startTime, endTime) to the client as JSON.

Permission review

Static risk signals and limitations

Network access

medium · line 41

The documentation includes network, browsing, or remote request actions.

SOLANA_RPC_URL=https://rpc.solanatracker.io/public

Network access

medium · line 44

The documentation includes network, browsing, or remote request actions.

NEXT_PUBLIC_SOLANA_RPC_URL=https://rpc.solanatracker.io/public

Runs scripts

medium · line 67

The documentation asks the agent to run terminal commands or scripts.

npm install @three-ws/agent-payments @solana/web3.js@^1.98.0

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score90/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars91SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
nirholas/three.ws
Skill path
pump-fun-skills/tokenized-agents/SKILL.md
Commit
87e97e04e6c97f570a34dc2e5906bd6911db9312
License
NOASSERTION
Collected
2026-08-05
Default branch
main
View the original SKILL.md

Before Starting Work

MANDATORY — Do NOT write or modify any code until every item below is answered by the user:

  • Agent token mint address (from pump.fun)
  • Payment currency decided (USDC or SOL)
  • Price/amount confirmed (in smallest unit)
  • RPC URL provided or a fallback agreed upon
  • Framework confirmed (Next.js, Express, other)

You MUST ask the user for ALL unchecked items in your very first response. Do not assume defaults. Do not proceed until the user has explicitly answered each one.

Safety Rules

  • NEVER log, print, or return private keys or secret key material.
  • NEVER sign transactions on behalf of a user — you build the instruction, the user signs.
  • Always validate that amount > 0 before creating an invoice.
  • Always ensure endTime > startTime and both are valid Unix timestamps.
  • Use the correct decimal precision for the currency (6 decimals for USDC, 9 for SOL).
  • Always verify payments on the server using validateInvoicePayment before delivering any service. Never trust the client alone — clients can be spoofed.
  • Always verify your code against this skill before finalizing. Before delivering generated code, re-read the relevant sections of this document and confirm:
    • Parameter types match the documented signatures — buildAcceptPaymentInstructions accepts number for numeric fields, validateInvoicePayment accepts number, and getInvoiceIdPDA accepts number.
    • Parameter ordering and names match exactly.
    • Default values (e.g. computeUnitLimit defaults to 100_000) are not contradicted.
    • Import paths use @three-ws/agent-payments, not internal module paths.

Supported Currencies

CurrencyDecimalsSmallest unit example
USDC61000000 = 1 USDC
Wrapped SOL91000000000 = 1 SOL

Environment Variables

Create a .env (or .env.local for Next.js) file with the following:

# Solana RPC — server-side (used to build transactions and verify payments)
SOLANA_RPC_URL=https://rpc.solanatracker.io/public

# Solana RPC — client-side (used by wallet adapter in the browser)
NEXT_PUBLIC_SOLANA_RPC_URL=https://rpc.solanatracker.io/public

# The token mint address of your tokenized agent on pump.fun
AGENT_TOKEN_MINT_ADDRESS=<your-agent-mint-address>

# Payment currency mint
# USDC: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
# SOL (wrapped): So11111111111111111111111111111111111111112
CURRENCY_MINT=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

RPC for mainnet-beta: The default Solana public RPC (https://api.mainnet-beta.solana.com) does not support sending transactions. You MUST ask the user which RPC endpoint to use. Present these free mainnet-beta options if the user does not have their own:

  • Solana Trackerhttps://rpc.solanatracker.io/public
  • Ankrhttps://rpc.ankr.com/solana

Do NOT silently pick one — wait for the user to confirm before proceeding.

Read these values from process.env at runtime. Never hard-code mint addresses or RPC URLs.

Install

npm install @three-ws/agent-payments @solana/web3.js@^1.98.0

Dependency Compatibility — IMPORTANT

@three-ws/agent-payments depends on @solana/web3.js and @solana/spl-token. When the app also installs these packages directly, mismatched versions can cause runtime errors.

Rules:

  1. Before installing @solana/web3.js, @solana/spl-token, or any @solana/wallet-adapter-* package, first check what versions @three-ws/agent-payments declares in its own package.json (inspect it via npm info @three-ws/agent-payments dependencies). Install the same ranges — or ranges that resolve to the same major.minor — so npm/pnpm hoists a single copy instead of two.
  2. Never blindly install "latest" for these shared packages. Always prefer the version that is most compatible with the latest @three-ws/agent-payments.
  3. If the project already has these packages at different versions, align them to match the SDK and re-install.

SDK Setup

PumpAgent is the main class. It can build payment instructions and verify invoices.

import { PumpAgent } from "@three-ws/agent-payments";
import { PublicKey } from "@solana/web3.js";

const agentMint = new PublicKey(process.env.AGENT_TOKEN_MINT_ADDRESS!);

Constructor

new PumpAgent(mint: PublicKey, environment?: "mainnet" | "devnet", connection?: Connection)
ParameterTypeDefaultDescription
mintPublicKeyThe tokenized agent's token mint address
environment"mainnet" | "devnet""mainnet"Network environment
connectionConnection (optional)undefinedSolana RPC connection (enables RPC fallback for verification)

Without connection — enough for building instructions and HTTP-based payment verification:

const agent = new PumpAgent(agentMint);

With connection — also enables RPC-based verification fallback and balance queries:

import { Connection } from "@solana/web3.js";

const connection = new Connection(process.env.SOLANA_RPC_URL!);
const agent = new PumpAgent(agentMint, "mainnet", connection);

Wallet Integration (Frontend)

Install @solana/wallet-adapter-react, @solana/wallet-adapter-react-ui, and @solana/wallet-adapter-wallets. Use useWallet() for publicKey and signTransaction, and useConnection() for the active RPC connection. MUST See https://raw.githubusercontent.com/pump-fun/pump-fun-skills/refs/heads/main/tokenized-agents/references/WALLET_INTEGRATION.md for the full WalletProvider setup, layout wrapping, and hook usage.

Building Payment Instructions

Use buildAcceptPaymentInstructions to get all the instructions needed for a payment. This is the recommended method — it automatically derives the user's token account and handles native SOL wrapping/unwrapping.

Parameters (BuildAcceptPaymentParams)

ParameterTypeDescription
userPublicKeyThe payer's wallet address
currencyMintPublicKeyMint address of the payment currency (USDC, wSOL)
amountbigint | number | stringPrice in the currency's smallest unit
memobigint | number | stringUnique invoice identifier (random number)
startTimebigint | number | stringUnix timestamp — when the invoice becomes valid
endTimebigint | number | stringUnix timestamp — when the invoice expires
tokenProgramPublicKey (optional)Token program for the currency (defaults to SPL Token)
computeUnitLimitnumber (optional)Compute unit budget (default 100_000). Increase if transactions fail with compute exceeded.
computeUnitPricenumber (optional)Priority fee in microlamports per CU. If provided, a SetComputeUnitPrice instruction is prepended.

Example

const ixs = await agent.buildAcceptPaymentInstructions({
  user: userPublicKey,
  currencyMint,
  amount: "1000000", // 1 USDC
  memo: "123456789", // unique invoice identifier
  startTime: "1700000000", // valid from
  endTime: "1700086400", // expires at
});

What It Returns

The returned TransactionInstruction[] always starts with compute budget instructions, followed by the payment instructions:

  • SetComputeUnitLimit is always prepended (default 100_000 CU). Override via computeUnitLimit if your transactions fail with "compute exceeded".
  • SetComputeUnitPrice is prepended only when computeUnitPrice is provided. Use this to set a priority fee for faster landing during congestion.

After the compute budget prefix:

  • For SPL tokens (USDC): The accept-payment instruction.
  • For native SOL: Instructions that handle wrapping/unwrapping automatically:
    1. Create the user's wrapped SOL token account (idempotent)
    2. Transfer SOL lamports into that token account
    3. Sync the native balance
    4. The accept-payment instruction
    5. Close the wrapped SOL account (returns rent back to user)

You do not need to handle SOL wrapping or compute budget yourself — buildAcceptPaymentInstructions does it for you.

Important

  • The amount, memo, startTime, and endTime must exactly match when verifying later.
  • Each unique combination of (mint, currencyMint, amount, memo, startTime, endTime) can only be paid once — the on-chain Invoice ID PDA prevents duplicate payments.
  • Generate a unique memo for each invoice (e.g. Math.floor(Math.random() * 900000000000) + 100000).

Deriving the Invoice ID

The Invoice ID is a PDA (PublicKey) that uniquely identifies an invoice on-chain. It is derived deterministically from the six invoice parameters. Both buildAcceptPaymentInstructions and validateInvoicePayment derive it internally, but you can also compute it yourself.

Import

import { getInvoiceIdPDA } from "@three-ws/agent-payments";
import { PublicKey } from "@solana/web3.js";

Usage

getInvoiceIdPDA returns [PublicKey, number]. The first element is the Invoice ID; the second is the PDA bump seed.

const tokenMint = new PublicKey(process.env.AGENT_TOKEN_MINT_ADDRESS!);
const currencyMint = new PublicKey(process.env.CURRENCY_MINT!);

const amount = 1000000;
const memo = 123456789;
const startTime = 1700000000;
const endTime = 1700086400;

const [invoiceId] = getInvoiceIdPDA(
  tokenMint,
  currencyMint,
  amount,
  memo,
  startTime,
  endTime,
);

console.log("Invoice ID:", invoiceId.toBase58());

All numeric parameters (amount, memo, startTime, endTime) are plain number values. BN conversion is handled internally.

PDA Seeds

The Invoice ID is derived with program AgenTMiC2hvxGebTsgmsD4HHBa8WEcqGFf87iwRRxLo7 using these seeds:

Seed indexValue
0"invoice-id" (UTF-8 bytes)
1tokenMint (32 bytes)
2currencyMint (32 bytes)
3amount (8 bytes, little-endian)
4memo (8 bytes, little-endian)
5startTime (8 bytes, little-endian)
6endTime (8 bytes, little-endian)

Because the PDA is deterministic, the same six parameters always produce the same Invoice ID. The on-chain program uses this to reject duplicate payments — once an Invoice ID PDA is created, the same combination cannot be paid again.

When to Use

  • Pre-check for duplicates — before building a payment transaction, check if the Invoice ID account already exists on-chain to avoid submitting a transaction that will fail:
const [invoiceId] = getInvoiceIdPDA(
  tokenMint,
  currencyMint,
  amount,
  memo,
  startTime,
  endTime,
);
const accountInfo = await connection.getAccountInfo(invoiceId);
if (accountInfo !== null) {
  // This invoice was already paid — generate a new memo
}
  • Debugging — if a payment transaction fails or verification returns false, derive the Invoice ID and inspect it on a Solana explorer to see whether the account exists.

Full Transaction Flow — Server to Client

This is the complete flow for building a transaction on the server, signing it on the client, and sending it on-chain.

Step 1: Generate Invoice Parameters (Server)

function generateInvoiceParams() {
  const memo = Math.floor(Math.random() * 900000000000) + 100000;
  const now = Math.floor(Date.now() / 1000);
  const startTime = now;
  const endTime = now + 86400; // valid for 24 hours
  const amount = Number(process.env.PRICE_AMOUNT) || 1000000; // e.g. 1 USDC

  return { amount, memo, startTime, endTime };
}

Step 2: Build Transaction and Serialize as Base64 (Server)

Build the payment instructions, assemble them into a full Transaction with a recent blockhash and fee payer, then serialize the unsigned transaction as a base64 string for the client.

import { Connection, PublicKey, Transaction } from "@solana/web3.js";
import { PumpAgent } from "@three-ws/agent-payments";

async function buildPaymentTransaction(params: {
  userWallet: string;
  amount: string;
  memo: string;
  startTime: string;
  endTime: string;
}) {
  const connection = new Connection(process.env.SOLANA_RPC_URL!);
  const agentMint = new PublicKey(process.env.AGENT_TOKEN_MINT_ADDRESS!);
  const currencyMint = new PublicKey(process.env.CURRENCY_MINT!);

  const agent = new PumpAgent(agentMint, "mainnet", connection);
  const userPublicKey = new PublicKey(params.userWallet);

  const instructions = await agent.buildAcceptPaymentInstructions({
    user: userPublicKey,
    currencyMint,
    amount: params.amount,
    memo: params.memo,
    startTime: params.startTime,
    endTime: params.endTime,
  });

  const { blockhash } = await connection.getLatestBlockhash("confirmed");

  const tx = new Transaction();
  tx.recentBlockhash = blockhash;
  tx.feePayer = userPublicKey;
  tx.add(...instructions);

  const serializedTx = tx
    .serialize({ requireAllSignatures: false })
    .toString("base64");

  return { transaction: serializedTx };
}

Return the base64 transaction string (and the invoice params like memo, startTime, endTime) to the client as JSON.

Step 3: Deserialize, Sign, and Send the Transaction (Client)

Deserialize the base64 transaction from the server, sign it with signTransaction from the wallet adapter, then send and confirm it. Call useWallet() and useConnection() only at the top level of your component; pass signTransaction and connection into the async helper so the async logic does not call hooks.

Async helper (e.g. in a utils file or alongside your component):

import { Connection, Transaction } from "@solana/web3.js";

async function signAndSendPayment(
  txBase64: string,
  signTransaction: (tx: Transaction) => Promise<Transaction>,
  connection: Connection,
): Promise<string> {
  if (!signTransaction) {
    throw new Error("Wallet does not support signing");
  }

  const tx = Transaction.from(Buffer.from(txBase64, "base64"));
  const signedTx = await signTransaction(tx);

  const signature = await connection.sendRawTransaction(signedTx.serialize(), {
    skipPreflight: false,
    preflightCommitment: "confirmed",
  });

  const latestBlockhash = await connection.getLatestBlockhash("confirmed");
  await connection.confirmTransaction(
    { signature, ...latestBlockhash },
    "confirmed",
  );

  return signature;
}

Component usage — call the hooks at the top level, then pass them into the helper (e.g. from a payment button handler):

import { useWallet, useConnection } from "@solana/wallet-adapter-react";

function PaymentButton({ txBase64 }: { txBase64: string }) {
  const { signTransaction } = useWallet();
  const { connection } = useConnection();

  const handlePay = async () => {
    if (!signTransaction) return;
    await signAndSendPayment(txBase64, signTransaction, connection);
  };

  return <button onClick={handlePay}>Pay</button>;
}

The wallet prompts the user to approve. After signing, the serialized transaction is submitted via sendRawTransaction and you wait for on-chain confirmation.

Verify Payment

Use validateInvoicePayment to confirm that a specific invoice was paid on-chain.

How It Works

  1. Derives the Invoice ID PDA from the six parameters (mint, currencyMint, amount, memo, startTime, endTime) using getInvoiceIdPDA internally. The resulting PublicKey uniquely identifies the invoice on-chain.

  2. Queries the Pump HTTP API — sends a GET request with invoice-id (base58) and mint as query parameters. If the endpoint returns a response, it validates every field individually:

    • data.user === user (base58)
    • data.tokenized_agent_mint === mint (base58)
    • data.currency_mint === currencyMint (base58)
    • data.amount === amount (BN equality)
    • data.memo === memo (BN equality)
    • data.start_time === startTime (BN equality)
    • data.end_time === endTime (BN equality)

    All seven checks must pass for the method to return true.

  3. RPC fallback — if the HTTP API is unavailable (network error or non-200 status) and a Connection was provided to the PumpAgent constructor, it falls back to scanning on-chain transaction logs. It fetches all signatures for the Invoice ID address, parses each transaction's logs for the agentAcceptPaymentEvent event, and performs the same field-by-field validation. Without a Connection, there is no fallback and the method returns false.

  4. Returns true if a matching payment event is found by either path, false otherwise.

Parameters

ParameterTypeDescription
userPublicKeyThe wallet that paid
currencyMintPublicKeyCurrency used for payment
amountnumberAmount paid (smallest unit)
memonumberThe invoice memo
startTimenumberInvoice start time (Unix timestamp)
endTimenumberInvoice end time (Unix timestamp)

Type note: validateInvoicePayment expects amount, memo, startTime, and endTime as number, not strings. If you stored them as strings, parse them first: Number(memo).

Simple Backend Verification

import { PumpAgent } from "@three-ws/agent-payments";
import { PublicKey } from "@solana/web3.js";

const agentMint = new PublicKey(process.env.AGENT_TOKEN_MINT_ADDRESS!);
const agent = new PumpAgent(agentMint);

const paid = await agent.validateInvoicePayment({
  user: new PublicKey(userWalletAddress),
  currencyMint: new PublicKey(process.env.CURRENCY_MINT!),
  amount: 1000000,
  memo: 123456789,
  startTime: 1700000000,
  endTime: 1700086400,
});

if (paid) {
  // Payment confirmed — deliver the service
} else {
  // Payment not found
}

No Connection is needed for basic verification — it uses the HTTP API by default.

Verification with Retries

Transactions may take a few seconds to confirm. Use a retry loop for reliability:

async function verifyPayment(params: {
  user: string;
  currencyMint: string;
  amount: number;
  memo: number;
  startTime: number;
  endTime: number;
}): Promise<boolean> {
  const agentMint = new PublicKey(process.env.AGENT_TOKEN_MINT_ADDRESS!);
  const agent = new PumpAgent(agentMint);

  const invoiceParams = {
    user: new PublicKey(params.user),
    currencyMint: new PublicKey(params.currencyMint),
    amount: params.amount,
    memo: params.memo,
    startTime: params.startTime,
    endTime: params.endTime,
  };

  for (let attempt = 0; attempt < 10; attempt++) {
    const verified = await agent.validateInvoicePayment(invoiceParams);
    if (verified) return true;
    await new Promise((r) => setTimeout(r, 2000));
  }

  return false;
}

End-to-End Flow

1. Agent decides on price → generates unique memo(number) → sets time window
2. Server: buildAcceptPaymentInstructions({...}) → returns TransactionInstruction[]
3. Server: builds full Transaction (blockhash + feePayer + instructions) → serializes as base64
4. Client: deserializes base64 → Transaction.from(Buffer.from(txBase64, "base64"))
5. Client: signTransaction(tx) — wallet prompts user to approve
6. Client: connection.sendRawTransaction(signedTx.serialize()) → connection.confirmTransaction(signature)
7. Server: with the exactly same parameters used for buildAcceptPaymentInstructions server  validateInvoicePayment({...}) → returns true/false (ALWAYS verify server-side)
8. Agent delivers the service (or asks user to retry)

Scenario Tests & Troubleshooting

See https://raw.githubusercontent.com/pump-fun/pump-fun-skills/refs/heads/main/tokenized-agents/references/SCENARIOS.md for detailed test scenarios (happy path, duplicate rejection, expired invoices, etc.) and a troubleshooting table for common errors and for wallet Integration must follow https://raw.githubusercontent.com/pump-fun/pump-fun-skills/refs/heads/main/tokenized-agents/references/WALLET_INTEGRATION.md.

Alternatives

Compare before choosing

Computed 10043,034

coreyhaines31/marketingskills

ab-testing

When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

Computed 10023,835

alirezarezvani/claude-skills

app-store-optimization

App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

Computed 1004,944

dotnet/skills

migrate-vstest-to-mtp

Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing

Computed 100165

JasonColapietro/suede-creator-skills

suede-ab-testing

Suede-owned experimentation discipline for hypotheses, sample sizing, test duration, significance, and repeatable experiment programs. Use when comparing variants, deciding whether a result is reliable, or building an experiment backlog and cadence. NOT FOR: analytics instrumentation (use suede-analytics), post-click conversion diagnosis (use suede-site-alchemy), or writing the variant copy itself (use suede-copy).