The project's README from github.com/anothaDev/luci-theme-vantage. As one markdown file: README.md.
A LuCI theme and live network dashboard for OpenWrt 25.12 and 24.10, built from scratch.
Screenshots show recorded data from a real access point, pseudonymised (documentation addresses and MACs, neutral names). See Develop.
Two packages. The app works under any LuCI theme; the theme is useful without the app.
luci-theme-vantage, the shell:
luci-app-vantage, the dashboard at admin/dashboard (the landing page):
![]() |
![]() |
| Light mode: health checks, network path and live throughput | Client inspector with experience score, signal and link details |
![]() |
![]() |
| Ctrl+K palette: every page, fuzzy matched | Stock Status page under the theme, with a combined memory bar |
![]() |
![]() |
| Stock Channel Analysis (neighbour networks are generated) | Phone layout with the bottom bar and the Wi-Fi/Wired switch |
For OpenWrt 25.12 (apk). Both packages are architecture-independent, so
the same files install on any target. For 24.10 (opkg, signed .ipk
repository), see OpenWrt 24.10.
From the signed repository, on the router (once; later versions come with
apk upgrade):
wget -O /etc/apk/keys/vantage-signing.pem https://anothadev.github.io/luci-theme-vantage/vantage-signing.pem
sha256sum /etc/apk/keys/vantage-signing.pem # must be c8a6c83eeb49ca2407932fb5e95785776128cef87db75ebaea0fe4171eee2157
echo 'https://anothadev.github.io/luci-theme-vantage/25.12/packages.adb' >> /etc/apk/repositories.d/customfeeds.list
apk update && apk add luci-theme-vantage luci-app-vantage
Or from the files of a
release (or
your own build), with the files in the current directory
(192.0.2.1 stands for your router's address):
sha256sum -c --ignore-missing SHA256SUMS
scp -O luci-theme-vantage-*.apk luci-app-vantage-*.apk [email protected]:/tmp/
ssh [email protected] 'apk add --no-network --allow-untrusted /tmp/luci-theme-vantage-*.apk /tmp/luci-app-vantage-*.apk'
Log out of LuCI and back in; the dashboard is now the landing page. On a fresh install the theme selects itself; an upgrade never overrides the theme you chose (System → System → Language and Style). Removing the theme switches LuCI back to Bootstrap.
The install guide covers requirements, verifying the packages, installing only one of them, upgrades, uninstalling, building Vantage into your own firmware, troubleshooting, and a ready-made prompt for installing with a coding agent.
With podman and the official OpenWrt SDK image:
dev/build/sdk-build.sh 25.12.4 # builds HEAD into dist/25.12.4/
The script builds from a clean clone of the commit in an SDK image pinned
by digest, so the same commit, SDK release and image always produce
byte-identical packages. It checks every package against the commit's
source (security-tests/verify_built_apk.js) before writing it to
dist/<release>/, next to SHA256SUMS and a BUILDINFO with the build
inputs. Optional index signing and the details are in the
install guide.
The UI is developed offline against recorded device data, never against a live device:
dev/replay/ serves the complete LuCI UI on 127.0.0.1
from a recording of a real LuCI session (ubus replies, HTTP responses
and static files; the format is in the replay's README) or from
hand-written fixtures, with the theme and app loaded from this tree;
reload to see an edit. Save & Apply works against an in-memory overlay.
Recordings stay outside the repository.--demo pseudonymises the recording as it loads:
documentation MACs and addresses (00:00:5E:00:53:xx, 192.0.2.0/24,
2001:db8::/32), neutral hostname, SSIDs and client names. The
screenshots above were taken this way.node dev/replay/server.js --mirror ../vantage-mirror --port 8106 --demo \
--theme-dir luci-theme-vantage/htdocs/luci-static/vantage --theme vantage \
--app-dir luci-app-vantage
See dev/replay/README.md for all options,
docs/SPEC.md for the product and
docs/luci-contract.md for what LuCI expects from a
theme. dev/icons/build.js generates the status icon set; prototypes/
holds the design prototypes the packages were made from. Coding agents
working on the repository should read AGENTS.md.
Checks:
node --test tests/
dev/i18n/update.sh --check
node security-tests/check_dom_sinks.js
node security-tests/check_private_addresses.js [--require-mirror --mirror ../vantage-mirror]
node security-tests/test_templates.js
node security-tests/test_acl_policy.js
/proc/stat,
and LuCI's swconfig switch port state) and no file.exec. Wireless configuration comes from the app's own rpcd
ucode plugin (luci.vantage wireless), which leaves out Wi-Fi keys,
SAE passwords and RADIUS secrets. Reverse DNS (network.rrdns lookup,
which lets its holder aim the device's DNS queries at any server) is a
separate, optional group, luci-app-vantage-rdns. The one write, device
names, goes through the plugin's set_alias, which validates the name
and MAC on the device and writes only /etc/config/vantage (at most 512
names); it is in its own group, luci-app-vantage-names. No group grants
uci writes. The firewall overview reads the firewall config (and the
interface status, to find the uplink) and is
shown only to sessions that hold LuCI's own luci-app-firewall group,
which already reads and changes that config; the app grants nothing for
it.E() and text
nodes; check_dom_sinks.js rejects innerHTML and other HTML sinks.test_templates.js renders the theme's templates with
hostile input and checks that markup stays stable, inline scripts carry
no data, the login error is generic and the theme adds nothing about the
device to logged-out pages. LuCI's core header still adds its L.env
script to every page (on anonymous 404 pages including the menu tree);
that is upstream behaviour, tracked as a known failure, see
docs/luci-contract.md section 2.test_acl_policy.js checks that the ACL grants exactly
the methods the app declares, and nothing more.check_private_addresses.js rejects
private IPv4/IPv6 addresses, MACs outside the documentation ranges, and
the hostnames and SSIDs recorded from the real device.| OpenWrt | Status |
|---|---|
| 25.12 | Built with the 25.12 SDK and tested |
| 24.10 | Signed .ipk packages since 1.0.8, built with the 24.10 SDK and tested on a 24.10.8 router without Wi-Fi (install) |
Available: English and Simplified Chinese (dashboard, thanks to @ntbowen). Translations are very welcome.
To add a language: fork the repository, run
dev/i18n/update.sh --add <lang> (a LuCI language code such as de or
zh_Hans), translate the two new .po files and open a pull request
that touches only po/ files. Preview your work in the replay with
--lang <lang>. The details are under
Translations.
Each translation installs as its own packages, e.g.
apk add luci-i18n-vantage-de luci-i18n-vantage-theme-de; see
Languages in the install guide.
Issues and pull requests are welcome; see
CONTRIBUTING.md. A bug report should include your
OpenWrt version (cat /etc/openwrt_release), your browser, and
screenshots taken with the replay's --demo mode or with personal data
removed: no real IP addresses, MACs or SSIDs. Report security problems
privately as described in SECURITY.md, not in a public
issue.
What changed in each release is in CHANGELOG.md.
Planned work and ideas are in docs/ROADMAP.md; next
up is searching clients, radios and networks with Ctrl+K.
GNU General Public License v3.0 or later (GPL-3.0-or-later), see
LICENSE and
luci-theme-vantage/NOTICE.