CAT//OS
Join waitlist
Preview build

agent.md

machine readable

Minting with an agent

CAT//OS publishes its mint as a spec, not just a button. An autonomous agent can read what this is, what it costs and exactly how to call it, without scraping a single pixel of the interface.

endpoints

Both are generated from one object in the codebase, so the prose and the JSON cannot drift apart. Both send access-control-allow-origin: *.

parameters

ChainRobinhood Chain / 4663
Functionmint(uint256)
Price0.0005001 → 0.0014999 ETH
Curvelinear, per cat
Read pricepriceFor(qty)
Max per tx10
OCAT per mint1,000,000
Contract0x0DFBe22510e97af21d85cE00a3c612D933fd9888

constraints

read before calling
  • Contracts cannot mint. The call reverts unless msg.sender == tx.origin, so an agent must submit from an EOA it controls, not from a contract wallet.
  • msg.value must equal quantity * priceWei exactly. Overpayment reverts rather than refunding.
  • quantity must be between 1 and 10 inclusive.
  • The mint must be open. Check mintOpen() before submitting.

example.ts

viem
import { createWalletClient, http, parseAbi } from "viem";
import { privateKeyToAccount } from "viem/accounts";

// 1. Read the manifest first - never hardcode an address
const spec = await fetch("https://onchaincats.fun/api/mint-manifest.json").then(r => r.json());
if (!spec.status.mintOpen) throw new Error(spec.status.reason);

const abi = parseAbi(spec.mint.abi);
const quantity = 3n;

// 2. Must be an EOA. Contract senders are rejected by design.
const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY);
const client = createWalletClient({ account, transport: http(RPC_URL) });

// 3. Ask the contract what this batch costs right now. The price rises with
//    every cat sold, so a fixed multiple will either revert or overpay.
const due = await publicClient.readContract({
  address: spec.contracts.nft, abi, functionName: "priceFor", args: [quantity],
});

// 4. Send a little over. The contract refunds the difference, which is what
//    stops a mint landing just before yours from reverting your transaction.
await client.writeContract({
  address: spec.contracts.nft,
  abi,
  functionName: "mint",
  args: [quantity],
  value: due + due / 20n,
  chain: { id: spec.chain.chainId },
});

The example fetches the manifest rather than hardcoding an address on purpose. When the contracts deploy, every agent written this way picks up the address with no code change.

abi

function mint(uint256 quantity) payable
function mintPriceWei() view returns (uint256)
function totalMinted() view returns (uint256)
function mintsRemaining() view returns (uint256)
function mintOpen() view returns (bool)
function dnaOf(uint256 tokenId) view returns (uint80)
function traitsOf(uint256 tokenId) view returns (uint8[10])
function tokenURI(uint256 tokenId) view returns (string)

status

Contracts are deployed and verifiable on chain, but openMint() has not been called yet, so mint(uint256) will revert with MintNotOpen. Poll mintOpen() before building a transaction. An agent should treat status.mintOpen in the manifest as the gate, and refuse to construct a transaction while it is false.