This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
Cashcast tells a small business which unpaid invoices are likely to be paid late, when each payment is likely to arrive, and how much cash to expect over the next eight weeks. It runs on your own laptop, so your client list and amounts stay with you.
It is built for people who send invoices and then wait: freelancers, small agencies, and the bookkeepers who manage receivables for several small clients. For them, late payment is not an abstract metric. It decides whether rent goes out on time and how much of the week goes into writing reminder emails.
Cashcast reads an invoice history (one CSV row per invoice: client, issue date, due date, amount, paid date) and, for every invoice still open, shows:
- the chance it will be paid late,
- a likely payment date with an 80% range, updated for how long the invoice has already been open,
- a suggested next step: contact today, send a reminder now, remind on the due date, or do nothing,
- the weekly cash you can expect from invoices already sent.
Who would pay for it, and why. Cloud accounting suites offer payment reminders and cash-flow views, but they expect the whole ledger in their cloud and a monthly subscription. Cashcast is a single-purpose tool that works on the CSV export people already have. A one-time license for freelancers, or a per-client fee for bookkeepers, is a plausible model, because the value is easy to state: fewer surprises in cash flow and less time spent chasing the clients who were going to pay anyway. Running the model locally is what makes a small one-time price workable, since there is no per-prediction API bill behind it.
Demo
Live demo (no install): https://starknightt.github.io/cashcast/
The live page is a replay. It uses IBM's public accounts receivable sample: 2,466 invoices from 100 business clients, 2012 to 2013, 36% of them paid late. Pick a date and you see what Cashcast would have told you that morning, using only invoices that had been paid before that date. Then tick Reveal what happened to put the real payment dates next to the predictions.
Things to try:
- Click Sep 1, 2013. 78 invoices are unpaid. Cashcast expects 4,327 to come in over the next four weeks (the sample has no currency). Tick Reveal what happened: 4,241 actually came in.
- Click Needs action to see only the invoices it suggests chasing, each with a one-line history computed from the data, for example "Paid 13 of 15 past invoices late, 36 days to pay on average."
- Scroll to Does it work? for the month-by-month backtest, including the result where TabPFN did not win.
Using it on your own invoices needs Python 3.10 or newer and works on a CPU. python -m cashcast.serve opens the same page in local mode with a file picker. The file goes from the browser to the Python process on 127.0.0.1 and nowhere else. On the bundled 404-row sample ledger, scoring takes about 7 to 9 seconds on my laptop CPU.
Code
StarKnightt
/
cashcast
Know which invoices will be paid late, and when the money will arrive. TabPFN on your laptop, client data stays local.
Cashcast
Know which invoices will be paid late, and when the money will arrive, before you chase anyone.
Cashcast is a small receivables tool for freelancers, small agencies and the bookkeepers who manage invoices for them. You give it your invoice history as a CSV. TabPFN, an open tabular foundation model, runs on your own laptop and tells you, for every unpaid invoice:
- the chance it will be paid late,
- a likely payment date with an 80% range, updated for how long the invoice has already been open,
- a suggested next step (contact today, send a reminder now, remind on the due date, or nothing),
- how much cash to expect in each of the next eight weeks.
Your client list and amounts never leave your computer.
Live demo: https://starknightt.github.io/cashcast/ (demo mode, no install)
Demo mode
The live page replays IBM's public accounts receivable sample (2,466 invoices from 100 business…
MIT licensed. The pipeline is about 660 lines of Python plus a static page with no build step:
cashcast/data.py load the IBM sample or any CSV into one schema
cashcast/features.py what was known on the day each invoice was sent
cashcast/model.py TabPFN v2 classifier and regressor
cashcast/forecast.py late chance, payment range, 8-week cash simulation
cashcast/backtest.py month-by-month test against four baselines
cashcast/demo.py replay data for the live page, scored against reality
cashcast/serve.py local mode (standard library HTTP server)
How I Built It
TabPFN does the predicting
TabPFN is a tabular foundation model from Prior Labs. It was pre-trained on millions of synthetic tables, so instead of training a model on your data, you hand it your table and it predicts in a single forward pass. For a small business with a few hundred or a few thousand invoices, that matters: there is no training loop to tune and nothing to babysit.
Cashcast uses two TabPFN v2 models on the same features:
- a classifier for "will this invoice be paid after its due date?",
- a regressor for "how many days until it is paid?", asked for 49 quantiles so it returns a full distribution per invoice rather than one number.
Features from the day the invoice was sent
The easiest way to fool yourself with this kind of data is leakage. The IBM sample includes columns such as DaysToSettle and Disputed that are only known after an invoice is settled, and using them makes the task look far easier than it is.
So features.py builds every row from what you knew on the day the invoice went out: how many of that client's invoices had already been paid, how often they were late, their average and most recent days to pay, how many of their invoices were still open, and how this amount compares with their usual. Invoices paid after the issue date are invisible to that row.
From a distribution to a decision
The regressor's quantiles are the useful part. An invoice that is still unpaid after 25 days is a different bet from one sent yesterday, so forecast.py conditions each distribution on the invoice's current age. From that it reads:
- the late chance, as P(paid after the due date | still unpaid today),
- the 10th, 50th and 90th percentile payment dates,
- 2,000 simulated payment schedules per date, summed per week, for the cash forecast.
The next-step labels are plain rules on top (overdue: contact today; 50% or more: reminder now; 30% or more: remind on the due date). The history line beside each invoice is computed, not generated, so it cannot state something the data does not support.
Did it work? A month-by-month backtest
For each month from January to October 2013, every model was trained only on invoices paid before that month began, then predicted the invoices sent during the month: 1,075 predictions in total. TabPFN on a CPU accepts up to 1,000 training rows by default, so each month uses the 1,000 most recent paid invoices.
| Model | AUC | Brier | Chase recall | Pay day error | 80% range hit |
|---|---|---|---|---|---|
| TabPFN v2 | 0.882 | 0.127 | 51.0% | 5.92 days | 79.1% |
| Logistic / linear regression | 0.890 | 0.122 | 50.4% | 5.81 days | 79.3% |
| Client's own history | 0.870 | 0.135 | 50.7% | 6.54 days | n/a |
| Gradient-boosted trees | 0.864 | 0.154 | 49.9% | 6.23 days | 57.5% |
| Base rate | 0.5 | 0.218 | 18.4% | 10.11 days | n/a |
"Chase recall" answers the business question: if you only chase the riskiest 20% of each month's invoices, what share of the late ones do you catch? Lower Brier and pay day error are better.
The honest reading: on this dataset, a plain logistic and linear regression is as accurate as TabPFN. I expected TabPFN to win clearly, and it did not. It does clearly beat gradient-boosted trees trained on the same rows, whose 80% ranges caught the real payment date only 57.5% of the time.
The probabilities are well calibrated. Of the 586 invoices TabPFN put below 20%, 8.7% were paid late (it predicted 6.2% on average). Of the 116 it put above 80%, 90.5% were (it predicted 87.4%).
Where TabPFN earns its place
A linear model with a residual band gives every invoice the same width of uncertainty. TabPFN gives each invoice its own distribution. To test whether that matters, I split clients into thirds by how much their past payment times varied:
| 80% range | Steady clients | Middle | Erratic clients |
|---|---|---|---|
| TabPFN | 80.5% hit, 16.0 days wide | 83.3%, 17.7 days | 73.3%, 19.9 days |
| Linear | 83.8% hit, 18.4 days wide | 84.2%, 18.5 days | 69.7%, 18.4 days |
TabPFN narrows the range for reliable payers and widens it for erratic ones, which is what you want, but the effect is modest and both under-cover the erratic third. The distribution is also what lets Cashcast answer "this invoice is 20 days old and still unpaid, now what?" without a separate model.
Checking the replay itself
The numbers on the live page were scored against what really happened (10 dates, 905 unpaid-invoice rows):
- Of 296 "send a reminder now" flags, 78% were in fact paid late. Among all not-yet-due invoices on those dates, 43% were.
- The real payment date fell inside the 80% range 77.1% of the time, with a typical miss of 5.78 days.
- The weekly cash forecast is the weak spot: the actual amount landed inside its 80% range in only 67.5% of 80 weeks. The simulation treats invoices as independent, so the range is too narrow.
- Each date takes about 40 seconds on a laptop CPU (classifier plus regressor on 1,000 rows).
What it still cannot do
- The sample contains only invoices that were eventually paid, so Cashcast has never seen an invoice that is written off.
- Every invoice in the sample has 30-day terms, so the effect of other terms is untested.
- It suggests whom to contact; it does not send anything.
- The live page is a replay of a public dataset. Before trusting it on your own ledger, run the same backtest on your history (
python -m cashcast.backtestshows how).
Why Does Open Innovation Matter?
It keeps the client list at home. An invoice ledger is a list of who pays you, how much and how reliably. With open weights, Cashcast runs on the laptop that already holds that file. The local server binds to 127.0.0.1, and after the one-time weight download, scoring still works with all network traffic blocked (I tested it by routing every request to a dead proxy).
It makes a small, cheap product possible. A one-time-license tool cannot carry a per-prediction API bill. Open weights mean the marginal cost of a forecast is a few seconds of CPU.
The license has to allow selling it. Prior Labs recommends its newest model, TabPFN-3.5, through its API under a free non-commercial license. That is a fine choice for research, but a side hustle is commercial by definition. TabPFN v2 weights are published under the Prior Labs License 1.1 (Apache 2.0 with an attribution requirement, which is why the page says "Built with PriorLabs-TabPFN"), download from Hugging Face without an account, and run offline. For this product, the openness of the license mattered as much as the openness of the weights. The trade-off is that I may be leaving accuracy on the table by not using the newest model.
Openness made the evaluation possible. Because the model, the data and the code are all inspectable, I could run every baseline on exactly the same rows and publish the result where TabPFN did not win. A black-box API would have given me a number to trust instead of a number to check.
Prize Categories
Best Use of TabPFN. TabPFN does all of the predicting in Cashcast. A TabPFN v2 classifier estimates the chance each invoice is paid late, and a TabPFN v2 regressor returns a 49-quantile distribution of days to payment, which Cashcast conditions on invoice age to produce payment ranges, reminder decisions and an eight-week cash simulation. It is tested month by month against four baselines on 1,075 invoices, with calibration and per-client range checks, and the results, including where a linear model matched it, are published in the repository and on the live page.




Top comments (0)