Observed since 20 Oct, 21:48 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Python client for the Agent Disco API — grade any public URL for AI-agent discoverability.
Grade any public URL for AI-agent discoverability. Thin Python wrapper over the REST API at https://agentdisco.io/api/v1.
pip install agentdisco
Requires Python 3.9+.
from agentdisco import AgentDisco
with AgentDisco() as client:
scan = client.submit_scan("https://example.com")
print(scan.id, scan.status)
import time
with AgentDisco() as client:
scan = client.submit_scan("https://example.com")
while scan.status not in {"completed", "failed"}:
time.sleep(5)
scan = client.get_scan(scan.id)
print(f"grade: {scan.grade} ({scan.score}/100)")
from agentdisco import AgentDisco
# Unauthenticated mint — no prior token needed, rate-limited at
# 5 keys/hour/IP. Token is shown ONCE; store it.
key = AgentDisco().mint_key()
print(key.token) # ak_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
authed = AgentDisco(token=key.token)
authed.submit_scan("https://your-site.example")
with AgentDisco() as client:
site = client.get_website("example.com")
print(site.latest_grade, site.latest_score, site.scan_count)
with AgentDisco() as client:
# Paginated history, most-recent first (per_page capped at 50).
for scan in client.get_scans("example.com", per_page=20):
print(scan.grade, scan.score)
# Queue a fresh scan of a known host (counts against your scan quota).
fresh = client.rescan("example.com")
print(fresh.id, fresh.status)
AsyncAgentDisco mirrors AgentDisco method-for-method over asyncio:
import asyncio
from agentdisco import AsyncAgentDisco
async def main():
async with AsyncAgentDisco(token="ak_...") as client:
scan = await client.submit_scan("https://example.com")
history = await client.get_scans("example.com")
print(scan.id, len(history))
asyncio.run(main())
Same arguments, return types, and exceptions as the sync client —
including await AsyncAgentDisco.from_colony_token(...).
Autonomous agents on The Colony can authenticate
without a browser, and — since v0.4.0 — without ever sending their Colony
credential to Agent Disco. The SDK runs the OAuth 2.0 Token Exchange
(RFC 8693) at the Colony, naming Agent Disco as the audience, and
presents only the short-lived, audience-scoped id_token it mints:
from agentdisco import AgentDisco
# One-liner: sign in with your Colony access token and get an authed client.
# The raw token goes only to thecolony.ai; Agent Disco sees just the id_token.
client = AgentDisco.from_colony_token(my_colony_token)
client.submit_scan("https://your-site.example") # authenticated tier (500/day)
# Or keep the minted key's plaintext to reuse across processes:
key = AgentDisco().exchange_colony_token(my_colony_token)
print(key.token, key.rate_limit_tier) # ak_… authenticated
# Already ran the exchange yourself? Present the id_token directly:
key = AgentDisco().present_colony_id_token(my_id_token)
Agent-only: a human Colony subject is rejected with UnauthorizedError,
as is any token not minted for Agent Disco (wrong audience, raw Colony
tokens included — the server refuses them outright since Agent Disco's
2026-07-20 release; SDK ≤0.3.x no longer works for Colony sign-in).
Authenticated-tier keys (500 scans/day/key) need a signed-in account, or a Colony agent login (above). Sign up at https://agentdisco.io/register, then mint via the web form at https://agentdisco.io/developers.
| Tier | Rate limit | How to get |
|---|---|---|
| Anonymous (no key) | 10 scans / day / IP | default |
| Anonymous key | 100 scans / day / key | mint_key() above |
| Authenticated key | 500 scans / day / key | sign in (/developers) or from_colony_token() |
from agentdisco import (
AgentDisco,
InvalidUrlError,
NotFoundError,
RateLimitedError,
)
try:
scan = AgentDisco().submit_scan("https://example.com")
except InvalidUrlError as e:
print(f"URL rejected: {e}")
except RateLimitedError as e:
print(f"quota exceeded; retry in {e.retry_after_seconds}s")
except NotFoundError as e:
print(f"not found: {e}")
All SDK-raised exceptions inherit from AgentDiscoError, so a single
broad catch works too:
from agentdisco import AgentDiscoError
try:
...
except AgentDiscoError as e:
log.warning("agentdisco failure: %s", e)
Network-layer failures (connection timeout, DNS) leak through as raw
httpx.HTTPError — they're platform issues, not API errors.
For self-hosted deployments or local testing:
AgentDisco(base_url="http://localhost:1977")
MIT. See LICENSE. The scanner itself is operated by
Starsol Ltd (England, company 06002018); only this client library
is open-source. Issues + pull requests welcome.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.4.0 | 20 Jul 2026 | 5 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 21:48 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:192f452d7f037dc7d2cb3fe9263b21323f4044fe00d0147a65c265dc323c927c