Author Archives: Dronerator

🚀 Breaking the Blockade: How We Taught Kafka to “Speak” Like a Synchronous API

Imagine the situation: Our system, let’s call it “BSDFlow”, is a modern, impressive Event-Driven monster. Everything happens asynchronously, reliably, and scalably through Kafka. Every entity creation and data update flows through the data pipelines like water.

Sounds like an architectural dream, right? Well, there’s a catch. And that catch starts when the user at the other end clicks a button.

The Dilemma: When the User Doesn’t Want to Wait 🐢

We live in a world of instant gratification. When we click “Save” in React, we expect to see a success message immediately (or an error, if we failed validation).

In a classic Event-Driven architecture, it works something like this:

  1. The client sends a command.
  2. The server throws the command into Kafka (like a message in a bottle).
  3. The server returns an immediate response to the client: “Got it, working on it!”.

But the client? They aren’t satisfied 😠. This answer tells them nothing. They don’t know if the .NET Backend actually processed the data, or if it hit an error along the way. The user needs a final and definitive answer.

This gap, between the speed of the Event and the need for an API response, is the blockade we had to break.

The Magic: A Promise with an ID ✨

The solution we developed allows the user to get an immediate response, while behind the scenes, everything remains asynchronous and safe. We turned our Node.js Middleware into a smart control unit.

The secret lies in the combination of a Promise Map and a Correlation ID.

How Does It Actually Work?

The process consists of three simple but brilliant steps:

1. The Middleware Steps In
When the request arrives from the Frontend, we generate a correlationId – think of it as a unique ID card for the request. We create a Promise, store it in memory within a data structure we called a Promise Map, and just… wait. We launch the message to Kafka, with the ID and the “Reply Topic” name attached to the message headers. The Middleware essentially gets an order: “Stop and await response” (await promise).

2. The Round Trip
The Backend (in our case, a .NET microservice) consumes the command, does the hard work (like a DB update), and at the finish line – sends a reply message to the Reply Topic we defined earlier. The most important part? It attaches the exact same correlationId to the reply.

3. The Resolve
Our Middleware, which is still waiting, constantly listens to the Reply Topic using a dedicated Consumer. The moment an answer arrives, it checks the ID, pulls the matching Promise from the Map, and releases it (resolve).

The result? The client gets a full, final answer, and the user enjoys a smooth experience, without knowing what a crazy journey their message just went through.

Show Me The Code 💻

We’ve talked a lot, now let’s see what this magic looks like in TypeScript. This is the heart of the mechanism in Node.js:

import { v4 as uuidv4 } from 'uuid'; 

// The map that holds all requests waiting for a reply
const pendingRequests = new Map();

async function sendRequestAndWaitForReply(command: any): Promise<any> {
    const correlationId = uuidv4();

    // Create a Promise and store it in the map with a unique ID
    const promise = new Promise((resolve, reject) => {
        // ... It's a good idea to add a Timeout here so we don't wait forever ...
        pendingRequests.set(correlationId, { resolve, reject });
    });

    // Send the message to Kafka (including the correlationId in headers)
    await kafkaProducer.send({ 
        topic: 'commands-topic',
        messages: [{ 
            key: correlationId, 
            value: JSON.stringify(command), 
            headers: { correlationId: correlationId, replyTo: 'reply-topic' } 
        }] 
    });

    return promise; // Wait patiently!
}

// When the answer arrives from the Reply Topic, our code does this:
function handleReplyMessage(message) {
    const correlationId = message.headers['correlationId'];
    const pending = pendingRequests.get(correlationId);

    if (pending) {
        // We found the Promise that was waiting for us!
        pendingRequests.delete(correlationId);
        pending.resolve(message.value);
    }
}

Wrapping Up

Sometimes the best solutions are those that bridge worlds. In this case, bridging the asynchronous world of the Backend with the synchronous need of the Frontend allowed us to maintain a robust architecture without compromising on user experience.

Have you encountered a similar problem? Have you implemented Request-Reply over Kafka differently? I’d love to hear about it in the comments! 👇

Why I Chose Monorepo: From Copy-Paste Hell to 2.8s Builds

Why I Chose Monorepo: From Copy-Paste Hell to 2.8s Builds

Friday, 11:47 PM. Portfolio site: white screen. Button component broke.

I’d updated the variant prop in my UI library repo. Pushed it. Forgot the portfolio had its own copy of Button.tsx—same name, different version, same breaking change.

Three repos. Three copies of the same component. Two of them broken.

That’s when I knew: the copy-paste had to stop.

TL;DR

What I did: Merged 3 separate repos (portfolio, web app, CLI) into one monorepo with shared packages.

The wins:

  • Builds: 5min 23s → 2.8s (95% cache hits with Turborepo)
  • Code duplication: ~40% → 0%
  • Type safety: Instant across all packages (no more publish-to-test)
  • DX: Change Button, see it update in 3 apps immediately

Setup time: 30 minutes

Would I do it again? Absolutely.

Keep reading for: The breaking point moment, what I tried, how it actually works, and 3 gotchas that cost me 4 hours.

The Problem

I’m building CodeCraft Labs—a portfolio site, a web playground, and eventually a CLI tool. React 19, TypeScript 5.6, Next.js 16, Tailwind v4. Solo dev for now, planning to bring on 2-3 people eventually.

The multi-repo nightmare:

Repository #1: portfolio (Next.js app)
Repository #2: web-prototype (React app)

Repository #3: ui-library (shared components)

What Actually Broke

I had a Button component. 230 lines. Used in both apps.

Initially: one repo, npm published as @​ccl/ui. Worked great.

Then I needed to iterate fast. Publishing to npm every time I changed padding? Painful. So I copy-pasted Button.tsx into both apps. “Just temporarily,” I told myself.

Three months later: three versions of Button.tsx, all diverged.

The breaking change:

// ui-library repo (v1.2.0)
export interface ButtonProps {
  variant: 'primary' | 'secondary' | 'ghost';
  onClick?: () => void;
}

// What I changed it to (v1.3.0)
export interface ButtonProps {
  variant: 'primary' | 'secondary' | 'ghost';
  onClick?: () => Promise<void>; // Added async support
}

Updated portfolio. Deployed. Worked.

Forgot the web-prototype had its own copy. It didn’t get the update. onClick handlers broke. Saturday morning: emails.

The Real Cost

Time waste:

  • Each shared component update: 15-20 minutes to sync across repos
  • Frequency: 5-10 updates per day
  • Daily cost: ~2+ hours of copy-paste coordination

What killed me:

  • TypeScript couldn’t catch cross-repo breakages (only failed after npm publish → install → build)
  • Three CI/CD pipelines to maintain
  • Deployment coordination (“Did I update all three?”)
  • Version drift anxiety

The moment I decided to change:
Saturday, 2:47 AM. Fixed the Button bug in 5 minutes. Spent 2 hours questioning if I wanted to keep doing this for the next year.

What I Looked At

Option 1: Keep Multi-Repo, Use npm link

The promise: Symlink local packages, no publishing needed.

Reality: npm link is… not great.

Tried it for a week:

  • Had to run npm link after every clean install
  • Forgot to re-link after switching branches: “Module not found” errors
  • Works on my machine, broke in CI
  • Gave up

Option 2: Git Submodules

The promise: Nest repos, share code via git.

Why I skipped it: Everyone who’s used git submodules told me “don’t use git submodules.” Listened to them.

Option 3: Monorepo (Turborepo + pnpm workspaces)

The promise:

  • One repo, multiple packages
  • Import local packages like npm packages (but instant)
  • TypeScript sees everything
  • Build caching makes builds stupid fast

Why I picked it:

  • pnpm workspaces handle package linking automatically (no more npm link hell)
  • Turborepo caches build outputs (only rebuild what changed)
  • Vercel built Turborepo, and I deploy on Vercel (figured integration would be good)

Setup took 30 minutes. Been using it for 6 months. Zero regrets.

How It Actually Works

Two tools doing different jobs:

pnpm workspaces = package manager

Turborepo = build orchestrator

The Structure

codecraft-labs/
├── apps/
│   ├── portfolio/          # Next.js → Vercel
│   ├── web/                # React app → Vercel
│   └── cli/                # Node.js CLI → npm
│
├── packages/
│   ├── ui/                 # Component library
│   │   ├── src/
│   │   │   ├── Button.tsx
│   │   │   └── ...
│   │   └── package.json    # name: "@​​ccl/ui"
│   └── typescript-config/  # Shared tsconfig
│
├── pnpm-workspace.yaml     # Defines workspaces
├── turbo.json              # Build pipeline
└── package.json            # Root dependencies

How pnpm Workspaces Link Packages

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'
// apps/portfolio/package.json
{
  "dependencies": {
    "@​​ccl/ui": "workspace:*"  // Links to packages/ui/
  }
}

