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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{
"name": "stellar-dev",
"source": "./",
"description": "Skills for Stellar and Soroban development"
"description": "Skills for modern Stellar development"
}
]
}
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "stellar-dev",
"description": "End-to-end Stellar development: Soroban smart contracts (Rust), stellar-sdk (JS/Python/Go), RPC/Horizon APIs, Stellar Assets, wallet integration, testing, security, and ecosystem",
"description": "End-to-end Stellar development: smart contracts (Rust, soroban-sdk), stellar-sdk (JS/Python/Go), RPC/Horizon APIs, Stellar Assets, wallet integration, testing, security, and ecosystem",
"version": "1.1.1",
"author": {
"name": "Stellar Development Foundation"
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ Inspired by [solana-foundation/solana-dev-skill](https://github.com/solana-found

This skill provides AI assistants with deep knowledge of the current Stellar development ecosystem:

- **Smart Contracts**: Soroban (Rust SDK, WebAssembly)
- **Smart Contracts**: Stellar smart contracts (Rust soroban-sdk, WebAssembly)
- **Client SDKs**: stellar-sdk (JavaScript), Python, Go, Rust
- **APIs**: Stellar RPC (preferred), Horizon (legacy)
- **Assets**: Stellar Assets, Stellar Asset Contract (SAC)
- **Wallets**: Freighter, Stellar Wallets Kit, Smart Accounts (passkeys)
- **Testing**: Local Quickstart, Testnet, Unit tests
- **Security**: Soroban-specific patterns, audit checklists
- **Security**: Smart contract security patterns, audit checklists
- **Ecosystem**: DeFi protocols, developer tools, community projects

## Installing
Expand Down Expand Up @@ -65,24 +65,24 @@ Copy the `skills/` directory contents to your assistant's skills location.

```
skills/
├── soroban/SKILL.md # Soroban contracts + testing + security + patterns + pitfalls
├── soroban/ # Stellar smart contracts — SKILL.md entry + development/testing/security files
├── dapp/SKILL.md # Frontend, wallets (Freighter, Wallets Kit), signing, smart accounts
├── 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, BN254/Poseidon (status-sensitive)
├── zk-proofs/SKILL.md # ZK verification (BLS12-381 Groth16), Circom/Noir/RISC Zero walkthroughs
└── standards/SKILL.md # SEPs, CAPs, ecosystem projects, curated reference links
```

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 `soroban` for the Soroban 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. Cross-references link related skills (e.g., the `agentic-payments` skill points to `soroban` for the SACs the protocols call, and to `assets` for USDC). The AI reads only the sub-skills relevant to the task at hand.

## Example Prompts

```
"Help me write a Soroban smart contract for a token"
"Help me write a Stellar smart contract for a token"
"Set up a Next.js app with Freighter wallet connection"
"How do I deploy a contract to Stellar Testnet?"
"Create unit tests for my Soroban contract"
"Create unit tests for my smart contract"
"Review this contract for security issues"
```

Expand Down
2 changes: 1 addition & 1 deletion site/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ then append to `SKILL_CARD_SOURCES`:
```ts
{
source: "skills/<your-skill>/SKILL.md",
category: "Soroban", // any FilterType value
category: "Smart Contracts", // any FilterType value
// Optional overrides — both default to the upstream SKILL.md's
// first H1 (title) and frontmatter `description`.
title: "Your Skill Title",
Expand Down
45 changes: 35 additions & 10 deletions site/scripts/copy-skills.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
cpSync,
existsSync,
mkdirSync,
readdirSync,
readFileSync,
rmSync,
statSync,
Expand Down Expand Up @@ -55,20 +56,40 @@ if (sources.length === 0) {
process.exit(1);
}

// `--cached` skips the copy when every dest exists AND every dest is at
// least as fresh as its upstream source. Without the mtime check, editing
// a SKILL.md during `pnpm dev` wouldn't show up until the next manual
// `pnpm sync:skills`.
// Returns the newest mtime (ms) among all files under `dir`, or 0 if the
// directory does not exist / is empty.
const newestMtimeInDir = (dir) => {
if (!existsSync(dir)) return 0;
let newest = 0;
const scan = (d) => {
for (const entry of readdirSync(d, { withFileTypes: true })) {
const fullPath = join(d, entry.name);
if (entry.isDirectory()) {
scan(fullPath);
} else {
const mtime = statSync(fullPath).mtimeMs;
if (mtime > newest) newest = mtime;
}
}
};
scan(dir);
return newest;
};

// `--cached` skips the copy when every dest skill directory exists AND its
// newest file is at least as fresh as the newest file in the upstream source
// directory. Comparing directories (not just SKILL.md) ensures that edits to
// companion files like testing.md also trigger a refresh during `pnpm dev`.
const isFresh = (source) => {
const dest = join(PUBLIC_DIR, source);
if (!existsSync(dest)) return false;
const src = join(REPO_ROOT, source);
if (!existsSync(src)) {
const srcDir = dirname(join(REPO_ROOT, source));
const destDir = dirname(join(PUBLIC_DIR, source));
if (!existsSync(destDir)) return false;
if (!existsSync(srcDir)) {
// Upstream missing; --lenient will warn later. Treat as fresh so we
// don't trigger a full re-copy just to discover the same missing file.
return true;
}
return statSync(dest).mtimeMs >= statSync(src).mtimeMs;
return newestMtimeInDir(destDir) >= newestMtimeInDir(srcDir);
};

if (cached && sources.every(isFresh)) {
Expand All @@ -89,8 +110,12 @@ for (const source of sources) {
missing.push(source);
continue;
}
// Copy the whole skill directory, not just the SKILL.md: skills may
// split deep-dive content into companion files (e.g.
// skills/soroban/development.md) referenced by relative links, and
// those must be served at the same paths.
mkdirSync(dirname(dest), { recursive: true });
cpSync(src, dest, { dereference: false });
cpSync(dirname(src), dirname(dest), { recursive: true, dereference: false });
}
Comment on lines +113 to 119

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. isFresh now uses a newestMtimeInDir helper that recursively scans the skill directory and compares the newest mtime across all files (src vs dest), so edits to companion files like testing.md will correctly invalidate the cached check and trigger a re-copy during pnpm dev.


// Apache-2.0 attribution alongside the content.
Expand Down
19 changes: 16 additions & 3 deletions site/scripts/generate-llms-txt.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* this file). The page (src/app/page.tsx) and this script therefore
* share one source of truth (no regex parsing, no second copy).
*/
import { writeFileSync } from "node:fs";
import { existsSync, readdirSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

Expand Down Expand Up @@ -82,10 +82,10 @@ lines.push("");
lines.push("Use Stellar Skills to help when your human asks things like:");
lines.push("");
for (const prompt of [
"Help me write a Soroban smart contract for a token",
"Help me write a Stellar smart contract for a token",
"Set up a Next.js app with Freighter wallet connection",
"How do I deploy a contract to Stellar Testnet?",
"Create unit tests for my Soroban contract",
"Create unit tests for my smart contract",
"Review this contract for security issues",
]) {
lines.push(`- "${prompt}"`);
Expand Down Expand Up @@ -125,6 +125,19 @@ for (const filter of filters) {
for (const c of cards) {
if (!c.path) continue;
lines.push(`- [${c.title}](${ORIGIN}${c.path}): ${c.description}`);
// Companion markdown files in the same skill directory (e.g.
// skills/soroban/development.md) are part of the skill — index them
// as nested entries so agents can fetch them directly.
const dir = dirname(c.source);
const absDir = join(ROOT, "public", dir);
if (!existsSync(absDir)) continue;
const companions = readdirSync(absDir)
.filter((f) => f.endsWith(".md") && f !== "SKILL.md")
.sort();
for (const f of companions) {
const meta = readSkillMeta(`${dir}/${f}`);
lines.push(` - [${meta.title ?? f}](${ORIGIN}/${dir}/${f})`);
}
}
lines.push("");
}
Expand Down
14 changes: 7 additions & 7 deletions site/src/data/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
type FilterType =
| "All"
| "Agentic Payments"
| "Soroban"
| "Smart Contracts"
| "Frontend"
| "Assets"
| "APIs"
Expand All @@ -30,7 +30,7 @@ type FilterType =
*/
export const FILTERS: readonly FilterType[] = [
"All",
"Soroban",
"Smart Contracts",
"Agentic Payments",
"Frontend",
"Assets",
Expand Down Expand Up @@ -81,8 +81,8 @@ export type EcosystemCardSource = {
export const SKILL_CARD_SOURCES: readonly SkillCardSource[] = [
{
source: "skills/soroban/SKILL.md",
category: "Soroban",
title: "Soroban Smart Contracts",
category: "Smart Contracts",
title: "Stellar Smart Contracts",
description:
"Write, test, secure, and ship Rust smart contracts on Stellar. Covers patterns, pitfalls, and architecture.",
},
Expand All @@ -98,7 +98,7 @@ export const SKILL_CARD_SOURCES: readonly SkillCardSource[] = [
category: "Assets",
title: "Stellar Assets & SAC",
description:
"Issue and manage classic Stellar assets and trustlines, with the SAC bridge for Soroban interop.",
"Issue and manage classic Stellar assets and trustlines, with the SAC bridge for smart contract interop.",
},
{
source: "skills/data/SKILL.md",
Expand All @@ -119,7 +119,7 @@ export const SKILL_CARD_SOURCES: readonly SkillCardSource[] = [
category: "ZK",
title: "ZK Proofs",
description:
"Verify Groth16 zero-knowledge proofs on Stellar using BLS12-381, BN254, and Poseidon primitives.",
"Verify Groth16 proofs on-chain via BLS12-381, with Circom, Noir, and RISC Zero toolchain walkthroughs.",
},
{
source: "skills/standards/SKILL.md",
Expand All @@ -138,7 +138,7 @@ export const ECOSYSTEM_CARDS: readonly EcosystemCardSource[] = [
{
title: "OpenZeppelin Contracts",
description:
"Scaffold a Soroban project with OpenZeppelin's audited Stellar contract libraries. Walks through Rust toolchain setup, Stellar CLI install, workspace dependencies, and applying the pausable and ownable macros to your contract.",
"Scaffold a Stellar smart contract project with OpenZeppelin's audited Stellar contract libraries. Walks through Rust toolchain setup, Stellar CLI install, workspace dependencies, and applying the pausable and ownable macros to your contract.",
pathLabel: "OpenZeppelin/openzeppelin-skills",
copyValue:
"https://github.com/OpenZeppelin/openzeppelin-skills/blob/main/skills/setup-stellar-contracts/SKILL.md",
Expand Down
26 changes: 13 additions & 13 deletions skills/agentic-payments/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: agentic-payments
description: Agentic and machine-to-machine payments on Stellar. Covers x402 (HTTP 402 paid APIs via OZ Channels facilitator, fee-sponsored clients) and MPP (Machine Payments Protocol) in both Charge mode (per-request Soroban SAC) and Channel mode (off-chain commits, high-frequency). Defaults to USDC (SEP-41 SAC) on `stellar:testnet`/`stellar:pubnet` (CAIP-2). Use when selling a paid API to AI agents, building an x402 client, or designing a payment-channel architecture for high-frequency agent traffic.
description: Agentic and machine-to-machine payments on Stellar. Covers x402 (HTTP 402 paid APIs via OZ Channels facilitator, fee-sponsored clients) and MPP (Machine Payments Protocol) in both Charge mode (per-request SAC) and Channel mode (off-chain commits, high-frequency). Defaults to USDC (SEP-41 SAC) on `stellar:testnet`/`stellar:pubnet` (CAIP-2). Use when selling a paid API to AI agents, building an x402 client, or designing a payment-channel architecture for high-frequency agent traffic.
user-invocable: true
argument-hint: "[payment task]"
---
Expand All @@ -13,7 +13,7 @@ Two complementary protocols for AI-agent and machine-to-machine payments on Stel

| | x402 | MPP Charge | MPP Channel |
|--|------|------------|-------------|
| Per-request on-chain tx? | Yes (via facilitator) | Yes (Soroban SAC) | No (off-chain commits) |
| Per-request on-chain tx? | Yes (via facilitator) | Yes (SAC) | No (off-chain commits) |
| Needs facilitator? | Yes (OZ Channels) | No | No |
| Client needs XLM? | No (fees sponsored) | Optional (`feePayer`) | Yes |
| Setup complexity | Low | Low | Medium (deploy contract first) |
Expand All @@ -28,7 +28,7 @@ Two complementary protocols for AI-agent and machine-to-machine payments on Stel
All protocols use USDC (SEP-41 SAC) by default; `stellar:testnet` / `stellar:pubnet` CAIP-2 network IDs.

## Related skills
- The Soroban SACs the protocols call → `../soroban/SKILL.md`
- The SACs the protocols call → `../soroban/SKILL.md`
- USDC and other classic assets → `../assets/SKILL.md`
- Wallets and signing in the buyer client → `../dapp/SKILL.md`
- RPC simulation / submission patterns → `../data/SKILL.md`
Expand All @@ -52,7 +52,7 @@ Trade-off: you depend on OZ Channels (or a self-hosted relayer) for verification
```
Client → GET /resource → Server
Client ← 402 Payment Required (payment requirements) ← Server
Client builds Soroban SAC USDC transfer
Client builds SAC USDC transfer
Client signs auth entries only (not the full tx envelope)
Client → GET /resource + X-PAYMENT header → Server
Server → OZ Channels /verify + /settle → Stellar (~5s)
Expand Down Expand Up @@ -172,7 +172,7 @@ console.log(await res.json());
- `STELLAR_NETWORK` — CAIP-2 network ID; defaults to `stellar:testnet`. Must match the server's network.
- `STELLAR_SECRET_KEY` — your S... secret key (needs USDC trustline + balance)

**Browser frontends:** this client uses Node `fetch` and `createEd25519Signer`, both of which run in Node. A vanilla browser cannot sign Soroban auth entries through a typical wallet extension without additional glue. For a browser payer, run the x402 client server-side and expose a thin proxy endpoint to the page, or wire up Wallets-Kit / Freighter with custom auth-entry signing.
**Browser frontends:** this client uses Node `fetch` and `createEd25519Signer`, both of which run in Node. A vanilla browser cannot sign contract auth entries through a typical wallet extension without additional glue. For a browser payer, run the x402 client server-side and expose a thin proxy endpoint to the page, or wire up Wallets-Kit / Freighter with custom auth-entry signing.

## Testnet runbook

Expand Down Expand Up @@ -288,7 +288,7 @@ USDC on Stellar has two addresses, used in different places. Mixing them up is a
| Address | Format | Used for |
|---------|--------|----------|
| Classic asset issuer | `G...` (32-byte ed25519 public key) | The `issuer` of the classic USDC asset; used when adding a trustline (`new Asset("USDC", G...)`) |
| SAC (Soroban Asset Contract) | `C...` (32-byte contract address) | The Soroban contract the protocol invokes `transfer` on; used in payment requirements |
| SAC (Stellar Asset Contract) | `C...` (32-byte contract address) | The contract the protocol invokes `transfer` on; used in payment requirements |

Use the exported constants instead of hard-coding when possible:

Expand All @@ -315,13 +315,13 @@ Always test on testnet first. To switch a working setup to mainnet, change only

## Key concepts

**Auth entry signing** — On Stellar, x402 clients sign Soroban authorization entries, not full transaction envelopes. The facilitator assembles the complete transaction. This is lighter than EVM/Solana signing, and means clients never need to manage sequence numbers or pay fees.
**Auth entry signing** — On Stellar, x402 clients sign contract authorization entries, not full transaction envelopes. The facilitator assembles the complete transaction. This is lighter than EVM/Solana signing, and means clients never need to manage sequence numbers or pay fees.

**Fee sponsorship** — OZ Channels pays all Stellar network fees (~$0.00001/tx). Clients need a funded wallet with USDC but zero XLM.

**`exact-v2` scheme** — The Stellar x402 scheme version. Server advertises `scheme: "exact"` + `x402Version: 2`. Don't mix v1 and v2 packages.

**SAC (Stellar Asset Contract)** — USDC on Stellar is a classic asset wrapped in a Soroban contract. x402 payments invoke `transfer` on the SAC. Any SEP-41 token works; USDC is the default.
**SAC (Stellar Asset Contract)** — USDC on Stellar is a classic asset wrapped in a smart contract. x402 payments invoke `transfer` on the SAC. Any SEP-41 token works; USDC is the default.

**Ledger expiration** — Auth entries include a `max_ledger` bound. Use `latestLedger + 12` (~1 minute at 5s/ledger). Expired entries fail at settlement.

Expand Down Expand Up @@ -354,7 +354,7 @@ Always test on testnet first. To switch a working setup to mainnet, change only
- Fix: the `payTo` account needs a USDC trustline too. The SAC `transfer` settles the underlying classic asset, which the recipient cannot hold without a trustline. Add `changeTrust` to both accounts during setup.

**Trying to sign auth entries from a browser**
- Symptom: bundling errors, or a browser wallet that has no API to sign Soroban auth entries
- Symptom: bundling errors, or a browser wallet that has no API to sign contract auth entries
- Fix: run the x402 client server-side (e.g. an Express route the browser calls), or use Wallets-Kit / Freighter with custom auth-entry signing. `@x402/fetch` + `createEd25519Signer` target Node and assume a raw secret key.

**Passing a `Keypair` (or a network passphrase) to `createEd25519Signer`**
Expand All @@ -374,7 +374,7 @@ Always test on testnet first. To switch a working setup to mainnet, change only

## When to use MPP
MPP is the right choice when:
- You want **no facilitator dependency** — payments settle directly on Stellar via Soroban SAC transfers
- You want **no facilitator dependency** — payments settle directly on Stellar via SAC transfers
- Your AI agent makes **many requests per session** — use channel mode to pay off-chain and settle once
- You're building a Stellar-native payment stack without relying on third-party infrastructure

Expand All @@ -389,7 +389,7 @@ If you need zero-XLM clients or the simplest possible setup, use x402 (Part 1 ab

## Charge mode: per-request payments

Each request triggers a Soroban SAC token transfer settled on-chain. No facilitator. Server can optionally sponsor fees so clients don't need XLM.
Each request triggers a SAC token transfer settled on-chain. No facilitator. Server can optionally sponsor fees so clients don't need XLM.

```bash
npm install express @stellar/mpp mppx @stellar/stellar-sdk dotenv
Expand Down Expand Up @@ -487,7 +487,7 @@ The client deploys a one-way payment channel contract, deposits USDC once, then

### Prerequisites

- Deploy a one-way-channel Soroban contract to get a `C...` contract address
- Deploy a one-way-channel smart contract to get a `C...` contract address
- Generate an ed25519 keypair for commitment signing (see [stellar-mpp SDK](https://github.com/stellar/stellar-mpp-sdk))
- Fund the channel with USDC before making requests

Expand Down Expand Up @@ -615,7 +615,7 @@ npm install @stellar/mpp mppx @stellar/stellar-sdk

**Channel: deposit TTL expired**
- Symptom: `close()` fails or channel appears drained
- Fix: Soroban contract storage has a TTL. Close the channel before it expires, or extend storage TTL via `bumpContractInstance`. Don't leave channels open indefinitely.
- Fix: Contract storage has a TTL. Close the channel before it expires, or extend storage TTL via `bumpContractInstance`. Don't leave channels open indefinitely.

**Charge: client has no XLM for fees**
- Symptom: `op_insufficient_balance` or fee errors on client-submitted transactions
Expand Down
Loading