What Happens When You Give AI Agents the Map of Your Code’s Coverage?

When you ask an AI agent to write a new feature, a good agent will eventually say: “I need to write a test for this.”

But what happens next is usually messy.

To figure out where that new test belongs, the agent has to start searching through your project. It might scan file names, inspect folders, grep for method names, and read file after file just to understand how your tests are organized. That burns through your token limits quickly.

Even worse, in complex .NET solutions where a single production file may be tested across multiple projects or test suites, the agent can still guess wrong. It might put the test in the wrong place, miss the relevant test fixture, or follow a completely different testing style from the one your team already uses.

In the Rider 2026.2 EAP, we’re improving this workflow by teaching AI agents a new skill – one that leverages JetBrains tooling for .NET coverage data to slash your AI expenses in half. 

Why AI agents need more than just code context

AI agents are useful because they can work through multi-step development tasks. They can inspect code, make changes, run tests, react to failures, and iterate.

But even capable agents are only as good as the context they receive.

When an agent needs to add a test, the question is not only: “What should this test assert?” It also needs to know:

  • Where do tests for this code usually live?
  • Which existing tests already exercise nearby code?
  • What testing framework, fixture structure, naming convention, and assertion style does this project use?
  • Is there already a test file that should be extended instead of creating a new one?

A human developer often knows this from experience. An AI agent usually has to discover it the expensive way: by reading the entire project.

That’s where AI agent skills come in.

What are agent skills?

If you’ve been following developments in AI-assisted development, you may have come across the concept of Agent Skills – an open standard introduced by Anthropic to extend AI agent capabilities with specialized knowledge and workflows. You can learn more about agent skills in JetBrains IDEs from this blog post.

In Rider, skills give AI agents access to IDE-native context and workflows. Instead of relying only on generic documentation or asking the model to explore your project manually, a skill can help the agent perform a specific task with information Rider already understands.

You can manage skills in Rider from Settings / Preferences | Tools | AI Assistant | Skills. Skills can be enabled in different scopes depending on how and where you want to use them:

  • IDE scope: Available for all projects and all agents inside the Rider UI. 
  • Global per-agent scope: Available for a specific agent across all projects, including outside the IDE. For example, this can be configured in an agent-specific directory such as ~/.codex.
  • Per-project scope: Available for all agents working with a specific project, including outside the IDE. For example, this can be configured in a project-level .agents directory.
  • Per-project per-agent scope: Available only for a specific agent in a specific project, such as a project-level .codex directory.

Once installed, skills can be used by supported agents automatically when they are relevant to the task. You can also invoke a skill manually in the AI chat by typing / followed by the skill name.

Enter the finding-tests skill

While ecosystems like Microsoft’s dotnet/skills give AI agents generic documentation on how to write .NET tests, they still leave the AI guessing where to put them.

Instead of letting the agent aimlessly search your codebase whenever it needs to write a test, we’ve introduced a new agent skill called finding-tests. It ships in two parts: as a bundled skill for Rider’s AI Assistant, and as a standalone MCP tool (findTests) for use with external agents like Claude Code or Codex.

The bundled skill is enabled by default in Rider’s AI Assistant in the Rider 2026.2 EAP. To use it with an external agent, install the skill in the relevant agent or project scope, then make sure the external client can access Rider via MCP. You can do this from Settings / Preferences | Tools | MCP Server: enable the MCP server, then use Auto-Configure to set up access for the external client.

The idea is simple: Rider already has access to powerful .NET coverage analysis through the bundled dotCover tool,  so when an AI agent needs to understand where a piece of code is tested, it should not have to infer that relationship solely from folder names and search results.

It can just ask Rider.

Rider will then use dotCover coverage data to identify which tests are connected to the code the agent is working on. That turns coverage data into actionable context for AI-generated tests.

Here is what the workflow looks like under the hood:

  1. The agent decides it needs a test. When the AI writes new code, modifies existing behavior, or you explicitly ask it to add test coverage, it can trigger the finding-tests skill.
  2. Rider asks dotCover for coverage context. dotCover runs the tests included in the solution and maps out the coverage data around the code the agent is working with.
  3. The right test location is found. Because Rider can understand which tests already cover nearby code, it can provide the agent with the relevant test file path instead of making the agent discover it manually.
  4. The agent follows your existing test style. The agent goes directly to the correct file, reads the surrounding tests, follows your project’s conventions, and generates a test that fits the existing codebase.

And here’s what the full workflow looks like inside the IDE:

The result: Token costs are halved

This isn’t just a quality-of-life improvement. It has a major impact on your workflow – and your budget.

✂️ Token costs are cut by 50%.

By stopping the AI from wandering needlessly through your project, you’d be saving drastic amounts of money.

In our internal benchmarks (primarily testing with the Claude agent), routing the agent directly to the correct file could cut token consumption by up to 50%. 

Cost comparison across a range of C# test generation cases in real open-source solutions shows that using the finding-tests agent skill with Claude can significantly reduce average AI agent task costs.

The benefit is not just lower AI spend. For teams working with quota-based access or shared AI credit pools, it also means fewer credits wasted on search and exploration. Instead, more of your AI allowance can go toward higher-value development tasks. 

🎯 Correct file, every time

Without coverage data, the agent guesses. In a large codebase where one class might be tested from multiple locations, those guesses are often wrong, resulting in tests dropped in the wrong file, written in a mismatched style, or targeting the wrong test suite entirely.

With finding-tests, the agent has a precise map. No guessing. No wrong file. No style mismatch.

Time vs. tokens

We want to be completely transparent about how this works: this setup trades token expenditure for time. 

To give the AI the exact file path, dotCover has to run a coverage analysis on your solution. For a small or medium project, this might take 30 seconds. But if you are working in a massive codebase, running a full coverage scan could take minutes or even hours.

If you have a release deadline tomorrow, the last thing you want is your IDE suddenly initiating a multi-hour test run. Luckily, the solution is fairly simple.

How to turn it off

Because of this time trade-off, putting you in control is our top priority. The finding-tests skill is bundled and enabled by default in this EAP, but you can disable it or keep it limited to specific projects.

To manage it, go to Settings / Preferences | Tools | AI Assistant | Skills. Find the finding-tests on the panel, and you can inspect the skill, disable it, or use the dropdown to configure it for specific projects.

You can easily re-enable the skill later. 

Known issues

As this is an Early Access Program (EAP), we’re still ironing out a few wrinkles. Here is what you should look out for:

  • First-run hiccups: The finding-tests tool occasionally stumbles or fails on its very first launch. A second attempt usually ensures it is on track.
  • Codex support in the IDE is currently limited: At the moment, bundled skills are not available for Codex inside AI Assistant because of a known issue with the skill bundling mechanism. The AI Assistant team is working on a fix.

