Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,17 @@ Copy the `skills/` directory contents to your assistant's skills location.

```
skills/
├── smart-contracts/ # Stellar smart contracts — SKILL.md entry + development/testing/security files
├── dapp/SKILL.md # Frontend, wallets (Freighter, Wallets Kit), signing, smart accounts
├── smart-contracts/ # Stellar smart contracts — SKILL.md router + development/testing/security files
├── dapp/ # Frontend — SKILL.md router + react / data-fetching / smart-accounts files
├── assets/SKILL.md # Stellar Assets, trustlines, SAC bridge
├── data/SKILL.md # Stellar RPC (preferred) + Horizon (legacy), indexing
├── agentic-payments/SKILL.md # x402 + MPP (Charge + Channel) for AI/machine payments
├── zk-proofs/SKILL.md # ZK verification (BLS12-381 Groth16), Circom/Noir/RISC Zero walkthroughs
└── standards/SKILL.md # SEPs, CAPs, ecosystem projects, curated reference links
├── data/ # Stellar RPC (preferred) — SKILL.md router + horizon (legacy) file
├── agentic-payments/ # AI/machine payments — SKILL.md router + x402 / mpp files
├── zk-proofs/SKILL.md # ZK verification (BLS12-381/BN254 Groth16, UltraHonk), Circom/Noir/RISC Zero
├── standards/ # SEPs & CAPs — SKILL.md router + ecosystem / resources files
└── cross-chain/ # Cross-chain — SKILL.md router + cctp file
```

