How Uber's Pre-AI Developer Infrastructure Became the Foundation for Its AI Agents

Open on YouTube ↗
Overview

What internal tools do engineers at a company with thousands of engineers and thousands of services actually use to build software with AI agents? In this episode of The Pragmatic Engineer, the host, a former Uber engineer, talks with Uday Kiran Medisetty, one of Uber's longest-tenured engineers and a Distinguished Engineer who now leads much of the company's agentic AI work. Uday walks through roughly two dozen internal systems, many of them shown on screen. The thread running through the conversation is that the coding harness is the easy part. In Uday's account, what made agents useful at Uber was a decade of investment in developer platforms built long before generative AI: cloud dev environments, standardized builds, API registries, distributed tracing, and test-routing infrastructure.

30 min read
3:59

From Two Services to Thousands

Uday joined Uber in May 2015 on the Real-Time API (RT API) team. At that point, they recall, Uber ran essentially two services. "Dispatch," written in Node.js, handled all rider and driver traffic using a simple four-second ping protocol that returned the full state of the world. "API," written in Python, took over once a trip was completed and handled post-trip processing such as payments and receipts. RT API was created to abstract internal services away from the mobile apps and to replace the four-second ping with REST APIs plus a server-to-client "push protocol." Because the app's state changes every few seconds as things happen in the physical world, Uber needed an efficient way to update riders and drivers. RT API was one of the highest-QPS services at the time. It was later rewritten in Go and, according to Uday, is still one of Uber's highest-QPS services.

The microservices boom came out of hypergrowth. Uber was constantly entering new countries and adding products, including Uber Eats, and teams needed to build functionality quickly. Uber invested heavily in service infrastructure for metrics, tracing, monitoring, observability, and deployment. Uday says little off-the-shelf software could handle that scale and rate of change, so much of it was built in-house. The company went from two services to the order of thousands. Around 2018–2019 Uber standardized on Go and Java as its primary languages, modernized its stack, and thought harder about architectural layers and platformization. On one fulfillment platform Uday worked on, the team actually consolidated services. Uday says Uber today runs in a similar ballpark of service count even though the business is about ten times larger. A single global tech stack serves every country, and shared building blocks serve all mobility and delivery verticals.

On headcount, Uday was roughly the 600th engineer, and the whole marketplace team was perhaps 50–60 engineers. Engineering grew to a few thousand. From around 2019–2020, Uber expanded to 12 global tech sites across almost every continent where it operates. Uday says this lets teams build products for hyperlocal markets, some of which are later rolled out globally. For their first ten years Uday worked on business platforms: fulfillment, Uber for Business, earner onboarding, and marketplace pricing. For the past year they have focused on agentic AI for engineers and the rest of the company, along with some user-facing AI work.

9:41

The Pre-AI Tooling Layer

Uday lists several systems Uber had to invent because nothing on the market fit its scale:

  • uOwn, which identifies who owns any asset. During an outage, for example, it tells you which team owns a service and who is on call.
  • Centralized design docs and incident management. Product and engineering design docs live in one place, and so does incident tooling. Uday describes Uber as "really obsessed" with how it handles incidents and learns from them.
  • M3DB, the metrics system. Uday estimates that around 2015–2016 Uber was already emitting about 500 million metrics per second with high cardinality. M3DB was later open-sourced, and companies have formed around it.
  • Michelangelo, the end-to-end ML platform covering feature creation, model building, monitoring, and serving for hundreds of models. Uday notes that parts of its deep learning infrastructure were open-sourced a couple of months before the recording.
  • Cadence, a durable workflow engine for processes that span days, such as driver onboarding or CRM campaigns. Before it existed, engineers kept building their own resiliency and state management. Cadence was open-sourced, and the host notes that Temporal drew heavily on its ideas.
  • Morpheus, the configuration, feature-flag, and experimentation platform. Uday calls Uber a very data-driven company where "everything goes through a feature flag, everything goes through an XP." Because Uber runs two- and three-sided marketplaces, simple A/B tests are often not enough, so the platform supports switchback experiments and automatically generates analyses such as p-values and metric choices. That in turn required investment in trustworthy metrics and data foundations.

The host remembers wondering why Uber needed its own feature-flag system. The answer turned out to be that no vendor treated cities as first-class citizens. Uday confirms that cities are deeply baked into the infrastructure. Some critical platform services shard by city. A city is pinned to a specific region and can be failed over to another region at any time. For some services, "logical deployment groups" route groups of cities to groups of containers. Uber uses this for services that need that level of isolation and reliability, not for all of them.

Uday's summary of the pattern: in the early years Uber had to invent a lot. As the industry matured, Uber now buys where it can, builds where it sees a unique need, and tries to open-source what might interest the rest of the industry.

15:53

DevPods: Cloud Dev Environments That Agents Inherited

The host remembers DevPods, built around 2017, as ahead of the industry. Uday explains the backstory. In the early microservices era every service had its own repository, and teams used two or three build systems and two or three test systems. Library upgrades across services were very hard, even for a central team. Around 2017–2018 Uber moved to one monorepo per language (Go, Java, iOS, Android, and so on), while still deploying services independently. Once the monorepos grew large, building them on a laptop and getting through local setup became painful.

DevPods are cloud developer boxes, one flavor per monorepo, and an engineer can have any number of them. They come with build caches, run on machines beefier than laptops, have the right tools preinstalled, and let Uber set SLAs on build and test times. In a live demo, Uday shows that a new DevPod spins up within seconds. Uber runs them on Kubernetes clusters across multiple clouds, keeps them warm, and clones them from prebuilt images that already include repositories and build caches. Bazel is the build system across all repositories, so one command builds any module.

Uday says this foundation paid off in the AI era because agents need the same kind of workspace. Uber created a "mega DevPod" containing all repositories, so agents can read context and open PRs across repos. Standardized building and testing meant Uber could put AGENTS.md and CLAUDE.md files at the top level, and most teams got value immediately without per-module setup. Claude Code, Codex, OpenCode, and other AI tools come preinstalled, so even non-engineers can create a DevPod and start experimenting.

19:47

Model Gateway and AI Guard: One Entry Point for Every Model

Uday describes the guiding principle for Uber's AI foundations. Models and harnesses change quickly, so Uber invested in building blocks that are model- and harness-agnostic. The first of these was the model gateway, started soon after ChatGPT launched. Uday first said 2013–2014 and corrected it to late 2023 and early 2024. It is built on Michelangelo, which now has a GenAI set of components, some of which are not yet in the open-source version.

A team creates a GenAI project in Michelangelo, picks models, and gets a project UUID. The client passes that ID and a caller token. The gateway exposes one OpenAI-compatible or Anthropic-compatible API, and all models from all vendors, open-weight or closed, sit behind it. Uday stresses that every model request at Uber goes through this gateway.

The first middleware added was AI Guard, intended to make sure no sensitive content is sent back to users. Because there is a single entry point, the security team can iterate on its own models. Uday mentions about five fine-tuned models covering content, safety policy, and communications policy, which run on every request and response under strict latency guardrails. Centralizing traffic also gave Uber per-user and per-caller attribution, spend tiers for projects and users, audit logging, session traces, and tracking of billing and cache-hit rates. Uday sees it as a natural place to add model routing in the future.

25:02

AIFX: Making Harnesses Interchangeable

The next question was how to let engineers switch harnesses, for example from Claude Code to Codex, without losing their settings, skills, tools, and plugins. Uber wraps all harnesses in a tool called AIFX ("AI foundations"). It is preinstalled on DevPods and can be installed locally. It has a concept of "personas" that ship with default plugins and skills, so engineers get useful defaults without installing anything. Settings are centrally managed and synced across a user's local machine and all their DevPods. A status line shows tips and tracks spend within the current session, within a harness, and across harnesses.

How Uber handles token spend

Asked whether a new senior engineer needs to worry about cost, Uday describes a tiered system. Everyone starts at a default spend tier. When they approach the limit, they can request the next tier with a simple manager approval, which prompts a conversation about ROI and responsible use. Uday says Uber does not want to restrict engineers who are spending on the right projects, because the goal is to maximize the gain, so it keeps the paperwork minimal. Interactive harnesses and background coding agents have separate tiers. A plugin called cost check analyzes an engineer's sessions and gives personalized tips. Uday says this has helped with real-time coaching on context health and model sizing and encourages useful conversations between engineers and managers.

29:38

MCP Gateway: Every Internal Service as a Tool

Around early 2025 Uber enabled Cursor, and MCP was emerging as a spec. Uber realized that exposing internal tools to AI could extend it well beyond coding. In April 2025 it started building an MCP gateway, described as "one gateway for all of the tools."

The key enabler was a pre-existing registry of IDLs for all services, defined in Thrift or Protobuf. Older services use Thrift, newer ones use Protobuf, and teams usually switch to Protobuf during rewrites. From that registry, Uber auto-generates a default MCP server for every service, with tools derived from existing APIs, including request and response specs and descriptions. Uber later used the API descriptions to generate LLM-optimized descriptions of APIs and fields. Uday says some auto-generated tools were 3,000–4,000 tokens, so this optimization mattered. Enabling a service takes one config and security-policy change, with no code changes. Teams can also build custom MCP servers with an internal framework and proxy them through the gateway.

Vendor tools such as Google Workspace and Slack are exposed through the same gateway, so internal and external tools install the same way through AIFX. In recent months Uber also projected every MCP server as a CLI, letting harnesses choose between MCP and CLI usage. Uday credits the speed of the build to the fact that the API gateway team, already expert in protocol transformation, also built the MCP gateway. Once Google Workspace and Slack were included, Uday says, people could automate almost anything. Slack, Google, Jira, Linear, and any internal service became "a CLI call away."

34:21

The Skills Monorepo

Early in the year of the recording, Uber created a skills monorepo. It contains core skills built by central platform teams and team-specific skills built by individual teams, packaged as plugins and skills that work across all harnesses. A single set of quality gates runs across them. Installing a plugin through AIFX updates the configuration of every harness, whether the engineer is currently using it or not. Because all skills use tools from the MCP gateway, there is one standard way for skills to access any tool.

The host asks why this is more complex than a Git repo of skill folders. Uday's answer: with current models, a v0 skill is easy to write, but making it good across all use cases is hard, so central management matters. He gives an example. When CLI projections of MCP servers became available, a couple of engineers used AI to update every skill in the repo to the CLI pattern. Uday says this is more token-efficient: if two plugins each declare three MCP servers, all six sit in context permanently. The marketplace is auto-installed for everyone, which helps discoverability and lets Uber build eval and discoverability pipelines around it. Some teams still keep their own repositories, but most skills go through this one.

Work still in progress includes a tool that gives engineers tips on improving their skills and a pipeline that collects harness traces and generates improvement patches for skills. Uday reports about 30,000 skill executions per day in recent weeks.

38:43

Context Graph and Cortana

Uday calls the context graph their favorite project. It grew out of Cortana, an AI assistant an engineer built in December and available on the web and in Slack, which can answer questions about any codebase by searching across repositories. People used it for research, query help, finding data sources, ownership questions, and root-cause analysis. Looking at the traces, the team saw that models spent many turns just getting grounded, because information was spread across siloed systems: task management, on-call dashboards, uOwn, and others.

The context graph connects all of these into one map for agents. Uday's live visualization showed more than 100 node types and more than 130 edge types, with data about three days old. A person node links to the assets they manage, design docs they wrote, features they work on, on-call events, config changes, incidents, Jira events, and PRs. Every node has relationships to other nodes. Cortana now uses the graph as default grounding. It first identifies the domain and services a question is about, then goes deeper into documents. Uday says this cuts the number of turns, and that for many categories of questions quality goes up while cost and latency go down. They describe this as still early.

Uday's example is the question "how many mobility trips around the world are paid in cash?" Answering it requires knowing which tables and columns exist, whether others have written similar queries in the last 30 days, and which team they came from. The graph helps the agent reach "blessed" queries quickly. Uday observes that writing Cypher queries by hand is hard for humans, but agents navigate the graph the way they navigate a file system with bash. Scale is not a problem: the graph platform team that runs Uber's production graph, which has billions of nodes, helped build it, and the context graph is much smaller.

Cortana is available in Slack, on the web, and in the CLI. Uday says it breaks down information silos across organizations. Someone in operations in any country can ask how something is built, who works on it, or what its history is. It can also produce a "360-degree" health report for a service by examining dependencies and storage systems and running queries. Existing user permissions carry over, so users can only see data they already have access to.

Planning: PRDs, ERDs, and Physical-World Edge Cases

Moving to the feature lifecycle, Uday says some phases are further along than others. The idea of a combined plan that agents and engineers iterate on together is still at the stage of "a lot of cool ideas." What exists today is a single place for product design docs, engineering design docs, launch reviews, experiment reviews, and production-readiness reviews, with agentic skills for working on them. Each project links to Jira or Linear, and all of it feeds into the context graph. The result is a source of truth for specs, approval status, and ownership that both humans and agents can trace from spec to execution.

Uday argues that planning matters more at Uber because of product and country heterogeneity. Corner cases outnumber the happy path, and operating in the physical world multiplies them: what happens if this goes wrong, how a support case gets handled, and so on. A good plan up front makes it easier for engineers or agents to decompose and execute the work.

50:50

Minion: The Background Coding Agent

Minion is Uber's background coding agent. The current version is Minion v2. Uday says around 15% of all production PRs go through it. It runs on the mega DevPod, so it can work across repositories and produce one or several PRs from a plan. It can be used from the web or Slack, with an optional plan mode, or given a single prompt for simple tasks.

In Slack, an engineer can align with a PM and EM in a thread, then write "@minion follow this thread and create a PR," and Minion uses the thread as context. Uday describes it as especially useful in support channels. Someone reports a bug, the on-call engineer asks Minion what it sees, Minion returns a root cause, and if the fix is simple it is made on the spot instead of going into the backlog. Minion started with mostly maintenance tasks. As more self-validation tools are added for web, mobile, and backend APIs, Uber aims to expand the kinds and share of tasks it handles.

55:26

Shortening the PR Cycle: Self-Healing CI and Code Inbox

Uday says PR volume has gone up year over year. Uber tracks P50 and P90 cycle times for the inner loop (getting a change to green and creating the remote PR) and for the outer loop (human review and CI). Reviews have become a big bottleneck, as at other companies.

Uber took several steps in response:

  1. Shift-left validation. Many simple CI jobs, including linters, coverage rules, build rules, and template rules, moved into the inner loop behind a single command, aifx validate, so agents can run them before creating a PR.
  2. Visual and environment validation. Agents can spin up emulators, web instances, and staging deployments to test changes, and skills teach them how.
  3. Self-healing CI. It can be applied to all PRs or per PR, with automations such as auto-request-review, auto-merge, and auto-fix.
  4. Code Inbox. A view showing PRs waiting on an engineer and PRs they are waiting on. For each PR it shows what the AI code review checked, sanity-test screenshots and videos, and build checks. Uber is adding a risk score and blast radius.

The growth in CI jobs, which Uday says doubled or more than doubled year over year, forced Uber to do an internal code red on its CI system to prepare for more PRs.

Will human code review go away?

Uday says Uber prefers to err on the safe side because incidents are very costly. Every PR still requires a human engineer's review. If confidence grows in risk scoring, which can be back-tested against years of data, and in AI code review, Uber might enable a "green lane" for auto-landing some classes of low-risk PRs. Uday stresses that Uber wants to be "really really sure" first. The current P0 is getting reviewers the right signals so they can review faster. Auto-landing is a P1.

1:00:43

Slate: End-to-End Testing That Agents Can Drive

Before agents, engineers tested multi-service features using Slate. An engineer deploys their branch to a personal Slate instance and pins a test account UUID to it. Requests from that account hit the branch for the services under test and normal staging for everything else. This works across two or three services at once.

Once Slate existed, Uber only had to teach agents to deploy to it and give them the relevant APIs. In the demo, an agent uses the Slate tool to create an environment, deploys a test service, runs an agent browser against both main and the branch, and produces a before/after report showing no regressions. That report can be attached to the PR. The same works for iOS, Android, web, and backend APIs.

The host stresses how hard this was to build. Uday explains that it relies on Jaeger, the distributed tracing system Uber built around 2017–2018 and later open-sourced. Every call has a parent span, and every hop adds a child span that can carry "baggage." Slate adds baggage naming the services under test and the pinned account, and the service mesh reads it to route requests to the Slate environment. Uday says it took years to retrofit every existing service and to make sure new ones were built this way. In their view, without systems like Slate it would have been very hard for agents to validate their own work.

1:06:39

Capri: Capturing and Replaying Production Traffic

Uday calls Capri (capture-replay) very Uber-specific and hard to get right, noting there were several earlier attempts. This is the version they believe can scale to all teams. The problem it addresses: the rider app has hundreds of screens across product lines, cities, and other dimensions. Writing tests for every combination would mean maintaining thousands of tests.

Because language frameworks are standardized, a single middleware can capture real production traffic. It records a service's inbound and outbound requests and responses, including calls to downstream APIs. Platform teams write simple rules that map request fields to dimensions they care about. From the captured traffic, Capri derives the full set of live dimension combinations a platform actually supports, called MatchGuard. MatchGuard runs pre-deploy in CI/CD and shows the before/after delta for every PR in a deploy. Uday's example is catching a change that breaks only cash trips in Brazil under a particular configuration, something hard for engineers or agents to test manually.

In the demo, Uday browses captured sessions tagged with metadata such as marketplace type and line of business "eats," inspects outbound calls, and shows how a bug affecting only San Francisco Uber Eats trips could be fixed and then verified by replaying that specific request against a Slate environment and diffing the result. The host recalls Deputy and Cerberus as earlier tools. Uday explains that Deputy routed production requests to a test instance and Cerberus routed a local instance back to staging servers, and that Slate now makes both largely unnecessary. Capri is being exposed to agents as well. Uday describes the intended loop: the agent fetches sessions of a given type, composes a matching request on its Slate instance, checks whether the fix worked, and iterates until it does.

1:12:28

Edge Gateway, Shepherd, and Fox

The Edge Gateway, the successor to RT API and written in Go, is now the single entry point for external APIs, including gRPC, webhooks, and GraphQL, with shared monitoring and alerting. It has its own capture-replay built on Capri. Using Jaeger data, Uber knows each service's dependencies and has automatically tagged them as required or optional. Uday says this gives both engineers and agents richer context when diagnosing alerts, for example by pointing to the likely unhealthy node in a service graph.

Shepherd handles large-scale changes in the monorepos. It started with OpenRewrite policies for deterministic changes such as signature updates. Shepherd knows which modules belong to which teams and creates a PR per module. With AI, it gained agentic campaigns: for example, fixing context propagation across all services so tracing works better, using prompts and skills that an agent runs on every module. Each migration is a "campaign" with a YAML policy, per-module PRs, and status tracking for the campaign owner, as in the JUnit 4 to JUnit 5 migration.

A few months before the recording, Uber added Fox, aimed at continuous improvement rather than one-time migrations, or "self-improving code bases" in Uday's words. Service owners enroll their service in skills such as dead-code cleanup, performance analysis, or noisy-log fixes. Each week, around Sunday when CI load is low, Fox generates a PR per enrolled skill. It is opt-in for now, and some skills may move to opt-out as they improve. Uber reviews maintenance-category PRs to decide which new skills to create or improve so more of that work can move into this managed loop. The aim is to cut toil so engineers can spend more time on feature work.

