Skip to content
brothydocs
Changelog

Changelog

What changed in each brothy release.

Changelog

All notable changes to this project are documented here. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

Unreleased

Added

  • Heading styles: # cycles classic (the default) → bars (a level-colored █ ▌ ┃ │ ┆ ┊ prefix) → ladder (shade glyphs ██ ▓▓▓ ▒▒▒▒ … that thin with the level) → rules (H1 and H2 run a rule to the end of the measure, H3 gets ╌╌, H4–H6 are bold color only) and saves it as headings in config.json. It applies to the document, zen, the ctrl+p peek and the theme picker sample; Source is unchanged.
  • A docs site (Astro Starlight, site/) at https://jackmort.github.io/brothy/, drawn as brothy’s own screen: the top line, the ¹Files ²Outline ³Info panel (a drawer on phones), the 80-column measure, key hints and a progress line, and brothy’s keys on the page (j k [ ] / 1 2 3 t ^b ?). The front page is the welcome page (wordmark, bowl and steam from the app’s own art) with the recorded tour playing in a frosted window (on a phone a tap opens it full screen, turned sideways); then install, and pages for every feature, the keys, themes, config and AI, built from the README and changelog and deployed by .github/workflows/pages.yml. Screenshots come in dark and light and follow the site’s theme. It uses only the brothy / brothy-light palettes, one face (IBM Plex Mono) and a new bowl-and-steam icon, also at the top of the README. (In the repository’s Pages settings choose GitHub Actions as the source.)
  • bun run cast (scripts/cast.ts) records the demo as site/public/casts/tour-{dark,light}.cast by playing a scripted tour of the real UI headlessly.
  • The recorded tour (docs site casts and README videos) shows the AI features too: TL;DR, ask, D on a live reload and the zen gloss, answered offline by a stand-in model (scripts/fakeai.ts) so recording needs no network or key; examples/notes/stock.md is the note they work on. The README shows docs/demo.mp4 (the gif is its fallback), and the videos are staged like the site demo: the same wallpaper behind a frosted glass window.

Changed

  • The TL;DR is a footnote: * and the whole summary (up to 14 rows, then ⏎ more on its rule) closed by a rule signed TL;DR · <model>. While the model works the block says asking <model> · 3 s, and regenerating keeps the old summary dimmed under the caret until the first words arrive; an outdated one says edited since · a refresh. A failed request leaves its error in the block with a retry. A * after the title in the top line marks a note with a TL;DR, the document footer offers a summarize until it is fresh, a summary that lands out of sight toasts TL;DR ready · 3 to read, and the ctrl+p peek shows it the same way.
  • Zen gloss: the note is a footnote, a short rule then ¹ and the text with a hanging indent, and the section’s heading carries the ¹. From 140 columns (at the default measure) notes sit in the right margin beside their headings, the other sections’ glosses dimmed and numbered by row. While the model works the rule says asking <model> · N s · a cancel. A cached gloss shows after a 600 ms pause in its section, an outdated one too, dimmed with edited since · a refresh. a on a gloss on screen shows more or less of a long one (it used to ask again); A asks again. A reply past 400 characters keeps its finished sentences instead of failing gloss too long.
  • Ask (? in ctrl+p) reads as a list you can trust: Matches with the word that matched on the right until the model has picked, then Answers marked ¹ ² ³ with the model’s reasons as footnotes under a rule, so a reason never cuts a heading. While a request runs, ▍ asking llama3.2 · 3 s (or ranking 12 excerpts) sits where the results will appear, and the pane shows exactly what was sent; before that it explains what ⏎ sends. The footer follows each step, Go to says ? asks your notes when AI is on, and nothing found or a failure ends in next steps (whether the question left, what to check). Opening an answer marks its heading and names it in the running head, with its reason on the footer line; ctrl+p then reopens the question with its answers without asking again, and a renamed heading lands on the matched word instead of giving up.
  • What changed on disk: after a live reload each changed section is numbered after its heading (¹ ² ³, a removed one in the margin where it was), the running head says ³ changed and the toast reloaded · ³ sections changed, with AI on or off. Info’s Changed since 09:23 block numbers its rows (added says new, removed is struck through), says D explain / D cancel / D retry at its right end, waits with ▍ asking <model> · 3 s, wraps the summary to 5 rows and each note to 2, keeps a failure in place (✗ …) and the last explanation dimmed under Earlier; past 8 rows + n more sections opens the rest (it was a dead + 1 more sections row). ⏎ on a change goes there and shows its note in a footnote (¹ of 3 · ] next); [ ] walk the changes, esc hides it. Below 100 columns D lands on the first change instead of opening the drawer; with the panel hidden and room in the margin the notes sit beside their headings. The prompt asks for at most 8 words per section.
  • What changed on disk, the Proof sheet: ⏎ on the Changed label in Info opens What changed, a popup with each changed section’s real lines (− removed, + added, context, … between hunks, long lines cut around the change), the summary and notes once D has explained them. ↑ ↓ move between sections, ⏎ goes to one, D explains in place, esc closes. It works without an ai block. The label is now the first stop in Info’s Changed block.
  • Development: Biome formats and lints the code (bun run lint, bun run format) and knip finds unused files, exports and dependencies (bun run knip); CI runs both.
  • New wordmark: a chunky 3×36 block-letter brothy (the U+2580 block family) on the welcome page, the ? sheet, --version, the docs site and the videos; the welcome art is as wide as the wordmark (36 columns, the bowl centred under it) and gives way to the text below that.
  • New default palette, Hōjicha: brothy and brothy-light move from teal / gold / coral to roasted-tea neutrals with one persimmon signature colour (H1, focus, the bowl), sand and dusty-plum H2 / H3, muted lavender links. Body text sits near 14:1, every content colour reaches 4.5:1 on the page, the side panel and code blocks, borders are easier to see, and error callouts no longer share the tip / H3 colour. The docs site, favicon and logo follow.

