Repository navigation
Releases: WhitenWhiten/topophany
Release list
Topophany v0.8.1
[0.8.1] - 2026-10-14
Changed
- The README and the homepage show the preview where 0.8.0 put it, at
home in Seattle, Osaka or Chengdu by language. Their stills, the
homepage's recording and the words beside them still showed the
network the preview had in Changsha, and the recording's two vantage
points were observers the preview no longer has, so made again it
would have shown nothing measured from either. They are captured
again, and the tour now fails to record, in the tests too, when it
views an observer the preview lacks. The homepage's vantage panel is
drawn where each language's preview puts its home, the transit host
and New York, with its map fitted to them and its arcs and labels laid
out so that none overlap. - Topophany has a new mark, the globe of the README's banner in little:
a dot-matrix Earth lit from the upper left, with an arc of light from
Shanghai to a place it brings to light across the Pacific. It is the
homepage's favicon, the mark beside its name and its Apple touch icon,
andscripts/icon.py(make icon) draws it from the land mask.
Fixed
- TLS and HTTPS checks, and https-connect hops, no longer report a
healthy service astls: timeouton a path that drops large
ClientHellos. Built with Go 1.26, a probe offered Go's default key
exchanges, led by the hybrid post-quantum X25519MLKEM768, whose key
share alone is over a kilobyte; where a path never delivered that
ClientHello, TCP connected and the handshake went unanswered until the
check timed out, while curl and OpenSSL reached the same server. Probes
now offer only X25519, P-256, P-384 and P-521, as those clients do.
Workers still offer the hybrid exchange to their collectors. - A worker with several collectors no longer probes on while it drops
every sample. Once each collector's share of the outbox was full, as
when all of them were down long enough, a new sample was kept for none
but reported as a degraded delivery, which a worker takes to mean
another collector still has it; it logged the loss and went on. With
room at no collector a worker now stops with the outbox's capacity
error, as one with a single collector always did, and keeps what it
queued. - An incident ledger that could not be written is written at the next
judgement, two seconds on, whether or not anything changed by then. A
failed write was tried again only once something else changed, yet the
collector logged "incident ledger written again" at the next judgement
that changed nothing, and a crash before the next change lost the
incidents that write held. The log now follows a write that succeeded. - A collector starting on a new data directory makes it durably. The
directory, those made above it and its new journal were never synced
into their parents, so on a POSIX filesystem a power loss could leave
the samples it had acknowledged, each written and synced, with no name
to find them by. Each is now synced into its parent as it is made,
before the collector opens, and so is any directory made to write a
file into, such as a credentials file's. - A worker starting on a new outbox makes it durably. Its directories
were never synced into their parents, and each record was synced into
pendingbutpendinginto nothing, so a power loss could lose the
samples a worker had queued before any collector took them. The
outbox's directories are now synced as they are made, before the
worker opens it.
Security
- A worker can no longer crowd other observers' alerts out of a webhook
they share. A webhook's queue held its 64 alerts whoever they were
from, so while it was down or slow a worker could fill it with
incidents of its own observer, which it can make at will, and every
alert from another observer was dropped until it drained. A full queue
now gives an alert from an observer with fewer waiting the place of the
newest from the observer with the most, so each keeps its share; a
drop is logged with the observer it was from. - A collector's TLS private key is read as its other credentials are.
topo servehanded--tls-keyto the TLS server to open as it was,
so a key other users could read, a link or anything but a file was
served from; now the key must be a regular file, not a link, of mode
0600or stricter on POSIX, or the collector does not start, and it
says why. Copy a key out of a certificate tool's directory of links,
such as Let's Encrypt'slive/, rather than pointing at it. - The editor no longer writes a terminal control or bidi rune from a
topology to the terminal. A field's text was shown without them, but
its cursor, in color, redrew the rune under it as it was, so moving
through a field of a crafted topology could send its controls one at a
time. Any such rune now shows as a space, wherever a single rune is
drawn, and the cursor stands where the text before it is shown rather
than a column further per control. - A worker can no longer fill its observer's share of a collector for
good by changing its boot. Each boot whose receipts expired left a
floor that was kept forever and counted against the observer's share,
and a worker picks its boot IDs, so one that sent each sample under a
new boot made its observer's samples refused with 429 from then on,
through a token rotation and a restart. An observer's floors now take
at most an eighth of its share; past that, those whose receipts were
taken longest ago go. The IDs they bound were received more than
--retentionand an hour ago, too long ago for their samples to be
accepted again, and a boot still delivering keeps its floor. - A topology's values reach no terminal raw. Errors that refused an
endpoint, link or path ID, a path's node or dependency, a check's kind
or a repeated header name wrote the value as it was, so a crafted
topology could clear, retitle or reorder the terminal of whoever
validated, served or edited it. Those values are now quoted with their
controls escaped, and everythingtopowrites to stderr, its errors and
logs, leaves out terminal controls and bidi runes but for newlines and
tabs.
Source commit: b8b1f14
Full Changelog: v0.8.0...v0.8.1
Topophany v0.8.0
[0.8.0] - 2026-10-14
Everything since 0.3.0. No release was published between them.
Added
- On the geo map,
phides every site plate and draws the arcs dashed,
leaving the markers and the lines.pagain brings the plates back.
The key does nothing on the virtual geo or the network graph. - Long-term history. Collectors roll every sample they accept up into
per-check rollups that outlive the raw journal: each sample's outcome
stands until the next sample or until it goes stale, and the time it
stood is summed as up, degraded, down or inconclusive (the monitor could
not tell), with the samples by outcome and a histogram of what the
passing ones took. Time no current sample stood for is unmeasured,
never up or down, so availability reads as "95.7% up over 96%
measured". Rollups are kept five minutes wide for two days, hourly for
32 days and daily after that, written with each checkpoint and rebuilt
from the journal, so a crash counts no sample twice.topo serve --rollup-bytescaps them (32 MiB by default); at the cap a collector
sheds the rollups of contracts it no longer counts, then the oldest
days of the observer whose rollups take the most room, and never stops
ingesting for them. - Snapshots carry each check's
availabilityover the last 24 hours, 7
days and 30 days. A check's evidence shows them, such asLast 24h: 99.2% up over 96% measured · down 11m, and the Checks tab its last
day's share up as UP 24H. GET /v1/rollups?check=ID&step=1h&span=7dlays a check's rollups out
in slots of five minutes, an hour or a day, andtopo history CHECK --step 1h [--span 7d]prints them, slot by slot with a total, or as
JSON. The preview keeps synthetic rollups as a collector watching all
along would, so scenarios show in them too.- A check's evidence opens with its recent samples, read from the
collector's history: a strip of one slot per sample colored by outcome,
with a grey dot for each interval in which none was taken, a bar for
what each passing sample took, and their median and 95th-percentile
times with the median DNS, connect, TLS and first-byte times.
topo show checks IDprints the same strip, and its JSON carries it
slot by slot assamples. - Collectors keep an incident ledger,
incidents.jsonin their data
directory, judged every two seconds from the evidence of all observers
whether anyone is looking: an incident opens when it is confirmed,
recovers while its failed checks pass again short of their recovery
threshold (a failure then is a relapse, not a new incident), and closes
as recovered, unconfirmed, paused or changed. Each change is logged.
Snapshots carry the open records and those closed in the last day as
ledger; the Incidents tab andtopo show incidentslist them after
the open incidents, one row per occurrence, and an incident's evidence
says when it opened, how often it happened before and how long it
lasted. A recovering incident still needs attention. - A collector logs what its store holds when it starts: each observer's
receipts and bytes against its share, and where its receipts settle at
the last hour's rate, since a receipt lasts the ingestion window and an
hour. It warns once when an observer is set to fill its share, and
when, so its sampling or--retentioncan change before its samples
are refused. - Webhook alerts.
topo serve --alerts alerts.jsonposts incidents that
open and close, and observers that fall silent or report again, as
JSON or in the formats of ntfy, Slack and Discord, filtered by event
and observer. The file names secrets, so it is private to the
collector likeauth.jsonand reloads with it onSIGHUP. Each
webhook has a bounded queue delivered in order, at least once, with
retries for failures, 408, 429 and 5xx until an alert has waited a
day. What waits is kept in the data directory asalert-queue.json,
so a collector that stops or reloads loses none of it, and each
webhook's sent and dropped alerts are counted there and logged at
start; logs name webhooks by ID, never by URL. - Everything the TUI shows can be read from the command line.
topo status
prints the Overview (verdict, check and tab counts, what needs attention,
services and observers) and says it in its exit status: 0 all clear,
2 something needs attention, 3 nothing current is known, 4 no collector
answered.topo show TAB [ID]prints any tab, or the evidence behind
one entry as the evidence panel has it, a server with its card;
topo show maplists the map's nodes and edges with what each may
claim.topo history CHECKreads a check's recent samples. Each takes
--json,--observerand the connection flags oftopo. - Collectors and workers reload on
SIGHUP(systemctl reloadwith the
shipped units): a collector rereads its topology andauth.json, a
worker its topology. A file that fails validation, names another
project or drops the process's own observer is refused and logged, and
the running topology kept; a reload logs which checks measure something
new and so start afresh. Windows has noSIGHUP; restart there. - Snapshots say, for each observer, whether its executor measures what the
collector counts. After a collector reload, an observer whose worker
still runs the old topology readsoutdated, needs attention and is
counted on the Observers tab until that worker reloads too. Workers
report this in their heartbeats. - Snapshots carry each endpoint's state from the checks that target it,
and the Topology tab's endpoints show the same evidence lines as other
entities: the state's reason and the checks behind it. topo preview [--scenario N] status(orshow,history) reads the
synthetic evidence, andtopo preview scenarioslists the scenarios, so
scripts and agents can be rehearsed on a simulated outage.- The preview speaks English, Japanese and Chinese. Names, notes and
scenarios come from one catalog per language in
internal/preview/locales, through references such as@node.win; a
language is supported when its catalog is there. Each language also has
its own placed topology, so the home is Seattle, Osaka or Chengdu
rather than one private network shown in translation. The node IDs,
the scenarios and the evidence stay the same, and a test holds every
language to that.topo preview --langpicks one, and by default the
first ofLC_ALL,LC_MESSAGESandLANGthat is set decides,
falling back to English.--print-topologywrites the topology in
that language, andtopo preview scenarios --jsongives each scenario
anidthat is the same in every language. - The homepage is in English at
/, Japanese at/ja/and Chinese at
/zh/, each linking the others, with a language menu and a hint that
offers a visitor arriving from elsewhere the page in their browser's
language. The pages are written byscripts/build_site.pyfrom one
template per page insite/srcand one catalog per language, and each
language replays a TUI recording of its own preview. It says what
Topophany is, and can be found as that: a sitemap naming every
language's page,robots.txt, and schema.org data for the site and
the software. Headings are lit dot by dot, the docs sit beside the
install, and the semantics are drawn as the TUI draws them. The page
is a line or two where it was the manual, and what was there for
effect is gone. - The README is translated into Japanese (
README.ja.md) and Chinese
(README.zh.md); a test keeps their commands, links and sections those
of the original, and each shows the TUI in its own language. make capturescaptures the TUI stills indocs/assetsfrom the
preview, painted by the homepage's terminal renderer: the README's in
every language, the guide's in English. They now show the current TUI.fshows the map alone, on the Overview or Topology (from another tab,
the Topology's), andforEscbrings the panels back. The selection
still moves with the arrow keys and is named with its state along the
map's foot. With the room, the virtual geo says what runs on each node,
services with a problem first and in their color, on a line under it
when its cards have the height, and geo plates name them after each
node.
Changed
- The geo map labels a site with a plate, its place over a row for each
node, set down where it covers the least land and the fewest arcs:
beside its marker when there is room, otherwise joined to it by a thin
leader, so a crowded region spreads its labels into the sea around it
rather than stacking them over each other. A short map shows fewer rows
and counts the rest, then folds a plate to one line. Labels stay put
while the selection moves. - Fitting every site, the geo map folds a stretch of longitude wider than
60° with no site in it, such as the Pacific between China and
California, to a narrow seam marked with how many degrees it holds, so
the coasts on either side get the width instead of an empty ocean. The
focus and world views are never folded. Its natural height is the
latitudes its sites span with room for their labels, rather than the
whole world, and on the Overview it keeps the rest when nothing needs
attention. - Labels take the room there is rather than a fixed width: virtual geo
cards widen to their full names where the gaps can spare it, a network
chip cut short by its column runs on into free cells to its right, a
service on the Overview with no cell beside it runs on to the edge, and
a server card's row keeps what it names whole before what it says on
the right. - Server cards name the server once, its state in the pill, and take an
amber or red header when something on them is affected or down. Their
sections open with a quiet label and a hairline rather than a bright
heading, and the frame is the card's edge, ...
Topophany v0.3.0
Added
- About links to the homepage, topophany.com, and to the source on GitHub,
written as OSC 8 hyperlinks where the terminal takes them
(TOPO_HYPERLINKS=0or1decides outright). On short screens the
blank rows between its paragraphs close up so the links stay. - Where there is room, About lists the keys of the mode the UI is in
(viewer, preview or editor) as keycaps, so?doubles as help. - Tabs count what in them needs a look (failing services, paths and
checks, open incidents, silent observers), red when anything is down and
amber otherwise; on narrow terminals the tab's number takes the color. - The terminal window is named after the verdict, such as
✖ 2 incidents · homelab · Topophany(✎ topology.json ●in the
editor), and its own title is put back on exit.
Changed
- The TUI writes only the cells that changed since the last frame, not
every line with a change, so animation on the maps sends a few hundred
bytes a step instead of tens of kilobytes. - While connecting or loading a view, the header, the status row, the
Overview's verdict and the empty map show a turning spinner rather than
a still◌, so a slow collector reads as busy, not stuck. - Menus, forms and confirmations cast a soft shadow onto the dimmed view.
- The Overview's big number is lit from above, a shade of its color for
each of its five pixel rows, as the About wordmark is. - On small terminals such as 80x24 the Overview keeps the verdict's big
number, puts the observers beside it, and when nothing needs attention
gives the room under a short all-clear to the service matrix. - The glints on the Overview's map run as smoothly as on the Topology
tab, and About's globe, once its introduction has played, turns at ten
frames a second rather than fourteen. - Times in the evidence read alike: an incident's start, a check's last
sample and when the collector received it are local time to the second
(2026-10-13 10:58:07 PDT), and an incident's start says how long ago
it was, rather than mixing in RFC 3339.
Fixed
- PTY acceptance reconstructs the terminal screen before checking state, so
incremental redraws correctly verify collector failover. CI fuzz suites use
an execution budget instead of a short wall-clock deadline. - Large topology diagrams have bounded layout work and an explicit fallback;
ordinary dense diagrams retain their routing and ordering quality. - Notices fade out, and the evidence footer identifies Enter as the back action.
- On narrow terminals the header's project and view no longer run into
the live indicator: they end in an ellipsis before it. Before the first
snapshot the header no longer says it was updated "never".
Security
- Enforce per-source collector connection quotas and absolute connection lifetimes;
close unauthenticated HTTP/1 connections while preserving authenticated reuse. - Give viewers a public topology revision that excludes private execution settings,
including revisions embedded in snapshots and observation history. Workers keep
the private execution revision contract.
Source commit: d440d53
Full Changelog: v0.2.0...v0.3.0
Topophany v0.2.0
Added
- A virtual geo map, now the default when any node has a location: places
become cards in columns from west to east and north to south, keeping
the world's order but not its distances, so crowded sites stay legible.
Each node has its own row, links are wires between rows (and brackets
inside a card for links within one place), and unplaced nodes such as
edges and the internet float as pills beside what they connect to.m
cycles virtual geo, geo and network; cards fold on short maps, and links
that find no room are counted in the legend. - A Servers tab (
3): a card for each server with its state, kind,
provider and place, the services it runs and the edges in front of them,
its addresses by network, what it hosts, who observes from it, its links,
and its notes as a memo. Edge and platform cards list what runs there,
what they stand in front of and where they answered from. Later tabs move
up one: Services is4and About is9. - Edges and platforms: nodes of kind
edge(Cloudflare, Vercel) and
platform(Supabase) with aprovider, services with aruntime
(workers,pages,functions, …), and endpoints that name the edges in
front of them invia. Evidence is attributed alongvia: an edge's
answer, even a 521, proves the edge; the origin counts only a passing
response not served from the edge's cache. - HTTP probes record which edge answered, from where and whether from its
cache (edge_provider,edge_pop,edge_region,edge_cache). - The preview topology puts Cloudflare in front of the main site, with a
Worker, a Pages site and a Vercel app on Supabase, and gains two
scenarios: the origin down behind Cloudflare, and the edge unreachable
from the mainland.
Changed
- The About globe reads as a sphere instead of a flat disc: a shaded ocean
and land lit from the upper left, falling off across a soft terminator and
toward the limb, with a graticule that curves with the surface. Truecolor
terminals shade under the dots; 256-colour terminals keep a dotted ocean.
The README banner is redrawn from the same art. - The homelab example models its CDN as an edge in front of the DMIT
origin.
Fixed
- Avoid a data race when reading outbox delivery retry state.
- A service reached over several failing paths no longer repeats "access
path unavailable" once per path in its reason.
Security
- Bound Exit-IP and Mihomo JSON structure before decoding; escape bidirectional controls in CLI JSON without changing parsed values.
- Reserve outbox capacity per destination, history capacity per observer, and snapshot computation per viewer; bound connections and pre-authentication work.
- Retain durable observation-ID bindings until administrative archival and scope persisted heartbeats to their project and configuration revision.
- Bind source verification to the tested commit and file manifest; resolve release tags back to the built commit immediately before publication.
- Add regression tests for all eleven scan-bundle findings, including restart recovery, invalid acknowledgements, and moved release tags.
Source commit: 52d0e16
Full Changelog: v0.1.0...v0.2.0
Topophany v0.1.0
Topophany's first usable release: a single topo binary for evidence-based network monitoring, collection, and scoped observation workers.
Highlights
- Terminal dashboard, geographic and network maps, service tables, offline previews, and a local topology editor.
- HTTP/TLS, DNS, TCP, UDP, and ICMP probes, CONNECT/SOCKS5 proxy chains, and local proxy/tunnel adapters.
- Evidence and freshness tracking, dependency-based state derivation, journal recovery, deduplication, and a durable worker outbox.
- Bounded API resources and JSON decoding, hardened storage and configuration boundaries, and immutable release builds.
Downloads
Choose the archive for your operating system and CPU, extract it, and run topo --help. Linux and macOS archives contain topo; Windows archives contain topo.exe.
| Platform | Architectures |
|---|---|
| Linux | amd64, arm64 |
| macOS | amd64, arm64 |
| Windows | amd64, arm64 |
Verify downloaded archives against SHA256SUMS.txt. On Linux, run sha256sum --ignore-missing --check SHA256SUMS.txt; on macOS, compare shasum -a 256 <archive> with the matching checksum. On Windows, use Get-FileHash <archive> -Algorithm SHA256.
See the README for setup and the changelog for release details.
Validation
The merged application passed the complete local acceptance suite: race detection, repeated tests, nine bounded fuzz targets, five cross-compilation targets, and loopback process acceptance. Statement coverage was 85.9%. Cross-compilation verifies builds; native Windows/macOS and production network acceptance were not performed.