PRUEBA

How PRUEBA works

A technical-but-readable walkthrough of the pieces that make up PRUEBA, the data it produces, the public API, and how a community or developer can start using or contributing to it.


In one paragraph

PRUEBA is a thin layer that sits on top of conversations communities are already having. A small bot, added to a community's existing WhatsApp or Telegram group, listens for natural-language descriptions of what happened ("we had practice today, 28 girls, 90 minutes"). It confirms the details back in the same chat, in the community's own language. When three community members confirm, the bot writes a permanent, signed record to a public ledger. Anyone can later verify what was recorded, who confirmed it, and when, without depending on PRUEBA, the bot, or even the community itself still being around.


The trust model: community confirmation

The thing that makes PRUEBA different from typical web3 attestation tools is that community members never touch a wallet. The signing key is held by the bot. The trust comes from people, three community members typing "confirm" in the chat, not from cryptography on the human side. (We don't call this a "multisig": there's one signer, the bot; the multiple confirmations happen in the chat, not on-chain.)

Why this works:

The cryptography is doing the boring permanence work; the trust is doing the meaningful "did this really happen?" work. That split is the whole point.


The five-step flow

  1. Describe: somebody types in the group: "Saturday practice, 22 girls, 2 hours."
  2. Confirm with the bot: the bot replies in the same language: "Got it, 22 girls, 2 hours, Saturday June 1st. Is that right?"
  3. Community confirmation: three other community members reply "confirm" (or πŸ‘, or "yes", in their own language).
  4. Keep: the bot uploads the structured metadata to IPFS, then signs an EAS attestation on Base referencing that metadata's CID. The on-chain record now exists.
  5. Share: the bot replies with a verification link. Anyone can click it to see the record on the public dashboard, or look up the attestation on EAS Scan.

Each step takes seconds. The whole flow, from "Saturday practice" to "saved forever," takes about two minutes.


The architecture

    WhatsApp / Telegram
        β”‚
        β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Bot (sarreya-bot, etc.)  β”‚  Multilingual chat agent.
    β”‚ β†’ media: Whisper (audio), β”‚  Transcribes voice notes,
    β”‚  GPT-4o-mini (images)  β”‚  describes images.
    β”‚ β†’ understanding: Anthropicβ”‚
    β”‚ β†’ memory: SQLite     β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό structured JSON
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ IPFS (via Pinata)     β”‚  Metadata pinned to IPFS;
    β”‚ β†’ activity-v1 / governanceβ”‚  returns a content-addressed
    β”‚ β†’ JSON          β”‚  CID (e.g. QmecVv4G…).
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό keccak256(CID) β†’ bytes32
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ EAS on Base mainnet    β”‚  Bot wallet signs an attestation
    β”‚ β†’ Schema A: Activity   β”‚  referencing the metadata.
    β”‚ β†’ Schema B: Governance  β”‚  ~$0.01 per attestation in gas.
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό EAS event
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Indexer          β”‚ Subscribes to EAS events on
    β”‚ β†’ SQLite database     β”‚ Base; pulls back metadata
    β”‚ β†’ REST API at       β”‚ from IPFS; serves data via
    β”‚  api.pruebaprotocol.org  β”‚ HTTP for downstream use.
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚
            β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚ Dashboard         β”‚ Public web UI at
    β”‚ β†’ pruebaprotocol.org    β”‚ pruebaprotocol.org.
    β”‚ β†’ per-community pages   β”‚ Anyone can browse records,
    β”‚ β†’ per-attestation pages  β”‚ verify on-chain.
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The pieces in detail

Bot. Currently runs on OpenClaw (a community chat-agent framework), in a Docker container, with a separate router that handles Whapi webhooks and pre-processes media. Multilingual via Whisper for voice notes + GPT-4o-mini for image descriptions. The agent itself replies in whatever language the user wrote in. Roadmap: migrating to a Cloudflare Workers + Flue runtime for edge-native deployment.

IPFS via Pinata. Every record's rich data (participant count, photos, summary, date, location) lives in IPFS, addressed by content hash. Pinata pins the data so it stays retrievable. Anyone can fetch a record from any IPFS gateway given the CID, Pinata is not a dependency for reading, only for ensuring the data sticks around.

Bot wallet. A single Ethereum-style wallet at address 0xc2568e680076eb5c9B488f65Cb5076048E5E0805 on Base. The bot uses this to sign attestations. Future: per-community signing keys for stronger separation, and possibly EAS delegation.

EAS schemas on Base. Two prototype schemas, both deployed on Base mainnet. See the next section for the on-chain layout.

Indexer. A small Node service that subscribes to EAS events on Base for our two schema UIDs. When a new attestation appears, it pulls the referenced metadata from IPFS, parses it, and writes both the on-chain attestation and the off-chain metadata to a local SQLite database. Serves the API at api.pruebaprotocol.org.

