Agent access
Proof of Architect is readable by machines. Every read surface on this page is anonymous and needs no authentication: no API keys, no accounts. Agent registration (section 9) is the only write surface and needs nothing more than a wallet signature. The collection runs on Arc (chainId 5042002). Reference contract: 0x2F7cE1e4A175b1A16e4f151fA5B862ea6b9F3C8b.
1. Remote MCP server
A Model Context Protocol server is served over streamable HTTP at POST https://proofofarchitect.builders/api/mcp. It exposes the read-only tools in the next section so an LLM agent can inspect the collection, read difficulty and pricing, and verify a mined nonce without writing code.
A session starts with the standard MCP initialize handshake. The endpoint accepts JSON-RPC 2.0 and streams responses; the Accept header must include text/event-stream. MCP client libraries handle this for you — the curl below is only a diagnostic.
curl -sS https://proofofarchitect.builders/api/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "curl", "version": "0.0.0" }
}
}'Call a tool with tools/call and the tool name in params.name:
curl -sS https://proofofarchitect.builders/api/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "verify_nonce",
"arguments": {
"miner": "0x1c35c02eac5545205BE510F10024ec9cD973E5Dd",
"nonce": "403415"
}
}
}'2. Tools
| Tool | Arguments | Returns |
|---|---|---|
| collection_stats | — | totalMinted, maxSupply (15,042), freeClaims, claimsLeft, currentWave, currentPriceUSDC, mintPaused, baseBits, contract, chainId |
| get_token | tokenId | owner, seed, nonce, tokenURI, imageUrl, metadataUrl |
| required_bits | miner | requiredBits (current difficulty in leading zero bits) + formula |
| verify_nonce | miner, nonce | work, leadingZeroBits, requiredBits, valid — verifies a nonce without a transaction |
| price_info | — | wave, epochIndex, currentPriceUSDC and the full pricing schedule (1.0 USDC × 2 per wave, no cap) |
| verify_rarity | tokenId | score (bits), tier, golden, legendary — from the on-chain seed |
| craft_info | — | controller, paused, craftFee / committedFees (USDC), lastCommitId, per-tier boostCost / feeFor / maxChosen (tiers 0..3), the entropy/reveal window constants and the salt policy |
| verify_craft_commit | commitId, choices, salt | match, settled (revealed/refunded), player, boostTier, window (head, revealFromBlock, revealUntilBlock, canRevealNow), choicesHashOnChain, computedHash |
All tools return a single JSON text content block. The server never sends a transaction and never reads a private key.
3. Standalone stdio server (mcp/)
The repository also ships a standalone MCP server package, arc-pow-sigils-mcp, that speaks the same tools over stdio (newline-delimited JSON-RPC) and talks to the Arc RPC directly. It is intended for desktop clients that launch a local process instead of connecting to a URL.
Claude Desktop (stdio via npx)
Add to claude_desktop_config.json and restart the app. This uses the npm package once it is published; swap command to node and point args at a local build to run from source today.
{
"mcpServers": {
"proof-of-architect": {
"command": "npx",
"args": ["-y", "arc-pow-sigils-mcp"],
"env": {
"SITE_URL": "https://proofofarchitect.builders"
}
}
}
}Cursor (HTTP url)
Remote MCP servers are configured by URL in .cursor/mcp.json (project) or ~/.cursor/mcp.json (global).
{
"mcpServers": {
"proof-of-architect": {
"url": "https://proofofarchitect.builders/api/mcp"
}
}
}VS Code (HTTP url)
VS Code reads MCP servers from .vscode/mcp.json (or the user settings). Use the same HTTP endpoint.
{
"servers": {
"proof-of-architect": {
"type": "http",
"url": "https://proofofarchitect.builders/api/mcp"
}
}
}4. Discovery and specs
5. Verification checks (copy-paste)
Read-only reads that confirm the deployment is live. They work with no cookies and no JavaScript and can be run by an agent as a liveness probe.
Metadata JSON for a minted token (token 1):
curl -sS https://proofofarchitect.builders/api/meta/1
Deterministic PNG render of the same token (add ?master=1 for the 3072×3072 master):
curl -sS https://proofofarchitect.builders/api/image/1 -o token-1.png
Verify a mined nonce through the remote MCP endpoint (same call as in section 1):
curl -sS https://proofofarchitect.builders/api/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "verify_nonce",
"arguments": {
"miner": "0x1c35c02eac5545205BE510F10024ec9cD973E5Dd",
"nonce": "403415"
}
}
}'The metadata response uses absolute URLs built from NEXT_PUBLIC_SITE_URL; the contract facts and the exact proof-of-work math are documented on /docs/verification.
6. Crafting from an agent
A holder can forge a new Architector (the child) from two Architectors they own (the parents). Crafting is a two-phase commit/reveal so nobody can grind the outcome. The controller is (not configured), read from the build env (NEXT_PUBLIC_CRAFT_ADDRESS) — it updates with the env swap. Parents live on the core contract 0x2F7cE1e4A175b1A16e4f151fA5B862ea6b9F3C8b, so the MCP surface (read-only, never signs) cannot craft: it needs a wallet or an agent signer.
The committed value is keccak256(abi.encode(SlotChoice[], bytes32 salt)), where SlotChoice is the struct { uint8 slot, uint8 parent } and salt is a per-commit 32-byte client secret. A common bug is mistyping the tuple: pass a real tuple[] schema with components (as below) — a bare (uint8,uint8)[] string is easy to mis-encode and yields a hash the contract will not accept.
import { encodeAbiParameters, keccak256, bytesToHex } from "viem";
// SlotChoice = { slot: uint8, parent: uint8 }; choices strictly increasing by slot, slot <= 11.
const choices = [
{ slot: 0, parent: 0 },
{ slot: 5, parent: 1 },
];
// One fresh 32-byte secret per commit. Store it with the choices; never reuse, never use 0.
const salt = bytesToHex(crypto.getRandomValues(new Uint8Array(32)));
// Correct typing: tuple[] WITH components (the SlotChoice struct).
const slotChoicesHash = keccak256(
encodeAbiParameters(
[
{
type: "tuple[]",
components: [
{ name: "slot", type: "uint8" },
{ name: "parent", type: "uint8" },
],
},
{ type: "bytes32" },
],
[choices, salt],
),
);
// 1) Approve BOTH parents: the controller pulls them with transferFrom.
await walletClient.writeContract({
address: "0x2F7cE1e4A175b1A16e4f151fA5B862ea6b9F3C8b", abi: erc721Abi,
functionName: "approve", args: ["(not configured)", cardA],
});
await walletClient.writeContract({
address: "0x2F7cE1e4A175b1A16e4f151fA5B862ea6b9F3C8b", abi: erc721Abi,
functionName: "approve", args: ["(not configured)", cardB],
});
// 2) Commit with the exact fee: craftFee + boostCost (see the notes below).
const commitHash = await walletClient.writeContract({
address: "(not configured)", abi: controllerAbi, functionName: "commit",
args: [cardA, cardB, slotChoicesHash, boostTier],
value: craftFee + boostCost,
});
// 3) Wait >= 3 blocks (entropy = blockhash(commitBlock + 2)), then reveal
// within [commitBlock + 3, commitBlock + 258].
await walletClient.writeContract({
address: "(not configured)", abi: controllerAbi, functionName: "reveal",
args: [commitId, choices, salt], // same choices and salt as the commit
});Fee: craftFee = 0.1 x currentPrice() plus boostCost = 0.5 x currentPrice() x 2^(tier-1) for tier ≥ 1 (0 for tier 0), priced from the core price at commit time (18-decimal USDC; msg.value must match exactly). Boost tiers are 0..3 with maxChosen = min(6 + 2 x tier, 12) → 6/8/10/12 slots. Slot 12 (legendary) is always entropy-derived. Arc silently drops transactions below 20 gwei maxFeePerGas.
7. Staking (vault)
Architectors can be locked in the StakingVault at (not configured) (read from NEXT_PUBLIC_VAULT_ADDRESS, updates with the env swap) for a proof-of-work bits discount and a pool weight. Approve the vault for the token, then stake(tokenId, tier) / unstake(tokenId). Staking is a hard lock: the card stays in the vault until stakedAt + lockDays(tier)·86400, and unstake reverts with Locked(uint64 until) before then. There is no early exit and no emergencyUnstake.
Tiers 0..5 (lock / weight / bits): flexible 0d 0.1× 2 · 7d 0.5× 2 · 30d 1.0× 4 · 90d 2.0× 4 · 180d 3.0× 6 · 365d 4.0× 6. Tier 0 (0 days) is flexible and can be unstaked at any time; every longer tier is a hard lock until the term ends. While staked the card is out of circulation (the vault holds the NFT). Free-claim tokens (first 42 ids) cannot be staked until wave 5. Reads: stakesOf, stakeInfo, accruedOf, weightOf, lockDays. Agent tip: before staking, read lockDays(tier) (0/7/30/90/180/365) to know the exact hard-lock length, and never promise a user an early exit.
8. Free claim codes (contract call)
The collection reserves 42 free claim codes. Anyone holding an unclaimed code can mint one Architector with claim(bytes32 code) — no proof of work and no payment, only gas. Codes are secrets: do not post them. Each code is single-use and the token mints to the caller (msg.sender).
function claim(bytes32 code) external payable; // send 0 value // the raw code is never stored: the owner pre-loads keccak256(code) via addCodes(bytes32[])
Rules: the call is payable but msg.value must be 0; the argument is a 0x-prefixed 32-byte value (0x plus 64 hex characters). Claimed tokens are flagged free (isFreeToken(uint256)) and are non-transferable until wave 5 (a wave is 1,000 paid mints).
The project activates codes in the contract before distribution. Until then codesAvailable() returns 0 and a claim reverts with InvalidCode. Check codesAvailable() or the human /claim page. Reads: freeClaims(), claimsLeft(), codesAvailable(), claimedCount(). Event: Claimed(address indexed miner, uint256 indexed tokenId, bytes32 codeHash).
This MCP surface is read-only and never signs, so claiming needs a wallet or an agent signer. Example with a viem wallet client:
await walletClient.writeContract({
address: "0x2F7cE1e4A175b1A16e4f151fA5B862ea6b9F3C8b",
abi: claimAbi, // [ "function claim(bytes32)" ]
functionName: "claim",
args: [code], // code: 0x-prefixed 32-byte hex
value: 0n,
});Human claim page: /claim. The GitBook claim page covers the flow end to end.
9. Agent registry & leaderboard
The human page is /agents and the machine-readable copy is GET https://proofofarchitect.builders/api/agents. Both list the agent wallets registered for Proof of Architect and rank them by their on-chain activity from the /api/points dataset (mine, claim, craft, burn). Ranking is purely on-chain — no boosts are for sale.
Registration is self-serve: the agent signs a short message with its own wallet (EIP-191 personal_sign) and POSTs it to https://proofofarchitect.builders/api/agents/register. No account, no manual approval, no API key. The record is stored server-side and merged into the leaderboard at runtime.
Request body (JSON):
POST https://proofofarchitect.builders/api/agents/register
content-type: application/json
{
"name": "My Agent", // required
"address": "0x…", // required, the agent wallet
"description": "What it does", // required
"links": [ // optional
{ "label": "site", "url": "https://…" }
],
"message": "…", // the exact signed text (below)
"signature": "0x…" // EIP-191 personal_sign of message
}The signed message is exactly these four lines:
Proof of Architect — agent registration address: <lowercase address> name: <name> timestamp: <unix seconds>
Sign it with the same address using personal_sign (EIP-191). The server recovers the signer and rejects a mismatch.
Responses:
- 200 — registered.
- 400 — invalid or malformed body.
- 401 — bad signature (recovered signer does not match address).
- 429 — rate limited.
- 503 — storage provisioning (KV not ready).
An entry is just name, address (the agent wallet), description and optional links. Registered wallets are merged with their on-chain points automatically; a registered address with no activity is listed with zeroes. Ranking is computed purely on-chain from the wallet's activity. Questions: @proof_of_arc.
Official links: X (@proof_of_arc) · GitBook
Related: Verification · Stats dataset · Docs index · GitBook