I decided to create an example of a user-defined function magic-money-xf
<https://github.com/tesujimath/limabean/blob/main/examples/clj/user.clj#L15>
which
does what previously would have required a plugin.  Hopefully this will
provide insight for anyone thinking  a lack of plugins might be a
show-stopper.

This example function (a Clojure transducer) takes the fully resolved
directives which are produced by the booking algorithm, and inserts
additional directives as follows.  After every open directive, a new
transaction is inserted, adding money to the account from some magical
benefactor.  And before the first such open, the open directive for the
magical equity account itself is inserted.

Example use as follows, making use of small.beancount
<https://github.com/tesujimath/limabean/blob/main/examples/beancount/small.beancount>
:

kiri> limabean --beanfile examples/beancount/small.beancount
[Rebel readline] Type :repl/help for online help info
[limabean] 4 directives loaded from examples/beancount/small.beancount

user=> (require '[clojure.pprint :refer [pprint]])
user=> (pprint *directives*)

[{:date #object[java.time.LocalDate 0x6b283550 "2016-03-01"],
  :dct :open,
  :acc "Assets:Bank:Current"}
 {:date #object[java.time.LocalDate 0x357849a2 "2016-03-01"],
  :dct :open,
  :acc "Expenses:Groceries"}
 {:date #object[java.time.LocalDate 0xcda6100 "2023-05-29"],
  :dct :txn,
  :flag "*",
  :payee "New World",
  :postings
  [{:acc "Expenses:Groceries", :units 10.00M, :cur "NZD"}
   {:acc "Assets:Bank:Current", :units -10.00M, :cur "NZD"}]}
 {:date #object[java.time.LocalDate 0x21e896f6 "2023-05-30"],
  :dct :txn,
  :flag "*",
  :payee "Countdown",
  :postings
  [{:acc "Expenses:Groceries", :units 17.50M, :cur "NZD"}
   {:acc "Assets:Bank:Current", :units -17.50M, :cur "NZD"}]}]

Apologies for the lack of nicer output formatting for directives, but
hopefully you can see a couple of open directives followed by a couple of
transactions, matching what was in the input file
<https://github.com/tesujimath/limabean/blob/main/examples/beancount/small.beancount>
.

And here's where we make our new list of directives with the magical
money, using that magic-money-xf
<https://github.com/tesujimath/limabean/blob/main/examples/clj/user.clj#L15>
function.  Note that it's a new list, so must be passed in explicitly
instead of the default *directives* where we want this one.

user=> (def directives-with-magical-us (into [] (magic-money-xf {:units
1000.00M :cur "USD" :acc "Equity:Rich-American-Uncle"}) *directives*))
user=> (count directives-with-magical-us)
7

user=> (pprint directives-with-magical-us)
[{:date #object[java.time.LocalDate 0x6b283550 "2016-03-01"],
  :dct :open,
  :acc "Equity:Rich-American-Uncle"}
 {:date #object[java.time.LocalDate 0x6b283550 "2016-03-01"],
  :dct :open,
  :acc "Assets:Bank:Current"}
 {:date #object[java.time.LocalDate 0x6b283550 "2016-03-01"],
  :dct :txn,
  :postings
  [{:acc "Equity:Rich-American-Uncle", :units -1000.00M, :cur "USD"}
   {:acc "Assets:Bank:Current",
    :units 1000.00M,
    :cur "USD",
    :payee "magical benefactor"}]}
 {:date #object[java.time.LocalDate 0x357849a2 "2016-03-01"],
  :dct :open,
  :acc "Expenses:Groceries"}
 {:date #object[java.time.LocalDate 0x357849a2 "2016-03-01"],
  :dct :txn,
  :postings
  [{:acc "Equity:Rich-American-Uncle", :units -1000.00M, :cur "USD"}
   {:acc "Expenses:Groceries",
    :units 1000.00M,
    :cur "USD",
    :payee "magical benefactor"}]}
 {:date #object[java.time.LocalDate 0xcda6100 "2023-05-29"],
  :dct :txn,
  :flag "*",
  :payee "New World",
  :postings
  [{:acc "Expenses:Groceries", :units 10.00M, :cur "NZD"}
   {:acc "Assets:Bank:Current", :units -10.00M, :cur "NZD"}]}
 {:date #object[java.time.LocalDate 0x21e896f6 "2023-05-30"],
  :dct :txn,
  :flag "*",
  :payee "Countdown",
  :postings
  [{:acc "Expenses:Groceries", :units 17.50M, :cur "NZD"}
   {:acc "Assets:Bank:Current", :units -17.50M, :cur "NZD"}]}]

So now we have a new open directive for the magical equity account, and a
couple of new transactions, for those opening benefits.  If only the real
world worked like this!

Also:

user=> (show (journal))
2023-05-29  Expenses:Groceries   New World     10.00  NZD  10.00 NZD
2023-05-29  Assets:Bank:Current  New World    -10.00  NZD
2023-05-30  Expenses:Groceries   Countdown     17.50  NZD  17.50 NZD
2023-05-30  Assets:Bank:Current  Countdown    -17.50  NZD
:ok

user=> (show (journal :directives directives-with-magical-us))
2016-03-01  Equity:Rich-American-Uncle                        -1000.00  USD
 -1000.00 USD
2016-03-01  Assets:Bank:Current         magical benefactor     1000.00  USD
2016-03-01  Equity:Rich-American-Uncle                        -1000.00  USD
 -1000.00 USD
2016-03-01  Expenses:Groceries          magical benefactor     1000.00  USD
2023-05-29  Expenses:Groceries          New World                10.00  NZD
    10.00 NZD
2023-05-29  Assets:Bank:Current         New World               -10.00  NZD
2023-05-30  Expenses:Groceries          Countdown                17.50  NZD
    17.50 NZD
2023-05-30  Assets:Bank:Current         Countdown               -17.50  NZD
:ok

I find this facility to bring your own functions directly into the user
interface to be quite compelling. 😁

Apologies for the long post if I exceeded anyone's level of interest!

Full disclosure: this is all very new and really not yet stabilised.  The
behaviour I am showing off here is on the main branch of limabean
<https://github.com/tesujimath/limabean> but not in the most recent release
0.2.7.  So if you want to have a play, clone the repo, and read the docs on how
to run a development version
<https://github.com/tesujimath/limabean/blob/main/clj/doc/50-development.md>
(you'll need Clojure tools but not Rust).  But I'll probably be cutting
another release next week with this and some other improvements.

cheers,
Simon

On Sat, 28 Feb 2026 at 09:56, [email protected] <[email protected]>
wrote:

>
> I believe this approach makes sense in limabean because the user interface
> is a full-blown programming language, Clojure, and you can do whatever you
> need with the list of fully resolved directives that are exposed there
> after loading the beanfile.
>
>
> Makes sense.
> ​
>
>
> Plugins would justify their existence by a need to modify the transactions
> earlier, before the booking algorithm has run. Are there compelling use
> cases for this?
>
>
> Some examples: anything that opens
> <https://github.com/redstreet/beancount_reds_plugins/tree/main/beancount_reds_plugins/opengroup#readme>,
> closes
> <https://github.com/redstreet/beancount_reds_plugins/tree/main/beancount_reds_plugins/autoclose_tree#readme>,
> or renames
> <https://github.com/redstreet/beancount_reds_plugins/tree/main/beancount_reds_plugins/rename_accounts#readme>
> accounts. YMMV, of course.
> ​
>
> --
> You received this message because you are subscribed to the Google Groups
> "Beancount" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion visit
> https://groups.google.com/d/msgid/beancount/699b4206-605b-4baf-8df6-3fd0ecf8653cn%40googlegroups.com
> <https://groups.google.com/d/msgid/beancount/699b4206-605b-4baf-8df6-3fd0ecf8653cn%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/beancount/CAFhGSbt5EACKHdJpXXHL0%3D%3DVn0DieT1crzr7cD0UQ%3DqCUv_cXw%40mail.gmail.com.

Reply via email to