Teaching a voice assistant the current time without a tool call
I wanted Emma, the router in Foreman, to answer date and time questions. Until today she honestly refused because she had no clock.
Prompt injection, not a tool
I prepended a fresh datetime line to the system prompt on every routing call. The format is colloquial: weekday, 12-hour time with no leading zero, and a short zone name like "Central" instead of "Central Daylight Time". A directive tells Emma to answer date and time questions straight from that line.
The datetime is built fresh every call and never cached. I proved freshness by patching the internal seam to return two instants a minute apart and diffing the built prompts.
I added a time command to Foreman that prints the same format for parity. No registry tool, no gate entry. The datetime is context, not capability.
TTS read clock times digit by digit
Kokoro spoke "9:07 AM" as "nine zero seven". I added normalization inside the say function that rewrites clock times in the synthesized copy only. Minutes 01 through 09 become "oh M", 00 becomes "o'clock", and 10 through 59 pass through. The regex only matches H:MM and H:MM AM/PM with hour 1 through 12, guarded by lookbehind and lookahead so git times, ratios, verses, and money are untouched.
Printed text still shows "9:07 AM". Only the spoken audio changes.
Weather via Open-Meteo
I added Foreman's first external data tool. Weather comes from Open-Meteo, which is free, keyless, and requires no signup. I classified it SAFE because it is external read-only data via a keyless GET.
The tool uses stdlib urllib with a 10 second timeout and returns a calm error dict on any failure. It translates WMO weather codes to plain words and reads user-editable latitude, longitude, and timezone constants that default to Appleton, Wisconsin.
Answers shape to the question. "Is it going to rain today?" gets an authored yes/no verdict plus numbers. "What's the weather?" gets a general two-sentence summary. The router's only say over the answer is a focus enum. Every number and the yes/no verdict come straight from the tool dict via a fixed template. The model cannot invent a temperature or a verdict.
Rain verdict thresholds: precipitation chance under 20 is "No rain expected", 20 through 60 is "Maybe", over 60 is "Likely". I verified the boundaries.
The forecast is today only. "Will it rain tomorrow?" routes to the rain focus but answers for today. I documented this as a known limit.
I added a keyword fallback route so degraded mode can still reach weather when the router is offline.
One named tool, one fixed source
This is the deliberate pattern for every future external tool. One named tool, one fixed source, SAFE-classified. Honest registry, not general web access.