Skip to content

Time Machine

View the console at a past instant: what did this page say at 03:12 last night? Open the console as of the incident and read every page in that moment's terms, or put two tabs on two ?at= values for a before/after of a change.

Overview with the Time Machine engaged at 9/26/2026, 06:26:30: the amber banner You are viewing … return to Live to act with a Return to Live button, 18 pairs failing (TCP), 6/6 nodes ready, 18 failing pairs, the Worst pairs table at 100.0% led by kc-accept-control-plane → kc-accept-worker2, the Firing alerts panel saying alert state is a live-only signal, the open incident acc-worker2-worker5 cut drill, and the time picker popover open with 15m ago, 1h ago, 6h ago and 24h ago presets, a September 2026 calendar with the 26th selected, date and time fields, Now, Cancel and Apply

Engaged, with the picker open: the amber control top right shows the viewed instant and opens a popover with relative presets, a calendar, date and time fields and Now. The banner offers Return to Live, and the page reads in that instant's terms: 18 pairs failing on TCP, 6 of 6 nodes ready, every worst pair touching worker2 or worker5, and a Firing alerts panel explaining that alert state is live-only and has no history here.

The ?at= parameter

The Time Machine owns exactly one URL key: ?at=, an RFC 3339 instant (2026-08-29T14:32:00Z). Every in-app link on a time-aware page carries it, so navigating stays inside the same instant, and any console URL with ?at= is a shareable snapshot address.

The parameter is strict on purpose, so a shared link means the same thing to the browser and to the Go API (time.RFC3339). A malformed value degrades to Live with a console warning. A future instant is clamped to now client-side, and the server backs the same rule independently: GET /api/v1/topology?at= answers 400 for a future instant. Values are truncated to the second.

Entering and leaving

The control lives in the page header, next to the range presets: the presets pick how long the window is, this picks where it ends. Idle it reads Time Machine: Now; engaged it shows the viewed instant, turns amber, and a banner appears: "You are viewing {at}", with a Return to Live button. Pressing it moves keyboard focus to the page's Time Machine control, or to the page itself where there is none, so focus is never dropped.

Other routes in and out:

  • The command palette: Toggle Time Machine — pick a time… and Return to Live.
  • Pasting or following any URL with ?at=.

Picking a time

The control opens a popover with a calendar, separate date and time fields, and a Now button that jumps both fields to the current moment. The fields speak your local wall clock; the ?at= they produce is UTC RFC 3339, and the picker does the conversion, so what you aim at is the time you lived through, not its UTC translation.

The time field works to the minute. The Time Machine's own precision is the second, but a seconds spinner buys nothing an operator wants to aim at; if you need a specific second, edit ?at= in the address bar. Under the hood the two fields are composed through the Date(y, m, d, h, min) constructor rather than by parsing a combined string, because some engines parse date-only strings as UTC and others as local time, and a picker that lands on a different hour per browser is worse than no picker.1

While engaged

Writes are disabled everywhere. Every mutating control is disabled with the same sentence: "Time Machine is engaged — return to Live to act." Starting a probe from a view of the past would run it now, against the present fleet, which is the one thing the mode must not let happen by accident. Disabled-by-time is deliberately distinct from missing-permission: permissions hide controls, the Time Machine disables them.

Live polling stops on every engaged page. Nothing refreshes while you are in the past.

What is and is not rewound

The control is offered only on pages that resolve their reads through ?at=; a page that ignores the past never invites it. Time-aware: Overview, Events, Matrix, Topology, Incidents, Routes · MTR, Run checks, Metrics, PromQL, and the pair, node, target and run pages. Not time-aware, because configuration is always now: Scheduled checks, Alerting, Settings.

Even on time-aware pages, some data has no past to travel to, and each page states its own bound in place:

  • Alert firing state is live-only, since Prometheus keeps no firing history (Overview, Incidents).
  • The MTR Explorer's route panes are live; those endpoints take no time parameter (Routes · MTR).
  • Run history is cut to the instant client-side over loaded pages, because GET /api/v1/runs has no time filter.
  • Open incidents, on the Overview and in the incident card of the pair, node and target pages, are cut to the instant client-side. The incident list has no "open at" filter: its time parameters match the window an incident was saved with, not when it was declared or resolved. So the page scans the list newest first and keeps the incidents declared by the instant and not resolved by then. The scan stops after 50 pages, and when that cuts it short, the panel says an older incident open at the instant may be missing. The object pages' card says "at {instant}" under its title.
  • A Topology past view is a reconstruction from topology events, bounded by database retention. It starts from the topology snapshot the console stores on connect and hourly, so an instant from before the first snapshot shows only the nodes whose agents changed after recording began.

How far back you can go is bounded by database.retentionDays (default 90 days) for event-backed views, and by Prometheus's own retention for metric-backed ones.


  1. web/src/components/ui/datetime-picker.tsx (composeLocal), which also renders the date field from the local getters rather than toISOString(), so a pick near midnight cannot shift by a day. ↩