diff --git a/.agents/skills/wfdash-giellie/SKILL.md b/.agents/skills/wfdash-giellie/SKILL.md index 9c2ced3..2480264 100644 --- a/.agents/skills/wfdash-giellie/SKILL.md +++ b/.agents/skills/wfdash-giellie/SKILL.md @@ -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.