# viewllm: a 9MB Go binary that serves an agent's HTML, and a tunnel that makes it public

> viewllm is a single-binary report viewer for the HTML and Markdown that coding agents produce, written in Go with no module dependencies and shipped through npm. Two things are worth reading past the feature list: the GitHub token is kept in the browser's localStorage, and the tunnel flag publishes everything in the served directory to anyone holding the URL.

**yz671/viewllm** — Single-binary HTML report viewer for LLM-generated artifacts

- Repository: https://github.com/yz671/viewllm
- Stars: 823 · Forks: 113
- Language: HTML
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/yz671-viewllm

## The tunnel publishes the whole served directory, with no account

Sharing is one flag. The startup banner says so plainly:

```
viewllm serving ./reports

  Open: http://192.168.1.42:8090
  To share over the internet, use -tunnel
```

And the tunnel output states the terms of the link it hands you:

```
viewllm serving ./reports — starting tunnel (powered by Cloudflare)...

  Share this link: https://random-words.trycloudflare.com

  Anyone with this link can view your reports.
  This link expires when you stop viewllm — a new one is created each time.
```

There is no login, no per-report permission and no share list. The unit of access is the URL, and the URL covers everything under the directory being served, not one report. The link's lifetime is tied to the process, which is the one good property: stop viewllm and the address stops resolving.

The per-device unread tracking has the same shape. Each browser that opens the link keeps its own read and unread state, and all of those preferences live in localStorage, so two people looking at the same tunnel see the same files and different badges.

## The GitHub token is stored in localStorage and sent from the browser

The second source of files is a GitHub repository, and the design here is unusual. Start viewllm with no directory, open the gear icon, choose Source, then Browse GitHub repository, enter a repository as `owner/repo` or paste its URL, add a token for private repositories, and connect.

Three consequences follow from that arrangement. The full file list arrives in a single GitHub API call, individual reports are downloaded on demand and rendered in the browser, and nothing is written to disk. The repository and the token are then saved in the browser's localStorage, so the connection is restored automatically next time.

Storing a personal access token in localStorage is the part to think about, because localStorage is readable by any script that runs on that origin. The page's guidance is correspondingly specific: prefer a fine-grained token, set Repository access to only the repositories you choose, and grant Contents as read-only, which is the only permission needed since Metadata read-only is added automatically. The alternative is a classic token with the `repo` scope, which the page itself describes as granting full read and write access to all of your private repositories, and to be used only if a fine-grained token is not an option.

Rate limits are stated too: 60 requests per hour unauthenticated, 5,000 with a token.

## The documented binary download is amd64 Linux, and npx is the portable path

There are three install routes and they are not equally supported by the page. The first is the one the project leads with:

```bash
npx viewllm@latest
```

The second is a release download, and the command names exactly one asset:

```bash
curl -fsSL https://github.com/yz671/viewllm/releases/latest/download/viewllm-linux-amd64 -o viewllm
chmod +x viewllm
./viewllm
```

That filename is amd64 Linux. No arm64 build, no Darwin build and no Windows build is named anywhere on the page, so a reader on an Apple Silicon Mac or on Windows has to use npx or compile. The third route is the source build:

```bash
git clone https://github.com/yz671/viewllm.git && cd viewllm
go build -o viewllm . && ./viewllm
```

The module requirement is a single line:

```gomod
module github.com/yz671/viewllm

go 1.24.3
```

No `require` block, which is the same fact the features table states as zero dependencies. Building it means having Go 1.24.3 or later and nothing else to fetch.

## No Go dependencies, but npm and frontend directories are in the tree

The repository lists ten top-level entries: `.github/`, `.gitignore`, `CHANGELOG.md`, `LICENSE`, `README.md`, `docs/`, `frontend/`, `go.mod`, `main.go`, `main_test.go` and `npm/`.

Two of those sit oddly against a claim of zero dependencies and a single Go binary. There is a `frontend/` directory, which is where the interface lives, and an `npm/` directory, which is where the npm package is defined, since that is the mechanism behind `npx viewllm@latest`. Neither is a Go dependency, and `go.mod` requires nothing at all.

The Go side is a single `main.go` at the root with one `main_test.go` beside it. The programme is therefore small and the interface is not, and the interface has to reach the binary somehow, which means it is either embedded at build time or fetched from the running server.

The repository's own language breakdown is HTML, not Go, for the same reason. On a language-share chart this project shows up as a web project, which is a reasonable description of where the code volume is and a misleading one about what you need installed to run it.

## Three releases in one afternoon, and nothing published since

The release history is compressed into a single date. v0.6.1 was published on 2026-06-24 at 10:59 UTC, v0.6.2 the same afternoon at 14:24, and v0.6.3 at 15:19. The last push to `main` came at 16:07 that day, roughly forty minutes after the final tag.

Since then there has been no release, and the default branch has not moved either, a gap of a little over three months to the day this was written. There is a `CHANGELOG.md` at the root, so the history between tags is recorded even when the tags are not cut.