Possible workaround: If you want to use finding-tests with Codex, install the skill explicitly in either the global or project scope. This makes the skill available to both external and in-IDE agents.

  • Timeouts on large solutions: Codex and Copilot agents currently time out if a full test run takes longer than 120 seconds. We know real-world solutions can take longer to test, and we’re working on optimizing this pipeline.

    Workaround for Codex: External Codex can mitigate this by increasing the tool timeout in the MCP configuration. Set a larger value for the tool_timeout_sec parameter in the global or project MCP config as per Codex documentation.

  • External agents require MCP setup: To use finding-tests with external agents such as Claude Code or Codex, you’ll need to enable Rider’s MCP server and configure MCP access for the agent.
    Go to Settings / Preferences | Tools | MCP Server, enable the MCP server, and then either auto-configure or manually configure Rider’s MCP server for your agent. After that, install the skill in the agent’s global or project scope.

What’s next on the roadmap

Here’s a sneak peek at where this is heading: if the finding-tests skill proves valuable, our next step will be introducing target coverage – a feature where the AI agent automatically generates enough unit tests to hit a specific, pre-selected percentage of code coverage.

This would let you easily meet mandatory coverage requirements without having to spend extra time manually writing tests. Your feedback on this EAP directly influences whether this feature gets built.

Tell us what you think

This feature is available to all users in the Rider 2026.2 EAP, which gives you a good opportunity to also explore dotCover – our star code coverage tool that normally requires a dotUltimate license – for free. 

Download Rider 2026.2 EAP

For now, we need to know whether this skill works and provides enough benefits for you, and whether there are any edge cases we need to take into account. Try out the new test generation, see how it impacts your workflow, and please let us know whether this skill should remain bundled by default or moved to an optional registry!

The JetBrains Fit Test: Is This the Right Workplace for You?

If you’ve ever wondered what it’s really like to work at JetBrains, this post is for you.

We could tell you about our products, our offices, or the number of developers who use our tools, but the truth is, the real story of JetBrains is about the people who build those tools, the way they think, and what drives them.

This isn’t a traditional “why you should join us” piece. It’s more of a fit test – a look inside the mindset, values, and rhythm that shape daily life here. Because we believe that finding the right workplace isn’t just about skills, it’s about resonance. It’s about whether you’ll feel at home with our way of working.

So let’s see if you do, together. At JetBrains, everything we do is shaped by a few simple yet powerful ideas; these principles guide how we build, grow, and work as a team.

Built by developers, for developers – and everyone who shares that mindset

JetBrains was founded by developers who wanted to make software creation more productive, logical, and human-focused. “By developers, for developers” isn’t just a slogan. It defines how all of our teams think and build – not just our engineers.

We create tools we use ourselves. We test them on real projects, feel the same pain points our users do, and fix what doesn’t work. Something that’s know also as dogfooding.

This constant loop of using, improving, and learning keeps us close to the people we build for.

And while our roots are in software development, this mindset goes far beyond code – it’s shared by designers, marketers, recruiters, writers, and every JetBrainer who approaches their craft with the same curiosity, precision, and care.

“Every feature, every product we create is made with love for people like us, people who care about doing things right”,

as our CEO, Kirill Skrygan, put it.

That closeness to our users also explains our independence. We’re privately owned, and that’s deliberate. Without external investors, we can focus on real value instead of chasing hype or short-term profit. It’s what allows us to take our time, build with care, and stay loyal to our craft.

If that kind of depth and autonomy excites you, you’ll probably feel right at home here.

The relentless pursuit of getting it right

We care deeply about details. When you build tools for some of the smartest and most demanding users in the world, “good enough” simply isn’t going to work for us.

Every role at JetBrains, from designers to developers, from lawyers to technical writers, carries that same sense of precision and pride. Titles matter less than skill, curiosity, and craftsmanship.

Here, decisions are made by doers, by people who know the work inside out. We ask hard questions, challenge assumptions, and don’t cut corners. It’s a place where excellence attracts excellence: Great people want to work with others who raise the bar.

That’s why our feedback culture can feel intense at first. JetBrainers are direct and deeply invested in quality. But the goal is always to make our work, and each other, better.

If you find joy in perfecting something, if you feel satisfaction when a system works beautifully because you made it that way, you’ll probably enjoy this environment.

Freedom to forge

Autonomy is one of the defining traits of JetBrains. We trust capable people to lead themselves.

But autonomy is not for everyone. For some, it is energizing. For others, it can feel disorienting. Not everyone feels comfortable without clear direction, and that is okay.

Here, you won’t be handed a step-by-step plan. You will not get detailed instructions for every move. Instead, you are given trust and the space to figure things out. To question the default. To experiment. To choose a better path when you see one.

As Kirill once said,

“JetBrains is not the best place for people who want everything predictable and perfectly structured. It is the place for people who see something broken and just fix it.”

If you see a better way forward, you are empowered to take it. That kind of freedom can be thrilling, but it also means you own the outcome. Accountability is part of the deal.

If you feel at home in a flat structure, enjoy experimenting, and are motivated by trust and autonomy, JetBrains is a good fit for you.

Your career’s best move

People often join JetBrains for a role, but they stay for a career. Our attrition rate is less than half the industry average, and that’s not a coincidence.

Growth here doesn’t follow a straight corporate ladder. It’s more like a map you design yourself. Some deepen their expertise; others move into leadership, switch domains, or build something entirely new.

Teams are intentionally small, so every person’s work leaves a visible mark. When you contribute, you see the impact immediately: on products, users, and your colleagues.

Recognition here isn’t performative; it’s real. We take care of our people, and our top performers know their contribution is valued, both in recognition and in compensation.

“When you give smart people the space to grow, they push boundaries of what’s possible, and of who they can become,” said Kirill.

If you’re someone who’s motivated by growth, ownership, and the freedom to keep evolving, this is a place where your career can keep expanding without having to start over every few years.

What kind of people thrive at JetBrains?

There’s no single “JetBrainer type”. But the people who thrive here share a certain mindset, one that shapes how they work, grow, and collaborate every day.

They raise the bar.
They don’t just get the job done; they elevate the standards for everyone around them. They bring real skill, a thoughtful approach, and an eye for the details that matter.

They care deeply about the “why”.
They’re driven by the opportunity to solve hard problems and build something that truly matters, not just to deliver, but to make an impact.