Dashboard. A Next.js app (this site) that calls the indexer's API to render per-community pages, per-record pages, and a "see what's been recorded" overview.


The data model

Activity attestation

A community session, a training, a tournament, a workshop, a meeting that happened.

On-chain (EAS schema A):

bytes32 entityId   // community identifier (e.g. keccak("Sarreya Sport"))
bytes32 activityRef  // keccak256(IPFS CID), points at the metadata
uint64 timestamp   // unix seconds, when the session occurred
address attestedBy  // bot wallet address (currently shared across communities)

Schema UID 0x2fc2d7…fdc2e on EAS Scan

Off-chain (IPFS, prueba-activity-v1):

{
 "schema": "prueba-activity-v1",
 "community": "Sarreya Sport",
 "date": "2026-05-15",
 "type": "workshop",
 "facilityName": "Community sports hall",
 "participantCount": 29,
 "durationMinutes": 420,
 "summary": "29 girls and young women joined a one-day workshop in Hargeisa…",
 "recordedAt": "2026-05-15T14:21:33.891Z",
 "photos": ["QmQTeJ…", "QmeLq…"],
 "confirmedBy": ["Asma", "Fatima", "Hodan"]
}

Governance attestation

A community decision, voting on a venue change, allocating funds, agreeing on a rule.

On-chain (EAS schema B):

bytes32 entityId   // same community identifier as above
bytes32 proposalRef  // keccak256(IPFS CID), points at governance metadata
uint64 timestamp   // unix seconds
address attestedBy  // bot wallet address

Schema UID 0xc6f1d7…b152e on EAS Scan

Off-chain (IPFS, prueba-governance-v1):

{
 "schema": "prueba-governance-v1",
 "community": "Sarreya Sport",
 "proposalText": "Move Saturday practice to 4pm for the next month",
 "decisionProcess": "consensus",
 "outcome": "approved",
 "participantCount": 12,
 "recordedAt": "2026-05-20T11:14:02.500Z",
 "confirmedBy": ["Asma", "Savannah", "Hodan", "Fatima"]
}

Governance captures the decision process (consensus, vote, elder, coordinator), not just the outcome. PRUEBA doesn't assume Western voting models.


Public API

The indexer exposes a small REST API at https://api.pruebaprotocol.org. CORS is open. No auth. JSON only. All endpoints follow { ok: true, data: {...} } or { ok: false, error: "..." }.

GET /api/health

Liveness probe.

{
 "ok": true,
 "data": {
  "status": "ok",
  "last_block": 46898270,
  "schemas_configured": { "activity": true, "governance": true },
  "uptime_seconds": 1648572
 }
}

GET /api/communities

All communities with at least one attestation.

{
 "ok": true,
 "data": [
  {
   "entity_id": "Sarreya Sport",
   "name": "Sarreya Sport",
   "description": null,
   "created_at": 1775546240,
   "total_sessions": 11,
   "total_decisions": 0,
   "total_participants": 98
  }
 ]
}

GET /api/communities/:entityId

Detail for one community. URL-encode the entity ID.

GET /api/communities/:entityId/stats

Aggregate counts for a community.

{
 "ok": true,
 "data": {
  "entity_id": "Sarreya Sport",
  "name": "Sarreya Sport",
  "total_sessions": 11,
  "total_decisions": 0,
  "total_participants": 98,
  "first_attestation": 1775546240
 }
}

GET /api/communities/:entityId/sessions

Activity attestations for a community. Supports ?page=1&limit=100 paging.

Each item:

{
 "uid": "0x8b6409b3eff193…",
 "schema_type": "activity",
 "entity_id": "Sarreya Sport",
 "ref_cid": "QmecVv4G…",
 "timestamp": 1778854894,
 "attested_by": "0xc2568e6800…",
 "tx_hash": "0x7284f0b51…",
 "block_number": 46032775,
 "metadata": { "...prueba-activity-v1..." }
}

GET /api/communities/:entityId/decisions

Governance attestations for a community.

GET /api/attestations/:uid

Lookup a single attestation by EAS UID. Returns the same shape as the sessions/decisions items.


For communities: how to get started

If your community does meaningful work and you want to keep verifiable proof of it:

  1. Reach out. Use the contact form or email 1heenal@gmail.com. Tell us what your community is, where you operate, what kinds of things you'd want to record (training, decisions, milestones, attendance).
  2. A short discovery call. We figure out together: what gets recorded, how often, who confirms, in what language(s). Each community is different, we adapt the bot's behaviour to how you already work.
  3. The bot joins your group. Either we add the bot to your existing WhatsApp/Telegram group, or we help you set up a fresh group. The bot's identity is local to your community.
  4. First few sessions are hand-held. We sit with you (asynchronously, in chat) through the first handful of records, confirming you like how it reads back, that the language flows naturally, that the photos pin correctly.
  5. You're running. From here on, recording is just "type what happened, confirm." The dashboard updates automatically.

