beanschedule plugin and import hook

68 views
Skip to first unread message

Tim Tickner

unread,
Feb 7, 2026, 12:04:10 PM (13 days ago) Feb 7
to Beancount
Hi all - 

I wanted to share a scheduled transaction repo I've been vibe coding as I learned Beancount over the past few months. It's still a work in progress but I've been using it consistently.

beanschedule provides two primary features: a plugin for forecasting scheduled transactions and a hook for augmenting imported transactions.

Every schedule is defined as a yaml file with match logic, recurrence rules, and expected postings. Currently, the only "dynamic" posting is loan amortization which would include accounts like Interest and Principal; the basic match is just a cost range.

Beangulp Import Hook
If you use the import hook, then imported transactions will be matched with metadata and postings applied. Missing schedules are logged as part of the beangulp logging.

Schedules Plugin
If you use the plugin, then forward looking transactions are added to the ledger in the same style as the `beanlabs.plugins.forecast.py` transactions with a `#` flag. I currently have this commented out most of the time because past forecasted transactions (e.g. the transaction hasn't posted yet) will mess with balance assertions, but it can be helpful to see cash flow (obviously, doesn't capture non-scheduled transactions).

CLI
Beanschedule provides a CLI, `beanschedule`, with a few commands for viewing loan amortization, detecting existing recurring transactions, summarizing configured schedules, and a few more commands (see the docs and code).

Roadmap
The roadmap is mostly administrative, specifically improving the formatting and making the repo more Ruff-compliant.

--- 

This is my first "real" open repo so I'd love to get any feedback! I'd love feedback on the repo, documentation, or feature requests! I know there are some similar implementations and some of the stuff that's been built here may not be super beancount-esque, so I'd love to hear about how I can improve the style. To be clear, this is heavily vibe coded, I don't want to claim credit for most of the code, but wanted to share with the community in case something like this is helpful for someone else.

It's very much a set-and-forget library, once schedules are onboarded, it's a pretty easy maintenance process.

---

Thanks all!
Tim

Mario Župan

unread,
Feb 7, 2026, 2:26:39 PM (13 days ago) Feb 7
to bean...@googlegroups.com


Respect! Watching your git repo. I'll try for sure. Right now I'm
collecting beancount posting examples and making a dataset for llm
training.



On Sat Feb 07, 2026 at 18:04, Tim Tickner wrote:
> Hi all -
>
> I wanted to share a scheduled transaction repo I've been vibe coding as I
> learned Beancount over the past few months. It's still a work in progress
> but I've been using it consistently.
>
> beanschedule <https://github.com/slimslickner/beanschedule> provides two
> some *similar* implementations and some of the stuff that's been built here
> may not be super beancount-esque, so I'd love to hear about how I can
> improve the style. To be clear, this is *heavily vibe coded*, I don't want
signature.asc

Martin Blais

unread,
Feb 7, 2026, 2:32:01 PM (13 days ago) Feb 7
to bean...@googlegroups.com
Thanks for sharing, added to the contribs doc.


--
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 beancount+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/beancount/0d2b86cc-be4e-4dc0-b3ec-5dceba0d639en%40googlegroups.com.

Chris Jansen

unread,
Feb 16, 2026, 4:15:27 PM (4 days ago) Feb 16
to Beancount
Thanks for creating and sharing this Tim! I spent some time trying to get it to work for me. The initial create command worked well on my ledger. I culled through it and arrived at a minimum set of 13 to play with. They all pass CLI beanschedule validate, but the schedule plugin fails in a couple of spots:

  1. The docs indicate that multiple postings with amount:null are valid (schedules/rent.yaml example). This made sense to me for double-entry bookkeeping when there are two postings. The code doesn't support it though ("At most one posting can have a null amount (the balancing posting).": https://github.com/slimslickner/beanschedule/blob/c160278ee3ffab5c5af32db98a90750d54be4382/beanschedule/plugins/schedules.py#L543 As a side note, the subsequent check on line 552 isn't going to catch postings with more than one null amount since that will be caught by the previous check.
  2. I set up two amortized accounts with postings for payment, principal, escrow and interest, but I get an error: "For amortization schedules, postings with 'amount: null' must have an explicit 'role' field. Valid roles: 'payment', 'interest', 'principal', 'escrow'. See POSTING_ROLES.md for details." Another side note here - I could not find POSTING_RULES.md. :-)

Tim Tickner

