# Lopifi Tools — the accountant's toolbelt

> A Chrome extension (MV3) and a matching /tools section on the docs site. Same engine, two surfaces. Local only by default: nothing leaves the machine, no account, no server, no telemetry. AI runs on Chrome's built-in models — Gemini Nano behind LanguageModel, Summarizer and Proofreader, an on-device

Source: https://lopifi.com/docs/tools/00-tools-spec
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

# Lopifi Tools — the accountant's toolbelt

A Chrome extension (MV3) and a matching `/tools` section on the docs site. Same engine, two
surfaces. **Local only by default**: nothing leaves the machine, no account, no server, no
telemetry. AI runs on Chrome's built-in models — Gemini Nano behind `LanguageModel`, `Summarizer`
and `Proofreader`, an on-device translation model behind `Translator` — so a client's bank
statement never touches a network.

---

## Who this is for

The person who spends their day between a PDF and a spreadsheet: a bank statement they must foot,
an AP invoice they must key, a lease they must read, a TB that is out by 8,100 (a transposition),
a deposit of 14,203.55 that has to be broken into the four invoices it paid.

Every feature below exists because that person currently solves it with a desk calculator, a
printout and a pen — or with a web tool that uploads the client's data to somebody else's server.

## The three non-negotiables

1. **Local only.** IndexedDB and the file system. The only network call the extension can make is
   the one the user makes by clicking a link. The manifest requests no host permission that would
   allow exfiltration, and there is no remote code.
2. **Money is minor units.** Shared with the `@lopifi` system — integers, per-currency scale,
   accounting negatives, `null ≠ 0`. Every parser and every schedule generator in `src/tools/lib`
   round once, at the end. The scale is never assumed to be 2: every money tool carries a
   **Currency** field (ISO 4217, default USD) and reads, prints and copies at that currency's
   exponent from `currencyScale()` — JPY 0 (`1,500,000`), USD 2, KWD 3 (`1.234`). FX conversion
   takes a from and a to currency and applies each one's scale.
3. **Provenance survives.** Every note, tick mark and tape entry records who, when, which page,
   which document hash. A note pack you send a colleague carries its own audit trail.

---

## Part 1 — The PDF layer

Chrome's built-in PDF viewer is a closed plugin: you cannot draw on it. So the extension ships its
own viewer built on `pdf.js`, and intercepts PDF navigation into it (the user can turn the takeover
off, and open a PDF into it by hand at any time).

### 1.1 Selection sum — the reason this exists

Drag a box over a column of figures on the page. The extension reads the **text layer** (not OCR
guesswork), pulls every number in the marquee, and shows `n`, sum, average, min, max, and the
count of negatives — immediately, in a floating pill. Shift-drag adds a second region. Click a
single number to add it to the tape.

Because it reads the text layer it understands what a printed page does not tell you: `(1,234.56)`
is negative, `1.234,56` is European, `1,234.56-` is a trailing-sign mainframe report, `$` and
`USD` are noise, and a page number is not an amount.

### 1.2 The tape (adding machine)

A running tape in the side rail. Every entry has an amount, an optional memo, a source (page +
coordinates, or typed), and a sign. It is an adding machine, not a calculator: entries stay
visible, the subtotal is always live, and you can insert, strike and re-order without losing
history. `=1200+340*2` works in the entry field — accountants come from spreadsheets.

Tape actions: subtotal marker, sign flip, ×(-1), % of subtotal, copy as TSV (pastes into Excel as
rows), copy the total alone, and "post to note" which drops the tape onto the page as an annotation.

### 1.3 Foot and cross-foot

Select a column → **Foot**: compares your sum to the printed total nearest the bottom of the
selection and tells you the difference. Select a block → **Cross-foot**: checks that the row totals
and the column totals agree to the grand total, and shows exactly which cell breaks it.

### 1.4 Tick marks

The workpaper convention, done properly. A palette of marks (`✓ ✗ ⌥ ∆ ○ ⊕ ¹ ² ³` and colour
variants) placed by click on any figure. Each mark carries a **legend entry** you define once per
document ("✓ = agreed to bank statement"), and the legend prints on the export. Filter the page by
mark; jump between marks; count them ("14 of 22 lines agreed").

### 1.5 Notes, highlights, redaction

- Sticky notes anchored to a text quad (they survive re-render and zoom).
- Highlight, underline, strike-through over selected text.
- Freehand and arrow for the screenshot-into-email case.
- **Redaction** that actually removes the text run, not a black rectangle over it, when exporting.

### 1.6 Extraction

- **Table → clipboard/CSV.** Marquee a table; column boundaries are inferred from x-positions of
  the text runs, and you can drag the inferred boundaries before copying.
