An observatory for your refs.

Refs change. Refscope records what changed, and when.

Refscope is a local, read-only observatory for Git refs and history. It watches one repository at a time, records what changes, and separates what was observed from what it means.

Local-first. Read-only. One command. MIT licensed.

Refscope mock UI showing a three-pane layout: a sidebar with branch and tag refs and a notice that history was rewritten on main, a commit timeline with seven commits and the most recent commit marked as new, and a collapsed detail panel.
The mock UI mid-session: sidebar with one rewrite notice, timeline with one new commit, detail panel collapsed.

What you get

Three things Refscope does that other Git tools do not.

History rewrites, recorded as facts

When a force push, rebase, or reset moves a ref, Refscope captures the previous tip, the new tip, the time, and the source of detection. The recoverable hash stays visible so the work is never described as lost.

Observation and interpretation, kept apart

What was observed (ref, hash, timestamp) is shown in one column. What it means (rewritten, merge, signature unknown) is shown in another. You can paste the facts into a postmortem without copying anyone's opinion.

A calm UI that lets you read

Live updates do not steal focus, do not auto-scroll, and pause on demand. Status is conveyed by colour, shape, and text together — the page survives greyscale printing, screen readers, and reduced motion.

Lenses

Three lenses over the same repository.

Switch between Live, Pulse, and Stream without losing the active ref, the selected commit, or any filters. Each lens is a different way to read the same observed facts.

Live

The commit timeline as a single, calm column.

The default view. Refs, working-tree changes, and incoming commits read top to bottom. Live updates do not steal focus and do not auto-scroll the row you were reading.

Pulse

A canvas of file-change particles, drifting and bursting in real time.

Each particle is a file, colored by its kind and sized by how often it changes. When a file's contents shift, that particle bursts with sparks and a brief flash. Idle, the field breathes; busy, it pops like popcorn. Right-click any particle to open its file history; uncommitted edits surface alongside committed changes.

Stream

One row per file change, in reverse chronological order.

An event-shaped feed: status, path, additions, deletions, and the commit it belongs to. New commits arrive at the top; working-tree edits are interleaved as they happen. Right-click a row to open its file history.

Demo

Each scene is a single observation, captured from the running mock UI.

  1. A force push is recorded, not announced

    The sidebar shows the ref name, the previous tip, the current tip, and the observed time. Nothing flashes. The recoverable hash stays visible so the user can run git reflog to recover.

    Sidebar showing a history-rewritten notice for the main branch with previous tip, current tip, and observation time visible.
  2. The commit timeline reads top to bottom

    Each commit is one row: hash, author, message, additions and deletions, signature status. New commits arrive without scrolling the row you were reading.

    Commit timeline listing ten commits in a dense table; the most recent commit row is highlighted to mark it as newly observed.
  3. Compare bar pins a base and a target

    Pick a base ref and a target ref. Refscope returns ahead and behind counts, file totals, and three copyable Git commands — log, diff --stat, diff — with the revisions kept as separate tokens.

    Compare bar with main as base and a feature branch as target, showing ahead and behind counts and three copyable Git commands.
  4. Live updates, paused

    Press pause. New observations are counted in the badge but the timeline holds still. Resume to apply the queue. Useful when you are reading a commit and a teammate force-pushes.

    Three-pane layout with the top bar's pause control engaged; the timeline holds its position while a counter records queued live updates.
  5. Command palette, same state as the page

    Cmd or Ctrl plus K. Run pause, copy current commit hash, clear path filter, and the page state updates in place. The palette does not maintain a parallel list of refs or commits.

    Command palette open with the pause command highlighted; the rest of the page is dimmed but readable behind the palette.
  6. Commit detail, with facts in their own column

    Hash, parents, refs, change graph, file-status mix, and the changed-files list sit in a column of their own. Interpretation lives in badges next to the facts, never inside them — paste the hash without copying anyone's opinion.

    Commit detail panel showing the full commit hash, parent commits, refs, a change graph, the file status mix, and a list of changed files.
  7. Period summary as an observation log

    Aggregate observations over a window into labelled bars — commit count, additions, deletions, signed commits, merge commits, and live-update arrivals — read like a telescope's nightly log.

    Period summary view showing labelled bars for commit count, additions, deletions, signed commits, merges, and live-update arrivals.
  8. Color-blind safe palette, one toggle away

    Switch the status palette to the Wong scheme so red, orange, blue, and yellow stay distinguishable for protan, deutan, and tritan vision. Status text and shapes carry the same meaning in either palette.

    Top bar with the CVD toggle on; sidebar and timeline are rendered in the Wong color-blind safe palette.
  9. Pulse lens, the codebase as a particle field

    Switch from Live to Pulse. Each particle is a file, colored by its kind and sized by how often it changes. When a file shifts, that particle bursts with sparks and a brief flash; idle, the field breathes. Uncommitted edits drift in the same field alongside committed changes.

    Pulse lens showing the repository as a canvas of drifting particles colored by file type, with the lens switcher set to Pulse.
  10. Stream lens, one row per file change

    Switch to Stream. Each row is a single file change — status, path, additions, deletions, and the commit it belongs to — in reverse chronological order. New commits arrive at the top; working-tree edits are interleaved as they happen.

    Stream lens showing a vertical feed of file changes with status badges, path, and addition/deletion counts, with the lens switcher set to Stream.
  11. File history, with related files alongside

    Right-click any file row, or open the path prompt from the top bar, to see one file's history: a hunk timeline, a branch-drift halo, and a related-files panel that surfaces co-change neighbours from the same commits.

    File history view for a single path, showing the per-file timeline, branch drift halo, and a related-files (co-change) panel listing co-changing paths.

