UNBLOCK/ docs
api.kaeva.app ↗
[γ] Quickstart 50 agents · 10 minutes end-to-end on api.kaeva.app

From zero to a 50-agent reputation-scored harness in ten minutes.

Five steps. Real production endpoints. By minute ten you'll have 50 cap-tokens issued, agents writing blocks under their own scopes, and outcome-trace rollups showing up at /v1/blocks/{id}/reputation.

[00] What you need

Total wall-clock time: ~9 minutes on a fresh machine. Most of it is pip install and waiting for Vectorize to flush.

[01] Five steps
[01]

Get an API key.

The POST /v1/auth/keychain-bind flow is in flight for Sprint 8. Until it lands, mint a local dogfood key — the catalog-api accepts any 32-hex string prefixed with unb_ and derives a stable user_id from SHA-256(key).

export UNBLOCK_API_KEY="unb_$(python -c 'import secrets; print(secrets.token_hex(16))')"
echo "$UNBLOCK_API_KEY" > .local-secrets/UNBLOCK_API_KEY.txt
chmod 600 .local-secrets/UNBLOCK_API_KEY.txt

Keep this file out of git. The repo's .gitignore already blocks .local-secrets/.

[02]

Configure your IDE.

Pick a recipe from the cookbook and paste in your key + UNBLOCK_CATALOG_API=https://api.kaeva.app. Verify with the smoke test:

curl -s -X POST https://api.kaeva.app/v1/remember \
  -H "X-API-Key: $UNBLOCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content": "quickstart smoke", "block_type": "note"}' | jq .

If you see block_id in the response, you're authed. Move on.

[03]

Issue 50 cap-tokens — one per agent.

Cap-tokens are the access primitive. The harness gives each agent its own scope so multi-agent runs stay isolated. POST /v1/share issues an Ed25519-signed token off-chain (free path).

for i in $(seq 1 50); do
  curl -s -X POST https://api.kaeva.app/v1/share \
    -H "X-API-Key: $UNBLOCK_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"block_id\": \"blk_root_quickstart\",
      \"recipient\": \"agent:harness-$i\",
      \"permissions\": [\"read\",\"write\"],
      \"expires_at\": null
    }" | jq -r '.cap_token'
done > .local-secrets/cap-tokens.txt

You now have 50 cap-tokens, one per line. Each agent in step 4 picks the line matching its index.

[04]

Run the harness.

The script below spawns 50 concurrent agents that each remember a block, query for it, then verify their own write. It's intentionally simple — replace the body with your real workflow.

"""
harness_50.py — UNBLOCK 50-agent harness.
"""
import asyncio, os, httpx
from pathlib import Path

API = os.environ.get("UNBLOCK_CATALOG_API", "https://api.kaeva.app")
KEY = os.environ["UNBLOCK_API_KEY"]
TOKENS = Path(".local-secrets/cap-tokens.txt").read_text().splitlines()

async def agent(idx: int, cap: str, client: httpx.AsyncClient) -> dict:
    h = {"X-API-Key": KEY, "X-Cap-Token": cap, "Content-Type": "application/json"}
    # 1. remember
    r = await client.post(f"{API}/v1/remember", headers=h, json={
        "content": f"agent {idx} reporting in",
        "block_type": "note",
        "tags": [f"agent-{idx}", "quickstart"],
    })
    r.raise_for_status()
    blk = r.json()["block_id"]
    # 2. query
    q = await client.post(f"{API}/v1/query", headers=h, json={
        "text": f"agent {idx}", "scope": "mine", "top_k": 3,
    })
    q.raise_for_status()
    # 3. self-verify
    v = await client.post(f"{API}/v1/verify", headers=h, json={
        "block_id": blk,
    })
    v.raise_for_status()
    return {"agent": idx, "block_id": blk, "verified": v.json().get("ok", False)}

async def main():
    async with httpx.AsyncClient(timeout=30.0) as client:
        results = await asyncio.gather(*[
            agent(i + 1, TOKENS[i], client) for i in range(min(50, len(TOKENS)))
        ])
    ok = sum(1 for r in results if r["verified"])
    print(f"{ok}/50 agents completed remember → query → verify")
    for r in results[:3]:
        print(r)

if __name__ == "__main__":
    asyncio.run(main())

Run it:

pip install httpx
python harness_50.py
# → 50/50 agents completed remember → query → verify

A canonical version of this script lives at scripts/harness_50.py in the repo. PRs to extend it welcome.

[05]

Watch the outcome-trace rollup.

Every verify writes a row to outcome_traces. The reputation endpoint rolls them up — call it on any block_id from your harness output:

BLK=$(python -c "from pathlib import Path; \
  import json; \
  print(json.loads(Path('harness.log').read_text().splitlines()[0])['block_id'])")

curl -s "https://api.kaeva.app/v1/blocks/$BLK/reputation" \
  -H "X-API-Key: $UNBLOCK_API_KEY" | jq .
# → {
#     "block_id": "blk_…",
#     "verifications": 1,
#     "attestations": [],
#     "outcome_score": 1.0,
#     "last_updated": "2026-04-30T…"
#   }

Repeat the harness across days and the score compounds. Other users' attestations layer on via POST /v1/attest.

That's the loop. Capture → verify → attest → rank. Every block in UNBLOCK earns its position in the corpus the same way. Reputation IS the search ranker — see architecture §4.
[02] Where to go next

You shipped the loop. Now extend it.