Multi-provider AI assistant panel for ERPNext desk
lazychat-erpnext demonstrates strong tool definition quality with comprehensive schemas, detailed descriptions, and clear parameter documentation. All 14 tools have explicit input schemas with proper JSON Schema structures and meaningful descriptions. The tool set is well-organized around ERPNext document operations with clear separation of read-only vs. write operations. However, there are notable gaps: no visible output schema documentation, missing tool annotations (readOnlyHint/destructiveHint/idempotentHint), no error handling guidance in descriptions, and some parameter descriptions could be more explicit about constraints and format requirements. The design favors staging/confirmation workflows (prepare_* tools) which is a strong security pattern, but this isn't explicitly documented as a best practice in tool descriptions.
Return field metadata (name, fieldtype, label, options, reqd) for a DocType so you know which values to provide before staging a create or update. Read-only.
Discover the canonical SQL join chain between two doctypes by walking Frappe's DocField metadata graph (Link / Table fields) with BFS. Returns the shortest hop list, or curated canonical when one exists (e.g. Purchase Invoice → Payment Entry returns the route via `Payment Entry Reference` child table including the required `reference_doctype = 'Purchase Invoice'` predicate). USE THIS BEFORE writing any cross-doctype JOIN — eliminates the need to memorize join shapes and prevents the most common SQL bug class (wrong join key, missing reference_doctype filter, item_code-only joins). Each hop includes `via_field`, `via_kind` (link / parent_to_child / child_to_parent / curated), and `on_template` with `<a>`/`<b>` alias placeholders for the FROM and TARGET tables. Curated routes carry a `warning` field with the gotcha — always read it. Output: {found, from, to, hops[], hop_count, canonical}.
Return the ERPNext desk context passed from the widget (doctype, docname, route).
Fetch a single document by name if the user can read it.
Missing output schema documentation. While input schemas are complete and visible, there is no documented return type or output structure for any tool. This forces LLMs to infer what fields they'll receive, risking errors in downstream tool chaining and data extraction.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) present in schemas. While tool descriptions mention read-only vs. write operations, the machine-readable annotations are missing. This prevents clients from applying safety rules automatically (e.g., not retrying destructive operations).
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2026-07-28+ | v2 |
Return canonical row-level + parent-level join hints for a doctype. Use this BEFORE writing variance/comparison SQL — the response tells you the EXACT join pattern (e.g. for Purchase Invoice Item, the row link to Purchase Receipt Item is via `pr_detail`, NOT `item_code`). Includes curated overrides for ERPNext's most-mismatched pairs: PR↔PI, SO↔SI, SI↔DN, Stock Ledger Entry↔PR, PR↔PO. Falls back to the generic describe_doctype links for uncurated doctypes.
Return the live _lz_items URL-prefill whitelist for a doctype (parent fields + item child-row fields the persistent helper Client Script honors). Call this BEFORE composing a Query Report with HTML buttons that prefill a new doc — the response tells you exactly which fields you can encode in the URL. Returns {doctype, helper_installed, is_supported_target, url_pattern, parent_whitelist, item_whitelist, example_payload}. Doctypes with helper_installed=true: Purchase Invoice, Sales Invoice, Purchase Receipt, Delivery Note (others can be added via install.py).
List documents with filters. Read-only. Default limit 20 (cheap schema probes). Pass an explicit limit when the user wants more rows — there is NO upper bound; the chat-ui truncates display at ~250 KB if the result won't fit your context window (with a clear notice). For TOTALS/COUNTS NEVER trust len(rows): always call count_doc or aggregate. For TRUE BULK that exceeds your context, use export_list_to_csv (writes a file, no context cost). Pass limit=0 (or negative) for unbounded fetch.
List workflow transitions available from the current state of a document. Read-only. Returns {current_state, transitions: [{action, next_state, allowed_role}]}.
STAGE adding a comment to a document's activity log. Does NOT actually add. Returns {preview_token, summary, preview, confirm_with}. Ask the user to '/commit TOKEN'.
STAGE creating a new document. Does NOT actually create. Returns {preview_token, summary, preview, confirm_with}. After calling, narrate the preview to the user and tell them EXACTLY: 'Reply with `/commit TOKEN` to apply, or anything else to cancel.' Never call any commit tool yourself — the /commit slash command is handled outside the agent loop.
Stage a form-prefill payload for a new-doc URL. Returns a short opaque token and a tiny URL (`/app/<dt>/new?_lz_token=<22-char>`) that the persistent Client Script will fetch and apply via `frappe.route_options` on form load. ALWAYS prefer this over the legacy `_lz_items=<base64>` URL convention when items count >= 5 OR total payload could exceed ~1 KB — the URL-embedded base64 approach hits HTTP 414 Request-URI Too Long for large reports (50+ rows). Token is single-use, user-bound, 5-min TTL (override via `ttl` arg, max 3600s). Re-checks create permission at staging time. Use the returned `url` directly in Query Report HTML link buttons (e.g. `<a href="<url>">Debit Note</a>`).
STAGE submitting (workflow-submit, docstatus 0→1) an existing document. Does NOT actually submit. Returns {preview_token, summary, confirm_with}. Ask the user to '/commit TOKEN'.
STAGE updating an existing document. Does NOT actually update. Returns {preview_token, summary, diff, confirm_with}. After calling, narrate the diff and ask the user to '/commit TOKEN'.
STAGE applying a workflow action (e.g. 'Approve', 'Reject') to a document. Validates the action is allowed from the current state. Does NOT actually apply. Returns {preview_token, summary, confirm_with}. Ask the user to '/commit TOKEN'.
Error handling and recovery guidance missing from tool descriptions. No tool description indicates what errors can occur, what they mean, or what the LLM should do next (retry, ask user, abort). This violates the recovery-guide pattern.
Parameter constraint documentation incomplete. Many parameters lack explicit format, range, or allowed-value guidance. E.g., 'ttl' in prepare_form_prefill mentions '[60, 3600]' but no validation or out-of-range error behavior is documented. 'filters' in get_list accepts 'object' with no schema for what filters are valid per doctype.
Prepare/commit workflow relies on out-of-band token handling. Tool descriptions reference '/commit TOKEN' as a slash command handled 'outside the agent loop'. This is a non-standard, undocumented interaction pattern that breaks MCP's request-response model and makes it impossible for standard MCP clients to support the confirmation flow.