Three tags in four hours is also a statement about versioning practice. A 0.6.x line moving that fast suggests the numbers are tracking internal churn rather than a compatibility promise, which matters if you plan to pin one. The page itself offers no stability statement, no support window and no compatibility table.

The performance numbers sit in the same frame. The features table gives a 9MB binary, about 7MB of memory, about 100ms startup and an API response under 5ms. They are presented without the hardware or the measurement method, so they are useful as an order of magnitude and not as a benchmark.

## The default port is 8090, and the tool also says it picks one itself

The usage line is short:

```
viewllm [directory] [-p port] [-exclude dir]... [-exclude-file name]... [-tunnel]
```

The flag table gives `-p` a default of 8090, and the sentence under the usage line says the current directory is served by default and that the tool finds an open port automatically. Those two statements pull in different directions: the table implies a fixed fallback, the sentence implies a scan.

The startup banner resolves the ambiguity for the common case, printing the LAN address on 8090. What neither says is what happens when 8090 is taken.

The two exclude flags are repeatable, so several directories and several filenames can be skipped on the command line, and the same patterns can be edited later in the interface. The settings list behind the gear icon is per device and stored in localStorage: toggles for showing HTML and Markdown, three themes, text snippets on and off, thumbnail previews described as live mini-renders, a recent files count with the options 0, 3, 5, 10, 15 and 20, custom ignore patterns, and the Source picker.

## The API listing stops after two endpoints

The documented interface is short, and then it stops:

```
GET /              → Web UI
GET /api/recent    → Recently modified files (with previews)
GET /api/tree
```

Two endpoints are described and a third begins. The arrow after `/api/tree` is followed by nothing, so whatever the file tree endpoint returns, along with any endpoint for the GitHub source, the tunnel state or settings, is not written down on the page.

That matters more for this project than it would for most, because the interface is the product. The whole point is watching an agent produce files and seeing them appear, and the mechanism that does it is a polling endpoint returning recently modified files with previews. Anything beyond that is guesswork from the browser's network tab.

What is documented elsewhere on the page fills some of the gap by behaviour rather than by interface: real-time file watching with unread indicators on new and modified files, shareable links to specific reports, hover preview popups on every file item, thumbnails, text snippets, and Markdown rendered with GitHub-style formatting alongside the HTML.

## Conclusion

viewllm is a good fit for the specific gap it names, which is that an agent writes a report, the report is rich HTML, and every ordinary way of looking at it is either a text editor or a directory listing. It is read only, has no database, and stops cleanly. Two cautions belong with that. The tunnel is not a share feature with access control, it is a public URL to everything in the served directory for as long as the process runs, so decide what is in that directory before using it. And the GitHub token lives in localStorage in the browser and is sent from the browser, which means it is reachable by any script on that origin, so the fine-grained read-only token the page recommends is the minimum, not a preference. On maintenance, the last release and the last push are both from 2026-06-24 and the page documents two of its API endpoints.

## FAQ

### What is viewllm and what problem does it solve?

viewllm is a single-binary viewer for the HTML and Markdown reports that coding agents such as Claude Code, Codex and Cursor generate. It exists because the alternatives fail: editor live preview breaks over SSH and WSL, GitHub renders Markdown only, a plain static server gives a raw directory listing, and sharing otherwise means emailing files.

### How do I install and run viewllm?

Run npx viewllm@latest with no install step. A release binary can be fetched with a curl command that names the viewllm-linux-amd64 asset specifically, and building from source needs Go 1.24.3, since go.mod declares no module dependencies. The current directory is served by default on port 8090.

### How do I share a viewllm report with someone outside my network?

Add the -tunnel flag, which creates a public URL through Cloudflare Tunnel. The page states that anyone with the link can view the reports, that there are no accounts involved, that the link expires when you stop viewllm, and that a new one is created each time the process starts.

### What GitHub permissions does viewllm need for a private repository?

A fine-grained personal access token limited to that one repository with Contents set to read-only, since Metadata read-only is added automatically. A classic token with the repo scope grants full read and write access to all private repositories and is only suggested when a fine-grained token is not possible. The token is kept in the browser's localStorage and sent only to GitHub's API from the browser.

### Does viewllm write anything to disk or need a database?

No. The page describes it as read-only, with no database, no config files and no background processes, and notes that reports pulled from a GitHub repository are downloaded on demand and rendered in the browser with nothing written to disk. The only stored state is preferences and the GitHub connection in localStorage, per device.

## Sources

- [Issues](https://github.com/yz671/viewllm/issues)
- [License: MIT](https://github.com/yz671/viewllm/blob/main/LICENSE)
- [README](https://github.com/yz671/viewllm/blob/main/README.md)
- [Releases](https://github.com/yz671/viewllm/releases)
- [yz671/viewllm on GitHub](https://github.com/yz671/viewllm)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yz671-viewllm
