Luna HR Docs

Luna AI

Luna AI is the chat assistant built into Luna HR. It answers natural-language questions by calling permission-scoped tools against your live data — never guessing, never inventing numbers. Whether you're an employee checking your leave balance, a manager looking at your team's absences, or an admin running company-wide reports, Luna routes to the right tool for the question and returns a structured answer.

Quick start

  1. Click Chat in the sidebar
  2. Type a question or use the microphone for voice input
  3. Use the suggestion chips on the landing screen — they adjust based on your permissions
  4. Open the History drawer to revisit previous conversations

What you can ask

Luna AI's available tools depend on your permissions. The lists below group questions by the audience that can ask them — if you don't see something it's because your role doesn't have access to the underlying data.

Everyone — your own data

  • "How much leave do I have left?"
  • "Show me my pending expense reports"
  • "What training am I overdue on?"
  • "What assets are assigned to me?"

Managers (anyone with leave:approve / expenses:approve / training:approve)

  • "What's awaiting my approval?"
  • "Is anyone in my team off this week?"
  • "Find me Sarah Patel" (then drill into her record)
  • "Approve leave request abc123" / "Reject expense report xyz789 — receipt missing"

Admins — analytics & company-wide reports

  • "Show me our headcount and KPIs for this year"
  • "Total expense spend this quarter"
  • "Who's overdue on mandatory training?"
  • "Absence breakdown by leave type this month"
  • "How's onboarding progressing for new hires?"
  • "Any signatures still outstanding?"
  • "How's our recruitment pipeline looking?"
  • "How many performance reviews are pending?"

Accounts / finance (admin or expenses:approve)

  • "What expense reports are awaiting payment?"
  • "Where are expense reports stuck?"
  • "Top expense spenders this quarter"
  • "What's our total mileage reimbursement this year?" (admin only)

How permissions work

Luna AI never sees data your account can't already see. Every tool checks your permissions server-side before returning a result, and the system prompt only lists the tools you actually have. This means:

  • Employees see only their own leave / expenses / training / assets
  • Managers see the items waiting for their approval and can search employees / look up profiles
  • Admins can pull company-wide reports, analytics, and operational status
  • Accounts users (with expenses:approve but not admin) see the expense payment run and authorisation queue but not the company mileage spend

If a tool requires a permission you don't have, the model simply won't be told it exists.

The full toolkit

Luna AI has 27 tools across four tiers, plus the system prompt routing table that lists them for the model. The breakdown:

Always-available (everyone)

| Tool | Returns | |------|---------| | get_leave_overview | Your leave balances + pending requests + upcoming approved leave | | get_expense_overview | Your recent expense reports + counts of pending / drafts | | get_training_overview | Your training records, active enrolments, certifications | | get_asset_overview | Assets currently assigned to you |

Manager / approver

| Tool | Permission | Returns | |------|------------|---------| | get_pending_approvals | Any *:approve or admin | Items awaiting your review across modules | | get_team_absences | Any *:approve or admin | Approved leave overlapping a window — manager sees direct reports, admin sees company | | search_employees | Any *:approve or admin | Find employees by name | | get_employee_details | Any *:approve or admin | Profile + leave balances + recent activity | | get_leave_request_details | leave:approve | Full detail on one leave request | | get_expense_report_details | expenses:approve | Full detail on one expense report | | approve_leave_request | leave:approve + AI setting | Action — approve a leave request | | reject_leave_request | leave:approve + AI setting | Action — reject a leave request | | approve_expense_report | expenses:approve + AI setting | Action — approve an expense report | | reject_expense_report | expenses:approve + AI setting | Action — reject an expense report |

Admin — analytics & reports (Tier 1)

| Tool | Returns | |------|---------| | get_company_overview | Headcount, offboarding count, pending leave + expense approvals | | get_company_analytics | KPI dashboard — headcount trend, expense YTD, training %, leave by type, dept breakdown | | get_leave_report | Date-range leave aggregations — totals, top absent employees, by leave type, who's off today | | get_expense_report | Date-range expense spend — by category, top spenders, awaiting payment, status counts | | get_training_compliance | Mandatory training — compliance %, overdue, expiring soon, top overdue employees |

Admin — operational (Tier 2)

| Tool | Returns | |------|---------| | get_onboarding_status | Pending invites, in-progress wizards, completions in last 30 days, recent activity | | get_pending_signatures | Outstanding e-signatures — count + 10 longest-pending with names | | get_recruitment_pipeline | Open roles, candidates by stage, interviews this week, pending offers, top roles | | get_performance_overview | Active goals, pending reviews, 1-1s this month, active review cycles |

Accounts / admin — finance (Tier 3)

| Tool | Permission | Returns | |------|------------|---------| | get_expense_payment_run | Admin or expenses:approve | Reports queued for payment — total owed, oldest waiting, per-employee totals | | get_expense_authorisation_queue | Admin or expenses:approve | Pipeline counts at every workflow stage + reports stuck >7 days | | get_mileage_summary | Admin only | Mileage claims — total miles, reimbursement, by fuel type, top claimers |

Composition (manager / admin)

| Tool | Returns | |------|---------| | resolve_org_node | Fuzzy-match a department/team/office name into an org node ID — call before scoping other tools | | resolve_expense_category | Fuzzy-match a category name (e.g. "lunch", "taxi") into an expenseCategoryId — call before submit_expense_report |

Write tools (employees, gated on company AI settings)

| Tool | Permission | What it does | |------|------------|--------------| | submit_leave_request | Any employee + submit_leave in allowedAiActions | Books leave on the user's behalf — full policy / blackout / allowance checks run unchanged | | submit_expense_report | Any employee + submit_expense in allowedAiActions | Submits an expense report with optional receipt extraction — full pre-approval / policy checks run unchanged |