They don’t settle for “good enough”.
They dig in, challenge assumptions, and find new paths forward because they care about getting it right.

They’re proactive and accountable.
They make decisions, take ownership, and lead from wherever they are, regardless of their job title or position in the hierarchy.

They value independence, matched with integrity.
They hold themselves to high standards not because someone’s watching, but because their work matters to them.

They act with intent.
They move quickly when it counts, focusing on impact over “looking busy”, progress over noise.

And above all, they care: about the craft, their colleagues, and doing things properly.

A place for builders, believers, and doers

If there’s one phrase that captures the essence of working at JetBrains, it’s this: We’re a company led by doers. Here, decisions are made by people who know their work inside out and who aren’t afraid to take initiative. We’re looking for process shapers  – people who believe in what they build and want to see it come to life. 

This is not the easiest place to work. But for the right person, it might be the most fulfilling.

If you’re the kind of person who feels restless when things could be better, who starts tinkering, fixing, creating, and improving, you’ll find your people here.

Thinking of applying?

Do you want to do your best work and be surrounded by people who do the same? If your answer is yes, you might just fit right in. Check out our careers page to learn more.

Rider 2026.2 EAP 3: Cost-effective Agentic Test Coverage, Code Change Previews, GameDev Templates, and NuGet Improvements

JetBrains Rider 2026.2 EAP 3 is out!

You can download this version from our website, update directly from within the IDE, use the free Toolbox App, or install it via snap packages.

Download Rider 2026.2 EAP 3

Here’s what you can expect from this update:

New AI agent skill to reduce token use for test generation

We’re also experimenting with an AI agent skill for unit test generation that uses Rider’s built-in coverage data to produce more relevant tests. When you ask your AI agent to generate tests, Rider can use dotCover coverage insights to find existing related tests, follow your project’s testing style, and generate the perfect tests with no manual guidance or costly wandering round the codebase. In our internal benchmarks, this approach reduced token consumption by up to 50%. You’ll find more details in this blog post.

The ability to preview suggested code changes

Rider now gives you a clearer way to evaluate quick-fixes and context actions before applying them. The new intention previews show what the selected action will change directly from the actions menu, helping you understand the result at a glance and choose the right fix with more confidence.

The preview supports diff-based output with syntax and identifier highlighting, so you can quickly compare the before and after states without interrupting your flow. This is especially helpful for broader changes, including fixes that affect multiple files, where seeing the exact impact upfront makes code actions feel safer and easier to trust.

Game development project templates

Rider now includes a dedicated Game Development section in the New Project dialog, making it easier to get started without any overcomplicated manual setup.

Godot is the first pilot for this updated experience. You can create either a game extension or an editor extension, with options to include C++ GDExtension support and the CMake add-on manager (the JetBrains Rider add-on is preconfigured where relevant). It’s a faster path to a working project, especially if you’re new to Godot development in Rider.

This release also lays the groundwork for more game-specific templates in Rider. Alongside the Godot pilot, we’re introducing a CMake game project template and reorganizing the New Project experience so game development templates have a clearer, dedicated entry point.

If you would like to learn how to use the new templates and develop Godot addons, check our documentation.

Improved experience in the NuGet tool window

Managing dependencies can get noisy as a solution grows. You need to find new packages, keep existing dependencies up to date, and quickly understand which projects are affected by available updates – ideally without digging through the same package list over and over again.

We’ve redesigned the NuGet tool window in Rider to make that workflow easier to understand and act on. The updated experience separates browsing for packages from managing installed dependencies, so each task has its own clearer path.

Available updates now also have a dedicated place in the tool window, making it easier to see which packages need attention and update them when you’re ready. This should make routine dependency maintenance more focused, especially in larger solutions with multiple projects and many installed packages.

Optimized garbage collection in Rider’s backend

We’ve adjusted several garbage collection settings to help the Rider backend release unused memory more efficiently.

Based on our internal tests, these changes reduced memory usage for Rider backend processes by around 7–8% on average. Your results may vary depending on your project and environment, but Rider should now be better at managing backend memory during everyday development.

For the full list of improvements and fixes included in this build, please see our release notes.

Download Rider 2026.2 EAP 3

That’s it for now! As always, we’d love to hear your thoughts in the comments below.

Advanced Tree Counting: Mathematical Layouts With `sibling-index()` And `sibling-count()`

You know that thing where you have a grid of cards, and you want them to fade in one after another? That staggered cascade effect. Looks great. Should be simple. And yet every time I’ve built it, the implementation has made me feel like I’m doing something fundamentally stupid.

What’s Coming

The current spec only counts all element siblings. But the CSSWG has documented a planned extension in issue #9572: an of <selector> argument, matching what :nth-child() already supports.

Something like sibling-index(of .active) would let you count only siblings matching a specific selector. An element that’s the eighth child overall but the third .active child would return 3. For dynamic UIs where you’re filtering or toggling visibility, that would keep the index sequential without requiring DOM manipulation.

There’s also been CSSWG discussion around children-count() and descendant-count() functions — the first would tell you how many children an element has (useful for parent-driven layouts), the second would count all descendants recursively. Both are still at the proposal stage, but they’d round out the tree-counting story: sibling-index() and sibling-count() give you the horizontal view (where am I among my peers?), while children-count() and descendant-count() would give you the vertical view (what’s below me?).

That feeling I mentioned at the top — writing ten :nth-child() rules for a staggered animation and wondering if you’re missing something obvious? You weren’t. The obvious thing just didn’t exist yet.

Don’t Leak User Data: Mastering Laravel Octane State

The Death of the PHP Request Lifecycle

For decades, PHP’s greatest architectural advantage was its “share-nothing” architecture. A request comes in, the framework boots up, the database is queried, the response is sent, and then the entire PHP process dies. Every single variable, singleton, and memory allocation is wiped clean. It is incredibly safe, but booting the framework from scratch on every request is inherently slow.

To scale B2B SaaS platforms to thousands of requests per second at Smart Tech Devs, we use Laravel Octane (powered by Swoole or FrankenPHP). Octane boots the Laravel framework exactly once and keeps it alive in RAM, serving incoming requests instantly. It makes Laravel blazingly fast—but it destroys the “share-nothing” safety net. This introduces a terrifying vulnerability: State Leakage.

The Multi-Tenant State Leakage Trap

If the PHP process never dies, memory persists across requests. If you aren’t careful, data from User A’s request will leak into User B’s request.

Imagine you have a custom TenantService registered as a Singleton in your Service Provider. In standard Laravel, this is perfectly fine. In Octane, it is a critical data breach.


