jaz-clio 5.62.0 → 5.63.1

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-api
3
- version: 5.62.0
3
+ version: 5.63.1
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, 159 production gotchas, error
@@ -48,7 +48,7 @@ Transaction fees are added to cash spent (not deducted like invoices), and a pay
48
48
 
49
49
  Pre-invoice / pre-bill documents. Sales pipeline: **Sale Quote** (estimate/quotation) → **Sale Order** → Invoice. Purchase pipeline: **Purchase Request** (requisition) → **Purchase Order** (PO) → Bill.
50
50
 
51
- Key capabilities: a Sale Order links to its source quote via `saleQuoteResourceId` (and a PO to its request via `purchaseRequestResourceId`) — the parent must be **issued** (created with `saveAsDraft:false`, i.e. CREATED/ACTIVE), not a DRAFT. Quotes/requests advance with **accept** (from the issued state), orders with **confirm**. Fulfillment is tracked on the parent via `orderState` (NOT_ORDERED / PARTIALLY_ORDERED / FULLY_INVOICED for quotes, FULLY_BILLED for requests — an order+invoice rollup, arap 2026-06; FULLY_ORDERED retired). Orders convert to invoices/bills via `convert_sale_order_to_invoice` / `convert_purchase_order_to_bill`, and the reverse link is exposed as create-time fields (see orders.md). Delete is draft-only; use void otherwise.
51
+ Key capabilities: a Sale Order links to its source quote via `saleQuoteResourceId` (and a PO to its request via `purchaseRequestResourceId`) — the parent must be **issued** (CREATED/ACTIVE), not a DRAFT: create it with `saveAsDraft:false`, or issue an existing draft in place with the update tool's `isDraftToActive*` flag. Orders made by Jaz Magic start PENDING until the update tool's `isPendingToActive*` flag takes them live. Order updates edit lines by `resourceId` and add any line without one (see orders.md). Quotes/requests advance with **accept** (from the issued state), orders with **confirm**. Fulfillment is tracked on the parent via `orderState` (NOT_ORDERED / PARTIALLY_ORDERED / FULLY_INVOICED for quotes, FULLY_BILLED for requests — an order+invoice rollup, arap 2026-06; FULLY_ORDERED retired). Orders convert to invoices/bills via `convert_sale_order_to_invoice` / `convert_purchase_order_to_bill`, and the reverse link is exposed as create-time fields (see orders.md). Delete is draft-only; use void otherwise.
52
52
 
53
53
  **API**: per entity (`sale-quotes`, `sale-orders`, `purchase-requests`, `purchase-orders`): CRUD `GET/POST/PUT/DELETE`, `POST /…/search`, `POST /…/:id/{accept|confirm}`, `POST /…/:id/void`, `POST /…/:id/fast-fix`, `POST /…/bulk-{accept|confirm|void|delete}`; orders also `POST /…/line-items/bulk-upsert`. Agent surface: `sale_orders` + `purchase_orders` namespaces (create/get/search/update/transition). See `references/orders.md`.
54
54
 