Run pnpm install. That’s it. pnpm creates symlinks:

apps/portfolio/node_modules/@​​ccl/ui → ../../packages/ui/

Now you can import:

// apps/portfolio/src/app/page.tsx
import { Button } from '@​​ccl/ui';

<Button onClick={async () => {
  await saveData();
}}>
  Save
</Button>

TypeScript sees the real source file in packages/ui/src/Button.tsx. Immediate type checking. No publishing. No version mismatches.

How Turborepo Makes Builds Fast

// turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    }
  }
}

Run turbo build:

  1. Analyzes dependency graph: Portfolio depends on @​ccl/ui
  2. Builds in order: @​ccl/ui first, then portfolio
  3. Caches outputs: Hashes inputs (source files, deps, config), stores outputs in .turbo/cache/
  4. Skips unchanged packages: If @​ccl/ui hasn’t changed, uses cached build (0.3s instead of 8.2s)

Real numbers from my project:

  • First build: 62.4s (cold, everything compiles)
  • Second build: 2.8s (95% cache hit)
  • Changed Button.tsx only: 8.1s (rebuilds @​ccl/ui + portfolio, skips web + cli)

That’s 22x faster than before.

The Migration

What I Did (30 minutes total)

1. Created monorepo structure (5 min)

mkdir codecraft-labs
cd codecraft-labs
pnpm init

Created pnpm-workspace.yaml:

packages:
  - 'apps/*'
  - 'packages/*'

2. Moved existing repos (10 min)

mkdir apps packages
mv ~/old-repos/portfolio apps/
mv ~/old-repos/web apps/
mv ~/old-repos/ui-library packages/ui

Updated each package.json to use @​ccl/ scope:

// packages/ui/package.json
{
  "name": "@​​ccl/ui",
  "version": "1.0.0"
}

3. Installed Turborepo (2 min)

pnpm add -Dw turbo

Created minimal turbo.json:

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

4. Updated imports (10 min)

Updated imports to use workspace packages:

import { Button } from '@​​ccl/ui';

5. Tested

pnpm install
turbo build
turbo dev

Worked. First try.

(That never happens. I was suspicious.)

The 3 Gotchas That Cost Me 4 Hours

Gotcha #1: Peer dependency hell

Symptom: pnpm install failed with peer dependency errors.

Problem: Portfolio had React 19, web app had React 18, ui-library allowed both.

Fix: Align all React versions:

pnpm add react@​​19.0.0 react-dom@​​19.0.0 -w
pnpm install

Took 90 minutes to figure out. The error message was unhelpful.

Gotcha #2: TypeScript path mapping

Symptom: TypeScript couldn’t find @​ccl/ui types.

Problem: Needed explicit path mapping in tsconfig.

Fix:

// apps/portfolio/tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@​​ccl/*": ["../../packages/*/src"]
    }
  }
}

Spent 45 minutes on this. Should’ve read the pnpm docs first.

Gotcha #3: Cached build was stale

Symptom: Changed Button.tsx, rebuild was instant, but changes didn’t show up.

Problem: Turborepo cached old output, didn’t detect file change (I had modified file outside of git).

Fix:

turbo build --force  # Bypass cache

Or clear cache:

rm -rf .turbo/cache

Lost 90 minutes debugging this. Thought my code was broken. It was just cache.

What Changed

Before Monorepo

# Update Button component workflow
cd ui-library
# Make changes
npm version patch
npm publish
cd ../portfolio
npm install @​​ccl/ui@​​latest
npm run build  # 5min 23s
git push
cd ../web
npm install @​​ccl/ui@​​latest
npm run build  # 4min 47s
git push

# Total: 15-20 minutes, 3 repos, 3 deploys

After Monorepo

# Update Button component workflow
cd packages/ui
# Make changes
turbo build  # 2.8s (cached)
git commit -m "Update Button API"
git push

# Vercel deploys both apps automatically
# Total: <3 minutes, 1 repo, 1 commit

The Numbers

Metric Before After Improvement
Build time 5min 23s 2.8s 22x faster
Code duplication ~40% 0% Eliminated
Repos to manage 3 1 66% less
Time per update 15-20 min <3 min 85% faster
Type safety Publish-to-test Instant Immediate
CI/CD pipelines 3 1 Simplified

Time saved: ~2 hours daily (5-10 component updates × 15-20 min each → <3 min)

Rough ROI: If you value time at $50/hr, that’s $100/day = $2,000/month in saved time.

But honestly? The real win is not having to think about it anymore. I change Button.tsx, TypeScript catches issues instantly, deploy once, done.

When to Use Monorepo

Use monorepo if:

  • You have 2+ projects sharing code
  • You’re copy-pasting components between repos
  • You want type safety across packages
  • You value fast iteration over independent deployment

Don’t use monorepo if:

  • Single app with no shared code (unnecessary overhead)
  • Completely independent projects (no shared code = no benefit)
  • You need different tech stacks per project (Go backend, Python ML, Node.js frontend—monorepo doesn’t help much)

My context: Solo dev, 3 apps, heavy code sharing, deploying on Vercel. Monorepo was perfect.

Your context might differ. If you have 100+ packages or a team of 50+, look at Nx instead of Turborepo (more features, more complexity).

Final Thoughts

Would I do it again? 100% yes.

What surprised me:

  • Setup was way easier than expected (30 minutes, actually worked first try)
  • Cache hit rate stayed high (95%+) even with active development
  • TypeScript catching cross-package issues instantly is addictive
  • Refactoring is fearless now (rename function, TS shows all usages across all packages)

What I’d do differently:

  • Align all dependency versions before starting (would’ve saved 90 minutes)
  • Read pnpm workspace docs first (would’ve saved 45 minutes on path mapping)

Biggest surprise: Adding a new app takes <5 minutes now. Copy structure, link packages, done. Planning to add 3 more apps in next 6 months—would’ve been a nightmare in multi-repo.

Bottom line: If you’re managing 2+ projects that share code, monorepo in 2025 is a no-brainer.

Resources

Official Docs:

My Code:

Community:

Questions? Drop a comment or hit me up:

Twitter: @saswatapal14

LinkedIn: saswata-pal

Dev.to: @saswatapal

More tech decision breakdowns coming—React 19, Tailwind v4, Vitest, Biome.

Part of the Tech Stack Decisions series

Why Cursor, Windsurf and co fork VS Code, but shouldn’t

Why Cursor, Windsurf and co fork VS Code, but shouldn’t

Forking VS Code gets you to market fast. Building on a platform gets you a product that lasts. Eclipse Theia is that platform.

Over the last two years, a wave of “AI native editors” has launched on top of a fork of Microsoft’s Visual Studio Code (VS Code). Cursor says it’s “built on VS Code”, Windsurf markets VS Code compatibility, and similar tools follow the same path. Cursor: https://www.cursor.com Windsurf Editor (Codeium): https://windsurf.com

On the surface this makes sense: you inherit a familiar UX and a huge extension ecosystem, and you can patch whatever the public extension API will not let you do. But forks come with hidden costs: ongoing rebasing, licensing puzzles, marketplace restrictions, and dependence on Microsoft’s governance.

Recent events have made this more concrete. In 2025, Microsoft extensions like the C and C++ tooling stopped working in Cursor and other forks, due to licensing and distribution enforcement. This is a good illustration of ecosystem risk when your product depends on a competitor controlled store.

In this article, we look at why well known products felt the need to go beyond the VS Code extension API, and why a platform approach is a better long term bet.

Image
Image showing on the left the VS Code Fork with many frightening robots, and on the right the Theia Platform with a much nicer set of tools

🔧 Extensible product vs platform to build a product

This conceptual distinction is crucial and often overlooked:

  • VS Code is an extensible product. It was designed as a developer tool first, with a stable API for third party extensions. That API is intentionally limited: it protects end users, keeps the UX coherent, and ensures Microsoft can evolve the product safely. But it was never designed as the foundation for other products.
  • A platform, by contrast, is designed for others to build on. It exposes deep, stable extension points across both frontend and backend, allows reshaping of the UX, and gives you governance over distribution and policy. A platform invites you to innovate, while an extensible product restricts you to safe, controlled add ons.

If you treat an extensible product like VS Code as if it were a platform, you hit walls quickly. Branding, reshaping the UX, embedding AI into every pane, or orchestrating application wide experiences push you beyond what the extension surface can do. That’s why so many teams end up considering a fork.

And this brings us to the following practical question:

⚠️ “Why not just use the extension API?”, where it runs out of road

Yes, you can ship impressive AI features as plain VS Code extensions today. The Marketplace has a long tail of AI tools. For example:

