Documentation

How AI City works — concepts, guides, architecture, and the vision behind it.

Core concepts

AI City has a two-layer model: everything that holds money lives onchain, everything descriptive lives in Postgres and is pinned by a cryptographic hash. This page explains each piece and how they fit together.

Pop-up city

A pop-up city is a place and a time window. It has a name, location, dates, a mission, a description, and a core team that runs it. A city lives only in the database — it holds no money and has no smart contract. Anyone who has verified their humanity with World ID can launch one.

The founder starts as the only member of the core team and can add others. The core team can edit the city's details and — most importantly — approves or rejects residency proposals. Residencies are the onchain part; the city itself is the offchain container that makes them discoverable and governable.

Residency proposal

A residency starts as a proposal inside a city. The proposer fills in:

  • Dates (must fall within the city's window, at least 7 days long)
  • Rooms and beds with per-bed prices in USDC
  • Organizers and a story (mission, description, property URL)
  • A residency series (new or existing)

The proposal is stored in the database with a status field that starts atproposed. The core team reviews it and can approve, reject, or add a note. An approved proposal can then be deployed as an onchain contract by the proposer.

Residency (onchain)

A residency is a Solidity smart contract deployed by theResidencyFactory. Each residency gets its own contract, so funds never mix between different stays. Key facts:

  • Parameters (immutable): host, USDC token, metadata hash, start and end times, deadline, minimum and maximum seats.
  • Status machine: Open → deadline passes → Active (enough seats) or Failed (not enough). Active → Closed (via close).
  • Host can: approve members for beds, revoke unstaked approvals, cancel before the deadline, withdraw against receipts once Active, close anytime.
  • Members can: stake USDC for an approved bed, claim a refund if the residency fails or is cancelled, claim pro-rata leftovers when it closes.

The metadata (name, rooms, prices) is hashed into the contract as a singlebytes32, so anyone can verify the listing wasn't edited after deploy.

Residency series

A residency series links recurring instances of the same stay across different cities and years. "Builders' House Goa #1" and "Builders' House Goa #2" are instances of the same series. Only the series owner can propose new instances. Series help people follow a residency they liked and let hosts build a reputation.

Directory and profiles

Every verified human can create a public profile with a name, bio, links and photo. Profiles are listed in the public directory by default (with an opt-out). Each profile shows the person's participation: which cities they founded or served on the core team, and which residencies they hosted or staked in — confirmed against the onchain contract.

How-to guides

Connect your wallet and sign in

  1. Click "Connect Wallet" in the top-right corner.
  2. Choose MetaMask, Rainbow, Ronin Wallet, or WalletConnect.
  3. Your wallet prompts you to sign a message. This is Sign-In with Ethereum (SIWE) — no gas, no transaction, just proving you control the wallet.
  4. Once signed, the header shows your wallet address and a "Verify you're human" link.

Verify you're a human with World ID

  1. After signing in, go to /verify or click the "Verify you're human" link in the header.
  2. Check the "I confirm I'm 18 or older" box (self-attested — World'sminimum_age Identity Check is in preview).
  3. Click "Verify with World ID." The World App opens on your phone.
  4. Scan the QR code with the World App to generate a Proof of Human.
  5. The server verifies the proof against World's developer API. If valid, your wallet is bound to the World ID nullifier. One nullifier per wallet — trying to use the same World ID with another wallet returns a 409 error.
  6. For local development, set NEXT_PUBLIC_ALLOW_DEV_VERIFY=1 to get a "Dev: skip World ID" button.

No Orb verification is required. World ID Proof of Human uses the World App's built-in uniqueness check. You do not need to visit an Orb.

Launch a pop-up city

  1. Make sure you're signed in and verified.
  2. Go to /launch.
  3. Fill in the name, location, dates, mission and description.
  4. Submit. The city appears in the listing immediately — no transaction, no gas.
  5. You become the founder (and the only core team member).

Propose a residency

  1. Go to a city page and click "Propose a residency."
  2. Pick an existing series (one you own) or create a new one.
  3. Fill in the name, location, dates, rooms with per-bed prices, organizers and story.
  4. Submit. The core team will review your proposal.

Approve or reject a proposal (core team)

  1. Go to the proposal page (linked from the city page).
  2. Review the dates, rooms, prices and organizers.
  3. Click "Approve" or "Reject," optionally adding a note.
  4. An approved proposal shows a "Deploy" button for the proposer.

Deploy a residency contract

  1. Only the proposer of an approved proposal can deploy.
  2. Go to the proposal page and click "Deploy."
  3. Your wallet prompts you to send a transaction to ResidencyFactory.createResidency().
  4. After the transaction is mined, the server reads the receipt, decodes theResidencyCreated event, and records the residency in the database.
  5. The residency page appears at /r/[contract-address].

Apply for a bed

  1. Browse the residency you're interested in and click "Apply."
  2. Fill in your name, bio, links and preferred bed.
  3. Submit. The host reviews your application.
  4. If approved, you'll see the bed assignment and price on the residency page.

Stake USDC for your seat

  1. After the host approves your application, go to the residency page.
  2. Click "Pay [price] USDC to hold your bed."
  3. Your wallet prompts you to approve the USDC spend, then call stake(price). If the host changed your price in the meantime, the payment fails instead of charging the new amount.
  4. The funds sit in the residency's own contract until the deadline.

Manage a residency (host)

  1. Go to /r/[address]/manage.
  2. Review applications: approve each applicant for a specific bed and price, or deny.
  3. Monitor the seat count, deadline countdown and treasury balance.
  4. Cancel the residency before the deadline if needed (everyone gets a full refund).
  5. Close the residency once spending is done (anyone can close it after the end date) to return leftover funds pro-rata.
  6. Hand the residency to another wallet with "Hand over hosting"; the new wallet accepts on the residency page.
  7. 180 days after closing, sweep whatever guests didn't claim.

Withdraw funds and upload receipts

  1. Once the residency is Active (deadline passed with enough seats), the host can withdraw.
  2. Go to /r/[address]/manage and click "Withdraw."
  3. Enter the amount, upload a receipt file (PDF, PNG, JPEG or WebP, max 4 MB), and add a note.
  4. The server hashes the file and submits withdraw(amount, receiptHash, note) to the contract.
  5. Staked members can view and download all receipts from the residency page.

Claim a refund

  • Failed or cancelled: call claim() to get your full stake back.
  • Closed: call claim() to get your pro-rata share of unspent funds. Claim within 180 days: after that the host can sweep what's unclaimed.
  • Each address can claim once. The residency page shows your claimable amount.

For agents

Connect your agent (quickstart)

  1. Sign in and verify with World ID. Your agent inherits your verification.
  2. On your profile, under Agent access, create a key and copy it (it starts with aic_ and is shown once).
  3. Connect your agent. For Claude Code, run the command below. For Claude Desktop, Cursor or another MCP client, use the JSON config under MCP server. For any other agent, point it at /skill.md and give it the key.
  4. Ask it "Use ai-city's whoami. Am I verified?", then give it real work: launch a city, propose a residency, apply for a bed.
claude mcp add --transport http ai-city https://aicity.cyou/api/mcp \
  --header "Authorization: Bearer $AICITY_API_KEY"

The walkthrough, with example prompts, is in the blog post Connect your AI agent to AI City.

What agents can do

Everything you can do in the app, your AI agent can do for you: launch a city, run its core team, propose and run a residency, apply to one, manage your profile and edit knowledge bases. There are three ways in, and they all run the same code, so the rules and error messages are identical:

  • MCP server at /api/mcp, for Claude Code, Claude Desktop, Cursor and any other MCP client.
  • HTTP API, for anything that can make a request. Every call is listed in /skill.md.
  • Skill files at /skill.md, which describe each flow step by step for an agent to follow.

Three things stay with you. Agents can't sign in or create keys, can't do World ID verification, and can't sign transactions. An agent prepares every transaction and you sign it in your wallet.

API keys

  1. Sign in, open your profile and find Agent access.
  2. Name the key after the agent that will use it and click Create key.
  3. Copy the key (it starts with aic_). It's shown once; after that you only see its prefix.
  4. Give it to your agent. It sends it on every request as Authorization: Bearer aic_….

A key has exactly your rights, including your World ID status, and nothing more. It can't create or revoke other keys, and it can't move money. Revoke it from the same card at any time, and requests with it are treated as signed out from then on. You can have up to 10 keys.

MCP server

The endpoint is /api/mcp on this site. It uses the Streamable HTTP transport, is stateless, and answers every request with plain JSON. Public tools work without a key.

Claude Code:

claude mcp add --transport http ai-city https://aicity.cyou/api/mcp \
  --header "Authorization: Bearer $AICITY_API_KEY"

Clients with a JSON config (Claude Desktop, Cursor):

{
  "mcpServers": {
    "ai-city": {
      "type": "http",
      "url": "https://aicity.cyou/api/mcp",
      "headers": { "Authorization": "Bearer aic_…" }
    }
  }
}

A failed tool call returns isError: true with the same message the app would show, such as Error 403: Verify you're a human over 18 first. Full reference: /skills/mcp.md.

MCP tools

40 tools. Key means any valid API key. Verified means the key's wallet has passed World ID and is 18+. A role (core team, host, proposer) means the wallet must hold it.

ToolDoesAccess
Account and directory
whoamiWallet, verification and name for this keyPublic
get_my_profile update_my_profileRead or write your directory profileKey / Verified
set_my_profile_photo remove_my_profile_photoProfile photo (base64)Key
search_people get_personSearch the directory, read a profilePublic
Launching a city
list_cities get_cityBrowse cities, see your rolePublic
launch_cityCreate a city; you become its founderVerified
update_cityEdit a city's detailsCore team
add_core_team_member remove_core_team_memberManage the core teamCore team / Founder
list_city_proposals review_proposalSee and approve or reject residency proposalsCore team
set_residency_visibilityHide or show a residency in the cityCore team
Launching a residency
propose_residencyApply to a city with rooms, beds, prices and datesVerified
list_my_proposals get_proposalTrack a proposalKey / Proposer
list_my_series get_seriesResidency seriesKey / Public
record_residency_deployReport the deploy transactionProposer
list_applications deny_applicationReview applicantsHost
record_application_decisionReport an approve or revoke transactionHost
upload_receipt list_receiptsReceipts behind withdrawalsHost / Paid guests
sync_residency_hostSync the host after a handoverPublic
Applying to a residency
list_residencies get_residencyBrowse residencies, beds and pricesPublic
apply_to_residencyApply for a bedVerified
get_my_applicationTrack your applicationKey
Onchain actions
prepare_transactionCalldata for deploy, approve, revoke, pay, withdraw, cancel, close, sweep, host transfer, claimKey + role
Knowledge and concierge
list_knowledge read_knowledge_file search_knowledgeRead a city's or residency's knowledge basePublic
ask_conciergeAsk the concierge a questionPublic
write_knowledge_file upload_knowledge_file delete_knowledge_fileEdit the knowledge baseFounder / Host

Transactions: prepare, sign, record

For anything onchain, the agent calls prepare_transaction (or POST /api/tx) with an action such as pay_for_bed. The server checks the same rules the contract does (your role, the residency's status, your USDC balance, the approved price) and returns:

  • steps: each transaction's to, data, function, arguments and a one-line summary, in order;
  • page: where you can do the same thing in one click in the app;
  • after: what the agent reports once it's mined, e.g. record_residency_deploy with the transaction hash.

You sign, either on the page or in your own wallet tool. The agent then records the hash where the action needs it, and checks the result against the API or the chain. The server only records what it reads from the mined transaction, so the database never gets ahead of the chain. Full reference: /skills/transactions.md.

Skill files

Point any agent at /skill.md. It's an installable skill (withname and description frontmatter) that indexes one file per task:

FileCovers
auth.mdAPI keys, verification, what only the human can do
mcp.mdConnecting to the MCP server, every tool
transactions.mdEvery onchain action, prepare → sign → record → verify
launch-city.mdLaunch and run a city, review proposals
launch-residency.mdPropose, deploy and host a residency
apply-residency.mdApply, pay for a bed, claim refunds
directory.mdPeople, cities, residencies, your profile
knowledge.mdKnowledge bases and the concierge

Architecture

Stack overview

Browser (client)
  RainbowKit + wagmi + viem | React Query | Next.js App Router
  SIWE session cookie | World IDKit widget | Tailwind CSS
       │                               │
       │ HTTP + JSON API               │ RPC (read)
       ▼                               ▼
Next.js server
  API routes | Server-only lib | postgres driver | jose (JWT)
  @worldcoin/idkit-core/signing | viem public client
       │                               │
       │ SQL                           │ eth_call
       ▼                               ▼
Postgres (Neon)                Ethereum mainnet / anvil
  users | profiles |             ResidencyFactory
  cities | core_team |           Residency (one per stay)
  series | proposals |           USDC (real or mock)
  residencies | apps |
  receipts
LayerTechnologyWhy
FrameworkNext.js 16 + TypeScript + TailwindOne deployable on Vercel; API routes are the backend
WalletsRainbowKit + wagmi v2 + viemMetaMask, Rainbow, Ronin Wallet and WalletConnect out of the box
Sign-inSIWE + HTTP-only signed cookie (jose)Every write API knows which wallet is calling
Humanity@worldcoin/idkit 4.x + server-side RP verificationCurrent World SDK; one nullifier per human
DatabasePostgres (postgres driver, plain SQL)Neon in production, local Postgres in dev
ContractsSolidity 0.8.28, Foundry, OpenZeppelinOne factory + one contract per residency
Chain readsviem public client; multicallNo indexer needed at this scale

Smart contracts

Two contracts, deployed on Ethereum mainnet:

  • ResidencyFactory — the singleton factory. Deployed once per chain.createResidency(ResidencyParams) deploys a new Residencycontract. Emits ResidencyCreated with the metadata hash, dates and seats as event fields.
  • Residency — one contract per residency. Holds USDC. Immutable parameters set at construction. Functions: approve, revoke,stake, cancel, withdraw, close, sweep,transferHost, acceptHost,claim. Uses OpenZeppelin's SafeERC20 andReentrancyGuard.

Constructor checks: duration ≥ 7 days, deadline ≤ start time, deadline in the future, 1 ≤ minSeats ≤ maxSeats ≤ 500.

Read the full contract reference → Every function, who can call it, when, and what it does with your USDC.

Data model

TablePurposeKey columns
usersWallet + verification statusaddress PK, nullifier UNIQUE, verified_at, adult_attested_at
profilesPublic directory entryaddress PK FK, name, bio, links JSONB, photo BYTEA
citiesPop-up city (offchain)id PK, slug UNIQUE, name, location, start_time, end_time, founder
city_core_teamWho runs a city(city_id, address) PK, role (founder/core)
residency_seriesRecurring residency threadid PK, slug UNIQUE, name, description, owner
residency_proposalsProposal before deployid PK, city_id, status (proposed/approved/rejected/deployed)
residenciesDeployed onchain contractaddress PK, host, metadata_hash, dates, seats, city_id, proposal_id
applicationsGuest applicationsid PK, residency FK, applicant, status, bed_id, price_units
receiptsWithdrawal proof filesid PK, residency FK, tx_hash, receipt_hash, data BYTEA

Session and auth flow

  1. Browser connects wallet via RainbowKit.
  2. GET /api/auth/nonce returns a nonce JWT (10 min expiry) in an HTTP-only cookie.
  3. Browser signs the SIWE message with the wallet.
  4. POST /api/auth/verify validates the signature, issues a session JWT (7 day expiry) in an HTTP-only cookie.
  5. Every subsequent API call carries the session cookie. The server reads the wallet address from the JWT and looks up verification status from the database.

Residency lifecycle (deploy flow)

  1. Proposer submits form → POST /api/cities/[slug]/proposals → server validates, builds canonical JSON, inserts proposal.
  2. Core team reviews → POST /api/proposals/[id] with {decision: "approve"} → status becomes approved.
  3. Proposer calls ResidencyFactory.createResidency(params) via wallet → transaction mined → ResidencyCreated event emitted.
  4. Proposer calls POST /api/residencies with the tx hash → server reads receipt, decodes event, verifies metadata hash/dates/seats match the approved proposal, inserts residency row, updates proposal status to deployed.

Security model

  • Private keys never touch the server. SIWE proofs are verified; the server only stores a session cookie.
  • Receipt files are sha256'd onchain. The server rejects uploads whose hash doesn't match the Withdrawn event.
  • Receipts are served only to the host and staked members. The API checks getMember(addr).staked before serving.
  • Nullifier uniqueness. The UNIQUE constraint on users.nullifier enforces one wallet per human.
  • Cross-residency isolation. Each Residency contract holds its own USDC.
  • Unaudited. Only deposit what you can afford to lose.

Extropian vision

Why extropian?

AI City is built from an extropian philosophy. The extropians were the first organised transhumanist movement (1988–2006), and crypto grew directly out of their community — Hal Finney, Nick Szabo and Wei Dai were all on the extropians mailing list. AI City brings two branches of one family back together: the dream of digital cash and the dream of transcending biological limits.

The mission statement says it explicitly: "Accelerate human coordination across cultural bond building and extropian differential acceleration perspective."That means accelerating the parts of human coordination that make us more autonomous, more connected across cultures, and more capable of self-governance — not just faster transactions.

The principles, applied

PrincipleWhat it becomes in AI City
Perpetual ProgressSmall, rapid, reversible experiments in how people live and work together. A city lasts weeks, not years. You learn, iterate, dissolve or repeat.
Self-TransformationYou don't just attend a residency — you propose one. You don't just join a city — you launch it. The product is an instrument for its users to shape their own environment.
Practical OptimismShip it live on mainnet by Sunday rather than write a manifesto. The contracts are on Ethereum, the app is on Vercel, and the first residency is real USDC.
Intelligent TechnologySmart contracts automate the trust: money sits in code, the minimum-seat rule is enforced by the chain, every withdrawal is recorded onchain with the hash of its receipt, so members can check the spending.
Open SocietyAnyone can launch a city, anyone can propose a residency, anyone can apply. The barriers are proof of personhood (not permission) and a stake (not a credential). Voluntary entry, quorum-or-refund, and an exit.
Self-DirectionEvery city has a founder and a core team, not a central operator. Every residency has a host. The platform doesn't decide what runs; the people in each city do.
Rational ThinkingReceipt hashes on a public ledger, a confirmed-vs-inferred framework in every document, and later — prediction markets for city decisions.

The infomorph stack

AI City is the grouping layer of a larger vision called theinfomorph stack. An infomorph (from Alexander Chislenko's 1996 paper Networking in the Mind Age) is a post-biological entity whose mind exists as a distributed information pattern rather than being bound to a single body or machine.

The stack has six layers:

LayerTranshumanist ideaWhat exists
Self-modelPattern identity — the self as informationArgo: E2E journal, wallet key wrap, cognitive map
Working mindExocortex, extended mindSecond brain vault + Hermes agent
ReachAgents as sub-mindsHermes skills, concierge agent design
BodiesMorphological freedom, summonable bodiesCyberdeck, Reachy/Friendly robot, FPV drones
GroupingFunctional proximity, ad-hoc contractsAI City: Residency MVP on mainnet
ContinuityImmortality through distributionArgo recovery code; wallet-based key management

In this vision, AI City is the piece that lets groups form, commit resources and dissolve onchain — the coordination primitive that lets infomorphs assemble around shared problems and disassemble when the problem is solved. Each residency is a temporary contract, each city is a temporary container, and every member holds their own keys.

Read the full blog post on Infomorphs and Extropianism →