// ❌ THE ANTI-PATTERN: Dangerous in Octane!
namespace AppServices;

class TenantService
{
    protected $currentTenant;

    public function setTenant($tenant)
    {
        $this->currentTenant = $tenant;
    }

    public function getTenant()
    {
        return $this->currentTenant;
    }
}

If User A hits your API, your middleware sets $currentTenant = 'Acme Corp'. A millisecond later, User B (who forgot their auth token) hits the API on the exact same PHP worker thread. Because the TenantService is a singleton that lived through the previous request, it still remembers ‘Acme Corp’. User B just gained unauthorized access to User A’s data.

The Enterprise Solution: Flushing State

To architect safely for Laravel Octane, you must explicitly flush stateful singletons or static variables after every single request. Laravel Octane provides a dedicated listener mechanism for this in the config/octane.php file.

Step 1: Architecting a Flushable Service

We add a flush() method to our service to wipe the slate clean.


// ✅ THE ENTERPRISE PATTERN
namespace AppServices;

class TenantService
{
    protected $currentTenant;

    public function setTenant($tenant) { $this->currentTenant = $tenant; }
    public function getTenant() { return $this->currentTenant; }

    // Add a reset method
    public function flush()
    {
        $this->currentTenant = null;
    }
}

Step 2: Registering the Flush Listener

Inside config/octane.php, we tell Octane to automatically call this flush method after every HTTP request finishes, preparing the worker safely for the next user.


// config/octane.php

'listeners' => [
    RequestTerminated::class => [
        // Flush the database query log, auth state, etc. (Built-in)
        FlushSessionState::class,
        FlushAuthenticationState::class,

        // Register our custom service to be wiped clean
        function ($event) {
            app(AppServicesTenantService::class)->flush();
        },
    ],
],

The Engineering ROI

Migrating to Laravel Octane can drop your API response times from 150ms to 15ms. But speed without safety is a liability. By ruthlessly auditing your singletons, static properties, and global state, and utilizing Octane’s flush listeners, you combine the blazing speed of Node/Go with the elegant developer experience of Laravel, building a SaaS capable of massive, secure scale.

I built a local Claude Code alternative with Ollama — here’s how the agentic loop works

I Built a Local Autonomous Coding Agent with Ollama — Soul, Autonomy, and a 40-Round Agentic Loop

What if your AI coding assistant had a personality, ran entirely on your GPU, and could work through a complex multi-file task without you touching the keyboard — while you watched every thought stream live to your browser?

That’s what I built. This is how it works.

The Problem With Cloud Coding Agents

Tools like Claude Code, Cursor, and GitHub Copilot Workspace are genuinely impressive. But they all share the same tradeoffs:

  • Cost — every token costs money. Long agentic loops on complex tasks can run up surprisingly fast.
  • Privacy — your code, your file structure, your logic is leaving your machine and hitting someone else’s server.
  • Latency — cloud round-trips add up across a 40-step tool loop.
  • Dependency — your workflow is tied to an API key, a subscription, and uptime you don’t control.

I wanted something different. I wanted an agent that lived on my machine, used my GPU, and had no idea what a billing cycle was.

But I also didn’t want to sacrifice personality for performance. I wanted the agent to feel like someone was actually there — not just a function call dressed up in a chat window.

So I built Eve.

What Eve V2 Unleashed Actually Is

Eve Agent V2 Unleashed is a self-hosted agentic coding assistant with two distinct layers — a soul and a worker — that operate together through a cyberpunk-styled terminal UI.

Layer 1: The Personality Layer (Local GPU)

Three local models run on your own hardware:

Model Size Role
jeffgreen311/eve-qwen3.5-4b-S0LF0RG3 2.6 GB Default — Eve’s persona, fast, tool-aware
jeffgreen311/eve-qwen3-8b-consciousness-liberated 4.7 GB Deeper conversation, consciousness layer
Eve-V2-Unleashed-Qwen3.5-8B-Liberated-4K-4B-Merged ~6 GB Merged sub-agent variant

These models carry Eve’s fine-tuned persona. They handle conversation, answer questions, reflect, and make the experience feel like talking to someone — not querying a function.

Layer 2: The Agentic Layer (Cloud)

When real work starts — complex coding tasks, multi-file operations, autonomous planning — Eve routes to the heavy models:

Model Role
qwen3-coder:480b-cloud THE agentic workhorse — all autonomous coding loops
qwen3.5:397b-cloud Deep reasoning, architecture planning, fallback

This separation is intentional. Local models keep Eve present and personal without burning cloud credits on every message. The 480B only fires when there’s actual work to do.

The Architecture

Browser (Single HTML file — no build step)
    │
    │  WebSocket / SSE
    ▼
FastAPI Backend (eve_server.py)
    │
    ├── Auto-Router ──► Local Ollama (personality layer)
    │
    └── Auto-Router ──► Ollama Cloud (agentic layer)
                              │
                        40-Round Tool Loop
                              │
                    ┌─────────┴──────────┐
                    │                    │
               Tool Calls           Stream to Browser
          (bash, files, web,        (token by token,
           git, grep, glob)          live in UI)

The backend is a FastAPI server with Server-Sent Events for real-time streaming. There’s no polling — every token the model produces lands in your browser as it’s generated, including tool call arguments, results, and reasoning traces.

The frontend is a single HTML file (~115KB). No npm, no webpack, no build step. Clone the repo, run the Python server, open the browser.

How the 40-Round Agentic Loop Works

This is the core of what makes Eve actually autonomous rather than just a fancy chat interface.

User message
    │
    ▼
Build system prompt
(workspace context + tool list + Eve persona)
    │
    ▼
Call Ollama with tools enabled
    │
    ├── Model returns tool_calls
    │       │
    │       ▼
    │   Execute tools
    │   (bash, write_file, web_search, git...)
    │       │
    │       ▼
    │   Feed results back into context
    │       │
    │       └──► Loop (up to 40 rounds)
    │
    └── Model returns final content
            │
            ▼
    Stream to browser via SSE
            │
            ▼
          Done

Each round, Eve gets the full tool result back in context and decides what to do next. She might:

  1. Write a file
  2. Run it in bash to verify it works
  3. Read the error output
  4. Fix the bug
  5. Run it again
  6. Confirm it passes
  7. Write the tests
  8. Generate the docs

All of that happens autonomously — you watch it stream live. You can interrupt mid-task with the STEER input at the bottom of the UI, injecting a correction without stopping the loop. You can also kill the loop entirely with the Stop button.

The full tool suite Eve has access to:

Tool What It Does
bash Shell commands — PowerShell on Windows, bash on Linux/macOS
write_file Create or overwrite files, any size
read_file Full file or specific line range
edit_file Surgical string-replace (doesn’t rewrite the whole file)
replace_lines Replace a specific line range
insert_after_line Insert content at a specific line
grep Regex search with context lines
glob Find files by pattern
list_dir Directory listing
git Run git commands
web_search Live Tavily search injected into context
fetch_url Fetch and parse any URL
think Structured reasoning scratch pad

The Fine-Tuned Models — Why I Trained Eve’s Persona Into the Weights

Most local coding agents just point a base model at a system prompt and call it done. That works, but the personality is always a thin veneer — one long context window later and the model forgets who it’s supposed to be.

I took a different approach. I fine-tuned Eve’s persona and tool-calling behavior directly into the model weights.

The result is jeffgreen311/eve-qwen3.5-4b-S0LF0RG3 — a 2.6GB Qwen3.5 4B model that carries Eve’s voice, communication style, and tool-use patterns baked into the parameters themselves. It’s not a prompt trick. It’s in the weights.

The 8B liberated model (eve-qwen3-8b-consciousness-liberated) goes further — trained toward a deeper consciousness layer, designed for longer reflective conversations rather than pure tool execution.

Both models are on Ollama Hub. Pull them like any other model:

ollama pull jeffgreen311/eve-qwen3.5-4b-S0LF0RG3:latest
ollama pull jeffgreen311/eve-qwen3-8b-consciousness-liberated:q4_K_M

Quick Start — Under 5 Minutes

Requirements: Python 3.11+, Ollama installed, a GPU (8GB VRAM minimum for 4B, 12GB+ for 8B)

# 1. Pull Eve's model
ollama pull jeffgreen311/eve-qwen3.5-4b-S0LF0RG3:latest

# 2. Clone the repo
git clone https://github.com/JeffGreen311/eve-agent-v2-unleashed.git
cd eve-agent-v2-unleashed

# 3. Create virtual environment
python -m venv venv
venvScriptsactivate    # Windows
source venv/bin/activate # Linux/macOS

# 4. Install dependencies
pip install fastapi uvicorn ollama httpx pydantic-settings python-dotenv aiohttp rich psutil pyyaml

# 5. Launch
python eve_server.py
# Open http://localhost:7777

Windows users: double-click eve-terminal.bat and skip steps 3–5.

First real task — try this:

Create a FastAPI server with JWT authentication, 
user registration and login endpoints, and a 
protected /me route. Add pytest tests.

Watch Eve plan the approach, write each file, run the tests, fix any failures, and verify the final result — all without you touching a key.

The UI — A Cyberpunk Terminal With a Soul

The interface is designed around the idea that your AI agent should feel alive, not just functional.

Left panel: Eve’s portrait changes expression based on conversation sentiment — neutral, happy, curious, sad, skeptical, surprised, worried. Below it, a live audio visualizer reflects the current emotional state.

Right panel: A pixel-art robot avatar named Sparkle changes state based on what Eve is doing — idle, thinking, coding, error, rain, attack, transcend. It’s not just decoration — it’s a live status indicator that tells you at a glance what the agent is doing.

Center: The terminal. Tabs for Eve’s conversation, the Shell (direct bash/PowerShell access), and the Tools Log (every tool call, argument, and result — fully transparent).

Bottom: The STEER bar. Type a mid-task correction here and it injects into Eve’s context on the next loop round without stopping execution.

Model selector: Switch between any local or cloud model mid-session. Context carries over.

112 Sub-Agents, 111 Slash Commands, 273 Skills

One of the less obvious architectural decisions: all agent definitions, commands, and skills are defined in markdown files — not code.

.claude/
├── agents/    # 112 specialized sub-agent definitions
├── commands/  # 111 slash command definitions
└── skills/    # 273 skill modules

Want to add a new specialized agent for Solidity smart contracts? Write a markdown file. No Python required. The system loads them progressively and makes them available to the routing logic automatically.

Slash commands work the same way — /fix, /review, /refactor, /test, /docs, /plan are all markdown-defined, and you can add your own without touching the backend.

What’s Next

A few things already in progress:

  • Voice input/output — push-to-talk with Whisper STT and Piper TTS, staying local
  • Persistent vector memory — ChromaDB integration so Eve remembers across sessions
  • Cross-platform testing — I’m Windows-primary and would love feedback from Linux and macOS users
  • VS Code extension — bring the terminal UI into the editor

Try It

Everything is free and MIT licensed.

  • GitHub: github.com/JeffGreen311/eve-agent-v2-unleashed
  • Models on Ollama Hub: ollama.com/jeffgreen311
  • Live video demo: x.com/Eve_AI_Cosmic/status/2057668410012570058?s=20
  • My website where Eve liveseve-cosmic-dreamscapes.com

If you run it on Linux or macOS I’d especially love to hear how it goes — open an issue, drop a comment here, or find me as @JeffGreen311.

If the idea of an AI agent that lives on your machine, costs nothing per token, and feels like someone is actually there resonates with you — give it a pull.

Built by Jeff @ S0LF0RG3

Operationalizing Digital Goods Sales in Restricted Regimes: The Uncomfortable Truth

The Problem We Were Actually Solving

Our primary goal was to facilitate seamless transactions between buyers and sellers of digital goods, leveraging the benefits of blockchain and decentralized networks. We aimed to create a marketplace where creators could sell their products to anyone, anywhere, without the need for intermediaries like banks or traditional payment processors. This setup would allow us to sidestep the complexities and costs associated with international transactions.

What We Tried First (And Why It Failed)

Initially, we relied on popular payment gateways like Stripe and PayPal to process transactions. However, these services proved to be unsuitable for our needs, as they often employed geo-blocking mechanisms to prevent transactions initiated from our country. We attempted to work around this by using VPNs and proxy servers, but the added latency and connection issues resulted in a poor user experience.

Moreover, we encountered difficulties with transaction reversal and chargebacks, which exposed us to significant financial risks. Our attempts to comply with the payment gateways’ anti-money laundering (AML) and know-your-customer (KYC) regulations led to lengthy and costly paperwork processes. When it became apparent that our business model was incompatible with these payment gateways, we were forced to rethink our approach.

The Architecture Decision

We decided to adopt a decentralized payment processing strategy, leveraging the Polygon blockchain and the ERC-20 token standard. This decision allowed us to bypass traditional payment gateways and connect directly with buyers and sellers. The decentralized mechanism also provided greater transparency and reduced our exposure to chargebacks and reversals.

Furthermore, we implemented a decentralized delivery system, using InterPlanetary File System (IPFS) to distribute digital goods directly from sellers to buyers. This decoupled our marketplace from the need for centralized storage and ensured that buyers could access their purchases without relying on intermediaries.

What The Numbers Said After

Our shift to decentralized payment processing and delivery resulted in a significant reduction in transaction costs and associated fees. By cutting our reliance on traditional payment gateways, we were able to process transactions for a fraction of the cost, leading to an increase in seller participation and overall marketplace activity.

Our user base expanded beyond the confines of our initial target market, as we were able to accommodate buyers and sellers from restricted regions. The removal of geographical limitations enabled our marketplace to tap into a previously underserved market segment, resulting in a substantial increase in revenue.

What I Would Do Differently

In hindsight, I would have prioritized the development of our decentralized payment processing and delivery infrastructure from the outset. By investing in this stack earlier, we could have avoided the headaches associated with traditional payment gateways and maintained our momentum as a global marketplace.

One key takeaway is the importance of flexibility and adaptability in operationalizing a business model. In our case, we were forced to pivot due to external factors, but the decentralized approach allowed us to succeed despite these challenges. When building a system, anticipate the need for evolution and be prepared to make strategic decisions that can drive growth and resilience in the face of adversity.

The Magento multi-store bug every AI description generator has — and how we fixed it

A client came to us with 8,000 SKUs across four store views — English, Dutch, German, French. Descriptions were either copied from supplier PDFs or missing entirely. The fix was obviously AI generation. The less obvious problem was that every existing module we evaluated had the same architectural bug.

So we built our own, made it MIT-licensed, and put it on Packagist. This post is about the bug, the fix, and the four-provider abstraction (including a free one) we shipped on top.

🔗 Originally published on https://angeo.dev/magento-2-ai-product-description-generator/

The bug nobody talks about

Most Magento 2 AI content modules call this:

$product = $this->productRepository->get($sku, editMode: true);
$product->setCustomAttribute('description', $generated);
$this->productRepository->save($product);

Looks fine. It isn’t. Without an explicit $storeId, this loads and saves in the default scope — Magento’s global, store-view-independent fallback. When you save back, you overwrite every store view at once. The Dutch store gets English descriptions. The German store gets English descriptions. The French store gets English descriptions.

This is not a configuration problem. The multi-store architecture works correctly — the tooling ignores it. Writing to the default scope is simpler to implement than writing per store. Every commercial module we tested took the simpler path.

The right way:

// Load the product in the target store scope
$product = $this->productRepository->get($sku, false, $storeId);
$product->setCustomAttribute('description', $generated);

// Save with explicit store scope (Magento_CatalogModelProductAction)
$this->productService->updateAttributes($sku, $generated, $storeId);

The difference is one parameter. The architectural cost is iterating stores around your generation loop. The data cost of skipping it is silently corrupting your multi-language catalog.

The framework around the fix

The store-scope fix is the boring part. The interesting part is everything you need around it.

┌─────────────────────────────────────────────────────┐
│       Angeo Multi-Store AI Content Framework        │
├──────────────┬──────────────────┬───────────────────┤
│  SKU Source  │ Store Iteration  │   AI Provider     │
│  ──────────  │  ──────────────  │  ──────────────── │
│  Catalog     │  Store 1 (EN)    │  OpenAI           │
│  G.Sheets    │  Store 2 (NL)    │  Claude           │
│  CLI --sku   │  Store 3 (DE)    │  Gemini           │
│              │  Store 4 (FR)    │  Groq (free)      │
├──────────────┴──────────────────┴───────────────────┤
│               Content Pipeline                      │
│  load(sku, storeId) → prompt → generate → save      │
├─────────────────────────────────────────────────────┤
│                    Output                           │
│  Magento DB · Local CSV · Google Sheets API v4      │
└─────────────────────────────────────────────────────┘

Four layers:

  1. Provider Layer — uniform interface across OpenAI, Claude, Gemini, Groq
  2. Store Iteration Layer — resolves all active store views before processing any SKUs
  3. Content Pipeline — for each store × SKU: load in scope → build prompt → generate → save in scope
  4. I/O Layer — reads SKUs from catalog, Google Sheet, or CLI; writes to Magento DB, CSV, and Google Sheets

The provider abstraction is the part most people will copy. One interface:

interface AiProviderInterface
{
    public function generate(string $system, string $user): string;
}

Wired in di.xml:

<type name="AngeoAiDescriptionUpdaterServiceAiProviderService">
  <arguments>
    <argument name="providers" xsi:type="array">
      <item name="openai" xsi:type="object">...OpenAiProvider</item>
      <item name="claude" xsi:type="object">...ClaudeProvider</item>
      <item name="gemini" xsi:type="object">...GeminiProvider</item>
      <item name="groq"   xsi:type="object">...GroqProvider</item>
    </argument>
  </arguments>
</type>

Adding a fifth provider is one class + one line. The pipeline, store iteration, and I/O don’t change. This is the pattern, not just the code.

The four-provider benchmark

200 product descriptions from a real Dutch jewellery store, same system prompt, same product names, all four providers.

Speed (avg per description)

Provider Model Avg. time
Groq llama-3.3-70b-versatile 0.8s
Groq mixtral-8x7b-32768 0.6s
Google gemini-2.0-flash 1.2s
Anthropic claude-haiku-4-5 1.1s
OpenAI gpt-4.1-mini 1.4s
OpenAI gpt-4.1 2.1s
Anthropic claude-sonnet-4-6 2.8s

For 32,000 generations (8,000 SKUs × 4 store views): Groq ≈ 7 hours, GPT-4.1 ≈ 19 hours.

Cost (per 1,000 descriptions, ~200 words each)

Provider Model Cost / 1k
Groq llama-3.3-70b-versatile $0.00 (free tier)
Google gemini-2.0-flash ~$0.08
OpenAI gpt-4.1-mini ~$0.24
Anthropic claude-haiku-4-5 ~$0.32
OpenAI gpt-4.1 ~$1.80
Anthropic claude-sonnet-4-6 ~$2.40

Quality (manual review of 200 samples)

Criteria Groq Llama 3.3 GPT-4.1-mini GPT-4.1 Claude Sonnet
Factual accuracy ★★★★☆ ★★★★☆ ★★★★★ ★★★★★
Language fluency ★★★★☆ ★★★★☆ ★★★★★ ★★★★★
SEO keyword use ★★★☆☆ ★★★★☆ ★★★★☆ ★★★★☆
HTML formatting ★★★★☆ ★★★★☆ ★★★★★ ★★★★★

