jaz-clio 5.8.1 → 5.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Requires **Node.js 18+** ([nodejs.org](https://nodejs.org)). Also fully compatib
19
19
 
20
20
  - [Three Ways In](#three-ways-in) — CLI, MCP, Skills
21
21
  - [CLI](#cli) — 55 command groups
22
- - [MCP Server](#mcp-server) — 285 tools for AI agents
22
+ - [MCP Server](#mcp-server) — 288 tools for AI agents
23
23
  - [Skills](#skills) — Teach any AI the Jaz API
24
24
  - [Setup](#setup) — Auth, multi-org, automation
25
25
 
@@ -54,7 +54,7 @@ clio practice create-engagement acme-pte-ltd --type monthly-close --period 2026-
54
54
 
55
55
  ## MCP Server
56
56
 
57
- 285 CLI tools, available to any AI agent that speaks MCP. Runs locally — no cloud, no ports. Includes the v5.2.0 `practice_*` tools (init, onboard_client, list_clients, load_client, create_engagement, load_engagement) so an agent in Claude Desktop or Claude Code can scaffold and load client workspaces conversationally.
57
+ 288 CLI tools, available to any AI agent that speaks MCP. Runs locally — no cloud, no ports. Includes the v5.2.0 `practice_*` tools (init, onboard_client, list_clients, load_client, create_engagement, load_engagement) so an agent in Claude Desktop or Claude Code can scaffold and load client workspaces conversationally.
58
58
 
59
59
  **Claude Code:**
60
60
  ```bash
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-api
3
- version: 5.8.1
3
+ version: 5.10.0
4
4
  description: >-
5
5
  Use this skill whenever you call, debug, or review code that touches the Jaz
6
6
  REST API. Covers field names, response shapes, 141 production gotchas, error
@@ -189,9 +189,9 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
189
189
  56. **Kebab-case URL aliases** — `capsuleTypes` endpoints also accept kebab-case paths: `/capsule-types` (list, search, CRUD). `moveTransactionCapsules` also accepts `/move-transaction-capsules`. Both camelCase and kebab-case work identically.
190
190
 
191
191
  ### Jaz Magic — Extraction & Autofill
192
- 57. **When the user starts from an attachment, always use Jaz Magic** — if the input is a PDF, JPG, or any document image (invoice, bill, receipt), the correct path is `POST /magic/createBusinessTransactionFromAttachment`. Do NOT manually construct a `POST /invoices` or `POST /bills` payload from an attachment — Jaz Magic handles the entire extraction-and-autofill pipeline server-side: OCR, line item detection, contact matching, CoA auto-mapping via ML learning, and draft creation with all fields pre-filled. Only use `POST /invoices` or `POST /bills` when building transactions from structured data (JSON, CSV, database rows) where the fields are already known.
193
- 58. **Two upload modes with different content types** — `sourceType: "FILE"` requires **multipart/form-data** with `sourceFile` blob (JSON body fails with 400 "sourceFile is a required field"). `sourceType: "URL"` accepts **application/json** with `sourceURL` string. The OAS only documents URL mode — FILE mode (the common case) is undocumented.
194
- 59. **Three required fields + one optional**: `sourceFile` (multipart blob — NOT `file`), `businessTransactionType` (`"INVOICE"`, `"BILL"`, `"CUSTOMER_CREDIT_NOTE"`, or `"SUPPLIER_CREDIT_NOTE"` — `EXPENSE` rejected), `sourceType` (`"FILE"` or `"URL"`). Optional: `uploadMode` (`"SEPARATE"` default, or `"MERGED"` for a single PDF containing multiple documents — the backend splits it via boundary detection before extraction). All required fields are validated server-side. **CRITICAL: multipart form field names are camelCase** — `businessTransactionType`, `sourceType`, `sourceFile`, `uploadMode`, NOT snake_case. Using `business_transaction_type` returns 422 "businessTransactionType is a required field". The File blob must include a filename and correct MIME type (e.g. `application/pdf`, `image/jpeg`) — bare `application/octet-stream` blobs are rejected with 400 "Invalid file type".
192
+ 57. **When the user starts from an attachment, always use Jaz Magic** — if the input is a PDF, JPG, or any document image (invoice, bill, receipt), the correct path is `POST /magic/createBusinessTransactionFromAttachment`. Do NOT manually construct a `POST /invoices` or `POST /bills` payload from an attachment — Jaz Magic handles the entire extraction-and-autofill pipeline server-side: OCR, line item detection, contact matching, CoA auto-mapping via ML learning, and draft creation with all fields pre-filled. Only use `POST /invoices` or `POST /bills` when building transactions from structured data (JSON, CSV, database rows) where the fields are already known. If you hold the invoice/bill as raw HTML (e.g. an email body), pass it via `sourceType: "HTML"` with an `html` field — the backend renders it to a PDF then extracts, so you do NOT need to save it to a file first.
193
+ 58. **Three upload modes with different content types** — `sourceType: "FILE"` requires **multipart/form-data** with `sourceFile` blob (JSON body fails with 400 "sourceFile is a required field"). `sourceType: "URL"` accepts **application/json** with `sourceURL` string. `sourceType: "HTML"` accepts the raw HTML body in an `html` field (JSON or multipart) — the backend renders it to a PDF, then extracts (use this for an email body you already hold; no file needed). The OAS only documents URL mode — FILE and HTML modes are undocumented there.
194
+ 59. **Three required fields + one optional**: the source (`sourceFile` multipart blob — NOT `file` — for FILE, `sourceURL` for URL, or `html` for HTML), `businessTransactionType` (`"INVOICE"`, `"BILL"`, `"CUSTOMER_CREDIT_NOTE"`, or `"SUPPLIER_CREDIT_NOTE"` — `EXPENSE` rejected), `sourceType` (`"FILE"`, `"URL"`, or `"HTML"`). For HTML mode, `html` is the raw HTML string (max 5 MB). Optional: `uploadMode` (`"SEPARATE"` default, or `"MERGED"` for a single PDF containing multiple documents — the backend splits it via boundary detection before extraction). All required fields are validated server-side. **CRITICAL: multipart form field names are camelCase** — `businessTransactionType`, `sourceType`, `sourceFile`, `uploadMode`, NOT snake_case. Using `business_transaction_type` returns 422 "businessTransactionType is a required field". The File blob must include a filename and correct MIME type (e.g. `application/pdf`, `image/jpeg`) — bare `application/octet-stream` blobs are rejected with 400 "Invalid file type".
195
195
  59a. **MERGED upload workflow tracking** — When `uploadMode: "MERGED"`, the upload response `workflowResourceId` is a **parent** tracking ID. The backend splits the PDF, then creates **child** workflows for each split page — these child IDs appear in `POST /magic/workflows/search` (by fileName or createdAt), NOT the parent ID. To track MERGED progress, search by `fileName` rather than the parent `workflowResourceId`.
196
196
  60. **Response maps transaction types**: Request `INVOICE` → response `SALE`. Request `BILL` → response `PURCHASE`. Request `CUSTOMER_CREDIT_NOTE` → response `SALE_CREDIT_NOTE`. Request `SUPPLIER_CREDIT_NOTE` → response `PURCHASE_CREDIT_NOTE`. S3 paths follow the response type. The response `validFiles[]` array contains `workflowResourceId` for tracking extraction progress via `POST /magic/workflows/search`.
197
197
  61. **Extraction is asynchronous** — the API response is immediate (file upload confirmation only). The actual Magic pipeline — OCR, line item extraction, contact matching, CoA learning, and autofill — runs asynchronously. Use `POST /magic/workflows/search` with `filter.resourceId.eq: "<workflowResourceId>"` to check status (SUBMITTED → PROCESSING → COMPLETED/FAILED). When COMPLETED, `businessTransactionDetails.businessTransactionResourceId` contains the created draft BT ID. The `subscriptionFBPath` in the response is a Firebase Realtime Database path for real-time status updates (alternative to polling).
@@ -402,9 +402,10 @@ Bills, invoices, and credit notes share identical mandatory field specs. Adding
402
402
 
403
403
  ### Reconciliation actions (write-side)
404
404
 
405
- 123. **8 reconciliation action endpoints under `/api/v1/reconciliations/*`** — these *commit* a reconciliation decision against a bank statement entry, distinct from `view_auto_reconciliation` (which queries `/search-magic-reconciliation` for *suggestions*). Two are async, six are sync:
405
+ 123. **11 reconciliation action endpoints under `/api/v1/reconciliations/*`** — these *commit* a reconciliation decision against a bank statement entry, distinct from `view_auto_reconciliation` (which queries `/search-magic-reconciliation` for *suggestions*):
406
406
  - **Async (jobId):** `quick_reconcile` (bulk match entries to journals, max 500), `apply_bank_rule` (bulk apply a rule to entries, max 500). Poll `search_background_jobs` filtered by `resourceId`; on `PARTIAL_SUCCESS` read `data[0].errorDetails` for per-row failures.
407
- - **Sync (single bank entry):** `reconcile_direct_cash_entry`, `reconcile_cash_journal`, `reconcile_manual_journal`, `reconcile_cash_transfer`, `reconcile_invoice_receipt`, `reconcile_bill_receipt`. Each returns `{bankStatementEntryResourceId, status, reference, valueDate}`.
407
+ - **Sync (single bank entry):** `reconcile_direct_cash_entry`, `reconcile_cash_journal`, `reconcile_manual_journal`, `reconcile_cash_transfer`, `reconcile_invoice_receipt`, `reconcile_bill_receipt`, `reconcile_with_payments` (match EXISTING — see Rule 158), `reconcile_learned_prediction`. Each returns `{bankStatementEntryResourceId, status, reference, valueDate}`.
408
+ - **Sync bulk:** `reconcile_magic_match` (bulk-accept MAGIC_MATCH suggestions, max 500) returns `{reconciled[], failed[]}`.
408
409
 
409
410
  124. **Recon prefill from the bank statement entry** — when caller omits `valueDate`, `dueDate`, payment `amount`, or direction (cash-in vs cash-out), the API fills these from the bank entry. Best-effort: a missing entry lookup logs a warning and forwards the payload as-is. Caller can always override by passing the field explicitly.
410
411
 
@@ -532,6 +533,13 @@ Supports `--json` for structured output. 186 articles across 20 sections. Automa
532
533
  - **Scheduled journals**: Flat: `{ status, startDate, endDate, repeat, valueDate, schedulerEntries, reference }`. `valueDate` is required.
533
534
  - **FX currency (invoices, bills, credit notes, AND journals)**: `currency: { sourceCurrency: "USD" }` (auto-fetches platform rate) or `currency: { sourceCurrency: "USD", exchangeRate: 1.35 }` (custom rate). Same object form on all transaction types. **Never use `currencyCode` string** — silently ignored.
534
535
 
536
+ 158. **Match-to-EXISTING reconciliation — `reconcile_with_payments` / `reconcile_magic_match` / `reconcile_learned_prediction`.** These reconcile a bank entry against transactions/payments the org ALREADY has, vs `invoice_receipt`/`bill_receipt` which CREATE new ones. Prefer match-to-existing to avoid duplicates.
537
+ - **`reconcile_with_payments`** — the headline. `businessTransactionPayments[]` each carry an open bill/invoice's `cashflowTransactionResourceId` (from `search_cashflow_transactions` or a suggestion's `cftBtResourceId`) + `transactionAmount`; the endpoint CREATES the payment AND reconciles in one call — **no `pay_bill`/`pay_invoice` first.** Also accepts `matchedPayments[]` (existing payments) / `matchedBatchPayments[]` / `adjustment` (over/under-payment + FX write-off). Guard: ≥1 match array non-empty. **FX is auto-resolved server-side — pass NO `currencySettings`/rate for the common case.** Only the rare bill-currency ≠ bank-currency case needs explicit `paymentAmount` (bank ccy) + `currencySettings`. FX gain/loss is NOT auto-posted — post it via `adjustment.cashAdjustmentEntries[]` to an FX account. Errors: `PAYMENT_AMOUNT_REQUIRED_IN_BUSINESS_TRANSACTION_SOURCE_CURRENCY` (cross-ccy missing paymentAmount), `INVALID_EXCHANGE_RATE_ERROR` (adjustment leg in non-functional ccy missing rate), `TOTAL_RECONCILIATION_AMOUNT_MISMATCHED_WITH_STATEMENT_ENTRY_AMOUNT` (sum ≠ entry → add adjustment leg). **NOT idempotent, no client key — a blind retry double-creates a payment; re-check `search_bank_records(status:'RECONCILED')` before retry.**
538
+ - **`reconcile_magic_match`** — bulk-accept MAGIC_MATCH suggestions (max 500 entries). Returns `{reconciled[], failed[]}` — a 200 with non-empty `failed[]` is a PARTIAL success (per-entry `errorCode`); loop on failed only. Entry-level idempotency-keyed server-side (re-submit returns done entries in `reconciled[]`).
539
+ - **`reconcile_learned_prediction`** — accept an ML prediction. `predictedPayload` + `predictedPayloadSchemaVersion` come VERBATIM from a `view_auto_reconciliation` (MAGIC_RECONCILE_WITH_CASH_IN_OUT) suggestion — never hand-construct. `retryToken` forces a fresh journal on edit-retry; omit for idempotent replay. On failure (stale payload), fall back to `reconcile_with_payments` — don't retry the blob.
540
+
541
+ 159. **`view_auto_reconciliation` returns execution-ready `suggestions[]` — the suggestion→commit seam.** Each suggestion carries `recommendedTool` (the commit tool to call), `execute` (ready-to-pass args — merge `bankAccountResourceId` for `reconcile_magic_match`), `confidenceTier` (high/medium/low, code-derived), and `autoCommitEligible` (true ⇒ high confidence + executable plan + under any `autoCommitMaxAmount` cap). **Decision gate:** `autoCommitEligible===true` → auto-commit via `recommendedTool`+`execute`; everything else → surface for confirmation. **Amount threshold is a HARD VETO over confidence** (pass `autoCommitMaxAmount`). Field mapping under the hood: `cftBtResourceId`→`cashflowTransactionResourceId` (single → `reconcile_with_payments`), `cftBtResourceIds[]`/`isBatch`→`matchedBusinessTransactions` (batch → `reconcile_magic_match`), `recommendationType`→tool, `confidenceScore`→tier. Pass `includeRaw:true` for the unmapped payload. On 500 (high-volume OOM) it returns `{degraded:true}` — scope by period or use the `clio jobs bank-recon match` cascade. NOT idempotent applies to every commit — see Rules 125 + 158.
542
+
535
543
  ## See Also
536
544
 
537
545
  - **jaz-recipes** — 16 IFRS-compliant transaction recipes with journal entries, capsules, and calculators
@@ -1118,7 +1118,7 @@ Processing is **asynchronous** — the API response confirms file upload immedia
1118
1118
  - `CUSTOMER_CREDIT_NOTE` → creates a draft customer CN (response type: `SALE_CREDIT_NOTE`)
1119
1119
  - `SUPPLIER_CREDIT_NOTE` → creates a draft supplier CN (response type: `PURCHASE_CREDIT_NOTE`)
1120
1120
 
1121
- **Two modes** — content type depends on `sourceType`:
1121
+ **Three modes** — content type depends on `sourceType`:
1122
1122
 
1123
1123
  #### FILE mode (multipart/form-data) — most common
1124
1124
 
@@ -1171,6 +1171,26 @@ Content-Type: application/json
1171
1171
  / Response: same shape as FILE mode
1172
1172
  ```
1173
1173
 
1174
+ #### HTML mode (raw email/document body)
1175
+
1176
+ Use when you hold the invoice/bill as raw HTML (e.g. an email body) rather than a file. The backend renders the HTML to a PDF, then runs the same extraction pipeline.
1177
+
1178
+ ```json
1179
+ / Request:
1180
+ POST /api/v1/magic/createBusinessTransactionFromAttachment
1181
+ Content-Type: application/json
1182
+
1183
+ {
1184
+ "businessTransactionType": "INVOICE",
1185
+ "sourceType": "HTML",
1186
+ "html": "<html>…invoice markup…</html>"
1187
+ }
1188
+
1189
+ / Response: same shape as FILE mode
1190
+ ```
1191
+
1192
+ `html` is the raw HTML string (max 5 MB); also works as a multipart field. No file or PDF conversion step is needed.
1193
+
1174
1194
  **What Jaz Magic extracts and autofills:**
1175
1195
  - Line items (description, quantity, unit price, amounts)
1176
1196
  - Contact name and details (matched against existing contacts)
@@ -1191,8 +1211,8 @@ Content-Type: application/json
1191
1211
  - JSON body with `sourceType: "FILE"` always fails (400) — MUST use multipart
1192
1212
  - `workflowResourceId` in `validFiles[]` is for tracking via `POST /magic/workflows/search`
1193
1213
  - `subscriptionFBPath` is the Firebase path for real-time status updates
1194
- - All three fields (`sourceFile`/`sourceURL`, `businessTransactionType`, `sourceType`) are required — omitting any returns 422
1195
- - File types confirmed: PDF, JPG/JPEG, PNG, HEIC, XLS, XLSX, EML (max 1 MB)
1214
+ - All three fields (the source — `sourceFile`/`sourceURL`/`html` — plus `businessTransactionType` and `sourceType`) are required — omitting any returns 422
1215
+ - File types confirmed: PDF, JPG/JPEG, PNG, HEIC, XLS, XLSX, EML (max 1 MB). HTML mode (`sourceType: "HTML"`) takes the raw HTML body instead of a file (max 5 MB); an `.eml` file is still FILE mode, not HTML mode.
1196
1216
 
1197
1217
  ---
1198
1218
 
@@ -398,10 +398,12 @@ DELETE → expects "A" (parentEntityResourceId, via /cash-entries/:id)
398
398
  | JSON body | multipart/form-data | FILE mode requires multipart — JSON returns 400 |
399
399
  | Sync response | Async extraction | Response = upload confirmation; extraction & autofill run async |
400
400
  | `status` field | `subscriptionFBPath` | Firebase path for tracking extraction progress |
401
+ | email body → save to file first | `html` + `sourceType: "HTML"` | Raw email/document HTML, rendered to PDF server-side — no file step |
401
402
 
402
403
  **Content-Type depends on sourceType:**
403
404
  - `sourceType: "FILE"` → `Content-Type: multipart/form-data` (MUST use multipart)
404
405
  - `sourceType: "URL"` → `Content-Type: application/json` (JSON body works)
406
+ - `sourceType: "HTML"` → `html` field (JSON or multipart) carrying the raw HTML body (max 5 MB; rendered to PDF server-side)
405
407
 
406
408
  ---
407
409
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-cli
3
- version: 5.8.1
3
+ version: 5.10.0
4
4
  description: >-
5
5
  Use this skill when running Clio CLI commands, building shell scripts with
6
6
  Clio, debugging auth issues, understanding --json output, paginating results,
@@ -362,7 +362,7 @@ Also: `clio reports pdf` — generate PDF from a message/document.
362
362
  ### `clio magic` — AI document extraction
363
363
  | Subcommand | Key flags |
364
364
  |------------|-----------|
365
- | `create <file>` | `--type` (invoice, bill, credit-note-customer, credit-note-supplier), `--wait`, `--password` |
365
+ | `create` | one of `--file <path>` / `--url <url>` / `--html <string\|@file>`; `--type` (invoice, bill, credit-note-customer, credit-note-supplier); `--merged` (split a multi-doc PDF). `--html` takes raw HTML (e.g. an email body), rendered to a PDF server-side. Encrypted PDFs: `name__pw__password.pdf`. |
366
366
  | `status <workflowIds>` | Comma-separated workflow IDs |
367
367
  | `search` | `--type`, `--status`, `--from`, `--to`, `--limit`, `--offset` |
368
368
 
@@ -232,8 +232,11 @@ Ingest documents, extract data via AI, and review results.
232
232
  # Ingest a folder of mixed PDFs (invoices, bills, bank statements)
233
233
  clio jobs ingest ./inbox/ --json
234
234
 
235
- # Or extract a single document
236
- clio magic create ./invoice-from-supplier.pdf --type bill --wait --json
235
+ # Or extract a single document (file, URL, or raw HTML)
236
+ clio magic create --file ./invoice-from-supplier.pdf --type bill --json
237
+
238
+ # From raw HTML — e.g. an email body (rendered to a PDF, then extracted)
239
+ clio magic create --html @./email-body.html --type invoice --json
237
240
 
238
241
  # Check workflow status
239
242
  clio magic status "wf-id-1,wf-id-2,wf-id-3" --json
@@ -241,6 +244,6 @@ clio magic status "wf-id-1,wf-id-2,wf-id-3" --json
241
244
  # Search past magic workflows
242
245
  clio magic search --type bill --status COMPLETED --from 2026-03-01 --json
243
246
 
244
- # For encrypted PDFs
245
- clio magic create ./encrypted-file.pdf --type invoice --password "secret123" --wait
247
+ # For encrypted PDFs — embed the password in the filename via __pw__
248
+ clio magic create --file ./encrypted-file__pw__secret123.pdf --type invoice --json
246
249
  ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-conversion
3
- version: 5.8.1
3
+ version: 5.10.0
4
4
  description: >-
5
5
  Use this skill when migrating accounting data into Jaz — importing from Xero,
6
6
  QuickBooks, Sage, MYOB, or Excel exports. Covers the full conversion pipeline:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-pseudo-sql
3
- version: 5.8.1
3
+ version: 5.10.0
4
4
  description: >-
5
5
  Use this skill when answering ad-hoc data questions that aren't covered by
6
6
  download_export (canonical reports — anomaly, audit, aging, P&L, BS, GL,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-jobs
3
- version: 5.8.1
3
+ version: 5.10.0
4
4
  description: >-
5
5
  Use this skill for recurring accounting workflows — month/quarter/year-end
6
6
  close, bank reconciliation, GST/VAT filing, payment runs, credit control,
@@ -48,7 +48,7 @@ Period-close jobs build on each other. Quarter = month + extras. Year = quarter
48
48
 
49
49
  | Job | CLI Command | Description |
50
50
  |-----|-------------|-------------|
51
- | **Bank Recon** (`generate_bank_recon_blueprint`) | `clio jobs bank-recon` | Clear unreconciled items: match, categorize, resolve. Paired tool: `clio jobs bank-recon match`. *Used in: monthly-close engagement (run as part of every period close; see `jaz-practice/references/monthly-close.md`).* |
51
+ | **Bank Recon** (`generate_bank_recon_blueprint`) | `clio jobs bank-recon` | Clear unreconciled items: match, categorize, resolve. **Match to EXISTING open bills/invoices/payments (`reconcile_with_payments`) is the primary path — create-new only when nothing matches.** Drive end-to-end via the `view_auto_reconciliation` decision gate (auto-commit high-confidence, checkpoint the rest — see `references/bank-recon.md` Step 4a). Paired tool: `clio jobs bank-recon match`. *Used in: monthly-close engagement (run as part of every period close; see `jaz-practice/references/monthly-close.md`).* |
52
52
  | **Document Collection** (`generate_document_collection_blueprint`) | `clio jobs document-collection` | Scan and classify client documents from local directories and cloud links (Dropbox, Drive, OneDrive). Outputs file paths for agent upload. Paired tool: `clio jobs document-collection ingest`. *Used in: onboarding flow (initial client doc capture; see `jaz-practice/references/onboarding.md`) and the open phase of every engagement (monthly-close, quarterly-gst, annual-statutory).* |
53
53
  | **GST/VAT Filing** (`generate_gst_vat_blueprint`) | `clio jobs gst-vat --period YYYY-QN` | Tax ledger review, discrepancy check, filing summary. *Used in: quarterly-gst engagement (see `jaz-practice/references/quarterly-gst.md`).* |
54
54
  | **Payment Run** (`generate_payment_run_blueprint`) | `clio jobs payment-run` | Select outstanding bills by due date, process payments. *Used in: monthly-close engagement (AP cycle inside the period close; see `jaz-practice/references/monthly-close.md`).* |
@@ -223,6 +223,17 @@ clio jobs bank-recon match --input data.json --find-all --json
223
223
  | `1:N` | Multiple bank records match one transaction | Split payment (1 payment across 2 bank entries) |
224
224
  | `N:M` | Multiple bank records match multiple transactions | Complex group match within a contact |
225
225
 
226
+ ### Committing a match → route to the right reconcile tool
227
+
228
+ The matcher finds matches against transactions the org **already has** — so commit via the MATCH-EXISTING path, not create-new:
229
+
230
+ - A 1:1 (or N:1) match to an **existing open bill/invoice** at `exact` / `fuzzy-high` (≥0.85) confidence → **`reconcile_with_payments`** (pass the matched transaction's `cashflowTransactionResourceId` in `businessTransactionPayments[]`). Do NOT use `reconcile_invoice_receipt`/`reconcile_bill_receipt` — those CREATE a duplicate.
231
+ - A batch of high-confidence matches → **`reconcile_magic_match`** in one call.
232
+ - Only when the matcher finds NO existing transaction → create one (`reconcile_invoice_receipt`/`reconcile_bill_receipt` or `create_cash_*`).
233
+ - `fuzzy-medium` (0.70–0.85) / `nm-confident` → surface for confirmation before committing (checkpoint), don't auto-commit.
234
+
235
+ See `bank-recon.md` Step 4a for the full auto-commit-vs-checkpoint decision gate.
236
+
226
237
  ---
227
238
 
228
239
  ## Worked Example
@@ -10,18 +10,24 @@
10
10
  - **`search_accounts(filter: {accountType: {eq: 'Bank Accounts'}})`** — step 1 alternative: same data via standard CoA-search envelope if downstream wants pagination.
11
11
  - **`search_bank_records(accountResourceId: <id>, status: 'UNRECONCILED', valueDateRange: {from, to}, limit: 200, sort: 'valueDate:asc')`** — step 2: per-account work queue.
12
12
  - **`search_bank_records(accountResourceId: <id>, status: 'POSSIBLE_DUPLICATE')`** — step 3: handle dups FIRST or you'll double-create reconciling them.
13
- - **`view_auto_reconciliation(bankAccountResourceId: <id>, recommendationType: 'MAGIC_MATCH' | 'MAGIC_RECONCILE_WITH_CASH_TRANSFER' | 'MAGIC_RECONCILE_WITH_BANK_RULE' | 'MAGIC_QUICK_RECONCILE' | 'MAGIC_RECONCILE_WITH_CASH_IN_OUT')`** — step 4: READ-ONLY auto-match suggestions. `MAGIC_RECONCILE_WITH_CASH_IN_OUT` returns Learned-Predictions (LP) suggestions sourced from past reconciliations on similar bank-entry shapes. Does NOT write. NOTE: documented 500 quirk on high-volume accounts see error table.
13
+ - **`view_auto_reconciliation(bankAccountResourceId: <id>, recommendationType: 'MAGIC_MATCH' | 'MAGIC_RECONCILE_WITH_CASH_TRANSFER' | 'MAGIC_RECONCILE_WITH_BANK_RULE' | 'MAGIC_QUICK_RECONCILE' | 'MAGIC_RECONCILE_WITH_CASH_IN_OUT', autoCommitMaxAmount?: <number>)`** — step 4: READ-ONLY auto-match suggestions. Returns **execution-ready `suggestions[]`** — each carries `recommendedTool`, `execute` (ready-to-pass args), `confidenceTier`, and `autoCommitEligible`. This is the entry point for the auto-match decision gate (step 4a). `MAGIC_RECONCILE_WITH_CASH_IN_OUT` returns Learned-Predictions. Does NOT write. NOTE: 500 quirk on high-volume accounts degrades to `{degraded:true}`; scope by period or fall back to the cascade matcher (see error table).
14
14
  - **`search_cashflow_transactions(filter: {organizationAccountResourceId: <bank-id>, totalAmount: {eq: <amt>}, valueDate: {between: [<-3d>, <+3d>]}})`** — step 5 manual match: search book-side transactions for the same amount within ±3 day window.
15
15
 
16
16
  ### MCP tools — execute reconciliation (NOT idempotent — see error table)
17
- - **`apply_bank_rule(actionShortcutResourceId: <rule-id>, businessTransactionResourceIds: [<bank-entry-ids>])`** step 4: rule-driven recon (async; returns jobId).
18
- - **`quick_reconcile(bankAccountResourceId, journalsForReconciliation: [...])`** — step 4: bulk async (max 500 per call); returns jobId.
19
- - **`reconcile_invoice_receipt(...)`** — step 4: 1:1 match of bank entry to AR invoice.
20
- - **`reconcile_bill_receipt(...)`** — step 4: 1:1 match to AP bill.
21
- - **`reconcile_direct_cash_entry(...)`** — step 4: bank entry to a single cash-in / cash-out line.
22
- - **`reconcile_cash_journal(...)`** — step 4: bank entry to a multi-line cash journal.
23
- - **`reconcile_manual_journal(...)`** — step 4: bank entry to a manual journal.
24
- - **`reconcile_cash_transfer(...)`** step 4: inter-account transfer.
17
+ **Match to EXISTING (preferredno duplicates):**
18
+ - **`reconcile_with_payments(bankStatementEntryResourceId, businessTransactionPayments: [{cashflowTransactionResourceId, transactionAmount}], matchedPayments?, matchedBatchPayments?, adjustment?)`** — **the primary match path.** Match a bank entry to an EXISTING open bill/invoice/payment; creates the payment AND reconciles in one call (no `pay_bill`/`pay_invoice` first). FX auto-resolved server-side — pass no rate. Sync.
19
+ - **`reconcile_magic_match(bankAccountResourceId, entries: [{workflowType:'MAGIC_MATCH', bankStatementEntryResourceId, matchedBusinessTransactions}])`** — bulk-accept MAGIC_MATCH suggestions (max 500). Returns `{reconciled[], failed[]}` a non-empty `failed[]` is a partial success; loop on it.
20
+ - **`reconcile_learned_prediction(bankStatementEntryResourceId, learnedPredictionResourceId, predictedPayload, predictedPayloadSchemaVersion, retryToken?)`** — accept an ML learned-prediction (payload passed verbatim from a `MAGIC_RECONCILE_WITH_CASH_IN_OUT` suggestion).
21
+ - **`apply_bank_rule(actionShortcutResourceId, businessTransactionResourceIds)`** — rule-driven recon (async; returns jobId).
22
+ - **`quick_reconcile(bankAccountResourceId, journalsForReconciliation)`** — bulk async (max 500); returns jobId.
23
+
24
+ **CREATE new (only when no existing open transaction matches):**
25
+ - **`reconcile_invoice_receipt(...)`** — CREATE a new AR invoice + reconcile. ⚠️ To match an EXISTING invoice use `reconcile_with_payments` instead.
26
+ - **`reconcile_bill_receipt(...)`** — CREATE a new AP bill + reconcile. ⚠️ To match an EXISTING bill use `reconcile_with_payments` instead.
27
+ - **`reconcile_direct_cash_entry(...)`** — bank entry to a single cash-in / cash-out line (no source document).
28
+ - **`reconcile_cash_journal(...)`** — bank entry to a multi-line cash journal.
29
+ - **`reconcile_manual_journal(...)`** — bank entry to a manual journal.
30
+ - **`reconcile_cash_transfer(...)`** — inter-account transfer.
25
31
 
26
32
  ### MCP tools — create missing transactions
27
33
  - **`mcp magic create --file <pdf>` / `create_business_transaction_from_attachment(...)`** — step 6 path B: OCR + autofill bill or invoice from receipt PDF/JPG.
@@ -94,20 +100,37 @@ clio jobs bank-recon match \
94
100
  --json
95
101
  ```
96
102
 
97
- Returns matches with confidence scores: `exact` (Phase 1 hash), `fuzzy-high` (Phase 2 weighted ≥ 0.85), `fuzzy-medium` (0.70-0.85), `nm-confident` (Phase 5). For each match returned:
103
+ Returns matches with confidence scores: `exact` (Phase 1 hash), `fuzzy-high` (Phase 2 weighted ≥ 0.85), `fuzzy-medium` (0.70-0.85), `nm-confident` (Phase 5). For each match returned — **prefer MATCH-EXISTING over CREATE-NEW** to avoid duplicating a bill/invoice the org already has:
98
104
 
99
105
  | Match type | Tool to invoke |
100
106
  |------------|----------------|
101
- | AR invoice ↔ bank cash-in | `reconcile_invoice_receipt(bankRecordResourceId, invoiceResourceId, paymentMethod, ...)` |
102
- | AP bill ↔ bank cash-out | `reconcile_bill_receipt(bankRecordResourceId, billResourceId, paymentMethod, ...)` |
103
- | Cash entry (single line) ↔ bank | `reconcile_direct_cash_entry(...)` |
107
+ | **AP bill ↔ bank cash-out (MATCH EXISTING open bill)** | **`reconcile_with_payments(bankStatementEntryResourceId, businessTransactionPayments:[{cashflowTransactionResourceId, transactionAmount}])`** ← primary |
108
+ | **AR invoice ↔ bank cash-in (MATCH EXISTING open invoice)** | **`reconcile_with_payments(...)`** ← primary |
109
+ | Existing payment ↔ bank | `reconcile_with_payments(..., matchedPayments:[...])` |
110
+ | Bulk accept magic suggestions | `reconcile_magic_match(bankAccountResourceId, entries:[...])` → `{reconciled[],failed[]}` |
111
+ | Learned-prediction (cash-in-out) | `reconcile_learned_prediction(...)` |
112
+ | AR invoice — CREATE NEW (no existing match) | `reconcile_invoice_receipt(...)` |
113
+ | AP bill — CREATE NEW (no existing match) | `reconcile_bill_receipt(...)` |
114
+ | Cash entry (single line, no document) ↔ bank | `reconcile_direct_cash_entry(...)` |
104
115
  | Cash journal (multi-line) ↔ bank | `reconcile_cash_journal(...)` |
105
116
  | Manual journal ↔ bank | `reconcile_manual_journal(...)` |
106
117
  | Inter-account transfer | `reconcile_cash_transfer(...)` |
107
- | Bulk same-shape (>5 items) | `quick_reconcile(bankAccountResourceId, journalsForReconciliation: [...])` (async, returns jobId) |
108
- | Bank rule applies | `apply_bank_rule(actionShortcutResourceId, businessTransactionResourceIds: [...])` (async) |
118
+ | Bulk same-shape (>5 items) | `quick_reconcile(...)` (async, returns jobId) |
119
+ | Bank rule applies | `apply_bank_rule(...)` (async) |
109
120
 
110
- For `view_auto_reconciliation` suggestions outside the cascade: invoke once per account, walk the suggestions, commit via the matching `reconcile_*`. Pure read — no execution side effect.
121
+ ## Step 4a Auto-match decision gate (the end-to-end driver)
122
+
123
+ Call `view_auto_reconciliation`. It returns execution-ready `suggestions[]`. On high-volume accounts the engine can 500 (OOM) and the tool returns `{degraded:true}` — recover via the `clio jobs bank-recon match` cascade matcher (Step 4, above), which doesn't hit this endpoint. Walk the suggestions:
124
+
125
+ - **`autoCommitEligible === true`** (high confidence, has an `execute` plan, under any amount cap) → **auto-commit**: call the suggestion's `recommendedTool` with its `execute` args. For many high-confidence matches, prefer ONE `reconcile_magic_match` call (server idempotency-keyed) over looping `reconcile_with_payments` (non-idempotent).
126
+ - **everything else** (medium/low tier, `recommendedTool` undefined, CREATE-NEW, or amount over threshold) → **checkpoint**: surface to the user for confirmation. **The amount threshold is a HARD VETO over confidence** — a high-confidence but large match still checkpoints (pass `autoCommitMaxAmount` to enforce in code).
127
+ - **`{degraded:true}`** (500) → fall back to the `clio jobs bank-recon match` cascade (Step 4, above).
128
+
129
+ **Safety (recon is NOT idempotent):** before EACH auto-commit, re-check `search_bank_records(status:'RECONCILED')` for that entry (guards a concurrent second agent — `reconcile_with_payments` has no client idempotency key). Enforce a per-run auto-commit cap; above it, checkpoint the remainder rather than firing hundreds of irreversible sequential writes.
130
+
131
+ ## Step 4b — Match a bank entry to an existing open bill/invoice
132
+
133
+ When you have a specific open bill/invoice to match (e.g. from `search_cashflow_transactions`), pass its `cashflowTransactionResourceId` to `reconcile_with_payments` — one call creates the payment AND reconciles. **No `pay_bill`/`pay_invoice` first.** Cross-currency (bank ccy ≠ bill ccy) is auto-resolved server-side — pass no rate; only the rare bill-ccy≠bank-ccy case needs explicit `paymentAmount` + `currencySettings`. On `TOTAL_RECONCILIATION_AMOUNT_MISMATCHED...`, put the delta into an `adjustment.cashAdjustmentEntries[]` leg (over/under-payment or FX write-off — the platform does NOT auto-post FX gain/loss) so the total equals the bank entry, then resend.
111
134
 
112
135
  ## Step 5 — Manual match (residuals)
113
136
 
@@ -207,10 +230,15 @@ Per account: `bookBalance == bankStatementBalance ± documentedTimingDifference`
207
230
 
208
231
  | Source | Error | Recovery |
209
232
  |--------|-------|----------|
210
- | `view_auto_reconciliation` | 500 on high-volume account | Documented quirk service can OOM on accounts with thousands of unreconciled rows. Workaround: invoke per-period (`valueDateRange: {from, to}`) instead of all-time, OR fall back to `clio jobs bank-recon match` cascade which doesn't hit this endpoint. |
211
- | `view_auto_reconciliation` | 404 | Endpoint not enabled for the org's plan tier. Use cascade matcher only. |
233
+ | `view_auto_reconciliation` | 500 on high-volume account returns `{degraded:true}` | Documented OOM quirk on accounts with thousands of unreconciled rows. The tool degrades (doesn't throw): scope per-period (`valueDateRange`) OR fall back to `clio jobs bank-recon match` cascade. |
234
+ | `view_auto_reconciliation` | 404 → returns `{notSupported:true}` | Endpoint not enabled for the org's plan tier. Use cascade matcher only. |
212
235
  | `quick_reconcile` | PARTIAL_SUCCESS jobId | Async result. Poll `search_background_jobs(filter: {resourceId: {eq: <jobId>}})` until terminal. Read `data[0].errorDetails[]` for per-row failures; loop back to step 4 for the failed rows. |
213
236
  | `quick_reconcile` / `reconcile_*` | (any) — NOT idempotent (rule 124) | On 500 / network error, do NOT retry. Confirm reconciled state via `view_auto_reconciliation` OR `search_bank_records(status: 'RECONCILED')` first. |
237
+ | `reconcile_with_payments` | (any 5xx/network) — NOT idempotent, **no client key** | A blind retry **double-creates a payment**. ALWAYS re-check `search_bank_records(status:'RECONCILED')` for the entry before retrying. (magic_match is entry-level idempotency-keyed; learned_prediction takes a `retryToken`.) |
238
+ | `reconcile_magic_match` | 200 with non-empty `failed[]` | PARTIAL success — `reconciled[]` succeeded, `failed[]` carries per-entry `errorCode`. Surface failures + loop only on the failed entries. **All-fail** (empty `reconciled[]`) = hard stop, surface. A re-submit returns already-done entries in `reconciled[]` (not `failed[]`) — don't treat them as new failures. |
239
+ | `reconcile_learned_prediction` | error (stale/invalid `predictedPayload`) | Do NOT retry the same opaque payload. Fall back to `reconcile_with_payments` or manual match. `retryToken` forces a fresh journal on an intentional edit-retry; omit for idempotent replay. |
240
+ | `reconcile_with_payments` | 422 `TOTAL_RECONCILIATION_AMOUNT_MISMATCHED...` | Payments + adjustments ≠ bank entry amount. Add the delta as an `adjustment.cashAdjustmentEntries[]` leg (over/under-payment or FX write-off) so the total matches, then resend. |
241
+ | `reconcile_with_payments` | 422 `...does not exist` / invalid status | The BT isn't an open bill/invoice (wrong id, already paid, or draft). Re-fetch via `search_cashflow_transactions`; finalize if draft. |
214
242
  | `reconcile_invoice_receipt` | 422 `invoice_status_invalid` | Matched invoice still DRAFT. `finalize_invoice(resourceId: <id>)` first. |
215
243
  | `reconcile_invoice_receipt` | 422 `amount_mismatch` | Bank amount ≠ invoice balance. Either partial payment (post via `create_invoice_payment` with partial amount, then reconcile), or wrong match (revisit step 4/5). |
216
244
  | `apply_bank_rule` | 422 `rule_action_unsupported` | Rule's configured action doesn't match the bank entry shape (e.g., rule expects positive amount, entry is negative). Edit the rule via `update_bank_rule`. |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-practice
3
- version: 5.8.1
3
+ version: 5.10.0
4
4
  description: >-
5
5
  Use this skill whenever an accounting practitioner is doing client work in
6
6
  Jaz — closing the books, filing GST, year-end statutory, onboarding a new
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-recipes
3
- version: 5.8.1
3
+ version: 5.10.0
4
4
  description: >-
5
5
  Use this skill when modeling complex multi-step accounting transactions —
6
6
  anything that spans multiple periods, involves changing amounts, or requires
@@ -6,7 +6,7 @@ Source of truth lives in the installed skills (`.claude/skills/jaz-*/SKILL.md` o
6
6
 
7
7
  ## Discovery
8
8
 
9
- The Jaz MCP server exposes 285 tools across 34 namespaces via 3 meta-tools. **Use the meta-tool flow — never enumerate tools blindly.**
9
+ The Jaz MCP server exposes 288 tools across 34 namespaces via 3 meta-tools. **Use the meta-tool flow — never enumerate tools blindly.**
10
10
 
11
11
  1. `search_tools(query)` → top-N tool names + namespaces.
12
12
  2. `describe_tools(names)` → full parameter schemas.