How/why was hledger started ?

I (Simon Michael) discovered John Wiegley's Ledger in 2006, and was very happy to find this efficient command-line reporting tool with a transparent data format.

Initially, I used it to generate time reports for my job. Before long I wanted that to work differently - splitting sessions at day boundaries, reporting in hours, etc. John had got busy elsewhere and the Ledger project now stalled, with unfixed bugs, wrong documentation and a confusing release situation persisting for a long time. I did what I could to help build momentum, reporting bugs, supporting newcomers, and contributing a new domain and website. But, I didn't want to spend time learning C++.

I was learning Haskell, which I did want to spend time in. I felt Ledger could be implemented well and, in the long run, more efficiently in that language, which has some compelling advantages such as lower maintenance costs. I urgently needed a reliable accounting tool that I enjoyed using. I also wanted to see what I could do to reduce roadbumps and confusion for newcomers.

I couldn't expect John to start over - at that time he was not the Haskell fan he is now! So in 2007 I began experimenting. I built a toy parser in a few different languages, and it was easiest in Haskell. I kept tinkering. Goals included:

Before too long I had a tool that was useful to me. With Ledger still installed, and by maintaining high compatibility, I now had two tools with different strengths, each providing a comparison for the other in case of confusion or suspected bugs, which was itself quite valuable.

The Ledger project later revived and has attracted new active contributors. I have remained active in that community, sharing discoveries and design discussions, and we have seen many ideas travelling in both directions. hledger shared #ledger's IRC channel until 2014, when I added #hledger to allow us more space.

I think having independent but compatible implementations has been quite helpful for troubleshooting, exploring the design space, and growing the "Ledger-likes" community. My other projects in that direction include the ledger-cli.org site, LedgerTips, IRC support on #ledger, and now plaintextaccounting.org.

Comparisons with other ledgerlikes



Compared to Ledger, hledger builds quickly and has a complete and accurate manual, an easier report query syntax, multi-column balance reports, better depth limiting, an interactive data entry assistant, and optional web and curses interfaces.

Compared to hledger, Ledger has additional power-user features such as the built in value expressions language, and it remains faster and more memory efficient on large files (for now).

We currently support:

We do not yet support:

And we add some new commands, such as:

File formats

hledger's journal file format is very close to Ledger's. Some unsupported Ledger syntax is parsed but ignored; some is not parsed and will cause an error (eg value expressions). There can also be subtle differences in parser behaviour, such as with hledger comments vs Ledger comments, or balance assertions.

It's quite possible (and useful) to keep a journal file that works with both hledger and Ledger, if you avoid the more exotic syntax. Or, you can keep the hledger- and Ledger-specific bits in separate files, which include a common file compatible with both:

$ ls *.journal
common.journal   # included by:

Functional differences

The "ledger4" parser

ledger4 is John's 2012/2013 rewrite of some parts of Ledger 3, including the parser, in Haskell. We added this to hledger for a while, hoping to attract contributions to improve this "bridge" between the projects, and improve our support for reading Ledger's files. Neither happened, so it was removed.

hledger CLI

With multiple commodities, output looks weird; why are some amounts shown with no account name ?

When hledger needs to show a multi-commodity amount, each commodity is displayed on its own line, one above the other (like Ledger).

Here are some examples. With this journal, the implicit balancing amount drawn from the b account will be a multicommodity amount (a euro and a dollar):

    a         EUR 1
    a         USD 1

the print command shows the b posting's amount on two lines, bottom-aligned:

$ hledger -f t.j print
    a         USD 1
    a         EUR 1
             EUR -1  ; <-
    b        USD -1  ; <- a euro and a dollar is drawn from b

the balance command shows that both a and b have a multi-commodity balance (again, bottom-aligned):

$ hledger -f t.j balance
               EUR 1     ; <-
               USD 1  a  ; <- a's balance is a euro and a dollar
              EUR -1     ; <-
              USD -1  b  ; <- b's balance is a negative euro and dollar

while the register command shows (top-aligned, this time!) a multi-commodity running total after the second posting, and a multi-commodity amount in the third posting:

$ hledger -f t.j register --width 50
2015/01/01       a             EUR 1         EUR 1
                 a             USD 1         EUR 1  ; <- the running total is now a euro and a dollar        
                                             USD 1  ;                                                        
                 b            EUR -1                ; <- the amount posted to b is a negative euro and dollar
                              USD -1             0  ;

Newer reports like multi-column balance reports show multi-commodity amounts on one line instead, comma-separated. Although wider, this seems clearer and we should probably use it more:

$ hledger -f t.j balance --yearly
Balance changes in 2015:

   ||           2015 
 a ||   EUR 1, USD 1 
 b || EUR -1, USD -1 
   ||              0 

You will also see amounts without a corresponding account name if you remove too many account name segments with --drop:

$ hledger -f t.j balance --drop 1
               EUR 1  
               USD 1  
              EUR -1  
              USD -1  

File formats

Journal format

Why does this entry give a "no amount" error even though I wrote an amount ?

  a 1

Because there's only a single space between a and 1, so this is parsed as an account named "a 1", with no amount. There must be at least two spaces between account name and amount.

Why do some directives not affect other files ? Why can't I put account aliases in an included file ?

This is documented at journal format: directives. (Also mentioned at hledger: Input files.) These docs could be improved.

Directives which affect parsing of data vary in their scope, ie the area of input data they affect. Eg, should they affect:

The differences are partly due to historical accident, and partly by design. We would like to preserve these properties:

This is why some directives are designed to last only until the end of the current file. This can be annoying, but it seems worthwhile to ensure reports are robust, and not changed by simply moving include directives or -f options around.

For alias directives, when you have multiple files, the workaround is to put them inline in a top-level file, before including the other files that the aliases should affect. See #1007.

See also: #510, #217

Other software


Why does Shift-Up/Shift-Down move the cursor instead of adjusting the period in hledger-ui ?

One way to fix: in iTerm2 do Preferences -> Profiles -> your current profile -> Keys -> Load Preset -> xterm Defaults (not Terminal.app Compatibility). And perhaps open a new tab with this profile.