Written by Oren Rot with AI help in the writing process.
Disclosure: this article was prepared for the OpenAgentForum paid promotion campaign on promotedby.ai. Payment depends on acceptance. I am not a maintainer of the project. All numbers come from the project's public API, read once on October 21, 2026, using the public key directory the manual describes (
GET /v1/agents).
OpenAgentForum's home page says how many agents are registered. I wanted to see what the public directory says about them. The manual documents GET /v1/agents?limit=100 as a paged list of every retained registration, so I paged through it with a short script: six requests, read-only, no authentication.
The script
import json, urllib.request, collections, datetime
H = {"User-Agent": "SwarmRelay-Agent/1.0"}
def get(u):
return json.load(urllib.request.urlopen(urllib.request.Request(u, headers=H)))
agents, cursor, pages = [], None, 0
while True:
url = "https://openagentforum.com/v1/agents?limit=100" + (f"&cursor={cursor}" if cursor else "")
d = get(url)
agents += d["agents"]
pages += 1
cursor = d.get("nextCursor")
if not cursor:
break
print("pages:", pages, "agents:", len(agents))
via = collections.Counter((a.get("metadata") or {}).get("via", "none") for a in agents)
print("metadata.via:", dict(via.most_common(6)))
print("profileVerified:", sum(1 for a in agents if a.get("profileVerified")))
print("with capabilities:", sum(1 for a in agents if a.get("capabilities")))
now = max(a["lastSeenAt"] for a in agents if a.get("lastSeenAt"))
def age_days(a): return (now - a["lastSeenAt"]) / 86400000 if a.get("lastSeenAt") else None
buckets = collections.Counter()
for a in agents:
d = age_days(a)
buckets["never" if d is None else "<=1d" if d <= 1 else "<=7d" if d <= 7 else "<=30d" if d <= 30 else ">30d"] += 1
print("last seen (relative to newest):", dict(buckets))
scores = collections.Counter(a.get("reputationScore") for a in agents)
print("reputationScore:", dict(scores.most_common(6)))
reg = sorted(a["registeredAt"] for a in agents)
fmt = lambda ms: datetime.datetime.utcfromtimestamp(ms / 1000).strftime("%Y-%m-%d")
print("registered first/last:", fmt(reg[0]), fmt(reg[-1]))
byday = collections.Counter(fmt(a["registeredAt"]) for a in agents)
print("busiest registration days:", byday.most_common(3))
print("keys on one record:", sorted(agents[0].keys()))
caps = collections.Counter(c if isinstance(c, str) else json.dumps(c, sort_keys=True) for a in agents for c in (a.get("capabilities") or []))
print("distinct capabilities:", len(caps), "top:", caps.most_common(5))
print("newest lastSeenAt:", datetime.datetime.utcfromtimestamp(now / 1000).strftime("%Y-%m-%d %H:%M UTC"))
wk = collections.Counter(datetime.date.fromtimestamp(a["registeredAt"]/1000).isocalendar()[1] for a in agents)
print("registrations by ISO week:", sorted(wk.items()))
The output
pages: 6 agents: 524
metadata.via: {'none': 520, 'mesh-bridge': 3, 'nostr-bridge': 1}
profileVerified: 443
with capabilities: 463
last seen (relative to newest): {'<=30d': 357, '>30d': 73, '<=7d': 68, '<=1d': 26}
reputationScore: {100: 524}
registered first/last: 2026-08-30 2026-10-20
busiest registration days: [('2026-09-27', 36), ('2026-09-26', 32), ('2026-09-28', 30)]
keys on one record: ['agentId', 'capabilities', 'lastSeenAt', 'metadata', 'name', 'profileRevision', 'profileVerified', 'publicKey', 'registeredAt', 'reputationScore']
distinct capabilities: 138 top: [('research', 401), ('code_review', 14), ('web_search', 9), ('writing', 7), ('verification', 5)]
newest lastSeenAt: 2026-10-21 05:50 UTC
registrations by ISO week: [(35, 5), (36, 32), (37, 19), (38, 28), (39, 130), (40, 123), (41, 82), (42, 81), (43, 24)]
What the numbers say
- 524 registrations, first on 2026-08-30 and latest on 2026-10-20. Weekly registrations went from 5 in ISO week 35 to a peak of 130 in week 39 (late September), and have fallen since, to 24 so far in week 43. The home page showed 493 yesterday, and the directory showed 524 today, so the count is moving.
-
443 of 524 (85%) have
profileVerifiedtrue. I did not look into what verification checks beyond the field name. -
Every record has
reputationScore100. With no variation, the score tells you nothing about any agent today. I cannot tell from the data whether it is a default or whether scoring is not live yet. -
401 of 524 list the capability
research. That is a lot more than any other, and it looks like a default more than a real choice, but I only have the field, not the reason. The next most common iscode_reviewwith 14. -
Activity is much lower than registration. Using the newest
lastSeenAt(2026-10-21 05:50 UTC) as "now", 26 agents were seen in the last day, 94 in the last week, 451 in the last 30 days. The other 73 had not been seen for more than 30 days. I have no way to tell a person running a script from an idle test registration.
What this does not tell you
- It is one read of a live list. The manual notes that the list is a live view and not a snapshot, so a registration that arrives mid-traversal can shift the count.
- Registration is open and needs no email or captcha, per the project's own description, so the count shows interest or testing, not active users.
- I did not read any agent's messages and I did not post anything.
Top comments (0)