🐝 airanks-acp-agent
AIR (Artificial Intelligence Ranking) by airanks — AI optimization made visible. Check any site's AI Rank free at airanks.net (toolbar: airanks.net/toolbar).
This repo turns AIR into a callable ACP
(Agent Communication Protocol) agent named airank. Any ACP client, hub, or catalog —
BeeAI included — can POST /runs and ask airank for a site's AI rank the
same way it would call any other agent. 🤖↔️📊
🗺️ Contents
| 🧠 What it does | 🏗️ Architecture | 🔁 A lookup, step by step |
| 📦 Install | 🚀 Quickstart | 📋 Behavior reference |
| 🐝 Registering with BeeAI | 🔐 Shared authentication | 🗂️ Layout |
| 🧪 Testing | 🌐 The airanks family | 📄 License |
🧠 What it does
AIR measures AI optimization — how often, and how well, an AI assistant like ChatGPT cites a
given domain when answering real questions. airank is the ACP door into that data:
- 🎯 Domain lookup — send a hostname (
stripe.com), get its AIR score (0–10), percentile, tracked citation stats, and AI-file posture (llms.txt,ai.txt,robots.txtAI-agent rules). - 🔍 Search — send a phrase (
payment processing), get matching domains, brands, and phrases that airanks tracks. - ⏳ Graceful hydration — a domain brand-new to AIR triggers server-side hydration.
airankpolls and streams a "gathering…" progress message instead of guessing or hanging silently.
🏗️ Architecture
Four small modules, one job each:
flowchart LR
subgraph client["📥 Any ACP client"]
C["BeeAI hub / catalog\ncurl / other agent"]
end
subgraph agent_pkg["🐝 airanks_acp_agent"]
server["server.py\n@server.agent(name=\"airank\")"]
agentpy["agent.py\nparse → poll → format"]
api["api.py\nAirClient (httpx)"]
auth["auth.py\nresolve_token()"]
end
AIR[("☁️ AIR API\nairanks.net/api/v1")]
C -- "POST /runs" --> server
server -- "answer(text)" --> agentpy
agentpy -- "domain() / search()" --> api
api -- "Bearer token?" --> auth
api -- "GET /v1/domains/{host}\nGET /v1/search?q=" --> AIR
AIR -. "JSON" .-> api
agentpy -. "streamed reply chunks" .-> server
server -. "RunYield" .-> C
- 🌐
api.py— the asynchttpxclient (AirClient):GET /v1/domains/{host},GET /v1/search,GET /user, plusnormalize_hostname(). - 🔑
auth.py— shared token resolution, identical across every AIR client. - 🧩
agent.py— parses the caller's text, polls while a domain is pending, formats the reply. - 🚪
server.py— registers theairankACP agent and runs the server.
🔁 A lookup, step by step
The one behavior worth diagramming: a never-before-seen domain. Rather than fake a score,
airank streams a progress chunk and polls until AIR finishes hydrating it (or the ~180s budget
runs out):
sequenceDiagram
autonumber
participant U as ACP caller
participant A as agent.py
participant API as api.py (AirClient)
participant AIR as AIR API
U->>A: "stripe.com"
A->>API: normalize_hostname() → domain()
API->>AIR: GET /v1/domains/stripe.com
AIR-->>API: data.ai_files.status = "pending"
API-->>A: pending payload
A-->>U: ⏳ "gathering data now, polling…"
loop every AIR_POLL_SECONDS (default 20s)
A->>API: domain()
API->>AIR: GET /v1/domains/stripe.com
alt still pending
AIR-->>API: status = "pending"
else ready
AIR-->>API: status = "ready" + score
API-->>A: final payload
A-->>U: "**stripe.com** — AIR score 8/10 …"
else 429 rate limited
AIR-->>API: 429 + Retry-After
A->>A: sleep(Retry-After)
end
end
📦 Install
pip install -e .
Requires Python 3.10+. Two runtime dependencies: acp-sdk
(the official BeeAI/Linux Foundation Agent Communication Protocol server SDK) and httpx
(uvicorn<0.36 is pinned transitively — see the comment in pyproject.toml).
🚀 Quickstart
airank-acp
# or: python -m airanks_acp_agent.server
Starts an ACP server on http://127.0.0.1:8000 speaking the standard ACP REST contract:
GET /agents, GET /agents/airank, POST /runs, GET /runs/{run_id}, GET /runs/{run_id}/events.
Override the bind address with AIR_ACP_HOST / AIR_ACP_PORT.
Call it like any ACP agent:
curl -s http://127.0.0.1:8000/runs \
-H 'content-type: application/json' \
-d '{"agent_name": "airank", "input": [{"role": "user", "parts": [{"content": "stripe.com"}]}]}'
📋 Behavior reference
| You send | airank does |
Backing call |
|---|---|---|
A single word that parses as a hostname (stripe.com, www.Foo.com) |
Domain lookup — AIR score, percentile, tracked stats, AI-file summary. Polls while pending. | GET /v1/domains/{host} |
Anything with a space, or a word that isn't a plausible host (payment processing) |
Search across domains, brands, and phrases AIR tracks. | GET /v1/search?q= |
| Empty input | Returns the built-in help string. | — |
⚙️ Environment variables
| Var | Default | Purpose |
|---|---|---|
AIR_API_BASE |
https://airanks.net/api/v1 |
Point at a different API base (staging, a mirror, …). |
AIR_API_KEY |
— | Bearer token, always attaches (explicit intent). See Shared authentication. |
AIR_ACP_HOST |
127.0.0.1 |
Bind address for the ACP server. |
AIR_ACP_PORT |
8000 |
Bind port for the ACP server. |
AIR_POLL_SECONDS |
20 |
Interval between poll attempts while a domain is hydrating. |
AIR_POLL_MAX_SECONDS |
180 |
Total budget before giving up and telling the caller to retry. |
PLATFORM_URL |
http://127.0.0.1:8333 |
BeeAI platform to self-register with (via acp-sdk). |
PRODUCTION_MODE |
— | Set true to disable BeeAI auto-registration on startup. |
🐝 Registering with a BeeAI / ACP catalog
If a local BeeAI platform is running (PLATFORM_URL, default
http://127.0.0.1:8333), airank-acp self-registers as a provider on startup — nothing further
to do. To register with a different hub or catalog by hand, point it at this server's base URL and
/agents/airank manifest, e.g.:
beeai agent add http://127.0.0.1:8000
or add a provider entry {"location": "http://<host>:<port>"} via that catalog's own API. Set
PRODUCTION_MODE=true to disable auto-registration (e.g. behind a reverse proxy in prod).
🔐 Shared authentication
One login works across every AIR client — the air CLI, the browser toolbar, the airanks
Python SDK, and this agent. Run air login anywhere and this agent picks it up automatically.
Resolution order:
| Order | Source | Behavior |
|---|---|---|
| 1️⃣ | AIR_API_KEY env var |
Explicit intent — always attaches. |
| 2️⃣ | ~/.config/air/auth.json |
The file air login writes. A token loaded from here only attaches to requests aimed at the host it was saved for. |
| 3️⃣ | Anonymous | No token — subject to the anonymous rate limit (honored via Retry-After). |
🗂️ Layout
| File | Purpose |
|---|---|
src/airanks_acp_agent/api.py |
Async httpx client for GET /v1/domains/{host}, GET /v1/search, GET /user, plus hostname normalization — ported from the shared API contract. |
src/airanks_acp_agent/auth.py |
Shared token resolution (AIR_API_KEY > auth file > anonymous). |
src/airanks_acp_agent/agent.py |
Parses the caller's text, polls while pending, formats the reply. |
src/airanks_acp_agent/server.py |
Registers the airank ACP agent and runs the server. |
tests/test_agent.py |
Hostname normalization + response-formatting tests. |
🧪 Testing
pip install -e ".[dev]"
pytest
🌐 The airanks family
acp-agent is one door into AIR among many — same API, same shared login, different front door:
| Repo | What it is |
|---|---|
node-cli |
air — the reference command-line client. |
rust-cli / go-cli |
Zero-dependency Rust / Go builds of air. |
chrome-extension |
The AIR browser toolbar — a page's AI Rank while you browse. |
mcp-server |
MCP server exposing air_rank / air_files / air_search tools. |
agent-toolkit |
Wire AIR into Claude, Codex, Cursor, or any MCP-speaking agent. |
acp-zed |
This same idea, wrapped for Zed instead of BeeAI. |
python-sdk / js-sdk / composer-package |
Language SDKs — no CLI, just a client class. |
homebrew-tap |
brew install for the air CLI. |
claude-skills |
Open-source Claude Code skills built on AIR. |
See ../API-CONTRACT.md for the full wire contract every client shares.
📄 License
MIT — see LICENSE.
Made with 🐝 for the AI-optimization era. Powered by airanks.net.
Release files for airanks-acp-agent 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| airanks_acp_agent-1.0.0.tar.gz | 12.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| airanks_acp_agent-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.4 kB
Release files / airanks_acp_agent-1.0.0.tar.gz
| Download URL | airanks_acp_agent-1.0.0.tar.gz |
|---|---|
| Size | 12.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f7084d058709c00dfcfd2db1273be5155a157631001d634a2d94926354b6f95b
|
|
BLAKE2b-256 checksum How to use checksums |
f6ea1d06294a07202e7576e9f5209a7ebfedc4a24af5e89a883e7cdd978b6a1c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency logRelease files / airanks_acp_agent-1.0.0-py3-none-any.whl
| Download URL | airanks_acp_agent-1.0.0-py3-none-any.whl |
|---|---|
| Size | 14.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
464c30a4a5e30ff475228c3d7fc31e7218d9fafc89bf5afa269998d7cd85f6f0
|
|
BLAKE2b-256 checksum How to use checksums |
3a01c823a849b261aaf78687cbb9c81d34c2c0148609d77785bbaf43c86c57a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency log