Skip to content

Latest commit

 

History

48 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tigriden — A Fast, Tiny End-to-End Research Workbench

Version License Platform

From the coding agent that runs your experiments to the scientific paper you submit — one window for the whole thing. An agentic coding workbench (per-folder terminals, a live file panel, change tracking with one-click rollback, a lightweight editor) with a document viewer bolted to the same window: your .tex shown as the page it compiles to, your PDFs as real pages, and the figures and data your code just produced next to both.

Run claude, codex, gemini — any terminal agent — each in its own folder, side by side, and watch what they do: the file panel updates as they write, the Changes panel lists every file they touched and reverts any of it, and the viewer renders whatever they produced — code, a chart, a CSV, a manuscript.

Written in pure Rust. No Electron, no TeX installation, and no webview under the UI — the panes rasterize themselves. The only web engine is the system WebKit view the HTML Rendered mode parks over the viewer, and nothing else uses it. ~10 MB binary, ~40 MB RAM, and a paper opens the moment you click it.

Tigriden with paperIEE.tex typeset in the viewer — a two-column journal page with figures and captions — the manuscript folder in the file panel on the left, and Claude Code running in the terminal below

Above: the whole loop in one window — the manuscript folder in the panel on the left, paperIEE.tex set on the two-column page its \documentclass produces (page 12, figures, captions and justified columns, straight from the source with no LaTeX run), and the agent that wrote it running underneath, one preset click away.

The research loop, end to end

One folder, one window, the whole cycle — the agent never leaves the terminal, and you never leave the app to look at what came out:

Stage What you do What Tigriden gives you
1. Code claude / codex / gemini in the project folder writes and runs the experiment A real terminal per folder, extra tabs for pytest, git or a second agent, and a file panel that updates as files appear
2. Check Read what the run produced before trusting it results.csv as an aligned table, loss.png or a vector PDF plot as an image, the agent's Markdown notes typeset on a page
3. Keep or undo Decide what survives the run The Changes panel lists every file touched, diffs each one, and reverts a file — or the whole run — with git or with invisible snapshots when there is no repo
4. Write Ask the agent to draft or revise the manuscript in the same folder paper.tex opens typeset on the page your \documentclass produces: two-column IEEE, single-column arXiv, equations, tables, figures — no compile
5. Iterate Reread, re-prompt, discard what missed The typeset page re-renders the instant the agent saves; rollback is one right-click
6. Submit Build the real artifact latexmk in a second terminal tab, then open the produced paper.pdf in the same viewer — pages, text selection, side-by-side with the source

Nothing in steps 2–5 costs a LaTeX run or a second application.

Why

Agentic coding means running several agents in several folders and checking in on them. A full IDE is overkill for that; a bare terminal multiplexer gives you no file browser, no diff, no editor. Tigriden is the minimal middle: one session per folder — agent, files, editor and change tracking together.

Writing with an agent has the same shape, plus a document. Today that means three apps — a terminal for the agent, Overleaf or a PDF viewer to see what the text actually looks like, and Finder to move figures around — and every look at the page costs a full LaTeX compile. Tigriden puts the typeset page in the same window: the paper size, margins and column grid your \documentclass asks for, rendered by a built-in typesetter, so it appears instantly and works on a machine with no TeX distribution. Compile when you are ready to submit, not to read a paragraph.

For agentic coding

  • One-click agents — preset buttons type the agent command into the terminal for you (claude, codex, gemini, opencode, or your own, fully configurable).
  • A real terminal — VTE-compliant (alacritty_terminal + a real PTY), so vim, top and the Claude Code TUI just work: bracketed paste, truecolor, mouse selection, right-click Copy / Paste / Select All, and a wheel that scrolls inside full-screen apps as well as through history (Shift+PgUp/PgDn/Home/End/↑/↓ page the scrollback). Drop a file from Finder on the terminal and its shell-quoted path is typed in, ready to attach to a prompt. Marks stay on the letters they belong to (0.1.9) — a cell's zero-width vowels, tones and accents are drawn as the one stack they are, so สวัสดีครับ keeps its Thai vowels and tone marks instead of thinning to bare consonants. Ctrl and ⌘ work on a non-Latin layout (0.2.0) — on a Thai keyboard Ctrl+O typed Ctrl+ญ, which matches no shortcut and encodes no control byte, so ^O never reached nano and the app's own ⌘ keys went dead. A combo is now resolved through the key's position on a Latin layout, the way macOS resolves its own shortcuts; plain typing, Dvorak, AZERTY, arrows and F-keys are untouched.
  • Multiple terminals per folder+ spawns extra shells in the same workspace, so an agent can run while you use a second tab for git, tests, or another agent.
  • Every file the agent touched, and an undo (0.1.1)File ▸ Show Changes Panel lists modified/added/deleted files within ~1 s of a write, with a syntax-highlighted diff per file. Discard Changes… reverts one file, reverts the whole run, both behind a confirmation. Git folders compare against the last commit; folders without git get invisible shadow snapshots, so a scratch project or a manuscript folder is just as safe. Snapshots skip bulk data (0.2.0) — a directory over 200 MB or a single file over 5 MB stays out, both sizes settable in Settings, so a training set or a PDF corpus does not end up copied into the snapshot store.
  • Several projects at once — one session per folder with its own shell, tree and open file; switching is instant. File ▸ New Window runs independent windows in parallel, and named [[teams]] give each window its own agent buttons. Windows no longer stall each other (0.2.0) — they share one event loop, so closing a terminal, opening a PDF, scanning fonts or watching a folder with git now happens off it.
  • A file panel that manages files (0.1.6) — gitignore-aware and live as the agent works. Drag files in from Finder, Cut/Copy/Paste through the system pasteboard in both directions, Delete to the Trash behind a confirmation, rename/duplicate/reveal from the keyboard or the context menu.
  • Built-in editor — syntax highlighting for 40+ languages (cosmic-text + syntect), Cmd+S to save. When the agent rewrites the file you have open, it reloads automatically (or asks, if you have unsaved edits).
  • Settings, themes, persistence (0.1.2)File ▸ Settings… (⌘,): six themes, accent color, a font and a text size for the editor and for the terminal, each picked on its own (0.1.8), scrollback, the snapshot size limits (0.2.0), applied live to every window. The pickers list the monospaced families your machine really has, and a configured family it does not have is swapped for one it does — never for the platform's proportional interface font. A native menu bar (Add Folder ⌘O, New Terminal ⌘T, Open Recent, New Window ▸ team, Save ⌘S, Close ⌘W) routes to whichever pane has focus, and folders, layout and the recent list come back on relaunch.
  • Small on purpose — no Electron, no webview under the UI, no C regex libraries; a Slint shell with both panes rasterized straight to pixel buffers, which is where the ~10 MB binary and the instant startup come from.

For writing and revising

  • LaTeX on the page, not in a text dump (0.1.7) — the viewer reads \documentclass (and geometry) and sets the file on that page: letter or A4, the class's margins, two columns for the journal classes (IEEEtran, ACM/SIG, RevTeX, [twocolumn]). It is paginated — numbered sheets, paragraphs continuing into the next column, headings kept with their text, figure*/table* spanning both columns at a page top, and a float that will not fit moving to the top of the next column while the text flows past it.
  • The parts a paper is made of\maketitle front matter (spanning title block, \thanks as the affiliation footnote, raised \textsuperscript markers, Abstract and Index Terms), the class's own section numbering (1.1 or I, A, 1), \cite printed as the number its \bibitem will carry, captions labelled "Figure 1:" or "Fig. 1." as the class does, cross-references resolved to numbers even when they point forward.
  • Real math, with TeX's metrics (0.1.8) — display equations get box layout: stacked fractions, radicals with an overline, \sum/\int carrying their limits, matrices and cases, every row of an align numbered on its own. \left(…\right) fences are sized to the ink they enclose, by TeX's delimiter factor, so nesting them keeps one paren size instead of growing a size a level; scripts, roots and accents measure against ink the same way, and atom spacing sets operators, relations and punctuation apart as TeX does. Inline math is set inline, with true raised and lowered scripts (V_S, x², R^{d_model}) instead of spelled-out _S.
  • Figures and tables of real manuscripts\graphicspath searched, vector PDF plots rasterized, pictures scaled by the minipage they sit in; tabular/tabularx/longtable set booktabs style. Preamble noise, package options and unknown commands never leak onto the page.
  • PDFs as actual pages — the compiled paper, a reference you are citing, a datasheet. Select and copy text straight off the page, with two-column papers copying one column at a time instead of zig-zagging across the gutter.
  • Markdown on the same white page, with the same typeset math — for notes, READMEs and agent-written summaries.
  • HTML two ways (0.2.0)Rendered is a real WebKit view over the pane (macOS; elsewhere the file opens in Reader), so a site looks and behaves as it does in Safari: stylesheets apply, scripts run, the page you are building is the page you see. Reader sets the same file as a typeset document on the white sheet — headings, lists, tables, <pre> blocks and local <img> figures, entities decoded, script and style left out — which is what an agent's HTML report wants. The header chip cycles Rendered / Reader / Source.
  • Everything else in the folder — images (png/jpg/gif/webp/bmp/tiff) and CSV/TSV as an aligned table, so a plot or a results file the agent just wrote is one click away.
  • Fast, because nothing compiles — no pdflatex run to see a change; PDF pages rasterize and images decode on background threads with the next page prefetched, so scrolling and zooming never stall. Cmd+= / Cmd+- / Cmd+0 zoom, and the LaTeX page re-typesets at the new size.
Everything the LaTeX view understands (the long list)

Paper and margins from \documentclass options and geometry; one or two columns; pagination with page numbers, column breaks inside paragraphs, keep-with-next headings, [H]-pinned versus floating figures and tables. \maketitle title blocks, \thanks footnotes, \textsuperscript, abstract and IEEEkeywords labels (bold run-in for journals, centered over an inset block for articles). Section numbering per class, \setcounter{secnumdepth}, \parindent/\parskip paragraph shape, center/flushleft/\centering, \LARGE down to \scriptsize — each scoped to its group. equation/align/gather, \[…\], $$…$$ and starred forms, each align row numbered on its own; a display too wide for its column is set a size smaller. Variables italic, operators and min/tanh/log upright, \mathbb/\mathcal letters, fences and radicals sized to the ink they enclose. \ref/\eqref/\autoref/\Cref resolved by a two-pass parse; \cite numbered from \bibitem; \captionsetup{labelformat=empty} respected. \includegraphics with \graphicspath, width=…\linewidth and minipage scaling, including vector PDF figures. tabular, tabularx, longtable and array in booktabs style; itemize/enumerate/description; verbatim/lstlisting/minted on a code panel; quote and article abstracts inset from both margins; \href/\url as links. Unknown commands, package options ([leftmargin=…], [htbp], natbib's [][]) and the whole preamble stay off the page.

Quick install (macOS)

No Rust needed — grab the prebuilt app from the latest release:

  1. Download Tigriden-0.2.0-macos-universal.app.zip (one download for both Apple Silicon and Intel).

  2. Unzip and drag Tigriden.app into /Applications.

  3. First launch only: the app isn't notarized, so right-click → Open → Open, or run:

    xattr -d com.apple.quarantine /Applications/Tigriden.app

Prefer a bare binary? The release also ships tigriden-0.2.0-macos-arm64.tar.gz (Apple Silicon) and tigriden-0.2.0-macos-x86_64.tar.gz (Intel) — untar and run ./tigriden.

Windows builds on the same release: unzip tigriden-0.2.0-windows-x86_64.zip and run tigriden.exe. It is built by CI on every tag rather than tested by hand — macOS is still the primary target — but the last three releases fixed what made it look broken on sight. 0.1.8: a config naming a font Windows does not have (Menlo, say) rendered the terminal in Segoe UI, the platform's proportional interface font. 0.1.9's mark stacking is platform-neutral code, and Windows falls back to Leelawadee UI for Thai — an OpenType face with real mark attachment, so tone marks sit slightly better there than under the Ayuthaya macOS reaches for. 0.2.0's Latin-layout fallback for Ctrl and ⌘ combos reads the physical key through winit, so it applies there as well. One thing in 0.2.0 is macOS only: Rendered HTML needs WKWebView, so on Windows an HTML file opens in Reader. Terminal teardown still runs off the event loop there, with Child::kill in place of the process-group signals Unix gets.

Build from source (stable Rust required)
git clone https://github.com/Sompote/Tigriden.git
cd Tigriden
cargo build --release
./target/release/tigriden        # or ./bundle/make-app.sh for dist/Tigriden.app

macOS is the primary target; Linux/Windows are untested but the stack is cross-platform.

Usage

Supervise a coding agent

  1. Click + Add folder and pick a project directory — a login shell opens there.
  2. Click a preset button (e.g. claude) to launch the agent, or type any command.
  3. Watch the file panel update as the agent works; click any file to read or edit it.
  4. Click + in the terminal tab strip for more shells in the same folder (each tab is its own shell; ✕ on hover closes one).
  5. Add more folders to run more agents in parallel; switch by clicking a session in the sidebar. The ✕ on a session header removes the folder (its shells stop; the folder stays in Recent).
  6. Click (bottom of the sidebar) to reopen any previously added folder without the file dialog.

Revise a paper with an agent

  1. + Add folder → pick the manuscript folder (the one with paper.tex and figures/). A login shell opens there.
  2. File ▸ Show Changes Panel, so every file the agent touches is listed and revertible before it types a word.
  3. Click claude (or type any agent command) and ask for what you want: "tighten Section 3 to 400 words", "make the notation consistent with Table 2", "add a limitations paragraph".
  4. Click paper.tex in the panel — it opens typeset, on the page your class produces, so you can read the revision as a reader will see it. No compile, no latexmk watch.
  5. Not convinced? Right-click the file in Changes ▸ Discard Changes… to put it back, or to revert the whole run, then ask again.
  6. Ready to submit? Run latexmk (or your build) in a second terminal tab with +, and open the resulting paper.pdf in the same viewer to check the real thing.

Everything else works the same way: drop new figures in from Finder, click a .csv the agent generated to read it as a table, open a reference PDF and copy a quotation straight off the page.

Track & roll back what the agent changes

  1. File ▸ Show Changes Panel — a Changes (N) section appears under each folder in the sidebar (off by default; it always starts off on launch).
  2. Tracking mode is chosen automatically per folder:
    • Git folders compare against the last commit — commit in the terminal to accept work and reset the list to zero.
    • Folders without git get an invisible shadow snapshot taken the moment you enable the panel (stored under ~/Library/Application Support/tigriden/snapshots/; no .git appears in your project). Re-enabling the panel re-snapshots "now".
  3. As the agent works, changed files appear within ~1 s as M (modified) / A (added) / D (deleted) rows — the count is files, not edits.
  4. Click a row to see the accumulated diff against the baseline; the File chip jumps to the editable file.
  5. Don't like a change? Right-click the row ▸ Discard Changes… restores that file to the baseline (new files are deleted, deleted files come back). The button on the Changes header — or right-click ▸ Discard All Changes… — reverts the whole run. Both ask for confirmation first.

Detection is watcher-driven (no polling): bursts of writes are coalesced for 250 ms, git status runs on a background thread, and nothing at all runs while the panel is off or the agent is idle.

Keys

Context Keys
Terminal everything a terminal expects: Ctrl+C/Z/D/R…, arrows, F1–F12, TUIs; drag to select (double-click = word), Cmd+C copies, Cmd+V pastes (bracketed), right-click for Copy / Paste / Select All; wheel scrolls history — and scrolls inside full-screen apps (Claude Code, vim, less) too — Shift+PgUp/PgDn pages it, Shift+Home/End jump to the ends, Shift+↑/↓ go line by line
File panel ↑/↓ walk the rows, ←/→ collapse / expand (or step to the parent), Return opens, F2 or ⌘R renames, ⌘D duplicates, ⌘X / ⌘C / ⌘V cut, copy and paste files through the system pasteboard, Delete or ⌘⌫ moves to the Trash (after a confirmation); right-click for the full menu
Editor typing, arrows / Home / End / PgUp / PgDn (+Shift selects, +Alt jumps words), Cmd+A / C / X / V, Cmd+S saves, right-click for Copy / Paste / Select All
Viewer wheel scrolls, right-edge scrollbar drags or click-jumps, PgUp/PgDn page, Home/End jump to the ends, ↑/↓ step; drag to select text — including on PDF pages (double-click = word), Cmd+A selects all, Cmd+C / Cmd+X copy, Esc clears, right-click for the menu; Cmd+C with nothing selected copies a whole PDF; on images, PDFs and the LaTeX page: Cmd+= / Cmd+- zoom, Cmd+0 resets, Ctrl/Cmd+wheel zooms, and a zoomed view pans horizontally

Configuration

Most of it is editable in File ▸ Settings… (⌘,), where the editor and the terminal take their own font and their own size; the file is ~/Library/Application Support/tigriden/config.toml, created on first run:

# Theme: classic-|minimal-|vivid- × -dark|-light ("dark"/"light" still work).
theme = "classic-dark"
accent = ""                 # "" = theme accent, or "#rrggbb"
font_family = "Menlo"       # editor, viewer + code blocks
term_font_family = "Menlo"  # terminal, on its own ("" = follow font_family)
font_size = 13.0            # editor + viewer (8-28)
term_font_size = 13.0       # terminal, sized on its own (8-28)
ui_font_size = 13.0         # sidebar, tabs, dialogs (10-18)
scrollback = 10000
show_changes = false        # start new windows with the Changes panel on

[[presets]]
label = "claude"
command = "claude"
send_enter = true

[[presets]]
label = "codex"
command = "codex"

[[presets]]
label = "gemini"
command = "gemini"

[[presets]]
label = "opencode"
command = "opencode"

# Optional: named preset groups for File ▸ New Window ▸ <team>.
[[teams]]
name = "reviewers"
[[teams.presets]]
label = "claude-review"
command = "claude /review"
send_enter = true

Both families are checked against the font database at startup: one this machine does not have is replaced by the first installed fallback for the platform (Menlo on macOS, Cascadia Mono on Windows, DejaVu Sans Mono elsewhere) and written back, so what the file says and what you see agree. A config from before 0.1.8 has no term_font_family and keeps one family for both until you pick a terminal font.

Presets and teams are file-only — the Settings dialog links to config.toml for those. Saving from Settings rewrites the whole file, so comments you add by hand are not preserved.

When a release adds an agent button, a config still holding an older build's stock list picks it up once, recorded as presets_version. Add or remove a single preset and the list becomes yours: later releases leave it alone.

Runtime state (restored folders, split position) lives next to it in state.toml; shadow snapshots for the Changes panel live in snapshots/.

Snapshot size limits (0.2.0)

A folder without its own git repository is tracked by a hidden snapshot repo under ~/Library/Application Support/tigriden/snapshots/. Two limits keep that store from growing past the projects it tracks, both in Settings ▸ Changes panel and in config.toml:

snapshot_file_mb = 5     # a file this big or bigger is not snapshotted
snapshot_dir_mb  = 200   # a directory subtree this big is excluded whole

0 on either means no limit. The directory rule is the one that matters: the mass in a research folder is rarely one huge file, it is thousands of medium ones. A folder of 4602 harvested PDFs averaging 1.7 MB snapshots to 100 MB at these values, and a 7638-image training set to 39 MB, while a 415 MB book folder keeps 128 MB and every source file in it. Excluded files are not listed in the Changes panel and cannot be rolled back from it.

Limits apply when a baseline is taken. Turn the Changes panel off and on again to re-take one for the folders already open.

Architecture

Slint provides only the chrome (sidebar, layout, splitter). The two hard parts are custom-rendered pixel panes on the CPU:

Pane Engine Rendering
Terminal headless alacritty_terminal grid fed by portable-pty glyphs rasterized per cell via cosmic-text's swash cache
Editor cosmic-text SyntaxEditor (syntect highlighting) draws itself into the same pixel-buffer canvas

The file viewer paints into the same kind of pixel buffer: Markdown/CSV/LaTeX layout via cosmic-text, PDF pages rasterized by hayro, and images decoded/resampled by the image crate — both on per-document worker threads, so the UI thread never waits on them. LaTeX runs through a built-in parser in src/tex.rs, which turns math into a tree that src/mathlayout.rs measures and positions as boxes — no TeX install needed. The page itself is a second pass: src/tex.rs reads the class options into a page geometry (paper, margins, columns), and the viewer packs the blocks into that grid column by column and sheet by sheet, splitting a paragraph at a line boundary when it runs off the bottom and holding full-width floats over to the top of the next page. Because the type size is derived from the page width, resizing the pane re-typesets the document rather than reflowing it, while a zoom step magnifies the page already typeset: every derived length comes off the page scale unrounded, so the proportions, line breaks and pagination hold at any zoom. Markdown shares both: it renders on the same white sheet and sends its $…$ bodies through that same parser and box layout, so a formula looks the same whichever file it came from. Only the pages in (or next to) the viewport are kept in memory, requests coalesce so a zoom gesture renders just the final size, and a nearest-neighbor preview covers the gap until each full-quality bitmap arrives.

Because the panes paint themselves, a theme is one definition in src/theme.rs feeding three consumers: the Slint Theme global (chrome), the ANSI 0-15 palette (terminal, shared with the PTY threads for OSC color queries), and a syntect theme name (editor).

Only the PTY reader threads and the viewer's rasterizer/decoder workers run in the background; rendering and editing happen on the UI thread with coalesced, throttled repaints.

src/mac.rs holds the AppKit calls neither Slint nor winit exposes: the pasteboard's file list (so the panel's ⌘C/⌘V interoperate with Finder) and the pointer location during an external drag, since winit's drop events carry a path but no coordinates.

