This blog post is AI-Assisted Content: Written by humans with a helping hand.
We replaced a seven-field form with a single sentence. Consultants type what they worked on — or import their Outlook calendar — and an AI assistant creates the time entry. The MVP was built in about 80 hours of development time using Claude Code, runs on Google Gemini, and is now used daily by 46 people who’ve had nearly 1,900 AI conversations with an 85% first-turn success rate.
1: The Problem
Every consultant at InterWorks tracks their time in MOAS, our internal operations system. The process looked like this: open MOAS, navigate to the right date, search for the client account, find the specific job within that account, pick a service item from a dropdown, type in your hours, write a description and submit. Do that five to fifteen times a day.
The form itself worked fine — MOAS even has smart job matching in its dropdowns. But doing it once takes six or seven clicks and field selections. Doing it fifteen times a day, across different clients and jobs, is where the friction compounds — not just in minutes lost, but in the mental overhead of context-switching between billable work and administrative data entry.
2: What Was Built
We built MOAS AI, a conversational time entry assistant where consultants type or speak what they worked on in plain English and the system creates their time entries. The AI layer is model-agnostic — built on the Vercel AI SDK so the underlying model can be swapped without changing application code — and currently runs on Google Gemini for conversation, with Groq Whisper for voice transcription. The MVP was built in about 80 hours of development time using Claude Code (Anthropic’s CLI agent) as the primary development tool, with a five-person team continuing to iterate on it since. It’s in production and used daily across InterWorks.
3: How It Works
A consultant opens MOAS AI and sees a chat window on the left and a visual timeline on the right. They type something like “2 hours on CIS 2040, data migration work this morning” and the AI does the rest — it searches for the job, resolves the account, picks the right service item, calculates start and end times, and creates a draft entry that appears immediately on the timeline.

The key capabilities:
- Natural language entry: Users describe their work the way they’d tell a “Half hour on the Nike project, reviewed dashboard mockups” becomes a fully-formed time entry with the correct job, service item, hours and description — no dropdowns, no searching.
- Automatic job resolution: The AI resolves job names from context — “interworks aus flat rate” or just “the AUS project” — so users never interact with a dropdown or search box. The system handles the lookup behind the scenes, and if there’s ambiguity, it asks rather than guessing.
- Calendar import: Users pull in their Outlook calendar events for the day and map them to jobs in bulk. Each event becomes a pre-filled draft with the meeting title as the description and the duration already calculated. This became the most popular way to use the tool — consultants who previously entered time from memory now import their calendar and adjust.

- Batch entry from notes: Consultants who keep a running log during the day — in Notepad, OneNote or a spreadsheet — can paste the whole thing into the chat. The AI parses multiple entries from a single message, creating all the drafts at once.
- Voice input: Consultants dictate entries on the go using Groq Whisper for transaction. The system shows the transcription first so users can verify before it acts — no silent misinterpretations.
- Visual timeline: Every draft appears on a day-view timeline, showing exactly when each block of work falls. Gaps in the day are visible at a glance. Weekday pills at the top summarize the whole week — showing draft hours versus submitted hours against each user’s expected schedule — so consultants know which days still need entries without clicking through them.

