# 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.

URL: https://biloh.com.au/docs/explanation/closing-the-books-by-chat
Category: Explanation | Audience: operator | Updated: 2026-09-18

## 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](/docs/concepts/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](/docs/how-to/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](/docs/how-to/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](/docs/how-to/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](/docs/how-to/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

- Try it yourself: [close your first month](/docs/getting-started/close-your-first-month).
- The engine's scope and honesty statement: [the finance engine overview](/docs/explanation/finance-engine-overview).
