chilla is a lightweight file and Git viewer built with Tauri, Bun, Solid.js, and Rust. It opens directories, files, Git diffs, and GitHub diff URLs from the command line, then previews Markdown, text, images, video, PDF content, and changed files inside a desktop UI.
Product website: chilla-viewer.com
brew tap tacogips/tap
brew install --cask chillaThis installs the signed and notarized macOS application bundle through Homebrew. After installation, launch it from Applications or from the command line:
open -a chilla
chilla .To upgrade later:
brew update
brew upgrade --cask chillaTo uninstall:
brew uninstall --cask chillaCurrent Homebrew caveats:
- the cask installs the macOS Apple Silicon DMG release artifact
- it is currently constrained to Apple Silicon via Homebrew
depends_on arch: :arm64 - Homebrew trust comes from the published signed and notarized DMG
For Apple Silicon Macs, download the signed and notarized DMG directly from the latest GitHub release:
https://github.com/tacogips/chilla/releases/latest
Manual install steps:
- Open the latest release page.
- Download the Apple Silicon DMG asset named like
chilla_<version>_aarch64.dmg. - Open the downloaded
.dmgfile. - Drag
chilla.appintoApplications. - Eject the mounted DMG.
- Launch
chillafromApplications, or runopen -a chillafrom Terminal.
If macOS Gatekeeper asks for confirmation on first launch, open the app from Finder with Control + click, choose Open, then confirm. The published DMG is signed and notarized; that prompt is the normal first-launch confirmation path when opening newly downloaded apps.
Use the direct DMG route when you do not use Homebrew, or when you want to manually download a specific release asset.
The repository also includes a root-level install.sh for installing release tarballs:
curl -fsSL https://raw.githubusercontent.com/tacogips/chilla/main/install.sh | bashSpecific version:
curl -fsSL https://raw.githubusercontent.com/tacogips/chilla/main/install.sh | bash -s -- v0.1.1Uninstall:
curl -fsSL https://raw.githubusercontent.com/tacogips/chilla/main/install.sh | bash -s -- uninstallInstaller behavior:
- resolves the current platform as one of
aarch64-darwin,x86_64-darwin,aarch64-linux, orx86_64-linux - prefers a matching archive in a local
release/directory when present - otherwise downloads the latest GitHub release asset named
chilla-v<version>-<target>.tar.gz - installs the extracted release tree under
~/.local/share/chilla/releases/ - updates
~/.local/bin/chillato point at the installed wrapper - can update the user's shell profile with a managed PATH block unless
--no-modify-pathis used - supports
./install.sh uninstallto remove the installed files and managed PATH block
New installer tarballs are built natively with mise run package-native and contain bin/chilla, not a .app bundle. Older published tarballs may still depend on /nix/store; use the signed DMG/Homebrew cask on macOS. Linux tarballs require compatible GTK/WebKitGTK system libraries.
For most macOS users, prefer the Homebrew Cask or direct DMG install paths above.
From an installed binary, the CLI shape is:
chilla [path]Examples:
chilla
chilla .
chilla docs/
chilla notes.md
chilla movie.mp4During development:
mise run devThe development task accepts paths in the same style:
mise run dev --
mise run dev -- README.mdREADME preview:
Git diff viewer:
Movie preview:
The repository design documents started from a Markdown workbench concept, then evolved toward a lightweight file and Git viewer. The current implementation is closer to a yazi-like desktop viewer/browser than a full Markdown editor:
chillawith no arguments opens the current working directory.chilla <dir>opens that directory in file-view mode.chilla <file>opens the file's parent directory and previews the selected file.- Markdown files get a richer preview flow with:
- rendered HTML
- heading extraction
- a toggleable table of contents
- Mermaid rendering in the preview pane
- local image links, including HEIC / HEIF assets when the platform WebView can decode them
- Non-Markdown files are previewed according to type:
- images: inline image preview, including HEIC / HEIF when the platform WebView can decode the file
- video: embedded video preview
- PDF: embedded iframe preview
- text-like files: syntax-highlighted source preview with prebuilt grammar data and a native regex engine for faster loading; Markdown code fences share the same engine
- source preview layout: full-pane code with a small inset, independent scrolling/zoom, and compact language/size metadata in a footer
- diff highlighting: shared token scanning and span coalescing across all 28 tokenizer kinds; see the complete syntax inventory and measured results
- JSON files: dedicated source highlighting that preserves original formatting and avoids general-purpose grammar parsing
- binary files: metadata/placeholder preview
Markdown source can be edited in the raw pane and saved back to disk. If the file changes on disk while the editor has unsaved changes, chilla keeps the local buffer and surfaces a conflict flow instead of silently overwriting it.
- File browser with List and Tree views and keyboard navigation inspired by terminal file managers, including toolbar icons for filtering and Git-ignored visibility, compact absolute-path display with full-path hover text, a
Tabdirectory-information tree, dedicated symbolic-link icons, and link destinations relative to the current directory with full-path hover text - Tree view roots the left pane at the current directory and expands folders inline. Ordinary browsing starts in List; Git and GitHub diffs start in Tree, with changed files grouped into folders. Use the List/Tree controls to switch views.
- Markdown heading extraction and table of contents
- Direct Markdown view selection with
1for raw source and2for rendered preview - Backend-owned Markdown parsing in Rust
- Mermaid hydration on the frontend after preview render
- Active preview headers show the selected file name across Markdown, text, image, CSV, EPUB, PDF, audio, and video views
- Local Markdown image resolution with HEIC / HEIF image fallback and open-in-default-app affordance when the WebView cannot render an image
- Direct image-file previews for AVIF, APNG, BMP/DIB, GIF, HEIC/HEIF, ICO, JPEG, PNG, SVG, TIFF, and WebP files that the platform WebView can decode
- Touch-style left-button drag panning for direct SVG and raster image previews
- GitHub diff URL viewer for pull requests, commits, and compares with changed-file browsing, GitHub jump action, cached diff loading, text modes for left/right, stack, and full-file review, plus rendered SVG image review
- Local Git diff viewer for uncommitted repository changes and commit/range startup diffs using the same review modes
- Automatic refresh of opened Markdown documents when the file changes on disk, including common atomic-replace save patterns
- Workspace refresh that re-reads the current directory or explicit file set and active local preview, and renews local image, PDF, media, and Markdown-embedded asset URLs even when file timestamps are unchanged
- Direct CSV view selection with
1for raw source and2for formatted table when available - Theme toggle with frontend CSS variables and backend syntax-theme synchronization
- Custom desktop toolbar, with a native macOS title bar for window-manager compatibility
- Startup window size and position fit the monitor's usable area, including smaller displays
- Compact window minimum (320 × 240) allows half, third, and quarter tiling with window managers
In directory Tree view, folders load as you expand them. The name filter applies to loaded files and keeps folders available for further browsing; use Load more for large folders. Diff filtering searches all changed paths and reveals matching files with their parent folders.
List and Tree use icon buttons on the toolbar's left side; filter and Git-ignore
visibility controls sit on the right. Click the filter icon or press f or / to show
and focus the search field. Press Esc in that field to clear and close it.
The directory toolbar also has Search file contents (Shift+S) and Find files (s) icons.
Enter a query and press Enter or Ctrl+M to search recursively below the current
directory and focus the first result. With current results, either key returns
to the first result without repeating the search.
Content search finds literal, case-sensitive text and shows matching lines with
their paths and line numbers. Find files matches part of a filename or relative
path, ignoring case. Use the arrow keys to navigate results; j/k
also move down/up while a result is focused. Focusing a result previews the file.
Click a result or press Enter on it to open the file. Press l on a result, or
click its right-arrow icon, to browse its containing directory with that file
selected and focused.
From results or browsing, press s or Shift+S to focus the corresponding search
field again. Each mode retains its query when reopened; these keys still type
normal text inside input fields. Escape closes search and returns to browsing.
Both searches follow Git-ignore visibility.
Search skips symlinks and Git metadata; content search also skips binary,
non-UTF-8 and oversized files. Skipped entries and incomplete results are reported.
Each directory expansion reads only its immediate children, in pages of up to 200 entries. Switching views reuses a compatible loaded root, and reopening a cached folder does not fetch another page. Unopened descendants remain unloaded.
Default global shortcuts:
?: show helpEsc: close helpq: quit the appCtrl+D: page the active file view down; in Git diff mode, page the selected diff file view rather than the changed-file sidebarCtrl+U: page the active file view up; in Git diff mode, page the selected diff file view rather than the changed-file sidebarjorArrowDown: scroll the active file view down one line when the file tree is hiddenkorArrowUp: scroll the active file view up one line when the file tree is hiddenShift+L: collapse or expand the left pane; the sidebar icon in the main toolbar provides the same action, including in Git diff mode. When folded, a small tab at the left edge of the content area also expands it with the mouse.- Collapsing the left pane moves keyboard focus to the preview and disables hidden browser controls and shortcuts. Expanding restores browser focus and navigation. Starting chilla with file arguments opens the preview with the left pane collapsed; opening a directory keeps it expanded.
g: toggle local Git diff for the opened repositoryy: copy the selected file or directory absolute pathr: refresh the current directory or explicit file set and active local fileShift+T: toggle table of contents for MarkdownShift+P: switch Markdown raw/preview pane, HTML raw/preview pane (preview is a sandboxed, script-disabled rendered view), or Raw/Formatted for CSV, TSV, JSON, JSONL, XML, CSS, and JS/TS previews1: select raw view for Markdown, HTML, or CSV/TSV/JSON/JSONL/XML/CSS/JS/TS2: select Markdown or HTML preview, or formatted CSV/TSV/JSON/JSONL/XML/CSS/JS/TS view when availableShift+F: toggle formatting for JSON, JSON Lines, XML, HTML, CSS, and JS/TS previews (no-op when formatted output is unavailable); for HTML this applies to the Raw view and switches out of PreviewShift+C: toggle syntax highlighting for text, CSV/TSV raw, and Markdown previews+/-: native preview zoom, from 50%-300% for rendered content or 50%-800% for direct SVG/raster images, in 10% steps (not configured by keymap.toml)Ctrl+mouse wheel: native preview zoom under the pointer (not configured by keymap.toml)Shift+D: toggle light/dark theme, including while browsing files
Theme switching uses Shift+D so Shift+S remains dedicated to content search.
Navigation, scrolling, and numeric view shortcuts act on the active document or diff context.
File tree shortcuts:
t: toggle List/Tree view in directory browsing and Git/PR diffsfor/: show and focus filters: find files recursively by filename or relative pathShift+S: search file contents recursively (literal, case-sensitive).: toggle Git-ignored entries in directory browsingTab: show the current directory's absolute path and metadata as a root-to-leaf treeEsc: close directory information, or clear and close the filter and return to the list when the filter is focusedjorArrowDown: move selection downkorArrowUp: move selection up,thena/A: sort by name ascending / descending,thene/E: sort by extension ascending / descending,thenm/M: sort by modified time ascending / descending,thens/S: sort by size ascending / descending,then0, or plain0: reset sort to default (nameascending)horArrowLeft: go to the parent directory in List view; in Tree view, collapse the current folder or select its parentlorArrowRight: open the selection in List view; in Tree view, expand a folder or move to its first childEnter: open a file or toggle a folder in Tree viewCtrl+M: same asEnterin the filter field
Press the comma prefix first, then release it and press the second key.
A popup at the app window's bottom-right lists all available next keys and their actions, remaining open while
you read it. Choose a key or press Esc to close it; moving focus away or
changing browser context also cancels the sequence. Uppercase second keys use
Shift. Recursive search shortcuts apply only to filesystem directory browsing.
Video preview:
-
Audio/video bytes are delivered through an internal Tauri protocol. Chilla does not start a media HTTP server or listen on a network port.
-
Opening a video from the file tree requests playback immediately when the webview allows it.
-
The preview overlay uses a focused play button with an icon-only affordance and an accessible label for the current file.
-
Space: play/pause when supported by the platform/webview
Image preview:
- Markdown image links resolve local image paths relative to the Markdown document, including
.heic,.heif,.heics, and.heifsfiles. - Direct file previews classify AVIF, APNG, BMP/DIB, GIF, HEIC/HEIF, ICO, JPEG (
.jpg,.jpeg,.jpe,.jfif), PNG, SVG, TIFF, and WebP files as images instead of generic binary or text files. - Display support depends on the platform WebView decoder; when an image cannot render, chilla shows a fallback with an option to open the file in the default app.
CSV preview:
1: raw CSV source2: formatted CSV table when parsing and safety limits allow it- Numeric CSV view shortcuts are ignored while typing in editable controls such as the file filter.
Diff viewer:
- Pass a GitHub diff URL to open read-only GitHub diff mode:
https://github.com/<owner>/<repo>/pull/<number>https://github.com/<owner>/<repo>/pull/<number>/fileshttps://github.com/<owner>/<repo>/commit/<sha>https://github.com/<owner>/<repo>/compare/<base>...<head>
- PR, commit and compare
.diff/.patchURLs are accepted as equivalent startup targets. A literal trailing.diff/.patchis treated as a transport suffix; use an encoded dot (%2E) when it belongs to a compare ref name. - GitHub shorthand:
- PR:
chilla github:<owner>/<repo> <number> - Branch comparison:
chilla github:<owner>/<repo> 'main...feature/branch' - Commit:
chilla github:<owner>/<repo> abcdef12 - Explicit commit (including all-numeric SHAs):
chilla github:<owner>/<repo> commit:12345678 - Bare decimal numbers always mean PR numbers; commit SHAs accept 4–40 hexadecimal characters.
- PR:
- Changed files open in Tree view by default; expand directories to navigate the diff like a file tree.
- Use the header reload button or
r(configurabledocument.reload) to fetch the active diff again. GitHub reload bypasses snapshot cache reuse, preserves surviving selection/tree context, and clears stale full-file previews. - Add
--no-github-diff-cachebefore the URL or shorthand to bypass the temp-directory cache. The older--no-pr-diff-cacheflag remains available as a compatibility alias. - Open a directory inside a Git repository and use
Git diffto switch to uncommitted-change diff mode. - Start commit/range diff mode with:
chilla <git-dir> <commit>chilla <git-dir> <base>..<head>chilla <git-dir> <base>...<head>
1: left/right diff2: stack diff3: full-file view4: rendered image view for SVG filesTab: cycle diff modes in the same order, including image view for SVG filesCtrl+D: page the selected diff file view downCtrl+U: page the selected diff file view upo: open the pull request, commit, or compare source in GitHub when reviewing a GitHub diff- Full-file view shows the latest file content, highlights added and modified lines, and marks deleted locations with a thin red line without rendering deleted content.
- SVG image view renders the latest complete SVG in an isolated image without replacing the existing XML/text review modes.
Workspace errors and keymap warnings appear as top-right overlays without moving the panes. Close a message with its dismiss button, or let it disappear after 8 seconds; hovering or focusing the message pauses the timer. Conflict-resolution prompts remain visible until addressed.
Create ~/.config/chilla/keymap.toml and restart chilla to customize browser
and workspace shortcuts. This location also applies on macOS. If
XDG_CONFIG_HOME is an absolute path, chilla instead reads
$XDG_CONFIG_HOME/chilla/keymap.toml. Missing configuration keeps the defaults;
chilla does not create or overwrite the file automatically.
The format follows Yazi's keymap model, using chilla's own built-in action names:
[[mgr.prepend_keymap]]
on = ["g", "f"]
run = "search.name"
desc = "Find filenames recursively"
[[mgr.prepend_keymap]]
on = ["g", "s"]
run = "search.content"
desc = "Search file contents recursively"
[[workspace.prepend_keymap]]
on = ["<C-b>", "t"]
run = "theme.toggle"
desc = "Toggle theme"Pressing a prefix such as g shows the remaining configured keys and
descriptions in the bottom-right popup. See examples/keymap.toml
for a copyable example. on accepts one key or an array of up to eight keys;
run accepts one built-in action or an ordered array of actions. desc is
optional. Normal typing and native editor/media controls are not remapped.
Contexts are [mgr] for directory/file-set and diff browsers, and [workspace]
for app actions. Each supports:
prepend_keymap: higher-priority overrides.keymap: replace that context's defaults;keymap = []disables them.append_keymap: lower-priority additions.
First matching entries win, including prefix conflicts: a prepended sequence
can take over a default single key. Use run = "noop" in a prepended entry to
disable a particular binding. Browser bindings take precedence over workspace
bindings in browser context. Browser defaults differ between filesystem and
diff modes; the same custom [mgr] entries apply to both.
Choose a workspace prefix that does not conflict with browser bindings when
you want it available there too; the example uses Ctrl+B followed by t.
Keys are case-sensitive: s and S differ. Named keys include <Enter>,
<Esc>, <Space>, <Tab>, arrows, <Home>, <End>, <PageUp>, <PageDown>,
and function keys. Modifiers use <C-s> (Ctrl), <D-s> (Command/Super),
<A-s> (Alt/Option), <S-Tab> (Shift), or combinations such as <C-S-s>.
Escape cancels a pending sequence; the popup has no timeout.
Escape therefore cannot be used as a continuation key. While typing in editable
controls, only Ctrl/Command bindings for document.save, files.open, or noop
are considered; ordinary text and native editing keys remain untouched.
Browser actions: cursor.up, cursor.down, parent, enter, open, filter,
search.name, search.content, view.toggle, ignored.toggle,
directory.info, sort.reset, and sort.FIELD.DIRECTION where FIELD is
name, extension, mtime, or size and DIRECTION is asc or desc.
Diff actions: diff.previous, diff.next, diff.view.cycle, diff.view.split,
diff.view.stack, diff.view.full, diff.view.image, diff.open,
scroll.up, and scroll.down. Actions unavailable in the current browser
mode have no effect.
Workspace actions: help, quit, files.open, document.save,
document.reload, path.copy, sidebar.toggle, git.toggle, toc.toggle,
presentation.toggle, presentation.raw, presentation.rendered,
format.toggle, syntax.toggle, theme.toggle, scroll.up, scroll.down,
document.previous, and document.next. noop is valid in either context.
presentation.toggle/presentation.raw/presentation.rendered also drive
Raw/Preview for Markdown and HTML (HTML Preview is a sandboxed, script-disabled
rendered view) and Raw/Formatted for CSV, TSV, JSON, JSON Lines, XML, CSS, and
JS/TS previews. format.toggle flips formatted/raw specifically for JSON,
JSON Lines, XML, HTML, CSS, and JS/TS previews (no-op elsewhere or when
formatted output is unavailable); for HTML it applies to the Raw view and
switches out of Preview. syntax.toggle turns syntax highlighting on/off for
text, CSV/TSV raw, and Markdown previews.
Invalid TOML, unknown fields/actions, invalid key notation, or files larger
than 64 KiB produce a visible warning and retain built-in defaults atomically.
run never executes shell commands or scripts. Reloading configuration requires
restarting chilla.
The app is split across a typed Tauri boundary:
src-tauri/- CLI parsing and startup target resolution
- directory listing and file classification
- Markdown rendering and heading extraction
- syntax highlighting
- filesystem watching for Markdown refresh
src/- workspace shell and desktop UI
- file browser interactions
- preview panes for Markdown, image, text, PDF, and video
- theme management
- Mermaid enhancement after HTML injection
Key runtime contracts:
StartupContext: initial workspace mode, directory, and selected fileDirectorySnapshot: current directory listingDocumentSnapshot: Markdown source, rendered HTML, headings, and revision metadataFilePreview: typed preview union for Markdown, image, video, PDF, text, and binary files
.
├── src/ # Solid.js frontend
├── src-tauri/ # Rust + Tauri backend
├── design-docs/ # design notes and specs
├── impl-plans/ # implementation plans
├── mise.toml # tool versions and development/CI tasks
└── package.json # locked Bun scripts/dependencies
- mise 2026.8.3 or newer
- macOS: Xcode Command Line Tools (full Xcode for signing/notarization)
- Linux: native Tauri libraries, installed separately from mise
The repository follows ign-template's tauri-v1: mise supplies Bun, Node and Rust (including rustfmt/clippy); the OS supplies native SDKs/libraries. Nix and direnv are not required. Frontend tools such as Biome come from the Bun lockfile.
On Ubuntu 24.04, install the Tauri prerequisites:
sudo apt-get update
sudo apt-get install -y build-essential pkg-config curl wget file libssl-dev \
libwebkit2gtk-4.1-dev libxdo-dev libayatana-appindicator3-dev librsvg2-dev
# Additional packages for desktop E2E:
sudo apt-get install -y webkit2gtk-driver xvfb xauth dbus-x11 fonts-dejavu-coremise install
mise run installmise run dev
mise run build
mise run package-native
mise run test
mise run test-tauri-e2e-linux
mise run check
mise run clippy
mise run fmt
mise run verifyEquivalent package-manager commands:
Use mise exec -- <command> when your shell does not have mise activation enabled.
bun run dev
bun run build
bun run typecheck
bun run test
bun run test:tauri:e2e:linux
CARGO_TERM_QUIET=true cargo test --manifest-path src-tauri/Cargo.tomlmise run build compiles the Tauri backend with Cargo --release.
mise run tauri-build creates the packaged desktop binary with Tauri's release build.
mise run package-native -- [output-directory] produces a native installer tarball
and checksum (default release/), refusing existing artifacts and Nix-linked
binaries. It does not publish anything. mise run verify includes the DOM suite.
The repository also includes a Linux-only desktop smoke test that runs the real Tauri app through tauri-driver:
mise run test-tauri-e2e-linuxNotes:
- The task installs pinned
tauri-driverthrough mise.WebKitWebDrivermust be onPATHfrom the OSwebkit2gtk-driverpackage, not mise. - If
DISPLAYis not set, the runner falls back toXvfbwhen available. - The smoke test opens the real workspace, filters to
README.md, and verifies the rendered Markdown preview.
The repository now also contains a separate Tauri macOS bundle flow for direct .app and .dmg builds:
mise run bundle-macos-dmgThat path uses src-tauri/tauri.macos.release.conf.json and is intended for Apple Developer ID signing/notarization on a local macOS release machine. Apple certificate material should stay in the local keychain and password manager, not in GitHub Actions secrets.
The local release task expects these environment variables to be exported by the local password-manager workflow:
APPLE_SIGNING_IDENTITYAPPLE_IDAPPLE_PASSWORD(an Apple app-specific password)APPLE_TEAM_ID
Publish signed/notarized macOS release assets from the local machine with:
mise run release-macos-dmg-local -- v0.3.0The release task mounts the final DMG read-only and verifies the embedded app's Developer ID signature, stapled notarization ticket, and Gatekeeper acceptance before uploading either release asset.
Repository-local GitHub Actions build unsigned .app/.dmg artifacts only for validation. They do not sign, notarize, or publish trusted release assets.
The following commands were confirmed passing while preparing this README:
bun run typecheckbun run testCARGO_TERM_QUIET=true cargo test --manifest-path src-tauri/Cargo.toml
The design docs under design-docs/specs/ still reflect two overlapping phases of the product:
- the original Markdown workbench design
- the later file-view mode extension
The implementation has already adopted file-view startup and multi-type preview behavior, so the source code is the more accurate reference for current behavior. The active implementation plans should be read as planning artifacts, not as a precise status dashboard.



