03 · Recruit CRM · 2024
Global AI Assistant
An MCP server for an enterprise applicant tracking system, with an agent on top. Recruiters stopped navigating the product and started telling it what they wanted, by voice or in plain language.
- Role
- AI product: tool surface, agent behaviour, voice and chat
- Focus
- MCP server, RAG, voice and chat, agent behaviour
The problem
A product that could do everything, one menu at a time
An enterprise ATS and CRM does not get complicated on purpose. It gets complicated one reasonable request at a time. A customer needs one more pipeline stage. A different customer needs a custom field on the company record, and a report that groups by it. Nobody ever asks for less. After enough years the product genuinely can do almost everything a recruitment agency needs, and almost nothing is where you would guess.
That cost does not land on the buyer. It lands on the recruiter who does the same eight things forty times a day. Move a candidate a stage forward. Log the call that just ended. Check which submissions are still sitting with the client. Every one of those is a known, finished, well built feature, and every one of them sits three or four deliberate navigation choices deep: which module, which view, which filter, which record, then the action.
In research the complaint was never that the feature was missing or badly designed. It was that getting to it broke the thing the recruiter was actually doing. They had a candidate on the phone, a sentence in their head, and a product that wanted them to remember its information architecture first.
By the time you have found the screen, you have lost the reason you opened it.
The product
One place to say what you want
The assistant took a plain language command, resolved it against the recruiter's own workspace, chose a tool, and reported back in the same sentence shape the recruiter had used. Voice for the hands-busy half of the job, text for everything else. Both ran through exactly the same tool surface, because two paths to the same action is two sets of behaviour to keep honest.
Recruit CRM · Assistant
Move the three shortlisted candidates on the Northwind backend role to interview, and give the hiring manager a heads up.
The platform
REQ-4182
Backend Platform Engineer
Northwind Robotics (fictional)
- D. FerrowScreened 4 JulShortlisted
- S. AldabeScreened 6 JulShortlisted
- M. CresseyScreened 9 JulShortlisted
Every name, client, requirement id and figure in this mock is invented
What I decided
Six product calls, written down as architecture
- 01
The agent reads anything the recruiter can read, and writes only what I could name
Read scope simply inherited the user's own permissions: if a record was invisible to them in the product, it was invisible to the agent acting for them. Writes went the other way, an explicit allowlist of narrow tools with typed arguments and no general escape hatch. There was a real temptation to expose one flexible update operation and let the model figure out the rest. I refused it, because an agent with a general write primitive cannot be described to the person about to approve it. If I cannot enumerate what it is capable of doing, I cannot tell a recruiter what it is about to do.
- 02
Some things stayed off the surface entirely, and stayed off for good
Deleting records, editing billing, changing user roles and permissions, and bulk edits past a small ceiling were never exposed as tools at all, rather than exposed with a warning. The reasoning is asymmetry: an assistant that saves ten seconds forty times a day is worth roughly nothing against one destroyed candidate history, and a confirmation dialog is a poor defence against a plausible sounding sentence. The recruiter kept doing those in the product, deliberately, with both hands.
- 03
Expose the jobs recruiters describe, not the endpoints the platform happens to have
The platform had hundreds of API operations. Mapping them one to one would have been faster and would have been the wrong product. A tool surface shaped like the database forces the model to do product thinking at runtime, badly, and differently each time. So tools were named after things recruiters say out loud: advance a candidate, log an activity, summarise a pipeline, find who is stalled. That moved judgement out of inference and into design review, where it could be argued about once and written down.
- 04
Ambiguity resolves by asking once, and only when guessing would cost something
Two paths, decided by reversibility rather than by model confidence alone. Reversible and reasonably clear meant act, then say plainly what was assumed and offer the undo. Irreversible, or genuinely split between candidate readings, meant one closed question with the options listed, never a second follow-up on top of it. A clarification chain feels like being interviewed by the software. If the agent needs three questions to act, the honest answer is that it should not have been asked to.
- 05
Errors are written in the recruiter's words, never the tool's
A recruiter does not know what a tool call is and should never have to learn. So failures never surfaced a tool name, an argument, a status code or a retry count. Every failure message answered three things instead: what did not happen, what state the record is in right now, and the one next thing to try. Partial runs were the hard case and got the strictest rule, the agent had to state what it did complete and what it did not, in that order, before anything else.
- 06
One interaction layer, not another panel in a product already full of panels
The obvious roadmap version was an assistant sidebar in each module, scoped to that module's data. It would have shipped sooner and it would have made the original problem worse, because the problem was surface area and this adds surface area. A global assistant only earns its place if it is the thing you reach for instead of navigating. Anything less than the whole platform behind it and it becomes one more place to look before you give up and click through the menus anyway.
How it works
What one sentence has to pass through
MCP is Anthropic's protocol and I did not design it. What I owned was the server on the other side of it, for a web application that already existed and had ten years of behaviour baked in: which of the platform's capabilities became tools, what each tool would accept and return, how the agent's view of a workspace stayed inside that user's permissions, and what the agent was supposed to do when a sentence did not cleanly map to anything. Most of the work was not protocol work. It was deciding what the product was willing to let an agent do.
Step 1
Capture, and show what was heard
Voice and text collapse into one text intent. Voice transcripts render before anything executes, so a misheard sentence is caught by the recruiter and not by a record.
Step 2
Resolve the intent
What is being asked for, which entities in the sentence refer to which records, and what is missing. Missing pieces are named here, not discovered halfway through.
Step 3
Ground it in the workspace
Retrieval over the customer's own data, scoped to what this user can already see, so a phrase like the backend role becomes exactly one requirement id or an honest question.
Step 4
Select tool, fill arguments
One choice from the allowlist. Arguments are validated against the tool's schema before execution, so a bad guess fails as a question rather than as a write.
Step 5
Gate anything that changes or leaves
Reads run immediately. Writes and anything outbound show the exact change and the exact recipient first, then wait. The gate states what will happen, it does not ask whether you are sure.
Step 6
Execute, then report in plain language
The result carries evidence: the field that changed, its previous value, a link to the record, and the undo where undo exists.
The second showcase below is the same argument drawn generically, in an unrelated domain, because that is where I first worked it out. A calm agent surface, and the system that produced it sitting directly underneath. Drag the lens across the panel to see through it, or use the toggle to hold the whole system open.
The gap I work in
Most AI products have impressive architecture underneath and frustrating experiences on top. I've spent my career fixing that gap.
AI that works but feels wrong is a failed product. The moment a user is confused or uncertain while interacting with AI, that is a product failure. UX is not a layer on top of the model. It is the product.
Drag the lens
Pull last quarter's churn and tell me what changed.
Churn moved from 4.1% to 5.3%. Almost all of it came from accounts under 20 seats. Enterprise held flat.
Is that seasonal?
No. The same quarter last year was 4.0%. The move tracks the pricing change that shipped in week three.
What produces it
- intent parse fetch metric, compare periods, explain delta
- tool selection warehouse query, not web search
- retrieval scoped to rows this user can already see
- memory asked about churn twice this week
- response synthesis number first, cause second
- verification every figure traced back to a row
- The number leads. Someone who asked for a figure should not read a paragraph to find it.
- One follow-up, not three. Choice is a cost when the user already knows what they want.
- Nothing ships that cannot be traced to a source row. One confident wrong number costs all the trust.
What was hard
Confirmation, trust, latency, and being wrong
Confirmation was the first real fight. Gate everything and you have taught the recruiter to click through gates without reading, which is worse than no gate at all, because now the product looks like it asked. So actions got ranked by reversibility and blast radius, and only the top band was gated. The wording changed too. A confirmation that asks whether you are sure gets a reflex. A confirmation that states three candidates move from Shortlisted to Interview and one email goes to a named person gets read, because it contains something the recruiter can check.
Trust behaved differently from adoption, and for a while the metrics hid it. People used the assistant, then opened the record by hand to verify it had done what it said. That is not adoption, that is supervision, and supervision costs more than the navigation it replaced. What moved it was making every result carry its own evidence, the changed field, the value it held before, a direct link. Verification had to be one glance inside the answer, or people would keep going to look for themselves.
Latency ran straight into the expectation that a chat box sets. Type a sentence, get an answer, two seconds, that is the contract everyone arrives with. A grounded multi-step run against a real enterprise workspace does not honour it and no amount of engineering was going to make it. Streaming the reasoning was what bought the time: naming the intent, then the tool it picked, then the retrieval it ran. A spinner spends the user's patience. A sequence of true statements about what is happening earns some.
The last one has no clean answer. Sometimes the model misreads intent on a record that matters, on a real candidate, on a live requirement, in front of a client. You do not design that away, you design for the minute afterwards. Narrow writes, single record by default, an undo wherever the underlying platform could support one, and a per-action audit trail that recorded the sentence the recruiter said alongside the change the agent made. When something did go wrong, the team could see exactly what was asked and exactly what happened, which is the difference between a bug and a mystery.
Outcome
One way in, for everyone on the platform
It became the single AI assistant for recruiters on the platform: one centralised interaction layer standing in front of a set of separate product navigation paths that had each grown up on their own. Not a feature inside a module. The way you addressed the product.
The more durable change was internal. Once a tool surface existed, new functionality had a second design question attached to it, alongside where does this live in the UI came how would an agent invoke this, and what is it allowed to do with it. Tool design became part of feature design rather than an integration task at the end. That is a shift in how a product team thinks, and it outlasts any particular assistant.
Public figures for this one do not exist, so there are none here. Adoption, latency and time saved were tracked internally and are not mine to publish, and an invented number would be worth less than the omission.
What I would do differently
Build the vocabulary from the user, not the product
I would build the tool surface from recordings of recruiters talking, before writing a single tool. The first set was derived from the product's own information architecture, because that was the map we had, and it made the assistant fluent in the product's vocabulary instead of the user's. We spent months translating afterwards. I would also ship the audit trail and the undo layer before the first write tool rather than alongside it. Both were treated as safety work to be built in parallel, and both turned out to be the thing that made recruiters willing to let go of the mouse.