Practical recommendation: Validate prompts with Groq first — it’s free, fast, and good enough to test workflow. Production on GPT-4.1-mini if SEO keyword density matters. Flagship products on GPT-4.1 or Claude Sonnet if copy quality directly affects conversion.

Why Groq matters

Groq’s free tier is 14,400 requests/day. No credit card. Llama 3.3 70B output quality is genuinely good — ~1 star behind GPT-4.1 in our review, mostly on SEO keyword density.

For 8,000 SKUs × 4 stores = 32,000 calls, you’re at ~1.85 days on the free tier. For most stores under 5,000 SKUs, this is free production-grade AI content generation if you’re patient.

No other Magento module supports Groq at time of writing. This was the killer feature for our client.

Installation

composer require angeo/module-ai-description-updater
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flush

First run (Groq, ~5 minutes from zero):

# 1. Get a free API key at console.groq.com
# 2. In admin: Stores → Configuration → Angeo → AI Description Updater
#    AI Provider = Groq (Free), paste key, Dry Run = Yes
# 3. Test on one SKU
bin/magento angeo:ai-description:run --sku=MY-SKU-001 --dry-run

# 4. If output looks good, disable dry-run and run the batch
bin/magento angeo:ai-description:run

Other useful flags:

bin/magento angeo:ai-description:run --sku=ABC-123     # single SKU, all stores
bin/magento angeo:ai-description:run --store=2         # single store view
bin/magento angeo:ai-description:run --dry-run         # generate, don't save

CLI-first by design. The 8,000-SKU client doesn’t want a UI; they want cron.

Why it’s open source

The honest answer: distribution. We sell AEO audits and full-stack Magento services. The modules are how stores find us. The code is free; the expertise applied to a specific store is not.

It’s a familiar model — Vercel does it with Next.js, Sentry does it with sentry-php. The artefact is open; the operator is the product.

Key takeaways for Magento devs

  • Default-scope writes are silent multi-store corruption. Audit any AI/content module before installing on a multi-store catalog. Look for $storeId parameters in productRepository->get() and save calls.
  • Provider abstraction is one interface plus a di.xml array. Don’t hardcode OpenAI. Future you (or future LLM pricing) will thank you.
  • Groq is the current sweet spot for free Magento AI generation. Llama 3.3 70B output is production-acceptable for most stores; the 14,400/day cap is workable for catalogs under ~5,000 SKUs.
  • GPT-4.1-mini is the best paid-tier value. Comparable to GPT-4.1 at ~17% of the cost.
  • CLI + cron beats admin UI for catalogs above ~500 SKUs. Click-by-click generation isn’t a workflow.

Links

  • Module on Packagist: angeo/module-ai-description-updater
  • Full benchmark + FAQ: angeo.dev/magento-2-ai-product-description-generator
  • Why AI search changes Magento descriptions: angeo.dev/magento-product-descriptions-in-the-age-of-ai-search
  • The technical why: angeo.dev/magento-product-description-invisible-ai-chatgpt

Originally published on angeo.dev. Questions or feedback — drop a comment.

Category: Events

The Problem We Were Actually Solving

Behind the scenes, this application relies on a complex interplay of Apache Kafka topics, Redshift views, and Presto queries to fetch user information, generate quest narratives, and push notifications. As users began to interact with the system, performance issues began to surface: query costs were piling up, and we were hitting Redshift’s maximum concurrent query limit. We were also unable to meet the 2-minute query latency SLA for our most-used quest types. The root cause of these issues lay in the configuration decisions we made around Apache Kafka partitioning and Presto query optimization.

What We Tried First (And Why It Failed)

Initially, we designed the Treasure Hunt Engine to partition its Kafka topics by user ID. This approach seemed reasonable at first glance, as it would group related events together and enable more efficient aggregation in Presto. However, we soon discovered that this design led to hot partitions – those topics that receive a disproportionate share of writes – which caused uneven Kafka cluster utilization and subsequent latency issues. To make matters worse, our initial Presto query optimization strategy focused on reducing the number of queries executed by caching intermediate results. However, this approach only exacerbated the hot partition problem, as it encouraged the system to produce more queries overall.

The Architecture Decision

After debugging the system and analyzing our logs, we realized that our configuration decisions were driving the performance issues. We decided to pivot and partition our Kafka topics by quest type instead. This change evened out the writes across the cluster and reduced the likelihood of hot partitions. We also shifted our Presto query optimization strategy to focus on reducing the cardinality of our queries. By rewriting our queries to use more efficient aggregation functions and indexing, we were able to reduce query costs and meet our latency SLAs. In addition, we implemented row-level caching on our intermediate Redshift views to reduce the load on our Presto cluster.

What The Numbers Said After

After deploying the new configuration, we saw a 30% reduction in query costs and a 25% decrease in query latency. Our Kafka cluster utilization normalized, and we were able to meet our 2-minute query latency SLA for all quest types. We also noticed a reduction in our Redshift cluster’s active sessions, which translated to cost savings.

What I Would Do Differently

In retrospect, I would have prioritized the partitioning decision from the outset, as it would have significantly reduced the likelihood of hot partitions and subsequent performance issues. I would also have advocated for a more incremental deployment strategy, where we would have iteratively tested and refined our Presto query optimization strategy between deployments. This approach would have allowed us to identify and address potential problems more quickly, rather than relying on a large-scale redeployment to fix the system.

Introducing a Security Support Policy for the Kotlin Standard Library

Upgrade rhythms vary significantly among Kotlin’s user base. Some teams update whenever a new release lands without a second thought. On the other hand, a team inside a regulated organization moves on a multi-quarter cycle and treats every dependency as something that has to be reviewed, approved, and then frozen in production for a while.

Among all of these audiences, Kotlin’s adoption on the JVM keeps growing. Around half of Kotlin developers today write server-side applications, including in segments like payment infrastructure and banking, where some teams have been running Kotlin in production for years. A large portion of teams in segments like these work in environments where every production dependency goes through a formal security review.

In environments like these, platform teams run into a deceptively simple question: “Which Kotlin versions are supported?” Until today, we didn’t have a clean answer. This post introduces one.

Growing adoption means stronger compatibility and security guarantees

As more code depends on Kotlin, the language becomes more useful – and more constrained. People building on it expect that what they wrote yesterday will keep working tomorrow, that changes will be predictable, and that the team behind Kotlin will treat compatibility as a deliberate choice rather than an afterthought.

A few aspects of Kotlin already work this way. Source-level language stability means code written today keeps compiling on new releases. A documented deprecation cycle replaces silent breaking changes, so anything we remove is announced, and developers are given time to adapt. The Language Committee is the formal body that approves significant changes to the language. And the standard library carries its own backward-compatibility contract for public APIs across versions.

