Before you start — this skill works with or without Mosofin
With Mosofin connected, the skill reads your live accounting data through the gateway: the figures come from your own books, it validates against the real chart of accounts, and most steps run automatically.
Without it, the skill still works. No subscription, no connector, or a skill copied on its own — you are not blocked and you are not asked to buy anything first. The Mosofin gates are skipped and you are asked for what each step needs instead: a trial balance, a statement, an export, the documents themselves. The accounting logic, the edge cases and the output standards are identical — only where the numbers come from changes, and the output always says which is which.
You choose, and you are asked. Where a connection exists, the skill asks at the start whether to use it for this run or whether you would rather supply the data yourself — a connected gateway is not taken as consent to read your books. Say no and it runs manually without asking again.
Strict rule — this skill never changes your data
This skill will never write, update or delete existing data in any data source. Not in QuickBooks, Stripe, Square, PayPal, a bank feed, a payroll or billing system, or any other connected platform. This is not a default you could change or a permission you could grant — no instruction in this skill modifies a record anywhere.
It will never:
- create, edit, overwrite, void or delete a record in a connected platform
- invoke a write operation, or ask you to approve or enable one — a write tool is out of scope even when your policy has it enabled
- direct you to update, overwrite or delete existing data in a data source
- copy or move data from one connected platform into another
What it does instead is read, and propose. Every entry, schedule, reconciliation and document it produces is a draft for you to review. Where it finds a problem — a duplicate, a mismatch, a stale balance — it describes the problem and proposes a correcting entry as a draft. It does not tell you to delete or overwrite the original, and it never acts on one itself.
Whether anything reaches your books is a decision you make outside this skill, in your own system, by your own hand. If you act on none of it, nothing in your data has changed.
Onboarding — required whenever Mosofin is connected
If the Mosofin gateway is connected, onboarding is not optional and not per-skill. Before any skill reads anything, the workspace and the data sources in it must be confirmed with you. It is the same sequence for every Mosofin skill, so it is kept in one place rather than repeated in each:
- in this repo:
shared/onboarding.md - installed on its own, or you would rather read the product docs: docs.mosofin.com/start-here/quickstart
Already onboarded this workspace? Then you have answered it once and will not be asked again from scratch — but the confirmation itself still happens every run. Gate 0 reads your workspace back and waits for an explicit yes; Gate 1 settles which company file. Those are not skippable, and no data is read before them.
No Mosofin connector? The skill still works. If the gateway is not present at all,
there is nothing to onboard: the gates are skipped, every step becomes [manual], and
you are asked for what each step needs — a trial balance, a statement, an export.
The accounting work is unchanged; only the data source is. You will be told this
once, and you will not be asked to install anything before being helped.
What follows in Part A is not more onboarding. It is this skill exploring what your confirmed workspace and data sources can actually do — which tools exist, which serve this particular request — so the run is shaped around your books rather than a generic template.
Bank Reconciliation (Mosofin)
Reconciles the cash balance per the general ledger (GL) to the bank statement balance for a specified period, explains timing differences, and identifies errors requiring correction.
In plain words: your books say you have one amount of cash; the bank says another. Usually both are right — cheques you wrote haven't been cashed yet, money you banked hasn't landed yet, and the bank has charged fees you didn't know about. Reconciling is proving that the two figures differ only for reasons you can name. Anything left over is an error, and finding it is the point.
This skill supports single or multiple bank accounts.
It is workspace-scoped: every ledger balance, payment and deposit comes from a tool call against a company file connected to your Mosofin workspace in this conversation, or from something you supplied by hand and that is labelled as such.
The defining limitation — read this before promising a reconciliation
A bank reconciliation has two sides. Mosofin can read one of them.
Mosofin connects the accounting system. It reads the GL cash balance, every payment, every deposit and every transfer recorded in the books. It cannot read a bank statement, a bank feed, or a downloaded transaction file, and no accounting datasource exposes one.
Without a bank statement, a bank reconciliation cannot be performed. Not partially, not approximately. Comparing the books to the books is not a reconciliation — it is a total agreeing with itself. Never label such an output a bank reconciliation, and never report a cash balance as "reconciled" on that basis.
What this skill genuinely does from a connected workspace, and it is worth doing:
- Builds the entire book side of the bridge from live data — the GL ending balance and every transaction behind it.
- Produces the candidate lists: payments recorded but plausibly not yet cleared (potential outstanding cheques), deposits recorded near period end (potential deposits in transit).
- Detects book-side errors without the statement — duplicate entries, wrong-account postings, wrong dates, and transactions after the cutoff.
- Flags stale items against the escalation rules in Quality checks.
- Prepares a reconciliation template with the book side complete, so that when the statement arrives the remaining work is matching, not rebuilding.
Then it asks for the statement and says exactly what it could not conclude without it.
If a banking or payments platform is a connected datasource in this workspace, that changes everything — check at Gate 1 before assuming the statement is unavailable.
Mosofin is read-only. It cannot post an adjusting entry, mark an item cleared, or sign off a reconciliation. Every entry below is a proposal for a human.
ONBOARDING — Confirm the workspace and its data sources
Required for every skill, every run — whenever Mosofin is connected. Gates 0 and 1 settle which books this is about: the workspace, and the data sources inside it. Part A then explores what those confirmed sources can actually do and personalises the run around them. Nothing is read before Gate 0 is answered.
If the Mosofin tools are not present at all, skip this part. There is nothing to onboard: say so once, then run the skill manually on data the user supplies. See the precondition check below.
Run Gates 0 → 1 → 2 → 3 in this order, before reconciling anything. This ordering is the contract. Do not skip a gate because a previous conversation covered it — connections, permissions, and company files change between periods.
Call the Mosofin tools by the bare names your own tool list exposes — list_workspaces,
get_agent_datasources, get_datasource_tools, invoke_datasource_api_tool, get_skills,
get_my_skill, create_skill. Do not add a mosofin_ prefix and do not hardcode a client-side
mcp__… namespace; that string is composed by whichever MCP client is running.
First — ask whether to use Mosofin for this run
Two things decide how this skill runs, and they are settled before Gate 0.
1. Are the Mosofin tools present at all? — list_workspaces and the rest of the
gateway. Check before doing anything else.
2. If they are present, ask the user. Once, in these terms:
Do you want me to use your Mosofin connection for this — reading the figures straight from your books — or would you rather provide the data yourself?
Wait for the answer. A connected gateway is not consent to read from it, and this skill does not open with a data read. Never assume, never auto-pick.
- Use Mosofin → onboarding is required. Run Gates 0-1 to confirm the workspace and its data sources, then Part A explores what those sources expose.
- Provide the data myself → skip Gates 0-2 entirely and run manually, exactly as though no connector were present. Do not ask again during the run. Raise it once more only if the user asks for something their supplied data cannot answer, and then as an offer, not a demand.
If the tools are not present, do not ask — there is nothing to choose. The skill was copied on its own, the connector was never added, or there is no subscription. Do not make connecting a condition of helping. Say once, plainly, that Mosofin is not connected and this run will be manual, then carry on with the skill's normal workflow: ask for what each step needs — a trial balance, a statement, an export, the documents themselves — and do the accounting work on what the user provides.
In manual mode, whether chosen or unavoidable:
- every step is
[manual]; there are no[auto]verdicts to claim, and none may be implied - the coverage sheet records why it was manual — gateway absent, or the user chose to supply the data — not that checks passed
- the accounting logic, edge cases and output standards are unchanged. That is the part of this skill that never depended on a connection
- mention once that connecting Mosofin would automate the manual steps, with a link to docs.mosofin.com. Do not raise it again, and never withhold work to press the point
What a manual run actually does, gate by gate
| Gate | In a manual run |
|---|---|
| Gate 0 — workspace | Skipped. There is no workspace to confirm. |
| Gate 1 — data sources | Skipped as a discovery step. Still ask which entity or company this work is for, by name, so every output can be labelled — but record it as user-asserted, not confirmed against a connection. |
| Gate 2 — capability map | Skipped. The map is not empty, it is uniform: every task is [manual]. |
| Gate 3 — profile, then interview | Runs, and grows. The profile half cannot run — there is no company-profile tool — so everything it would have derived silently becomes a question: base currency, fiscal calendar, country or region, time zone. Then the interview runs in full, and every row of the Inputs table that would have been [auto] becomes something to ask for. |
Then Part B runs unchanged on what the user supplied.
Ask the user to upload the data, and name the formats. A manual run does not mean retyping anything. Say plainly what to upload, in what form, and what each item is for — then read it from the files they provide.
| Ask for | Upload as |
|---|---|
| Ledger detail, trial balance, transaction listings | CSV or XLSX export, or a pasted table |
| Statements and third-party documents | PDF or CSV, or a clear photo / scan |
| Invoices, bills, receipts, remittances | PDF or image — a single file or a batch |
| Short facts — a date, a balance, a policy | typed straight into the chat |
Ask for the whole set up front, as a checklist, not drip-fed. A person collecting exports would rather be given one list than be interrupted six times. Mark which items are strictly required and which merely improve the result, so they can decide how much to gather.
Confirm what actually arrived before starting the work. Name each file, say what was read from it — period covered, row count, opening and closing balances — and list what is still outstanding. If a file is unreadable, covers the wrong period, or does not contain what its name suggests, say so at once. Never work around a bad input silently, and never guess at a column you cannot identify — ask.
If something cannot be supplied, say what the output will and will not be — before doing the work. Never estimate a figure that was meant to come from the books, never fill a gap with a plausible number, and never present a partial result as complete. An honest partial answer, clearly labelled, is the correct outcome.
Everything the user provides is evidence like any other. Reconcile it, check it, and challenge it where it does not tie. Manual input is not more trustworthy than a ledger read — it is less, because nothing validated it on the way in.
Present but not authenticated is not the same as absent. If the tools are there and
a call returns a reconnect_url or an auth error, surface it and let the user choose —
reconnect, or continue manually. Do not silently fall back.
Confirming scope — workspace, then data sources, then tools
Nothing is read until scope is confirmed, and scope is confirmed in this order. Each step depends on the answer to the one before it, so none of them may be skipped, merged, or guessed at.
| # | Question to the user | How it is settled |
|---|---|---|
| 1 | Which workspace? | list_workspaces with no arguments. Read the workspace back by name and wait for an explicit yes. On selection_required, ask whether this is single- or multi-workspace, then which by name, then call again with workspace_ids=[…] and mode="single"/"multi". |
| 2 | Which data sources, in that workspace? | get_agent_datasources with the confirmed workspace_id. connected: true is in scope; connected: false is excluded and named as excluded, with any reconnect_url surfaced. Then settle the entity scenario — single-entity: which company; multi-entity: which set — always by display_name. |
| 3 | Which tools do those sources actually expose? | get_datasource_tools per in-scope datasource, and per company file when several are live — permissions are per company. This is discovery, not a question: read what is there before promising anything. |
Never auto-pick. Not the workspace, not the company file, not the entity scenario. Silence is not a yes, and an answer to one question is not an answer to the next.
Names, never internal ids. Name the workspace and refer to companies by
display_name. Never print an internal numeric tenant id, and never show a raw
data_source_id — pass the opaque handle, show the name.
Only then does the work begin. Once the workspace, the data sources and their tools
are confirmed, resolve every task against what was actually found: what is available
now decides which steps are [auto], which are [gated] and which fall to [manual].
Where the confirmed tools cannot answer the request, say so and ask — do not substitute
an assumption for a capability.
The catalogue is authoritative. Take exact tool_name values from the Gate 2
listing — names are not uniformly styled, some underscored, some hyphenated.
Do not invent a tool name. On UNKNOWN_TOOL, read the valid names from the error
and retry.
Never call a tool whose effective_policy is disabled.
This map is built fresh every run and held only for this run. It is written out in the coverage sheet, never written back into this file.
Gate 0 — Confirm the workspace
Call list_workspaces with no arguments.
- One workspace → read the workspace name back and wait for an explicit yes.
- Two or more (
selection_required) → ask in chat whether this is single- or multi-workspace, then which workspace(s) by name, then call again withworkspace_ids=[…]andmode="single"/mode="multi".
Never auto-pick. Never print an internal numeric tenant id — name the workspace, pass the opaque
ws_… handle.
Gate 1 — Discover live datasources and settle the entity scenario
Call get_agent_datasources with the confirmed workspace_id.
connected: true→ in scope.connected: false→ excluded, and named as excluded. Surface anyreconnect_url.
Check every connected row for a banking or payments platform. This is the highest-value check
in the whole gate for this skill: a connected bank feed converts the reconciliation from
[manual] to genuinely two-sided. Do not assume the workspace is accounting-only without
looking.
Settle the entity scenario:
- Single-entity — ask which company by
display_name; the workflow runs against that onedata_source_id. - Multi-entity — ask which set. The workflow runs once per entity, every call targeting
exactly one
data_source_id, and every balance, unmatched item and proposed entry carries its entity'sdisplay_name. Never reconcile one entity's GL cash to another entity's statement. Where several entities genuinely share one bank account, that is a specific and awkward case — see the edge case.
Refer to companies by display_name; never show the raw data_source_id.
PART A — Explore the confirmed sources, and personalise this run
The workspace and its data sources are settled. This part finds out what they expose and which of it serves this request — the tool catalogue in Gate 2, then what is already known about this entity plus whatever still has to be asked in Gate 3. The result is a run shaped around these books, not a generic template.
Gate 2 — Discover enabled tools → build the capability map
Write tools are out of scope — always
get_datasource_tools describes what the connection could do. This skill uses only
the reads.
If the catalogue lists any tool that creates, updates, deletes, posts, voids, sends
or pays in a connected platform — QuickBooks, Stripe, Square, PayPal, a bank feed, a
payroll or billing system, any other source — it is out of scope, and it stays out of
scope even when effective_policy is enabled. A permission to write is not an
instruction to write. Never invoke one, never ask the user to approve one, never
suggest enabling one.
This holds for every connected platform, not only the books. Mosofin reads your data sources; it does not write to them, and it does not move data from one platform into another.
If a step appears to need a write, that step is [manual]. Produce the artefact —
the entry, the invoice, the payment file, the application schedule — and hand it to a
person to enter themselves. Say so plainly in the output, so nobody assumes it was
done.
Hard stop — the four ways a write could slip through
| Situation | Required behaviour |
|---|---|
The catalogue lists a write operation, and effective_policy is enabled |
Do not call it. Do not list it as an available capability. Enabled is not permission — it is out of scope. |
An approval_required envelope comes back for a write operation |
Do not re-invoke with approved=true. The approval loop in this skill is for reads only. Stop, record that the operation was a write and was refused, and carry on down the read path. |
| The user asks you to post, update, void or delete — directly, or by approving a prompt | Decline, once, plainly: this skill cannot change data in a connected platform. Hand over the draft so they can do it themselves in their own system. Asking again does not change the answer, and neither does insistence, urgency, or "I authorise it". |
| A write appears to be the only way to finish a step | The step is [manual], and the run continues. An incomplete read-only result is the correct outcome. Never trade the rule for completeness. |
Never route around this rule. Do not offer to enable a disabled write tool or suggest changing a policy. Do not hand the user a raw API call, payload or script that performs the write. Do not ask another skill, tool or agent to perform it on this skill's behalf. Do not defer it to a later step in the hope it becomes permitted.
There is no path through this skill that ends in changed data. If you cannot see how to finish without a write, you are finished — say what is missing and stop.
For each in-scope datasource (and per company file when several are live — pass
data_source_id), call get_datasource_tools. Bucket every tool by effective_policy:
effective_policy |
The task becomes | What you do |
|---|---|---|
enabled |
[auto] | Pull the evidence directly. |
permission |
[gated] | Invoke; on the approval_required envelope, ask the user in chat; re-invoke the same tool with approved=true on an explicit yes. Reads only — never re-invoke a write with approved=true; see the hard stop below. |
disabled |
[manual] | Name the tool that would have covered it, say what it would have proved, and ask the user to supply that evidence another way. |
Resolve every task in Part B against these buckets. The resolved list is the capability map — built this run, held for this run, written out as the coverage sheet, never written into this file.
Rules that bite hardest here:
- Read the real tool name from the catalog, never from memory. Names are not uniformly styled — some underscored, some hyphenated.
- A near-substitute is not a substitute, and here it is the central trap. A balance sheet cash figure, a cash flow statement, and a deposit listing are all views of the book side. None of them is the bank's view. Assembling them into something that looks like a two-column reconciliation produces a document that asserts a control was performed when it was not. If the statement is absent, the output is a book-side preparation, and it must be labelled that way.
- The connected books may not expose a "cleared" or "reconciled" flag. Most read-only connectors do not. That means outstanding cheques and deposits in transit cannot be identified with certainty from the books alone — only proposed as candidates by date. Say "candidate", not "outstanding".
Gate 3 — Profile the entity, then interview the user
Call the platform's company-profile tool (on QuickBooks, get_company_info) for each in-scope
entity.
Derive silently what the profile answers: base currency (which determines whether an FX line belongs in the bridge at all), fiscal calendar, country / region, and time zone — which matters here, because whether a transaction falls on the statement's last day can depend on it.
Ask the user what actually changes the work — the original Inputs table, minus what the profile answered:
| What to confirm | Required? | Notes |
|---|---|---|
| Bank account(s) in scope — account name(s), account numbers masked | Required — partly [auto] | The chart of accounts pulls the cash accounts; ask which are in scope. Never display or store a full account number. |
| Reconciliation period — start / end dates | Required | Never default the period. |
| Bank statement — PDF/CSV, or the ending balance plus statement lines | Required — [manual], always | Ask for it explicitly and early. If it cannot be supplied, say what the output will and will not be before doing the work. |
| GL activity for cash account(s) — date, description, amount, counterparty, reference | Required — usually [auto] | Pulled from the connected books. |
| Prior month reconciliation status — prior recon report or last reconciled date | Recommended — [manual] | Without it, opening outstanding items are unknown and the bridge starts blind. Ask for at least the last reconciled date. |
| Cutoff policy — posting cutoffs, deposit processing, cheque clearing | Recommended — [manual] | Sets the date windows in Step 3 and the escalation ages in Quality checks. |
| Materiality threshold | Recommended | Ask; do not assume. Note that the final tie is to the cent regardless — materiality governs which items get chased, not whether the bridge balances. |
| Confirm scope | Required | Read back in-scope and excluded company files by display_name, and the accounts in scope by name. |
| Confirm any profile contradiction | Required if one appears | |
| Confirm manual evidence | Required | The statement and the prior recon will both be [manual]. Record what was not supplied. |
Ask as one short batch. Propose defaults where reasonable — but never default the period, the account, or the entity.
On later runs, read stored preferences first (Step 7), confirm in one line, and ask only what is new, changed, or contradicted. The account list, cutoff policy and escalation ages should not be re-asked every month.
PART B — The domain work
Every step below is the original procedure, unchanged in count, order, or substance, with
plain-language wording, an [auto] / [gated] / [manual] verdict, and the typical evidence
tool added.
Never drop a task because no tool covers it. A [manual] task is a task with a named gap,
not an absence.
Tool names in italics are typical. Resolve real names and policies from your Gate 2 catalog.
Step 0 — Fetch the evidence (grounding)
Pull the [auto] / [gated] reads. Batch independent reads into one message — the cash
ledger, the deposits, the payments and the transfers do not depend on each other. Never serialize
them.
The server is stateless: pass data_source_id on every call, including retries.
Typical opening batch, per in-scope entity:
search_accounts— to identify the cash / bank accounts by their real names — usually [auto]get_trial_balance/get_balance_sheet— the GL cash ending balance — usually [auto]get_general_ledgeron each cash account for the period — every book-side movement, the core of this skill — usually [auto]search_deposits/get_deposit— money banked, and the deposit-in-transit candidates — usually [auto]search_bill_payments/get_bill_payment— supplier payments, the outstanding-cheque candidates — usually [auto]search_purchases— cheques, card spend and direct debits — usually [auto]search_payments/search_sales_receipts— customer receipts — usually [auto]search_transfers— movements between the entity's own accounts, which appear on both sides and are a classic double-count — usually [auto]search_journal_entries— manual entries hitting cash, a frequent error source — usually [auto]get_company_info— base currency and time zone — usually [auto]
Handle the envelopes:
approval_required→ ask the user in chat, then re-invoke the same tool withapproved=true.entity_required→ ask bydisplay_name, then pass thatdata_source_id.tool_policy_disabled→ convert that task to [manual] and record the gap.UNKNOWN_TOOL→ read the valid names from the error; do not guess.- Dead connection → surface the
reconnect_url.
Check the mock flag. mock: true is fixture data — it can demonstrate the bridge's format
but cannot support a completed reconciliation, because a reconciliation is a control and
performing it on fixtures records a control as operating when it did not.
Step 1 — Establish the two starting points
Capture:
- Bank statement ending balance as of the statement end date — [manual]
- GL cash account ending balance as of the same date — [auto]
(
get_trial_balance,get_balance_sheet,get_general_ledger)
Confirm both are for the same account and currency. This sounds trivial and is a common real error: an entity with several accounts at the same bank, or a foreign-currency account carried in the base currency, will produce a bridge that can never balance. State the account name, the currency, and the date on both sides before going further.
If the statement balance is not available, stop and say so here — do not proceed to build a bridge with one side missing and present it as a reconciliation. Continue instead with the book-side preparation described at the top of this file, clearly labelled.
Step 2 — Build the reconciliation bridge
Two ladders that must meet in the middle.
Bank statement ending balance
+ Deposits in transit
- Outstanding checks / payments
+/- Bank errors (rare; document)
= Adjusted bank balance
Book balance (GL ending balance)
+ Bank interest and other credits not recorded
- Bank fees and other debits not recorded
+/- Errors on books
= Adjusted book balance
Adjusted bank balance must equal adjusted book balance.
- Deposits in transit — money you banked that the bank hasn't credited yet. [gated]:
the deposits are [auto] (
search_deposits), but which are still in transit needs the statement. Without it, list them as candidates by date. - Outstanding cheques / payments — payments you issued that haven't been cashed. Same split:
the payments are [auto] (
search_bill_payments,search_purchases); which are still outstanding needs the statement. - Bank errors — rare, and [manual]. Document them; banks do make mistakes and they are worth pursuing.
- Interest and credits not recorded / fees and debits not recorded — [manual] to identify
without the statement, since by definition they are not in the books. This is the same blind
spot described in
bank-fee-and-interest-analysis. - Errors on books — [auto] and the strongest automated contribution here: duplicates, wrong amounts, wrong dates, wrong accounts, all detectable in the ledger alone.
Step 3 — Match transactions (bank vs GL)
Work down the methods; record which one produced each match, because a level-1 match and a level-4 match carry very different confidence.
Matching process — [gated], requiring both sides:
- Exact amount + date window match (same day to ± 3 business days) — the strongest.
- Exact amount + fuzzy description match — for when the bank's wording differs from yours.
- Reference match (cheque number, ACH ID, wire reference, merchant descriptor) — often the most reliable of all where the reference survives on both sides.
- Split / combined matches — one bank line covering several book entries, or vice versa. Common with batched deposits and card settlements, and the level where false matches start.
[auto] even without a statement: run the book side against itself to find duplicates — the same amount, counterparty and date recorded twice. That is not matching, but it removes a frequent cause of an unbalanced bridge before the statement even arrives.
Step 4 — Classify all unmatched items
Unmatched bank items — [manual] without the statement, since these are things only the bank knows:
- Bank fees
- Interest earned
- Returned items / NSF — a customer's payment bounced ("non-sufficient funds")
- Chargebacks — a card issuer reversing a payment
- Merchant processor netting / reserves — the processor taking its fee before paying you, or holding back a reserve
- Loan payments (principal / interest) — often taken automatically by direct debit
- FX gains / losses (if applicable)
- Unknown (needs research) — an honest category; give it an owner and a date
Unmatched GL items — [auto] to list, [gated] to classify:
- Deposits in transit
- Outstanding checks
- Timing differences
- Book errors — duplicate entry, wrong account, wrong amount, wrong date. [auto] to detect
all four from the ledger alone (
get_general_ledger,search_journal_entries), which makes this the part of Step 4 that can be completed before the statement arrives
Step 5 — Propose corrections / journal entries
DR is a debit, CR a credit; every entry balances. Mosofin does not post — these are
proposals.
JE templates:
Record bank fee
DR Bank Fees Expense XXX
CR Cash (Bank Account) XXX
Record interest income
DR Cash (Bank Account) XXX
CR Interest Income XXX
Use the real account names from the connected chart of accounts (search_accounts,
[auto]) rather than the generic labels above, and say which you chose. Every proposed entry
names the statement line that evidences it — an entry proposed without that evidence is a guess
at what the bank did.
Step 6 — Close out and document
Deliver:
- Reconciliation summary table — both ladders, meeting or not meeting
- Unreconciled items list with owner + next action — every item, including the "unknown" category
- Proposed JEs with memos and support — marked as proposals
- Sign-off checklist — [manual]. Mosofin cannot sign anything. Preparer and reviewer are named humans, and they should not be the same person
Step 7 — Evolve the skill (Mosofin-specific, final step)
The file you installed is a seed. After the user has seen the results and approved them, ask — explicitly, at that point, not earlier — whether to save this as their own customized version. A general "yes, go ahead" from earlier does not count.
This runs every month, so the evolution step pays back quickly.
On an explicit yes, persist the decisions:
- The bank account list — by account name and the entity that owns it, with masked identifiers only
- The cutoff policy — posting cutoffs, deposit processing times, typical cheque clearing windows — which sets the Step 3 date windows
- The escalation ages — the deposit-in-transit and outstanding-cheque thresholds from Quality checks, if the entity uses different ones
- The materiality threshold for chasing items
- Recurring statement items — the standing monthly fee, the regular loan direct debit, the processor's settlement pattern — so each is recognised rather than re-researched every month
- The account mapping for fees, interest and FX
- Where the statement comes from and who supplies it
- The replay recipe: the exact sequence of reads that produced the book side
Save via create_skill — bundle SKILL.md, references/run-recipe.json, and the preference
files; set datasources= to match the recipe; no .html, .css, or .svg files. Or write
preference files alongside the installed skill.
Never persist bank account numbers, statement contents, balances, or unreconciled item detail. Account numbers are payment credentials and the top fraud target; balances and item lists are the period's evidence and belong in the close file. Persist the policy, the thresholds and the account names.
Key every preference and asset by datasource + entity display_name. Write "quickbooks /
Northbrook Trading — Operating account (…4471): cheques clear in ~5 days, escalate DIT over 10
business days" — not "cheques clear in ~5 days". Entities bank differently, and an unlabelled
clearing window applied to the wrong company file mis-ages every item. Record the chosen
scenario (single vs multi, and which set) as a preference too.
Never persist state. Connections, company files, tool policies, and mock status belong to
the workspace and are re-discovered by Gates 1–2 every run. Decisions are the user's; state is
the workspace's.
On later runs, match stored entity names against Gate 1's live list. An entity in preferences that is no longer connected is flagged — never silently dropped, never applied elsewhere.
Outputs
- Reconciliation summary — with a header stating the workspace, the entity
display_name, the account by name, the period, whether a bank statement was supplied, and whether any figure rests onmockdata. - Matched transaction list — each with the matching method (1–4) that produced it.
- Unmatched lists with classification — bank side and book side, per Step 4.
- Exception log with recommended next actions — each with an owner and a target date.
Coverage sheet — NEW, Mosofin-specific.
One row per task in Steps 1–6:
| Task | Entity (display_name) | Account | Verdict (auto / gated / manual) | Tool used | Policy (enabled / permission / disabled) | mock | Gap — what could not be verified and what the user must supply |
If no statement was supplied, the rows for the bank side, the matching step and the unmatched-bank
classification all read manual with the gap "bank statement not supplied", and the summary
says the reconciliation was not completed. That is the correct, expected output — not a defect,
and not something to disguise with a book-side total.
If creating xlsx, read first: /mnt/skills/public/xlsx/SKILL.md
File naming — Mosofin addition (the original left it unstated, and multi-account, multi-entity
output needs it): Bank_Rec_[AccountName]_[YYYY-MM].xlsx, and in a multi-entity run
Bank_Rec_[EntityDisplayName]_[AccountName]_[YYYY-MM].xlsx. Every file states which datasource,
which display_name and which account it covers.
Grounding: every figure traces to a tool result in this conversation or to labelled user-supplied evidence. End with a single Data sources line grouping calls by datasource. Where the data does not cover something, name the tool that would have covered it instead of estimating.
Quality checks
- Same statement end date on both sides
- No duplicates in the GL export — [auto] to test, and worth doing on every run
- Deposits-in-transit older than 10 business days escalated — money banked that the bank has not credited after two weeks is usually a lost deposit or a booking error, not timing
- Outstanding checks older than 90 days escalated — a cheque uncashed for a quarter may be lost, may be a duplicate payment about to be made, and in many jurisdictions eventually becomes unclaimed property
- Adjusted balances tie to the cent — not to materiality. A bridge that nearly balances has an unidentified item in it
Mosofin additions:
- The workspace was confirmed by name and the user said yes before any data was read
- Every in-scope company file is named by
display_name; every excluded one is named as excluded, with the consequence stated - The capability map was discovered this run via Gate 2 — never recalled from a previous conversation or from this file
- The output states plainly whether a bank statement was supplied, and if not, is labelled a book-side preparation rather than a reconciliation
- A book-side total is never presented as a reconciled cash balance
- Outstanding cheques and deposits in transit identified without a statement are labelled candidates, never confirmed outstanding items
- Every task carries its verdict (
[auto]/[gated]/[manual]), the tool used, and that tool's policy, in the coverage sheet - Every matched item records the matching method that produced it
- Every proposed entry names the statement line that evidences it
- Account names in every proposed JE are the real names from the connected chart of accounts
mockstatus is reported wherever it applies, and no reconciliation is signed off on mock data- Every figure traces to a tool result in this conversation or to labelled user-supplied evidence; the answer ends with a
…(truncated)