@@ -85,9 +85,9 @@ Four entities sharing one shape. Replace `{entity}` with `sale-quotes`, `sale-or
85
85
  |--------|------|-------------|
86
86
  | GET | `/{entity}` | List |
87
87
  | GET | `/{entity}/:resourceId` | Get single |
88
- | POST | `/{entity}` | Create. Sale Order links via `saleQuoteResourceId`; Purchase Order via `purchaseRequestResourceId` (parent must be issued saveAsDraft:false not a draft). |
88
+ | POST | `/{entity}` | Create. Optional `currency { sourceCurrency, exchangeRate? }`. Sale Order links via `saleQuoteResourceId`; Purchase Order via `purchaseRequestResourceId` (parent must be issued, not a DRAFT/VOID, and in the same currency). |
89
89
  | POST | `/{entity}/search` | Advanced search with filters |
90
- | PUT | `/{entity}/:resourceId` | Update |
90
+ | PUT | `/{entity}/:resourceId` | Update. `lineItems` edits by line `resourceId` (`deleted: true` removes; a line without one is ADDED): send every stored line once any names a resourceId. `isDraftToActiveSaleQuote` / `isDraftToActivePurchaseRequest` issue a DRAFT; `isPendingToActiveSaleOrder` / `isPendingToActivePurchaseOrder` take a PENDING order live. |
91
91
  | DELETE | `/{entity}/:resourceId` | Delete (DRAFT only — else use void) |
92
92
  | POST | `/{entity}/:resourceId/void` | Void (cancel) |
93
93
  | POST | `/sale-quotes\|purchase-requests/:resourceId/accept` | Accept (→ ACCEPTED) |
@@ -19,8 +19,10 @@ Two MCP namespaces wrap these: **`sale_orders`** (Sale Quotes + Sale Orders) and
19
19
  | `PURCHASE_ORDER` | DRAFT (default) / ACTIVE (saveAsDraft:false) | **confirm** → CONFIRMED | VOID | yes (default true) |
20
20
 
21
21
  - **Quotes & Requests use `accept`. Orders use `confirm`.** (`transition_*` enforces this via a documentType × action matrix.)
22
- - **`accept` works on the ISSUED state, not DRAFT** a Sale Quote must be CREATED, a Purchase Request must be ACTIVE. Accepting a DRAFT returns `422 Invalid status` (verified live). There is no exposed DRAFTissued verb: **issue a document by creating it with `saveAsDraft:false`** (update with `saveAsDraft:false` does NOT issue an existing DRAFT verified live).
23
- - **Sale Orders have no draft state** `saveAsDraft` is ignored; created directly as `CREATED`.
22
+ - **`accept` works on the ISSUED state, not DRAFT**: a Sale Quote must be CREATED, a Purchase Request must be ACTIVE. Accepting a DRAFT returns `422 Invalid status` (verified live). **Issue an existing DRAFT in place** with the update tool's flag: `update_sale_order` `isDraftToActiveSaleQuote: true` (CREATED), `update_purchase_order` `isDraftToActivePurchaseRequest: true` (→ ACTIVE). Send every stored line with its `resourceId` in the SAME update: a flag-only update is refused with `422 SALE_LINE_ITEMS_REQUIRED` (verified live 2026-09-23 on a sale quote). It keeps the document's number and line ids (verified live: DRAFT → CREATED, same reference, same line `resourceId`; a line without an account issued fine), so never create a second quote/request to issue one. (Update with `saveAsDraft:false` does NOT issue a DRAFT, verified live.) To create one already issued, pass `saveAsDraft:false` on create.
23
+ - **Sale Orders have no draft state**: `saveAsDraft` is ignored; created directly as `CREATED`.
24
+ - **PENDING orders.** Jaz Magic creates Sale Orders and Purchase Orders as `PENDING`. Take one live with `update_sale_order` `isPendingToActiveSaleOrder: true` / `update_purchase_order` `isPendingToActivePurchaseOrder: true`. Search accepts `status: PENDING`.
25
+ - **Each activation flag belongs to one documentType** (`isDraftToActiveSaleQuote` → SALE_QUOTE, `isPendingToActiveSaleOrder` → SALE_ORDER, `isDraftToActivePurchaseRequest` → PURCHASE_REQUEST, `isPendingToActivePurchaseOrder` → PURCHASE_ORDER). The update tools refuse a flag sent for the other type.
24
26
  - Statuses verified live: SQ create → `DRAFT` (or `CREATED` with `saveAsDraft:false`); SQ accept (from CREATED) → `ACCEPTED`; SO create → `CREATED`; SO confirm → `CONFIRMED`; PR create → `DRAFT` (or `ACTIVE` with `saveAsDraft:false`); PR accept (from ACTIVE) → `ACCEPTED`; PO `saveAsDraft:false` → `ACTIVE`; PO confirm → `CONFIRMED`.
25
27
 
26
28
  ## Linking (quote → order, request → PO)
@@ -30,7 +32,9 @@ Quote→Order / Request→PO linking is a **create-time reference field**:
30
32
  - **Quote → Order**: pass `saleQuoteResourceId` on `create_sale_order` (documentType `SALE_ORDER`).
31
33
  - **Request → PO**: pass `purchaseRequestResourceId` on `create_purchase_order` (documentType `PURCHASE_ORDER`).
32
34
 
33
- **The parent must be ISSUED (not DRAFT/VOID).** A CREATED/ACCEPTED quote (or ACTIVE/ACCEPTED request) is linkable — accept is **optional** (CREATED already links). Linking to a `DRAFT`/`VOID` parent returns `SALE_QUOTE_STATUS_INVALID_FOR_ORDER_CONVERSION` ("must not be in VOID or DRAFT status to create sale order"). The `create_*` tools pre-flight this: for a DRAFT parent the `repair` hint says to issue it (create with `saveAsDraft:false`) **not** to accept it (accept fails on DRAFT). So: to order from a quote/request, create the quote/request with `saveAsDraft:false`.
35
+ **The parent must be ISSUED (not DRAFT/VOID).** A CREATED/ACCEPTED quote (or ACTIVE/ACCEPTED request) is linkable — accept is **optional** (CREATED already links). Linking to a `DRAFT`/`VOID` parent returns `SALE_QUOTE_STATUS_INVALID_FOR_ORDER_CONVERSION` ("must not be in VOID or DRAFT status to create sale order"). The `create_*` tools pre-flight this: for a DRAFT parent the `repair` hint points at issuing THAT document in place (`update_sale_order` `isDraftToActiveSaleQuote: true` / `update_purchase_order` `isDraftToActivePurchaseRequest: true`), **not** at accepting it (accept fails on DRAFT) and not at creating a duplicate.
36
+
37
+ **Currency.** A linked order must use the same currency as its quote/request: a linked order in a different currency is refused.
34
38
 
35
39
  Creating and confirming an order from an issued quote rolls the parent quote's `orderState` up to reflect downstream progress (arap order-status rollup, 2026-06): a confirmed order **not yet invoiced** shows `PARTIALLY_ORDERED` (verified live); the terminal `FULLY_INVOICED` is reached only once every linked order is fully invoiced. Purchase requests mirror this with `FULLY_BILLED`. `orderState` is a **response field**, not a search filter — values: `NOT_ORDERED` / `PARTIALLY_ORDERED` / `FULLY_INVOICED` (quotes) / `FULLY_BILLED` (requests). The older `FULLY_ORDERED` value was retired by this rollup.
36
40
 
@@ -49,12 +53,34 @@ Body: `valueDate` + `dueDate` required; `reference` is required unless you set `
49
53
 
50
54
  ## Fields (create)
51
55
 
