Argus Fleet
panoptes the board for Argus · MIT

Which machine needs you?

One page for every machine running your AI agents: which are up, what runs on each, and which one is waiting for you. That one comes first. Click a session and you are in that terminal, on that machine.

$ curl -fsSLO https://raw.githubusercontent.com/andreaderuvo/panoptes/master/install.sh && bash install.sh

Reads the Argus on each machine. Runs on Linux, macOS and Windows, needs no tmux, and fits in a container.

A sketch of the Panoptes board: six machines, sorted so the one waiting for you is first, then one that has stopped answering, then one with a nearly full disk, then the ones that are working. board.internal:8070 Fleet 6 machines · 1 needs you gpu2 waiting for you · 6m load 3.1 · mem 58% · up 12d disk 61% train-v3 eval the A100 box nas-old not answering last seen 14 min ago backup the one in the cellar lab-box working load 1.2 · mem 33% · up 3d disk 93% api-cache shell clear old runs! hetzner working load 0.8 · mem 41% · up 40d disk 44% docs site laptop working load 0.4 · mem 62% · up 2d disk 78% notes build-01 idle load 0.0 · mem 12% · up 9d disk 20% shell 4 argus on 3 machines · 2 more calling in the one that needs you comes first gone quiet: still here, in red, until you say click a session and you are in it
why

When one machine becomes three, you become the polling loop.

A tab per machine, and you going round them. The agent that finished forty minutes ago finished into an empty room. The board does the going round for you.

Without it

  • Three tabs, and you check each of them in turn.
  • Which box had the full disk? You open all of them to find out.
  • A machine that is off looks exactly like one you forgot you had.

With the board

  • One page, sorted: waiting for you first, whatever machine it is on.
  • Load and the fullest disk on every tile, amber over 74%, red over 90%.
  • A machine that stops answering goes red and stays, saying when it last called in.
  • A tile says what the machine said

    Name, state, load, memory, the fullest disk, and one chip per tmux session. A chip is a link into that session, on that machine's own Argus.

  • Plus one line of yours

    A note per machine, in pencil: what the box is for, what it was doing. It is the only part of a tile that only you know.

  • A colour per machine

    Taken from the name, so it is the same on every device you open the board from, and yours to change.

One tile, explained: the machine's name and how long it has been waiting for you, the fullest disk, one chip per session, and a note written by you. gpu2 waiting for you · 6m load 3.1 · mem 58% · up 12d disk 61% train-v3 eval the A100 box and for how long the fullest disk,and only that one one chip per session:click one to go in your own note,in pencil everything else, the machine said
keys

It can look. It cannot get in.

The board reads a handful of numbers off each machine, and it is built so that losing it costs you a list of session names.

One read-only key per machine

A watcher token opens GET /api/overview on that machine's Argus and nothing else: no shell, no files, no writes, no proxy.

No key reaches a browser

The board holds them and the page never sees one. A click opens that machine's own Argus, in its own origin, with its own token.

No shell of its own

No terminal, no file browser, and no way to run a command it was not given by name on the machine itself.

Who holds which key: the browser talks to the board with the board's token; the board keeps one read-only watcher key per machine; clicking a session opens that machine's own Argus. your browser or phone panoptes 3 watcher keys kept here argus hetzner argus lab-box argus gpu2 board token GET /api/overview only a click opens that machine's own Argus no machine key ever reaches the browser
networks

Two directions, because networks are not symmetrical.

Local pull, remote push: the same arrangement as Prometheus in agent mode, or any dial-out agent such as Tailscale or the kubelet.

Two directions: the board polls a machine it can reach, and a machine behind a one-way firewall calls in to the board every ten seconds instead. panoptes :8070 argus · hetzner in the config argus · gpu2 report_to, every 10s nothing comes in pull: the board asks push: it calls in silence is the signal

The board asks

Write the machine down and it gets polled. A request that fails is itself the signal that the machine is down.

# ~/.config/panoptes/config.yaml
machines:
  - name: hetzner
    url: http://hetzner.internal:8090
    token: <a watcher token from that machine's Argus>

The machine calls in

Some networks only open one way. Then the machine opens the connection, in the direction that already works.

# argus config, on the machine that cannot be reached
report_to:
  url: http://board.internal:8070
  token: <the registration token>
  name: gpu2
  every: 10
Three rules keep the weak keys weak.

Announcing and looking use different tokens: the registration key cannot read the board, and the board's key cannot invent machines. The list you wrote by hand wins, so nothing holding the registration key can replace a real machine with one of its own. And a machine that stops calling in goes cold instead of staying green for ever.

actions

Start and stop, without a command in a request.

The menu on a tile can start and stop things on that machine. Each machine publishes named things in its own config, and the board may ask for one of those names and nothing else.

  • Named by the machine

    Only what a machine lists under runnable can be started or stopped, and only by a watcher allowed to.

  • Stopping Argus asks twice

    And says what it costs: every tmux session keeps running, but starting Argus again takes a shell on that machine.

  • Every press is written down

    The board's journal keeps who pressed what, and the address it came from.

The menu on a tile offers to start and stop nightly, a name the machine published in its own Argus config, and to stop that Argus, which asks twice. lab-box load 1.2 · up 3d ▶ start nightly ■ stop nightly stop this argus… asks twice # argus, on lab-box runnable: - name: nightly run: python3 nightly.py may_run: true may_stop_argus: false only names the machine published itself no command in a request
# argus config, on the machine
runnable:
  - name: nightly
    run: python3 nightly.py

watchers:
  - name: panoptes
    token: …
    may_run: true            # otherwise the token stays read-only
    may_stop_argus: false    # the one thing this board cannot undo
phone

A glance, from anywhere.

On a phone the board is one column in the same order, so the answer is at the top of the screen. It follows your light or dark setting, and installs as an app where the certificate allows it.

The board on a phone: one column, in the same order, the machine waiting for you at the top. Fleet 1 needs you gpu2 waiting · 6m nas-old not answering lab-box disk 93% hetzner working laptop working which machine needs me? one column, same order
install

Running in a minute.

Python 3.11 or newer, on Linux, macOS or Windows. The first run prints a link with a token in it, and shows a demo board until you tell it about a machine.

# read it first, then run it
curl -fsSLO https://raw.githubusercontent.com/andreaderuvo/panoptes/master/install.sh
less install.sh && bash install.sh
panoptes                     # prints a URL with a token in it
panoptes --qr                # and a code to photograph

No sudo, nothing outside your home, and the same line again updates it.

Then add your machines, or let them call in: the machine guide has both, with the exact configuration on each side.

faq

Before you try it.

Do I need Argus for this?

Yes. The board reads each machine's Argus and links back into it. Argus is one machine in a browser tab; the board is every machine on one page. Start with Argus, and add the board when one tab per machine stops scaling.

What does it actually hold?

Per machine: a name, a URL, a read-only watcher token, an optional colour and your note. Per sweep: hostname, uptime, load, memory, the fullest disk, and the session names with which of them is waiting. No file, no path, no command.

What happens when I restart the board?

The machines that called in are still there. A machine you stopped goes red instead of vanishing, because for the one question the board answers, gone and never-existed must not look alike. Forgetting one is something you do on purpose.

Can several people watch one board?

Yes, and the journal is why that works: a machine only knows that the board pressed stop, while the board knows which browser the click came from.

What is it built with?

Python on the server and plain JavaScript in the browser. No build step and no database: one file for the config, one for the machines that called in, one for the journal. MIT licensed.

Stop going round your machines. Let the board do it.