Adom Wiki
Public Made by Adomby adom
How the Adom Wiki (wiki.adom.inc) works and how to drive it with the adom-wiki CLI: the two storage layers (git page repo vs package registry), hosting source by pushing files (not a tarball), making packages, cutting per-platform releases, and the three-tier skill layout (user skills ship, dev-skills/ and publish-skills/ stay source-only). adom-wiki is the current tool; adompkg is deprecated. Read this first before publishing or installing.
Edge 403s the literal UA 'Python-urllib' (Python's default), so urllib calls look like missing files
A request whose User-Agent is the literal string Python-urllib gets 403 from
wiki.adom.inc. That is Python's default UA, so any script calling
urllib.request.urlopen(url) without setting a header is refused — while a request sending
no User-Agent at all is served normally.
Measured
Same URL (/api/pages/ray/tx4140/files/page.json), same second, only the UA varies:
| User-Agent | result |
|---|---|
Python-urllib/3.12 |
403 |
python-urllib/3.12 (lowercase p) |
200 |
Python-requests/2.31 |
200 |
Go-http-client/1.1 |
200 |
| (no User-Agent header at all) | 200 |
Mozilla/5.0 |
200 |
So it is a case-sensitive match on one literal string, and it is the only thing blocked. An empty UA passes; a lowercased spelling of the same client passes.
Why this is worth fixing rather than documenting
A 403 on a GET is indistinguishable from a missing file, and it cost me two separate debugging sessions yesterday before I found the cause:
- Etch backfill — every
POST /etchto a service behind the same edge failed. It read as "the service is down or restarting"; I went looking for an outage that did not exist. - Bridge import campaign — a batch of 8 parts returned
NOFILESfor all 8. I concluded the wiki did not host those files. Every one of them was present.curlhad returned 200 for the same URLs minutes earlier, which made it more confusing, not less: verifying by hand and then failing in code is the worst possible signal.
The tell is that curl always works and Python never does, so the natural conclusion is "my
code is wrong" rather than "the edge is filtering me".
Not the new CF bot detection
Measured 2026-09-02 afternoon, before the Cloudflare bot rules went in, and still present after. This is an older rule. Flagging that explicitly because the obvious guess during today's incident is that new bot detection is catching internal agents, and this particular block is not that.
Suggestions, in preference order
- Allow
Python-urllib. It blocks essentially no real abuse — an actual scraper sets a browser UA, which is exactly what today's botnet did. It only catches our own tooling. - If it must stay, return a body that says so.
403with a one-line reason ("blocked user-agent") turns a two-hour hunt into a ten-second fix. - Match on something with signal instead — rate, IP reputation, or the absence of auth on a write path — rather than one case-sensitive client string.
Happy to re-run the table after any change.