4: How It Was Built
The stack: React 18 with TypeScript on the frontend, Fastify on the backend, Prisma ORM talking to SQL Server (MOAS’s existing database), TanStack Router and Query for routing and state, and shadcn/ui with Tailwind for the interface. The AI layer uses the Vercel AI SDK with tool-calling to orchestrate lookups and draft creation. Authentication goes through Azure AD, delegating the user’s MOAS API token so every action is scoped to their permissions.
The AI architecture: The conversation is powered by a configurable LLM (currently Google Gemini, swappable via a single environment variable) with a structured system prompt that teaches the model InterWorks’ domain — how jobs, accounts, and service items relate, what the naming conventions mean, and when to ask clarifying questions versus making reasonable assumptions. The model has access to tools for searching jobs, resolving service items and creating or modifying draft entries — each scoped to the authenticated user’s permissions.
The system prompt went through significant iteration. Early versions were monolithic — one large block of instructions. We split it into a static core (domain knowledge, tool descriptions, behavioral rules) and a dynamic section (user context, recent jobs, current date/time) that’s assembled at request time. This made the prompt testable and the model’s behavior more predictable. The static/dynamic split also enabled prompt caching — Google Gemini caches the static portion of the system prompt across requests, so only the dynamic context (current date, recent jobs, user info) counts as new tokens on each turn. For a chatty application where every message re-sends the full prompt, that meaningfully reduces both latency and cost.
The development tool: The entire application was built using Claude Code (Anthropic’s CLI agent) as the primary development environment. Claude Code handled everything from scaffolding new features to debugging Prisma queries to writing the system prompt itself. We used it the way a senior engineer uses an IDE — it wrote the code, we reviewed it, caught the edge cases, and pushed it in the right direction.
The hard part — batch submission: Early on, submitting time entries meant sending them to the MOAS API one at a time. For a consultant with fifteen entries, that meant fifteen sequential API calls — slow and brittle. Tyler Palesano, our team lead, built a parallel batch submission pipeline. The new approach submits entries concurrently, but we immediately hit the MOAS API’s rate limit at 60 requests per minute. Tyler designed a throttling layer that respects the limit while keeping the UI responsive — a loading overlay shows progress, and the system handles partial failures gracefully rather than rolling everything back. It was the kind of problem where the naive approach works fine for one entry but falls apart at scale.
Effort: Cole Shelton (our director) created the initial repo and scaffolding in January 2026. Matt Mueggenborg took over as primary developer in February. The team grew to include Luke Davis (PR reviews and an eval framework for chat quality), Greg Nelms (MOAS API endpoints), and Tyler (batch submission and API infrastructure). Commit activity scaled from 40/month in January to 335/month in May as features stacked up. The calendar import and voice input features each took roughly one to two weeks of focused engineering.
5: Why It Matters
The most telling signal is how people use it. Calendar import — which we almost treated as a secondary feature — became the dominant workflow. Consultants who used to enter time from memory at the end of the day now pull in their calendar events each morning or afternoon and adjust descriptions and hours. That shift alone reduced the gap between what people actually did and what they reported.
The time entry chat — the core AI feature — grew to 46 active users in its first three months: 13 in April, 11 more in May, and 22 in June, each cohort added deliberately as we stabilized the experience. Those 46 users generated nearly 1,900 AI conversations, growing from 51 in April to over 1,000 in June. Of those interactions, 85% completed on the first turn, 14% asked a clarifying question (which job? which service item?), and fewer than 0.2% hit an actual error. Average response time is about six seconds — fast enough that people don’t switch tabs while waiting.
The conversational interface collapsed six or seven form fields into a single sentence. Instead of selecting a job from a dropdown, picking a service item, entering hours, typing a description, and setting a start time — separately, for each entry — users describe their work once and the system fills in every field. That’s not a convenience feature; it’s the difference between a system people tolerate and one they actually prefer to use.
This was a team effort. Cole set the direction and stayed hands-on with UI feedback throughout. Tyler solved the hardest infrastructure problem. Luke built the review pipeline that keeps code quality high. Greg extended the MOAS API where we needed new capabilities. The tool is better because it was built by the people who use it.
6: Where This Could Go
Three concrete next steps we’re actively planning or prototyping:
- Per-account and per-user prompt rules: Some clients have mandatory formatting — entries must start with a location number, or include a project code in the description. We’re building injectable prompt snippets that activate when a job is resolved, so the AI enforces account-specific rules without the user having to remember them. The same mechanism supports per-user preferences like description prefixes.
- Deterministic hardening: The AI occasionally makes redundant API calls or inconsistently formats descriptions, even when the prompt says not to. We’re moving those behaviors into code — a service item cache that short-circuits unnecessary lookups, and a post-processing step that enforces sentence casing and proper noun capitalization on every description before it hits the Less reliance on prompt instructions, more on deterministic logic.
- Cross-request prompt caching: Gemini’s implicit caching works within a single multi-step tool loop but not across separate chat requests, because the drafts list in the system prompt changes after each entry. We’re restructuring the prompt so volatile data (current drafts) lives outside the cached prefix, which should make the full static prompt cacheable across an entire session.
For anyone building a similar tool internally: Start with the calendar import. It’s the simplest capability to build (you’re mapping structured data, not parsing free text), and it delivers the most immediate value because it anchors time entries to real events instead of memory.
7: Takeaway
Time entry is the kind of problem that seems too mundane to solve with AI, until you realize that every consultant at your company does it every day, and the friction compounds into hours of lost productivity and inaccurate records. We built a conversational interface that meets people where they already are — typing, talking or looking at their calendar — and it took about 80 hours of development time with Claude Code as the building tool and a model-agnostic AI layer inside.
