Applied AI Engineer · Choreograph / WPP
Michel Epe
I joined the support team at Choreograph and ended up building the AI tools the team runs on.
Fragmented information, knowledge that lives with one person and goes nowhere, processes that can't keep up: I built systems that fix exactly that, and other teams keep asking for the same thing.
ProductionAskOpti
Powerful AI capabilities were already there, but getting to them meant installing tools, navigating a terminal, and jumping through access hoops. Most people just didn't bother. AskOpti brought those same capabilities into Slack, where the whole team already lives. Three teams use it daily, and more keep asking to get onboarded.
View case study →Close ↑
Multi-agent orchestration
Entry points
Orchestrator
Sub-agents (parallel)
MCP tools
The Problem
Support, implementation, and enablement teams needed fast answers from product data spread across Zendesk, a customer-facing knowledge base, and Atlassian. Finding one answer meant checking all three tools by hand, so a single query could eat up minutes.
What I Built
A multi-agent Slack bot. The orchestrator (Claude Sonnet) receives a question and reasons about which sources to query. Sub-agents (Claude Haiku) execute the tool calls in parallel through MCP connections. Results get synthesized into a structured answer posted back to the thread.
The system is interface-agnostic. The same agent backend powers a Slack bot, a Claude Code plugin, and a Teams bot in development. Each entry point has different capabilities but shares the same architecture and tool connections.
The Hard Parts
- 1.
Latency. The first version averaged 250 seconds. I made five targeted changes: upgraded the sub-agent model, cut orchestrator round limits from 5 to 3, cut sub-agent limits from 8 to 4, increased the concurrent semaphore from 2 to 4, and tightened the investigation contract format. P50 dropped to 10-12s. P95 went from 149s to 35-45s.
- 2.
Testing model changes safely. Built a shadow testing system that runs experimental configurations in parallel with production without surfacing results to users. New configs get validated against real queries before promotion.
- 3.
Interface parity. The same agent backend serves Slack, Claude Code, and Teams, each with different capabilities and tool access. Getting the abstraction right meant any new interface is an addition, not a rewrite of what already works.
ProductionKB Automation
Every support team has the same problem: thousands of tickets, no time to capture what's in them, and documentation that's outdated before it's finished. Multiple people tried to solve this at Choreograph and moved on. I built a pipeline that does it automatically, with a human reviewer at the end instead of the beginning. The knowledge base now grows on its own.
View case study →Close ↑
4-stage pipeline · two-LLM design
Stage 1 · Ingest
Stage 2 · Cluster
Stage 3 · Interpret
Stage 4 · Generate
The Problem
Thousands of support tickets per product, per quarter. Valuable signal buried in unstructured text. No way to query it. Teams writing knowledge base articles by hand, missing patterns that only become visible across hundreds of tickets at once.
I was living this problem every day as a support specialist, which meant I knew exactly where the friction was before I wrote a line of code.
What I Built
A 4-stage pipeline. Stage 1: fetch tickets, scrub PII with Presidio before any LLM touches the text. Stage 2: cluster with sentence-transformers and k-means/HDBSCAN. No LLM here, just a cheap embedding model running locally. Stage 3: Claude evaluates each cluster. Stage 4: Claude generates the article, with validation at every step.
Splitting the work across two models was deliberate. sentence-transformers do the heavy lifting of grouping 5,000 tickets, and Claude only ever sees the pre-grouped clusters. That keeps the cost at $1-3 per run no matter how many tickets come in.
The Hard Parts
- 1.
Article generation rate. Started at 9%. Claude kept deciding clusters did not warrant articles. Fixed by tuning cluster quality thresholds and rewriting the interpretation prompt. Reached 90%+.
- 2.
Hallucination prevention. An LLM writing factual content about real products at a real company is a liability, so I built 30+ regex validators, a circuit breaker that halts the pipeline after repeated failures, retry logic with tightened prompts, and a circular-loop detector. So far that has held the hallucination rate at 0% in production.
- 3.
Observability. Instrumented 25+ Prometheus metrics across all four stages, built Grafana dashboards, wrote 30+ alert rules. Added a checkpoint/resume system so a failed run picks up where it left off.
PublishedSwarm
When multiple AI agents work in parallel, they can overwrite each other's work without knowing it. Swarm solves this by mapping which files each agent will touch before anything runs, and only allowing parallel execution where it's actually safe. Built it for my own projects, published it on npm so others could use it too.
View case study →Close ↑
DAG execution ordering
Task list
Analysis
Execution
The Problem
Running multiple Claude workers in parallel is fast. But workers editing the same file produce corrupted output. And when a long run fails halfway through, you lose all progress and start over.
Building AskOpti and KB Automation in parallel made this concrete. I needed a coordination layer that was smarter than "run one at a time" but safer than "run everything at once."
What I Built
A TypeScript framework that analyzes a task list before any execution begins. It maps which files each task will touch, finds overlaps, and builds a directed acyclic graph. Tasks with no shared files run in parallel. Tasks that share files run sequentially.
Human-in-the-loop checkpoints gate high-risk operations. SQLite backs the memory layer so workers resume across sessions without repeating completed work.
The Hard Parts
- 1.
Pre-execution file analysis. The system needs to infer which files a task will touch before running it. I used task description parsing and file path heuristics, tuned against actual file changes from real runs.
- 2.
Risk-based gating. A conflict on a config file is more dangerous than one on a test file. The risk model gates parallel execution based on file type and location, not just detected overlap.
ShippedCC Plugin
Support agents forget steps under pressure. Not because they don't know the process, but because the queue is long and the documentation is buried somewhere. This plugin brings the right investigation steps directly into the workflow, triggered by natural language during a ticket. Less back and forth, fewer missed checks, faster resolution.
View case study →Close ↑
Investigation contract · confidence routing
Input
Supervisor
Workers (parallel)
Confidence routing
The Problem
Support and implementation teams use Claude Code but querying Zendesk, the knowledge base, and Atlassian for a specific ticket required writing custom prompts every time. No shared workflow, no consistency, no way to distribute institutional knowledge about how to investigate properly.
What I Built
A Claude Code marketplace plugin with six investigation skills. There is no runtime code at all; the whole system is prompt engineering and JSON configuration.
Skills follow a task worker pattern: a supervisor skill decomposes the investigation, parallel workers query different sources through MCP connections, results get synthesized following a strict investigation contract format.
The Hard Parts
- 1.
Hallucination prevention through format constraints. The investigation contract forces the model to declare confidence before making any claim. High confidence routes to drafting, low confidence routes to escalation. The format constraints end up doing the same job that validators handle in a traditional system, without a line of code.
- 2.
Platform routing. 12 ad platform configs, each with detection keywords and known error codes in JSON. The model reads the ticket, identifies the platform, and routes to the right config. No code, just structured data and prompt instructions that reference it.
- 3.
Model routing rules. Skills include explicit instructions: no Opus or Claude 4.6 for tool calls. Keeps costs down without sacrificing quality. Baked into the skill definitions so future contributors cannot override it accidentally.
I joined Choreograph's support team and ended up building the AI tools the team runs on. KB Automation shipped first. Then AskOpti. Then Swarm. Each one started as a problem I was living myself.
My background is in healthcare and mental health, not computer science. What that gave me is a habit of putting myself in someone else's shoes before I write a line of code. Who is this person, what are they trying to do, what gets in their way? That shows up in the work: AskOpti exists because powerful AI tools were too hard to access for most people on the team. The plugin exists because support agents forget steps under pressure, not because they're bad at their jobs.
I'm looking for teams that want to move fast on AI and need someone who can own it end to end.
epe.michel@gmail.com →