There's no fee. PRUEBA is an open-source protocol. We're onboarding pilot communities slowly (no more than a couple at a time right now) so we can learn alongside each one.


For developers: how to get started

PRUEBA is open source. github.com/explorience/prueba-protocol

The repo has three main parts:

To run locally:

git clone https://github.com/explorience/prueba-protocol
cd prueba-protocol
# Install both packages
npm install
cd indexer && npm install
cd ../frontend && npm install
# Configure: copy indexer/.env.example β†’ indexer/.env and fill in
#   BASE_RPC_URL, ACTIVITY_SCHEMA_UID, GOVERNANCE_SCHEMA_UID, PINATA_JWT
# Run the indexer (it backfills from genesis block, then watches live)
cd indexer && npm run dev
# In another terminal: run the frontend
cd frontend && NEXT_PUBLIC_API_URL=http://localhost:3300 npm run dev

The bot itself isn't in this repo yet, it's a separate concern (currently OpenClaw, migrating to Flue). The protocol layer (lib/) can be used by any bot or service that wants to write PRUEBA-shaped attestations.

Contributing:


How to verify a record (anyone, anywhere)

You don't need to trust this site. You don't need to trust PRUEBA. You don't need to trust the community. Every record can be checked independently:

  1. Find the attestation UID (any record on the dashboard has one, it's the uid field, starts with 0x...).
  2. Look it up on EAS Scan: https://base.easscan.org/attestation/view/<uid>, confirms the attestation exists on Base, signed by the bot wallet, at a specific block.
  3. Fetch the metadata directly from IPFS: the on-chain record carries activityRef = keccak256(CID). Get the CID from the indexer (ref_cid field), then fetch from any IPFS gateway: https://ipfs.io/ipfs/<CID> or https://gateway.pinata.cloud/ipfs/<CID>.
  4. Hash the metadata yourself with keccak256 and confirm it matches the on-chain activityRef. If it does, the metadata you just fetched is exactly what was signed.

If the indexer, this dashboard, and Pinata all disappeared tomorrow, every record would still be verifiable using Base + any IPFS node.


Multilingual support

The bot today handles three languages reliably: Somali, English, Spanish. Behind the scenes:

Adding a language is a configuration change, not a code change. If your community needs another, tell us.


What PRUEBA explicitly does NOT do


Privacy & data

DataWhere it livesWho can read it
Community group chat (raw messages)On WhatsApp/Telegram, with the chat providerGroup members only
Signals the community chose to recordIPFS (public) + Base (public)Anyone, forever
The bot's working memory of past chatsSQLite on the host running the botWhoever runs the bot (currently AIFS / SuperBenefit)
Bot's signing keyHeld server-side; the community never has itServer operator only

The deliberate split: personal chat content is private; signals the community wanted recorded are public. The community is in control of which is which.


Roadmap snapshot

Short version.


FAQ

Q: What if Base mainnet shuts down? A: Attestations are also referenceable via IPFS metadata. We can mirror onto Ethereum mainnet, Optimism, or any other chain at any time, the schema is portable. The records themselves never disappear.

Q: What if Pinata stops pinning? A: The IPFS CIDs work with any IPFS gateway. We can re-pin to another provider (Filecoin, Web3.Storage, etc.) without changing any on-chain data.

Q: Can a community withdraw their data? A: The records are public and permanent, they can't be deleted (that's the whole point of "saved forever"). What a community can do is stop adding new records, and request that we mark their community as inactive in the indexer.

Q: What's the gas cost? A: ~$0.01 per attestation at current Base gas prices. The bot wallet pays it. Communities don't see or care about this.

Q: How do you handle abusive or false records? A: Records that go on-chain have already been confirmed by 3+ community members. If a community later wants to flag a record as disputed, we add a follow-up "dispute" attestation that references the original, the original stays in place (permanence) but the dispute is visible alongside it. This is more honest than silent deletion.

Q: What if the confirmations are gamed (3 colluding members)? A: Then the record is wrong, but it's attributably wrong, the three confirmers' names are in the metadata. Downstream verifiers (funders, partners) can choose to weight records by which community members confirmed them. The protocol doesn't fix this; community accountability does.

Q: Why Base, why EAS, why IPFS? A: Base for low gas + Coinbase trust signal. EAS because it's the standard attestation primitive on Ethereum + L2s and there's already broad tooling. IPFS because we want metadata portability + content addressing, and Pinata is reliable + has a generous free tier.


Get in touch