52
- Required: `valueDate`. Recommended: `reference` (omit it to take the next number from your org's own series must be unique per org), `contactResourceId`, `lineItems`.
56
+ Required: `valueDate`, and `reference` unless you set `autoReference: true` (takes the next number from your org's own series). Omitting both is refused: omitting `reference` does NOT auto-number. `reference` must be unique per org. Recommended: `contactResourceId`, `lineItems`.
57
+
58
+ - `currency: { sourceCurrency, exchangeRate?, rateDirection? }` (all four documents). Omit for the org's base currency; the currency must be enabled on the org. A linked order must name the same currency as its quote/request. Currency is fixed at create: the update body has no currency field. CLI: `--currency <code>` (+ `--exchange-rate`, `--rate-direction`), same as invoices.
53
59
 
54
60
  - Line items reuse the standard shape: `{ name, quantity, unitPrice, accountResourceId?, taxProfileResourceId?, … }`. `accountResourceId` is **required on each line when the document is not a draft** (i.e. always for Sale Orders; for quotes/requests/POs when `saveAsDraft:false`). The `create_*` tools pre-flight this.
55
61
  - Notes field differs by side: **sales** use `invoiceNotes`, **purchases** use `purchaseNotes`. The `notes` tool param maps to the right one automatically.
56
62
  - Other optional fields: `dueDate`, `terms` (0/7/15/30/45/60), `tag`, `customFields`, `billTo`, `billFrom`, `capsuleResourceId`, `expectedTotal`.
57
63
 
64
+ ## Editing line items (update)
65
+
66
+ `lineItems` on `update_sale_order` / `update_purchase_order` **edits lines, it does not replace them.** The API pairs each sent line with a stored line by its `resourceId`:
67
+
68
+ | Sent line | Effect |
69
+ |-----------|--------|
70
+ | has the `resourceId` of a stored line | that line is edited in place |
71
+ | has a stored `resourceId` + `deleted: true` | that line is removed |
72
+ | has no `resourceId` | a NEW line is added |
73
+ | stored line not sent (when any line names a resourceId) | whole update refused: `422 lineItems must include every line item on this … when any line names a resourceId; N not sent` |
74
+
75
+ Measured live (2026-09-23, one-line sale quote): resending the lines without ids answered **200 and left 2 lines** (the "replace" reading duplicates every line); naming some ids but not all → 422; every id sent (+ `deleted: true` on one) → edited in place.
76
+
77
+ To change lines:
78
+ 1. `get_sale_order` / `get_purchase_order` and copy every `lineItems[].resourceId`.
79
+ 2. Send EVERY stored line with its `resourceId`, in display order: edit fields in place, `deleted: true` to remove, and add new lines without a `resourceId`.
80
+ 3. An edited line keeps only what you send: resend every stored field you want kept (tax profile, `taxVatAdjustment`, `withholdingTax`, `discount`, `unit`, `itemResourceId`). Dropping a stored tax profile or a non-zero `taxVatAdjustment` is refused; dropping `withholdingTax` (or the others) is NOT refused, it is silently lost. A GET returns the account as `organizationAccountResourceId`; send it back as `accountResourceId`.
81
+
82
+ The update tools (and `clio … update --lines`) pre-flight this against the stored document: lines with no `resourceId` at all on a document that already has lines are refused locally (nothing is written) unless `appendLines: true` (CLI `--append-lines`) says adding is the intent; naming some stored lines but not all is refused locally with the missing ids.
83
+
58
84
  ## Delete vs Void
59
85
 
60
86
  - **DELETE is draft-only** (422 on anything non-draft). `transition_* action:DELETE` pre-flights status and returns a `repair` hint to use `VOID` for non-draft records.
@@ -82,12 +108,13 @@ clio supplier-credit-notes download <id> # supplier CN PDF
82
108
 
83
109
  ```bash
84
110
  # 1. Issue the quote (--finalize → saveAsDraft:false → status CREATED). A plain
85
- # draft (no --finalize) stays DRAFT and cannot be linked or accepted.
86
- clio sale-orders create -t quote --finalize --contact <id> --lines '[{"name":"Widget","quantity":2,"unitPrice":50,"accountResourceId":"<acct>"}]' --date 2026-05-30 --json
111
+ # draft (no --finalize) stays DRAFT and cannot be linked or accepted until issued
112
+ # in place: clio sale-orders update <quoteId> -t quote --activate --lines '[{"resourceId":"<lineId>",…}]'
113
+ clio sale-orders create -t quote --finalize --ref Q-1001 --contact <id> --lines '[{"name":"Widget","quantity":2,"unitPrice":50,"accountResourceId":"<acct>"}]' --date 2026-05-30 --json
87
114
  # 2. (Optional) accept it (CREATED → ACCEPTED). A CREATED quote is already linkable.
88
115
  clio sale-orders accept <quoteId> --json
89
116
  # 3. Create the order linked to the issued quote (created as CREATED)
90
- clio sale-orders create -t order --quote <quoteId> --contact <id> --lines '[…]' --date 2026-05-30 --json
117
+ clio sale-orders create -t order --auto-ref --quote <quoteId> --contact <id> --lines '[…]' --date 2026-05-30 --json
91
118
  # 4. Confirm the order (CREATED → CONFIRMED)
92
119
  clio sale-orders confirm <orderId> --json
93
120
  # 5. The parent quote now rolls up to orderState = PARTIALLY_ORDERED (confirmed order, not yet invoiced)
@@ -100,7 +127,7 @@ Purchase side is symmetric: `create -t request --finalize` (→ ACTIVE) → (opt
100
127
 
101
128
  ## Search
102
129
 
103
- `search_sale_orders` / `search_purchase_orders` take `documentType` plus the standard filter set (reference, status, contact, contactResourceId, currencyCode, date range, amount range, tag). The `status` enum is the per-side union (sales: DRAFT/CREATED/ACCEPTED/CONFIRMED/VOID; purchases: DRAFT/ACTIVE/ACCEPTED/CONFIRMED/VOID). For advanced/nested queries (e.g. filter by `saleQuoteResourceId`), pass the raw `filter` object. See `search-reference.md` §24–25 and `search-enums.md` §25–26.
130
+ `search_sale_orders` / `search_purchase_orders` take `documentType` plus the standard filter set (reference, status, contact, contactResourceId, currencyCode, date range, amount range, tag). The `status` enum is the per-side union (sales: DRAFT/PENDING/CREATED/ACCEPTED/CONFIRMED/VOID; purchases: DRAFT/PENDING/ACTIVE/ACCEPTED/CONFIRMED/VOID). For advanced/nested queries (e.g. filter by `saleQuoteResourceId`), pass the raw `filter` object. See `search-reference.md` §24–25 and `search-enums.md` §25–26.
104
131
 
105
132
  Search behaves exactly like the other entities: `sortBy` is an array, `order` is `ASC`/`DESC`, and an `offset` must be paired with a sort. Duplicate `sortBy` values are rejected (`422 — must contain unique values`).
106
133
 
@@ -414,7 +414,7 @@ No enum fields. Plain string filters (no operators): `currencyCode`, `name`, `pu
414
414
 
415
415
  | Field | Valid Values |
416
416
  |-------|-------------|
417
- | `status` | `DRAFT`, `CREATED`, `ACCEPTED`, `CONFIRMED`, `VOID` |
417
+ | `status` | `DRAFT`, `PENDING`, `CREATED`, `ACCEPTED`, `CONFIRMED`, `VOID` |
418
418
  | `currencyCode` | ISO 4217 (see above) |
419
419
  | `terms` | `0`, `7`, `15`, `30`, `45`, `60` (integer — payment terms in days) |
420
420
 
@@ -422,7 +422,7 @@ No enum fields. Plain string filters (no operators): `currencyCode`, `name`, `pu
422
422
  **Date fields**: `valueDate`, `dueDate`, `createdAt` (DateTime), `updatedAt` (DateTime), `approvedAt`
423
423
  **Link field**: `saleQuoteResourceId` (on Sale Orders — the source quote)
424
424
 
425
- > The `status` enum is the union across both sale documents: a **Sale Quote** moves `DRAFT → CREATED → ACCEPTED` (then `VOID`); a **Sale Order** is created as `CREATED → CONFIRMED` (then `VOID`). Fulfillment is reported on the parent quote via `orderState` (`NOT_ORDERED`, `PARTIALLY_ORDERED`, `FULLY_INVOICED`) — an order+invoice rollup (arap, 2026-06; `FULLY_ORDERED` retired), response field only, not a search filter.
425
+ > The `status` enum is the union across both sale documents: a **Sale Quote** moves `DRAFT → CREATED → ACCEPTED` (then `VOID`); a **Sale Order** is created as `CREATED → CONFIRMED` (then `VOID`). An order made by Jaz Magic starts `PENDING` until `update_sale_order` with `isPendingToActiveSaleOrder: true` takes it live. Fulfillment is reported on the parent quote via `orderState` (`NOT_ORDERED`, `PARTIALLY_ORDERED`, `FULLY_INVOICED`) — an order+invoice rollup (arap, 2026-06; `FULLY_ORDERED` retired), response field only, not a search filter.
426
426
 
427
427
  ---
428
428
 
@@ -430,7 +430,7 @@ No enum fields. Plain string filters (no operators): `currencyCode`, `name`, `pu
430
430
 
431
431
  | Field | Valid Values |
432
432
  |-------|-------------|
433
- | `status` | `DRAFT`, `ACTIVE`, `ACCEPTED`, `CONFIRMED`, `VOID` |
433
+ | `status` | `DRAFT`, `PENDING`, `ACTIVE`, `ACCEPTED`, `CONFIRMED`, `VOID` |
434
434
  | `currencyCode` | ISO 4217 |
435
435
  | `terms` | `0`, `7`, `15`, `30`, `45`, `60` |
436
436
 
@@ -438,7 +438,7 @@ No enum fields. Plain string filters (no operators): `currencyCode`, `name`, `pu
438
438
  **Date fields**: `valueDate`, `dueDate`, `createdAt` (DateTime), `updatedAt` (DateTime), `approvedAt`
439
439
  **Link field**: `purchaseRequestResourceId` (on Purchase Orders — the source request)
440
440
 
441
- > The `status` enum is the union across both purchase documents: a **Purchase Request** moves `DRAFT → ACTIVE → ACCEPTED` (then `VOID`); a **Purchase Order** moves `DRAFT → ACTIVE → CONFIRMED` (then `VOID`). Fulfillment is reported on the parent request via `orderState` (`NOT_ORDERED`, `PARTIALLY_ORDERED`, `FULLY_BILLED`) — an order+invoice rollup (arap, 2026-06; `FULLY_ORDERED` retired), response field only, not a search filter.
441
+ > The `status` enum is the union across both purchase documents: a **Purchase Request** moves `DRAFT → ACTIVE → ACCEPTED` (then `VOID`); a **Purchase Order** moves `DRAFT → ACTIVE → CONFIRMED` (then `VOID`). An order made by Jaz Magic starts `PENDING` until `update_purchase_order` with `isPendingToActivePurchaseOrder: true` takes it live. Fulfillment is reported on the parent request via `orderState` (`NOT_ORDERED`, `PARTIALLY_ORDERED`, `FULLY_BILLED`) — an order+invoice rollup (arap, 2026-06; `FULLY_ORDERED` retired), response field only, not a search filter.
442
442
 
443
443
  ---
444
444
 
@@ -723,7 +723,7 @@ Also covers `POST /api/v1/sale-quotes/search` — same filter shape (`SaleOrderF
723
723
  |-------|------|-------|
724
724
  | `resourceId` | StringExpression | |
725
725
  | `reference` | StringExpression | Order/quote number |
726
- | `status` | StringExpression | DRAFT, CREATED, ACCEPTED, CONFIRMED, VOID |
726
+ | `status` | StringExpression | DRAFT, PENDING, CREATED, ACCEPTED, CONFIRMED, VOID |
727
727
  | `contactResourceId` | StringExpression | |
728
728
  | `contact` | ContactNestedFilter | Nested: name, resourceId, status |
729
729
  | `saleQuoteResourceId` | StringExpression | (Sale Orders) source quote link |
@@ -755,7 +755,7 @@ Also covers `POST /api/v1/purchase-requests/search` — same filter shape (`Purc
755
755
  |-------|------|-------|
756
756
  | `resourceId` | StringExpression | |
757
757
  | `reference` | StringExpression | Order/request number |
758
- | `status` | StringExpression | DRAFT, ACTIVE, ACCEPTED, CONFIRMED, VOID |
758
+ | `status` | StringExpression | DRAFT, PENDING, ACTIVE, ACCEPTED, CONFIRMED, VOID |
759
759
  | `contactResourceId` | StringExpression | Supplier |
760
760
  | `contact` | ContactNestedFilter | Nested: name, resourceId, status |
761
761
  | `purchaseRequestResourceId` | StringExpression | (Purchase Orders) source request link |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-cli
3
- version: 5.62.0
3
+ version: 5.63.1
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,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-conversion
3
- version: 5.62.0
3
+ version: 5.63.1
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-kit
3
- version: 5.62.0
3
+ version: 5.63.1
4
4
  description: >-
5
5
  Use this skill when an accountant, bookkeeper, or owner is running real books
6
6
  in Jaz across one or more organizations from the terminal — setting up a
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-pseudo-sql
3
- version: 5.62.0
3
+ version: 5.63.1
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.62.0
3
+ version: 5.63.1
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,
@@ -110,7 +110,7 @@ Cross-check: `generate_trial_balance(period_end: '2025-01-31')`. Sum credit move
110
110
 
111
111
  For each existing `Prepaid Expenses` capsule (via `search_capsules(filter: {status: {eq: 'ACTIVE'}})` (capsule type is not filterable — see `building-blocks.md` § Filter limits)):
112
112
 
113
- 1. **STOP — do not select these with a filter.** Journals cannot be narrowed to one capsule: `JournalFilter` declares no `capsuleResourceId`, a journal row carries no capsule link even at `view: 'full'` or on `GET /journals/{id}`, and `GET /capsules/{id}` returns only `totalTransactions` a count (all measured 2026-09-07). A date+status search returns EVERY matching DRAFT in the org, including drafts a practitioner deliberately parked, so passing it to `bulk_update_journals(saveAsDraft: false)` finalizes unrelated work. Surface the capsule and its expected journal count and let the practitioner identify the journals to finalize.
113
+ 1. **STOP — do not select these with a filter.** Journals cannot be narrowed to one capsule by a filter: `JournalFilter` declares no `capsuleResourceId`, and `GET /capsules/{id}` returns only `totalTransactions`, a count (measured 2026-09-07). A date+status search returns EVERY matching DRAFT in the org, including drafts a practitioner deliberately parked, so passing it to `bulk_update_journals(saveAsDraft: false)` finalizes unrelated work. `get_journal` (`GET /journals/{id}`) does return the link as `capsule: {resourceId, type, title}` (measured 2026-09-23), so check each candidate journal's `capsule.resourceId` against this capsule, keep only the matches, and confirm the count with the practitioner before finalizing.
114
114
  2. If empty: either the recipe was set up wrong (no journal for this period — investigate via `search_journals` without status filter to see if it's already ACTIVE, then skip), OR the practitioner went off-recipe. Surface to practitioner.
115
115
  3. If found: collect resourceIds, then `bulk_update_journals(items: [{resourceId: <id>, saveAsDraft: false}, ...])`.
116
116
  4. New prepaid setups during this period (a new prepaid started this month): invoke `plan_recipe(recipe: 'prepaid-expense', ...)` (see the `prepaid-expense` recipe in the transaction-recipes skill) — this creates the bill + N future-dated DRAFT journals; the current period's journal is then in the bulk_finalize_drafts queue above.
@@ -141,7 +141,7 @@ On first month of FY only — engine creates the scheduler and posts the first a
141
141
 
142
142
  For each active loan capsule (via `search_capsules(filter: {status: {eq: 'ACTIVE'}})` (capsule type is not filterable — see `building-blocks.md` § Filter limits)):
143
143
 
144
- 1. **STOP — do not select these with a filter.** Journals cannot be narrowed to one capsule: `JournalFilter` declares no `capsuleResourceId`, a journal row carries no capsule link even at `view: 'full'` or on `GET /journals/{id}`, and `GET /capsules/{id}` returns only `totalTransactions` a count (all measured 2026-09-07). A date+status search returns EVERY matching DRAFT in the org, including drafts a practitioner deliberately parked, so passing it to `bulk_update_journals(saveAsDraft: false)` finalizes unrelated work. Surface the capsule and its expected journal count and let the practitioner identify the journals to finalize.
144
+ 1. **STOP — do not select these with a filter.** Journals cannot be narrowed to one capsule by a filter: `JournalFilter` declares no `capsuleResourceId`, and `GET /capsules/{id}` returns only `totalTransactions`, a count (measured 2026-09-07). A date+status search returns EVERY matching DRAFT in the org, including drafts a practitioner deliberately parked, so passing it to `bulk_update_journals(saveAsDraft: false)` finalizes unrelated work. `get_journal` (`GET /journals/{id}`) does return the link as `capsule: {resourceId, type, title}` (measured 2026-09-23), so check each candidate journal's `capsule.resourceId` against this capsule, keep only the matches, and confirm the count with the practitioner before finalizing.
145
145
  2. Should return exactly one DRAFT journal per active loan. Each is a 3-line entry (debit Loan Payable, debit Interest Expense, credit Cash) with the correct amortization split for the period.
146
146
  3. Collect resourceIds, then `bulk_update_journals(items: [{resourceId: <id>, saveAsDraft: false}, ...])`.
147
147
  4. Do NOT post manual loan-interest accruals — the recipe already emitted the journal with the correct split per `clio calc loan` schedule.
@@ -118,7 +118,7 @@ plan_recipe(
118
118
  )
119
119
  ```
120
120
 
121
- Then `execute_recipe(...)`. Engine emits 2 journals: declaration (Dr Retained Earnings / Cr Dividends Payable, with optional withholding leg) and payment cash-out. Both attached to the dividend capsule. Both can be DRAFT or ACTIVE based on `finalize` flag.
121
+ Then `execute_recipe(...)`. Engine emits a declaration journal (Dr Retained Earnings / Cr Dividends Payable) and a payment cash-out, plus a withholding cash-out when `withholdingRate > 0`. Only the declaration journal follows the `finalize` flag (DRAFT or ACTIVE). The cash-outs post ACTIVE immediately, dated `paymentDate`: cash entries have no draft state. So run `execute_recipe` on the actual payment date, not at FY-end when the dividend is only declared. If the declaration must be booked in the FY-end close, post it alone with `create_journal` and record the payment with `create_cash_out` when the money leaves the account.
122
122
 
123
123
  For interim dividends declared during the year: those should already be posted in their respective monthly closes. Y3 covers FY-end final dividend only.
124
124
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-recipes
3
- version: 5.62.0
3
+ version: 5.63.1
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
@@ -77,22 +77,17 @@ If `topUpRequired` is below the entity's materiality threshold: skip the recipe
77
77
 
78
78
  ```
79
79
  plan_recipe(
80
- // Note: gl*, capsuleType, capsuleName, bankAccountResourceId, vendor, customer below are illustrative — auto-resolved at execute time from CoA, not real plan_recipe params.
81
80
  recipe: 'ecl',
82
- receivables: [
83
- {bucket: 'current', balance: 100000, lossRate: 0.005},
84
- {bucket: '30d', balance: 50000, lossRate: 0.02},
85
- {bucket: '60d', balance: 20000, lossRate: 0.05},
86
- {bucket: '90d', balance: 10000, lossRate: 0.10},
87
- {bucket: '120d+', balance: 5000, lossRate: 0.50}
81
+ buckets: [
82
+ {name: 'Current', balance: 100000, rate: 0.5},
83
+ {name: '1-30 days', balance: 50000, rate: 2},
84
+ {name: '31-60 days', balance: 20000, rate: 5},
85
+ {name: '61-90 days', balance: 10000, rate: 10},
86
+ {name: '91+ days', balance: 5000, rate: 50}
88
87
  ],
89
88
  existingProvision: 5000,
90
89
  currency: 'SGD',
91
- glAllowance: <resourceId of 'Allowance for Doubtful Debts' account>,
92
- glBadDebtExpense: <resourceId of 'Bad Debt Expense' account>,
93
- valueDate: '2025-12-31',
94
- capsuleType: 'ECL Provision',
95
- capsuleName: 'FY2025 Year-End ECL True-Up'
90
+ startDate: '2025-12-31' // provision date: the aged AR report date. The ECL journal is dated on it.
96
91
  )
97
92
  ```
98
93
 
@@ -113,6 +108,10 @@ If `Allowance for Doubtful Debts` doesn't exist in the CoA: `create_account(name
113
108
  execute_recipe(recipe: 'ecl', ...same args...) // accounts auto-resolved from CoA; pass `bankAccountName` / `contactName` for fuzzy resolve
114
109
  ```
115
110
 
111
+ `startDate` is required: it dates the ECL journal, so pass the aged AR report date (`2025-12-31` here).
112
+
113
+ When the calculated ECL equals `existingProvision` there is no adjustment: the plan has no steps and `execute_recipe` refuses with "Nothing to post" before creating anything.
114
+
116
115
  Returns: `{ capsule: {resourceId, type, title}, steps: [{step: 1, action: 'journal', status: 'created', resourceId: <journal id>}], summary: {total: 1, created: 1} }`. The single journal is DRAFT — finalize via `update_journal(resourceId: <id>, saveAsDraft: false)` once the practitioner confirms the inputs.
117
116
 
118
117
  ### Step 5 — Verify
@@ -83,7 +83,7 @@ execute_recipe(recipe: 'loan', ...same args...) // accounts auto-resolved from
83
83
  ```
84
84
 
85
85
  Returns: `{ capsule: {resourceId, type, title}, steps: [{step, action, status, resourceId}, ...], summary: {total, created, ...} }`. The recipe creates **termMonths + 1 entries upfront**:
86
- - Step 1: 1 cash-in for the loan disbursement (per `jaz-api/SKILL.md` rule 26: `accountResourceId` at top level for the bank account, `lines: [{accountResourceId: <Loan Payable>, amount: 100000}]` for the offset). Posted ACTIVE if `finalize: true` was passed; otherwise DRAFT.
86
+ - Step 1: 1 cash-in for the loan disbursement (per `jaz-api/SKILL.md` rule 26: `accountResourceId` at top level for the bank account, `lines: [{accountResourceId: <Loan Payable>, amount: 100000}]` for the offset). Posted ACTIVE immediately, whatever `finalize` says: cash entries have no draft state.
87
87
  - Steps 2..termMonths+1: **N future-dated DRAFT journals** (one per repayment period, dated end-of-month for each month from `<startDate>+1 month` through `<startDate>+termMonths`). Each is a 3-line entry: debit Loan Payable (principal portion per amortization schedule), debit Interest Expense (interest portion), credit Cash.
88
88
 
89
89
  All N journals attach to the same capsule. They sit DRAFT until you finalize them — typically one per month during monthly-close after the actual bank payment posts.
@@ -95,17 +95,19 @@ execute_recipe(recipe: 'dividend', ...same args...) // accounts auto-resolved f
95
95
 
96
96
  Returns: `{ capsule: {resourceId, type, title}, steps: [{step, action, status, resourceId}, ...], summary: {total: 2 or 3, created: 2 or 3} }`. The recipe creates 2 entries (or 3 with withholding), all attached to the same capsule:
97
97
  - Declaration journal (DRAFT or ACTIVE per `finalize` flag)
98
- - Payment cash-out (DRAFT the actual bank payment hasn't happened yet at recipe-execution time; finalize when payment leaves the account)
99
- - Withholding cash-out (DRAFT — same; finalize when the WHT remittance is made to tax authority)
98
+ - Payment cash-out: posted ACTIVE immediately, dated `paymentDate`. Cash entries have no draft state, so `finalize` does not apply and there is nothing to finalize later.
99
+ - Withholding cash-out: same, posted ACTIVE immediately, dated `paymentDate`.
100
100
 
101
- ### Step 5 Verify (after both finalized)
101
+ **Run the recipe on the actual payment date**, once the money has left the bank account. The declaration journal still carries `declarationDate`, so booking it late puts it in the right period. Running at declaration time instead posts a live bank payment that has not happened yet, which the bank reconciliation will not match until the real payment arrives. If the declaration must be booked before the payment (for example at FY-end), post the declaration alone with `create_journal` (Dr Retained Earnings / Cr Dividends Payable) and record the payment with `create_cash_out` when the money leaves the account.
102
+
103
+ ### Step 5 — Verify (after the declaration is finalized and the payment is posted)
102
104
 
103
105
  After declaration finalized (Dec 31, 2025):
104
106
  - `generate_balance_sheet(period_end: '2025-12-31')`.
105
107
  - Assert: `balance['Retained Earnings']` reduced by 200,000.
106
108
  - Assert: `balance['Dividends Payable']` increased by 200,000.
107
109
 
108
- After payment finalized (Mar 15, 2026):
110
+ After payment posted (Mar 15, 2026):
109
111
  - `generate_balance_sheet(period_end: '2026-03-15')`.
110
112
  - Assert: `balance['Dividends Payable']` is now 0.
111
113
  - Assert: `balance['Cash']` reduced by 200,000 (or 180,000 if withholding).
@@ -148,6 +150,6 @@ After payment AND WHT remittance:
148
150
  ## Cross-references
149
151
 
150
152
  - Year-end close (Y3 in year-end-close) — final FY dividend declaration AFTER the FY's audited net profit is determined. The declared amount and withholding rate drive the recipe inputs.
151
- - Month-end close — interim dividends declared mid-year are posted in the month they were declared. Recipe runs once at declaration; payment cash-out finalizes when the actual bank disbursement happens (typically next month).
153
+ - Month-end close — interim dividends declared mid-year are posted in the month they were declared. The payment cash-outs post ACTIVE the moment the recipe runs, so run it once the bank disbursement has happened (typically next month), or book the declaration alone with `create_journal` in the declaration month and record the payment with `create_cash_out` when it is made.
152
154
  - `audit-prep.md` step 8 — auditor reviews `generate_equity_movement` to verify dividends are correctly classified as equity reduction (not P&L expense).
153
155
  - `statutory-filing.md` — SG Form C-S Box 12 (dividends paid during YA) reads from this capsule's payment cash-out entries.
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### Recipe engine entry point
8
8
  - **`plan_recipe(recipe: 'fixed-deposit', ...)`** — used in step 2: returns RecipePlan with placement + N accrual + maturity steps.
9
- - **`execute_recipe(recipe: 'fixed-deposit', ...)`** — used in step 4: posts the placement cash-out (today), N future-dated DRAFT accrual journals (one per period), and maturity cash-in (dated termMonths later, also DRAFT).
9
+ - **`execute_recipe(recipe: 'fixed-deposit', ...)`** — used in step 4: posts the placement cash-out (today), N future-dated DRAFT accrual journals (one per period), and maturity cash-in (dated termMonths later, posted ACTIVE immediately: cash entries have no draft state).
10
10
 
11
11
  ### Calculator (cross-check, no API key needed)
12
12
  - **`clio calc fixed-deposit --principal <p> --rate <annual %> --term <months> --start-date <YYYY-MM-DD> --currency <code> [--compound monthly|annually] --json`** — used in step 1: compute monthly accrual amounts. Default simple interest; `--compound` for compound interest. Returns `{ totalInterest, schedule[n] }` where each row carries `period`, `accrualDate`, `accrualAmount`, `accruedToDate`, `journal`.
@@ -83,7 +83,7 @@ Bank account: resolve `bankAccountResourceId` for the disbursement bank (where t
83
83
  execute_recipe(recipe: 'fixed-deposit', ...same args...) // accounts auto-resolved from CoA; pass `bankAccountName` / `contactName` for fuzzy resolve
84
84
  ```
85
85
 
86
- Returns: `{ capsule: {resourceId, type, title}, steps: [{step, action, status, resourceId}, ...14], summary: {total: 14, created: 14} }`. The recipe creates 14 entries upfront: 1 placement cash-out (immediately ACTIVE if `finalize: true`), 12 future-dated DRAFT accrual journals, 1 future-dated DRAFT maturity cash-in (dated `startDate + termMonths`).
86
+ Returns: `{ capsule: {resourceId, type, title}, steps: [{step, action, status, resourceId}, ...14], summary: {total: 14, created: 14} }`. The recipe creates 14 entries upfront: 1 placement cash-out (ACTIVE immediately, whatever `finalize` says), 12 future-dated DRAFT accrual journals, 1 future-dated maturity cash-in (dated `startDate + termMonths`, also ACTIVE immediately: cash entries have no draft state).
87
87
 
88
88
  ### Step 5 — Monthly action (during monthly-close)
89
89
 
@@ -31,7 +31,7 @@
31
31
 
32
32
  ### Engine entry points (DO NOT INVOKE in normal operation)
33
33
  - ~~`plan_recipe(recipe: 'fx-reval', ...)`~~ — engine still accepts this for legacy reasons; output is for inspection only.
34
- - ~~`execute_recipe(recipe: 'fx-reval', ...)`~~ **double-posts. Never invoke in a production org.**
34
+ - ~~`execute_recipe(recipe: 'fx-reval', ...)`~~ (and `clio ct fx-reval` without `--plan`): **refused.** Executing would double-post, so the engine rejects the call before it creates anything.
35
35
 
36
36
  ### Cross-references
37
37
  - Operational context: invoked during month-end close only as a VERIFICATION step (cross-check Jaz's auto-posted reval against an independent calculation; surface any variance). Same during the GST/VAT filing cycle and year-end close.
@@ -130,9 +130,9 @@ This file feeds `audit-prep.md` step 8 supporting schedules. Auditors love indep
130
130
 
131
131
  ---
132
132
 
133
- ## Why the engine still accepts the recipe
133
+ ## Why the engine still plans the recipe
134
134
 
135
- Historical: pre-platform-auto-FX-reval orgs needed this. Some orgs may still run on a configuration where auto-FX is disabled (rare, legacy). For those orgs, `execute_recipe(recipe: 'fx-reval', ...)` posts the manual reval per the prior version of this recipe (period-end journal + Day 1 reversal). DO NOT use this path in any modern org.
135
+ Historical: pre-platform-auto-FX-reval orgs needed this. Some orgs may still run on a configuration where auto-FX is disabled (rare, legacy). `execute_recipe(recipe: 'fx-reval', ...)` is refused for every org, so for those orgs take the period-end journal and Day 1 reversal from `plan_recipe(recipe: 'fx-reval', ...)` and post them as two manual journals with `create_journal` (the reversal dated the first day of the next period). DO NOT do this in any modern org.
136
136
 
137
137
  If you genuinely need to know whether auto-FX is enabled for a specific org: check organization settings via `get_organization()`. If the auto-FX flag is on (default and typical), this recipe is verification-only as documented above.
138
138
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### Recipe engine entry point
8
8
  - **`plan_recipe(recipe: 'provision', ...)`** — used in step 2: returns RecipePlan with PV-recognition journal + N period unwinding journals + settlement cash-out.
9
- - **`execute_recipe(recipe: 'provision', ...)`** — used in step 4: posts initial PV journal (today), N future-dated DRAFT discount-unwinding journals (one per month), and settlement cash-out (dated `settlementDate`, also DRAFT).
9
+ - **`execute_recipe(recipe: 'provision', ...)`** — used in step 4: posts initial PV journal (today), N future-dated DRAFT discount-unwinding journals (one per month), and settlement cash-out (dated `settlementDate`, posted ACTIVE immediately: cash entries have no draft state).
10
10
 
11
11
  ### Calculator (cross-check, no API key needed)
12
12
  - **`clio calc provision --amount <undiscounted total> --rate <annual %> --term <months> --start-date <YYYY-MM-DD> --currency <code> --json`** — used in step 1: compute PV at recognition + per-period unwinding charge. Returns `{ presentValue, totalUnwindingCharge, schedule[n] }` where each row has `period`, `openingProvision`, `unwindingCharge`, `closingProvision`.
@@ -83,7 +83,7 @@ Bank account: only needed for the settlement cash-out at the end of the term.
83
83
  execute_recipe(recipe: 'provision', ...same args...) // accounts auto-resolved from CoA; pass `bankAccountName` / `contactName` for fuzzy resolve
84
84
  ```
85
85
 
86
- Returns: `{ capsule: {resourceId, type, title}, steps: [{step, action, status, resourceId}, ...62], summary: {total: 62, created: 62} }`. Initial recognition journal (today, ACTIVE if `finalize: true`); 60 future-dated DRAFT unwinding journals; 1 future-dated DRAFT settlement cash-out.
86
+ Returns: `{ capsule: {resourceId, type, title}, steps: [{step, action, status, resourceId}, ...62], summary: {total: 62, created: 62} }`. Initial recognition journal (today, ACTIVE if `finalize: true`); 60 future-dated DRAFT unwinding journals; 1 future-dated settlement cash-out, posted ACTIVE immediately (cash entries have no draft state).
87
87
 
88
88
  ### Step 5 — Monthly action (during monthly-close)
89
89