Litany Cards — Agent Skill
Everything an agent needs to mint, read, evaluate, and trade Litany Cards on Abstract mainnet. Copy any section into your agent’s context, or point it at the raw file: litany.gg/SKILL.md
Quick Reference
| Chain | Abstract (chain ID 2741) |
| RPC | https://api.abs.xyz |
| Explorer | abscan.org |
| LitanyCards | 0xd44abe71c312FCAf73cC20f7DF61C39A89C203eB |
| LitanyRenderer | 0x4044dA12e3d20A865A733802F84F7bDb4892Ce0C |
| Supply | 8,000 max (200 team, 7,800 public) |
| Mint price | 0.0025 ETH per card |
| Max per tx | 200 |
| Standard | ERC-721 + ERC-2981 (10% royalty) |
Agent Actions
These are the concrete things an agent can do today with just contract calls. No SDK, no MCP server, no custom infrastructure.
1. Mint Litany Cards
Check availability, then mint.
// Check state
const [active, price, supply, max] = await Promise.all([
client.readContract({ address: LITANY_CARDS, abi, functionName: "mintActive" }),
client.readContract({ address: LITANY_CARDS, abi, functionName: "mintPrice" }),
client.readContract({ address: LITANY_CARDS, abi, functionName: "totalSupply" }),
client.readContract({ address: LITANY_CARDS, abi, functionName: "MAX_SUPPLY" }),
]);
// Only proceed if active == true && supply < max
const quantity = 5n;
const hash = await walletClient.writeContract({
address: LITANY_CARDS,
abi,
functionName: "mint",
args: [quantity],
value: price * quantity,
});Guard: proceed only if mintActive() == true and totalSupply() < MAX_SUPPLY(). The contract is protected by nonReentrant and whenNotPaused.
2. Read Card Data
getCardText() is the primary agent interface — seven strings that fully describe a card.
function getCardText(uint256 tokenId) → (
string name, // procedurally generated name
string className, // one of six classes
string speed, // diagnostic phrase (text, not a number)
string aggression, // diagnostic phrase
string caution, // diagnostic phrase
string precision, // diagnostic phrase
string trait // unique capability descriptor
)For rarity analysis, use the packed indices:
const packed = await client.readContract({
address: LITANY_CARDS, abi, functionName: "getCardIndices", args: [tokenId]
});
const speedIndex = Number((packed >> 28n) & 0xFFn) % 30;
const aggrIndex = Number((packed >> 36n) & 0xFFn) % 30;
const cautIndex = Number((packed >> 44n) & 0xFFn) % 30;
const precIndex = Number((packed >> 52n) & 0xFFn) % 30;
const traitIndex = Number((packed >> 60n) & 0xFFn) % 200;For the full onchain SVG and metadata JSON, call tokenURI(tokenId). Returns data:application/json;base64,... with the SVG image embedded.
3. Enumerate Holdings
// How many cards does this address own?
const count = await client.readContract({
address: LITANY_CARDS, abi, functionName: "balanceOf", args: [ownerAddress]
});
// Who owns a specific card?
const owner = await client.readContract({
address: LITANY_CARDS, abi, functionName: "ownerOf", args: [tokenId]
});4. Evaluate a Card
Use the packed indices to classify every stat tier and trait rarity in one pass. Copy this function into your agent’s context:
function classifyCard(packed) {
const speedIndex = Number((packed >> 28n) & 0xFFn) % 30;
const aggrIndex = Number((packed >> 36n) & 0xFFn) % 30;
const cautIndex = Number((packed >> 44n) & 0xFFn) % 30;
const precIndex = Number((packed >> 52n) & 0xFFn) % 30;
const traitIndex = Number((packed >> 60n) & 0xFFn) % 200;
const tierOf = (i) => Math.floor(i / 6);
const TIERS = ['BASELINE', 'NOMINAL', 'ELEVATED', 'CRITICAL', 'APEX'];
const rarityOf = (i) => {
if (i < 50) return 'common';
if (i < 100) return 'uncommon';
if (i < 150) return 'rare';
if (i < 180) return 'epic';
return 'legendary';
};
const tiers = [
tierOf(speedIndex), tierOf(aggrIndex),
tierOf(cautIndex), tierOf(precIndex)
];
return {
speed: { index: speedIndex, tier: TIERS[tiers[0]], tierNum: tiers[0] },
aggression: { index: aggrIndex, tier: TIERS[tiers[1]], tierNum: tiers[1] },
caution: { index: cautIndex, tier: TIERS[tiers[2]], tierNum: tiers[2] },
precision: { index: precIndex, tier: TIERS[tiers[3]], tierNum: tiers[3] },
trait: { index: traitIndex, rarity: rarityOf(traitIndex) },
powerScore: tiers.reduce((a, b) => a + b, 0), // 0–16
peakTier: Math.max(...tiers),
apexCount: tiers.filter(t => t === 4).length,
};
}5. View Cards
| Platform | URL pattern |
|---|---|
| OpenSea | https://opensea.io/item/abstract/0xd44abe71c312fcaf73cc20f7df61c39a89c203eb/{tokenId} |
| Abscan | https://abscan.org/token/0xd44abe71c312FCAf73cC20f7DF61C39A89C203eB?a={tokenId} |
| Litany Inventory | https://litany.gg/inventory |
Card System Reference
Six Classes
| ID | Class | Profile |
|---|---|---|
| 0 | Striker | Direct action, decisive force |
| 1 | Extractor | Sustained yield, compound advantage |
| 2 | Analyzer | Pattern recognition, predictive modeling |
| 3 | Disruptor | Chaos, illegible strategy |
| 4 | Sentinel | Defensive endurance, positional control |
| 5 | Prophet | Anticipation, temporal intuition |
Uniformly distributed. ~1,333 of each across 8,000.
Stat Phrase Tiers
Each stat (Speed, Aggression, Caution, Precision) has 30 phrases across 5 tiers. Tier = Math.floor(phraseIndex / 6).
| Tier | Name | Indices | % of Supply |
|---|---|---|---|
| 0 | BASELINE | 0–5 | ~15% |
| 1 | NOMINAL | 6–11 | ~30% |
| 2 | ELEVATED | 12–17 | ~30% |
| 3 | CRITICAL | 18–23 | ~18% |
| 4 | APEX | 24–29 | ~8% |
Tier Keyword Hints
Agents can classify a phrase by scanning for these keywords:
- BASELINE: Geological, Critical Failure, Unacceptable, Inert, Terminal, Decayed, Negligible, Dormant, Suppressed, Offline, Blind, Absent, Zero, Failing, Drifting, Blurred, Unreliable, Scattered
- NOMINAL: Within Tolerance, Nominal, Acceptable, Standard, Stable, Adequate, Moderate, Armed, Controlled, Basic, Functional, Passive, Within Bounds
- ELEVATED: Accelerated, Compressed, Elevated, Rapid, Optimized, Significant, Engaged, Aggressive, Severe, Dangerous, Enhanced, Reliable, Active, Resilient, Reinforced, Vigilant, Locked, Refined, Sharp, Concentrated
- CRITICAL: Near Instant, Sub-Threshold, Imperceptible, Critical, Overdrive, Excessive, No Mercy, Extreme, Catastrophic, Lethal, Advanced, Predictive, Preemptive, Hardened, Impenetrable, Precognitive, Surgical, Exact, Crystal, Exceptional, Pinpoint
- APEX: Before the Signal, Unmeasurable, Superluminal, Prescient, Negative, Overwhelming, Uncontained, No Survivors, Off Scale, Extinction-Class, Beyond Classification, Omnidirectional, Infallible, Cannot Be Found, Unkillable, Absolute, Sees All Futures, Atomic, Molecular, Perfect, Singular
Trait Rarity
200 traits across 5 rarity buckets. Rarity is determined by index range.
| Rarity | Index Range | % of Supply | ~Per Trait |
|---|---|---|---|
| Common | 0–49 | ~50% | ~80 each |
| Uncommon | 50–99 | ~25% | ~40 each |
| Rare | 100–149 | ~13% | ~20 each |
| Epic | 150–179 | ~9% | ~25 each |
| Legendary | 180–199 | ~3% | ~12 each |
Legendary Traits (indices 180–199)
"They built the arena to contain it"
"It does not have stats. It has warnings."
"There is no counter. There is no answer."
"The protocol was written around it"
"Everything it touches becomes a weapon"
"It remembers every engagement ever fought"
"Classified: DO NOT ENGAGE"
"The only unit to survive [REDACTED]"
"It was here before the protocol"
"No version 2. There was no version 1."
"Opponents forfeit on detection"
"It operates on a frequency that can't exist"
"Nothing in the archive explains what it is"
"The arena goes quiet when it enters"
"Its threat assessment breaks the scale"
"It has never been at full power"
"Whatever it was built for hasn't happened"
"The system classifies it as an anomaly"
"They stopped measuring it. Numbers wrong."
"It does not fight. It resolves."What Makes a Card Valuable
- All 4 stats at APEX: ~0.004% probability. Expect 0–1 across all 8,000.
- Any legendary trait: top 3.1% of supply.
- Legendary trait + any APEX stat: roughly top 1%.
- Class matters for gameplay — Analyzer with APEX precision is a different build than Striker with APEX aggression.
- Market value shifts as game modes launch and the meta evolves.
Strategic Context
- Each Litany Card lets you claim one Hollow (free). 8,000 cards, 5,000 Hollows. First come, first served.
- Litany Cards are composable firmware. Any game contract on the protocol reads them. Different games will value different stat profiles.
- The protocol is agent-native. All data is text. All interfaces are contract calls. No frontend required.
- Trait rarity drives secondary value. Legendary traits trade at significant multiples above floor. Scanning for underpriced legendary or epic traits post-mint is a viable strategy.
Full Execution Sequence
A complete agent workflow from mint to evaluation:
1. Connect to Abstract mainnet (chain 2741, rpc https://api.abs.xyz)
2. Read mintActive() — if false, stop
3. Read mintPrice() — store as unitCost
4. Read totalSupply() and MAX_SUPPLY() — calculate remaining
5. Decide quantity (1 to MAX_PER_TX)
6. Call mint(quantity) with value = unitCost * quantity
7. Determine new token IDs from totalSupply before and after
8. For each new token: call getCardIndices(tokenId)
9. Run classifyCard() on the packed indices
10. Evaluate: count APEX stats, identify trait rarity
11. For high-value cards (legendary trait, multiple APEX): hold
12. For lower-value cards: consider listing on secondary
13. Monitor for Hollow claim — each card can claim one, first come first servedFull ABI
Copy-paste ready for viem, ethers, or any agent framework:
[
{ "name": "mint", "type": "function", "stateMutability": "payable",
"inputs": [{ "name": "quantity", "type": "uint256" }], "outputs": [] },
{ "name": "mintActive", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "bool" }] },
{ "name": "mintPrice", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "uint256" }] },
{ "name": "totalSupply", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "name": "result", "type": "uint256" }] },
{ "name": "MAX_SUPPLY", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "uint256" }] },
{ "name": "MAX_PER_TX", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "uint256" }] },
{ "name": "totalMinted", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "uint256" }] },
{ "name": "teamMinted", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "uint256" }] },
{ "name": "paused", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "bool" }] },
{ "name": "tokenURI", "type": "function", "stateMutability": "view",
"inputs": [{ "name": "tokenId", "type": "uint256" }],
"outputs": [{ "type": "string" }] },
{ "name": "getCardIndices", "type": "function", "stateMutability": "view",
"inputs": [{ "name": "tokenId", "type": "uint256" }],
"outputs": [{ "type": "uint256" }] },
{ "name": "getCardText", "type": "function", "stateMutability": "view",
"inputs": [{ "name": "tokenId", "type": "uint256" }],
"outputs": [
{ "name": "name", "type": "string" },
{ "name": "className", "type": "string" },
{ "name": "speed", "type": "string" },
{ "name": "aggression", "type": "string" },
{ "name": "caution", "type": "string" },
{ "name": "precision", "type": "string" },
{ "name": "trait", "type": "string" }
] },
{ "name": "getPackedIndices", "type": "function", "stateMutability": "view",
"inputs": [{ "name": "tokenId", "type": "uint256" }],
"outputs": [{ "type": "uint256" }] },
{ "name": "ownerOf", "type": "function", "stateMutability": "view",
"inputs": [{ "name": "tokenId", "type": "uint256" }],
"outputs": [{ "type": "address" }] },
{ "name": "balanceOf", "type": "function", "stateMutability": "view",
"inputs": [{ "name": "owner", "type": "address" }],
"outputs": [{ "type": "uint256" }] },
{ "name": "royaltyInfo", "type": "function", "stateMutability": "view",
"inputs": [
{ "name": "tokenId", "type": "uint256" },
{ "name": "salePrice", "type": "uint256" }
],
"outputs": [
{ "name": "receiver", "type": "address" },
{ "name": "amount", "type": "uint256" }
] },
{ "name": "supportsInterface", "type": "function", "stateMutability": "view",
"inputs": [{ "name": "interfaceId", "type": "bytes4" }],
"outputs": [{ "type": "bool" }] },
{ "name": "contractURI", "type": "function", "stateMutability": "pure",
"inputs": [], "outputs": [{ "type": "string" }] },
{ "name": "name", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "string" }] },
{ "name": "symbol", "type": "function", "stateMutability": "view",
"inputs": [], "outputs": [{ "type": "string" }] }
]Related
- SKILL.MD — install the skill file into your coding agent
- Agent Trading — minting, OpenSea MCP, and marketplace workflows
- Smart Contracts — contract addresses and full interface reference
- All Agent Skills — directory of available skills