Skip to content

The web interface

Terminal window
loadout ui

Starts a small server on 127.0.0.1, opens your browser, and stops when you stop the command. There is no daemon and nothing left running afterwards.

The interface exists because a flat configuration file cannot answer the question that matters most: which of my aliases point at tools I never installed?

It gives you:

  • The alias catalog with live availability — every entry shown with whether the tool it needs exists on this machine.
  • Pack toggles, with the count each contributes.
  • Credential entries: which exist, which is active, which have values stored. Never the values themselves.
  • The command reference, with each function’s requirements resolved against this machine.
  • A diff of the generated shell file before anything is written.

That last one matters more than it sounds. This tool writes a file sourced into every shell you open; showing exactly what changes is what makes that trustworthy. A test asserts the applied file is byte-identical to what the diff previewed, because a preview that can differ from the result is worse than no preview.

Terminal window
loadout ui --port 8800 # fixed port, rather than picking a free one
loadout ui --no-open # do not try to launch a browser
loadout ui --print-url # print only the URL, for scripting

The URL contains a token generated for this run. Anyone who has it can rewrite what your shell executes at login, for as long as the server is running.

This interface rewrites the file your shell sources on every login. That makes it, in effect, a remote code execution API for your account.

Binding to 127.0.0.1 keeps other machines out. It does not keep other pages out: any site open in your browser can issue requests to localhost. Three checks run before any request is served.

  • A per-run token. Generated at startup, compared in constant time, gone when the server stops. It reaches the page in the query string, because a browser navigation cannot set a header, and the page moves it into sessionStorage and strips it from the URL so it does not linger in your address bar or history.
  • Origin must be ours. A request carrying any other site’s Origin is refused before the token is even considered.
  • Host must be loopback. This is the defence against DNS rebinding, where an attacker points a hostname they control at 127.0.0.1 so your browser treats their page as same-origin. Their hostname will not match.

Static assets are the one deliberate exception: the stylesheet, the script and the favicon are served without a token, because a <link> or <script> tag cannot present one. They are inert files compiled into the binary and identical for every user. Everything that reads your configuration or writes to disk is behind the token.

Credential values are never sent to the page — only whether a value exists.

The full reasoning is in the security model.

Use SSH port forwarding. This is the intended answer and it needs no configuration.

Terminal window
# on the server
loadout ui --port 8800 --no-open --print-url
# on your laptop, in another terminal
ssh -L 8800:127.0.0.1:8800 you@server

Then open the URL the server printed. Your browser connects to 127.0.0.1 on your own machine, SSH carries the traffic, and nothing listens on a public interface. The Host header is loopback, so the checks pass unchanged.

Putting the interface behind https://loadout.example.com does not work, by design. A proxy sends Host: loadout.example.com, the loopback check refuses it, and the request gets a 403 before reaching any handler.

Allowing a configured hostname would be a small change. It is deliberately not offered, because that Host check is the DNS rebinding defence, and removing it leaves a single per-run token in a URL as the only thing between the public internet and an API that rewrites what your shell executes at every login.

URLs leak — through browser history, referrer headers, proxy logs, screen shares. A leaked token here is not an information disclosure, it is arbitrary code execution on that machine the next time you open a terminal. The token is also valid for the entire life of the process, with no revocation and no audit trail.

If you genuinely need a remote interface, the authentication has to live in front of it — mTLS, an OAuth proxy, or at the very least HTTP basic auth over TLS — and you should treat that as running an admin panel for your shell, because that is what it is. SSH forwarding gives you the same access, over a credential you already have, with nothing new exposed.