<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Labidi Aymen</title>
    <link>https://aymen.co/</link>
    <description>Architect &amp; Engineering Manager at Inetum, founder of Nuraly. Writing about AI agents in production, software architecture, and the web.</description>
    <language>en</language>
    <atom:link href="https://aymen.co/feed.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Phone Programming</title>
      <link>https://aymen.co/ai/phone-programming/</link>
      <guid isPermaLink="true">https://aymen.co/ai/phone-programming/</guid>
      <pubDate>Tue, 01 Sep 2026 00:00:00 GMT</pubDate>
      <description>Claude Code did not move programming from the IDE to the terminal. It moved programming from writing to reviewing.</description>
      <content:encoded><![CDATA[<p>When Claude Code launched, I asked the obvious question. Why do we need a terminal? We have an IDE.</p>
<p>That was the wrong angle.</p>
<p>Today I ask the opposite. Why do we need an IDE, now that we have Claude Code?</p>
<h2>What I actually built</h2>
<p>A few months ago I started an experiment. One small VM per project. Each VM carries the exact environment that project needs: the runtime, the database, the credentials, the test data. Nothing shared.</p>
<p>On each VM, an agent. It gets a task, works in a branch, and opens a merge request when it is done. The pipeline takes over from there. SonarQube runs. The e2e suite runs. Coverage is checked.</p>
<p>Then my phone buzzes. A merge request is waiting for final validation. I read the diff, the pipeline report, the agent's summary. I approve or I send it back with a comment.</p>
<p>That is the whole loop. The phone is not a gimmick. It is the last step of the pipeline, and the only step that still needs me.</p>
<h2>Why I started, and why I stayed</h2>
<p>I started to offload work. R&amp;D spikes, debugging sessions that eat an afternoon, the small tickets nobody wants. The goal was to free my hours, not to change how I program.</p>
<p>The turn came a few weeks in. I was reviewing a merge request on my phone, at a café, and I realised I had not opened my IDE in days. The project had moved every one of them. Nothing was blocked on me except approval.</p>
<p>I had not stopped working on the project. I had stopped typing in it.</p>
<h2>The IDE was built for a job I no longer do</h2>
<p>An IDE is a machine for writing code. Autocomplete, refactoring, go to definition, inline errors. Every feature exists to help a human produce text faster and with fewer mistakes.</p>
<p>But I don't produce the code anymore. I review it.</p>
<p>Review needs different tools. A clear diff. The pipeline verdict next to it. The reasoning the agent followed. A way to say &quot;no, try again&quot; in one sentence. My phone does all of that, anywhere. My IDE does most of it too, and only while I am sitting in front of it.</p>
<p>The terminal question was never the point. Claude Code did not move programming from the IDE to the terminal. It moved programming from writing to reviewing. The terminal was just where that shift happened to appear first.</p>
<h2>What this changes for a team</h2>
<p>The question I hear from engineers is the same one I asked at launch, in a different form. &quot;If the agent writes the code, what do we do?&quot;</p>
<p>We do the part that was always the hard part.</p>
<p>We decide what to build. We design the systems, the loops and the graphs. We define the environment the agent works in, and that environment is now the real codebase. We write the pipeline that decides what is acceptable. We read the diff and we say yes or no.</p>
<p>Those are senior skills. They are the skills of an architect and a reviewer, not a coder. The engineers who struggle in this model are not the juniors. They are the people who measured their value in lines written.</p>
<h2>The downside</h2>
<p>My screen time went up. Not the laptop. The phone.</p>
<p>The loop I built rewards checking. A merge request can land at any moment, and every buzz might be one. So I look. At lunch. In the car. At night, when nothing is waiting and I look anyway.</p>
<p>I traded hours at a desk for a habit in my pocket. That is not a clean win. The desk had edges. The phone has none.</p>
<h2>The questions it opens</h2>
<p>If review fits in a pocket, what is a workday? What does a team look like when nobody shares a screen, a room, or a schedule? Who is responsible for a line that no human typed?</p>
<p>And the one I keep coming back to. If the phone is where I say yes or no, how long before that step goes away too?</p>
<p>I don't have the answers. I have a pipeline that works and a phone that buzzes too often. That is enough to keep going, and not enough to go back.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Joule Code - Always-on agents</title>
      <link>https://aymen.co/ai/joule-code-always-on-agents/</link>
      <guid isPermaLink="true">https://aymen.co/ai/joule-code-always-on-agents/</guid>
      <pubDate>Wed, 26 Aug 2026 00:00:00 GMT</pubDate>
      <description>What happens when the task is longer than your session?</description>
      <content:encoded><![CDATA[<p>Joule Code is an agentic coding tool built to run autonomously on servers, VMs and your own machine, connected to a Joule server for knowledge, work context and preconfigured agents.</p>
<h2>What Joule Code is not</h2>
<p>It is not here to replace Claude Code or Codex. If you want an interactive pair programmer for your daily work, those tools are excellent, and Joule already plugs into them through its MCP server.</p>
<p>Joule Code answers a different question: what happens when the task is longer than your session?</p>
<p>A DevOps agent that watches a deployment and reacts, not one that observes and reports. A worker that runs a migration overnight. A node in a workflow graph that gets an environment, a goal and the freedom to use both until the job is done. That is where Joule Code lives.</p>
<p>It also handles lightweight development. Small features, fixes, scripted changes. But the design center is long-running, unattended work.</p>
<h2>What it connects to</h2>
<p>Joule Code is a client of the Joule platform. Link it to a Joule server and it gets three things a standalone coding tool does not have:</p>
<ul>
<li>Knowledge attached to your agents.</li>
<li>The work already in progress on the platform: tasks, workflows, conversations.</li>
<li>Preconfigured agents you can hand a job to instead of describing it from scratch.</li>
</ul>
<p>Models come from wherever you want. Go through your Joule server, or point Joule Code straight at Anthropic, OpenAI or whatever provider you already pay for, with your own keys. Attaching a server gives you the platform. It does not decide which model answers.</p>
<p>Run it alone and it is a coding agent. Run it attached and it is a hand on the platform.</p>
<h2>Sessions that outlive the terminal</h2>
<p>Joule Code runs its conversations behind a daemon. Quit the terminal and the session does not die. Configure an agent, give it the task, close the laptop. It keeps going.</p>
<p>Session state is owned by the daemon and bound to your account, not to the client that started it. Reconnect from the terminal or open the same conversation in the Console web; either way you attach to the same running session, with its full history and current state. Switching clients is not a resume. Nothing was interrupted.</p>
<h2>Skills, plus Knowledge</h2>
<p>Joule Code supports skills, the same way every coding tool does now. Skills stay. They are the right way to teach an agent a procedure.</p>
<p>What skills do not solve is context. The usual pattern is to ship a folder of markdown files into the repository and hope the agent reads the right one. It goes stale, it duplicates across repos, and it grows until nobody wants to maintain it.</p>
<p>Joule Code adds the Knowledge feature of the platform on top of skills. You move the heavy part of that context, architecture notes, domain rules, API references, past decisions, into Knowledge and keep the repository light. The agent runs RAG over the knowledge attached to its Joule server, so that context lives in one place, stays current, and is shared across every session and every project that needs it. Skills tell the agent how to do the work. Knowledge tells it what it is working with.</p>
<h2>Checkpoints</h2>
<p>A checkpoint is a saved state of a conversation. Start a new session from it and the agent already knows the project, the conventions and the decisions made so far. No re-reading the folder tree, no rebuilding context from markdown files.</p>
<p>There is a second benefit. Checkpoints make requests cacheable, so the same grounded context does not get paid for twice.</p>
<h2>Session pools</h2>
<p>Real work is several features at once, in several conversations, and one of them usually depends on another.</p>
<p>Sessions are independent by default. When they belong together, you group them into a pool: the same feature, a shared subsystem, a set of related tasks. Inside a pool, a session can sneak peek another one: its status, its tasks, where it stands. Enough to know whether the thing you depend on is done, without merging the two conversations or asking a human to relay.</p>
<h2>The search engine</h2>
<p>Joule Code has access to the search engine we run on Joule. When the task needs fresh data, a new API version, a changelog, a breaking change from last week, the agent goes and gets it. It does not have to guess from training data.</p>
<h2>Interfaces</h2>
<p>The daemon owns the session, so the interface is your choice. The TUI, the Console web, and a VS Code extension, now in preview, all attach to the same running session. Pick the one that fits the moment, or use several at once.</p>
<h2>Built with Lumen</h2>
<p>Joule Code is written in Lumen, our programming language. TypeScript syntax, native binary. The same language that runs the Joule backend and the workflow engine. One stack, one mental model, end to end.</p>
<h2>Early adopters</h2>
<p>We are looking for early adopters. There is a <a href="https://t.me/+ZVbEIHk64UA5ZDc0">Telegram group</a> where we discuss features, bugs and releases, and you are invited.</p>
<p><a href="https://joule.sh/code">joule.sh/code</a></p>
<p>Ask. Search. Make.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Open letter to the companies still stuck in legal review over an AI coding tool</title>
      <link>https://aymen.co/ai/open-letter-stuck-in-legal-review/</link>
      <guid isPermaLink="true">https://aymen.co/ai/open-letter-stuck-in-legal-review/</guid>
      <pubDate>Mon, 24 Aug 2026 00:00:00 GMT</pubDate>
      <description>The tooling debate is over. What remains is an adoption gap, and it widens every quarter.</description>
      <content:encoded><![CDATA[<p>Three months. That is how long some of you take to get a Copilot contract through legal.</p>
<p>Your developers pay for Claude Code themselves and ship with it. The tool you are still evaluating is already in production. It is just not on your invoice.</p>
<p>The tooling debate is over. What remains is an adoption gap, and it widens every quarter.</p>
<p>I have not written a line of code in 2026. My team ships to production every week. Not prototypes. Not demos. Customer-facing code, reviewed and deployed.</p>
<p>The companies pulling ahead did one thing differently. They put agentic workflows inside delivery, not inside a pilot. Startups got there first because they had no committee to ask. Everyone else has a choice: do the same, or watch the gap become a moat.</p>
<p>This is not the end of software engineering. It is the best the job has been in years. Engineers design, review, and decide. Agents type.</p>
<p>If most of your engineers are not building with agents today, you do not have a tooling problem. You have a leadership problem. Buying a license will not fix it.</p>
<p>Neither will an AI committee. You know the one. It writes the standard CLAUDE.md, picks the approved tools, hands out scripts, and schedules meetings to encourage adoption. That is top-down, and this does not work top-down. Find the engineer who ships the highest quality code with the least effort. Give them the mic. Let them show the team what they do, with no committee validation and no meetings in between.</p>
<p>By 2027 the teams running agent-native delivery will not be faster than you. They will be playing a different game. You will still be choosing a tool.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Joule.sh - The AI Workspace</title>
      <link>https://aymen.co/ai/joule-the-platform-i-built/</link>
      <guid isPermaLink="true">https://aymen.co/ai/joule-the-platform-i-built/</guid>
      <pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate>
      <description>Joule is an AI platform and workspace for individuals and enterprises to build, maintain and deploy AI workflows and agents.</description>
      <content:encoded><![CDATA[<p>Every AI project I built started the same way: week two, and I am writing the same components again. Agent orchestration. Search with real context. Document generation. Workflow logic. Different projects, different codebases, same patterns.</p>
<p>If you keep rebuilding the same thing, at some point it should become a product.</p>
<figure class="video" data-youtube="R8HEWlsWraE">
  <button class="video-play" type="button" aria-label="Play the video: Joule.sh - The AI Workspace">
    <img src="/images/joule-video-poster.jpg" alt="The Joule workspace, running a research task" width="1280" height="720" loading="lazy" decoding="async">
    <span class="video-play-icon" aria-hidden="true"></span>
  </button>
</figure>
<h2>What Joule is</h2>
<p>Joule is an AI platform and workspace for individuals and enterprises to build, maintain and deploy AI workflows and agents.</p>
<p>Each word in that sentence is deliberate.</p>
<p>Platform, because the components work together as one system, not as a bag of SDKs you have to glue yourself.</p>
<p>Workspace, because it is where you actually operate day to day, not a control panel you visit once a month.</p>
<p>Build, maintain and deploy, because most AI tools stop at the demo stage and leave the operational reality to you.</p>
<p>Workflows and agents together, because real systems need both: agents for judgment, workflows for structure.</p>
<p>The distinction matters. The market is full of chatbots with plugins on one side and low-level frameworks on the other. The chatbots cap what you can build. The frameworks hand you a box of parts and a wish of good luck. Joule sits in the space between: the pieces every serious AI system needs, already built, already integrated, already running in production.</p>
<h2>The main components</h2>
<h3>Lumen Agents</h3>
<p>The backend and the core of the platform. It orchestrates agents and manages all configuration around them. It is open source, part of the Lumen standard contrib packages: Lumen - std-contrib</p>
<h3>The workflow engine</h3>
<p>Written in Lumen as well, it serves as the backbone of every agent workflow. Every step an agent takes runs through it. One core, one mental model, one place to look when something breaks.</p>
<h3>The search engine</h3>
<p>It provides RAG context to the models. We index 1 million pages each day and growing, with a fallback strategy born from a cost problem that turned into a product of its own. We never planned to build it. It is now one of the strongest parts of the platform.</p>
<h3>The frontend</h3>
<p>It runs on our own full stack web framework and design system. Owning the UI layer end to end means the platform evolves at the speed we decide, not at the speed of a dependency's release cycle.</p>
<h3>The MCP server</h3>
<p>It lets you integrate Joule directly into coding agents like Claude Code and Codex, and deploy or manage workflows and agents from inside your coding session. Everything through natural language.</p>
<h3>Tasks</h3>
<p>Tasks let agents work without a human in the loop. A task runs on a schedule or on a trigger, executes its workflow, and delivers the result. You do not prompt it. You define it once, and it works while you do something else.</p>
<h3>Document generation</h3>
<p>It turns agent output into real deliverables. Not text in a chat window, but actual documents, produced through a self-correcting loop where the agent fixes its own failures. The reliability comes from the loop design, not from prompt engineering.</p>
<h3>Knowledge</h3>
<p>Knowledge gives every agent its own grounded context through a file sync model. Folders attach to agents, agents become specialists, and specialists compose as sub-agents inside the workflow graph.</p>
<h3>Connectors</h3>
<p>Connectors link Joule to Atlassian, Asana, Linear and other platforms where work already happens. The difference from every chat product: connectors in Joule are not only conversation features. They are tasks and nodes in the workflow itself.</p>
<h3>Discover</h3>
<p>A feed of fresh, synthesized content, in the spirit of Perplexity's feed. It is the direct fruit of combining two components we already had: our own search engine, which knows what is fresh and in demand, and our agents, which turn that signal into substance. Nobody planned it. The architecture produced it.</p>
<h3>Live environments</h3>
<p>Live environments give agents a real place to execute. You define an environment per project: runtime, dependencies, credentials and tools, and everything that runs in that project runs inside it. Agents stop working in the abstract and start working in your actual context.</p>
<p>Joule is live at <a href="https://joule.sh/">joule.sh</a>. Try it, break it, tell me what's missing.</p>
<p>Ask. Search. Make.</p>
]]></content:encoded>
    </item>
    <item>
      <title>I Quit the Habit, Not the Hardware</title>
      <link>https://aymen.co/notes/i-quit-the-habit-not-the-hardware/</link>
      <guid isPermaLink="true">https://aymen.co/notes/i-quit-the-habit-not-the-hardware/</guid>
      <pubDate>Thu, 13 Aug 2026 00:00:00 GMT</pubDate>
      <description>Phone addiction is the condition of the moment. Everyone has it. You can throw the device away, but then you downgrade yourself. You block access to things…</description>
      <content:encoded><![CDATA[<p>Phone addiction is the condition of the moment. Everyone has it.</p>
<p>You can throw the device away, but then you downgrade yourself. You block access to things that actually work, and you make life harder for no real gain.</p>
<p>Some people carry sensors that talk to their phone. A CGM sensor on the arm, glucose numbers on the screen. Some live far from their family and the phone is the only line back. Going flip phone is going backward. That is not the answer.</p>
<p>None of that justifies how much we use it. None of it justifies the hooks.</p>
<p>Detox does not work either. You go clean for a week, then you come back and use it more than before. I ran all the tricks. Grayscale screen. App limits. Empty home screen. They buy you a few days.</p>
<p>What changed this time is simple. I am done.</p>
<p>Same feeling I had in 2019 when I quit social media. Not a plan, not a challenge, not a streak. A decision.</p>
<p>This year the decision was about how I use the phone, not whether I own one. I worked on it constantly because it was there. Accessible. Which meant I was in working mindset every waking hour. Work does not end when the laptop closes if the work fits in your pocket.</p>
<p>I have said this before. This time it feels different. The phone sits on my desk and I look at it with no appetite. Nothing pulls.</p>
<p>What made the difference is attention. Being conscious of where it goes, deliberately, all day. That is the best thing you can do for yourself. Focus on one task. Live it fully. Not half your mind on the work and the other half digesting what is happening on the screen in the background.</p>
<p>I still use blocking tools on the iPhone. They add friction. They do not lock me out. The lock has to come from me, otherwise I just find the way around it.</p>
<p>The other change is in how I handle ideas. I used to execute first and decide later. That built knowledge fast, and it built experience I still use. It also burned attention on things that did not deserve it.</p>
<p>Now I let an idea sit before I build it. Cognitive load is a real budget. With everything happening right now, you have to be selective about what you consume, and more selective about what you let occupy your head.</p>
<p>The battle continues. The difference is that I am no longer fighting the device. I am protecting my attention, and the phone is just one of the things trying to take it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Lumen - Write TypeScript, Compile to a native binary</title>
      <link>https://aymen.co/lumen/lumen-write-typescript-compile-to-a-native-binary/</link>
      <guid isPermaLink="true">https://aymen.co/lumen/lumen-write-typescript-compile-to-a-native-binary/</guid>
      <pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate>
      <description>Recently I&#39;ve been designing a programming language. Here&#39;s why.</description>
      <content:encoded><![CDATA[<p>Recently I've been designing a programming language. Here's why.</p>
<p>I love how Zig and Rust are fast and flexible. The control, the performance, the fact that what you ship is a real native binary. No runtime hiding behind it, no engine deciding things for you at 2am in production.</p>
<p>But every time I sat down to actually build something, I felt the tax.</p>
<p>More ceremony. More time fighting the compiler over things that had nothing to do with the problem I was solving. And a smaller pool of people who could read my code back to me.</p>
<p>Then I looked at the other side.</p>
<p>TypeScript's syntax is something most of the industry already speaks fluently. Interfaces, generics, async/await, arrow functions. Expressive without being exotic. Nobody needs a course to read it.</p>
<p>And that's when it clicked: the syntax was never the hard part of Rust or Zig. The runtime was.</p>
<p>TypeScript's problem was never how it looked. It was everything underneath it: a JS engine, a garbage collector, dynamic prototypes, and an npm install that pulls in a universe of transitive dependencies you never asked for.</p>
<p>So I started asking a different question.</p>
<p>This isn't the first time I've written a lexer, an AST, a type checker, a compiler. I've built that pipeline before. I know what it costs and I know what it takes. So this wasn't a leap into the unknown. It was pointing something I already knew how to build at a problem I'd actually felt.</p>
<p>What if you kept the syntax everyone already knows, and swapped out everything underneath it for something with Zig's discipline?</p>
<p>That's Lumen.</p>
<h3>What it actually is</h3>
<p>Lumen type-checks familiar TypeScript syntax, emits Zig, and compiles that straight to a small, dependency-free native binary. No VM. No garbage collector. No runtime.</p>
<p>You write this:</p>
<p>And you get a native executable. Not a bundle. Not a container with Node inside it. A binary.</p>
<p>Zig is the backend. Your TypeScript is type-checked, emitted as Zig, and compiled to a native binary from there.</p>
<p>The syntax you already know is all there: records and interfaces, generics, classes with extends and #private fields, template literals, try/catch/finally, async/await, map/filter/reduce. But it's a deliberate, static subset. No prototypes. No eval. No dynamic shapes that make the compiler guess.</p>
<h3>The decisions that make it different</h3>
<p>Generics are monomorphized. Write once over a type parameter, and each instantiation compiles to specialized code. No boxing, no runtime type juggling.</p>
<p>Closures compile. Capture your locals, and they get lowered to a heap environment, with no garbage collector waiting behind them.</p>
<p>Concurrency is real. Worker.run(fn) spawns an actual detached OS thread and hands you back a Promise<T>. Genuine CPU parallelism, not a simulated one, because there's no per-thread interpreter overhead to pay in the first place.</p>
<p>It talks to C directly. Write a declare function, link a C library, and call it. No bindings generator, no FFI ceremony. Strings and scalars marshal across the boundary for you.</p>
<p>And because there's no interpreter in the middle, some of this ends up faster than the runtime it borrows its syntax from. Anchored regex patterns compile to specialized native matchers at build time, around 3× faster than V8 on checks like semver and identifiers. A typed EventEmitter runs about 3.5× faster than Node's on a tight emit loop.</p>
<p>The standard library lives in the open, in std-contrib. Take the markdown package. Rendering a typical 3 KB document in a tight loop, it does about 6,775 renders/sec, against 2,020 for markdown-it and 1,064 for marked. That's roughly 3.4× faster than markdown-it and 6.4× faster than marked on the same document. Same reason every time: it compiles the parser instead of interpreting one.</p>
<p>Standard library: <a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Fgithub%2Ecom%2Flumen-lang-org%2Fstd-contrib&amp;urlhash=UtLG&amp;trk=article-ssr-frontend-pulse_little-text-block">github.com/lumen-lang-org/std-contrib</a></p>
<h3>A package is just a URL</h3>
<p>There's no package manager. No install step. No node_modules.</p>
<p>A simple module is just an import over HTTPS:</p>
<p>Lumen import with url</p>
<p>The .ts is fetched over HTTPS and inlined at compile time. A remote module can pull in its own siblings by relative path, fetched recursively, each URL fetched once per build. Only https:// is allowed, and remote code runs at build time. So you import from sources you trust, and you know exactly what went into your binary.</p>
<p>And it's not just source modules. You can pull in a C library the same way. The quickjs package embeds a full QuickJS sandbox through Lumen's FFI:</p>
<p>A C engine, embedded and running, imported from a URL. No build script, no bindings step, no package manager. That's the whole point.</p>
<h3>What I'm deliberately not doing</h3>
<p>I'm building out the standard library piece by piece: crypto, filesystem, networking, worker threads, all backed by real OS primitives, not polyfills.</p>
<p>But I'm being deliberate about what not to bring over from Node.js. I'm not chasing 100% API parity for its own sake.</p>
<p>Parity was never the goal. Discipline was.</p>
<p>std - lumen</p>
<h3>The same source, native or in the browser</h3>
<p>Lumen compiles to a native binary, or to WebAssembly, from the same source. The standard library is honest about the line between them: every function is marked for its target, so you know up front what runs everywhere and what's native-only. Pure computation, crypto, string and URL work, the event emitter, runs identically on both. The things that can't cross, raw syscalls, threads, direct filesystem access, are labeled, not silently broken.</p>
<p>This is also why the playground works the way it does. When you compile to WASM, a C dependency like the QuickJS engine gets linked straight into the compiled module. The whole program becomes one self-contained wasm file. So the QuickJS example above, a full JavaScript sandbox embedded through the FFI, runs in your browser with nothing installed. You're not looking at a simulation of the language. You're running the real compiler output.</p>
<p>The full standard library surface is at <a href="https://www.linkedin.com/redir/redirect?url=http%3A%2F%2Flumen-lang%2Eorg%2Fstdlib&amp;urlhash=VKEn&amp;trk=article-ssr-frontend-pulse_little-text-block">lumen-lang.org/stdlib</a>.</p>
<h3>The bet</h3>
<p>The core bet is simple: remove the runtime tax without asking anyone to learn a new mental model.</p>
<p>You already know the syntax. You shouldn't have to trade it away to ship a real binary.</p>
<p>There's a playground. Write Lumen and watch it compile in the browser, no install:</p>
<p><a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Flumen-lang%2Eorg%2Fplay&amp;urlhash=gyUu&amp;trk=article-ssr-frontend-pulse_little-text-block">https://lumen-lang.org/play</a></p>
<p>It's still early, and it's open. If that's a problem you've felt too, come look at the rest:</p>
<p>I'd love to hear what you think.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Spec-Driven Development (SDD)</title>
      <link>https://aymen.co/ai/spec-driven-development-sdd/</link>
      <guid isPermaLink="true">https://aymen.co/ai/spec-driven-development-sdd/</guid>
      <pubDate>Thu, 14 May 2026 00:00:00 GMT</pubDate>
      <description>There is a new artifact in the loop, and it sits above the code. Code used to be the only thing we wrote, the only thing we reviewed, the only thing we shipped.</description>
      <content:encoded><![CDATA[<p>There is a new artifact in the loop, and it sits above the code.</p>
<p>Code used to be the only thing we wrote, the only thing we reviewed, the only thing we shipped. Process and ceremony existed because code was expensive to produce and hard to change. That cost has dropped. A description of what we want can now generate working code in seconds, and we can iterate on the description faster than we used to iterate on the code itself.</p>
<p>So the loop has two artifacts now. The description, and the code generated from it. Both have to be right. Neither one replaces the other.</p>
<p>Which forces two questions to the surface. Is what the agent produced actually a reply to what we asked? And is the input we gave it clean enough to be worth replying to?</p>
<p>The first question I will cover in another article. This one is about the second. The spec.</p>
<hr>
<h3>Spec-driven is not vibe coding</h3>
<p>The opposite of spec-driven is not test-driven. It is vibe coding. Describe the goal, get a block of code back, hope it is what you meant. Fast, fun, and unreliable the moment the system has more than one moving part.</p>
<p>Spec-driven changes the order. You write the description first. The agent generates code from it. You review the code, you test it, you ship it. Both artifacts are real, both have to be right. The spec is what you start from. The code is what runs.</p>
<p>What changes is the relationship between them. The spec is the source the code is generated from, and the place fixes start. The code is still the thing that runs in production, and it still earns the same review and the same tests as anything you wrote by hand. Neither one carries the system alone.</p>
<hr>
<h3>The canonical workflow</h3>
<p>Two tools have made spec-driven a real workflow rather than a philosophy.</p>
<p>Spec Kit, from GitHub, formalized the approach. It splits the description into four artifacts: a constitution for non-negotiable principles the agent must respect across every feature, a spec for the what, a plan for the how, and a tasks breakdown for execution. The flow runs /constitution → /specify → /plan → /tasks → /implement, with clear phase gates. Thorough, opinionated, greenfield-friendly. The cost is weight. A Spec Kit change can generate eight hundred lines of markdown before any code is written.</p>
<p>OpenSpec, from Fission AI, is the lighter cousin. TypeScript instead of Python, npm install instead of toolchain setup, no rigid phase gates. Its distinctive idea is the delta spec. Instead of rewriting the whole description on every change, you describe what is being added, modified, or removed, and the deltas merge into the main specs after the change ships. Specs live alongside the code in the repository, which makes it brownfield-friendly in a way Spec Kit is not. Same change, around two hundred and fifty lines.</p>
<p>The two tools are not competing philosophies. They are different points on the same curve. Spec Kit treats specification as a first-class engineering phase with its own ceremony. OpenSpec treats it as a lightweight layer that sits next to the code and evolves with it. Same source-of-truth idea, different appetite for process.</p>
<p>Both are designed for the same shape of problem: one project, one codebase, one target. The spec exists so the agent does not drift, so requirements survive past the chat session, so the team aligns before code is written. That is the canonical use case.</p>
<hr>
<h3>Where we pushed it further</h3>
<p>The methodology has a principle inside it that is bigger than the tooling. The spec is the source of truth. The code is regenerated output. Fix the spec, not the code.</p>
<p>Once you internalize that principle, a question follows. If the code is regenerated output, why does there have to be only one of it?</p>
<p>We were writing a native mobile application. Android and iOS, sharing one project. For some features iOS owned its own behavior. Fine at first, the diff stayed small. Then it grew. Each platform needed its own visual identity, its own feel. The &quot;shared project with platform branches&quot; model started to bend.</p>
<p>The standard alternatives were the usual ones. Own three codebases and pay the synchronization cost forever. Or pick a cross-platform framework (Flutter, React Native, Kotlin Multiplatform) and accept the shared runtime, the shared idioms, the not-quite-native feel.</p>
<p>We tried a third path. One description. Multiple targets. Same source of truth, regenerated as native code for each platform. The agent writes idiomatic code for each one because it is generating, not transpiling. The spec never runs. There is no shared runtime. The cost is a regeneration step instead of a compile step, and the discipline of keeping the description honest across all three.</p>
<p>This is not what Spec Kit or OpenSpec ship out of the box. Neither tool advertises multi-target generation as a feature. We took the principle they encode (intent as source, code as output) and pushed it past the canonical workflow. The tools gave us the discipline. The discipline gave us the architecture.</p>
<p>We applied it to Android, iOS, and eventually web. Same description, three outputs. The agent is the compiler. That arrangement was not realistic three years ago. It is now.</p>
<hr>
<h3>Where we landed on the artifacts</h3>
<p>We did not start with Spec Kit or OpenSpec. We started with one file and let it grow. As the project grew, the file split itself almost naturally. Principles drifted into their own document, the architectural how drifted into another, feature behavior stayed in the middle, change-by-change deltas appeared on their own. By the time we read the docs of both tools, we recognized most of what was already on disk. The shape is convergent because the pressures are real.</p>
<p>The rest of this article uses &quot;spec&quot; loosely. It means the full description, across whatever files it ended up in.</p>
<hr>
<h3>What goes in the spec</h3>
<p>The first instinct is to put everything in. Resist it.</p>
<p>A spec is not documentation. Documentation describes what exists for a human reader. A spec describes what should exist for an agent that will build it. Different audience, different rules.</p>
<p>What goes in:</p>
<ul>
<li>
<p>Behavior. What the feature does, in plain language. Not what it looks like, not how it is implemented. What it does, when, in response to what.</p>
</li>
<li>
<p>Abstractions and data shapes. The objects the feature works with, the contracts between them, the invariants the agent must respect. This is the part the agent leans on hardest.</p>
</li>
<li>
<p>Algorithm snippets. Small, high-density pieces of logic the agent should not reinvent. Sorting rules, eligibility checks, pricing formulas. If it has subtle correctness requirements, it belongs in the spec.</p>
</li>
<li>
<p>Platform-divergent behavior. When iOS and Android genuinely diverge in what the feature does, name it once and explain why. Not a list of differences. A rule the agent can apply.</p>
</li>
</ul>
<p>What stays out:</p>
<ul>
<li>
<p>UI pixels. Spacing, colors, exact paddings. That belongs in a design system the agent reads separately. Mixing them turns every spec change into a visual review.</p>
</li>
<li>
<p>Prose explanation of why decisions were made. Useful for humans, noise for agents. Keep it in a sibling doc if you need it.</p>
</li>
<li>
<p>Platform-idiomatic UI and gestures. Navigation patterns, gesture handling, animation curves, lifecycle quirks. These live in per-platform layers the agent reads alongside the spec. The spec owns behavior and contracts. The platform layer owns feel.</p>
</li>
</ul>
<p>The test I use: would removing this line make the agent's output worse? If yes, keep it. If no, it does not belong.</p>
<hr>
<h3>What broke first</h3>
<p>Drift between platforms. A prompt-driven change to one platform's code does not automatically update the spec, and does not automatically propagate. You patch iOS, the spec is now a lie, Android falls behind, the next web regeneration is wrong. The rule we landed on: a change starts in the spec, the spec updates first, then the agent regenerates each platform from the new source. The regenerated code goes through the same review and tests as anything else.</p>
<p>That sounds obvious until you watch yourself break it. The agent will happily edit the generated code in place if you ask. Sometimes that is the right move for a one-off fix. But if the change has any chance of being relevant to the other platforms, it has to start at the spec, or the divergence is back. Discipline has to be wired into the prompt and the workflow. It is not the default.</p>
<p>Context window pressure. As the spec grew, the agent started going back and forth before committing to a solution. Propose, second-guess, re-read, propose again. Useful in small doses, expensive when the spec is large and most of it is irrelevant to the task at hand.</p>
<p>We started scoping which parts of the spec load for which task. Keep the relevant section dense, keep the rest out of the way. Code generation went back to working like before. Sometimes better, because the agent was not drowning in spec it did not need.</p>
<hr>
<h3>What actually changes</h3>
<p>You now have two artifacts to keep right instead of one. The spec, and the code generated from it.</p>
<p>Reviews split along that line. You review the spec for intent. Does it describe the system you want, in a way an agent can build from. You review the generated code for correctness. Does it do what the spec says, does it run, does it pass the tests. Both reviews matter. Skipping the code review because the spec is good is how regressions ship. Skipping the spec review because the code looks fine is how the next regeneration silently breaks something.</p>
<p>You stop owning three implementations of the same feature and start owning one description of it. You stop arguing about which platform got it right and start arguing about what right means, once, in the spec. The code still has to be read. It just gets read against the spec instead of against itself.</p>
<p>When something is wrong, you check both. If the spec is wrong, you fix it there and regenerate. If the spec is right and the code drifted, you regenerate. If the spec is right and the code is right but the behavior is wrong, the spec was incomplete. Fix the spec, regenerate. The fix almost always lands in the spec, but the code is what tells you it landed.</p>
<p>If you are running a spec-driven loop and have hit different walls than these, I want to hear about it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>LumenJS deep dive — Lazy Hydration</title>
      <link>https://aymen.co/lumen/lumenjs-deep-dive-lazy-hydration/</link>
      <guid isPermaLink="true">https://aymen.co/lumen/lumenjs-deep-dive-lazy-hydration/</guid>
      <pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate>
      <description>This article is part of the LumenJS deep dive series a series about the architectural decisions behind LumenJS, an open-source full-stack web framework designed for agent-driven…</description>
      <content:encoded><![CDATA[<p>This article is part of the LumenJS deep dive series a series about the architectural decisions behind LumenJS, an open-source full-stack web framework designed for agent-driven development.</p>
<ul>
<li><a href="/lumen/lumenjs-deep-dive-loaders/">Loaders</a></li>
<li><a href="/lumen/lumenjs-deep-dive-subscribe/">Subscribe</a></li>
<li><a href="/lumen/lumenjs-deep-dive-socket/">Socket</a></li>
<li><a href="/lumen/lumenjs-deep-dive-llms-txt/">llms.txt</a></li>
</ul>
<p>Every component on a page costs JavaScript. Most of the time that cost is invisible. But on content-heavy pages (blog posts, dashboards, feeds), it adds up. You end up shipping and executing code for components the user may never scroll to.</p>
<p>Lazy hydration solves that.</p>
<h2>Lazy Hydration</h2>
<p>Wrap any component in <nk-island> and its JavaScript module is code-split out of the page bundle. As long as nothing else imports the module statically, the bundler ships it in its own chunk. Instead of arriving with the page, you choose when it loads: on page load, on scroll, when the browser is idle, or when a media query matches.</p>
<p><img src="/images/lumenjs-deep-dive-lazy-hydration-1.png" alt="Code sample from lazy-hydration" loading="lazy" decoding="async"></p>
<p>Everything outside <nk-island> hydrates normally. SSR is unchanged, with one caveat: for the component inside the island to render server-side, its module still has to be in the page's import graph (through a page or layout import). The import attribute on <nk-island> is a client-side URL only. What the island defers is when the JavaScript arrives on the client.</p>
<h2></h2>
<h2>Hydration strategies</h2>
<p>Four strategies, each with a clear purpose.</p>
<p>client:load - loads immediately on page load. Use it for interactive content visible on first paint.</p>
<p>client:visible - defers loading until the component scrolls into the viewport. A comments block, a reactions widget, a heavy chart none of them need JavaScript until the user actually reaches them.</p>
<p>client:idle - loads when the browser is idle. Good for low-priority components that should hydrate soon but are not critical for first interaction.</p>
<p>client:media - loads only when a CSS media query matches. Perfect for components whose JavaScript is only useful at certain screen sizes, a desktop sidebar, a mobile-only drawer.</p>
<p><img src="/images/lumenjs-deep-dive-lazy-hydration-3.png" alt="Code sample from lazy-hydration" loading="lazy" decoding="async"></p>
<h2>How it works</h2>
<p>When the chosen strategy triggers, the module is dynamically imported and the custom element registers itself. From that point on, the component behaves like any other element on the page.</p>
<p>No config flag. No setup. The runtime is included on every page and only activates when <nk-island> elements are present. Observers and listeners are one-shot. They release themselves after hydration fires.</p>
<h2>Escape hatches</h2>
<p>A few details matter once you start using islands in real pages.</p>
<p>data-hydrated lands on the element once the module loads. Useful for E2E tests waiting on hydration, for CSS that should only apply after the component is live, and for debugging which islands have fired.</p>
<p>island-hydrated is a bubbling, composed event dispatched at the same moment. Listen for it on any ancestor when you need to chain behavior: preload an analytics module, kick off a second island, mark a region as ready.</p>
<p>window.__nk_islands is a registry the runtime checks before doing a dynamic import. If a host has populated it with a loader for the import path, the island uses that loader. Otherwise the runtime falls back to import(path). This gives a project an escape hatch to wire islands into its bundle graph instead of relying on raw URL imports.</p>
<h2>In practice</h2>
<p>A content-heavy page where the reactions widget only loads when the user scrolls to it:</p>
<p><img src="/images/lumenjs-deep-dive-lazy-hydration-4.png" alt="Code sample from lazy-hydration" loading="lazy" decoding="async"></p>
<p>The page renders fully on the server. The article content hydrates immediately. The reactions widget waits. First paint is fast, interaction cost is deferred.</p>
<h2>Composing with component loaders</h2>
<p>LumenJS lets any Lit component, not just a page, export its own loader(). The data is fetched server-side, stripped from the client bundle, and inlined into the SSR'd HTML. The component owns its data dependency.</p>
<p>Pair that with an island and the two principles compose on a single component. The component loader runs on the server and produces the reactions count. The widget is rendered into HTML with that data and shipped. No client JavaScript. When the user reaches the widget, the island imports its module, the element registers, and the component takes over the SSR'd region, now interactive.</p>
<p>Server work runs only for pages that include the widget. Client JavaScript runs only for users who scroll to it. Each layer defers what it controls. The page composes them.</p>
<h2>Conclusion</h2>
<p>Lazy hydration in LumenJS is one custom element, <nk-island>, that defers a dynamic import() until a trigger fires: page load, viewport intersection, browser idle, or media query match. The server-rendered DOM stays visible in the meantime. The component module replaces it when it arrives.</p>
<p>The cost is not free. Each island adds a custom element to the DOM and, depending on the strategy, an observer or listener until the trigger fires. For above-the-fold critical UI, plain hydration is faster: the JS would have shipped anyway, and the extra element is overhead. The win shows up below the fold, on long pages, where most of the component tree is JavaScript the user may never reach.</p>
<p>Lazy hydration is not a default. It is a tool you reach for when a component does not need its JavaScript on first paint. Used in the right places, the page becomes lighter without the user noticing anything changed.</p>
]]></content:encoded>
    </item>
    <item>
      <title>LumenJS deep dive — llms.txt</title>
      <link>https://aymen.co/lumen/lumenjs-deep-dive-llms-txt/</link>
      <guid isPermaLink="true">https://aymen.co/lumen/lumenjs-deep-dive-llms-txt/</guid>
      <pubDate>Sat, 02 May 2026 00:00:00 GMT</pubDate>
      <description>This article is part of the LumenJS deep dive series — a series about the architectural decisions behind LumenJS, an open-source full-stack web framework designed for agent-driv…</description>
      <content:encoded><![CDATA[<p>This article is part of the LumenJS deep dive series — a series about the architectural decisions behind LumenJS, an open-source full-stack web framework designed for agent-driven development.</p>
<ul>
<li><a href="/lumen/lumenjs-deep-dive-loaders/">Loaders</a></li>
<li><a href="/lumen/lumenjs-deep-dive-subscribe/">Subscribe</a></li>
<li><a href="/lumen/lumenjs-deep-dive-socket/">Socket</a></li>
</ul>
<p>We build LumenJS to be agent-ready. Not as a feature - as a principle. One small example of that is how we handle /llms.txt.</p>
<h2>llms.txt</h2>
<p>Every LumenJS project automatically serves a /llms.txt endpoint. No config. No setup. An AI tool hitting that URL gets a plain text map of your entire application pages, routes, data, features.</p>
<p>The idea comes from the <a href="https://llmstxt.org">llmstxt.org</a> convention. We just made it automatic.</p>
<p>When a request hits /llms.txt, LumenJS scans every page and API route in your project, calls their loaders, expands dynamic routes by discovering all entries, and renders everything as readable plain text.</p>
<p><img src="/images/lumenjs-deep-dive-llms-txt-1.png" alt="Code sample from llmstxt" loading="lazy" decoding="async"></p>
<p><img src="/images/lumenjs-deep-dive-llms-txt-2.png" alt="Code sample from llmstxt" loading="lazy" decoding="async"></p>
<h2>Why it matters</h2>
<p>An agent working on your codebase does not need to read every file to understand what the application does. It reads /llms.txt and gets the full picture in seconds - routes, data shapes, active features.</p>
<p>This is the same reason we built loaders the way we did. Colocation. Every unit tells the full story of what it contains. /llms.txt is that principle applied at the application level.</p>
<h2>Dynamic routes</h2>
<p>For routes like /blog/:slug, LumenJS does not just list them. It calls the parent loader to discover all entries, then calls each dynamic page's loader to render the full content. The result is a real map of your data, not just your code structure.</p>
<p>If the database is empty or a loader fails, the route falls back to - Dynamic route. No crash, no incomplete output.</p>
<p>Routes that export auth = true are excluded. The expansion mechanism detects the auth flag and skips them private data stays private, even in a public endpoint.</p>
<h2>Override</h2>
<p>If you need a hand-crafted version, place a file at public/llms.txt. LumenJS detects it and serves it as-is, skipping auto-generation entirely.</p>
<p><img src="/images/lumenjs-deep-dive-llms-txt-3.png" alt="Code sample from llmstxt" loading="lazy" decoding="async"></p>
<h2>Conclusion</h2>
<p>/llms.txt is a small feature with a clear purpose. It makes your application readable to the tools that will work on it agents, assistants, pipelines. Zero configuration because it should not require any. The framework knows your routes, your loaders, your data. It does the work.</p>
<p>Agent-ready is not a mode you turn on. It is how the framework is built.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Claude Code is Awesome. Still Not Enough.</title>
      <link>https://aymen.co/ai/claude-code-is-awesome-still-not-enough/</link>
      <guid isPermaLink="true">https://aymen.co/ai/claude-code-is-awesome-still-not-enough/</guid>
      <pubDate>Mon, 27 Apr 2026 00:00:00 GMT</pubDate>
      <description>In the last two years I&#39;ve generated thousands, probably millions of lines of code. Long-running agents.</description>
      <content:encoded><![CDATA[<p>In the last two years I've generated thousands, probably millions of lines of code. Long-running agents. Live sessions. Like every developer right now.</p>
<p>To ship production, that's not enough.</p>
<p>Vendors will sell you anything. They'll tell you they put agents in their pipeline and ship production code. Not true yet. I'm working across multiple projects, from products and tooling used inside big tech companies to startup R&amp;D. I invest heavily in coding agents and live coding. Here's what I've learned so far.</p>
<hr>
<h2>Code is cheap. That doesn't mean you should buy it.</h2>
<p>A beautifully generated piece of code is compelling. Watching it build, run, ship on the first try feels great.</p>
<p>Then ask yourself: from that moment, what's the drift from version one? 50%? 60%? I'd say 80%.</p>
<p>Why? Because the first version is never mature. And now you're in the rewrite loop.</p>
<p>Even with a clean instruction.md or claude.md, you still get code duplication. You still get drift. You still get the &quot;yes, you're right…&quot; message. And you start losing track of what state your code is actually in.</p>
<p>Say you land on a good version. You wrote unit tests. You feel solid. Then you read through the full thing and decide it could be more maintainable. Even if you asked for maintainable code from the start. Another rewrite. Update the tests. Run QA again.</p>
<p>You're in a cycle. You're not shipping.</p>
<p>The code is cheap. The rewrite is cheap too. Nothing feels stable anymore.</p>
<hr>
<h2>What you gain, what you lose</h2>
<p>You do learn. New patterns. New ways of doing things. That's real.</p>
<p>But that's not the point. The point is to ship a working, maintainable application.</p>
<p>I lived this on one of my own projects. The agent generated a working module on the first pass. I ran it. It built. It passed tests. Then I read it and saw three places where the same logic was reimplemented with different names. I asked for a refactor. The refactor introduced a new pattern that conflicted with how the rest of the codebase handled errors. Another pass. By the time the module looked clean, the test suite needed a rewrite to match the new shape.</p>
<p>Net progress: zero features shipped. Net learning: a lot. Net feeling: busy.</p>
<p>Right now everyone feels busy and building. A small portion is shipping real production. Incremental shipping has never been easier, and yet the loop is so compelling it pulls you away from shipping.</p>
<hr>
<h2>When the loop works</h2>
<p>It would be dishonest to stop here. The loop does work. I've seen it.</p>
<p>On my own agentic coding pipeline, I built two workflows that handle GitHub issues end to end. One for immediate bug fixes. One for plan-first feature work. Both run with quality gates, Docker testing, and notifications back to me. The agent does the heavy lifting. I review and merge.</p>
<p>The reason it works isn't the agent. It's the surrounding infrastructure. The pipeline has clear contracts. The quality gates are non-negotiable. The agent operates inside a frame I designed before I let it touch anything.</p>
<p>Same story with LumenJS, the framework I open-sourced this year. Web components on web standards, file-based routing, server boundaries the framework physically enforces. Half the reasons I built it that way exist because an agent is the primary developer. Less room to go wrong. The framework is the structured surface. The agent is the worker. The structure came first.</p>
<p>That's the pattern. The agent isn't the system. The agent works inside one.</p>
<hr>
<h2>So how do you survive</h2>
<p>You stick with a stack you actually know. The moment you let the agent pick everything, you lose ownership. You also lose the ability to debug it when it breaks.</p>
<p>You resist the buzz from the magic generation. That feeling is a fake sense of accomplishment. Too good to be true. 99% of the time, the real work is still ahead of you. The build passing is not the finish line. It's barely the start.</p>
<p>You invest in infrastructure more than before. Start with a solid layer: architecture, must-use and must-not-use patterns, data flow, component responsibilities, testing infrastructure, CI. Everything from day one. That's what lets you plug in a coding agent and actually get value out of it. Small, validated, incremental steps. You leverage the agent and you keep ownership and control.</p>
<p>This is the part most teams skip. They want the agent first and the structure later. It doesn't work in that order. The structure is what makes the agent useful.</p>
<p>You still need to learn how to code, more than before. You still need to try patterns and learn their tradeoffs. You still need to master the agent's tools and make them work for you. The skill ceiling went up, not down. The agent makes the floor higher and the ceiling further away at the same time.</p>
<p>And you still own the agent's output. If you ship code you don't understand and it breaks, that's on you. Not the agent. Not the vendor. You.</p>
<hr>
<h2>What this means for engineering leaders</h2>
<p>If you run a team and you're being pitched on agent-driven development as a productivity multiplier, ask one question: what's the infrastructure my team needs in place before the agent makes us faster?</p>
<p>If the answer is &quot;none, just turn it on,&quot; walk away.</p>
<p>The teams getting real leverage from coding agents right now are not the teams with the most agents. They're the teams with the cleanest contracts, the strictest quality gates, and the engineers who still read every diff before it merges.</p>
<p>Code is cheap. Judgment is not. Infrastructure is not. Ownership is not.</p>
]]></content:encoded>
    </item>
    <item>
      <title>LumenJS deep dive — Socket</title>
      <link>https://aymen.co/lumen/lumenjs-deep-dive-socket/</link>
      <guid isPermaLink="true">https://aymen.co/lumen/lumenjs-deep-dive-socket/</guid>
      <pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate>
      <description>This article is part of the LumenJS deep dive series a series about the architectural decisions behind LumenJS, an open-source full-stack web framework designed for agent-driven…</description>
      <content:encoded><![CDATA[<p>This article is part of the LumenJS deep dive series a series about the architectural decisions behind LumenJS, an open-source full-stack web framework designed for agent-driven development.</p>
<ul>
<li><a href="https://www.linkedin.com/posts/labidi-aymen_lumenjs-opensource-fullstack-activity-7449086801660727296-Z1mk?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAAwYWYkBJCNcptQuOElbelqXoOJ3m3fc5-k&amp;trk=article-ssr-frontend-pulse_little-text-block">Loaders</a></li>
<li><a href="https://www.linkedin.com/posts/labidi-aymen_lumenjs-activity-7451555202505170944-vZ80?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAAAwYWYkBJCNcptQuOElbelqXoOJ3m3fc5-k&amp;trk=article-ssr-frontend-pulse_little-text-block">Subscribe</a></li>
</ul>
<p>subscribe() solved one direction. Server pushes, client listens. But some features need both sides talking. Chat, collaborative editing, presence, games. For that we added socket().</p>
<h2>Socket</h2>
<p>Same pattern, different primitive. Each page can export a socket() function. It runs on the server, sets up event listeners, and gives you a two-way channel — the client can send, the server can respond or broadcast.</p>
<p><img src="/images/lumenjs-deep-dive-socket-1.png" alt="Code sample from socket" loading="lazy" decoding="async"></p>
<p>The server listens with on(). It pushes back with push(). It broadcasts to a room with room.broadcast(). The cleanup function runs when the client disconnects.</p>
<p>On the component side, the framework injects an emit() method automatically, no wiring, no import.</p>
<p><img src="/images/lumenjs-deep-dive-socket-2.png" alt="Code sample from socket" loading="lazy" decoding="async"></p>
<p>That's the full loop. Client emits, server receives, server broadcasts, components update.</p>
<p><img src="/images/lumenjs-deep-dive-socket-3.png" alt="Code sample from socket" loading="lazy" decoding="async"></p>
<h2>Rooms</h2>
<p>Rooms are first-class. Join on connect, leave on disconnect, broadcast to everyone or everyone except the sender.</p>
<p><img src="/images/lumenjs-deep-dive-socket-4.png" alt="Code sample from socket" loading="lazy" decoding="async"></p>
<p>broadcast() excludes the sender. broadcastAll() includes everyone. Pick what fits.</p>
<h2>When to use subscribe vs socket</h2>
<p>The decision is simple. If the data only flows one way, server to client, use subscribe(). It uses native SSE, zero dependencies. If the client needs to send events too, use socket(). It uses <a href="https://socket.io">Socket.IO</a>, installed separately with lumenjs add socketio.</p>
<p>No overhead either way. <a href="https://socket.io">Socket.IO</a> client is only loaded on pages that export a socket() function.</p>
<h2>When socket grows</h2>
<p>Same rule as loaders and subscribe. Move the handler out to _socket.ts in the page folder. LumenJS picks it up automatically.</p>
<p><img src="/images/lumenjs-deep-dive-socket-5.png" alt="Code sample from socket" loading="lazy" decoding="async"></p>
<h2>Conclusion</h2>
<p>Three primitives. loader() for initial data. subscribe() for server push. socket() for bidirectional communication. Each one follows the same convention, a named export, collocated with the component, stripped from the client bundle.</p>
<p>The tradeoff here is infrastructure. <a href="https://socket.io">Socket.IO</a> needs a stateful server with sticky sessions. Traditional serverless functions don't fit. Plan for it before you reach for it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Agentic DevTeam @Nuraly</title>
      <link>https://aymen.co/ai/agentic-devteam-at-nuraly/</link>
      <guid isPermaLink="true">https://aymen.co/ai/agentic-devteam-at-nuraly/</guid>
      <pubDate>Wed, 22 Apr 2026 00:00:00 GMT</pubDate>
      <description>One of the most challenging parts of the software development cycle is maintenance. Over time, teams face turnover, loss of expertise, and shrinking bandwidth leaving little room to secure, enhance, or fix what&#39;s already in production.</description>
      <content:encoded><![CDATA[<p>One of the most challenging parts of the software development cycle is maintenance. Over time, teams face turnover, loss of expertise, and shrinking bandwidth leaving little room to secure, enhance, or fix what's already in production.</p>
<p>We faced these exact problems. Here's how we overcame them using coding agents.</p>
<hr>
<h2>Humans are mission-driven. So are our agents.</h2>
<p>At work, at home, in life we each operate around a set of missions. We applied the same model to our agents. We built an agentic team around our tools and gave each agent a defined set of missions to carry out over time.</p>
<p>Our job as humans doesn't disappear it shifts. We create missions, specify timing and frequency, and let agents execute. Then we observe for drift, update missions that are complete, and retire ones that no longer fit the current state of the project.</p>
<hr>
<h2>Start small. Start safe.</h2>
<p>We began by identifying mission types with low risk and clear scope: daily improvements, security checks, bug detection. The kind of work a single agent can handle with little chance of going off course.</p>
<hr>
<h2>The code flow: GitHub as source of truth</h2>
<p>Here's the pipeline we use to develop and maintain both LumenJS and the Nuraly platform.</p>
<ol>
<li>
<p>Issue creation A mission scans the codebase and creates a ticket for a specific task. If a similar ticket already exists, the agent skips it.</p>
</li>
<li>
<p>Implementation Another mission picks up the ticket, creates a branch, implements the fix or feature, opens a PR, and iterates until checks pass build, tests, and SonarQube pipelines. If something breaks, a separate agent takes over to fix it.</p>
</li>
<li>
<p>PR review On our SaaS, we maintain a next branch before anything goes live. A review agent inspects each PR: if the changes are small and obvious, it merges to next. Otherwise, it leaves a comment requesting improvements. The cycle stays open another agent picks up the PR, evaluates the feedback, and either pushes back (if the change isn't worth it) or implements what's requested. To avoid burning tokens, we cap the number of retry attempts.</p>
</li>
<li>
<p>Human validation Once the PR is green, a human steps in to validate what the agent has done before anything ships.</p>
</li>
</ol>
<hr>
<h2>Missions are scoped by project.</h2>
<p>Each project has its own set of missions. What we've found: small, incremental changes over time give us more control and visibility than large codebases nobody has the bandwidth to manage.</p>
<hr>
<h2>The human role doesn't disappear, it shifts.</h2>
<p>This is the part people often misunderstand about agentic systems. Agents don't replace human judgment. They replace human execution of repetitive, well-defined tasks.</p>
<p>Here's how the responsibility actually divides:</p>
<ul>
<li>
<p>Humans define the mission its scope, timing, retry limits, and success criteria. Humans observe for drift and decide when a mission is stale or needs updating. Humans do the final validation before anything ships.</p>
</li>
<li>
<p>Agents execute they create tickets, open branches, push code, iterate through fix loops, and auto-merge small obvious changes. They work continuously, within the boundaries they've been given.</p>
</li>
</ul>
<p>The key insight: as long as missions stay small and well-scoped, agents stay predictable. The human overhead doesn't scale with the number of agents it scales with the number of missions you define, which is a much smaller number.</p>
<hr>
<h2>The shift is worth it.</h2>
<p>We didn't need more developers or more sprints. We needed a different model small missions, running continuously, with humans staying in the loop at the right moments.</p>
<p>What surprised us most wasn't what the agents could do. It was the clarity the mission model forced on us. When you define work precisely enough for an agent to execute it, vague tickets stop being acceptable.</p>
<p>Small changes compound. Drift is the real risk. And the loop never fully closes without a human that's not a limitation, it's the point.</p>
]]></content:encoded>
    </item>
    <item>
      <title>LumenJS deep dive — Subscribe</title>
      <link>https://aymen.co/lumen/lumenjs-deep-dive-subscribe/</link>
      <guid isPermaLink="true">https://aymen.co/lumen/lumenjs-deep-dive-subscribe/</guid>
      <pubDate>Sun, 19 Apr 2026 00:00:00 GMT</pubDate>
      <description>One of the decisions you make early when building a framework is how to handle real-time data. Most solutions reach for WebSockets, third-party libraries, or client-side polling…</description>
      <content:encoded><![CDATA[<p>One of the decisions you make early when building a framework is how to handle real-time data. Most solutions reach for WebSockets, third-party libraries, or client-side polling. We went a different direction.</p>
<h2>Subscribe</h2>
<p>The same colocation principle behind loaders applies here. Each page can export a subscribe() function. It runs on the server, stays alive for the entire duration the user is on the page, and pushes data to the client over SSE, Server-Sent Events, native to the browser, zero dependencies.</p>
<p><img src="/images/lumenjs-deep-dive-subscribe-1.png" alt="Code sample from subscribe" loading="lazy" decoding="async"></p>
<p>The function starts when the user lands on the page. Every call to push() delivers data to the client. Each key in the pushed object becomes a reactive property on the component - same pattern as loader(). The function ends when the user navigates away.</p>
<p><img src="/images/lumenjs-deep-dive-subscribe-2.png" alt="Code sample from subscribe" loading="lazy" decoding="async"></p>
<h2>Cleanup</h2>
<p>subscribe() is not a one-shot handler. It is a persistent process. Which means you are responsible for what you start. Always return a cleanup function — it runs when the client disconnects.</p>
<p><img src="/images/lumenjs-deep-dive-subscribe-3.png" alt="Code sample from subscribe" loading="lazy" decoding="async"></p>
<p>No cleanup means leaked connections and dangling intervals. The framework gives you the hook - use it.</p>
<h2>Loader and subscribe together</h2>
<p>They are designed to work on the same page. loader() handles the initial data. subscribe() handles what changes after. The component declares the properties once and receives data from both sources.</p>
<p><img src="/images/lumenjs-deep-dive-subscribe-4.png" alt="Code sample from subscribe" loading="lazy" decoding="async"></p>
<p><img src="/images/lumenjs-deep-dive-subscribe-5.png" alt="Code sample from subscribe" loading="lazy" decoding="async"></p>
<p>Page loads with real data. Updates arrive as they happen. No client-side fetching logic, no state management, no polling.</p>
<h2>When subscribe grows</h2>
<p>Same rule as loaders. When the handler gets complex, move it out. Place a _subscribe.ts file in the page folder and LumenJS picks it up automatically.</p>
<p><img src="/images/lumenjs-deep-dive-subscribe-6.png" alt="Code sample from subscribe" loading="lazy" decoding="async"></p>
<p>The page stays focused on rendering. The server logic lives where it belongs.</p>
<h2>Conclusion</h2>
<p>Subscribe extends the loader idea into the time dimension. Loaders answer the question: what does this page need to render? Subscribe answers: what does this page need to stay current?</p>
<p>Both follow the same principle server logic collocated with the component that needs it, stripped from the client bundle, with no wiring required.</p>
<p>The tradeoff is the same too. A subscribe handler is a persistent server process. Every active user keeps it alive. For pages with heavy watchers or expensive streams, that cost adds up. Design for it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>LumenJS deep dive — Loaders</title>
      <link>https://aymen.co/lumen/lumenjs-deep-dive-loaders/</link>
      <guid isPermaLink="true">https://aymen.co/lumen/lumenjs-deep-dive-loaders/</guid>
      <pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate>
      <description>One of the best things about building a framework is that you get to fix what bothers you in others, and simplify what was never meant to be complex. Everything has tradeoffs. T…</description>
      <content:encoded><![CDATA[<p>One of the best things about building a framework is that you get to fix what bothers you in others, and simplify what was never meant to be complex. Everything has tradeoffs. This is about one feature that made LumenJS work for us.</p>
<h2>Loaders</h2>
<p>Grouping related logic into a single unit is one of the best architectural decisions you can make. It helps with maintenance, onboarding whether that's a human or an agent.</p>
<p>For the web, we have components. Angular, React, Vue, and also Web Components the native browser primitive. What we did is take Web Components, enhance them with server-side logic, and add loaders.</p>
<p>Each page can export a loader(). It runs on the server, on every request, and the returned properties are injected into the component. It's a layer on top not a rewrite. The component keeps working exactly as before, with either injected properties from the parent or data loaded from the server.</p>
<p><img src="/images/lumenjs-deep-dive-loaders-1.png" alt="Code sample from loaders" loading="lazy" decoding="async"></p>
<p>Each key in the return object becomes a reactive property on the component. No wiring. No boilerplate.</p>
<p><img src="/images/lumenjs-deep-dive-loaders-2.png" alt="Code sample from loaders" loading="lazy" decoding="async"></p>
<h2>When loaders grow</h2>
<p>When everything lives in one file, it grows fast. For pages with complex server logic, this becomes unmaintainable. Two options:</p>
<p>Split logic into service functions inside the same file. Or move the loader out entirely place a _loader.ts file in the page folder and LumenJS picks it up automatically. No import, no wrapper.</p>
<p><img src="/images/lumenjs-deep-dive-loaders-3.png" alt="Code sample from loaders" loading="lazy" decoding="async"></p>
<p>The page file stays clean. The loader lives where it belongs.</p>
<h2>The same idea, at component scale</h2>
<p>Page loaders solve the data-fetching problem at the route level. But the same pattern works for any component in your project.</p>
<p>A sidebar needs user preferences. A dashboard widget needs its own slice of data. Each of these can export a loader() same syntax, same server-side guarantees, automatically stripped from the client bundle. No mixin, no wiring.</p>
<p>Where it gets interesting is with lazy components. A heavy comments section think Disqus-style, loaded only when the user scrolls down can own its backend logic too. The loader runs when the component enters the viewport, not on page load. The database query, the auth check, the pagination all of it stays collocated inside the component and executes only when needed. You save execution time and keep the first paint fast.</p>
<p><img src="/images/lumenjs-deep-dive-loaders-4.png" alt="Code sample from loaders" loading="lazy" decoding="async"></p>
<p><img src="/images/lumenjs-deep-dive-loaders-5.png" alt="Code sample from loaders" loading="lazy" decoding="async"></p>
<h2>Conclusion</h2>
<p>The boundary between &quot;page data&quot; and &quot;component data&quot; disappears. Every unit owns its server logic collocated, self-contained, deferred until needed.</p>
<p>Co-location at every scale: page, component, viewport. The tradeoff is real though you give up the familiar separation of frontend and backend files. And loaders can be misused. A component with a loader rendered inside a map triggers one server call per instance. N+1.</p>
<p>The rule is simple: loaders are for components that own their data independently. If the data belongs to the list, load it in the page loader and pass it down.</p>
<p>When used in the right place, the tradeoff is worth it.</p>
<p>Loader examples : <a href="https://github.com/Nuralyio/lumenjs/tree/main/examples/loaders">https://github.com/Nuralyio/lumenjs/tree/main/examples/loaders</a></p>
<p>Documentation: <a href="https://lumenjs.dev">https://lumenjs.dev</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>LumenJS - A framework designed for coding agents</title>
      <link>https://aymen.co/lumen/lumenjs-a-framework-designed-for-coding-agents/</link>
      <guid isPermaLink="true">https://aymen.co/lumen/lumenjs-a-framework-designed-for-coding-agents/</guid>
      <pubDate>Wed, 08 Apr 2026 00:00:00 GMT</pubDate>
      <description>Most frameworks are designed for developers. LumenJS is designed for coding agents and the developers who work with them.</description>
      <content:encoded><![CDATA[<p>Most frameworks are designed for developers. LumenJS is designed for coding agents and the developers who work with them.</p>
<p>That distinction matters more than it sounds.</p>
<p>LumenJS is a full-stack web component framework and platform built with TypeScript. File-based routing, server loaders, SSR, authentication, real-time communication, database, storage - everything you need to build a production application, in one coherent system built on web standards.</p>
<h2>We Didn't Guess. We Observed.</h2>
<p>We paid close attention to how coding agents actually behave in practice - what they struggle with, where they drift, what structures they naturally produce correct output in.</p>
<p>That feedback is embedded in every design decision LumenJS makes. When a pattern caused agents to go wrong, we changed the framework. When agents reliably produced clean output in a certain structure, we made that structure the default.</p>
<h2>We've Done This Before</h2>
<p>Back in 2019 before LLMs, before any of this we built <a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Fgithub%2Ecom%2Fsustainland%2Fsustain&amp;urlhash=mPlU&amp;trk=article-ssr-frontend-pulse_little-text-block">SustainJS</a>. Same instinct: something about how web apps were being structured felt wrong, so we built what we thought was right.</p>
<p>Then the LLM era arrived. While building <a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Fnuraly%2Eio%2F&amp;urlhash=Dj1-&amp;trk=article-ssr-frontend-pulse_little-text-block">Nuraly</a>, we went through framework after framework React, Astro, separate frontend and backend projects. Each one had the same problem: designed for humans writing deliberately, not agents generating at speed.</p>
<p>So we concluded, for the second time, that we had to build our own. Except this time, we had coding agents to help us build it.</p>
<h2>Native Technologies. By Conviction.</h2>
<p>We've said this before: we build on native and near-native technologies because they last.</p>
<p>We chose Lit Element as the renderer for <a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Fgithub%2Ecom%2FNuralyio%2FNuralyUI&amp;urlhash=T_-x&amp;trk=article-ssr-frontend-pulse_little-text-block">NuralyUI</a>. Now LumenJS takes web components to the next level a full-stack platform where routing, server data, and real-time subscriptions are all built around the same browser standard.</p>
<p>No deprecation dates. No migration guides waiting to be written. Just the platform.</p>
<p>pages/dashboard.ts auth, data, and real-time in one file</p>
<h2>A Platform, Not Just a Framework</h2>
<p><a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Flumenjs%2Edev%2F&amp;urlhash=K6oh&amp;trk=article-ssr-frontend-pulse_little-text-block">LumenJS</a> ships with production-ready modules built in. Authentication with 2FA. A full communication stack with chat, conversations, and WebRTC calls. Not integrations to wire up. Not tutorials to follow. They are there, they work, you use them.</p>
<p>The difference between a framework and a platform is whether you spend the first week building infrastructure or building your product.</p>
<h2>Proof of Concept? We Call It Production.</h2>
<p>We are rewriting Nuraly on top of LumenJS. Not a demo. Not a side project. The full platform - calls, shared workflows, collaborative session building, live execution. Everything we needed it to handle, it handles.</p>
<p>When something breaks, we fix it. That is the only kind of reliability test that matters.</p>
<h2>The Visual Editor</h2>
<p>We started with a low-code studio. Low-code has a ceiling.</p>
<p>So we pivoted to an augmented code visual editor a visual layer on top of real code, not a replacement for it. LLM coding agents work alongside it, accelerating the writing while the editor makes output legible.</p>
<p>Same philosophy as LumenJS: don't hide the code. Structure it better.</p>
<p>Click any element on the page. A properties panel shows its attributes, styles, and matching CSS rules from the component source. Edit a value and it writes directly to the TypeScript source through the AST - not the DOM, the actual file.</p>
<p>The AI is part of the editor. Select an element, open the chat, describe what you want. It reads the source, applies the change, and you can roll back if it gets it wrong. Claude Code and OpenCode are both supported.</p>
<p>Nothing from the editor ships to production</p>
<p>Lumenjs editor mode</p>
<h3>What Ships With It</h3>
<ul>
<li>
<p>File-based routing, SSR, server loaders, API routes</p>
</li>
<li>
<p>Real-time subscriptions over SSE and <a href="https://www.linkedin.com/redir/redirect?url=http%3A%2F%2FSocket%2EIO&amp;urlhash=CFko&amp;trk=article-ssr-frontend-pulse_little-text-block">Socket.IO</a></p>
</li>
<li>
<p>Authentication with OIDC, native email/password, and TOTP 2FA</p>
</li>
<li>
<p>Full communication module: chat, conversations, WebRTC calls, end-to-end encryption</p>
</li>
<li>
<p>Email with built-in templates and multiple provider support</p>
</li>
<li>
<p>File storage with local and S3 adapters</p>
</li>
<li>
<p>Database layer that works identically on SQLite and PostgreSQL</p>
</li>
<li>
<p>Permissions, i18n, SEO, rate limiting middleware</p>
</li>
</ul>
<p>This is not a list of planned features. It is what exists today.</p>
<p>The APIs are not stable yet. We are moving fast and things will change. We expect to reach v1 by Q4. Build on it with that in mind.</p>
<h2>Conclusion</h2>
<p>We are excited to launch LumenJS - not only because it represents how we practice augmented code, but because we have a team of coding agents as maintainers keeping the project alive, secure, and stable.</p>
<p>This is not a side project waiting for attention. It is a living framework, maintained the same way it was built.</p>
<p><a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Flumenjs%2Edev&amp;urlhash=AaVR&amp;trk=article-ssr-frontend-pulse_little-text-block">https://lumenjs.dev</a></p>
<p><a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Fgithub%2Ecom%2Fnuralyio%2Flumenjs&amp;urlhash=Sq28&amp;trk=article-ssr-frontend-pulse_little-text-block">https://github.com/nuralyio/lumenjs</a></p>
<p><a href="https://www.linkedin.com/redir/redirect?url=https%3A%2F%2Fnuraly%2Eio%2F&amp;urlhash=Dj1-&amp;trk=article-ssr-frontend-pulse_little-text-block">https://nuraly.io</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Why Building Agents Is an Operations Problem, Not a Technology One</title>
      <link>https://aymen.co/ai/why-building-agents-is-an-operations-problem-not-a-technology-one/</link>
      <guid isPermaLink="true">https://aymen.co/ai/why-building-agents-is-an-operations-problem-not-a-technology-one/</guid>
      <pubDate>Tue, 03 Mar 2026 00:00:00 GMT</pubDate>
      <description>Adding a chatbot UI to an LLM is not enough anymore. Agents are distributed systems with nondeterministic planners — and the real challenge is operations, not technology.</description>
      <content:encoded><![CDATA[<p>Adding a chatbot UI to an LLM is not enough anymore. And if we're being honest with ourselves, it was never enough.</p>
<h2>The Demo Trap</h2>
<p>Most agent projects start the same way. A simple UI. A simple API interface with an LLM. It works beautifully in the demo.</p>
<p>Then comes the real use case.</p>
<p>Suddenly, the team expects great results from the same setup they prototyped in a weekend. They start gluing UI to API, connecting endpoints, building wrappers, and wondering why the results are mediocre at best.</p>
<p>Here's the problem: there's not much value in that layer. The chatbot interface, the API wrapper, the prompt template: these are commodity components now. Everyone has them. They're table stakes, not differentiators.</p>
<p>Before you touch any of that, you need to deeply understand how to interface with the LLM, what components relate to it, and how they all connect with each other.</p>
<p>When you do that, when you truly understand the system, something shifts. You stop treating the LLM like a piece of code and start thinking about it as a system. You stop solving technical problems and start solving real ones.</p>
<h2>Agents Are Simple in Tech, Brutal in Operations</h2>
<p>The building blocks of an agent are simple. An LLM, tool calling, a feedback loop: the concepts are well-documented and the primitives are accessible.</p>
<p>But the system behavior is not. Tool calling is not reliable tool execution. A feedback loop is not correct state handling. Multi-step agents break in subtle, hard-to-reproduce ways. Here's the framing that makes it click for anyone who's run production infrastructure: agents are distributed systems with nondeterministic planners. If you've ever dealt with eventual consistency, partial failures, or observability gaps in microservices, multiply that by a component that makes different decisions every time you run it.</p>
<p>Building agents encompasses many technical and non-technical areas that most demos conveniently skip. Before your agent can do anything meaningful in production, you need to consider:</p>
<p><strong>Access management.</strong> Who can the agent act on behalf of? What permissions does it inherit? If your client has a cloud environment, how do you connect to it securely?</p>
<p><strong>Data governance.</strong> What data can the agent access? What can it store? What are the compliance requirements? This gets especially complex with European clients under GDPR.</p>
<p><strong>Security.</strong> An agent that can take actions is an agent that can take wrong actions. An agent with cloud credentials that rotates a resource instead of tagging it can take down a staging environment. An agent with database access that misinterprets &quot;clean up old records&quot; can wipe production data. The attack surface is fundamentally different from a read-only chatbot, and the blast radius is real.</p>
<p><strong>Monitoring.</strong> How do you know what your agent is doing? An agent that silently retries a failed API call 40 times before your alerting catches it is not a hypothetical; it's a Tuesday. How do you catch failures before your client does? How do you audit decisions the agent made autonomously?</p>
<p><strong>Infrastructure.</strong> Local or remote providers? Self-hosted or cloud? How do you handle latency, failover, and scaling for long-running agent tasks?</p>
<p><strong>User experience.</strong> How do you surface what the agent is doing in a way that builds trust rather than anxiety? How do you handle the cases where the agent needs to ask for clarification?</p>
<p><strong>Integration.</strong> The agent doesn't live in a vacuum. It needs to connect to existing systems, APIs, databases, and workflows that were never designed for autonomous actors.</p>
<p>You need all of these pieces in place before you can design and distribute a working agent. Not after. Before. That's what makes this an operations problem, not a technology problem.</p>
<h2>The Delegation Problem</h2>
<p>Are the clients, are we as developers, actually ready for delegation?</p>
<p>We used to do everything ourselves. As developers, it's not easy to delegate code writing. We built our careers on it. We had fun doing it. We got deep satisfaction from shipping something we wrote with our own hands.</p>
<p>Then you start delegating to AI. And the results are mixed.</p>
<p>Sometimes the model isn't good enough for the task. Sometimes your prompting isn't precise enough. Sometimes both. And when you hit those walls, something interesting happens.</p>
<p>You start shifting your focus. From writing to planning. From coding to architecture. From execution to design.</p>
<p>You start a new kind of race: you think more and type less.</p>
<p>This is the real transformation that agents bring. Not replacing developers, but changing what it means to be one. The role evolves from writing code to orchestrating systems, from executing tasks to leading missions.</p>
<h2>The Generation Trap</h2>
<p>We now know that almost any piece of software can be generated relatively easily. AI can write code, scaffold applications, generate entire features from a description. This creates an enormous, and misleading, promise around delivery.</p>
<p>&quot;If code can be generated in minutes, surely delivery is easy now.&quot;</p>
<p>It's not. And believing this is a trap.</p>
<p>Because it was never about writing code. It was always about understanding what the client actually means. Then executing on that understanding. Then iterating based on what you learn.</p>
<p>It's about infrastructure. It's about security. It's about integration. It's about all the things that code generation doesn't touch.</p>
<p>We absolutely need expertise. More than ever, in fact. But the expertise we need is not for executing tasks. It's for planning, reviewing, managing, and leading.</p>
<p>Not to type. To think.</p>
<p>Not to execute. To lead the mission.</p>
<h2>Stop Chasing Frameworks</h2>
<p>The market is crowded. Every week brings a new framework, a new wrapper, a new &quot;agent builder&quot; that promises to make everything easy.</p>
<p>None of them solve the actual problems.</p>
<p>Frameworks don't solve trust. Frameworks don't solve accountability. Frameworks don't solve blast radius. They solve wiring, and wiring was never the hard part.</p>
<p>The teams that will fail are the ones chasing the next wrapper, shipping demo-driven agents, and confusing &quot;it works on my laptop&quot; with production readiness. The teams that will fail are startups optimizing for speed of generation while ignoring speed of recovery.</p>
<p>The teams that will succeed, especially in the enterprise, are the ones treating agents like what they are: production systems that happen to include a nondeterministic component. They invest in governance, security, monitoring, and integration before they write a single line of agent code. They build operational maturity first.</p>
<p>The real value was never in the chatbot UI. It was never in the framework. It was in the ability to design, deploy, and operate a system that earns trust.</p>
<p>That's the mission. Lead it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Nuraly | How We Ship Code with AI Agents</title>
      <link>https://aymen.co/ai/nuraly-how-we-ship-code-with-ai-agents/</link>
      <guid isPermaLink="true">https://aymen.co/ai/nuraly-how-we-ship-code-with-ai-agents/</guid>
      <pubDate>Mon, 23 Feb 2026 00:00:00 GMT</pubDate>
      <description>How we use Claude Code and AI agents in our development cycle at Nuraly — from GitHub tickets to deployment, with quality gates, human review, and dedicated QA VMs.</description>
      <content:encoded><![CDATA[<p>We've been heavily using code agents especially Claude Code in our development cycle at Nuraly. But not alone. The agent is equipped with other tools, and the real value comes from how they work together.</p>
<h2>The Workflow</h2>
<p>It starts with a GitHub ticket, created by a PM or QA. Claude Code with the Ralph Wiggum plugin activated spins up a fresh environment, initializes it with the latest codebase, and analyzes the ticket. It loads the relevant Claude Code skills and gets to work.</p>
<p>It creates a branch. It starts coding. When needed, it commits progressively and updates the checklist in GitHub to keep the status visible especially if other agents are working on related issues at the same time.</p>
<p>Once the work is ready, the agent creates a pull request and starts collaborating with other agents. GitHub Copilot steps in for a diff model review a second pair of AI eyes on the code.</p>
<p><img src="/images/nuraly-workflow.jpg" alt="Nuraly Workflow" loading="lazy" decoding="async"></p>
<p>At the end of each execution, a summarized version of the conversation is saved. So when work continues on the ticket through a PR comment or a follow-up task the agent picks up the compact context from the previous run. This way, we keep working on the ticket without losing context.</p>
<h2>Quality Gates</h2>
<p>This is where SonarQube enters. It analyzes the PR and flags the pipeline status. If it fails, Claude Code reads the issues and quality gate results, creates a separate branch to fix them, validates the fixes, then merges them back into the ticket branch.</p>
<p>If the pipeline passes, a Telegram message is sent to the collaborators who worked on the ticket this also doubles as a way to test our own workflow engine in a real scenario.</p>
<p>Why Telegram? Because we've made a deliberate choice about where our developers spend their time. The old model has engineers glued to screens, refreshing CI dashboards, waiting for pipelines, context-switching between Slack threads and terminal windows. We don't want that. We want our team talking to clients, understanding problems firsthand, sitting in the room where decisions are made. The agents handle the waiting. The notifications come to you not the other way around. Build the feedback loop around people, not around screens.</p>
<p>Then comes the human review. We still keep this step. We value the human eye.</p>
<p><img src="/images/nuraly-quality-gates.jpg" alt="Quality Gates" loading="lazy" decoding="async"></p>
<h2>After the Merge</h2>
<p>Once the ticket is merged, Claude Code spins up a dedicated QA VM for that specific ticket launched from a pre-built image, which makes it extremely fast. After validation, the VM is carefully destroyed. Clean in, clean out.</p>
<p>We chose this over resetting environments because resets are fragile. You can miss something a stale config, a leftover dependency or add a feature and forget to update the reinit script. Starting from a fresh image for QA removes that risk entirely. It was one of our best decisions.</p>
<p><img src="/images/nuraly-qa-vm.jpg" alt="QA VM" loading="lazy" decoding="async"></p>
<p>The deployment itself is triggered from the GitHub issue. When the issue is flagged as ready for test, an agent worker detects it, prepares the environment, and comments back on the issue with the VM details. Everything stays in the ticket no separate workflows, no context switching.</p>
<p>With this cycle, a QA engineer can test a ticket before the code review is even done — and continue working on it by adding comments directly on the issue. No need to wait on an engineer, no getting blocked. The feedback loop between QA and the agent stays continuous.</p>
<h2>Why We Still Read Every Line</h2>
<p>This is how we ship working code at Nuraly while keeping quality and ownership intact. Every agent code is reviewed. SonarQube's pipeline needs to be green. But after all, we still read the new and modified code line by line.</p>
<p>Not because we don't trust the tools but because the code is ours. Agents accelerate the work. The ownership stays with us.</p>
]]></content:encoded>
    </item>
    <item>
      <title>I Waited. Here&#39;s What I Think About OpenClaw.</title>
      <link>https://aymen.co/ai/i-waited-heres-what-i-think-about-openclaw/</link>
      <guid isPermaLink="true">https://aymen.co/ai/i-waited-heres-what-i-think-about-openclaw/</guid>
      <pubDate>Tue, 17 Feb 2026 00:00:00 GMT</pubDate>
      <description>A grounded take on OpenClaw — what it actually is, why the real value isn&#39;t in the agent loop, and what&#39;s blocking broad adoption of autonomous AI agents.</description>
      <content:encoded><![CDATA[<p>I deliberately waited before saying anything about OpenClaw. When something gets this much hype, I've learned to let the dust settle before forming an opinion. Now that I've looked at it closely, I can share what I see.</p>
<h2>What It Actually Is</h2>
<p>OpenClaw is an LLM running in a loop with tools. A workflow that calls an LLM node, gives it access to your file system, browser, shell, and messaging apps, then loops until the task is done. It can also accept commands from long-running nodes like Telegram or WhatsApp, which makes it feel interactive and always-on.</p>
<p>That's it.</p>
<p>I'm not saying it's bad. The engineering is solid. But let's call it what it is: a well-packaged agent loop. An LLM node connected to tools, running over iterations, with persistent memory and messaging integrations. This pattern has existed for a while. Workflow engine, LLM nodes, tool access, long-running connections. The architecture is not new.</p>
<h2>What Actually Matters</h2>
<p>What actually matters right now and what OpenClaw confirms is everything around the LLM. The tools you give it. How you manage context. How you handle memory between sessions. How you set guardrails so the agent doesn't go rogue. That's where the real engineering challenge lives.</p>
<p>We already know this. The LLM is the brain. But the tools, the context management, the memory persistence — that's the body. And without a good body, the brain just hallucinates in the dark.</p>
<h2>The Access Paradox</h2>
<p>There's something worth sitting with here. The more data and control you hand to an AI agent, the more it can do for you. But that same access is exactly what lets it hurt you. It's the same lever, pulled in two directions. Give it your email, your calendar, your file system, your shell — and yes, it becomes powerful. But now the cost of a bad decision scales with the access you gave it.</p>
<h2>Fragile and Expensive</h2>
<p>Here's my honest concern with investing in this pattern right now: autonomous agents are still either fragile or expensive to run. One user mentioned hitting their entire Claude Max daily limit within hours just by letting the agent loop autonomously (before Anthropic blocked users from routing their subscription through third-party tools like this). Another had their agent accidentally start a fight with an insurance company. These aren't edge cases — they're the current state of autonomous AI.</p>
<h2>The Real Blocker</h2>
<p>And this is where it gets interesting. I think the real blocker for broad adoption isn't the models, isn't the tooling, isn't even the cost. It's security. Until we solve the agent security problem — how to give an AI meaningful access without exposing everything to a single bad reasoning step — autonomous agents will stay in the hands of early adopters willing to absorb the risk. Enterprises won't touch this. They can't afford an agent that emails a client the wrong thing, deletes the wrong file, or leaks sensitive data because it misunderstood a prompt.</p>
<h2>Where This Leaves Us</h2>
<p>In the absence of a genuine research breakthrough — something on the level of what we saw with Claude's leap in reasoning — we're essentially optimizing the loop. Making the tools better. Managing context smarter. But the fundamental limitation remains: the model reasons well enough for short, bounded tasks, and starts breaking down on anything truly complex or long-running.</p>
<p>Would I invest in building on OpenClaw right now? No. Not because it's bad, but because the value isn't in the loop itself. The value is in the platform layer underneath — the workflow engine that sets boundaries, the persistence layer that maintains state, the permission system that controls access. That's what enterprises actually need, and that's what doesn't come for free with an open-source agent loop.</p>
<p>Build the infrastructure. The agent patterns will keep evolving. But the foundation? That compounds.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How Key-Value service can enhance platform UX</title>
      <link>https://aymen.co/ai/how-key-value-service-can-enhance-platform-ux/</link>
      <guid isPermaLink="true">https://aymen.co/ai/how-key-value-service-can-enhance-platform-ux/</guid>
      <pubDate>Tue, 03 Feb 2026 00:00:00 GMT</pubDate>
      <description>Why building a dedicated key-value service early can simplify persistence, speed up onboarding, and even power AI agent state across your platform.</description>
      <content:encoded><![CDATA[<p>When you're building a platform, you're not just developing for customers. You're developing for yourself first. This changes everything about how you prioritize.</p>
<p>Persistence management is one of those features that quietly sinks to the bottom of the backlog. We all want it. We all know we need it. But the priority stays low, pushed aside by urgent customer requests and deadlines. &quot;One day, when we have time, we'll implement it properly.&quot; There's a good chance that day never comes.</p>
<p>So we decided to stop waiting.</p>
<h2>The Solution: A Dedicated KV Service</h2>
<p>At Nuraly, we built a separate service, a simple key-value store that serves our other microservices. It can hold encrypted values when needed, and it runs independently from everything else.</p>
<p>What can you store? More than you'd expect:</p>
<ul>
<li>API keys and secrets</li>
<li>Database connection strings</li>
<li>User-specific settings per service</li>
<li>Feature flags and configuration overrides</li>
<li>Agent state</li>
</ul>
<p>That last one surprised us too. We now use the KV service to hold the state of our AI agents, their context, progress, and memory between sessions. What started as a configuration store became the backbone of our agent persistence.</p>
<p>All of this sits behind a dedicated permission service, so access stays controlled and auditable.</p>
<p><img src="/images/kv-service-architecture.jpg" alt="KV Service Architecture" loading="lazy" decoding="async"></p>
<h2>Why This Works</h2>
<p>The beauty of a standalone KV service is isolation and simplicity. You don't need to manage persistence inside each microservice anymore. No more duplicating the same storage logic across services. No more spinning up separate databases just to hold configuration for each one.</p>
<p>Instead, the feature is one HTTP request away.</p>
<p>Each microservice pulls only what it needs, nothing more. No hardcoded values buried in deployment scripts. No redundant persistence layers bloating every service. Just a clean API call.</p>
<p>It's a small architectural decision, but it compounds. Onboarding new microservices becomes faster. Rotating credentials becomes trivial. Debugging configuration issues becomes possible. And every new service you spin up inherits the same persistence capability without implementing storage logic from scratch.</p>
<h2>Where This Leads</h2>
<p>I've started thinking of persistence not as a feature to implement later, but as infrastructure to build early. The cost of doing it right upfront is low. The cost of doing it wrong, or not at all, accumulates invisibly until it doesn't.</p>
<p>If you're building a platform, don't let persistence sink in your backlog. Build the KV layer now. Your future self will thank you.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Angular 14: Standalone components</title>
      <link>https://aymen.co/javascript/angular-standalone-components/</link>
      <guid isPermaLink="true">https://aymen.co/javascript/angular-standalone-components/</guid>
      <pubDate>Mon, 13 Jun 2022 00:00:00 GMT</pubDate>
      <description>At ReactConfg 2018 Event, Dan Abramov explained the Logo of React, he said that the user interface can be splitted into small independent units called components - similar to an…</description>
      <content:encoded><![CDATA[<h2></h2>
<p>At ReactConfg 2018 Event, Dan Abramov explained the Logo of React, he said that the user interface can be splitted into small independent units called components - similar to an Atom - and they will focus, in the next few years, on Hooks: “Electrons” as he named them.</p>
<p>On the other side of the Javascript world, Angular started focusing on smaller units as Component, Directive and Pipes rather than modules.</p>
<p>Starting from Angular 14, Components can be standalone and imported into modules or other components without the need for a dedicated module.</p>
<h2>Standalone Component in Action.</h2>
<p>To test this feature, I created a blank project and activated the routing option.</p>
<p>Then, I created a basic component <code>UserDetailComponent </code> , the metadata looks like the following.</p>
<script src="https://gist.github.com/labidiaymen/2dd68d910b2d68e230ee15d2b66964ea.js"></script>
<h2></h2>
<p>Then, created a service for the User.
For the sake of the demo, this service is not provided in the root <code>providedIn: 'root'</code></p>
<script src="https://gist.github.com/labidiaymen/5706440fbf88bf979b264b6413d90b36.js"></script>
<p>So now, all we have to do is to use the service in the component. Before Angular 14, we had to create a module that defines all providers components and other dependencies or import everything in the <code>AppModule</code>.</p>
<p>Now, we can declare Components as standalone and provide the service directly into the Component</p>
<script src="https://gist.github.com/labidiaymen/20ceddab8dbf00204621cd5c3e12f146.js"></script>
<h2></h2>
<p>In the Route Module, we can directly import the component rather than the Module.</p>
<script src="https://gist.github.com/labidiaymen/35fd2acb26b0577ddfaa4f1d1cf42ae1.js"></script>
<h2></h2>
<p><a href="https://github.com/labidiaymen/angular-standalone-components">Github Srouce</a></p>
<!-- [Demo on Stackblitz](https://stackblitz.com/github/labidiaymen/angular-standalone-components) -->
<p>You can play with the demo directly on Stackblitz</p>
<iframe loading="lazy" style="width: 100%;height: 313px;" src="https://stackblitz.com/edit/github-vpsfla?embed=1&file=src/app/user-detail/user-detail.component.ts"></iframe>
<h2>Motivation</h2>
<p>Have you ever thought: why a framework like Angular started to review their vision about modularity?</p>
<p>In most Angular applications we are used to find some CoreModule, SharedModule and others that contain the common unit which is used in more than one module.</p>
<p>Everytime the application grows, there's a chance that these modules will grow too.</p>
<p>That's fine until we start thinking about performance.</p>
<p>In the chart below, we will demonstrate the use of a common NgModule and how to import a component directly inside another module without the middle man, Thanks to Angular 14 of course.</p>
<h3>Sharing standard component</h3>
<p><img src="/images/Angular-14-Standalone-components-1.drawio.png" alt="aa" loading="lazy" decoding="async"></p>
<h2></h2>
<p>In this case we have three components, two services and more than two modules.</p>
<p>These units are used in more than one place, so we created a <code>SharedModule</code> to package them.
This ShareModule has been imported in the two modules.</p>
<p>When lazyloading the module with LazLoading routes, the SharedModule alongs with the components and services and every unit exported, will be loaded in each module.</p>
<h3>Sharing standalone component</h3>
<p><img src="/images/Angular-14-Standalone-components-2.drawio.png" alt="aa" loading="lazy" decoding="async"></p>
<h2></h2>
<p>In this case we have the same unit (components, pipes, services and modules) but we ditched the SharedModule.</p>
<p>We transformed the component in Standalone mode, which means that every component will load the needed providers.</p>
<p>The <code>FormatDatePipe</code> load the <code>DateTimeService</code> and <code>DocumentViwerComponent</code> load <code>DocumentService</code>.</p>
<p>Now When lazyloading a Component, only the component that is directly linked to it will be loaded.</p>
<h3>Conclusion</h3>
<p>Angular started approaching ReactJS with the small independent unit approach by introducing Standalone Component, which seems a big step toward enhancing web application performance and building a better and more maintainable web.</p>
<p>Personally, I'm not fan of the idea of working with only one Framework, since we can explore multiple paths at the same time then adopt what was a success in each Framework.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Angular 14: CLI Auto completion</title>
      <link>https://aymen.co/javascript/angular-cli-auto-completion/</link>
      <guid isPermaLink="true">https://aymen.co/javascript/angular-cli-auto-completion/</guid>
      <pubDate>Sun, 12 Jun 2022 00:00:00 GMT</pubDate>
      <description>Introduction As Front-end Architect, choosing the right Framework can impact the whole company even the group, that’s why we choose carefully the technologies that we adopt. For…</description>
      <content:encoded><![CDATA[<h2>Introduction</h2>
<p>As Front-end Architect, choosing the right Framework can impact the whole company even the group, that’s why we choose carefully the technologies that we adopt.</p>
<p>For many years Angular prove how stable, it is, and when braking change happens, it will be accompanied by a great documentation.</p>
<p>Even there a tool to assist you when updating project. <a href="https://angular.io/cli/update"><code>ng update</code></a></p>
<h2>Angular CLI auto completion</h2>
<p>Bootstraping Component, Pipe and Service is a daily task when starting a new feature with Angular projet.
So we use <code>ng</code> command to generate our static files.</p>
<p>If you use VS Code or Intellij or any IDE there's extentions that execute ng generate command for you.
But if you want use the command line in your Terminal you will have hard time to remember the arguments to pass.</p>
<p>That's why Angular has introduce <strong>CLI auto completion</strong></p>
<p>To use this feature on Winsows you need to activate WSL(Windows Subsystem for Linux) or Use GIT Bash.</p>
<p><img src="/images/ng-completion-1.PNG" alt="adding profile for windows" loading="lazy" decoding="async"></p>
<p>Double check if the command has added the command to the <code>.bashrc</code></p>
<p><img src="/images/ng-completion-2.PNG" alt="bashrc example" loading="lazy" decoding="async"></p>
<p>And than we can use TAB key to autocomplete, it's a bit slow on windows but it works.
<img src="/images/ng-completion-3.PNG" alt="ng completion demo" loading="lazy" decoding="async"></p>
<p>We can go even further with the list of available flags.</p>
<p><img src="/images/ng-completion-4.PNG" alt="ng completion flags" loading="lazy" decoding="async"></p>
<h2>Conclusion</h2>
<p>Tools make the life of developers easier, every improvement can affect their productivity. This makes us sometimes choose a framework among others in order to get a richer toolkit.</p>
]]></content:encoded>
    </item>
    <item>
      <title>(C++) isASCII(string) : Check if the string has a special characters</title>
      <link>https://aymen.co/c-plus-plus/isascii-check-if-the-string-has-a-special-characters/</link>
      <guid isPermaLink="true">https://aymen.co/c-plus-plus/isascii-check-if-the-string-has-a-special-characters/</guid>
      <pubDate>Mon, 02 Mar 2020 00:00:00 GMT</pubDate>
      <description>When using C++ to serve multi-languages users, we need to validate the caractères in the string to find out what to do. In our case, we need to find out if there&#39;s a special cha…</description>
      <content:encoded><![CDATA[<p>When using C++ to serve <strong>multi-languages</strong> users, we need to validate the caractères in the string to find out what to do.</p>
<p>In our case, we need to find out if there's a special character in the string to convert them,  and this was made by checking the decimal code of each character and check if it is above 127 or not,</p>
<p>why <strong>127</strong>?</p>
<p>Because the <strong>ASCII</strong> table told us that the characters code starts from 0 (NULL) and ends at 127(DEL)</p>
<p><img src="/images/asciifull.gif" alt="ASCII character table" loading="lazy" decoding="async"></p>
<p>So we made this function.</p>
<p>bool isASCII(const std::string&amp; s)
{
return !std::any_of(s.begin(), s.end(), [](char c) {
return static_cast<unsigned char>(c) &gt; 127;
});
}</p>
<p>And this how we used it</p>
<p> </p>
<p>#include <iostream>
#include <string>
#include <algorithm></p>
<p>bool isASCII(const std::string&amp; s)
{
return !std::any_of(s.begin(), s.end(), [](char c) {
return static_cast<unsigned char>(c) &gt; 127;
});
}</p>
<p>int main(){
std::string testString = &quot;not a valid Ãscii&quot;;
std::cout &lt;&lt; &quot;Is valid ASCII &quot; &lt;&lt; isASCII(testString.c_str()) &lt;&lt; std::endl;
}</p>
<p>And the output will be:</p>
<p>Is valid ASCII 0</p>
<p>0 as NULL is C++</p>
<p> </p>
<p>PS: Will share snippets as I'm learning C++</p>
]]></content:encoded>
    </item>
    <item>
      <title>A Stable JavaScript (fatigue)</title>
      <link>https://aymen.co/javascript/a-stable-javascript-fatigue/</link>
      <guid isPermaLink="true">https://aymen.co/javascript/a-stable-javascript-fatigue/</guid>
      <pubDate>Wed, 30 Oct 2019 00:00:00 GMT</pubDate>
      <description>Have you felt the JavaScript fatigue before? I have . Being a web developer using JavaScript frameworks consumes a lot of energy. The JavaScript meant to be for the front-end de…</description>
      <content:encoded><![CDATA[<p>Have you felt the <a href="https://goo.gl/Hgnph7">JavaScript fatigue</a> before? <strong>I have</strong>.</p>
<p>Being a web developer using JavaScript <strong>frameworks</strong> consumes a lot of energy.</p>
<p>The JavaScript meant to be for the <strong>front-end</strong> development and to add some interaction to static pages, like display images on click, validate forms and load <strong>async</strong> portion of data.</p>
<p>Look around you now, JavaScript <strong>is everywhere</strong>. every month or a week there a new framework or library that want to change the world appears.</p>
<p>Let's look at some history:</p>
<p>At first, there's plain <strong>JavaScript</strong>, at that age, you need to write more for less, then it comes the libraries like <a href="https://jquery.com/">jQuery</a>, <a href="https://mootools.net/">MooTools</a>, and YUI( <a href="https://yuilibrary.com/">Yahoo! UI Library</a> )</p>
<p>Then <strong>Angular.js</strong> has appeared at 2009, followed by <a href="https://knockoutjs.com/">Knockout</a>, <a href="http://backbonejs.org/">Backbone.js</a>, <a href="https://www.emberjs.com/">Ember.js</a>, and others.</p>
<p>After a while <a href="https://reactjs.org/">React</a> has been <strong>introduced</strong> by <a href="https://developers.facebook.com/">Facebook</a> at 2013, a <strong>component-based</strong> frontend framework</p>
<p>Then in 2016, it comes <a href="https://angular.io/">Angular 2+</a> a complete Javascript framework for the front-end.</p>
<p>But <strong>Ryan Dahl</strong> let the front-end developer be a full-stack developer by making <a href="https://goo.gl/1Y1wmg">Node.js</a></p>
<p>After 2009 developers start making <strong>web application and services</strong> with Javascript and new JavaScript frameworks start popups.</p>
<p>Starting from 2017-2018 people start choosing a path to follow, like Angular developer, React Developer and so on.</p>
<p>Also <strong>me</strong>, I'm known as Angular developer,  That's the main framework that I work with but you need also to <strong>master</strong> other Frameworks if you want to be laways <strong>fresh</strong>.</p>
<p>Following everything is the perfect option to lose <strong>focus</strong>. for me, I'm really aware of what I should <strong>consume</strong> to prevent the <strong>distraction</strong>, and also I create a routine to keep up with what should I know.</p>
<p>Again have you felt the <a href="https://goo.gl/Hgnph7">JavaScript fatigue</a> before? Share your <strong>experience</strong> with us ?.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Cypress as Frontend developer</title>
      <link>https://aymen.co/javascript/cypress-as-frontend-developer/</link>
      <guid isPermaLink="true">https://aymen.co/javascript/cypress-as-frontend-developer/</guid>
      <pubDate>Sun, 09 Sep 2018 00:00:00 GMT</pubDate>
      <description>As a frontend developer you will interact with backend developers more than you will interact with your family members, so keeping the good relationship is the main thing you ne…</description>
      <content:encoded><![CDATA[<p>As a <strong>frontend</strong> developer you will interact with <strong>backend</strong> developers more than you will interact with your family members, so keeping the good <strong>relationship</strong> is the main thing you need to <strong>focus</strong> on.</p>
<p>When everything goes right, everybody is happy, but when one thing goes wrong, not nesserely everybody should feel sad.</p>
<p>To keep the good relationship we need to remove all the <strong>confusing</strong> things from the workflow and <strong>everybody should speak the same language</strong>.</p>
<p>Let's pick a case that everybody will pass on :</p>
<p>You create a view with <strong>Angular</strong>, Vue or React, you consumed mock services and everything looks OK,</p>
<p>Then it comes the moment of truth when you will connect the frontend view with the backend service/<strong>API</strong>, you implemented it and it didn't work you will contact the backend developer and he will tell you that his service work like a charm.</p>
<p>You invite him to look at the result and he admitted that there's a <strong>bug need to fix</strong>.</p>
<p>After he fixes his code, two things can happen :</p>
<p>The bug fixed and everything goes right.</p>
<p>The bug persists and you show him the <strong>scenario</strong> again and we loop through this until we get everything OK, if we did not break other parts of the <strong>App</strong>.</p>
<p>That's Ok but, this takes time and energy.</p>
<p>Here's I start a searching for <strong>automation</strong>, then to end to end <strong>testing</strong>, to simulate everything, and here's my experience :</p>
<p>I found <strong><a href="https://www.cypress.io/">Cypress</a></strong> and start writing my tests for my views and after each view or service <strong>implementation</strong>, then the worrying start decreasing.</p>
<p>With the (<strong>e2e</strong>) end to end testing, you stop worrying about <strong>regression</strong> and focusing on the new <strong>functionalities</strong> that need to implement.</p>
<p>With that, the relation between the front and back Team <strong>start recovering</strong>.</p>
<p>If the <strong>test fails</strong> I made a video of the issue and send it the concerned person, <strong>otherwise</strong> I invite him to watch the scenario fails ?</p>
<p>I start being less exhausted as a Front-end developer.</p>
<p><strong>Next step</strong>, is to add the e2e test, to the <strong>DevOps</strong> pipeline.</p>
<p>And you, how are you dealing with the <strong>regressions?</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>Docker, where have you been ?</title>
      <link>https://aymen.co/javascript/docker-where-have-you-been/</link>
      <guid isPermaLink="true">https://aymen.co/javascript/docker-where-have-you-been/</guid>
      <pubDate>Sun, 29 Jul 2018 00:00:00 GMT</pubDate>
      <description>Euuh Docker , I know you&#39;re here for a while, but this is the right time I took the courage and make the hole things work with you. First of all, I&#39;m a consultant and I have a s…</description>
      <content:encoded><![CDATA[<p>Euuh <a href="https://www.docker.com/"><strong>Docker</strong></a>, I know you're here for a while, but this is the right time I took the courage and make the hole things work with you.</p>
<p>First of all, I'm a <strong>consultant</strong> and I have a <strong>startup</strong> which means I work on lots of things with a lot of <strong>things</strong>.</p>
<p>And to keep it up without loses I need to isolate each thing from the other things. and here's where I start using Docker.</p>
<p>I hear people talking about Docker on the <a href="https://en.wikipedia.org/wiki/DevOps"><strong>DevOps</strong></a> field but this is not the case for me, I start using Docker in the development environment, and here's how.</p>
<p>In the last mission, I was working on a frontend application using the <a href="https://angular.io/"><strong>Angular</strong></a> framework, and it's not just me, we were a team working on the same project trying the make things happen, really fast.</p>
<p>But this is not the case when we have a different version of Node.js and <a href="https://cli.angular.io/"><strong>@angular/</strong></a>cli.</p>
<p>This start occurring when building success in some machine and fail in other, and here we start using Docker in the development <strong>environment</strong>, we choose a Node.js version that matches with the production server and we create an image for the environment, then we all start using the same image.</p>
<p>Besides all of that, any <strong>new member</strong> can use the same image without installing any of other <strong>tools</strong> than Docker, and it makes the integration of new members easy and smooth.</p>
<p>Then I start controlling the <strong>CPU</strong> and the Memory of the container to keep the host machine cool and prevent battery drain when I'm walking around with my MacBook Pro</p>
<p>That does not <strong>end</strong> here.</p>
<p>I start exploring new applications that were hard to install especially when I was using <strong>Windows</strong>, but with Docker, I just need to <strong>pull an image</strong> and run it.</p>
<p>I use <strong>Docker</strong>, how about <strong>you</strong>?</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
