Closing the books by chat

A month-end in Biloh is a conversation. You hand the assistant a bank statement export and say what you want; it imports, matches deposits to invoices, settles bills, codes the rest, pairs your own transfers, checks the envelopes, closes the month and the quarter, and reads the BAS back on the ATO's labels. Each step is a tool with preconditions the assistant can read, every refusal names its reason, and nothing it does moves money at the bank. This page follows one such conversation from the first upload to the accountant's pack.

What does "by chat" mean here?

It means the assistant does the bookkeeping, not that it explains bookkeeping to you. Biloh exposes every finance action as a tool over MCP, each with a description an agent reads before calling it: what the tool is for, when not to use it, what it needs to be true first, and exactly which rows it will write. The assistant strings those tools together to do what you asked, and reads the results back in your words.

Below is one month, as the conversation runs. The operator's lines are what a real operator would type. The tool names are shown so a builder can follow along; the operator never needs them.

Week one: "Here's this week's statement"

"Import this statement into the everyday account."

The assistant calls list_bank_accounts to find the account and where its feed has got to, then import_bank_csv with the file and the account id. Before a single row is written, the import checks that the statement's implied opening balance chains onto the account's last known balance. If it does, every line lands and the assistant says how many. If it does not, the import is refused:

"That file doesn't chain onto the everyday account. The account's last balance is $1,472.30 and this statement starts from $1,745.30, so there is a $273.00 window missing between them. Export the days in between and I'll import both."

That is the balance chain at work, and it is why a month closed in Biloh is complete rather than assumed complete.

Week one, continued: "Match the deposits"

"Match this week's deposits to invoices."

triage_bank_feed in worklist mode returns every untriaged line with, for each deposit, ranked candidates: the outstanding invoices it could be paying, with the evidence for each (an invoice number printed in the bank text, an exact amount, a known payer alias) kept separate from any cautions. A candidate with a warning is never auto-suggested. The assistant confirms the clear ones with match_bank_credit_to_invoice, which records the payment on the bank's real value date and teaches the client's bank alias for next time, and asks you about the rest:

"Three deposits matched. One $990.00 deposit from a name I don't recognise matches the amount of two different invoices. Which is it, or is it neither?"

Full detail: reconcile money in.

Week two: "Code the spend"

"Code the rest. The $180 supermarket one is mostly personal but about $12.50 was cleaning supplies. The $1,540 to the window contractor is their August bill."

Three different tools, one sentence. The supermarket line becomes a split_bank_transaction with two typed splits, GST claimed only on the business part. The contractor line settles their recorded bill with settle_bill_with_bank_debit, releasing the payables it covers. Everything else is coded to a reporting category with triage_bank_feed in decide mode, and a repeat supplier gets a rule so next month it codes itself.

Then the paper. A receipt you photographed in the car park last Tuesday is sitting in the shoebox. suggest_shoebox_pairings offers it against the matching debit, you say yes, and its GST moves from "held out" to "claimable" on the quarter's BAS with no further action. See reconcile money out.

Week four: "Where are we?"

"How are the envelopes looking?"

get_envelope_targets answers with what should be in the tax set-aside (the open quarter's net GST plus your income-tax provision) and the contractor buffer (open payables plus the next six weeks of scheduled visits at each visit's contractor rate), what is actually there by the chained bank balance, and the gap. The assistant does not move money. You make the sweep at your bank, and when both accounts' statements are next imported the two halves are paired with match_transfer_pair and reach no report.

Month end: "Close September"

"Close September."

run_period_close with kind month. First it ties every bank line in the month by running balance; a break refuses the close and names it. Then it snapshots the month's cash figures into the close record and locks it. The assistant reads back received, GST collected, receipt count and outstanding AR, and whether the roll-up above it is now stale.

"And the quarter."

The same tool with kind quarter. If a child month is still open the close is allowed but the response says which, so nothing is silently unlocked.

If a payment turns up late, reopen_period with a required reason unlocks the month, you record the payment, and you close again. The reason is the audit trail. See close a month and a quarter.

Quarter end: "Do my BAS"

"What do I owe the ATO for July to September?"

get_bas_worksheet returns G1, 1A, 1B and the signed net position on the ATO's own labels, plus an exceptions list naming every purchase whose GST is held out of 1B for missing paper. The assistant reads it back field by field, so lodging in ATO Online services is copy-across.

"Generate the pack for my accountant."

generate_period_pack composes one ZIP: the Sales and GST and Purchases and GST reports as spreadsheets and print-ready PDFs, the BAS worksheet, the GST workings, the exceptions list, the cash P&L, the evidence bundle, and a manifest with a checksum for every file. Every figure in it is a read of the same library the live report uses, so the pack and the screen can never disagree. See prepare the BAS and the accountant pack.

Why can a context-free agent do this?

Because the tools are written for one. Each description carries the "use when" and "don't use when" cases in the operator's own phrases, the preconditions that must hold, and the side effects it will have. get_bookkeeper_worklist tells an agent whether there is anything new to work at all. search_tools finds a tool by intent. And every refusal returns a code and the figures that explain it, so the agent can tell you what to do next rather than what went wrong.

Biloh tests this claim rather than asserting it. Its own smoke runner hands a fresh agent a synthetic month of bank statements across three accounts and checks, to the cent, that the agent can bring the books to a closed quarter with the right BAS, and that every refusal above fires where it should.

Next steps

Last updated 2026-09-18