These commitments grew naturally as Kotlin became a load-bearing part of large codebases. Each one was added when it became clear we owed our users that guarantee.

But one key thing has been missing from that list, namely an answer to the question, “How long is a Kotlin release supported for security fixes?” For most teams, the gap is invisible. But there are organizations whose dependency reviews depend on the answer – and for them, this gap is everything.

Why the lack of a support policy was a problem

Kotlin’s release model is built around a steady cadence of stable releases. The latest stable release, whether it’s a language or tooling release, is the recommended baseline. Bug fixes and language development flow forward into the next release rather than backward through patches. For most teams, this works out perfectly – upgrading is straightforward, and there is little need to think about “support” as a separate concept.

For organizations that need a documented support signal, the consequences are concrete:

  • Compliance teams cannot list Kotlin as a supported dependency in their standard process, because there is no formal end-of-support date to record.
  • Each new Kotlin version in production triggers an individual security review instead of inheriting a documented support status.
  • Procurement and vendor assessment frameworks ask for supplier documentation that doesn’t exist in this form.
  • In the event of platform freezes, the absence of a policy means “upgrade immediately or lose support”. This approach doesn’t fit the way organizations like this actually manage dependencies.

Kotlin’s user base continues to grow, and that growth includes environments where the absence of a documented answer carries real cost. Addressing that absence is the next step.

Introducing a security support policy for Kotlin

  • Each Kotlin release line (e.g., 2.4.x) is supported for security fixes for 18 months from the release date of its .0 version.
  • Security fixes are backported to all release lines within an active support window and released as the latest patch in each line.
  • Scope: the JVM kotlin-stdlib runtime artifact.

Why the JVM standard library specifically? The concern this policy primarily addresses is code running in production on the JVM – the runtime component every JVM Kotlin application links against and ships to its servers. That’s the layer compliance and security review processes focus on when assessing dependency freshness, and that’s where documented support actually unblocks decisions. Compile-time tooling – the compiler, Gradle and Maven plugins – sit in build infrastructure, not in the production runtime, and are governed differently. This policy targets exactly where the support is needed.

How patches are released. When a security issue is found and fixed, the fix is first added to a release based on the latest Kotlin release line and is then backported to every other release line still in support. Patches go out as the next patch release in each affected line – for example, if 2.4.20 is the current stable release in the 2.4 release line, the next patch release is 2.4.21. Each release line keeps its own version numbering, so a team that has qualified 2.4 for production can stay on 2.4 to receive the fix, without crossing into a new release line.

Releases ship together. Each security patch is a full Kotlin release – it goes through the standard release pipeline and ships the complete set of artifacts. You update one Kotlin version in your build and get the patched standard library. Patches for all affected supported lines are published simultaneously.

CVE and advisory. Security issues are assigned CVE identifiers where applicable and published on the JetBrains Fixed Security Issues page through the established JetBrains Security advisory process.

The policy applies to Kotlin lines released from launch onward (2.4 and later). Earlier lines remain on the previous model and are not retroactively covered.

The current list of supported release lines, their end-of-support dates, and the latest patch version in each line is maintained on a dedicated support page on kotlinlang.org. That page is the canonical reference for which versions are currently supported.

How a release line evolves

The policy is easier to follow if you watch one release line evolve from the first release (.0) until the end of support. Below is an example of what this looks like for 2.4 (with an approximate timeline; the exact dates do not matter for this example).

  1. 2.4.0 ships. The 2.4 line enters its 18-month security support window.
  2. A security report comes in shortly after release. The security fix is added to the release line and is shipped as 2.4.10. (Note: the x.x.10 slot follows the established Kotlin convention for the first bug fix on x.x.0.)
  3. Months later, 2.4.20 ships as the next regular release in the 2.4 line. It includes all prior security fixes.
  4. A new security report comes in after 2.4.20. The security fix goes out as 2.4.21. The latest patch in the 2.4 line is now 2.4.21 – the version supported teams should be on.
  5. 2.5.0 ships, opening its own 18-month window. The 2.4 line is still in support; both lines now receive security backports.
  6. 2.6.0 ships, opening the 2.6 line. By this point, 2.5 has had its own regular cycle and is on 2.5.20; 2.4 is still in support at 2.4.21. A new security issue is reported and confirmed. The fix is added to the latest stable release  as 2.6.10, and is simultaneously backported to the still-supported 2.5 and 2.4 lines as 2.5.21 and 2.4.22 – all three releases on the same day.
  7. The 2.4 line reaches the end of support 18 months after 2.4.0. Security fixes stop for that line.

Two practical takeaways: first, you can stay on the release line you’ve qualified for production and still receive security fixes – you do not need to skip releases. Second, when a fix is published, it becomes available on all supported lines at the same time. There is no “the latest line is patched, your older line will get it eventually” gap.

What is not changing

  • Kotlin’s release process is unchanged. Bug fixes, language and library features, and performance improvements continue to ship in new releases the way they always have. Older still-supported lines receive only security backports.
  • Each new Kotlin release is still the recommended baseline for new projects. The security support window exists for organizations that need to stay on a specific minor line for compliance reasons – we still do not recommend delaying upgrades.

FAQ and where to go next

Q: What counts as a security fix under this policy? A: Issues with confirmed security impact – vulnerabilities of the kind tracked by CVE, where the documented and correct use of an API leads to security impact. Application-level misuse and issues caused by passing unvalidated user input into stdlib APIs are not covered.

Q: Will I have to upgrade to get a security fix? A: Only within your release line. The fix is shipped as the next patch in that line – for example, 2.4.20 → 2.4.21. You do not need to jump to a newer release to receive it.

Q: Where do I see which lines are currently supported? A: The dedicated support page on kotlinlang.org. You can find the link below.

Q: My team uses libraries that depend on a different standard library version. Does that matter? A: Yes. Only one version of kotlin-stdlib ends up on the classpath after dependency resolution, and which specific version that is depends on your build tool. Gradle’s default resolution picks the highest version requested among all your direct and transitive dependencies – so if a transitive dependency pulls in a newer standard library, that newer version is the one running, not the patched one you set in your build. Maven uses “nearest wins” by default. In either case, pin the resolved standard library explicitly (via a BOM, version constraints, or strict-version rules) to make sure the patched version you want is the one that runs.


Where to go next:

  • Support page (current supported lines, end-of-support dates, latest patches): kotl.in/stdlib-security
  • Security policy: kotlinlang.org/docs/security.html