unread,
Feb 16, 2026, 5:07:46 PM (4 days ago) Feb 16
to Beancount
Chris - thanks for sharing your experience here. I have two thoughts:
  1. Claude went kinda nuts and didn't clean up old code. The call out of the check on line 552 is absolutely correct. There's a lot of "old" code that can and should be cleaned up. I have this on my todo list - to basically "un-AI" it.
  2. For amortization, there are two ways to set it up: static and stateful, which are mostly effectively explained here. Agree that POSTING_ROLES.md is not there and that's a gap in documentation, there also doesn't seem to be very good documentation in the code for how the amortization roles work (sorry!). Can you see if my example below is helpful for now?
Here's my mortgage schedule yaml:
id: loan-123-main-st
enabled: true
match:
account: Assets:Banking:Checking:Joint-Ally-Spending
payee_pattern: Chase Bank
amount_tolerance: 0.0
amount_min: null
amount_max: null
date_window_days: 5
recurrence:
frequency: MONTHLY
start_date: 2024-01-01
end_date: null
day_of_month: 4
amortization:
payment_day_of_month: 1
balance_from_ledger: true
annual_rate: 0.055
monthly_payment: 2310.25
compounding: MONTHLY
transaction:
payee: Chase Bank (Mortgage)
narration: Mortgage Payment
tags:
- property-123-main-st
metadata:
schedule_id: loan-123-main-st
property: 123-main-st
postings:
- account: Assets:Banking:Checking:Joint-Ally-Spending
amount: null
narration: null
role: payment
- account: Expenses:House:Escrow
amount: 323.31
narration: Escrow
role: escrow
- account: Expenses:House:Mortgage-Interest
amount: null
narration: Mortgage Interest
role: interest
- account: Liabilities:Loans:Mortgage:123-Main-St
amount: null
narration: Mortgage Principal
role: principal
missing_transaction:
create_placeholder: true
flag: "!"
narration_prefix: "[MISSING]"

and the beanschedule amortize loan-123-main-st --ledger main.bean command returns this:

INFO: Loading schedules from directory: schedules

INFO: Loaded 45 schedules (44 enabled) from directory: schedules

Schedule: loan-123-main-st

Mode: Stateful (balance from ledger)

Liability Account: Liabilities:Loans:Mortgage:123-Main-St

Balance as of 2026-02-03: $321,494.23

Interest Rate: 5.500% (MONTHLY)

Monthly Payment: $2,310.25

Forecast Horizon: 12 months (12 payments)


Total Interest: $20,685.41

Total Principal: $7,037.59

Total Paid: $27,723.00

Interest/Principal Ratio: 293.9%


   #         Date      Payment    Principal     Interest        Balance

-----------------------------------------------------------------------

   1   2026-03-01 $   2,310.25 $     571.83 $   1,738.42 $   378,720.07

   2   2026-04-01 $   2,310.25 $     574.45 $   1,735.80 $   378,145.62

   3   2026-05-01 $   2,310.25 $     577.08 $   1,733.17 $   377,568.54

   4   2026-06-01 $   2,310.25 $     579.73 $   1,730.52 $   376,988.81

   5   2026-07-01 $   2,310.25 $     582.38 $   1,727.87 $   376,406.43

   6   2026-08-01 $   2,310.25 $     585.05 $   1,725.20 $   375,821.38

   7   2026-09-01 $   2,310.25 $     587.74 $   1,722.51 $   375,233.64

   8   2026-10-01 $   2,310.25 $     590.43 $   1,719.82 $   374,643.21

   9   2026-11-01 $   2,310.25 $     593.14 $   1,717.11 $   374,050.07

  10   2026-12-01 $   2,310.25 $     595.85 $   1,714.40 $   373,454.22

  11   2027-01-01 $   2,310.25 $     598.58 $   1,711.67 $   372,855.64

  12   2027-02-01 $   2,310.25 $     601.33 $   1,708.92 $   372,254.31

Note that the amortization calendar specifically excludes escrow, so the escrow amount would be added as a posting in addition to principal, interest, and the paying account.

Give me some time this week and I'll follow up when this has been cleaned up a bit. I can also include some better unit tests for amortization and leverage the example schedules in the unit tests. The next version has support for one-time transactions (e.g. I just went to Costco and want to write out all my splits now, then merge that with an imported transaction when that comes in a few days). I'll make sure to include some readme cleanup and some of my use cases in that release too.

Thanks,
Tim

Chris Jansen

unread,
Feb 16, 2026, 5:48:36 PM (4 days ago) Feb 16
to Beancount
Thanks for the mortgage example, I set my escrow to a specific amount instead of null and it works now. I'm looking forward to updates!
Reply all
Reply to author
Forward
0 new messages