0.2.0 - 2026-10-28

Added

  • brothy - (or brothy with a pipe and no path) reads Markdown from stdin: one document titled stdin, keys from /dev/tty; no Files tree, watcher or project record, and links resolve against the current folder’s notes, scanned in the background after the first frame (or on first link use). The panel has only Outline and Info (1 2), also after following a link and coming back with H. Input over 5 MB stops with brothy: input too large (limit 5 MB) before the rest is read.
  • e opens the note in $VISUAL / $EDITOR (fallback vi) at the line at the top of the view (exact in Source, from the nearest heading in Preview); VS Code, VSCodium and Cursor get -g path:line and Sublime Text path:line instead of +line. The reader resumes and reloads when the editor exits, and says so when it exits with an error; on a note followed from piped input the editor reads keys from /dev/tty.
  • Selecting text with the mouse copies it to the clipboard (OSC 52) and says how much.
  • Opt-in AI, only on a key press, through an ai block in config.json (OpenAI, OpenRouter, Anthropic, Gemini, Ollama, LM Studio or any OpenAI-compatible endpoint; keys come from the environment). Up to 3 requests run at once. r re-reads the block. A baseURL with a query (?api-version=…) keeps it.
    • a summarizes the current note into a TL;DR at the top of the Info tab; a again cancels. Summaries are cached in ~/.cache/brothy/summaries.json and shown again for free. In stdin mode the summary lasts for the run and is not cached.
    • Zen gloss: a in zen explains the section under the reading line in one or two sentences on a muted sheet (nothing is inserted into the text); esc hides it. A gloss already made for an unchanged section shows by itself when you reach it again; an outdated one needs a. ai.gloss picks the style: explain, simplify or translate:<tag>. Glosses are cached in ~/.cache/brothy/glosses.json.
    • D explains what changed on disk since the note was opened: only the changed hunks are sent, and the reply (one or two sentences plus a few words per section) appears under Changed in the Info tab; ⏎ on a changed section jumps to it. Past the size cap later sections are listed by heading while they fit, then counted (… and 12 more sections); a reply that runs long keeps its summary and the section notes it finished. An explanation is dropped once a reload is too large to compare.
    • ? in the ctrl+p switcher asks your vault a question: ⏎ sends only the question and the model returns search terms; the answers are sections brothy finds itself, and ⏎ opens one at its first matching line (also under a heading with no letters, such as ## ★). A separate ↻ rerank with excerpts row (cost shown first) sends up to 12 candidate excerpts to order them.
  • A live reload lists the changed sections in the Info tab (Changed, with +added −removed counts) and the toast says how many (reloaded · 2 sections changed). The list is local and works without AI; the baseline is the text the note had when opened, kept in memory only. A reload over 2 MB, or one that rewrites too many lines to compare quickly (a formatter run over a long note), says too large to compare instead of freezing the reader.
  • Braille minimap at the right edge from 110 columns, in Preview and Source: headings stand out, the part on screen sits on a band, and find hits show in a lane beside it. Click to jump; m toggles it (saved as minimap). Wide (CJK) characters count by their width.
  • ctrl+p peek pane from 100 columns: the highlighted note’s path and length, its outline around the hit, its TL;DR when a fresh one is cached (the pane never sends a request), and its first lines; only the part shown is rendered, so a note of several MB peeks quickly.
  • The keys sheet (? twice) groups the keys under Global, Document, Zen, Panel and AI chips, in two columns from 100 columns.
  • Welcome page while no note is open (a folder with no Markdown): the wordmark over a bowl of broth with rising steam, the keys to start, and recent projects you can open with ↑↓ ⏎ or a click. The panel, a, s, w, z and Z keys wait for a note.
  • Panel tabs carry their key number (¹Files ²Outline ³Info), also in the compact strip; the rule under the open tab is accent while the panel has focus.
  • motion in config.json (default true): false draws the welcome page still (no ink-in, no rising steam).
  • Nine theme families from their upstream palettes (MIT): ayu, cyberdream, iceberg, melange, nightfox (light: dayfox), nightowl (light: Light Owl) and oxocarbon with a dark theme and a -light twin, and the dark-only synthwave84 and vesper; 42 themes in 22 families. Roles that missed the contrast floors were nudged in lightness only; oxocarbon-light leads with the dark theme’s teal, with a blue secondary, pink errors and orange warnings.
  • --theme and theme in config.json take a family name too (one, ayu): its dark theme, or its only one; --help lists the families instead of all 42 names.
  • The theme picker handles a family with only one mode: its missing cell on the board and the missing side of the switch are muted and struck through, tab / ← → and a click there do nothing, and the pane shows the family’s own theme whatever mode you asked for; the next pair shows that mode again.

Changed

  • The theme picker (t) lists the 22 families once, with a query to filter them (letters now type, so j k g G no longer move; ↑↓ and ctrl+n ctrl+p do) and a dark / light switch (tab, ← →). From 100 columns a pane renders a sample note (marks, links, code, a callout, tasks, a table) in the highlighted theme on its own background. The app no longer re-themes while you move: ⏎ applies and saves, esc closes with nothing changed.
  • The theme picker’s list is a board: a dark and a light column under a header, each cell a specimen (Aa and the primary, secondary and accent dots) in that theme’s own colours on its own background, so both twins show without flipping. The cursor is one cell framed in the app’s primary (↑↓ family, ← → or tab mode; the footer says ←→ dark/light), the theme in use keeps a thin muted frame, and a click on a cell applies that theme; hovering does not scroll the board. The list is 41 columns wide and the pane 58 at 120 columns.

Fixed

  • A theme in config.json that names no theme ("one" before family names, or a removed one) is reported at start instead of opening brothy without a word.

Security

  • AI requests go only to the endpoint in your ai block: HTTP redirects are refused (AI: <host> redirects · set baseURL to the final URL), and neither the key nor custom ai.headers is sent over plain http: except to localhost. Key and header values are redacted from error toasts.
  • Front matter (other than the title used as the note name) and %%comments%% are never sent. Cache files are private (0700 folder, 0600 files).

0.1.1

Fixed

  • Sinhala, Malayalam and Devanagari text keeps its zero-width joiners (ශ්‍රී, chillu letters, half-forms) instead of showing �; a lone or leading joiner and bidi controls are still replaced.
  • A paragraph underlined with a single - is a heading in the Source outline and the ctrl+p switcher too, so heading hits jump to the right place.
  • The empty-folder message shows the folder name with control characters replaced.

0.1.0

First public release. Renamed to brothy: the command, binary and repo are brothy, and config lives in ~/.config/brothy.

Added

  • Terminal Markdown reader: folder tree (fuzzy filter, folder counts), Preview and Source views, a tabbed Files / Outline / Info panel (a drawer below 100 columns), find in document, live reload, mouse support.
  • Layout at an 80-column measure (w for full width) with a running-head top line, ghost hints and a progress line.
  • Pre-wrapped rendering: tables that shrink to fit, task lists, code blocks with tree-sitter highlighting for JS/TS/JSX/TSX/Zig and a fallback for other languages.
  • Obsidian syntax: wikilinks and embeds, callouts, ==highlights==, %%comments%%, collapsed dataview/tasks blocks, known HTML tags.
  • Navigation: note switcher across the vault (ctrl+p: notes, headings, text), project opener (o), link labels (f), back/forward history (H/L).
  • 26 themes (13 dark/light pairs) with a live-preview picker, transparent background (T, --transparent).
  • Zen mode (z, settings Z): centered text, scroll or pages flow, spotlight, typewriter, teleprompter.
  • Prebuilt binaries for Linux and macOS (x64, arm64).

Keys any key closes

jk
scroll
gG
top · bottom
[]
previous · next section
/
search the docs
123
Files · Outline · Info
ctrl+b
hide / show the panel
t
theme picker
space
play / pause the tour (front page)
esc
close the drawer
?
this sheet

brothy's own keys: keyboard reference