Writer’s Brief

The Hook

What if you could type “show me times in Tokyo on Valentine’s Day” into your terminal and get a formatted comparison table?

Main Points to Cover

  1. Textual makes surprisingly polished terminal UIs with almost no effort - DataTable, Input, styling all built in
  2. Ollama tool calling turns natural language into structured function calls locally - no API keys, no cloud
  3. The fuzzy resolver layer is the unsung hero - it’s what makes “NYC” and “Brasil” work without the user needing to know IANA timezone IDs

The Angle

Personal tool built to solve an actual annoyance - coordinating across timezones. The interesting part is how the three layers (TUI, LLM, resolver) snap together and each one has a clean fallback (keyword parsing, stdlib timezones, alias map).

Target Reader

Developers who want to build useful CLI tools with LLM integration. People curious about Ollama tool calling in practice (not just chat).

Tone Notes

Practical, show-don’t-tell. The app is simple enough to explain in full but has enough layers to be interesting. Lean into the “it just works” moments (typing a bare city name, date parsing flexibility).

Raw Material / Moments to Write From

These are notes for Alex to write from. Not prose.

  • System Python on macOS refused to install textual because it couldn’t upgrade rich (permission error on system site-packages). Venv fixed it instantly. Classic macOS Python moment.
  • WorldTimeAPI returns 598 timezone IDs. The stdlib fallback has them too but fetching validates we’re using real, current data.
  • Textual’s run_test() is genuinely useful - headless testing of a TUI app without needing a terminal. You simulate keypresses and check widget state.
  • The “bare city name” feature happened naturally - if no keyword matches, try resolving the input as a city. If it resolves, add it. Simple fallback that feels like magic.
  • Ollama tool calling works by defining JSON schemas for functions, sending them with the chat request, and the LLM responds with structured tool_calls instead of text. It can call multiple tools in one response (e.g., “show me Tokyo on Feb 14” triggers both set_date and add_locale).
  • The fuzzy matching threshold of 60 is lenient enough to catch typos but strict enough to avoid weird matches. thefuzz wraps Levenshtein distance.
  • Day rollover handling: when you’re in New York at 11 PM and look at Tokyo (14h ahead), the cell shows “01:00 PM (Feb 08)” - the date annotation prevents confusion.
  • Two display modes: “today” shows next 12 hours from now (useful), specific date shows all 24 hours (comprehensive).
  • Current hour row gets [bold reverse] styling - Textual’s Rich markup support means you just wrap the string.