1.99.4
Pre-release
Release notes
(2.0 preview 4)
holdings command,
better lot tracking,
command aliases,
reorganised help command,
run/repl improvements,
barewide balance layout,
hledger-ui --watch memory leak fixed,
hledger-web security fixes.
hledger 1.99.4
Breaking changes
-
In journal format, a single tab is also now accepted as the separator between account and amount, for improved compatibility with Ledger. This also means account names can no longer contain tab characters.
-
In CSV rules, when a directive like
date-formatorseparatoris declared more than once, the last declaration now takes precedence, as the manual describes, rather than the first.
(Except forskip, where the first declaration still wins, also as the manual describes.)
This makes it possible to override an included rules file's directives by writing new declarations after theincludeline.
If any of your rules files relied on the old undocumented behaviour, declaring a directive before anincludeto override the included file, you should move that declaration below theinclude. #2539 -
The
accountscommand now more strictly respects transaction-specific query terms
such asdate:,status:,desc:; these prevent matching a declared
but unused account, which doesn't have those fields. (Previously they were ignored in that case.)
Onlyacct:,depth:,type:ortag:can match an unused account. -
The
payeescommand gets similar query fixes:payee:now matches
declared payees as expected (previously it matched none of them, so
apayee:query could hide them from the report),
and transaction-specific query terms likedate:ordesc:no longer match
a declared but unused payee. -
any:andall:queries now also work in posting-oriented reports
like register, balance and aregister; previously they had an effect only in
commands which show whole transactions, like print.
So those reports can now select postings based on their siblings: eg
hledger balance expenses any:cashshows expenses which were paid
with cash - previously this required a two-command pipeline.
Also aregister with these queries now behaves more consistently,
showing the same transactions as print would. -
Config files can no longer specify the command to run via a bare first word in the general section.
Since config files can now define command aliases (which can run shell commands), letting a config file also select the default command was too risky.
The command to run must now always be given on the command line. -
The
democommand, which played asciinema recordings, has been removed. -
The
--tldrflag has been renamed to--examples. -
stats's-1flag has been renamed to--oneline.
Config files
-
Command aliases: you can now define custom commands by adding
NAME = COMMAND...to the[alias]section of your config file.
COMMAND can be a builtin command, an addon command, another alias, or a shell command prefixed with!, and can be continued on multiple indented lines.
(Shell commands will run only from your user config file, or one specified explicitly with--conf.) -
In config files, a
#inside single or double quotes is no longer misparsed as a comment start. -
Leading whitespace before a section header, and a trailing line containing whitespace with no final newline, are now accepted.
-
--conf/--no-confflags inside a config file are now dropped, instead of being passed along and causing trouble later. -
Config file errors now follow hledger's standard FILE:LINE-and-excerpt format, and parse errors are displayed properly.
Command line
-
Colour handling is more robust:
- ANSI colour is no longer used when
TERM=dumb, eg in an Emacs shell, which was leaking escape codes into piped or redirected output.--color=yescan still override. - Colour output now works in terminals where the background lightness can't be detected, eg inside Emacs (a light background will be assumed).
- In terminals without truecolor support, eg Emacs vterm or a stripped
COLORTERMover ssh/tmux, we now downgrade to the nearest xterm 256-colour.
- ANSI colour is no longer used when
-
Command line arguments are now passed to addon commands exactly as you
typed them, fixing cases where apostrophes, empty strings or other special
characters were mangled or silently dropped (Kevin F. Konrad, #2696).
(Except on Windows, where addons are still run through the shell, so
that .bat and other script addons keep working; there, arguments can
still be mangled.)
Quoting is also improved on the other paths which still build a shell command line:
addons run fromrunandrepl, and!shell aliases (Arthur Cinader). -
Options written after
--are passed through to an addon command rather than consumed by hledger;
additional--arguments are also passed through;
and--written in a config file section or a command alias now works as it does on the command line.
(Kevin F. Konrad, Arthur Cinader, #2696) -
hledger no longer rejects a flag with "needs a value" when that flag
belongs to some other command. Eg--sorttakes a value inregister,
sohledger help --sortused to fail with "--sort needs a value";
nowhelpreports the more accurate "Unknown flag: --sort", and an
addon given--sortreceives it.
(Kevin F. Konrad, #2696) -
Abbreviating
print's--locationsflag, egprint --loc, now works as expected. -
Balance assertion failure messages show a better troubleshooting command:
- regex metacharacters (eg the curly braces in
{2026-07-12, 2.5 €}) will be escaped -Eis added, so zero-amount postings will also be shown- instead of
-I, the more precise--ignore-assertionsis used.
- regex metacharacters (eg the curly braces in
-
acc,comm,descare now official short spellings for theaccounts,commodities, anddescriptionscommands.
Help
-
helphas been reorganised and is now an entry point for all hledger docs.helpwith no arguments (orhledgerwith no command) shows a quick reference card.help commandsshows the full commands list.help examples [CMD]shows command examples (like--examples).help usage [CMD]shows command options and docs (like-h).help manual [TOPIC]orhelp TOPICshows the full manual, in several formats, now including the HTML versions at hledger.org.help install/docs/support/home/sponsor/relnotesopen the corresponding hledger.org page in a web browser.
-
help's matching of manual topics is more powerful.
help manual TOPIC(orhelp TOPIC) now matches by exact match or unique prefix, with all viewers.
It now also searches the hledger-ui and hledger-web manuals.
A topic matching several headings, or nothing, now warns or lists the candidates instead of failing or being ignored. -
help manualhas a new-lflag which lists manual topics rather than showing them.
Andhelp manualwith no further arguments lists all topics, indented to show some of their hierarchy. -
When
TERM=dumb, or in Emacs shells that don't support TUIs,help manualnow defaults to showing plain text instead of failing to run a manual viewer. And it shows only the introduction, not the whole manual. -
helpnow hashas its official alias. -
The new browser-opening features (
help home,--webmanand friends)
work on all platforms, using the open-browser library: the Win32 API
on Windows,openon mac,xdg-openor other launchers on Linux.
(Arthur Cinader) -
The commands list can now be limited to particular categories of
command withhelp commands --builtins,--addonsor--aliases;
the flags can be combined. (--builtinhas been renamed to
--builtins, but still works as a unique prefix.)
Data entry
-
addwill no longer suggest default amounts having ambiguous digit group marks
(such as1.000or1,000), which if accepted could be misparsed later. Instead it will
add a trailing decimal mark to disambiguate (eg1.000,or1,000.). #2656 -
Numbers can now also use
_or'as digit group marks. (Kevin F. Konrad, #273, #1489)
Data import
-
In CSV data, characters which journal format can't represent are now
replaced, with a warning: a semicolon in a description is replaced
with.,(it would otherwise start a comment when read back,
truncating the description), and a right parenthesis in a
transaction code is replaced with](it would otherwise end the
code early). #2413 -
CSV rules files'
includedirectives are handled more robustly
#2537: include cycles, and unreadable included files, are now
reported with a proper error message showing the include directive's
location; errors in included files are reported at the right file
and line (previously they were reported against the top-level file);
included files now handle BOMs and CRLF line endings like the
top-level file; and whitespace around the included file path is
ignored. -
A CSV rules file's data-generating command (
source | cmd) failing
no longer aborts the whole run; instead it warns and continues, as
if no data was found. So whenimportprocesses several rules
files, one flaky external source won't block the rest. Data-cleaning
commands (source PATTERN | cmd) still fail hard, since they
operate on a file that was actually found. -
importwitharchiveenabled, if there are multiple downloaded copies of the source file,
now properly deletes processed files and always makes progress.
(Previously it could stall, reprocessing the oldest file each time.) -
import --dry-runno longer wrongly archives data files when the flag
is given abbreviated, eg asimport --dr. Also,import's
special file handling - preferring the oldest file matching a
sourceglob, and honouring thearchiverule - now happens only
whenimportitself reads its data files; previously any command
could trigger it if the word "import" happened to appear in its
arguments. -
--debug=2now shows clearer output when reading a CSV rules file.
Lot tracking
Lot tracking has been reworked extensively since 1.99.3. In summary:
-
How lot tracking is enabled has changed: a
lots:tag enables it only on commodities now, not accounts. An account'slots:tag now just sets that account's disposal method (FIFO, LIFO, etc - a value is now required), or opts the account out of tracking withlots: NONE(eg for tax-sheltered accounts). -
Many more real-world entries are now recognised and handled correctly: transfers involving multiple source or destination accounts, transfers written with
{}cost annotations, transfer fees that are unpriced or split across several postings, in-kind (priceless) disposals, and entries whose amounts are implied or set by balance assignments. -
In lot transfer entries, the source or destination amount can now be elided, like other amounts. #2724
-
Several bugs that could silently produce wrong numbers are fixed: a transfer's sent and received quantities must now match (previously lots could be silently dropped, or a shortfall silently treated as a no-gain fee); fees are now deducted before a transfer selects its lots, so FIFO/LIFO etc choose from the right lots; amounts stay correct when lot detail is collapsed for display (previously balances could be wrong or fees double-counted); and a transfer into an
AVERAGEpool now re-averages the pool's cost, as an acquisition does. -
Lot names are shown consistently and are always usable: a lot now displays the same name (same cost precision) when acquired, disposed, or transferred; inferred cost bases display enough digits to be exact; and any lot name shown in reports or errors can be used to reference that lot. Also,
print --lotsoutput can now always be read back by hledger. -
Error messages are clearer and more accurate: they show the entry as it was written, not hledger's processed version; "no lots available" errors list the lots actually available; quantity-mismatch errors suggest the likely cause; an unbalanced entry is reported as such instead of producing a confusing inferred cost; and incompatible mixes of global (
*ALLetc) and per-account disposal methods are now rejected.
Also lot errors summarise how hledger interpreted the entry's postings. -
Balance assertions on lot subaccounts can't be checked correctly (assertions are checked before lots are calculated), and are now handled consistently: close --lots no longer generates them, and when lot detail is hidden (in print output or hledger-ui) existing ones are ignored instead of failing spuriously. The manual and the assertion failure message now explain this limitation.
-
closeno longer generates a spurious zero posting for some emptied accounts, andclose --lotsoutput is more readable (lot subaccount balances no longer show redundant costs). -
A new
holdingsreport shows your lot-tracked investment holdings, per account and commodity or per lot, with units, cost basis, current price and market value, portfolio weight, unrealised and realised gains, and XIRR annualised return.
Multiple cost and value commodities are supported, and displayed separately, or as a single-currency view with-X COMM. -
The "no lots available" and "no lots matching" errors now show the
attempted transaction's date, clarifying that lot availability is
checked at that date. -
holdings: the cost column's heading matches the lots shown:
"Avg cost" on rows aggregating multiple lots, as before; and now
also with --lots, when the lots shown all use the AVERAGE method
(their per-lot rows show the pool's average cost). "Unit cost" when
each lot shows its own cost, and "Unit/Avg cost" when both kinds of
lot are shown together. The csv/tsv/html/json outputs keep the stable
unitcost field name regardless. -
holdings: show cost information for AVERAGE accounts.
An AVERAGE account's Avg cost, Cost, UGain and UGain% columns were
blank: holdings parses each lot's cost basis from its subaccount name,
and AVERAGE lots' names deliberately omit the cost (staying stable
across re-averaging). Now, when a lot's name has no cost part, holdings
fills in the pool's running average as of the report end date, computed
from the lot postings' cost basis annotations: sum of quantity * unit
cost over the pool's postings (acquisitions carry their acquisition
cost, disposals and transfers the then-current average), divided by
total units. The sum spans the whole pool - the base account's lots for
AVERAGE, all accounts' for AVERAGEALL - so with --lots, each pool lot's
row shows the pool average, as in the lot state, where every pool lot
carries the current average.
REPL & run
The repl and run commands have been improved since 1.99.3. In summary:
-
Most general flags given to
repl/runat startup (such as-I,--strict,-b/-e,--depth,--cost,--color) are now applied to every command in the session or script (overrideable by flags within the session). -
runscripts are more robust: successfully running an addon command no longer ends the script. -
File handling is more flexible: an
-fat startup sets the default journal file(s) for all commands, and is passed to addon commands; and a nonexistent default journal file is tolerated, as at the command line (soadd/importcan create it). -
The REPL now auto-reloads before each command, detecting changes in input files, the config file, or installed addon commands. This can be disabled with the
--no-watchflag. -
The REPL is friendlier: it shows a small startup banner, and the journal's base file name in the prompt; the help and quit commands are
handq; andechointerprets common backslash escapes like\nand\t. -
Getting help in the REPL works better:
helpandCMD -hnow show the same full, paged output as at the command line, andhelp(alsosetup) no longer fails when there's a problem in the journal. -
Quoted arguments in
run/replcommand lines and in config files are now tokenised more like the shell: quotes can enclose part of an argument, not just the whole of it, sodate:'1 to 15'is the single argumentdate:1 to 15, as at the command line. Also like the shell, a lone quote within an argument (egdesc:o'brien) must now be quoted or avoided. -
A
run/replcommand line that can't be tokenised, eg because of an unclosed quote, now shows a proper parse error with the position and the problem line, instead of a raw parse error dump. -
Changes to CSV rules files now trigger a reload. Automatic reloading watched only journal data files, so edits to a CSV rules file had no effect until restart. Journals now also record the other files their data came from - the CSV rules file, any rules files it includes, and the data file read by a
sourcerule - and these are watched too. This affectsrepl, hledger-ui and hledger-web.
Reports
-
printhas a new--onelineflag showing just each entry's first line, for a compact overview. -
Multi-period balance reports using
--treeand--transposetogether now show only the leaf accounts, for less confusing output. #1941 (JoeJoeflyn) -
balancehas a new--full-namesflag, which in tree mode shows full account names instead of the usual indented leaf names. (Henning Thielemann, #2429, #2661) -
balance's--no-elideflag now also has an effect in list mode: it adds the parents of the posted-to accounts, shown with their own exclusive balances (usually zero, so add-Eto see them). Egbal --no-elide -Eshows a complete table of every posted-to account and its parents. (Henning Thielemann, #2429, #2661) -
In
balance's single-period csv/tsv/html/fods output,--dropno longer causes the total row's "Total:" heading to be truncated. #2688 -
Omitting
roi's--pnloption now works as documented, selecting no postings; previously it selected all postings. (Dmitry Astapov, #2670) -
Repeating the
--transposeflag now toggles it, allowing a previous--transposeto be cancelled. -
setupno longer reports unused commodity aliases as undeclared commodities; it's now consistent withcheck commodities. -
balance --budgetreports no longer lose their goals when the command
includes transaction or posting filters, such asstatus:,desc:
or--cleared#2545. Instead only the attributes that meaningfully select goals
(account, account type, depth, date, commodity) affect them.
So now,bal --budget --clearedcompares cleared spending against the full goals. -
-X/--valuewith a commodity to which no conversion price can be
found now prints a warning, instead of silently having no effect. An
equivalent commodity symbol is suggested if one is known (eg$for
USD). -
Report titles in HTML output are improved:
balancenow shows the
same default heading as its text output (for multi-period and budget
reports),register,aregisterandholdingsnow show a title
too, and in all of these--title=TEXTreplaces it and--title=
suppresses it. Also, the title is now a<h3 class="report-title">
element placed before the table, making it easier to style. -
In
print's csv/tsv/html/fods/sql output, the debit column now
appears before the credit column, following convention. -
In
aregister's csv/tsv/html output, the "change" column has been
renamed to "amount", matchingprint's output and making it easier
to re-import with csv rules. -
HTML output now has newlines between elements, making it easier for
humans to read and troubleshoot; rendering in browsers is unchanged.
#2326 -
aregister's HTML output now has the same builtin table styles as the other reports. -
HTML output now prevents wrapping within all dates and individual commodity amounts, by default.
(Multi-commodity amounts can still wrap between the amounts.)
Each amount is wrapped in aspanwith an "amount" class, and date cells are marked with a "date" class,
for easier styling. -
In HTML output, a
hledger.cssfile now overrides the builtin styles
(previously the builtin styles took precedence).
An examplehledger.cssfile is provided in the repo. -
In
print's beancount output, underscores in account names are now
converted to dashes rather than hex-encoded, giving cleaner names
(assets:wells_fargobecomesAssets:Wells-fargo, not
Assets:WellsC5ffargo). #2596 -
print's beancount output no longer emits price directives dated in
year 0, which Beancount rejects. The 1:1 prices inferred from
commodityalias:tags are now dated 0001-01-01; other output
formats are unchanged. -
bal: A new
barewidelayout combines the bare and wide layouts:
amounts are bare numbers, and each commodity gets its own column,
with the symbol shown in the column heading. All column groups share
the same set of commodity columns. Supported in single-period,
multi-period and budget balance reports, with txt, csv and html
output. (Henning Thielemann)
Other
-
rewrite's--diffoutput can now be applied bypatchorgit apply#2548. Previously its hunks contained no context lines, so
they were rejected. Now each source file is diffed as a whole, with
the standard three lines of context. And changed transactions which
have no journal entry to patch (ones read from CSV or timeclock
data, or generated by a periodic rule) are now left out of the diff
and reported on stderr, instead of producing bogus or destructive
hunks. -
statsnow shows the base currency's symbol as used in the journal,
with the guessed ISO 4217 code alongside when that differs (eg$ (USD)). Previously it showed only the code, which looked like a
journal commodity but wasn't usable in queries or-X. -
The aeson (JSON library) lower bound has been relaxed from 2.3 to
2.2.5.1, the oldest version not vulnerable to the HSEC-2026-0007
denial of service, easing installation while the ecosystem catches
up with newer aeson. -
Exclude megaparsec 9.8.0, to avoid a position marker bug in error messages (megaparsec#572).
Docs
-
aregister: noted that transactions with multiple currencies may occupy more than one line
-
balance, help: minor updates
-
balance: html and fods output are not multi-period-only; they have been supported since 1.40
-
Boolean queries: simplified and clarified
-
check: move the basis check note to the end
-
commodity/Directives: clarify commodity and
Ddirective scopes #2665 -
decimal marks: clarify commodity/decimal-mark directive scope leakage #2664; simplify Trailing decimal marks
-
Directives: fixed a link to the Ledger page
-
First lots example: improved
-
fixed some stray junk characters in the manual
-
help flags: clarified
-i/-m/-wvs--info/--man/--webman; reduced line wrapping in 80-column terminals; misc edits -
Lot reporting: various edits, including a holdings example and cross-reference
-
lots: documented the consequences of changing the cost basis method, and two ways to make a change apply only going forward
-
lots: documented how to record a transfer that received more than was sent
-
PART 5's sections promoted to markdown-level-1 headings, consistent with the manual's other PARTs
-
Period expressions: fixed outdated date adjustment info #2714
-
quickref: consistent checks ordering
-
rewrite: noted that --diff re-renders the transactions it changes, and that --layout can be set to minimise the diff
-
roi vs holdings: added comparison examples and interop advice (see also Examples)
-
Two-space delimiter: rewritten
-
Dropped the "added in VERSION" and "experimental" labels throughout
the manuals; notable behaviour changes still mention the hledger
version.
Examples
examples/home-page-example.journalis the example journal from the hledger.org home pageexamples/lots/lots.journalis renamed (from lot-entries.journal), updated sohledger holdingsshows a full report, and contains notes comparing roi and holdings XIRRexamples/lots/irr.journalis another example comparing roi and holdings XIRRexamples/csv/banking/has new rules for SimpleFIN (json and csv exports) and for Unify Federal Credit Union
Scripts/addons
bin/check-fancyassertionsnow checks assertions in date order, avoiding spurious failures with journals recorded out of chronological order. #1742bin/hledger-barnow allows its flags to appear anywhere among the arguments, and sets scale with a new-soption.bin/getpricesnow has a small delay between requests, reducing failures with some providers.
hledger-ui 1.99.4
Fixes
-
Fixed a long-standing memory leak (and background CPU use) when reloading with --watch #1825.
Now --watch mode has no extra memory/CPU cost, and can be used freely with large journals.
It's safe (and recommended!) to enable by default, eg in your~/.hledger.conffile
add[ui] --watch. -
hledger-ui gracefully handles more reloading failures,
such as failure caused by a changed CSV file or rules file,
or by a file momentarily removed when your editor saves it.
Instead of quitting, it now shows the error screen, allowing recovery. -
Pressing DOWN at the last list item, or pressing C-l (recenter) when
near the end of a list, no longer scrolls into blank padding space;
hledger-ui now keeps as many items as possible on screen.
(#2278, #2593, Juan Wajnerman)
Improvements
-
The L key now toggles showing lot subaccounts and per-lot detail
(ie, it toggles the CLI's --lots flag). It resets to the startup
state if ESC is pressed. -
Changes to CSV rules files now trigger a reload, like changes to data
files (see hledger changelog). -
Warnings (eg the CSV data warnings, which could appear on every
--watch reload) no longer scroll and disrupt the display; instead
they are shown on the bottom line, until the next key press.
Also the screen is now fully repainted after a reload,
repairing any other stray terminal output. -
The transaction screen now refreshes in place, when there's a reload
#1825. Previously you had to exit and re-enter it. -
Error screen reloading is less flickery and more robust.
-
Add the -? and --webman flags; rename --tldr to --examples (see hledger changelog).
-
Exclude megaparsec 9.8.0, to avoid a position marker bug in error messages (megaparsec#572).
hledger-web 1.99.4
Security
-
An XSS (cross-site scripting) vulnerability has been fixed in the
add form's autocomplete. Journal data from an untrusted source could
execute javascript when shown as a completion suggestion. All
hledger-web users should upgrade.
(Arthur Cinader, Simon Michael, #2698, advisory GHSA-538p-cvc4-4qjm) -
A second XSS vulnerability has been fixed, in the add form's error
message. Any web page visited while hledger-web was running
could use it to run javascript in hledger-web's origin, and
from there read the whole journal, or alter it. All hledger-web
users should upgrade. (Arthur Cinader, Simon Michael, #2700,
advisory GHSA-vq7r-8w52-jv84) -
A newline submitted by a user in a transaction's description, code or
account name is now removed, so the user can't inject an include directive
to read arbitrary files accessible to the hledger-web server.
(Simon Michael, #2704, advisory GHSA-vq7r-8w52-jv84) -
hledger-web now sends a Content-Security-Policy header with every
page #2703 (Arthur Cinader). This tells your browser to load
scripts, styles, images and fonts only from hledger-web itself, and
to run only hledger-web's own scripts - so if anything script-like
ever reached a page, eg through data in your journal, the browser
would refuse to run it and report it in the console. In
normal use you should notice no difference. -
hledger-web now sends the
X-Frame-Options: SAMEORIGINand
X-Content-Type-Options: nosniffsecurity headers on every
response, so other sites can't frame its pages for clickjacking, and
browsers won't second-guess content types. Static files and error
pages get them too. (Arthur Cinader) -
The unused Google Analytics hook has been removed (it was always disabled;
no page ever loaded analytics).
(Simon Michael)
Fixes
-
The upload form now shows the name of the chosen file. It never did
before, because of an escaping bug that disabled its handler.
(Arthur Cinader) -
/favicon.ico and /robots.txt no longer return 404 when hledger-web
is run outside its source directory; they are now built into
the executable, like the other static files. robots.txt now also asks
crawlers not to index the site. (Arthur Cinader) -
The register chart no longer disappears when a commodity symbol
contains a backslash or a double quote. Its legend has also moved
out of the chart, where it could cover the start of the balance
line, up to the title line above it.
(Arthur Cinader)
Improvements
-
hledger-web now has its own favicon: a gold coin struck with an equals
sign, in the palette of the hledger coin logo. It replaces the Yesod
scaffold's blue "y". (Arthur Cinader) -
The web UI's javascript has been modernised, replacing five vendored
libraries with standard browser features (Arthur Cinader, #2702):
autocomplete suggestions now use a native<datalist>; the button
beside the date field opens the browser's own date picker (typed
smart dates like "today" still work); and keyboard shortcuts,
sidebar state and transaction-link highlighting are handled by small
standard code. Two dead third-party script tags (html5shiv, chrome
frame) are gone, so nothing is loaded from a third party now. jquery
and the flot library remain, for the register chart. Also,
browser-drawn widgets like the suggestion list and date picker now
stay light when the OS is in dark mode. -
The add and help dialogs now use the native
<dialog>element
instead of bootstrap modals, so bootstrap.js is no longer loaded
(Arthur Cinader). They keep the familiar look - rounded corners,
shadow, dimmed backdrop - and open near the top of the window as
before. -
The journal and register tables have been tidied up (Arthur Cinader).
Digits in amounts are shown with equal width, so numbers line up neatly
in a column; column headers are small and muted rather than bold black;
and the zebra striping is replaced by a faint highlight on the row
under the pointer. #2718 -
The account sidebar now keeps its scroll position when you click an
account or navigate #2679 (Arthur Cinader). The sidebar and the
main content also scroll independently, on wider screens. -
Add the -? and --webman flags; rename --tldr to --examples (see hledger changelog).
-
hledger-web still opens the browser and exits two minutes after
its last page is closed, by default, for cleanup and security;
this is now done by a new implementation which fits better
with the Content Security Policy.
(Arthur Cinader, #2722) -
--port 0 lets the OS choose a free port #2559 (Arthur Cinader).
The chosen port is reported in the startup message and used in the
default base url, so scripts can discover it. This now works in the
default --serve-browse mode too, which previously required a fixed
port; the browser is opened at the chosen port. -
Changes to CSV rules files now trigger a reload, like changes to data
files (see hledger changelog). -
hledger-web no longer depends on the yesod-static and hjsmin
packages for serving its css, js and font files. This is
mainly a packaging fix: yesod-static doesn't build with crypton 1.1+,
which had kept hledger-web out of stackage nightly.
There is a behaviour change: static file urls no longer carry an
?etag=...suffix; instead browsers are told when their cached copy
is still good. -
The aeson lower bound has been relaxed from 2.3 to 2.2.5.1, the
oldest version not vulnerable to the HSEC-2026-0007 denial of
service, easing installation while the ecosystem catches up with
newer aeson. -
Exclude megaparsec 9.8.0, to avoid a position marker bug in error messages (megaparsec#572).
project changes 1.99.4
- The hledger repo has moved to the hledgerorg github
organisation: https://github.com/hledgerorg/hledger. Old
links redirect. #2681
Docs
-
ai.journal: updates
-
RELEASING: revise release script with lessons from the 1.52.2 release
-
AI: allow maintainer-discretion exceptions for hledger 1.x security fixes
-
ai.journal: switch to simpler t/kt/Mt output-token units; import June/July usage; other edits
-
AI: various edits and clarifications (extra usage notes, policy reference links)
-
ANNOUNCE: edits
-
CHANGELOGS: retired; superseded by RELEASING and changelogs/SKILL.md
-
CONTRIBUTING: added a developer quick start; fixed test and benchmark links #2528
-
CREDITS, .mailmap: various edits (headings, alignment, stats table; consolidated Alex Chen's commits; tidied committer names)
-
DECISIONS: updates
-
DEVFAQ, DEVWORKFLOWS, TESTS and other dev docs: updated for current tools, scripts and test suites; removed dead links; DEVFAQ now defers to install.md for build instructions #2528
-
examples/lots: merge and refresh the roi-vs-holdings comparison notes; cross-reference lots.journal and irr.journal
-
FUNDING: updated links
-
ghrelnotes: note the updated Windows binary; fix the eget command
-
hledger.conf.sample: edits
-
html: document builtin styling in the manual; sample hledger.css now demonstrates customising it
-
PULLREQUESTS, pull request template: many edits; link to the AI policy; first-time contributors' PRs may no longer use AI tools
-
REGRESSIONS: discontinue the regression bounties; other edits
-
release notes: fixed and simplified the binary install instructions - the mac/linux install command was discarding its download #2707, and the windows command now installs to a directory that can be on PATH; also noted what the install command needs, and updated the eget repo path
-
relnotes/changelog: AI usage section edits; fix a link
-
RELEASING: edits; consolidated to a single release script, grouped into phases
-
RULES: new doc gathering repo policies, old and new, in one place
-
SPEC-holdings: record decisions (future-dated postings stay included by default; XIRR's final cashflow is the displayed Value at the report date)
-
SPEC-lots: add a roadmap section for future work (per-account lot-tracking opt-out, tax boundary declarations, AVERAGE vs transfers, non-local-method coherence checks)
-
STYLE: new hledger-web doc recording the rules a change to the web UI's appearance should follow (no build step, nothing from a third party, no style attributes, how tabular and monetary data should read), for people and coding agents alike
-
examples: added lots/average.journal
-
README: dropped the gitscope.dev badges; that service is gone
Tools/infrastructure
- Changelog tooling improved:
just changelogsnow pre-cleans changelogs items (routine commits dropped, AI usage lines stripped, breaking changes lifted to the top, possible duplicates flagged); a stale resume point (eg after a rebase) is detected and reported with its fix; and a newjust changelogs-checkverifies resume points, issue links and leftover draft markers. Changelog section headings are simplified: Security, then Breaking changes, then topic or generic headings as needed. - CI: binaries-mac-arm64-hx, an experimental workflow using the hx build tool (an alternative to stack/cabal, for easier reproducible builds); cache the official cabal binary; build with -O1
- CI: bump most third-party actions to their latest major version; binaries-mac-arm64 bumped to macos-26-arm64; binaries-mac-x64 lists dependency versions like the others
- CI: the addon functional tests now run again (they had been accidentally excluded since 2017)
- CI: the hledger-web browser tests now run on pull requests, as a non-blocking check
- .gitignore, .ignore: stop tracking site/ under git entirely, but keep site/src/*.md (and the old manuals) visible to ripgrep/VS Code search via a new .ignore file
- hledger-web: added an on-demand Playwright browser test suite covering the web UI's client-side behaviour, runnable with
just browsertest - hledger-web: the favicon's vector sources and the standard-library script that regenerates the .ico from them are now committed, so the mark can be edited rather than redrawn
- Justfile: various
just ai-*AI-usage-reporting recipe tweaks;just holdings-*recipes for trying the holdings command against hledger/beancount/rledger example data;just installrel,just contribs*fixes; gitignore .hx; experimental hx build tool config - Release automation improved:
just ghrelnow assembles the github release on github (no local round trip for binaries) and creates it as a draft, withjust ghrel-publishmaking it public after review;just installpageautomates Install page version bumps;just generaloptionshelpautomates updating the general options help in the manuals; and the relbranch, reltags-push and ghbin-download recipes are more robust - Shake: changelogs: capitalise multi-line items' first lines and give them a trailing period, so they read as complete sentences; single-line items are left as written
- skills: add binary-badges skill, checking/refreshing the version badges in site/src/install.md; fix its red badge colour to match repology's hex
- skills: add release skill for assisting hledger releases
- skills: the changelogs skill was missing its YAML frontmatter, so it had no useful name or description to be matched against
- stack/cabal: ensure haskeline 0.8.4.1 is used, fixing the Windows build again #2410
- tools/aicommits: new script (plus
just ai-commits*recipes) to report AI usage parsed from commit messages' "AI usage:" trailers - tools/skills: add a credits skill documenting the CREDITS.md refresh process
- Shake changelogs: resume points rewritten by rebase/amend are now
auto-relocated (matching author date/author/subject), instead of
re-listing already-drafted commits; changelogs-catchup is rarely
needed now.
credits 1.99.4
Simon Michael,
Arthur Cinader,
Henning Thielemann,
Kevin F. Konrad,
Dmitry Astapov,
Juan Wajnerman,
Adam Sardo,
JoeJoeflyn,
Joshua Chapman,
Juliano Solanho,
Rostislav Raykov.
Install
The hledger Install page lists the easiest ways to install a recent release,
such as brew on macos, choco/scoop/winget on Windows, or eget on all platforms.
Or, follow these instructions to install the specific release binaries below:
GNU/Linux, 64-bit Intel
At the command line:
curl -fL https://github.com/hledgerorg/hledger/releases/download/1.99.4/hledger-linux-x64.tar.gz | tar -xzv -f- -C/usr/local/bin hledger hledger-ui hledger-web
hledger --version; hledger-ui --version; hledger-web --version # should show 1.99.4
Prefix tar with sudo if /usr/local/bin is not writable.
Mac, 64-bit ARM or Intel
Open a terminal window.
(Don't download these binaries with your web browser - they won't get authorised.)
On ARM macs:
sudo mkdir -p /usr/local/bin
curl -fL https://github.com/hledgerorg/hledger/releases/download/1.99.4/hledger-mac-arm64.tar.gz | sudo tar -xzv -f- -C/usr/local/bin hledger hledger-ui hledger-web
hledger --version; hledger-ui --version; hledger-web --version # should show 1.99.4
On Intel macs:
sudo mkdir -p /usr/local/bin
curl -fL https://github.com/hledgerorg/hledger/releases/download/1.99.4/hledger-mac-x64.tar.gz | sudo tar -xzv -f- -C/usr/local/bin hledger hledger-ui hledger-web
hledger --version; hledger-ui --version; hledger-web --version # should show 1.99.4
If the version check shows an older version, you have another hledger earlier in $PATH; which -a hledger will find it.
Windows, 64-bit ARM or Intel
In a powershell window (press WINDOWS-R, powershell, ENTER).
(Don't download the zip with your web browser - programs downloaded that way may be blocked when you run them.)
cd ~
curl.exe -fLO https://github.com/hledgerorg/hledger/releases/download/1.99.4/hledger-windows-x64.zip
Expand-Archive hledger-windows-x64.zip -Force -DestinationPath "$env:LOCALAPPDATA\Programs\hledger"
$env:LOCALAPPDATA\Programs\hledger (ie C:\Users\YOURNAME\AppData\Local\Programs\hledger) is not in $env:Path by default,
so if $env:Path doesn't show it, add it once:
[Environment]::SetEnvironmentVariable('Path', "$env:LOCALAPPDATA\Programs\hledger;" + [Environment]::GetEnvironmentVariable('Path','User'), 'User')
$env:Path = "$env:LOCALAPPDATA\Programs\hledger;$env:Path" # for this window; new windows will pick it up automatically
Then:
hledger --version; hledger-ui --version; hledger-web --version # should show 1.99.4
If the version check shows an older version, you have another hledger earlier in $env:Path; where.exe hledger will find it.
These are 64-bit Intel binaries; they also run on ARM machines (emulated).
They may also work on Windows 7:
use Windows Explorer to extract hledger-windows-x64.zip into a folder of your choice,
then open a command window (WINDOWS-R, cmd, ENTER) and run the hledger programs.
Next steps
Once installed, run hledger, and see the Docs.