Why an observatory?

A telescope log, not an alarm bell.

Git history is rewritten in places no one is watching. A force push, a reset, a reflog expiry — yesterday's commit becomes today's stranger, and the only record of the change is the change itself.

Refscope is the observatory. It opens beside your repository, records what was observed, and separates that record from any interpretation. It does not raise alarms. It does not infer intent. It writes down the time, the ref, and both hashes, the way a telescope log writes down the time, the coordinates, and the seeing conditions.

When the question comes — "what happened to main at 02:17?" — Refscope has an answer that does not require trust in Refscope. The evidence is there, in the same form a Git command would have produced, with the interpretation labelled separately so it can be agreed with or rejected on its own.

Security and sandbox

Refscope reads from Git. It does not write back.

The constraints below are enforced in code, not in documentation.

WhatHow
Repository access Allowlist via RTGV_REPOS. Only listed repository ids are served.
Git commands A fixed read-only set: cat-file, diff, for-each-ref, log, merge-base, rev-list, rev-parse, show.
Spawn model Argument-array, shell: false, --no-pager, bounded stdout and stderr, timeouts.
Environment GIT_*, SSH agent, proxies, GCM, lazy fetch, terminal prompt, optional locks, ext-diff, and textconv are stripped or disabled.
Cryptographic signatures Not verified. Refscope reports signed: false and signatureStatus: "unknown" rather than guess.
Network surface Localhost HTTP. Default origins: 127.0.0.1:5173, localhost:5173. Override with RTGV_ALLOWED_ORIGINS.

Quickstart

Two steps. No install needed — Refscope runs against the current directory by default.

  1. Run Refscope against this directory

    npx -y github:simota/refscope
  2. Open the observatory

    http://127.0.0.1:4175

    The CLI opens this URL automatically. The address is here for reference.

To watch a different repository, pass an absolute path: npx -y github:simota/refscope --repo /absolute/path/to/git/repo. To skip the auto-open, add --no-open. Refscope rejects non-Git roots before serving.

Building from source (make dev-self) is documented in the repository readme.

Beyond MVP

What is not yet here.

Refscope is a v0. Below is what is honest to say about what comes next, and what does not.

Likely next

  • Static export of the recorded observation log for offline reading
  • Multi-repository view with several observatories visible at once instead of one at a time
  • Reflog overlay so recoverable hashes stay reachable from the timeline after a rewrite

Not in scope

  • Cryptographic signature verification (would invoke external GPG)
  • Operations against the repository (no commit, no push, no rebase)
  • Cloud or remote agent (local-first only)

No quarter-by-quarter dates. No Q3-2026 promises. The repository's open issues are the source of truth.