So why do Cursor, Windsurf, and other “AI native editors” still fork instead of “just using the API”? Because the differentiators they want, AI woven into every pane, proactive behaviour driven by global context, and ownership over distribution and governance, live beyond what the extension surface is designed to allow.

VS Code’s extension API is deliberately stable and constrained. That’s good for end users, it is limiting for teams trying to build product level experiences. Conceptually, adding a menu, command, or extra view is squarely in extension territory, but branding, reshaping the UX, or deeply weaving AI into the core experience quickly pushes you outside those safe boundaries. The examples below illustrate where this line gets crossed in practice.

Full stack control matters Building a compelling AI native product is not just about what happens in the editor. You need full stack control: how do you host the system? how do you integrate it with LLMs, web UIs, version control backends, custom deployment pipelines, or proprietary data sources? An extension runs in someone else’s sandbox. A platform lets you own the entire stack, from backend services to frontend UX, and wire them together however your product demands.

The Copilot advantage, governance over the API surface You might wonder why GitHub Copilot seems so well integrated in VS Code. The reason is simple: Microsoft opened explicit internal and provisional APIs for this extension over time. They could do this because they have the sources of VS Code under their control. Other vendors do not have this type of governance advantage. If you’re building a competing AI tool, you’re stuck with the public, stable API, while your competitor gets to shape the platform to fit their needs.

A few examples that frequently push teams to fork:

1) Custom chat UX, often the heart of AI native products Chat is frequently the primary interface for AI native editors, yet VS Code’s chat API is only partially extensible. You can contribute chat participants and commands, but you cannot tailor the chat panel’s layout, styling, or interaction patterns to match your product vision. Almost all forks, and even many VS Code extensions, build their own custom chat windows as a result. For extensions, these separate chat implementations often lack full integration with the rest of the workbench, creating a disjointed experience. For forks, custom chat becomes possible but adds to the maintenance burden. If chat is central to your product’s identity, the built in chat surface won’t let you differentiate.

2) True overlay or embedded AI in any view (Explorer, Terminal, Debug, Problems) Extensions can add views and webviews, decorate text, and place context menu entries, but cannot freely render overlays into Microsoft’s built in views. Even seemingly simple tasks, like reacting to hover or selection in the built in File Explorer, lack public events. The UX guidelines nudge you to context menus or new panels, not invasive overlays. If your product vision needs first class, in place AI everywhere, you hit walls quickly.

3) Observability of user activity across the workbench You can observe text document edits and active editor changes. But there is no comprehensive, supported activity stream API for everything a user does across built in views, and the few window level signals that exist are limited and have rough edges. For proactive AI that reacts to what just happened anywhere, you’ll end up resorting to fragile workarounds, or a fork.

4) Terminal output and non editor context Terminal APIs have historically required proposed or limited contracts. Reading raw output reliably from all terminals is not a stable, generally available capability for Marketplace extensions. That makes terminal aware copilots harder to ship purely as a VS Code extension.

5) Global editor state and multi editor context You can inspect the active editor and the set of visible editors, but a complete inventory of open editors and their state is not cleanly exposed as a first class, stable API. The long trail of issues and discussions around open editors illustrates how tricky this is for extension authors who need holistic context.

6) Full control over debug sessions You can start sessions and send Debug Adapter Protocol requests via DebugSession customRequest, and many scenarios work. But building a product that orchestrates multi session debugging, steps intelligently, and cross links with other views means living with adapter differences, fragile command execution, and no guarantees for non standard actions. That’s fine for an extension. It is a risky foundation for a product’s core UX.

7) Competing with, or coordinating, other extensions VS Code now has inline completions and AI chat APIs, but precedence and interaction between providers isn’t something extensions can reliably control. Co existence works in many cases, but you can’t build a product that depends on always winning over someone else’s extension.

And when you outgrow the API, you’re tempted to fork. That’s exactly the trap!

🪤 The fork trap in practice

Forks give you immediate superpowers: patch any internal, add new IPC, rewire the shell. But every VS Code monthly release brings integration work. You either lag behind upstream, users notice, or you staff an ongoing rebasing team, expensive. Meanwhile, you cannot rely on Microsoft’s marketplace or proprietary extensions to fill gaps. Microsoft has also removed or restricted direct VSIX downloads in the Marketplace over time, making offline or alternative distribution harder for non official editors.

We’ve written about this at length: forking looks fast now, but you pay it back with interest. The costs include maintenance, ecosystem access, legal licensing, and governance risk vis a vis a direct competitor with Copilot strategically integrated into VS Code.

🌍 Eclipse Theia: a platform for custom IDEs and AI tools

Eclipse Theia was built to let you create products, not just extensions. If your starting point is something very close to VS Code, you can get there: Eclipse Theia runs VS Code extensions, uses the same Monaco editor, and supports familiar UX patterns out of the box. But unlike a fork, you aren’t stuck inside someone else’s product boundaries. From that familiar baseline, you can go further, reshaping the UX, embedding AI deeply, and owning the governance.

Here is what that means in practice:

  • Design your own UX and shell Eclipse Theia’s open extension points, frontend and backend, let you compose and replace UI parts. You can embed AI assistants directly in non editor views, Terminal, Explorer, Debug, custom panels, or build proactive AI that observes lifecycle and UI events across the whole application, something extensions in VS Code can’t reliably do.
  • Fully customise your AI chat experience Unlike VS Code’s constrained chat API, Eclipse Theia lets you fully customise the chat view, add custom commands, integrate suggested questions, and design workflows tailored to your users’ needs. Whether you want a branded chat interface, domain specific interaction patterns, or seamless integration with the rest of your workbench, you have complete control.
  • Holistic context collection In Eclipse Theia, you can track multiple editors, recent edits, active tasks, terminal state, debug state, and domain specific artefacts in a single coherent context model. This enables AI that reacts to the full workbench, not just partial signals.
  • Own your AI strategy With Theia AI, you get a framework for LLMs, prompt management, tools agents, and context plumbing. You can integrate AI into commands, code actions, terminal flows, or custom widgets on your terms. You choose the models, cloud, on prem, or local, the data boundaries, and the UX.
  • Full stack extensibility and governance Eclipse Theia runs VS Code extensions and integrates with Open VSX for distribution, but you can also curate your own registry and policies. You define your update cadence, telemetry policy, and model endpoints, free from single vendor control. Open VSX Registry: https://open-vsx.org
  • Proof in production Arduino IDE 2.0 is one example of a deeply customised Eclipse Theia based product, not a VS Code fork, used by millions of developers worldwide. For a broader overview, see the active ecosystem of Eclipse Theia adopters: https://www.eclipse.org/topics/ide/articles/the-active-ecosystem-of-eclipse-theia-adopters/

In short: the feature classes that routinely force teams to fork VS Code, proactive AI, AI embedded everywhere, holistic context, and governance control, are first class capabilities in Eclipse Theia.

🏛️ Why it matters that this lives at the Eclipse Foundation

This is not just a technical choice. It is also about governance.

Eclipse Theia and Open VSX are hosted by the Eclipse Foundation, which means vendor neutral governance, transparent IP management, and community driven roadmaps. For adopters, that reduces the risk of policy shifts by a single commercial actor, especially when you are building a product that might compete with capabilities bundled into VS Code itself. The ecosystem benefits from shared maintenance, shared innovation, and a predictable governance model. Open VSX is an Eclipse open source project operated by the Eclipse Foundation: https://open-vsx.org

Practically, this lets companies invest in differentiation rather than continuously rebasing a fork, while still staying close to the VS Code user experience when that is valuable.

🔒 Governance matters, especially when your competitor runs the store

If your product competes with Copilot or with VS Code itself, you’re essentially forking a competitor’s flagship and hoping their policies won’t shift under you. We’ve argued before that open is not open enough when governance and distribution are controlled by a single vendor. The Eclipse community’s answer is open tech and open governance.

With Eclipse Theia, you’re not alone. You become part of an active ecosystem where multiple adopters share common maintenance costs and collectively benefit from platform innovations. Generic improvements, new IDE features, AI framework enhancements, security updates, are developed once and shared across the entire community. You invest in differentiation, not in reinventing the wheel or constantly rebasing a fork.

📚 Further reading

✨ One last thought

Cursor, Windsurf, and others have shown what AI can feel like in an editor. The next winners will show what AI can feel like in a seamless product. If that’s your goal, don’t start by forking your competitor’s product. Start on a platform designed for you.

Theia platform: start here https://theia-ide.org/theia-platform/

Thomas Froment


Hashtag Jakarta EE #310

Hashtag Jakarta EE #310

Welcome to issue number three hundred and ten of Hashtag Jakarta EE!