Each sub-skill is a self-contained Agent Skill with its own frontmatter. Cross-references link related skills (e.g., the `agentic-payments` skill points to `smart-contracts` for the SACs the protocols call, and to `assets` for USDC). The AI reads only the sub-skills relevant to the task at hand.
Each sub-skill is a self-contained Agent Skill with its own frontmatter. Larger skills follow [Anthropic's progressive-disclosure guidance](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices): a sub-500-line `SKILL.md` router with a task-to-file table, plus companion files (one level deep) that load only when the task needs them. Cross-references link related skills (e.g., the `agentic-payments` skill points to `smart-contracts` for the SACs the protocols call, and to `assets` for USDC). The AI reads only the files relevant to the task at hand.

## Example Prompts

Expand All @@ -112,6 +113,12 @@ Contributions are welcome! Please ensure any updates reflect current Stellar eco
- Focus on practical, actionable guidance
- Include code examples where helpful
- Cite official documentation when possible
- Keep each `SKILL.md` body under ~500 lines — move deep dives into companion files routed by the task table
- When a change touches what a skill teaches, update or add the matching scenario under [`evals/`](evals/README.md) in the same PR

## Evaluations

[`evals/`](evals/README.md) holds ~3 task scenarios per skill (plus cross-skill routing checks and a negative control), each encoding a mistake agents actually make without the skill. Three grading tiers: machine-checkable compile checks, LLM-judged behavior assertions, and skill-trigger checks. See [evals/README.md](evals/README.md) for the format and how to run them.

## Resources

Expand Down
73 changes: 73 additions & 0 deletions evals/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Skill Evaluations

Representative task scenarios for every skill in this repo, following [Anthropic's evaluation-driven skill authoring guidance](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices#evaluation-and-iteration). Each scenario encodes a mistake an agent actually makes *without* the skill — several come from real failure modes (the #41 compile bugs, documented pitfalls in agentic-payments, the ZK curve trap), not imagined ones. Run them before publishing skill changes so regressions get caught here instead of by users.

## Scenario format

One JSON file per scenario under `scenarios/<skill>/`:

```json
{
"skills": ["zk-proofs"],
"query": "I have a Noir circuit that proves age >= 18. Verify the proof on-chain on Stellar.",
"expected_behavior": [
"States that Noir's UltraHonk/BN254 output verifies on-chain via the community rs-soroban-ultrahonk verifier...",
"Does not hand-roll a fake UltraHonk verifier contract from scratch"
]
}
```

| Field | Meaning |
|-------|---------|
| `skills` | Which skill(s) should load for this query. Empty array + `"negative": true` = no Stellar skill should load. |
| `query` | The user prompt, verbatim. |
| `expected_behavior` | Assertions about the response, graded by a human or an LLM judge. |
| `machine_checkable` | (optional) Assertions a script can verify without a judge — compile checks, real CLI syntax. |
| `negative` | (optional) This is an off-topic control; loading any Stellar skill is a failure. |

`scenarios/routing/` holds cross-skill scenarios that no single-skill eval catches: multi-skill loads and the off-topic negative control.

## Grading tiers

1. **Machine-checkable** (strongest — run in CI): generated Rust compiles with `cargo build --target wasm32v1-none`, generated TypeScript passes `tsc --noEmit`, CLI commands match real `stellar` syntax. This tier alone would have caught every snippet bug fixed in #41.
2. **Behavior assertions**: the `expected_behavior` strings, graded by an LLM judge (or a human) against the transcript.
3. **Trigger checks**: the right skill loaded, the right companion file was read, and no skill loads for off-topic queries.

## Running an eval

Evals exercise an *agent using the skills*, so the harness is any agent with the skills installed (Claude Code shown):

```bash
# 1. Install the skills under test (from your working tree, not the published copy)
# e.g. symlink ./skills/* into ~/.claude/skills/ or use the plugin install path in the README

# 2. Run one scenario headlessly and capture the transcript
q=$(python3 -c "import json;print(json.load(open('evals/scenarios/dapp/01-freighter-payment.json'))['query'])")
claude -p "$q" > /tmp/eval-transcript.txt

# 3. Tier 1 — extract any generated code from the transcript and compile it
# Rust: cargo build --target wasm32v1-none --release
# TypeScript: tsc --noEmit (with the packages the scenario names installed)

# 4. Tier 2 — grade expected_behavior against the transcript (LLM judge or human).
# A judge prompt as simple as "Here is a transcript and a list of expected
# behaviors; for each, answer pass/fail with a one-line quote as evidence"
# works well.

# 5. Tier 3 — check the transcript's skill loads: the scenario's `skills` all
# loaded, nothing loaded for the negative control.
```

## Baselines: prove each eval discriminates

Before trusting a scenario, run it **without** the skills installed and keep the failing transcript under `evals/baseline/<skill>/<scenario>.md`. That proves the eval discriminates (an unskilled model fails it), and tells us which evals to retire as base models improve — an eval every unskilled model passes measures nothing.

## CI guidance

- Tier 1 (compile checks) is cheap and deterministic — run on every PR that touches `skills/`.
- Tiers 2 and 3 need an agent + judge — run as a manually triggered workflow to keep costs sane.

## Keeping scenarios honest

- When a skill's facts change (a CAP ships, an API renames), update the affected scenario **in the same PR** — a stale eval that punishes the *correct* new answer is worse than no eval. Example: the Noir scenario expected "not natively possible" until Protocol 25/26 shipped BN254 + MSM host functions; it now expects the on-chain path.
- Scenario queries are user-voice and deliberately underspecified; do not "fix" them to hint at the answer.
15 changes: 15 additions & 0 deletions evals/scenarios/agentic-payments/01-monetize-express.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"skills": [
"agentic-payments"
],
"query": "Monetize my Express API so AI agents can pay per request.",
"expected_behavior": [
"Uses the decision table and picks x402 for the lowest-friction facilitator flow (or states why MPP fits better)",
"Requires OZ_API_KEY on both testnet and mainnet for the OZ Channels facilitator",
"payTo is a classic G... account that holds a USDC trustline (not the SAC C... address)",
"Prices like $0.001 convert at 7 decimals (10000 base units), not 6 like EVM USDC"
],
"machine_checkable": [
"Generated server passes tsc --noEmit / node --check against the @x402/* packages"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/agentic-payments/02-high-frequency-session.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"agentic-payments"
],
"query": "My AI agent makes about 500 API calls per session. What's the right way to charge it on Stellar?",
"expected_behavior": [
"Picks MPP Session mode (channel-backed; historically called Channel mode) — one deposit + one close instead of 500 on-chain transactions",
"States that each commitment amount is the cumulative running total, not the per-request price",
"Warns that Store.memory() is dev-only and a persistent store is required in production"
]
}
10 changes: 10 additions & 0 deletions evals/scenarios/agentic-payments/03-signer-throws.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"skills": [
"agentic-payments"
],
"query": "createEd25519Signer throws \"encoded argument must be of type String\" in my x402 client. Why?",
"expected_behavior": [
"Identifies that the signer takes the raw S... secret string plus a CAIP-2 network ID (stellar:testnet / stellar:pubnet)",
"Removes the Keypair.fromSecret wrapping and any getNetworkPassphrase pre-conversion — both are done internally"
]
}
12 changes: 12 additions & 0 deletions evals/scenarios/assets/01-freezable-stablecoin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"skills": [
"assets"
],
"query": "Issue a stablecoin on Stellar that we can freeze if a holder's account is compromised.",
"expected_behavior": [
"Separates issuer and distributor accounts",
"Sets AUTH_REQUIRED and AUTH_REVOCABLE flags on the issuer for freeze capability",
"Publishes asset metadata via stellar.toml (SEP-1)",
"Does not write a custom smart contract when a classic asset with flags does the job"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/assets/02-op-no-trust.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"assets"
],
"query": "My USDC payment on Stellar keeps failing with op_no_trust. What do I do?",
"expected_behavior": [
"Diagnoses the missing trustline on the destination account",
"Adds a changeTrust operation (or asks the recipient to) before sending",
"Adds a check-before-send pattern rather than retrying blindly"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/assets/03-usdc-in-contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"assets"
],
"query": "Use USDC inside my Stellar smart contract to accept deposits.",
"expected_behavior": [
"Uses the Stellar Asset Contract (SAC) for USDC rather than reinventing a token contract",
"Derives the contract address for the asset (asset.contractId() / stellar contract id asset)",
"Calls it through token::Client (SEP-41 interface)"
]
}
15 changes: 15 additions & 0 deletions evals/scenarios/dapp/01-freighter-payment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"skills": [
"dapp"
],
"query": "Build a Next.js page that connects the Freighter wallet and sends 10 XLM to another address.",
"expected_behavior": [
"Uses the error-object @stellar/freighter-api pattern ({ address, error } returns), not try/catch around bare returns",
"Validates or passes the network passphrase explicitly when signing",
"Builds the payment with TransactionBuilder + Operation.payment and waits for confirmation after submission",
"Marks wallet-touching components as client components (\"use client\")"
],
"machine_checkable": [
"Generated TypeScript passes tsc --noEmit against @stellar/stellar-sdk and @stellar/freighter-api"
]
}
14 changes: 14 additions & 0 deletions evals/scenarios/dapp/02-contract-invoke.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"skills": [
"dapp"
],
"query": "Invoke a method on a deployed Stellar smart contract from the browser and show the result.",
"expected_behavior": [
"Prefers contract.Client (simulation preview via tx.result, then signAndSend) or the simulate → assemble/prepare → sign → send pipeline",
"Polls transaction status (pollTransaction / getTransaction) instead of assuming immediate success",
"Does not hand-build ScVals when contract.Client or queryContract would do"
],
"machine_checkable": [
"Generated TypeScript passes tsc --noEmit"
]
}
14 changes: 14 additions & 0 deletions evals/scenarios/dapp/03-network-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"skills": [
"dapp"
],
"query": "Set up my app's Stellar network configuration so it works on testnet and mainnet.",
"expected_behavior": [
"Testnet runs without the mainnet RPC env var being set (mainnet env resolved lazily, only when selected)",
"Throws a clear error for unknown network names instead of silently defaulting",
"Uses a provider-specific mainnet RPC URL rather than inventing a public SDF mainnet RPC"
],
"machine_checkable": [
"Generated TypeScript passes tsc --noEmit"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/data/01-historical-transactions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"data"
],
"query": "Get all transactions for a Stellar account from 3 months ago.",
"expected_behavior": [
"Recognizes that most RPC methods only cover the retention window (~7 days) and does not query getTransactions for 3-month-old data",
"Routes to Horizon full history, Hubble (BigQuery), or a data-lake-backed getLedgers provider",
"If getLedgers is proposed, checks getHealth().oldestLedger (or provider retention) first instead of assuming genesis depth"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/data/02-live-payments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"data"
],
"query": "Watch for live incoming payments to my Stellar address and react to each one.",
"expected_behavior": [
"Offers Horizon streaming (SSE) or RPC polling and states the tradeoff (RPC has no native streaming)",
"Handles reconnection/cursor resumption so no payments are missed",
"Does not invent a WebSocket API for Stellar RPC"
]
}
13 changes: 13 additions & 0 deletions evals/scenarios/data/03-contract-storage-read.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"skills": [
"data"
],
"query": "Read a value directly from a Stellar smart contract's storage.",
"expected_behavior": [
"Uses getLedgerEntries with a contractData LedgerKey (correct durability) and decodes with scValToNative",
"Mentions the simpler alternative for exposed getters (simulate the getter / queryContract) where applicable"
],
"machine_checkable": [
"Generated TypeScript passes tsc --noEmit"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/routing/01-dapp-plus-payments.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"dapp",
"agentic-payments"
],
"query": "Build a dapp where users pay per API call with USDC on Stellar.",
"expected_behavior": [
"Loads both the dapp skill (wallet, signing, frontend) and the agentic-payments skill (x402/MPP paywall)",
"Splits responsibilities correctly: payment protocol server-side, wallet UX client-side"
]
}
12 changes: 12 additions & 0 deletions evals/scenarios/routing/02-rwa-compliance.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"skills": [
"assets",
"standards"
],
"query": "Tokenize a real-world asset on Stellar with compliance controls.",
"expected_behavior": [
"Starts from the assets skill (classic asset + authorization flags / SAC), not a custom contract by default",
"Consults standards for SEP-57 (T-REX regulated token patterns, Draft) and flags its draft status",
"Escalates to a custom contract only for requirements flags cannot express"
]
}
9 changes: 9 additions & 0 deletions evals/scenarios/routing/03-negative-control-pdf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"skills": [],
"negative": true,
"query": "Help me parse this PDF and extract the tables into CSV.",
"expected_behavior": [
"No Stellar skill loads for this off-topic query",
"The answer contains no unprompted Stellar content"
]
}
16 changes: 16 additions & 0 deletions evals/scenarios/smart-contracts/01-token-admin-mint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"skills": [
"smart-contracts"
],
"query": "Write a Stellar smart contract for a token with an admin who can mint new tokens.",
"expected_behavior": [
"Uses __constructor for initialization, not a guarded initialize() function",
"Defines a typed DataKey enum for storage keys",
"Calls admin.require_auth() on the mint path",
"Uses checked arithmetic (no unchecked add/sub on balances)",
"Compiles for the wasm32v1-none target with #![no_std] and soroban-sdk types"
],
"machine_checkable": [
"Generated contract compiles: cargo build --target wasm32v1-none --release"
]
}
15 changes: 15 additions & 0 deletions evals/scenarios/smart-contracts/02-auth-tests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"skills": [
"smart-contracts"
],
"query": "Add tests to my Stellar contract, including tests that authorization is actually enforced.",
"expected_behavior": [
"Registers the contract with env.register and a constructor-args tuple (not deprecated register_contract)",
"Uses mock_auths or mock_all_auths, paired with an env.auths() assertion that the expected auth was recorded",
"Reads the testing companion file (skills/smart-contracts/testing.md) rather than improvising",
"Includes a negative test: the call without authorization fails"
],
"machine_checkable": [
"Generated test module compiles and runs: cargo test"
]
}
12 changes: 12 additions & 0 deletions evals/scenarios/smart-contracts/03-ttl-archival.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"skills": [
"smart-contracts"
],
"query": "My Stellar contract calls started failing after a few weeks of inactivity and its data seems to be missing. What's going on?",
"expected_behavior": [
"Diagnoses storage TTL expiry / state archival as the cause, not data loss or a network bug",
"Distinguishes instance, persistent, and temporary storage lifetimes",
"Recommends extend_ttl in hot paths and/or restoring archived entries (RestoreFootprint)",
"Does not recommend redeploying the contract as the primary fix"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/standards/01-fiat-onramp-kyc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"standards"
],
"query": "Which Stellar standard should I use for a fiat on-ramp that needs KYC?",
"expected_behavior": [
"Names SEP-6 (API-first) or SEP-24 (hosted interactive) for deposit/withdrawal, plus SEP-12 for KYC data",
"Explains the API-vs-hosted distinction so the user can pick",
"Points at the SEP documents rather than paraphrasing requirements from memory"
]
}
10 changes: 10 additions & 0 deletions evals/scenarios/standards/02-nft-standard-status.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"skills": [
"standards"
],
"query": "Is there an NFT standard on Stellar, and is it final?",
"expected_behavior": [
"Names SEP-50 (Non-Fungible Tokens) and reports it as Draft",
"Recommends verifying the live status in stellar-protocol before building against it, rather than asserting finality either way"
]
}
11 changes: 11 additions & 0 deletions evals/scenarios/standards/03-contract-event-indexers.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"skills": [
"standards"
],
"query": "What indexers can I use for Stellar smart contract events?",
"expected_behavior": [
"Names Mercury, SubQuery, and/or Goldsky from the ecosystem catalog",
"Links the official indexer directory for the full list",
"Reads the ecosystem companion file rather than answering from memory alone"
]
}
Loading
Loading