vendor/cosmic-text/ is a verbatim copy of cosmic-text 0.19 with one change: its syntect dependency uses the pure-Rust fancy-regex engine instead of the oniguruma C library (smaller binary, no C build dependency).

Debug builds

cargo build --features framedump, then run with TIGRIDEN_DUMP=/tmp/frames to dump both panes as PNGs. TIGRIDEN_TEST_INPUT='claude\r', TIGRIDEN_TEST_OPEN=path, TIGRIDEN_TEST_SETTINGS='style=vivid,font-size-step=2', TIGRIDEN_TEST_CHANGES=1 (reports the Changes panel's tracking mode and contents around a write), TIGRIDEN_TEST_CTXMENU=1 (runs the right-click menu's Copy and Select All against the terminal and reports what reached the clipboard), TIGRIDEN_TEST_SCROLLBACK=up|down (wheels the terminal and reports the mode, history size and resulting screen — the way to tell scrollback from alternate-screen scrolling) and TIGRIDEN_TEST_WHEEL_UI=1 (dispatches a real scroll event through Slint's hit-testing, to prove wheel input still reaches the terminal) script the first session for headless testing. For the typeset LaTeX page there is a faster loop that needs no window: TEX_DUMP=paper.tex TEX_DUMP_OUT=/tmp/tex TEX_DUMP_PAGES=3 TEX_DUMP_FROM=0 cargo test tex_sheet_dump -- --nocapture writes one PNG per page.

Changelog

  • 0.2.0HTML in the viewer, a window that stays responsive, and a snapshot store that stays small.

    A snapshot no longer copies the data it sits next to. The store had reached 17 GB across 40 folders. Two folders held 13 of it. Nothing capped, packed or deleted anything, ever.

    A per-file cap does not fix that on its own. The mass is never in the giants. One folder carried 4602 harvested PDFs averaging 1.7 MB, a literature corpus. Another held 7638 JPGs averaging 0.65 MB, a training set. Both sit under any per-file cap worth setting. A 5 MB cap caught 3.0 GB of the first folder and 1.6 GB of the second, and left the rest.

    What marks those files is the directory they sit in. A manuscript folder does not hold 4600 PDFs. A subtree of 200 MB or more is now excluded whole, at the shallowest point over the line, and a single file of 5 MB or more is excluded wherever it sits. The root is never excluded, so a big folder still tracks its own small files. Measured against the real folders: 8.1 GB becomes 100 MB, 6.5 GB becomes 39 MB, and a 415 MB book folder keeps 128 MB with every source file in it.

    Both sizes are settings. Settings ▸ Changes panel takes folders at 100 MB, 200 MB, 500 MB, 2 GB or no limit, and files at 1, 5, 20, 100 MB or no limit. config.toml calls them snapshot_file_mb and snapshot_dir_mb. The git workers run on their own threads, so the values cross as two atomics rather than through the thread-local config.

    An exclude only holds back a file git is not already tracking. A file that grew past the cap since the last baseline is dropped from the index too, which the next commit records as a deletion. The file itself is untouched. Baselines also run git gc now: one repo held 5499 loose objects and 6.91 GiB with nothing in a pack, because git's default threshold is 6700 and no baseline ever asked. And a folder whose every file is excluded commits an empty baseline. Without a commit there was no baseline, so every refresh walked the whole tree again trying to take one.

    HTML opens as a document, two ways. Reader sets an .html file on the same white sheet Markdown and LaTeX use. It gives you headings, justified paragraphs, blockquotes, lists, tables as real grids, <pre> kept as a code block and a local <img> as a figure. <sup> and <sub> reuse the math painter's script tags. HTML 4 entities are decoded, and the bodies of <script> and <style> are dropped. src/html.rs is a small tokenizer, not the HTML5 tree algorithm. It does close what real pages leave open: <p> at the next block, <li> at the next item, <td> and <tr> at the next cell and row. That suits an agent's report. It does not suit a site, whose content the page often builds at load time. A project's index.html arrives as empty containers that data.js fills in. So Rendered is a real WKWebView parked over the pane. It loads the file with loadFileURL:allowingReadAccess, so the page's own stylesheets, scripts and images resolve beside it. This is a browser view. A page can reach the network exactly as it would in Safari. The header chip cycles Rendered / Reader / Source. The view stands down for another tab, the editor or a dialog.

    ⌘ and Ctrl combos resolve through a Latin layout. On a Thai layout, Ctrl+O typed Ctrl+ญ. No shortcut matched that and no control byte encoded it. So ^O never reached nano, and every ⌘ key in the app went dead. The physical key is now read from the winit event, which still knows its position. Its US-layout character is substituted only when Ctrl or ⌘ is held and the typed character is a single non-ASCII one. Plain Thai typing, Dvorak and AZERTY letters, arrows and F-keys pass through untouched.

    Six waits came off the shared event loop. Every window runs on one Slint event loop, so anything that blocks it freezes them all. Two windows made that plain: work started in one stopped the other. Terminal teardown called Child::kill, which signals the shell alone and sleeps up to 250 ms before escalating, then Child::wait. A shell wedged on its way out held wait4 for over two minutes in testing. Teardown now signals the shell's process group and the tty's foreground group, then hands the child to a thread that escalates and reaps. Two windows on one folder shared its snapshot repository, and each re-took the baseline. That discarded changes the first window still offered to roll back. An existing baseline is now left alone, and has_baseline asks git for a commit rather than trusting the HEAD file. Git ran a thread per 250 ms batch of file system events. An agent writing files left a full-tree git status running every quarter second. Each session now has one thread with a coalescing queue and a per-folder lock. Font scanning built a FontSystem per window; one is shared now. Opening a PDF parsed it on the event loop, and Cmd+C on a PDF ran the text extraction there too. That extraction took 11.8 s on a 1.3 MB paper in a debug build. The worker opens the document and extracts its text when the file opens, so the copy is a field read.

  • 0.1.9Thai in the terminal, marks and all. A Thai syllable is one grid cell holding a consonant plus zero-width vowels and tone marks: alacritty stacks those marks onto the cell rather than giving them columns of their own, and the renderer only ever read the cell's base character. Every mark was dropped on the way to the screen, so สวัสดีครับ ที่นี่ arrived as สวสดครบ ทน — consonants standing, vowels and tones gone, which is the same thing as being unable to type Thai. A cell's whole stack is now shaped as one cluster, which is also what puts each mark over the right part of the letter instead of beside it; a cell carrying nothing but a mark draws instead of being skipped as blank, and a syllable under the block cursor keeps its marks rather than dropping to a bare consonant. Every mark a terminal stores this way travels the same path — Lao vowels and tones, Hebrew niqqud, Arabic harakat, a combining accent on a Vietnamese or Greek letter — and an emoji written with a variation selector now gets its emoji form. Copying always carried the marks — only the drawing was losing them.

  • 0.1.8Display math set the way TeX sets it. \left(…\right) delimiters were scaled to the body's line box, which carries leading no glyph reaches into, so every fence came out oversized and each nesting level multiplied the last — LN(ReLU(Wf + b)) in four different paren sizes. Fences are now measured against the body's ink either side of the math axis and grown by TeX's delimiter factor, whose slack is exactly what stops the cascade. Scripts, roots and accents measure the same way, so a superscript sits on the base it belongs to and a radical over a fraction stays a radical. Atom spacing grew a left and a right side: punctuation takes its space on the right only, and a named operator is followed by the thin space that the \! of \LN\!\left( is written to cancel. align keeps every row — the math parser stopped at \\ and the block-level code never split there, so all but the first row vanished; each row is now its own numbered equation, breaks nested in a matrix are left alone, and a \label binds to the row carrying it. Plus \mathbb and \mathcal letters, a real minus sign, spacing accents in place of combining marks that shape to nothing, a second script level for inline math (R^{d_{model}} no longer reads as R^d_(model)), and a wide equation nudged clear of its own number.

    The terminal gets a font of its own. Settings now has an Editor font and a Terminal font, each picked separately — a grid of cells and a page of prose do not want the same face. Both lists are built from the families the font database really holds, and both names are checked at startup: a family this machine lacks is swapped for the first installed fallback and written back to config.toml. That is the Windows fix — cosmic-text answers a family it cannot find with the platform's interface font, so a config carried from a Mac drew the terminal in proportional Segoe UI. The picker also opens inline in the dialog instead of in a popup, which was placed from its unscrolled position and could open outside the window once the dialog had been scrolled, swallowing the click. A config written before the split keeps one family for both until you choose a terminal font, and a settings change that only touches the terminal no longer re-typesets the open document.

  • 0.1.7LaTeX is set on the page its class asks for. The viewer reads \documentclass (and a geometry call) and lays the document out on that page — letter or A4, the class's margins, two columns for the journal classes (IEEEtran, ACM/SIG, RevTeX, [twocolumn]) — then paginates it: numbered sheets, paragraphs continuing into the next column, headings kept with their text, full-width figure*/table* at the top of a page, and any float that will not fit moving to the top of the next column while the text flows past it ([H] stays pinned). The type size follows the page, so a paper reads at page size rather than editor size, and Cmd+= / Cmd+- magnify that page — same line breaks, same sheets, figures growing with the text, the way zooming a PDF does. Front matter comes out as \maketitle sets it — spanning title block, \thanks as the affiliation footnote, raised \textsuperscript markers, Abstract/Index Terms labels — sections carry the class's own numbering (1.1 or I, A, 1, or none under secnumdepth), \cite prints the number its \bibitem will carry, and captions are labelled the way the class labels them. Inline math is finally inline: real raised and lowered scripts (V_S, km s⁻¹) instead of spelled-out _S; a display too wide for its column is set a size smaller. \graphicspath figures resolve (vector PDF plots included) and scale with the minipage around them, tabularx joins tabular as a booktabs-style table, center/\centering and the \LARGE\scriptsize sizes apply — and stop at the end of their group, which is what kept leaking a table's \scriptsize into the rest of a paper.

  • 0.1.6 — the left panel becomes a file manager. Drag files in from Finder and they are copied into the folder you drop on, with the target row highlighted as you drag (winit hands over the dropped paths but no coordinates, so the pointer is read from AppKit and hit-tested against the row list); drop on the terminal instead and you still get the shell-quoted path. Cut / Copy / Paste use the system pasteboard, so files move both directions between Tigriden and Finder — Cut+Paste moves, Copy+Paste copies, and a name clash takes a " 2" suffix rather than overwriting. Delete / ⌘⌫ moves to the Trash behind a confirmation, which the context menu's Move to Trash now asks for too. Rows carry a selection and the keyboard drives it: ↑/↓ walk and scroll into view, ←/→ collapse, expand or step to the parent, Return opens, F2 or ⌘R renames, ⌘D duplicates. Markdown is set on the same white page as LaTeX — serif, justified columns, paper margins — and its math is typeset, not dumped: $…$ and $$…$$ go through the same box layout a .tex file gets, so fractions stack, \sum/\int carry their limits, and \tag{1} is set flush right as the equation number (math code fences work too). The terminal has its own text size, split from the editor and viewer; a config written before the split keeps one size for both until you move it.

  • 0.1.5 — copying text, everywhere it was missing. Select text in the viewer: drag across Markdown paragraphs, code blocks, CSV tables and the glyphs of rendered PDF pages, double-click for a word, Cmd+A for all, Esc to clear, Cmd+C / Cmd+X to copy. PDF selection builds a real text layer from the same content stream the renderer draws, so highlights sit on the glyphs — on cropped and rotated pages too — and two-column papers copy one column at a time instead of zig-zagging across the gutter; Cmd+C with nothing selected still copies the whole document. Right-click the terminal, editor or viewer for Copy / Paste / Select All — Copy greys out with nothing selected, Paste is hidden on read-only views, and the right-click no longer clears the selection you just made. The mouse wheel now scrolls inside full-screen apps: TUIs run on the alternate screen, which keeps no scrollback of its own, so the wheel did nothing at all in Claude Code, vim or less; apps that asked for mouse reporting now get real wheel events at the pointer's cell, and the rest get arrow keys, xterm's alternate-scroll behaviour. Plus an opencode preset button, which configs still carrying the stock three take on once.

  • 0.1.4 — viewer performance and polish: PDFs rasterize and images decode on background threads (scrolling and zooming no longer stall the UI), pages prefetch ahead of the scroll, wheel repaints are throttled; a scrollbar on the right of the viewer (draggable thumb, click-to-jump) plus PageUp/PageDown, Home/End and ↑/↓ keys; ⌘ detection for wheel zoom and shortcuts now reads the modifier state straight from the OS; scrollback limit changes apply to already-running terminals.

  • 0.1.3 — viewer zoom for images and PDFs (Cmd+=/-/0, Ctrl/Cmd+wheel, header magnifier buttons, panning), PDFs rendered as actual pages, Markdown tables drawn as real grids, terminal scrollback keys (Shift+PageUp/PageDown/Home/End/↑/↓).

  • 0.1.2 — Settings UI (⌘,): 6 themes, accent colors, fonts and sizes, scrollback, all applied live to every window.

  • 0.1.1 — file change tracking with per-file/all rollback (git or invisible shadow snapshots), multiple windows with per-window agent teams.

  • 0.1.0 — first release: per-folder sessions with terminal, file tree, editor, viewers, presets.

Roadmap / known limitations (v1)

The LaTeX view is a fast reader's approximation of the page, not a TeX engine — for the final artifact, compile:

  • Line breaking is TeX-like but not TeX: no hyphenation and no paragraph-wide optimum, so line breaks and page breaks differ from the compiled PDF.
  • Side-by-side minipage panels stack vertically, each at its declared width.
  • Macros you \newcommand are not expanded; \input/\include files are not pulled in (open them directly).
  • A journal's affiliation footnote is set under the byline rather than at the foot of the first column.

Elsewhere:

  • Editor undo
  • Mouse reporting to TUIs
  • IME / dead-key composition
  • Editor tabs (currently one open file per session)
  • PDF page rendering (done in 0.1.3)
  • LaTeX typeset on the class's own page (done in 0.1.7)
  • Linux / Windows testing

License

MIT

About

Fast, tiny end-to-end research workbench: per-folder terminals for AI coding agents, change tracking with one-click rollback, and LaTeX/PDF/Markdown read as typeset pages.

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages