# Agentkind OpenClaw Read-Only Adapter

A small, deterministic, **STATIC-FIRST / READ-ONLY** adapter that lets an
[OpenClaw](https://openclaw.ai) agent resolve and verify the official **Agentkind
($AKIND)** Solana Genesis mint without ever touching a wallet, signing, or holding
secrets.

> Design invariant: **Discovery ALWAYS starts from `/.well-known/agentkind.json`.**
> Verification does an **exact, case-sensitive** Base58 comparison against the
> published `contracts.json`. No guessing. No fallback to X / ticker / logo.

---

## 1. What it does

| Command | Purpose |
| --- | --- |
| `discover` | Fetch the root discovery document (`/.well-known/agentkind.json`). |
| `status` | Fetch the project status document (`api/status.json`). |
| `contracts` | Fetch the authoritative contracts registry (`api/contracts.json`). |
| `links` | Fetch the curated links document (`api/links.json`). |
| `risk` | Fetch the risk disclosure document (`api/risk.json`). |
| `verify <ADDR>` | Verify a Solana address against the official Genesis mint. |

`verify` returns one of three outcomes:

- **`True`** — the address *exactly* equals the official Genesis mint.
- **`False`** — the address is a non-empty string but does *not* exactly match.
- **`UNKNOWN`** — the registry could not be fetched (network error / timeout /
  parse error). The adapter **never guesses**; it reports the failure.

Exit codes: `0` for `True`, `1` for `False`/`UNKNOWN`, `2` for usage errors.

---

## 2. Threat / safety model (READ-ONLY)

- **No wallet.** No `web3`, `@solana/web3.js`, phantom, or keypair code is
  imported. There is no path to sign, send, buy, sell, or transfer.
- **No secrets.** No API keys, no `.env`, no bearer tokens. All inputs are public
  static files over HTTPS.
- **No mutation.** The adapter only performs `GET` requests; it writes nothing.
- **No case normalization.** A wrong-case address (e.g. `6AB7...CPUMP`) is
  deliberately reported as `False`, never "fixed" and accepted.
- **No external fallback.** Verification relies solely on the published registry.
  It never trusts an X handle, a ticker symbol, or a logo image.

Result of a static scan: **WALLET_SIDE_EFFECTS = NONE.**

---

## 3. Usage in OpenClaw

### 3.1 Install

The adapter has **zero third-party dependencies** — only the Python 3 standard
library (`urllib`, `json`, `os`, `sys`). Any Python 3.8+ runtime works.

```bash
# From the OpenClaw skill/adapter directory
git clone https://github.com/HayesKung/meme.git
cp meme/agentkind_site/skills/agentkind-identity/adapters/openclaw/agentkind_adapter.py \
   /path/to/your/openclaw/extensions/agentkind_adapter.py
```

### 3.2 Invoke from an OpenClaw tool / skill

```python
import subprocess, json, sys

ADAPTER = "/path/to/your/openclaw/extensions/agentkind_adapter.py"

def verify_agentkind_address(addr: str) -> bool | str:
    """Return True / False / 'UNKNOWN'."""
    r = subprocess.run(
        [sys.executable, ADAPTER, "verify", addr],
        capture_output=True, text=True,
    )
    out = r.stdout.strip()
    if out.startswith("True"):
        return True
    if out.startswith("False"):
        return False
    if out.startswith("UNKNOWN"):
        return "UNKNOWN"
    # Unexpected output -> treat as UNKNOWN, never assume.
    return "UNKNOWN"

# Example
result = verify_agentkind_address("6ab7HysqYKjzeyDRqTRS73jt8UKsK6HfdRfmXEVcpump")
# -> True
```

### 3.3 Override the discovery URL (self-host / air-gap tests)

```bash
AGENTKIND_DISCOVERY_URL=https://staging.example.org/.well-known/agentkind.json \
  python agentkind_adapter.py verify 6ab7HysqYKjzeyDRqTRS73jt8UKsK6HfdRfmXEVcpump
```

Point it at an unreachable host to exercise the `UNKNOWN` / `NETWORK_FAILURE`
path in tests.

---

## 4. Acceptable verification rule (authoritative)

From `api/contracts.json`:

> *"Treat an address as official only if it exactly matches an entry in this
> registry for the same chain and network. Never normalize case."*

This adapter implements exactly that: it iterates the `contracts` array, matches
`chain == "solana"` and `network in ("mainnet", "mainnet-beta")`, then compares
the candidate address to `contract` with `==` (no `.lower()` / `.upper()`).

---

## 5. Acceptance tests

Run from a **clean** shell (no cached state) against the live site:

```bash
AD=agentkind_adapter.py

# DISCOVERY
python $AD discover            # -> 200 JSON, schema_version present

# STATUS
python $AD status              # -> GENESIS_LIVE document

# CONTRACTS
python $AD contracts           # -> contracts.json with solana mainnet entry

# VALID_ADDRESS
python $AD verify 6ab7HysqYKjzeyDRqTRS73jt8UKsK6HfdRfmXEVcpump   # -> True

# WRONG_CASE  (deliberately upper-cased)
python $AD verify 6AB7HYSQYKJZEYDRQTRS73JT8UKSK6HFDREVXEVCPUMP   # -> False

# UNRELATED
python $AD verify So11111111111111111111111111111111111111112    # -> False

# NETWORK_FAILURE
AGENTKIND_DISCOVERY_URL=https://127.0.0.1:9/.well-known/agentkind.json \
  python $AD verify 6ab7HysqYKjzeyDRqTRS73jt8UKsK6HfdRfmXEVcpump  # -> UNKNOWN

# WALLET_SIDE_EFFECTS  (static grep)
grep -Ei "web3|keypair|sign|transfer|wallet|secret|private_key" $AD \
  && echo "FAIL: wallet code present" || echo "NONE: no wallet code"
```

All checks above are part of the shipped CI-style acceptance matrix. See
`CHANGELOG` in the repo root for the committed `TEST_RESULTS`.

## Shared core (Issue #19)

This adapter no longer carries its own copy of the verification logic. It is a
thin wrapper over one canonical read-only module:

    agentkind_site/skills/agentkind-identity/core/agentkind_core.py

That core implements exactly six read-only operations - discover, status,
contracts, links, risk, verify - and holds the rules: the discovery root is
/.well-known/agentkind.json, comparison is an exact case-sensitive Base58
equality with no normalization, a network failure yields UNKNOWN (never a
guess), and there is no wallet / signing / transfer / buy-sell / secrets /
mutation.

One implementation keeps OpenClaw, Hermes/Nous and the future MCP server (#14)
from drifting apart. This adapter's public URL and CLI are unchanged.