The conference year is getting closer to the end. Last week, I was in Ottawa for JakartaOne Livestream 2025 and next week I will go to Paris to speak at the Paris JUG as well as attend Open Source Experience while I am there. These will be the last events for me in 2025, but as you can see on my list of events, I have quite a few lined up for the beginning of 2026. I update the list continuously, so make sure to check it out if you want to meet up at an event or possibly schedule me for your JUG or conference.

One of the talks at this year’s JakartaOne Livestream that caught my attention was about Eclipse Tradista by Olivier Asuncion. Eclipse Tradista is a risk management solution for the financial sector built with Jakarta EE. It is an excellent example of the benefits of Jakarta EE for applications build with a modular architecture.

The Jakarta EE Platform project didn’t meet last week due to JakartaOne Livestream, so I don’t have much to report on regarding Jakarta EE 12. Make sure to join the last two platform calls of the year on December 9 and 16. See details in the Jakarta EE Specifications calendar.

Ivar Grimstad


JakartaOne Livestream 2025

JakartaOne Livestream 2025

JakartaOne Livestream 2025 is a wrap! This was the seventh time we did the livestream, so we are getting used to it. This year we also had a professional production crew helping us out, and we also chose to switch platforms to stream on YouTube rather than what we have been using previous years.

The Livestream lasts for almost 12 hours, so it is a very long day. But also a lot of fun. Being together with the team in Ottawa these days in the beginning of December has become a nice pre-holiday tradition for us. Make sure to check out the recording of the show if you missed some of the talks, or weren’t able to follow it live.

Ivar Grimstad


Hashtag Jakarta EE #309

Hashtag Jakarta EE #309

Welcome to issue number three hundred and nine of Hashtag Jakarta EE!

I am currently in Ottawa with Tanja and Shabnam preparing JakartaOne Livestream 2025. This is the seventh edition of JakartaOne Livestream, so you would assume we know what to do at this point. Which I guess we do.

As previous years, I will be in Studio Jakarta EE with Shabnam and Tanja between the talks as hosts of the show. Check it out and make sure to register for the event so you have it in your calendar. And I hope to see as many as possible of you on Tuesday.

The last week, there was a ballot in the Jakarta EE Specification committee for a resolution about allowing the use of other namespaces, such as org.eclipse.microprofile, for Jakarta EE specifications. The resolution was voted down with 7 negative and only 3 positive votes. This was also the situation for the non-binding community votes which ended with 4 negative and only 1 positive vote. This result shows that the Jakarta EE Working group members and the community values the consistency of the Jakarta EE brand.

Ivar Grimstad


Support open source this Giving Tuesday: Help sustain the technologies you use every day

Support open source this Giving Tuesday: Help sustain the technologies you use every day

For more than a decade, Giving Tuesday has been a global day of generosity, a day when people come together to give, collaborate, and this year, the Eclipse Foundation is proud to participate by highlighting widely used open source software that powers your digital life.

Open source technologies, from developer tools to infrastructure powering global industries, form the backbone of modern innovation. Yet, this vital ecosystem doesn’t sustain itself. It requires continuous investment in services, security, compliance, and community development

This Giving Tuesday (2 December), we are inviting everyone who benefits from open source, developers, enterprises, startups, students, researchers, and tech enthusiasts, to give back to the tools that have supported your work all year  

Your 1€ makes a difference: Here is why.

Imagine this: The most-used Eclipse Foundation projects receive millions of downloads every single day. If we could get just €1 per download this Giving Tuesday, we could secure and sustain these essential technologies for years to come.

 

Your contribution is direct and meaningful: 

Your gift helps ensure the securityinnovation, and longevity of widely used open source projects. This Giving Tuesday, you can directly support the tools that have supported your work all year.

Don’t wait. Become a sponsor today: Support open source now!

Join a global movement

When you become a sponsor, you’re joining a worldwide network of people committed to keeping open source secure, innovative, and accessible. Your support helps maintain the tools and technologies that developers rely on year-round.

Flexible Giving, Real Impact: 

  • No minimum commitment:  Every contribution, big or small, has a real and lasting impact.
  • Global access with multicurrency options: With flexible giving options in multiple currencies, contributors from around the world can easily support the projects they depend on.

Whether you choose a one-time gift or set up recurring support, your sponsorship directly helps maintain the technologies that keep the digital ecosystem moving forward.

 Three Ways to Give Back This Giving Tuesday

  1. Become a sponsor today Make a one-time or recurring donation to directly support our infrastructure and services.
  2. Learn more about our sponsorship programUnderstand the full scope of our work and where your support goes.
  3. Share the Message: Help us spread the word on social media and tag the Eclipse Foundation.

Thank you for helping keep open source strong, secure, and thriving for everyone.

Carmen Delgado


State, Logic, And Native Power: CSS Wrapped 2025

If I were to divide CSS evolutions into categories, we have moved far beyond the days when we simply asked for border-radius to feel like we were living in the future. We are currently living in a moment where the platform is handing us tools that don’t just tweak the visual layer, but fundamentally redefine how we architect interfaces. I thought the number of features announced in 2024 couldn’t be topped. I’ve never been so happily wrong.

The Chrome team’s “CSS Wrapped 2025” is not just a list of features; it is a manifesto for a dynamic, native web. As someone who has spent a couple of years documenting these evolutions — from defining “CSS5” eras to the intricacies of modern layout utilities — I find myself looking at this year’s wrap-up with a huge sense of excitement. We are seeing a shift towards “Optimized Ergonomics” and “Next-gen interactions” that allow us to stop fighting the code and start sculpting interfaces in their natural state.

In this article, you can find a comprehensive look at the standout features from Chrome’s report, viewed through the lens of my recent experiments and hopes for the future of the platform.

The Component Revolution: Finally, A Native Customizable Select

For years, we have relied on heavy JavaScript libraries to style dropdowns, a “decades-old problem” that the platform has finally solved. As I detailed in my deep dive into the history of the customizable select (and related articles), this has been a long road involving Open UI, bikeshedding names like <selectmenu> and <selectlist>, and finally landing on a solution that re-uses the existing <select> element.

The introduction of appearance: base-select is a strong foundation. It allows us to fully customize the <select> element — including the button and the dropdown list (via ::picker(select)) — using standard CSS. Crucially, this is built with progressive enhancement in mind. By wrapping our styles in a feature query, we ensure a seamless experience across all browsers.

We can opt in to this new behavior without breaking older browsers:

select {
  /* Opt-in for the new customizable select */
  @supports (appearance: base-select) {
    &, &::picker(select) {
      appearance: base-select;
    }
  }
}

The fantastic addition to allow rich content inside options, such as images or flags, is a lot of fun. We can create all sorts of selects nowadays:

  • Demo: I created a Poké-adventure demo showing how the new <selectedcontent> element can clone rich content (like a Pokéball icon) from an option directly into the button.

See the Pen A customizable select with images inside of the options and the selectedcontent [forked] by utilitybend.

See the Pen A customizable select with only pseudo-elements [forked] by utilitybend.

See the Pen An actual Select Menu with optgroups [forked] by utilitybend.

This feature alone signals a massive shift in how we will build forms, reducing dependencies and technical debt.

Scroll Markers And The Death Of The JavaScript Carousel

Creating carousels has historically been a friction point between developers and clients. Clients love them, developers dread the JavaScript required to make them accessible and performant. The arrival of ::scroll-marker and ::scroll-button() pseudo-elements changes this dynamic entirely.

These features allow us to create navigation dots and scroll buttons purely with CSS, linked natively to the scroll container. As I wrote on my blog, this was Love at first slide. The ability to create a fully functional, accessible slider without a single line of JavaScript is not just convenient; it is a triumph for performance. There were some accessibility concerns around this feature, and even though these were really valid, I’m sure it’s up to us developers to make it work. The good thing is, all these UI changes are making it a lot easier than custom DOM manipulation and dragging around aria tags, but I digress…

We can now group markers automatically using scroll-marker-group and style the buttons using anchor positioning to place them exactly where we want.

.carousel {
  overflow-x: auto;
  scroll-marker-group: after; /* Creates the container for dots */

  /* Create the buttons */
  &::scroll-button(inline-end),
  &::scroll-button(inline-start) {
    content: " ";
    position: absolute;
    /* Use anchor positioning to center them */
    position-anchor: --carousel;
    top: anchor(center);
  }

  /* Create the markers on the children */
  div {
    &::scroll-marker {
      content: " ";
      width: 24px;
      border-radius: 50%;
      cursor: pointer;
    }
    /* Highlight the active marker */
    &::scroll-marker:target-current {
      background: white;
    }
  }
}

See the Pen Carousel Pure HTML and CSS [forked] by utilitybend.

See the Pen Webshop slick slider remake in CSS [forked] by utilitybend.

State Queries: Sticky Thing Stuck? Snappy Thing Snapped?

For a long time, we have lacked the ability to know if a “sticky thing is stuck” or if a “snappy item is snapped” without relying on IntersectionObserver hacks. Chrome 133 introduced scroll-state queries, allowing us to query these states declaratively.

By setting container-type: scroll-state, we can now style children based on whether they are stuck, snapped, or overflowing. This is a massive “quality of life” improvement that I have been eagerly waiting for since CSS Day 2023. It has even evolved a lot since we can also see the direction of the scroll, lovely!

For a simple example: we can finally apply a shadow to a header only when it is actually sticking to the top of the viewport:

.header-container {
  container-type: scroll-state;
  position: sticky;
  top: 0;

  header {
    transition: box-shadow 0.5s ease-out;
    /* The query checks the state of the container */
    @container scroll-state(stuck: top) {
      box-shadow: rgba(0, 0, 0, 0.6) 0px 12px 28px 0px;
    }
  }
}
  • Demo: A sticky header that only applies a shadow when it is actually stuck.

See the Pen Sticky headers with scroll-state query, checking if the sticky element is stuck [forked] by utilitybend.

  • Demo: A Pokémon-themed list that uses scroll-state queries combined with anchor positioning to move a frame over the currently snapped character.

See the Pen Scroll-state query to check which item is snapped with CSS, Pokemon version [forked] by utilitybend.

Optimized Ergonomics: Logic In CSS

The “Optimized Ergonomics” section of CSS Wrapped highlights features that make our workflows more intuitive. Three features stand out as transformative for how we write logic:

  1. if() Statements
    We are finally getting conditionals in CSS. The if() function acts like a ternary operator for stylesheets, allowing us to apply values based on media, support, or style queries inline. This reduces the need for verbose @media blocks for single property changes.
  2. @function functions
    We can finally move some logic to a different place, resulting in some cleaner files, a real quality of life feature.
  3. sibling-index() and sibling-count()
    These tree-counting functions solve the issue of staggering animations or styling items based on list size. As I explored in Styling siblings with CSS has never been easier, this eliminates the need to hard-code custom properties (like --index: 1) in our HTML.

Example: Calculating Layouts

We can now write concise mathematical formulas. For example, staggering an animation for cards entering the screen becomes trivial:

.card-container > * {
  animation: reveal 0.6s ease-out forwards;
  /* No more manual --index variables! */
  animation-delay: calc(sibling-index() * 0.1s);
}

I even experimented with using these functions along with trigonometry to place items in a perfect circle without any JavaScript.

See the Pen Stagger cards using sibling-index() [forked] by utilitybend.

  • Demo: Placing items in a perfect circle using sibling-index, sibling-count, and the new CSS @function feature.

See the Pen The circle using sibling-index, sibling-count and functions [forked] by utilitybend.

My CSS To-Do List: Features I Can’t Wait To Try

While I have been busy sculpting selects and transitions, the “CSS Wrapped 2025” report is packed with other goodies that I haven’t had the chance to fire up in CodePen yet. These are high on my list for my next experiments:

Anchored Container Queries

I used CSS Anchor Positioning for the buttons in my carousel demo, but “CSS Wrapped” highlights an evolution of this: Anchored Container Queries. This solves a problem we’ve all had with tooltips: if the browser flips the tooltip from top to bottom because of space constraints, the “arrow” often stays pointing the wrong way. With anchored container queries (@container anchored(fallback: flip-block)), we can style the element based on which fallback position the browser actually chose.

Nested View Transition Groups

View Transitions have been a revolution, but they came with a specific trade-off: they flattened the element tree, which often broke 3D transforms or overflow: clip. I always had a feeling that it was missing something, and this might just be the answer. By using view-transition-group: nearest, we can finally nest transition groups within each other.

This allows us to maintain clipping effects or 3D rotations during a transition — something that was previously impossible because the elements were hoisted up to the top level.

.card img {
  view-transition-name: photo;
  view-transition-group: nearest; /* Keep it nested! */
}

Typography and Shapes

Finally, the ergonomist in me is itching to try Text Box Trim, which promises to remove that annoying extra whitespace above and below text content (the leading) to finally achieve perfect vertical alignment. And for the creative side, corner-shape and the shape() function are opening up non-rectangular layouts, allowing for “squaricles” and complex paths that respond to CSS variables. That being said, I can’t wait to have a design full of squircles!

A Hopeful Future

We are witnessing a world where CSS is becoming capable of handling logic, state, and complex interactions that previously belonged to JavaScript. Features like moveBefore (preserving DOM state for iframes/videos) and attr() (using types beyond strings for colors and grids) further cement this reality.

While some of these features are currently experimental or specific to Chrome, the momentum is undeniable. We must hope for continued support across all browsers through initiatives like Interop to ensure these capabilities become the baseline. That being said, having browser engines is just as important as having all these awesome features in “Chrome first”. These new features need to be discussed, tinkered with, and tested before ever landing in browsers.

It is a fantastic moment to get into CSS. We are no longer just styling documents; we are crafting dynamic, ergonomic, and robust applications with a native toolkit that is more powerful than ever.

Let’s get going with this new era and spread the word.

This is CSS Wrapped!

Beyond The Black Box: Practical XAI For UX Practitioners

In my last piece, we established a foundational truth: for users to adopt and rely on AI, they must trust it. We talked about trust being a multifaceted construct, built on perceptions of an AI’s Ability, Benevolence, Integrity, and Predictability. But what happens when an AI, in its silent, algorithmic wisdom, makes a decision that leaves a user confused, frustrated, or even hurt? A mortgage application is denied, a favorite song is suddenly absent from a playlist, and a qualified resume is rejected before a human ever sees it. In these moments, ability and predictability are shattered, and benevolence feels a world away.

Our conversation now must evolve from the why of trust to the how of transparency. The field of Explainable AI (XAI), which focuses on developing methods to make AI outputs understandable to humans, has emerged to address this, but it’s often framed as a purely technical challenge for data scientists. I argue it’s a critical design challenge for products relying on AI. It’s our job as UX professionals to bridge the gap between algorithmic decision-making and human understanding.

This article provides practical, actionable guidance on how to research and design for explainability. We’ll move beyond the buzzwords and into the mockups, translating complex XAI concepts into concrete design patterns you can start using today.

De-mystifying XAI: Core Concepts For UX Practitioners

XAI is about answering the user’s question: “Why?” Why was I shown this ad? Why is this movie recommended to me? Why was my request denied? Think of it as the AI showing its work on a math problem. Without it, you just have an answer, and you’re forced to take it on faith. In showing the steps, you build comprehension and trust. You also allow for your work to be double-checked and verified by the very humans it impacts.

Feature Importance And Counterfactuals

There are a number of techniques we can use to clarify or explain what is happening with AI. While methods range from providing the entire logic of a decision tree to generating natural language summaries of an output, two of the most practical and impactful types of information UX practitioners can introduce into an experience are feature importance (Figure 1) and counterfactuals. These are often the most straightforward for users to understand and the most actionable for designers to implement.

Feature Importance

This explainability method answers, “What were the most important factors the AI considered?” It’s about identifying the top 2-3 variables that had the biggest impact on the outcome. It’s the headline, not the whole story.

Example: Imagine an AI that predicts whether a customer will churn (cancel their service). Feature importance might reveal that “number of support calls in the last month” and “recent price increases” were the two most important factors in determining if a customer was likely to churn.

Counterfactuals

This powerful method answers, “What would I need to change to get a different outcome?” This is crucial because it gives users a sense of agency. It transforms a frustrating “no” into an actionable “not yet.”

Example: Imagine a loan application system that uses AI. A user is denied a loan. Instead of just seeing “Application Denied,” a counterfactual explanation would also share, “If your credit score were 50 points higher, or if your debt-to-income ratio were 10% lower, your loan would have been approved.” This gives Sarah clear, actionable steps she can take to potentially get a loan in the future.

Using Model Data To Enhance The Explanation

Although technical specifics are often handled by data scientists, it’s helpful for UX practitioners to know that tools like LIME (Local Interpretable Model-agnostic Explanations) which explains individual predictions by approximating the model locally, and SHAP (SHapley Additive exPlanations) which uses a game theory approach to explain the output of any machine learning model are commonly used to extract these “why” insights from complex models. These libraries essentially help break down an AI’s decision to show which inputs were most influential for a given outcome.

When done properly, the data underlying an AI tool’s decision can be used to tell a powerful story. Let’s walk through feature importance and counterfactuals and show how the data science behind the decision can be utilized to enhance the user’s experience.

Now let’s cover feature importance with the assistance of Local Explanations (e.g., LIME) data: This approach answers, “Why did the AI make this specific recommendation for me, right now?” Instead of a general explanation of how the model works, it provides a focused reason for a single, specific instance. It’s personal and contextual.