Submitting an expense from a receipt photo

When the Submit expense reports toggle is on, you can drag a receipt image into the chat and ask Luna to submit it. The flow:

  1. Drop the receipt photo (or several) into the message and ask something like "Submit this lunch receipt"
  2. Luna reads the image with vision, extracts vendor / date / total / currency / description, and matches a category (via resolve_expense_category)
  3. Luna shows you a one-line summary per receipt and waits for you to confirm before submitting
  4. On confirmation it creates the report, attaches the receipt to the line item, populates aiExtractedData for the audit trail, and submits — running every existing policy check (pre-approval thresholds, blocked categories, workflow routing, notifications)

Confidence scores from the vision step are stored alongside the extracted values so admins reviewing the approval queue can see when Luna was unsure. Anything Luna can't read clearly (faded ink, partial total) gets flagged in chat for you to confirm before the submit.

The receipt image is the same one you attached to the chat message — no separate upload step. The same goes for PDFs (e.g. emailed receipts).

Composing tools for richer answers

Luna AI can chain tools together to answer questions that need data from more than one place. Every analytic tool exposes opaque IDs alongside display names in its output, and accepts those IDs in filter args on follow-up calls.

Scoped report filters — most of the report tools accept optional filters:

| Tool | New optional filter args | |------|--------------------------| | get_company_analytics | org_node_id | | get_leave_report | org_node_id, employee_id | | get_expense_report | org_node_id, employee_id, category_id | | get_training_compliance | org_node_id, course_id | | get_team_absences | org_node_id (admin override of the manager default) | | get_mileage_summary | employee_id, fuel_type |

Multi-step patterns Luna will use:

  • "Compare Engineering vs Sales leave usage this year"resolve_org_node twice → get_leave_report twice with the two org_node_id values
  • "What's our headcount in London office?"resolve_org_node("London")get_company_analytics with that org_node_id
  • "Show me Sam Patel's mileage YTD"search_employees("Sam Patel")get_mileage_summary with the employee_id
  • "Find Jane and approve her leave"search_employeesget_pending_approvalsapprove_leave_request
  • "Travel expense spend last quarter"get_expense_report with period: "last_quarter" and category_id for travel

If a question is more than one tool round away, Luna runs the tools in parallel where possible and combines the results in its reply. The system prompt teaches the routing patterns and the tool outputs always include IDs to make chaining work.

Date ranges

The report-style tools accept a relative period so the model doesn't have to do date maths:

  • today · this_week · next_7d · next_30d
  • this_month · this_quarter · ytd · last_30d

You can also give explicit dates like "expense spend from March 1st to March 31st" — those always override the period.

Settings — Admin > Company

The AI section of the Company settings page controls how Luna AI behaves:

  • Communication toneformal · friendly (default) · casual
  • Strictness level — controls how cautious Luna is when an answer isn't a clean tool round-trip:
    • Strict — refuse rather than guess, always quote concrete numbers from tools, plainly report failures
    • Balanced (default) — answer confidently from tool results, caveat extrapolation
    • Flexible — make reasonable assumptions but note them, suggest related actions
  • Proactive suggestions — when on, Luna appends a relevant follow-up question after each answer (e.g. "💡 You might also want to ask: ..."). Skipped for approve/reject confirmations.
  • Auto-approval — opt-in cap on AI-initiated approvals
  • Allowed AI actions — checklist of which action tools (approve_leave, reject_leave, approve_expense, reject_expense) the AI is permitted to perform on the user's behalf. If a permission is granted to a user but the action isn't in this list, the action tool is withheld from that user's tool list.

Admin observability — Admin > AI Usage

A new admin page (admin permission required) shows how Luna AI is being used across your company over the last 30 days:

  • Active conversations + new conversations in the last 7 days
  • Message volume — total messages, split user vs assistant
  • Avg response time with p95 — useful for spotting slowdowns
  • Tool hit rate — what % of assistant replies actually called a tool
  • Avg tool rounds — per assistant turn that used any tool. Higher means more compositional reasoning (e.g. "compare X and Y" questions running 2-3 rounds)
  • Exhausted budget — count of turns that ran every tool round without producing a reply. Zero is the happy path; any positive number flags stuck multi-step queries worth investigating
  • Most-used tools with failure rates colour-coded (green = 0% failures, outline = under 20%, destructive ≥ 20%) — easy to spot broken or misconfigured tools
  • Top users by message count
  • Token usage (input / output) — for cost tracking

Each assistant message stores the audit trail — which tools fired, whether each one succeeded — so this page is always live.

Voice + image input

  • Voice input — click the microphone icon to dictate (en-GB)
  • Image attachments — drag-and-drop or paste images (PNG/JPG/WebP, up to 4 MB each). Useful for sharing screenshots, receipt photos, or expense documentation

What Luna AI won't do

  • Invent numbers — every figure comes from a tool result
  • See data outside your permissions
  • Approve / reject anything that isn't in your company's allowedAiActions whitelist
  • Share data with other companies (everything is companyId-scoped)

Switching providers

Luna AI ships using Google Gemini 2.5 Flash by default. The provider can be swapped to Anthropic Claude by flipping a single constant in convex/ai.ts (PROVIDER = "anthropic") and setting ANTHROPIC_API_KEY in the Convex environment. Tool calling, streaming, and image support work on both.

  • Leave — the data behind get_leave_overview and get_leave_report
  • Expenses — the data behind the expense + payment-run tools
  • Training — the data behind get_training_compliance
  • Reports — the admin-facing reports the AI tools wrap
  • Approvals — the manager queue the AI surfaces
  • Roles & Permissions — what controls who sees what