|
| 1 | +# Codeviewer |
| 2 | + |
| 3 | +**Read the code. Run the agent. Same window.** |
| 4 | + |
| 5 | +A fast, read-only code viewer with a real built-in terminal and live git indicators. It's for |
| 6 | +watching your code while an agent (Claude Code, Codex, aider…) or any CLI tool works on it. |
| 7 | + |
| 8 | +**[Download at codeviewer.21no.de](https://codeviewer.21no.de)**: macOS (Apple silicon / Intel), |
| 9 | +Linux (x86-64 / ARM64), or a single command-line binary. Every download comes with a SHA-256 and |
| 10 | +signed build provenance; see [how to verify](https://codeviewer.21no.de/#verify). |
| 11 | + |
| 12 | + |
| 13 | + |
| 14 | +- **Zero dependencies.** Bun + TypeScript only: the terminal emulator, syntax highlighter, |
| 15 | + fuzzy finder, file watcher and UI are all written from scratch. |
| 16 | +- **Standalone app.** On macOS it's a native app (AppKit + the system WebKit), installed from a |
| 17 | + 40 MB `.dmg`, with no browser bundled. On Linux it bundles a verified |
| 18 | + [ungoogled-chromium](https://github.com/ungoogled-software). Either way, the window is locked down to its own |
| 19 | + loopback server and keeps no browser state. |
| 20 | +- **Typography:** JetBrains Mono for code and terminal, Inter for the UI, both embedded (OFL). |
| 21 | + Sizes adapt to pixel density: 13px on HiDPI screens, 14px on 1× screens. |
| 22 | +- **Real terminal:** a native PTY (`Bun.spawn({ terminal })`) plus a canvas-rendered xterm-compatible |
| 23 | + emulator with 256/truecolor, the alternate screen, mouse (SGR), bracketed paste, OSC 8 links, |
| 24 | + OSC 52 clipboard, synchronized output, wide characters and emoji, and pixel-exact box |
| 25 | + drawing. Sessions survive page reloads. |
| 26 | +- **Git (read-only):** |
| 27 | + - Explorer status letters and colors (M A U D R C), with folders rolled up and ignored files dimmed. |
| 28 | + - Colored tabs. |
| 29 | + - Gutter markers vs `HEAD`; click one to peek at the old lines. |
| 30 | + - Inline blame on the active line. |
| 31 | + - Status bar: branch, ahead/behind, merge/rebase state, stash count, and change counts that open |
| 32 | + a changed-files list (⌘⇧G). |
| 33 | + - Everything updates live as files, the index or refs change. |
| 34 | +- **Live:** files that change on disk reload in place, the changed lines flash, the gutter marks |
| 35 | + them, and the explorer shows dots on changed files. |
| 36 | +- **Fast:** a virtualized code view and tree, an incremental highlighter, and dirty-row |
| 37 | + terminal rendering. A 100k-line file opens instantly. |
| 38 | + |
| 39 | +See [DESIGN.md](DESIGN.md) for the expert-panel design review and the architecture. |
| 40 | + |
| 41 | +## Install |
| 42 | + |
| 43 | +| Platform | Download | Contents | |
| 44 | +| --- | --- | --- | |
| 45 | +| macOS | `Codeviewer-<v>-macos-{arm64,x64}.dmg` | Drag `Codeviewer.app` to Applications | |
| 46 | +| Linux | `codeviewer-<v>-linux-{x64,arm64}.tar.gz` | `codeviewer/`, with `install.sh` (adds `~/.local/bin/codeviewer` and a desktop entry) | |
| 47 | +| Headless | `dist/bin/codeviewer-*` | Slim single binaries with no browser, for `--no-open` / SSH | |
| 48 | + |
| 49 | +- **macOS:** launch from Finder (it asks for a folder), drop a folder on the Dock icon, or use |
| 50 | + **Codeviewer → Install 'codeviewer' Command…** and run `codeviewer <dir>` from any terminal. |
| 51 | + The app is ad-hoc signed, not notarized, so on first launch of a *downloaded* DMG, |
| 52 | + right-click → Open (or run `xattr -dr com.apple.quarantine /Applications/Codeviewer.app`). |
| 53 | +- **Linux:** Chromium's sandbox needs unprivileged user namespaces. Some distros (Ubuntu 24.04+) restrict |
| 54 | + them, and `install.sh` prints the one-time command for the setuid `chrome-sandbox` when that's the case. |
| 55 | + The sandbox is never disabled. |
| 56 | + |
| 57 | +## Use |
| 58 | + |
| 59 | +```sh |
| 60 | +codeviewer [dir] # opens the app window (macOS: Codeviewer.app; Linux: bundled Chromium) |
| 61 | +codeviewer . --no-open # headless/SSH: just print the URL |
| 62 | +codeviewer open src/app.ts:42 # from inside a codeviewer terminal: show a file in the viewer |
| 63 | +``` |
| 64 | + |
| 65 | +Options: `--port N`, `--host ADDR` (default `127.0.0.1`), `--shell PATH`, `--browser` (use your default browser). |
| 66 | +Closing the app window quits codeviewer. Settings live in `~/.config/codeviewer/settings.json` |
| 67 | +(on macOS, `~/Library/Application Support/codeviewer`). |
| 68 | + |
| 69 | +| Keys | Action | |
| 70 | +| --- | --- | |
| 71 | +| ⌘P / Ctrl+P | Go to file (`path:line` works) | |
| 72 | +| ⌘⇧P / Ctrl+Shift+P | Command palette | |
| 73 | +| ⌃\` | Toggle / focus terminal · ⌃⇧\` new terminal | |
| 74 | +| ⌘F · ⌃G | Find in file · go to line | |
| 75 | +| ⌘B · ⌘⇧E | Toggle sidebar · focus explorer | |
| 76 | +| ⌘W · ⌘⇧[ ⌘⇧] | Close tab · switch tabs | |
| 77 | +| ⌘= ⌘- ⌘0 | Font size | |
| 78 | +| ⌘⇧G · ⌥F5 / ⌥⇧F5 | Changed files · next / previous change in file | |
| 79 | +| ⌘-click in terminal | Open `path:line` or URL | |
| 80 | +| Left ⌥ | Meta in the terminal (right ⌥ still types special characters) | |
| 81 | + |
| 82 | +## Security |
| 83 | + |
| 84 | +The server binds to localhost and serves a shell. It was hardened through an adversarial review |
| 85 | +(DESIGN.md §11): |
| 86 | + |
| 87 | +- **Access:** |
| 88 | + - A random 256-bit token travels only in the URL *fragment*, then in a request header. |
| 89 | + - There are no cookies (they leak across localhost ports). |
| 90 | + - `Host` is validated (no DNS rebinding), WebSockets require a matching `Origin`, and writes must be JSON. |
| 91 | +- **No secrets in process arguments:** browsers start through a private bootstrap page. |
| 92 | +- **Files:** every path is `realpath`-contained in the root, and files are opened with |
| 93 | + `O_NOFOLLOW|O_NONBLOCK` (regular files only). Nothing writes to the viewed tree. |
| 94 | +- **Git runs untrusted repositories safely:** |
| 95 | + - No filters, textconv, diff drivers, signature checks, fsmonitor or submodule recursion. |
| 96 | + - It never writes the index. |
| 97 | +- **App windows:** |
| 98 | + - A throwaway profile, locked to the window's own server port. |
| 99 | + - External links open in your default browser. |
| 100 | + - Terminal clipboard writes always show a notice. |
| 101 | +- **Builds:** the Linux browser is pinned by SHA-256 in `packaging/browser-pins.json`. |
| 102 | + |
| 103 | +## Verify a download |
| 104 | + |
| 105 | +Releases are built by [GitHub Actions](.github/workflows/release.yml) from a version tag, on a |
| 106 | +clean runner. Each release has `SHA256SUMS` and a Sigstore-signed provenance attestation: |
| 107 | + |
| 108 | +```sh |
| 109 | +shasum -a 256 -c SHA256SUMS --ignore-missing # Linux: sha256sum -c … |
| 110 | +gh attestation verify <file> --repo BackendStack21/codeviewer |
| 111 | +``` |
| 112 | + |
| 113 | +## Develop |
| 114 | + |
| 115 | +```sh |
| 116 | +bun run dev # build the client and serve the current directory |
| 117 | +bun test # emulator, highlighter, path-safety and fuzzy tests |
| 118 | +bun run build # slim binaries (dist/bin) + .dmg / .tar.gz for every target (dist/release) |
| 119 | +bun run build:local # this machine only: dist/bin/codeviewer + its app (on a Mac: the .dmg) |
| 120 | +bun scripts/build.ts --slim # binaries only, no browser download |
| 121 | +bun scripts/build.ts --browser <tag|latest> # re-pin the Linux browser (packaging/browser-pins.json) |
| 122 | +bun run site # landing page → site/dist (reads dist/release for sizes + checksums) |
| 123 | +``` |
| 124 | + |
| 125 | +### Releasing |
| 126 | + |
| 127 | +1. Bump `version` in `package.json` and commit. |
| 128 | +2. `git tag v<version> && git push --tags` |
| 129 | +3. The release workflow runs the tests, builds every package, attests provenance, publishes |
| 130 | + the GitHub release with `SHA256SUMS`, and deploys the landing page to GitHub Pages |
| 131 | + (custom domain `codeviewer.21no.de`, served from `site/dist/CNAME`). |
| 132 | + |
| 133 | +## License |
| 134 | + |
| 135 | +[MIT](LICENSE) © 2026 [21no.de](https://21no.de). Bundled fonts: JetBrains Mono and Inter (SIL OFL 1.1, |
| 136 | +see `vendor/fonts`). The Linux packages bundle ungoogled-chromium (BSD-3-Clause and others). |
0 commit comments