- **Find all amounts / dates / invoice numbers / account codes** on the document, as a list you can
  copy or send to the tape.
- **Text layer check.** If the page has no text layer it is a scan; the extension says so loudly
  rather than silently summing nothing.

### 1.7 Compare

Two PDFs side by side with the numeric diff called out: same-label lines whose figures moved, lines
present in one and not the other. The month-over-month TB, the redlined lease, the restated
statement.

### 1.8 Document integrity

SHA-256 of the file on open, shown in the workpaper header and stamped into every export. If the
client sends a "corrected" copy, you know instantly.

---

## Part 2 — Chrome built-in AI (on-device)

All of it optional, all of it local, every output labelled as machine-generated and never written
into a figure the user might read as truth.

| Feature | API | What it does |
|---|---|---|
| Summarise | `Summarizer` | Key points of a lease, contract, engagement letter |
| Extract | `LanguageModel` (JSON schema) | Vendor, invoice №, dates, subtotal, tax, total, currency, terms — then **checks the arithmetic itself** and flags a total that does not equal subtotal + tax |
| Classify | `LanguageModel` | Invoice / statement / receipt / contract / tax notice — drives the default tool layout |
| Explain | `LanguageModel` | "What does this clause commit us to?" over a selection |
| Translate | `Translator` | The foreign vendor invoice |
| Draft | `LanguageModel` | The PBC request, the review note, the "please explain this variance" email — from your tick marks and notes |
| Proofread | `Proofreader` | The note you are about to send the client |

Guardrails: extraction output is always shown as a **form to confirm**, never auto-posted; every AI
field is marked with provenance; and if the on-device model is unavailable the feature is hidden,
not degraded to a cloud call.

---

## Part 3 — Notes: local, portable, shareable

Storage is an **append-only operation log** per document, keyed by the document's SHA-256, in
IndexedDB. Ops carry `{id, authorId, authorName, at, kind, payload}`.

- **Export** → `.ledgernotes.json`: the op log plus a document fingerprint (hash, page count, page
  sizes, first-page text digest).
- **Import** → merges by op id. Because the log is append-only and each op is idempotent, two
  people annotating the same statement can merge in either order and land in the same place. A
  strike of someone else's note is itself an op, so nothing is ever lost, only superseded.
- **Fingerprint mismatch** is surfaced, not silently accepted: "these notes were made against a
  different file — 3 pages vs 4."
- Share is a file. Email it, drop it in the client folder, put it in the workpaper. No server,
  no account, no link that outlives the engagement.
- Export also to **Markdown** (a review-note summary) and **annotated PDF** (marks, notes, tick
  legend and workpaper header burned in via `pdf-lib`).

---

## Part 4 — The quick tools

Available in the extension side panel, on any tab, and mirrored at `/tools` on the site. Each one
is a pure function in `src/tools/lib` with unit tests, shared by both surfaces.

**Selection sum anywhere.** Not just PDFs — highlight figures in Xero, QBO, NetSuite, a Gmail
table, a CSV preview on GitHub, and a pill shows count/sum/average.

### Reconciliation & investigation
| Tool | Why |
|---|---|
| **Difference diagnoser** | Out by 8,100 → divisible by 9 → transposition, and difference ÷ 9 says how much the two swapped digits differ by. Also catches a line omitted or posted twice, a sign flip (half the gap is a figure in the data), a decimal slide (the "off by a factor of 10"), and per-line rounding. |
| **Subset finder** | A deposit of 14,203.55 against 40 open invoices: which combination sums to it? Meet-in-the-middle over minor units — exact, not floating point. |
| **Two-list matcher** | Bank lines vs GL lines: exact (amount and day), then the same reference whatever the date (INV-0042 = inv 42), then amount within a date window, then many-to-one. Outputs the unmatched two ways. |
| **Duplicate finder** | The same reference whatever the date, same vendor + amount within N days (14 by default — under a month, so rent is not flagged), and same-amount/different-vendor. |
| **Benford's law** | First-digit distribution with a χ² result over a pasted column. |
| **Round-number test** | Concentration at .00 / .50 / 000 — the other cheap fraud smell. |

### Schedules (all produce a journal-ready table)
Straight-line, double-declining and sum-of-the-years'-digits **depreciation** — accelerated
methods computed per asset-year (DDB at factor ÷ life in years on net book value, salvage only a
floor, switching to straight-line when that gives more; SYD over whole years) and each year's
charge spread evenly over its months — with mid-month, mid-quarter (10.5/7.5/4.5/1.5 months by
in-service quarter) and half-year (six months of the first year's charge in the first calendar
year, the rest after the life ends) conventions. **Prepaid amortisation** even, or by days split at
calendar month-ends. **Deferred revenue release**, **accrual and reversal**, **loan amortisation**
(payment solve, interest/principal split, balloon paid with the final instalment, first payment one
month after funding), **lease PV** and the ROU asset/liability roll-forward under ASC 842 /
IFRS 16 — the liability's payment is fixed on every row and the final row's interest closes it, and
the ROU asset amortises straight-line for a finance lease or as the plug to a straight-line cost for
an ASC 842 operating lease. Every schedule's final period absorbs the rounding.

