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

ChainAbstract (chain ID 2741)
RPChttps://api.abs.xyz
Explorerabscan.org
LitanyCards0xd44abe71c312FCAf73cC20f7DF61C39A89C203eB
LitanyRenderer0x4044dA12e3d20A865A733802F84F7bDb4892Ce0C
Supply8,000 max (200 team, 7,800 public)
Mint price0.0025 ETH per card
Max per tx200
StandardERC-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

PlatformURL pattern
OpenSeahttps://opensea.io/item/abstract/0xd44abe71c312fcaf73cc20f7df61c39a89c203eb/{tokenId}
Abscanhttps://abscan.org/token/0xd44abe71c312FCAf73cC20f7DF61C39A89C203eB?a={tokenId}
Litany Inventoryhttps://litany.gg/inventory

Card System Reference

Six Classes

IDClassProfile
0StrikerDirect action, decisive force
1ExtractorSustained yield, compound advantage
2AnalyzerPattern recognition, predictive modeling
3DisruptorChaos, illegible strategy
4SentinelDefensive endurance, positional control
5ProphetAnticipation, 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).

TierNameIndices% of Supply
0BASELINE0–5~15%
1NOMINAL6–11~30%
2ELEVATED12–17~30%
3CRITICAL18–23~18%
4APEX24–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.

RarityIndex Range% of Supply~Per Trait
Common0–49~50%~80 each
Uncommon50–99~25%~40 each
Rare100–149~13%~20 each
Epic150–179~9%~25 each
Legendary180–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

  1. Each Litany Card lets you claim one Hollow (free). 8,000 cards, 5,000 Hollows. First come, first served.
  2. Litany Cards are composable firmware. Any game contract on the protocol reads them. Different games will value different stat profiles.
  3. The protocol is agent-native. All data is text. All interfaces are contract calls. No frontend required.
  4. 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 served

Full 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