{"ok":true,"site":{"host":"tandem-lac.vercel.app","url":"https://tandem-lac.vercel.app/","type":"live","desc":"A multi-branch restaurant back office where an AI agent reads freely but can never change anything alone. Every write is a costed proposal the manager approves. Built on WebMCP.","tools":[{"name":"get_business_snapshot","kind":"answer","impl":"imperative","description":"Current trading position for the chain or named branches: last-7-day revenue and gross margin, order count, how many items are off the menu, and how many ingredients are below par. Start here before proposing anything.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"branchIds":{"type":"array","items":{"type":"string"},"description":"Branch ids to act on. Omit or leave empty to mean the whole chain. Use list_branches to get ids."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_branches","kind":"answer","impl":"imperative","description":"Every branch with its id, city, seat count and whether it is trading right now. Use the ids from here in other tools.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_menu","kind":"answer","impl":"imperative","description":"Menu with the price charged at a branch, ingredient cost per portion, gross margin, and how many portions the branch can still make from stock on hand. Flags anything currently off the menu.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"branchId":{"type":"string","description":"Branch to price against. Defaults to the first branch."},"category":{"type":"string","enum":["mains","sides","drinks","desserts"],"description":"Optional category filter."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_stock_alerts","kind":"answer","impl":"imperative","description":"Ingredients below par, worst first, with days of cover left at the branch's actual run rate and which menu items stop being sellable when each runs out. This is the fastest way to find a problem worth acting on.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"branchIds":{"type":"array","items":{"type":"string"},"description":"Branch ids to act on. Omit or leave empty to mean the whole chain. Use list_branches to get ids."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_orders","kind":"answer","impl":"imperative","description":"Recent orders, newest first, with branch, channel, status and total. Use it to find a specific order id before proposing a refund.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"branchIds":{"type":"array","items":{"type":"string"},"description":"Branch ids to act on. Omit or leave empty to mean the whole chain. Use list_branches to get ids."},"status":{"type":"string","enum":["placed","preparing","delivering","completed","refunded"],"description":"Optional status filter."},"limit":{"type":"number","description":"How many to return, 1–20. Default 10."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"analyze_item_performance","kind":"answer","impl":"imperative","description":"Sales performance over the last 7 days. With an itemId, returns units, revenue, share of branch revenue and margin for that item. Without one, ranks the whole menu by revenue.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"itemId":{"type":"string","description":"Menu item id, from list_menu."},"branchIds":{"type":"array","items":{"type":"string"},"description":"Branch ids to act on. Omit or leave empty to mean the whole chain. Use list_branches to get ids."},"limit":{"type":"number","description":"How many items to rank. Default 8."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_shifts","kind":"answer","impl":"imperative","description":"Today's roster for a branch, plus any hour where staff on duty falls short of the covers that branch typically does. Use it before proposing a shift change.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"branchId":{"type":"string","description":"Branch id. Defaults to the first branch."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_suppliers","kind":"answer","impl":"imperative","description":"Suppliers with their lead time and minimum order value, and which ingredients each one supplies at what unit cost. Needed to build a purchase order that will actually be accepted.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"list_proposals","kind":"answer","impl":"imperative","description":"Proposals you have raised and how the manager decided on each. Check this before re-proposing something — a rejected proposal should not be sent again unchanged.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"onlyPending":{"type":"boolean","description":"Return only those still awaiting a decision."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"get_audit_log","kind":"answer","impl":"imperative","description":"Chronological record of what you proposed and what the manager decided, newest first. Every change to this business is attributable through here.","annotations":{"readOnlyHint":true},"inputSchema":{"type":"object","properties":{"limit":{"type":"number","description":"How many entries, 1–20. Default 10."}}},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"show_section","kind":"act","impl":"imperative","description":"Switches the screen the manager is looking at, optionally focusing one branch and highlighting a row. Call this before explaining something so they are looking at what you mean.","inputSchema":{"type":"object","properties":{"section":{"type":"string","enum":["overview","menu","stock","orders","staff","audit"],"description":"Which section to show."},"branchId":{"type":"string","description":"Optional branch to focus."},"highlightId":{"type":"string","description":"Optional id of a menu item, ingredient, order or shift to highlight."}},"required":["section"]},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"propose_price_change","kind":"answer","impl":"imperative","description":"Proposes a new price for one menu item. Does NOT change the price: it puts a costed proposal on the manager's screen showing the projected weekly margin effect after demand elasticity, and returns only once they approve or reject. Give a clear rationale — they see it.","inputSchema":{"type":"object","properties":{"itemId":{"type":"string","description":"Menu item id, from list_menu."},"newPriceCents":{"type":"number","description":"New price in cents, e.g. 1650 for $16.50."},"branchIds":{"type":"array","items":{"type":"string"},"description":"Branch ids to act on. Omit or leave empty to mean the whole chain. Use list_branches to get ids."},"rationale":{"type":"string","description":"Why this change is worth making, in one or two sentences."}},"required":["itemId","newPriceCents","rationale"]},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"propose_menu_availability","kind":"answer","impl":"imperative","description":"Proposes taking a menu item off sale (86'ing it) or putting it back. Does NOT change availability on its own — it shows the manager the weekly revenue at stake and waits for their decision.","inputSchema":{"type":"object","properties":{"itemId":{"type":"string","description":"Menu item id, from list_menu."},"branchIds":{"type":"array","items":{"type":"string"},"description":"Branch ids to act on. Omit or leave empty to mean the whole chain. Use list_branches to get ids."},"restore":{"type":"boolean","description":"true puts the item back on sale. Defaults to false, which takes it off."},"rationale":{"type":"string","description":"Why, in one or two sentences."}},"required":["itemId","rationale"]},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"propose_stock_correction","kind":"act","impl":"imperative","description":"Proposes correcting the counted stock of one ingredient at one branch, up or down. Use it after a physical count or a wastage report. Waits for the manager's decision.","inputSchema":{"type":"object","properties":{"branchId":{"type":"string","description":"Branch id."},"ingredientId":{"type":"string","description":"Ingredient id, from list_stock_alerts or list_suppliers."},"deltaQty":{"type":"number","description":"Signed change in the ingredient's own unit, e.g. -2.5 or 8."},"rationale":{"type":"string","description":"Why the count is being corrected."}},"required":["branchId","ingredientId","deltaQty","rationale"]},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"propose_purchase_order","kind":"transact","impl":"imperative","description":"Proposes buying stock from a supplier for one branch. This spends real money, so it never places the order itself: the manager sees the total cost, whether it clears the supplier's minimum, and whether delivery arrives before the branch runs out.","inputSchema":{"type":"object","properties":{"supplierId":{"type":"string","description":"Supplier id, from list_suppliers."},"branchId":{"type":"string","description":"Branch the stock is delivered to."},"lines":{"type":"array","description":"What to order.","items":{"type":"object","properties":{"ingredientId":{"type":"string"},"qty":{"type":"number","description":"Quantity in the ingredient's unit."}},"required":["ingredientId","qty"]}},"rationale":{"type":"string","description":"Why this order, at this size, now."}},"required":["supplierId","branchId","lines","rationale"]},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"propose_refund","kind":"act","impl":"imperative","description":"Proposes refunding a customer, in whole or in part. Money leaves the business, so this always requires a human decision regardless of amount. The manager sees the order, the amount and the reason you give.","inputSchema":{"type":"object","properties":{"orderId":{"type":"string","description":"Order id, from list_orders."},"amountCents":{"type":"number","description":"Refund amount in cents. Cannot exceed the order total."},"reason":{"type":"string","description":"The customer's reason, in their words where you have them."}},"required":["orderId","amountCents","reason"]},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"propose_shift_change","kind":"act","impl":"imperative","description":"Proposes reassigning a shift or moving its hours. The manager sees any coverage gap the change would open, computed from that branch's real hourly demand, before they decide.","inputSchema":{"type":"object","properties":{"shiftId":{"type":"string","description":"Shift id, from list_shifts."},"newStaffName":{"type":"string","description":"Who should cover it instead."},"newStartHour":{"type":"number","description":"New start hour, 0–23."},"newEndHour":{"type":"number","description":"New end hour, 0–23."},"rationale":{"type":"string","description":"Why the change is needed."}},"required":["shiftId","rationale"]},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"}],"category":"Productivity & Business","favicon":"/favicons/tandem-lac.vercel.app.ico","apiSurface":"spec","toolCount":17}}