Last update: September 25, 2010

Welcome to the umm web site!

What's umm? It's Uwe's Money Mangler — errr, Manager! umm is a tiny, minimal, command-line accounting program. I was motivated to write it by a couple of things: I had been using Quicken from Intuit for some years, and that had an annoying failure mode every so often: an upgrade of computer hardware or OS would cause Quicken to not run anymore, and some years of my data would thus be trapped in a binary blob and lost. I'd chuck the whole thing in frustration and stop keeping track of this (really rather important) stuff for a year or two, and then I'd start over again. Not ideal!

So... eventually I got tired of this, and I decided to try something different. I had looked at gnucash, but the last time I looked at it I was frankly intimidated... huge, with lots of dependencies — although it's open-source, it was not going to be as simple as I wanted. Recently I came across ledger and its haskell remix hledger, and I looked at those. But there were a couple of minor things I didn't like so much, and there were a couple of features I wanted that they were missing, and anyway I needed a hacking project, so I decided to just take the idea and write my own: umm.

Design Criteria

The design criteria for this little program were fairly simple:

A few specific things I wanted the program to do:

If you prefer a more GUI-oriented program, you should probably look elsewhere... but if you think this might work for you, then read on.


Quick Links

Build umm from Source

You'll need a working haskell compiler for this. I've used ghc 6.8.3 on an old iMac G3 running OSX 10.3.9 (my main development platform, actually — if it works here & performs ok, it'll be fine everywhere else...), ghc 6.10.{1,3,4} on x86 running a slightly out-of-date version of Ubuntu Linux, and ghc 6.10.3 on Windows XP. I've also tried ghc 6.12.1, but I haven't fully upgraded all the libraries, so that didn't work. But I don't anticipate any significant problems once libraries and cabal are updated.

Grab the source, above, unpack it, chdir into the source directory, then run

         cabal configure && cabal build

or

         ghc -O2 --make -o umm UMM*.hs

"Install" umm

Whether you built as per above, or you downloaded one of the pre-built versions,
just move the umm executable to wherever you want, and you're good to go!

A Bit of Terminology

A Couple of Small Examples

Here's a complete small ledger file. See also sample1.dat in the source tarball, slightly tweaked from this to test some currency symbols.

        ccs US$ "The Almighty Buck"

        income cash
        income interest
        expense cash

        account acc1 2009-9-1 "test account 1"
        account acc2 2009-9-1 "test account 2"

        group all acc1 acc2

        ccs FOO "The Foo Companies"
        ccs BAR "The Bar Companies"
        ccs CLAM "Groupe Mollusque"

        xfer 2009-9-1 cash acc1 100
        buy 2009-9-1 acc1 10 FOO 15
        xfer 2009-9-2 interest acc1 0.25
        buy 2009-9-2 acc1 20 FOO 27
        xfer 2009-9-3 acc1 cash 5.25

        xfer 2009-9-1 cash acc2 100
        buy 2009-9-1 acc2 10 BAR 25
        xfer 2009-9-2 interest acc2 0.25
        buy 2009-9-2 acc2 20 FOO 27
        xfer 2009-9-3 acc2 cash 5.25
        xfer 2009-9-4 acc1 acc2 25

        xfer 2009-9-5 cash acc1 200
        buy 2009-9-5 acc1 30 FOO 40
        buy 2009-9-5 acc1 30 BAR 40

        price 2009-9-5 FOO 1.5

        xfer 2009-9-6 cash acc1 20 CLAM

        price 2009-10-21 FOO 2.1
        price 2009-10-24 FOO 2.4
        price 2009-10-25 FOO 2.5
        price 2009-10-23 FOO 2.3
        price 2009-10-22 FOO 2.2

        price 2009-10-25 BAR 3.25
        price 2009-10-27 3 BAR 10

        split 2009-11-5 CLAM 2 1
        price 2009-11-11 CLAM 0.001

Overview of Commands

You run the program like so:

         umm ledger-file command options

where command options is one of the following

The commands may be shortened to the unique prefixes or anything longer: 'bal', 'bala' etc, 'reg', 'regi' etc, but not 'r'.
If no command or options are specified, the default action is to show the balances of all accounts as of the current date.

account is the name of an account, account-or-group is the name of an account or an account group,
and account-or-pseudo-account is the name of an account or an income or expense pseudo-account.

ccs is the name of a currency, commodity, or security.

date defaults to the current date if not specified.

date-range specifies the range in which the operation should show results. There are several ways to specify a date range:

Overview of Records

still under construction — see the actual program, which does have a description of each record type in its help listing.

umm is line-oriented, with each line of the ledger file forming a separate record. There are about a dozen types of records in a ledger, (mostly) indicated with keywords:

Blank lines are also treated as comments, and leading and trailing whitespace in any line is ignored. Also, all combinations (or mixtures) of <CR> and <LF> characters are accepted as line-end markers, so there should be no portability issues between *nix and windows systems — the intent is that it should Just Work... if it doesn't, shout at me!

Internally, not all of these are distinct: buy and sell are just syntactic sugar for exch, and birthday and anniversary are more or less syntactic sugar for todo, but you probably don't need to worry about that unless you want to hack on umm. Also, internally there is another type of record, for indicating parsing errors. These get printed out as

    #err ccs 123bux

New in version 0.1.5 is the second form of the xfer record: this allows specifications of multiple transfers from one source account to multiple target accounts as one transaction. This is to do things like specifying that a part of my salary goes to my savings account, a part goes to my 401(k), etc. I don't have as compelling a use case for the corresponding merge, ie multiple source accounts to one target account, so I haven't implemented that.

Since split-transfer transactions can get somewhat long, I've also added, as of version 0.1.5, the ability to split a record across multiple lines, like this:

    xfer 2038-1-19 salary {savings 100 GalCred,\
        \ retirement 20 GalCred, taxes 80 GalCred}

The effect is to merge the two lines and annihilate the two backslashes and all the whitespace between them. Because there are two backslashes, you have exact control over other whitespace outside the backslashes; thus, this allows you to break a line in the middle of a string or indeed in the middle of an account or ccs name. This is not necessarily a good idea... don't abuse it.

Also, because of the order in which various operations get done inside the program, in order to comment out the above, you would need to add just one '#' at the beginning of the first line only:

    # xfer 2038-1-19 salary {savings 100 GalCred,\
        \ retirement 20 GalCred, taxes 80 GalCred}