Example: Imagine an AI-powered music recommendation system like Spotify. A local explanation would answer, “Why did the system recommend this specific song by Adele to you right now?” The explanation might be: “Because you recently listened to several other emotional ballads and songs by female vocalists.”

Finally, let’s cover the inclusion of Value-based Explanations (e.g. Shapley Additive Explanations (SHAP) data to an explanation of a decision: This is a more nuanced version of feature importance that answers, “How did each factor push the decision one way or the other?” It helps visualize what mattered, and whether its influence was positive or negative.

Example: Imagine a bank uses an AI model to decide whether to approve a loan application.

Feature Importance: The model output might show that the applicant’s credit score, income, and debt-to-income ratio were the most important factors in its decision. This answers what mattered.

Feature Importance with Value-Based Explanations (SHAP): SHAP values would take feature importance further based on elements of the model.

  • For an approved loan, SHAP might show that a high credit score significantly pushed the decision towards approval (positive influence), while a slightly higher-than-average debt-to-income ratio pulled it slightly away (negative influence), but not enough to deny the loan.
  • For a denied loan, SHAP could reveal that a low income and a high number of recent credit inquiries strongly pushed the decision towards denial, even if the credit score was decent.

This helps the loan officer explain to the applicant beyond what was considered, to how each factor contributed to the final “yes” or “no” decision.

It’s crucial to recognize that the ability to provide good explanations often starts much earlier in the development cycle. Data scientists and engineers play a pivotal role by intentionally structuring models and data pipelines in ways that inherently support explainability, rather than trying to bolt it on as an afterthought.

Research and design teams can foster this by initiating early conversations with data scientists and engineers about user needs for understanding, contributing to the development of explainability metrics, and collaboratively prototyping explanations to ensure they are both accurate and user-friendly.

XAI And Ethical AI: Unpacking Bias And Responsibility

Beyond building trust, XAI plays a critical role in addressing the profound ethical implications of AI*, particularly concerning algorithmic bias. Explainability techniques, such as analyzing SHAP values, can reveal if a model’s decisions are disproportionately influenced by sensitive attributes like race, gender, or socioeconomic status, even if these factors were not explicitly used as direct inputs.

For instance, if a loan approval model consistently assigns negative SHAP values to applicants from a certain demographic, it signals a potential bias that needs investigation, empowering teams to surface and mitigate such unfair outcomes.

The power of XAI also comes with the potential for “explainability washing.” Just as “greenwashing” misleads consumers about environmental practices, explainability washing can occur when explanations are designed to obscure, rather than illuminate, problematic algorithmic behavior or inherent biases. This could manifest as overly simplistic explanations that omit critical influencing factors, or explanations that strategically frame results to appear more neutral or fair than they truly are. It underscores the ethical responsibility of UX practitioners to design explanations that are genuinely transparent and verifiable.

UX professionals, in collaboration with data scientists and ethicists, hold a crucial responsibility in communicating the why of a decision, and also the limitations and potential biases of the underlying AI model. This involves setting realistic user expectations about AI accuracy, identifying where the model might be less reliable, and providing clear channels for recourse or feedback when users perceive unfair or incorrect outcomes. Proactively addressing these ethical dimensions will allow us to build AI systems that are truly just and trustworthy.

From Methods To Mockups: Practical XAI Design Patterns

Knowing the concepts is one thing; designing them is another. Here’s how we can translate these XAI methods into intuitive design patterns.

Pattern 1: The “Because” Statement (for Feature Importance)

This is the simplest and often most effective pattern. It’s a direct, plain-language statement that surfaces the primary reason for an AI’s action.

  • Heuristic: Be direct and concise. Lead with the single most impactful reason. Avoid jargon at all costs.

Example: Imagine a music streaming service. Instead of just presenting a “Discover Weekly” playlist, you add a small line of microcopy.

Song Recommendation: “Velvet Morning”
Because you listen to “The Fuzz” and other psychedelic rock.

Pattern 2: The “What-If” Interactive (for Counterfactuals)

Counterfactuals are inherently about empowerment. The best way to represent them is by giving users interactive tools to explore possibilities themselves. This is perfect for financial, health, or other goal-oriented applications.

  • Heuristic: Make explanations interactive and empowering. Let users see the cause and effect of their choices.

Example: A loan application interface. After a denial, instead of a dead end, the user gets a tool to determine how various scenarios (what-ifs) might play out (See Figure 1).

Pattern 3: The Highlight Reel (For Local Explanations)

When an AI performs an action on a user’s content (like summarizing a document or identifying faces in photos), the explanation should be visually linked to the source.

  • Heuristic: Use visual cues like highlighting, outlines, or annotations to connect the explanation directly to the interface element it’s explaining.

Example: An AI tool that summarizes long articles.

AI-Generated Summary Point:
Initial research showed a market gap for sustainable products.

Source in Document:
“…Our Q2 analysis of market trends conclusively demonstrated that no major competitor was effectively serving the eco-conscious consumer, revealing a significant market gap for sustainable products…”

Pattern 4: The Push-and-Pull Visual (for Value-based Explanations)

For more complex decisions, users might need to understand the interplay of factors. Simple data visualizations can make this clear without being overwhelming.

  • Heuristic: Use simple, color-coded data visualizations (like bar charts) to show the factors that positively and negatively influenced a decision.

Example: An AI screening a candidate’s profile for a job.

Why this candidate is a 75% match:

Factors pushing the score up:

  • 5+ Years UX Research Experience
  • Proficient in Python

Factors pushing the score down:

  • No experience with B2B SaaS

Learning and using these design patterns in the UX of your AI product will help increase the explainability. You can also use additional techniques that I’m not covering in-depth here. This includes the following:

  • Natural language explanations: Translating an AI’s technical output into simple, conversational human language that non-experts can easily understand.
  • Contextual explanations: Providing a rationale for an AI’s output at the specific moment and location, it is most relevant to the user’s task.
  • Relevant visualizations: Using charts, graphs, or heatmaps to visually represent an AI’s decision-making process, making complex data intuitive and easier for users to grasp.

A Note For the Front End: Translating these explainability outputs into seamless user experiences also presents its own set of technical considerations. Front-end developers often grapple with API design to efficiently retrieve explanation data, and performance implications (like the real-time generation of explanations for every user interaction) need careful planning to avoid latency.

Some Real-world Examples

UPS Capital’s DeliveryDefense

UPS uses AI to assign a “delivery confidence score” to addresses to predict the likelihood of a package being stolen. Their DeliveryDefense software analyzes historical data on location, loss frequency, and other factors. If an address has a low score, the system can proactively reroute the package to a secure UPS Access Point, providing an explanation for the decision (e.g., “Package rerouted to a secure location due to a history of theft”). This system demonstrates how XAI can be used for risk mitigation and building customer trust through transparency.

Autonomous Vehicles

These vehicles of the future will need to effectively use XAI to help their vehicles make safe, explainable decisions. When a self-driving car brakes suddenly, the system can provide a real-time explanation for its action, for example, by identifying a pedestrian stepping into the road. This is not only crucial for passenger comfort and trust but is a regulatory requirement to prove the safety and accountability of the AI system.

IBM Watson Health (and its challenges)

While often cited as a general example of AI in healthcare, it’s also a valuable case study for the importance of XAI. The failure of its Watson for Oncology project highlights what can go wrong when explanations are not clear, or when the underlying data is biased or not localized. The system’s recommendations were sometimes inconsistent with local clinical practices because they were based on U.S.-centric guidelines. This serves as a cautionary tale on the need for robust, context-aware explainability.

The UX Researcher’s Role: Pinpointing And Validating Explanations

Our design solutions are only effective if they address the right user questions at the right time. An explanation that answers a question the user doesn’t have is just noise. This is where UX research becomes the critical connective tissue in an XAI strategy, ensuring that we explain the what and how that actually matters to our users. The researcher’s role is twofold: first, to inform the strategy by identifying where explanations are needed, and second, to validate the designs that deliver those explanations.

Informing the XAI Strategy (What to Explain)

Before we can design a single explanation, we must understand the user’s mental model of the AI system. What do they believe it’s doing? Where are the gaps between their understanding and the system’s reality? This is the foundational work of a UX researcher.

Mental Model Interviews: Unpacking User Perceptions Of AI Systems

Through deep, semi-structured interviews, UX practitioners can gain invaluable insights into how users perceive and understand AI systems. These sessions are designed to encourage users to literally draw or describe their internal “mental model” of how they believe the AI works. This often involves asking open-ended questions that prompt users to explain the system’s logic, its inputs, and its outputs, as well as the relationships between these elements.

These interviews are powerful because they frequently reveal profound misconceptions and assumptions that users hold about AI. For example, a user interacting with a recommendation engine might confidently assert that the system is based purely on their past viewing history. They might not realize that the algorithm also incorporates a multitude of other factors, such as the time of day they are browsing, the current trending items across the platform, or even the viewing habits of similar users.

Uncovering this gap between a user’s mental model and the actual underlying AI logic is critically important. It tells us precisely what specific information we need to communicate to users to help them build a more accurate and robust mental model of the system. This, in turn, is a fundamental step in fostering trust. When users understand, even at a high level, how an AI arrives at its conclusions or recommendations, they are more likely to trust its outputs and rely on its functionality.

AI Journey Mapping: A Deep Dive Into User Trust And Explainability

By meticulously mapping the user’s journey with an AI-powered feature, we gain invaluable insights into the precise moments where confusion, frustration, or even profound distrust emerge. This uncovers critical junctures where the user’s mental model of how the AI operates clashes with its actual behavior.

Consider a music streaming service: Does the user’s trust plummet when a playlist recommendation feels “random,” lacking any discernible connection to their past listening habits or stated preferences? This perceived randomness is a direct challenge to the user’s expectation of intelligent curation and a breach of the implicit promise that the AI understands their taste. Similarly, in a photo management application, do users experience significant frustration when an AI photo-tagging feature consistently misidentifies a cherished family member? This error is more than a technical glitch; it strikes at the heart of accuracy, personalization, and even emotional connection.

These pain points are vivid signals indicating precisely where a well-placed, clear, and concise explanation is necessary. Such explanations serve as crucial repair mechanisms, mending a breach of trust that, if left unaddressed, can lead to user abandonment.

The power of AI journey mapping lies in its ability to move us beyond simply explaining the final output of an AI system. While understanding what the AI produced is important, it’s often insufficient. Instead, this process compels us to focus on explaining the process at critical moments. This means addressing:

  • Why a particular output was generated: Was it due to specific input data? A particular model architecture?
  • What factors influenced the AI’s decision: Were certain features weighted more heavily?
  • How the AI arrived at its conclusion: Can we offer a simplified, analogous explanation of its internal workings?
  • What assumptions the AI made: Were there implicit understandings of the user’s intent or data that need to be surfaced?
  • What the limitations of the AI are: Clearly communicating what the AI cannot do, or where its accuracy might waver, builds realistic expectations.

AI journey mapping transforms the abstract concept of XAI into a practical, actionable framework for UX practitioners. It enables us to move beyond theoretical discussions of explainability and instead pinpoint the exact moments where user trust is at stake, providing the necessary insights to build AI experiences that are powerful, transparent, understandable, and trustworthy.

Ultimately, research is how we uncover the unknowns. Your team might be debating how to explain why a loan was denied, but research might reveal that users are far more concerned with understanding how their data was used in the first place. Without research, we are simply guessing what our users are wondering.

Collaborating On The Design (How to Explain Your AI)

Once research has identified what to explain, the collaborative loop with design begins. Designers can prototype the patterns we discussed earlier—the “Because” statement, the interactive sliders—and researchers can put those designs in front of users to see if they hold up.

Targeted Usability & Comprehension Testing: We can design research studies that specifically test the XAI components. We don’t just ask, “Is this easy to use?” We ask, “After seeing this, can you tell me in your own words why the system recommended this product?” or “Show me what you would do to see if you could get a different result.” The goal here is to measure comprehension and actionability, alongside usability.

Measuring Trust Itself: We can use simple surveys and rating scales before and after an explanation is shown. For instance, we can ask a user on a 5-point scale, “How much do you trust this recommendation?” before they see the “Because” statement, and then ask them again afterward. This provides quantitative data on whether our explanations are actually moving the needle on trust.

This process creates a powerful, iterative loop. Research findings inform the initial design. That design is then tested, and the new findings are fed back to the design team for refinement. Maybe the “Because” statement was too jargony, or the “What-If” slider was more confusing than empowering. Through this collaborative validation, we ensure that the final explanations are technically accurate, genuinely understandable, useful, and trust-building for the people using the product.

The Goldilocks Zone Of Explanation

A critical word of caution: it is possible to over-explain. As in the fairy tale, where Goldilocks sought the porridge that was ‘just right’, the goal of a good explanation is to provide the right amount of detail—not too much and not too little. Bombarding a user with every variable in a model will lead to cognitive overload and can actually decrease trust. The goal is not to make the user a data scientist.

One solution is progressive disclosure.

  1. Start with the simple. Lead with a concise “Because” statement. For most users, this will be enough.
  2. Offer a path to detail. Provide a clear, low-friction link like “Learn More” or “See how this was determined.”
  3. Reveal the complexity. Behind that link, you can offer the interactive sliders, the visualizations, or a more detailed list of contributing factors.

This layered approach respects user attention and expertise, providing just the right amount of information for their needs. Let’s imagine you’re using a smart home device that recommends optimal heating based on various factors.

Start with the simple: “Your home is currently heated to 72 degrees, which is the optimal temperature for energy savings and comfort.

Offer a path to detail: Below that, a small link or button: “Why is 72 degrees optimal?

Reveal the complexity: Clicking that link could open a new screen showing:

  • Interactive sliders for outside temperature, humidity, and your preferred comfort level, demonstrating how these adjust the recommended temperature.
  • A visualization of energy consumption at different temperatures.
  • A list of contributing factors like “Time of day,” “Current outside temperature,” “Historical energy usage,” and “Occupancy sensors.”

It’s effective to combine multiple XAI methods and this Goldilocks Zone of Explanation pattern, which advocates for progressive disclosure, implicitly encourages this. You might start with a simple “Because” statement (Pattern 1) for immediate comprehension, and then offer a “Learn More” link that reveals a “What-If” Interactive (Pattern 2) or a “Push-and-Pull Visual” (Pattern 4) for deeper exploration.

For instance, a loan application system could initially state the primary reason for denial (feature importance), then allow the user to interact with a “What-If” tool to see how changes to their income or debt would alter the outcome (counterfactuals), and finally, provide a detailed “Push-and-Pull” chart (value-based explanation) to illustrate the positive and negative contributions of all factors. This layered approach allows users to access the level of detail they need, when they need it, preventing cognitive overload while still providing comprehensive transparency.

Determining which XAI tools and methods to use is primarily a function of thorough UX research. Mental model interviews and AI journey mapping are crucial for pinpointing user needs and pain points related to AI understanding and trust. Mental model interviews help uncover user misconceptions about how the AI works, indicating areas where fundamental explanations (like feature importance or local explanations) are needed. AI journey mapping, on the other hand, identifies critical moments of confusion or distrust in the user’s interaction with the AI, signaling where more granular or interactive explanations (like counterfactuals or value-based explanations) would be most beneficial to rebuild trust and provide agency.

Ultimately, the best way to choose a technique is to let user research guide your decisions, ensuring that the explanations you design directly address actual user questions and concerns, rather than simply offering technical details for their own sake.

XAI for Deep Reasoning Agents

Some of the newest AI systems, known as deep reasoning agents, produce an explicit “chain of thought” for every complex task. They do not merely cite sources; they show the logical, step-by-step path they took to arrive at a conclusion. While this transparency provides valuable context, a play-by-play that spans several paragraphs can feel overwhelming to a user simply trying to complete a task.

The principles of XAI, especially the Goldilocks Zone of Explanation, apply directly here. We can curate the journey, using progressive disclosure to show only the final conclusion and the most salient step in the thought process first. Users can then opt in to see the full, detailed, multi-step reasoning when they need to double-check the logic or find a specific fact. This approach respects user attention while preserving the agent’s full transparency.

Next Steps: Empowering Your XAI Journey

Explainability is a fundamental pillar for building trustworthy and effective AI products. For the advanced practitioner looking to drive this change within their organization, the journey extends beyond design patterns into advocacy and continuous learning.

To deepen your understanding and practical application, consider exploring resources like the AI Explainability 360 (AIX360) toolkit from IBM Research or Google’s What-If Tool, which offer interactive ways to explore model behavior and explanations. Engaging with communities like the Responsible AI Forum or specific research groups focused on human-centered AI can provide invaluable insights and collaboration opportunities.

Finally, be an advocate for XAI within your own organization. Frame explainability as a strategic investment. Consider a brief pitch to your leadership or cross-functional teams:

“By investing in XAI, we’ll go beyond building trust; we’ll accelerate user adoption, reduce support costs by empowering users with understanding, and mitigate significant ethical and regulatory risks by exposing potential biases. This is good design and smart business.”

Your voice, grounded in practical understanding, is crucial in bringing AI out of the black box and into a collaborative partnership with users.

How UX Professionals Can Lead AI Strategy

Your senior management is excited about AI. They’ve read the articles, attended the webinars, and seen the demos. They’re convinced that AI will transform your organization, boost productivity, and give you a competitive edge.

Meanwhile, you’re sitting in your UX role wondering what this means for your team, your workflow, and your users. You might even be worried about your job security.

The problem is that the conversation about how AI gets implemented is happening right now, and if you’re not part of it, someone else will decide how it affects your work. That someone probably doesn’t understand user experience, research practices, or the subtle ways poor implementation can damage the very outcomes management hopes to achieve.

You have a choice. You can wait for directives to come down from above, or you can take control of the conversation and lead the AI strategy for your practice.

Why UX Professionals Must Own the AI Conversation

Management sees AI as efficiency gains, cost savings, competitive advantage, and innovation all wrapped up in one buzzword-friendly package. They’re not wrong to be excited. The technology is genuinely impressive and can deliver real value.

But without UX input, AI implementations often fail users in predictable ways:

  • They automate tasks without understanding the judgment calls those tasks require.
  • They optimize for speed while destroying the quality that made your work valuable.

Your expertise positions you perfectly to guide implementation. You understand users, workflows, quality standards, and the gap between what looks impressive in a demo and what actually works in practice.

Use AI Momentum to Advance Your Priorities

Management’s enthusiasm for AI creates an opportunity to advance priorities you’ve been fighting for unsuccessfully. When management is willing to invest in AI, you can connect those long-standing needs to the AI initiative. Position user research as essential for training AI systems on real user needs. Frame usability testing as the validation method that ensures AI-generated solutions actually work.

How AI gets implemented will shape your team’s roles, your users’ experiences, and your organization’s capability to deliver quality digital products.

Your Role Isn’t Disappearing (It’s Evolving)

Yes, AI will automate some of the tasks you currently do. But someone needs to decide which tasks get automated, how they get automated, what guardrails to put in place, and how automated processes fit around real humans doing complex work.

That someone should be you.

Think about what you already do. When you conduct user research, AI might help you transcribe interviews or identify themes. But you’re the one who knows which participant hesitated before answering, which feedback contradicts what you observed in their behavior, and which insights matter most for your specific product and users.

When you design interfaces, AI might generate layout variations or suggest components from your design system. But you’re the one who understands the constraints of your technical platform, the political realities of getting designs approved, and the edge cases that will break a clever solution.

Your future value comes from the work you’re already doing:

  • Seeing the full picture.
    You understand how this feature connects to that workflow, how this user segment differs from that one, and why the technically correct solution won’t work in your organization’s reality.
  • Making judgment calls.
    You decide when to follow the design system and when to break it, when user feedback reflects a real problem versus a feature request from one vocal user, and when to push back on stakeholders versus find a compromise.
  • Connecting the dots.
    You translate between technical constraints and user needs, between business goals and design principles, between what stakeholders ask for and what will actually solve their problem.

AI will keep getting better at individual tasks. But you’re the person who decides which solution actually works for your specific context. The people who will struggle are those doing simple, repeatable work without understanding why. Your value is in understanding context, making judgment calls, and connecting solutions to real problems.

Step 1: Understand Management’s AI Motivations

Before you can lead the conversation, you need to understand what’s driving it. Management is responding to real pressures: cost reduction, competitive pressure, productivity gains, and board expectations.

Speak their language. When you talk to management about AI, frame everything in terms of ROI, risk mitigation, and competitive advantage. “This approach will protect our quality standards” is less compelling than “This approach reduces the risk of damaging our conversion rate while we test AI capabilities.”

Separate hype from reality. Take time to research what AI capabilities actually exist versus what’s hype. Read case studies, try tools yourself, and talk to peers about what’s actually working.

Identify real pain points AI might legitimately address in your organization. Maybe your team spends hours formatting research findings, or accessibility testing creates bottlenecks. These are the problems worth solving.

Step 2: Audit Your Current State and Opportunities

Map your team’s work. Where does time actually go? Look at the past quarter and categorize how your team spent their hours.

Identify high-volume, repeatable tasks versus high-judgment work. Repeatable tasks are candidates for automation. High-judgment work is where you add irreplaceable value.

Also, identify what you’ve wanted to do but couldn’t get approved. This is your opportunity list. Maybe you’ve wanted quarterly usability tests, but only get budget annually. Write these down separately. You’ll connect them to your AI strategy in the next step.

Spot opportunities where AI could genuinely help:

  • Research synthesis: AI can help organize and categorize findings.
  • Analyzing user behavior data: AI can process analytics and session recordings to surface patterns you might miss.
  • Rapid prototyping: AI can quickly generate testable prototypes, speeding up your test cycles.

Step 3: Define AI Principles for Your UX Practice

Before you start forming your strategy, establish principles that will guide every decision.

Set non-negotiables. User privacy, accessibility, and human oversight of significant decisions. Write these down and get agreement from leadership before you pilot anything.

Define criteria for AI use. AI is good at pattern recognition, summarization, and generating variations. AI is poor at understanding context, making ethical judgments, and knowing when rules should be broken.

Define success metrics beyond efficiency. Yes, you want to save time. But you also need to measure quality, user satisfaction, and team capability. Build a balanced scorecard that captures what actually matters.

Create guardrails. Maybe every AI-generated interface needs human review before it ships. These guardrails prevent the obvious disasters and give you space to learn safely.

Step 4: Build Your AI-in-UX Strategy

Now you’re ready to build the actual strategy you’ll pitch to leadership. Start small with pilot projects that have a clear scope and evaluation criteria.

Connect to business outcomes management cares about. Don’t pitch “using AI for research synthesis.” Pitch “reducing time from research to insights by 40%, enabling faster product decisions.”

Piggyback your existing priorities on AI momentum. Remember that opportunity list from Step 2? Now you connect those long-standing needs to your AI strategy. If you’ve wanted more frequent usability testing, explain that AI implementations need continuous validation to catch problems before they scale. AI implementations genuinely benefit from good research practices. You’re simply using management’s enthusiasm for AI as the vehicle to finally get resources for practices that should have been funded all along.

Define roles clearly. Where do humans lead? Where does AI assist? Where won’t you automate? Management needs to understand that some work requires human judgment and should never be fully automated.

Plan for capability building. Your team will need training and new skills. Budget time and resources for this.

Address risks honestly. AI could generate biased recommendations, miss important context, or produce work that looks good but doesn’t actually function. For each risk, explain how you’ll detect it and what you’ll do to mitigate it.

Step 5: Pitch the Strategy to Leadership

Frame your strategy as de-risking management’s AI ambitions, not blocking them. You’re showing them how to implement AI successfully while avoiding the obvious pitfalls.

Lead with outcomes and ROI they care about. Put the business case up front.

Bundle your wish list into the AI strategy. When you present your strategy, include those capabilities you’ve wanted but couldn’t get approved before. Don’t present them as separate requests. Integrate them as essential components. “To validate AI-generated designs, we’ll need to increase our testing frequency from annual to quarterly” sounds much more reasonable than “Can we please do more testing?” You’re explaining what’s required for their AI investment to succeed.

Show quick wins alongside a longer-term vision. Identify one or two pilots that can show value within 30-60 days. Then show them how those pilots build toward bigger changes over the next year.

Ask for what you need. Be specific. You need a budget for tools, time for pilots, access to data, and support for team training.

Step 6: Implement and Demonstrate Value

Run your pilots with clear before-and-after metrics. Measure everything: time saved, quality maintained, user satisfaction, team confidence.

Document wins and learning. Failures are useful too. If a pilot doesn’t work out, document why and what you learned.

Share progress in management’s language. Monthly updates should focus on business outcomes, not technical details. “We’ve reduced research synthesis time by 35% while maintaining quality scores” is the right level of detail.

Build internal advocates by solving real problems. When your AI pilots make someone’s job easier, you create advocates who will support broader adoption.

Iterate based on what works in your specific context. Not every AI application will fit your organization. Pay attention to what’s actually working and double down on that.

Taking Initiative Beats Waiting

AI adoption is happening. The question isn’t whether your organization will use AI, but whether you’ll shape how it gets implemented.

Your UX expertise is exactly what’s needed to implement AI successfully. You understand users, quality, and the gap between impressive demos and useful reality.

Take one practical first step this week. Schedule 30 minutes to map one AI opportunity in your practice. Pick one area where AI might help, think through how you’d pilot it safely, and sketch out what success would look like.

Then start the conversation with your manager. You might be surprised how receptive they are to someone stepping up to lead this.

You know how to understand user needs, test solutions, measure outcomes, and iterate based on evidence. Those skills don’t change just because AI is involved. You’re applying your existing expertise to a new tool.

Your role isn’t disappearing. It’s evolving into something more strategic, more valuable, and more secure. But only if you take the initiative to shape that evolution yourself.

Further Reading On SmashingMag