I2P has thousands of sites and no good way to find them. Addresses are 52-character base32 strings. There is no DNS. The few search engines that exist crawl on their own schedule and hand you a title and a link. When a site goes dark, whatever it had is gone.
Nexus is my attempt at the discovery part. It is one repo with two apps that share a single i2pd router.
Abyssal
The public side. A crawler fetches eepsites, stores what it finds, and builds a full text index on top. The index is SQLite FTS5 with porter stemming, so searching tunnels also matches pages that say tunnel.
Results can be narrowed by language and by site type (directory, docs, forum, stats, service). There is a browse view too, for when you do not have a query and just want to see what exists. A graph view is built from links the crawler actually found, which is how you run into sites that no directory lists.
Every capture also gets written to disk, so there is an archive of old versions. If a site disappears you can still open what it looked like the last time it was crawled.
The crawler has controls because crawling I2P politely matters. Up to 20 workers sharing one proxy connection, a delay between requests per worker, a page limit, a depth limit, and pause, resume or rerun on a job. A scheduler re-crawls sites on an interval so the index does not rot.
Prism
The private side, a dashboard for the router you are running. Peers, tunnel counts, bandwidth, tunnel build success rate and uptime, plus a tunnel list so you can see the state of each one. There is a browser tab that proxies .i2p pages through your own router and rewrites links so clicking around stays inside the proxy, and an address book manager for hosts.txt subscriptions. That whole side sits behind an api key header, because it controls your router.
How it is put together
Every service is FastAPI. The index and the archive metadata live in SQLite. Both frontends are React with Vite and Tailwind. One nginx container is the entry point, and Docker Compose brings up i2pd, the crawler, both frontends and the proxy.
Where it is at
23 commits, all from June 2026. The Docker stack runs on a Linux host, which was the only supported way to run it, because i2pd needs host networking to publish its LeaseSet.
I have been working on running it natively since then, since a project you cannot run on your own machine is annoying to improve. Abyssal now starts outside Docker against a local SQLite file and a Homebrew i2pd, and both frontends build and talk to it. That gets its own devlog.
I still want a read-only public mirror of the index, per-site crawl delays so the crawler is easier on small hosts, and some way to handle old captures being reused for bad stuff.