Runtime agents
Agents are narrow conversational helpers that live inside the bot. Each one is triggered conservatively, validates everything the model returns, and asks you to confirm before anything is written.
Enabling agents
The four direct-message agents are off by default and enabled by name. They are tried in priority order on each inbound direct message: natural-language schedule first, then Q&A, then the blocker router, then onboarding. The first agent that handles a message stops the chain.
RUNTIME_AGENTS_ENABLED=nl_schedule,onboarding,qa,blocker_router
Natural-language leave
A short message that mentions being off, out, sick, on leave or working from home is sent to the model with today’s date, and the model returns a structured request with a confidence. Below 0.6 confidence nothing happens. The bot then asks you to confirm before filing.
- Server-side validation rejects anything the model returns that is out of policy: unknown kinds, malformed dates, spans over 60 days, or a start more than 7 days in the past. Invalid output is dropped silently rather than echoed.
- The confirmation waits ten minutes; a different answer re-runs extraction on the new text.
- The filed request enters the normal approval flow, so every guardrail in PTO and leave still applies.
I'm off Friday Got it — I’ll file PTO for 2026-06-19. Reply YES to confirm, or describe the dates again to fix. yes Filed. Admin will be notified.
Self-service Q&A
Questions about your own record are routed to one of eight query templates. The model chooses the template and the parameters; the product runs the query with your own user ID and parameter binding, so user text never reaches the database.
| hours_this_week | total hours Monday to today |
|---|---|
| hours_last_week | total hours last week |
| hours_for_day | hours on a date |
| signin_for_day | when you signed in on a date |
| signoff_for_day | when you signed off on a date |
| attendance_this_month | days worked and days late this month |
| pto_remaining | leave used this year by type |
| recent_blockers | your last five blockers |
Blocker router
When a check-in records a blocker, the router extracts its keywords, scans the last 14 days of teammates’ Today sections for whoever mentioned those words most, and sends that person a heads-up quoting the blocker and the reason for the match. The asker is told who was pinged. At most three routes per asker per hour, and quoted text is escaped so it cannot mention the whole room.
Heads-up from Lina — they’re blocked on something you recently worked on: > invoice export fails on large accounts (matched on “export, invoice” in their standup on 2026-09-08)
Onboarding
The first time the bot sees a new person it sends a short tutorial with the check-in format and asks two questions: which days they work (weekdays, specific days, all seven, or skip) and their timezone. The answers write the person’s schedule so absence and lateness are judged against their own days from day one.
Other in-bot agents
- Ticket triage: when a support ticket opens, the support persona receives read-only context (recent attendance, strikes, recent audit events) and must return one of two actions: resolve with a short answer, or ask exactly one clarifying question.
- Intent router: in a shared room with several personas, one call picks the single best-fit bot for a message and returns null below 0.45 confidence so nobody answers small talk. Identical decisions are memoised for six hours.
- Late-reason judge and blocker-reply intent: accuracy-critical verdicts run on the provider’s strongest model (AI_REASONING_MODEL) even when the everyday model is small.
- All agent calls are non-essential and degrade to keyword paths once the daily AI budget is spent.