### Money maths
Penny-perfect **allocation** (largest-remainder, sums to the total exactly), **VAT / sales tax**
gross↔net at any rate, **markup vs margin**, **FX conversion with a rate you type** between two named currencies, each at its own scale, plus realised /
unrealised **FX gain-loss** (signed by whether the item is a receivable or a payable), **NPV / IRR / XIRR**, **effective vs nominal rate**, **number to
words** for checks (US grammar, no "and" inside the number) or British cheques.

### Dates & terms
Fiscal period resolver (any FY start), **payment-terms calculator** (Net 30, 2/10 net 30 and 2/10, n/30, EOM and
Net 10 EOM, 15 MFI) with the discount decision, day-count conventions (actual/365, actual/360, 30/360, and ISDA actual/actual — the period split at
each 1 January, leap-year days over 366 and the rest over 365),
business-day arithmetic, and the day count that makes a proration exact.

### Data hygiene
**Number cleaner**: paste anything a report throws at you — `(1,234.56)`, `1.234,56`, `1,234.56-`,
`$ 1 234.56`, `1.2k` — get clean signed values, one per line, ready for the tape or Excel.
**Journal entry balancer**: paste or key lines, see the debit/credit totals, the out-of-balance,
and copy an import-ready CSV. **Trial balance checker**: paste a TB, get the balance check plus
sign anomalies against each account's normal balance (contra accounts carry the opposite one:
accumulated depreciation and allowances a credit; sales returns, allowances and discounts, treasury
stock and owner drawings a debit; bank and processing fees are read as expenses, not cash).

### Identifiers
IBAN (mod-97), ABA routing (checksum), EIN, VAT number format by country, ISIN, LEI, credit-card
Luhn. All offline, all format/checksum only — no lookup, no network.

---

## Part 5 — What we deliberately do not build

- No cloud sync, no account, no "share link". Sharing is a file.
- No OCR. A scan gets a clear warning, not a plausible wrong number.
- No cloud AI fallback. If Gemini Nano is not there, the AI panel is not there.
- No auto-posting to a ledger. Every output is something you copy, look at, and paste.
- No "confidence score" theatre on extracted figures. Confirm the form or don't.

## What is built, and what is not

This document is the design. `v0.1` implements most of it; the rest is specified deliberately and
not yet written. Nothing below is claimed on any user-facing page that does not ship it.

**Shipped in v0.1**

Selection sum · foot · the tape (with spreadsheet arithmetic, strike, subtotals, post-to-page) ·
tick marks with an editable legend · sticky notes with replies, clear and strike · highlight ·
redaction (drawn opaque, with an explicit warning about what that does not remove) · table
inference to TSV · find text / regex / all amounts / all dates · scanned-page detection ·
SHA-256 integrity · the note-pack export/import merge with fingerprint checking · review-note
Markdown · annotated-PDF export with a workpaper cover page and notes index · page-range extraction ·
on-device summarise / classify / extract-with-arithmetic-check / ask / draft-review-note ·
selection sum on any page · all 22 quick tools, on both surfaces.

**Specified, not yet built**

| Feature | Where it stands |
|---|---|
| Cross-foot | `crossFoot()` exists in `extension/src/lib/pdf-text.ts` and is tested; there is no UI for selecting a block as a grid yet. |
| Compare two PDFs | Not started. Needs a second document context and a line-matching pass over the two text layers. |
| Freehand and arrow annotations | Not started. The op log already carries anchors that would hold them. |
| True redaction | Export draws opaque rectangles. Removing the underlying text run means rewriting the content stream, which `pdf-lib` does not expose; until then the export says so plainly rather than implying more. |
| Translate / proofread | Wrapped in `extension/src/lib/ai.ts`, not yet surfaced in the viewer — the translator needs a source language and that choice has not been designed. |
| PDF merge from several files | `mergePdfs()` exists; there is no multi-file picker. |
| Subset finder over figures read off a PDF | The tool works on pasted lists. Feeding it a marquee selection directly is the obvious next step. |

## Layering

```
src/tools/lib/*.ts          pure, framework-free, unit-tested — the whole toolbelt
     ↑                    ↑
src/app/tools/*          extension/src/*
(Next.js, @lopifi UI)    (MV3: viewer, overlay, side panel, notes store)
```
