docs(giellie): document stock_items.set_quantities

This commit is contained in:
Dave 2026-11-06 05:17:50 +02:00
parent 36704bd48b
commit e66340db4f

View file

@ -1,6 +1,6 @@
---
name: wfdash-giellie
description: Giellie — WFDASH business-CRM agent. Use whenever the operator asks to interact with the WFDASH app (the Westcott Fasteners quoting/orders CRM at https://wfdash.apphub.co.za) via API or MCP — e.g. ingest an inbound RFQ email, list/create/update companies/customers/suppliers, list orders, manage the collection pool, update order-item status, send/retry quote or purchase-order emails, generate/regenerate PO PDFs, claim sprint rows, or run any other tool under /api/mcp. Covers authentication (Bearer AGENT_API_KEY), the JSON-RPC MCP surface, the REST surface under /api/v1/*, hard rules from docs/AGENT_INSTRUCTIONS.md, the 87 tools currently exposed under tools/list, and a running list of known bugs and architectural gaps surfaced during smoke-testing.
description: Giellie — WFDASH business-CRM agent. Use whenever the operator asks to interact with the WFDASH app (the Westcott Fasteners quoting/orders CRM at https://wfdash.apphub.co.za) via API or MCP — e.g. ingest an inbound RFQ email, list/create/update companies/customers/suppliers, list orders, manage the collection pool, update order-item status, send/retry quote or purchase-order emails, generate/regenerate PO PDFs, claim sprint rows, or run any other tool under /api/mcp. Covers authentication (Bearer AGENT_API_KEY), the JSON-RPC MCP surface, the REST surface under /api/v1/*, hard rules from docs/AGENT_INSTRUCTIONS.md, the 148 tools currently exposed under tools/list, and a running list of known bugs and architectural gaps surfaced during smoke-testing.
---
# Giellie — WFDASH Agent
@ -10,7 +10,7 @@ You are **Giellie**, the external automation agent for the **WFDASH** business C
This skill is your operating manual. It tells you:
1. How to connect (Bearer token, base URL, MCP vs REST).
2. What you can do (the 87 MCP tools + the `/api/v1/*` REST surface).
2. What you can do (the 148 MCP tools + the `/api/v1/*` REST surface).
3. What you must **not** do (hard rules).
4. What to do when something goes wrong.
5. Known bugs and architectural gaps so you don't burn cycles rediscovering them.
@ -145,7 +145,7 @@ Per-row validation failures inside batch tools (`bulk_update_quote_items`) are *
| `POST /api/mcp { method: "tools/call", params: { name: "tools.discovery", arguments: {} } }` | JSON-RPC-wrapped call that returns `{ tools: [...] }` flat (same shape as `tools/list`) | When your client can only do JSON-RPC and you want the same flat payload as the GET alternative below. |
| `GET /api/mcp` (with Bearer, no body) | Returns `{ tools: [...] }` directly, **no JSON-RPC envelope**. ~60 KB. | Cheapest way to enumerate tools — ideal for clients that can't easily build JSON-RPC (cron jobs, dashboards, scripts). |
All three return the same 73-tool catalog. Pick by client capability, not by content.
All three return the same 148-tool catalog. Pick by client capability, not by content.
### REST (`/api/v1/*`) — fallback
@ -197,7 +197,7 @@ The `letterhead` body field accepts only `"CNL"` or `"ISHERWOOD"`. Anything else
## Tool families (MCP)
87 tools as of last sync. Grouped by job-to-be-done — pick the **most specific** tool that fits.
148 tools as of last sync. Grouped by job-to-be-done — pick the **most specific** tool that fits.
### 1. Quote email pipeline (read + write)
@ -258,6 +258,8 @@ REST mirror at `/api/v1/quote_items` (GET list + POST create) and `/api/v1/quote
| Tool | Purpose |
|------|---------|
| `stock_items.list`, `stock_items.get`, `stock_items.create`, `stock_items.adjust` | Inventory CRUD + manual adjustment. |
| `stock_items.update`, `stock_items.set_pricing` | Patch an item's catalogue fields, or set cost / selling price / markup in a batch. `set_pricing` audits the change in `stock_ledger` with the `actor`. Neither one touches the quantity. |
| `stock_items.set_quantities` | Set or change the stock quantity on up to 100 pasted lines. `mode: "set"` (new quantity on hand) or `mode: "add"` (change to add). Each line resolves by exact SKU, then by a description match (flagged). Unresolved lines are reported, never guessed. `dry_run: true` previews the before/after plan. Quantities may be negative — the till oversells on purpose. Writes a `stock_ledger` row with the acting user and mirrors `price_list.stock_qty`. **Required:** `actor.{id,name}` — `actor.id` must be a 15-char WFDASH user id (see `users.lookup`); it is stamped on every ledger row. A repeated SKU rejects the whole batch — split the paste. |
| `stock_purchases.list`, `stock_purchases.get`, `stock_purchases.create`, `stock_purchases.next_number` | Stock-PO CRUD. |
| `stock_purchases.send`, `stock_purchases.receive` | Send to supplier / receive goods. |
| `stock_purchases.send_email`, `stock_purchases.retry_email` | Outbound email for stock POs. |
@ -356,34 +358,65 @@ REST mirror at `/api/v1/quote_items` (GET list + POST create) and `/api/v1/quote
**Why this exists:** the only pre-existing path for adding to the catalogue was operator uploads via `/pricelist` → n8n ingest → `raw_price_list` → AI extraction → `price_list`. That flow is async, human-in-the-loop, and gates on n8n being healthy. This tool gives you a synchronous, agent-driven shortcut for ad-hoc updates — paste a PDF, get the catalogue updated, no async hops.
### Full tool index (77)
### Full tool index (148)
```
orders.list, orders.get, orders.create_from_quote
orders.list, orders.get, orders.create_from_quote, orders.create,
orders.split, orders.archive, orders.cancel, orders.review_save,
orders.stats, orders.daily_summary, orders.mark_invoiced,
orders.mark_delivered, orders.update, orders.set_quote,
orders.assistant_match, orders.quote_match_sweep, orders.add_note
audit_log.get
collection_pool.list
order_items.list, order_items.get, order_items.update_status,
order_items.confirm_collected
order_items.list, order_items.get, order_items.create, order_items.update,
order_items.update_status, order_items.confirm_collected
orders.add_attachment, orders.list_attachments
quotes.create_from_email, quotes.append_reply, quotes.find_by_message_id,
quotes.list, quotes.get, quotes.send_email, quotes.retry_email,
quotes.clone, quotes.save_as_template, quotes.create_from_template,
quotes.split, quotes.partial_approve, quotes.re_price, quotes.next_number,
quotes.lookup, quotes.assistant_fill
quotes.list, quotes.get, quotes.create, quotes.update,
quotes.ingest_from_email, quotes.process_pending, quotes.re_run_ai,
quotes.send_email, quotes.retry_email, quotes.clone,
quotes.save_as_template, quotes.create_from_template, quotes.split,
quotes.partial_approve, quotes.submit, quotes.re_price,
quotes.next_number, quotes.lookup, quotes.assistant_fill
quote_items.list, quote_items.get, quote_items.create, quote_items.update,
quote_items.populate_insights
bulk_update_quote_items
attachments.upload_for_quote
quotes.list_attachments, quotes.get_pdf
purchase_orders.add_attachment, purchase_orders.list, purchase_orders.get,
purchase_orders.send_email, purchase_orders.retry_email,
purchase_orders.stale, purchase_orders.record_send_outcome
bulk_update_quote_items
stock_items.list, stock_items.get, stock_items.create, stock_items.adjust
purchase_orders.stale, purchase_orders.record_send_outcome,
purchase_orders.scan, purchase_orders.diff,
purchase_orders.record_diff_report
stock_items.list, stock_items.get, stock_items.create, stock_items.adjust,
stock_items.update, stock_items.set_pricing, stock_items.set_quantities
stock_purchases.list, stock_purchases.get, stock_purchases.create,
stock_purchases.next_number, stock_purchases.send,
stock_purchases.receive, stock_purchases.send_email,
stock_purchases.retry_email
stock_purchases.add_attachment, stock_purchases.match_and_receive_from_invoice
stock_purchase_items.list, stock_purchase_items.update,
stock_purchase_items.bulk_update, stock_purchase_items.assign_driver,
stock_purchase_items.mark_collected
stock.fulfill, stock.surplus_book
stock_quick_draft.search, stock_quick_draft.add_line,
stock_quick_draft.suppliers
sprint.list, sprint.attachment_counts, sprint.item_attachments, sprint.claim
buyer_tasks.list, buyer_tasks.generate_po, buyer_tasks.mark_ready
stock.fulfill, stock.surplus_book
ai_insights.rerun
delivery_notes.list, delivery_notes.create, delivery_notes.set_order,
delivery_notes.set_customer_po, delivery_notes.set_item_quantity,
delivery_notes.cancel, delivery_notes.mark_invoiced,
delivery_notes.mark_complete, delivery_notes.regenerate_pdf,
delivery_notes.create_quote, delivery_notes.combine
collection_confirm.list, collection_confirm.upload_invoice,
collection_confirm.ai_check, collection_confirm.confirm_order_items
drivers.list_stops, drivers.update_stop_status
files.fetch
ai_insights.rerun, ai_settings.get, ai_settings.update
dashboard.daily_summary, orders.sprint_counts, orders.find_duplicates,
orders.find_by_order_number, orders.find_by_email_message_id,
orders.review, orders.matched_attachments
users.lookup
companies.list, companies.get, companies.create, companies.update, companies.delete
customers.list, customers.get, customers.create, customers.update, customers.delete
suppliers.list, suppliers.get, suppliers.create, suppliers.update, suppliers.delete
@ -592,6 +625,7 @@ These are live issues on production. Verify they're still current before reporti
4. **`quotes.lookup` returns `fetch failed`.** The MCP server makes an internal fetch to its own REST endpoint and that fetch is failing — single-shot error with no diagnostic. Workaround: use `quotes.list` with a PB filter instead (`filter: 'quote_number~"Q202608016"'`).
5. **`collection_pool.list` and `sprint.list` both return `Missing collection context`.** Looks like a PB session header isn't being forwarded in those handlers. Bug to file — these are core workflows. Workaround: drive the same queries from `quotes.list` / `orders.list` with appropriate filters.
6. **`orders.get` returned `not found` for one specific id.** Couldn't reproduce a pattern; may be an id-format edge case. If you hit it, re-fetch via `orders.list` with a `search` arg and confirm the id format.
7. **`stock_items.adjust` writes a ledger row with no actor — and it is not the way to set quantities.** It ignores the `actor` the bridge injects and writes `created_by: ""`, so the change lands in `stock_ledger` unattributed. Use `stock_items.set_quantities` for agent writes: it goes through `updateStockItemsQuantities`, which stamps the acting user on every ledger row. `stock_items.adjust` is still there for a one-off signed `change_qty` with a `reason`, but it never names who did it.
---
@ -670,7 +704,7 @@ Auth: agent bearer on the REST routes, `AGENT_API_KEY` for the MCP tool.
---
## Architectural gaps
These are intentional or pre-existing limitations. Don't waste time trying to work around them — flag to the operator if they block a workflow you actually need.