However, in accordance with DWIM, the program will also accept

    # xfer 2038-1-19 salary {savings 100 GalCred,\
    #    \ retirement 20 GalCred, taxes 80 GalCred}

New in version 0.2.0 is the optional periodic prefix for xfer, buy, sell, and exch records. This is a way to indicate that the transaction is repeated multiple times at regular intervals. This is useful for tracking regular payments, or automatic transfers of money into an investment account, etc. I'm not quite sure that it's as useful for buying and selling stuff, since presumably usually the price will vary depending on market conditions, but I've added it anyway. There may possibly be a use for it with a todo record, but I can't think of any reason why any of the other record types would need this modifier... see the next paragraph for essentially periodic todo records, albeit only with a period of 1 year.

New in version 0.2.1 are the birthday and anniversary records. These aren't quite financial, but it seemed to me that they are related enough, certainly in the periodic-reminder aspect, that it made sense to add them. They act pretty much like todo records, except that (i) they only trigger in a period of one week on either side of the specified date, and (ii) the print format is ever so slightly different: the year is not included in the printout.

New in version 0.3.1 is the periodic version of todo records. I decided that it makes sense to do these. They don't quite act in the same way the birthday and anniversary records do, in that old todo records which were generated from a periodic spec will continue to show up until they are reconciled; so if you have a periodic reminder to pay the rent, and you don't mark that as reconciled for a couple of months, you'll see multiple instances of it. On the other hand, maybe that's not such a bad thing...

The structure of the periodic prefix is as follows:

    recurring period until end-date [reconciled rec-date]

where recurring, until, and reconciled are literal keywords, end-date and rec-date are dates in the usual format, and period is one of the following:

daily every day
weekly every week, ie, every 7 days
monthly every month
quarterly every 3 months
annually every year
biweekly every 2 weeks, ie, every 14 days
bimonthly every 2 months
biannually every 2 years
semiweekly twice a week, at D and D+3
semimonthly twice a month, at D and D+15
         semiannually          every 6 months
N days
N weeks
N months
N years

The start date of the series is taken as the date in the base record. To generate the series, this start date is stepped by the period and records are generated as long as the stepped date is not later than the specified end date. The generated records are marked as reconciled if they are before the rec-date, and unreconciled if after. If that's not specified, then internally the rec-date is set to "the beginning of time" which means that none of the generated records are marked reconciled.

For example, here is a complete xfer record describing a transfer of $100 from a checking account to an investment account every other Friday for all of 2010 (and please ignore the fact that January 1, the start date, was a holiday):

    recurring biweekly until 2010-12-31 reconciled 2010-5-1 \
        \ xfer 2010-1-1 checking invest 100

Note that since the periodic modifier is longer than the record itself, I've used split-line notation here, and in fact umm will do this automatically: when printing periodic records like the above, it will always show them in the above split-line form.

Brief Overview of Code, for Hackers

There are six modules:

Main UMM.hs this is the main routine, plus most of the IO stuff
UMMData UMMData.hs definitions of the various data types, plus routines to show them, plus a couple of utility routines
UMMParser     UMMParser.hs     parsers for records, commands, dates — all built on Parsec, very easy to understand (if I do say so myself)
UMMPlot     UMMPlot.hs     code to very minimally exercise gnuplot — there are modules on hackage that do very nice graphing, but this is part of keeping this self-contained
UMMEval UMMEval.hs the main routines for processing records
UMMHelp UMMHelp.hs one long string which is the help message

Overall, it's about 2400 lines of code. The parser is pretty much all standard Parsec, and the help file is basically just a large string constant; so, leaving those out, there's not a huge amount of code to dig into.

Summaries of changes

Version 0.1.0 unleashed upon an unsuspecting world on 2009-11-18... muahahaha! Look out, Intuit, here I come! :-)

Version 0.1.1 released on 2009-11-22: added support for UTF-8 encoded Unicode currency symbols, plus made the date optional in an account record.

Version 0.1.2 released on 2009-11-27: turned check number into a more-general ID (first user-contributed patch — thanks, Nicolas!), plus added an optional "initial price" to ccs records. There's also a contributed vim syntax-highlighting mode from Nicolas!

Version 0.1.3 released on 2009-11-29: no changes in functionality, just made it -Wall-clean.

Version 0.1.4 released on 2009-12-05: wrote basis command, partially-working export command to write out data in ledger format, cleaned up a bunch of hlint suggestions.

Version 0.1.5 released on 2009-12-19: added code to allow records to continue across multiple lines if desired, and allow split-transfer records: in one transaction, transfer multiple chunks of loot from one source account to multiple destinations.

Version 0.1.6 released on 2010-01-18: added the ability to specify an optional initial amount in an account, plus work on price translation: specify ccs as either basic or derived, and allow specification of the base ccs into which any given derived ccs is to be translated.

Version 0.1.7 released on 2010-03-20: fixed a small bug in the reporting of split xfer transactions: although the amounts were all always correct, the transaction wasn't always printed properly.

Version 0.2.0 released on 2010-05-02: added recurring transactions.

Version 0.2.1 released on 2010-05-09: added significantly better date range specification, plus birthday and anniversary records, plus a few small cleanups here & there — for one, the reporting of split xfer transactions still wasn't quite right.

Version 0.2.2 released on 2010-06-13:

Version 0.3.0 released on 2010-07-11: plot command now works for accounts as well as price data — see sample 1 or sample 2 — and X axis is properly formatted as time data.

Version 0.3.1 released on 2010-09-25:


If you have questions or comments about the stuff here, please contact me at korg@korgwal.com.

Enjoy! -- Uwe Hollerbach

Page last modified at 2010-09-25 11:30 US/Pacific

Valid HTML 4.01 Transitional