Profpatsch/users/Profpatsch/alloy-viz
- java/src/de/profpatsch/alloy/Worker.java 14.2 KiB
- probes/ 4.0 KiB · 3 files
- testdata/ 4.6 KiB · 2 files
- CLAUDE.md 12.9 KiB
- IMPL.md 27.5 KiB
- README.md 2.7 KiB
- alloy-viz.1 3.5 KiB
- default.nix 3.9 KiB
- dot.go 5.9 KiB
- go-deps.nix 767 B
- go.mod 171 B
- go.sum 328 B
- instance.go 11.2 KiB
- jobs.go 5.4 KiB
- main.go 2.8 KiB
- render_test.go 7.4 KiB
- serve.go 15.0 KiB
- templates.go 6.7 KiB
- theme.go 7.3 KiB
- watch.go 1.8 KiB
- worker.go 11.7 KiB
alloy-viz
View Alloy instances in a browser, without the Alloy GUI.
Point it at a .als file; it solves the selected command, renders the instance
as a graph, and re-solves whenever you save. You keep editing in your own
editor — the browser is a viewer.
nix run ~/kot/Profpatsch#alloy-viz -- model.als
Then open http://127.0.0.1:8791.
See man alloy-viz for the full reference (flags, and why solving happens in a
separate process).
What it does
- Watches the model. Saving re-solves and re-renders. Editing a sibling
<model>.thmtheme re-renders too. - Runs one command at a time. The command picker lists every
run/checkin the file; only the selected one is solved. Running all of them is what makesalloy execslow. - Never blocks. Solve times range from 0.1 s to several minutes, so runs are asynchronous, with live progress (variables, clauses, elapsed time) and a Cancel button.
- Applies the theme. Node visibility, colour and shape, and relations shown as attributes rather than arrows, are honoured — enough to reproduce the figures in Practical Alloy.
Building and installing
nix build ~/kot/Profpatsch#alloy-viz
# Or install it, to get `alloy-viz` and `man alloy-viz` on PATH
nix profile install ~/kot/Profpatsch#alloy-viz
There is no daemon to install: alloy-viz runs for as long as you are looking at a model, and exits with Ctrl-C.
How it is put together
browser ──HTTP+SSE──> alloy-viz (Go) ──NUL-JSON on stdin/stdout──> alloy-viz-solver (Java)
· watches the file · one warm JVM
· owns the job, kills to cancel · parse + solve
· XML → graph → DOT → `dot -Tsvg` · Alloy's own instance XML
The Java process is a dumb worker behind the Go one. It is kept warm between runs, so a re-solve after a save skips the JVM start and the parse — measured at 152 ms warm against 566 ms cold for the same command.
One model per process: alloy-viz views the file you name and nothing else, so
watching a second model means running a second one on another port.
Cancelling kills the worker, because that is the only thing that stops a solve:
SAT4J ignores Thread.interrupt() entirely. The next run transparently
re-parses (~1 s).
Implementation notes, verified facts and traps are in CLAUDE.md;
the original research and design rationale are in IMPL.md.
Status
Slice 1. Renders the first state of a solution.
Not implemented: instance enumeration (New Solution), the evaluator, trace stepping for temporal models, projection, and magic layout.
alloy-viz(1)
NAME
alloy-viz - view Alloy instances in a browser
SYNOPSIS
alloy-viz [-addr host:port] [-command index] [-no-run] <model.als>
DESCRIPTION
alloy-viz solves a command from an Alloy model and renders the resulting instance as a graph in a browser, re-solving every time the file is saved. It replaces driving the Alloy Analyzer's Swing GUI by hand.
The browser is a viewer, not an editor: you keep editing the .als file in your own editor. alloy-viz watches it and pushes each new instance over server-sent events.
Only the selected command is run. Running every command in a file is what makes alloy6(1)'s exec slow – five commands in the shipped ceilingsAndFloors.als take about 15 seconds – and while editing it is almost never wanted.
If a theme file exists beside the model, named after it with a .thm extension, it is applied. Editing the theme also triggers a re-render.
Options
-addr host:port
Address for the web UI. Default 127.0.0.1:8791.
-command index
Index of the command to run at startup, counting run and check commands from 0 in declaration order. Default 0.
-no-run
Do not solve at startup; wait for a command to be selected. Useful when the default command is a slow one.
ARCHITECTURE
alloy-viz is a supervisor; the solving happens in alloy-viz-solver, a Java process holding a warm JVM and the parsed model. It is kept alive between runs, so repeated runs skip both the JVM start and the parse. The saving is substantial: a solve that takes 566 ms on a cold worker takes about 150 ms on a warm one.
One model is viewed per process; to watch a second file, run a second alloy-viz on another port.
Solving runs in that separate process because it is the only way to stop it. A running SAT4J solve ignores Thread.interrupt() entirely – kodkod's SAT4J wrapper calls isSatisfiable() with no interrupt polling – so there is no in-process cancellation path. The Alloy GUI has the same constraint and solves it the same way.
Cancelling therefore kills the process, which also discards the parsed model; the next run re-parses it, costing under a second. This is a good trade for a solve that was taking long enough to be worth cancelling, and solve times vary enormously: a small structural model solves in a tenth of a second, while protocol-design/instance_19 takes over two minutes. Nothing in the UI ever blocks on a solve.
ENVIRONMENT
ALLOY_VIZ_SOLVER
Path to the alloy-viz-solver binary. The nix wrapper sets this; otherwise the binary is looked up on
PATH.
EXAMPLES
View a model, running its first command:
$ alloy-viz filesystem.als
Start on a specific command, chosen from the list:
$ alloy-viz -command 3 filesystem.als
Open a model with a slow default command without solving it first:
$ alloy-viz -no-run leaderelection.als
SEE ALSO
dot(1)
The instance XML that alloy-viz renders is Alloy's own format, documented in edu/mit/csail/sdg/translator/instance.txt in the Alloy sources.
AUTHORS
Profpatsch
CAVEATS
Only the first state of a temporal (Electrum) trace is rendered. Stepping through a trace, enumerating further instances, and the evaluator are not implemented.
Theme support is partial: node visibility, colour and shape, and whether a relation is folded into node labels, are honoured. Projection, magic layout and per-atom overrides are not.