1:18:02

Wisdom and Debug Assist: From Bug Report to PR

All employees dogfood Uber's apps. Wisdom is the system for bug reports filed from employee beta builds. AI routes each report to the right team, and the report includes logs and telemetry: screens visited, analytics, network requests, and feature flags. Uday says reproducing bugs used to be a huge problem. Now Wisdom gives engineers reproduction steps along with expected and observed behavior.

On top of this, a managed agent called Debug Assist examines the telemetry and the codebase and proposes a root cause along with an impact and evidence timeline. If the engineer agrees, they hand it to Minion, which creates a PR and attaches it to the Jira task alongside the RCA. If someone later corrects the root cause or opens a different PR, that becomes data for improving both Debug Assist and Minion. Engineers can also make a test device replay the network responses served to the employee who filed the bug, so they see the same issue and can confirm a fix.

1:21:26

The Changing Job and How Uber Measures Productivity

Asked how the role is changing, Uday frames the work as repeatedly finding and removing the next bottleneck, using both AI and conventional systems engineering, with the goal of maximizing the number of features shipped. They mention "capability overhang": current models could do much more than organizations use them for, because orchestration, harnesses, and tooling lag behind.

On productivity, Uday says Uber previously measured standard things such as code throughput, plus periodic developer experience surveys (NPS and sentiment), incidents per diff, and code coverage. The internal conversation is now shifting from diff velocity to feature velocity: "you can create 100 diffs but if they're not all feature diffs," that does not necessarily add user value. Uber tags PRs by complexity and category (feature, bug fix, maintenance, testing, documentation) and tracks the mix year over year. Uday reports that the feature share is rising and the maintenance share is falling, which they take as a sign of going in the right direction. Because links between product docs, engineering docs, and tasks were often missing, Uber is using AI to cluster and tag the gaps so it can compute P50 feature cycle time by complexity, per half, over the past two to three years. The aim is to find where the bottleneck sits, whether in the PRD phase, the launch phase, or the rollout phase.

Personally, Uday says that in their whole career their way of working has never changed this much. Even Distinguished Engineers at Uber are hands-on, and Uday says they are producing far more PRs than a year ago and exploring more ideas. They see the core skills shifting toward context engineering (deciding what context an agent needs and setting up the environment to provide it), giving the right specs and constraints, multitasking across many parallel sessions, and quickly verifying output so regressions don't ship.

The host suggests a new primitive: instead of asking how to build and verify software, engineers ask how to set up an agent that can build and verify it. Uday agrees and gives an example from customer support. Converting a human runbook into a policy an AI support agent can follow used to involve many manual steps: finding the right APIs and attributes for dynamic elements, configuring systems, running manual evals before launch, and running continuous evals after. The team taught agents to produce a solid v0 policy, automated configuration and testing, and used past context to generate synthetic evals. Uday says the process went from weeks to days per policy, with guardrails and human verification steps still in place.

Asked about a favorite tool, Uday mentions recently experimenting with personal agents to automate manual tasks in their personal life, following the same pattern: give the agent the context, provide inputs, and keep a human-in-the-loop verification step. They close by saying Uber is still early, with much left to build.

The Host's Takeaways

In a closing segment, the host, who left Uber six years earlier and found much of this tooling new, adds a few observations. Uber was known for about 5,000 services with about 2,000 engineers a decade ago. It has since consolidated toward well-sized rather than micro services, though the count is still in the ballpark of 4,500–5,000. The host singles out Capri as a big improvement over Deputy and Cerberus, which made capture hard. On code review, the host notes that every PR at Uber still merges only after a human decides it is ready, while AI-driven risk signals help engineers decide which PRs deserve deep review and which can get a quick "LGTM." The host's broader conclusion is that Uber's decade of developer-productivity investment, such as DevPods from 2017 being reused for Minion and existing validation systems becoming agent feedback loops, is paying off. The host suggests that, at least in Uber's case, the companies getting the most from AI are those that already had strong developer platform teams before AI.