<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hello</title>
    <description>The latest articles on DEV Community by Hello (@e-mc2).</description>
    <link>https://dev.to/e-mc2</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3985340%2F85f1fe93-e189-4d8e-b4af-cb5f713f344d.jpg</url>
      <title>DEV Community: Hello</title>
      <link>https://dev.to/e-mc2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/e-mc2"/>
    <language>en</language>
    <item>
      <title>Ai Coding with EkkoJS</title>
      <dc:creator>Hello</dc:creator>
      <pubDate>Wed, 24 Jun 2026 04:10:44 +0000</pubDate>
      <link>https://dev.to/e-mc2/ai-coding-with-ekkojs-2hbk</link>
      <guid>https://dev.to/e-mc2/ai-coding-with-ekkojs-2hbk</guid>
      <description>&lt;h2&gt;
  
  
  Vibe Coding Is Not the Problem. Guessing Is.
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ekkojs.com" rel="noopener noreferrer"&gt;EkkoJS&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The main website for EkkoJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://rune.ekkojs.com" rel="noopener noreferrer"&gt;Rune&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dedicated documenattion for Rune&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://asgard.ekkojs.com" rel="noopener noreferrer"&gt;Asgard&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dedicated documentation and example for Asgard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you are tired of hearing that vibe coding is not secure, that you will never ship anything viable, or that AI-assisted development can only produce toys, EkkoJS was built for you.&lt;/p&gt;

&lt;p&gt;EkkoJS exists for builders who have taste, motivation, methodology, and loop sensitivity. It is for people who know what they want to build, but do not want to waste half their energy fighting setup, fragmented tooling, outdated documentation, and hallucinated APIs.&lt;/p&gt;

&lt;p&gt;EkkoJS is a JavaScript and TypeScript runtime built from the ground up for the AI coding era.&lt;/p&gt;

&lt;p&gt;Its core idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A runtime should be able to teach any capable AI coding model how to use it, without prior training.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No fine-tuning. &lt;br&gt;
No prior model knowledge. &lt;br&gt;
No guessing. &lt;br&gt;
No fake APIs invented because the model saw something similar in another framework.&lt;/p&gt;

&lt;p&gt;With EkkoJS, the runtime itself becomes part of the development loop.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Real Problem With Vibe Coding
&lt;/h2&gt;

&lt;p&gt;The problem is not that people use AI to code.&lt;/p&gt;

&lt;p&gt;The problem is that AI often codes against incomplete, outdated, or missing context.&lt;/p&gt;

&lt;p&gt;When a model does not know a runtime, a framework, or a library deeply enough, it starts to approximate. It mixes patterns. It borrows APIs from other ecosystems. It produces code that looks correct, but does not actually run.&lt;/p&gt;

&lt;p&gt;That is where the risk begins.&lt;/p&gt;

&lt;p&gt;Not in the idea of AI-assisted coding itself, but in the gap between the model's memory and the real tool in front of you.&lt;/p&gt;

&lt;p&gt;EkkoJS attacks that gap directly.&lt;/p&gt;


&lt;h2&gt;
  
  
  EkkoJS Is AI-Self-Sufficient
&lt;/h2&gt;

&lt;p&gt;EkkoJS comes with integrated live runtime guidance.&lt;/p&gt;

&lt;p&gt;Through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko doc &lt;span class="nt"&gt;--llm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;a capable AI coding model can extend its working context with accurate, current, runtime-aware information.&lt;/p&gt;

&lt;p&gt;That includes documentation, architecture, usage examples, API behavior, and smart error guidance designed to explain how to fix problems instead of letting the model guess.&lt;/p&gt;

&lt;p&gt;The result is a tighter loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The model asks the runtime how it works.&lt;/li&gt;
&lt;li&gt;The runtime provides accurate guidance.&lt;/li&gt;
&lt;li&gt;The model writes code using the real installed version.&lt;/li&gt;
&lt;li&gt;Errors become explainable instead of mysterious.&lt;/li&gt;
&lt;li&gt;Iteration becomes faster and cheaper.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is what I call &lt;strong&gt;Zero-Shot Runtime Coding&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Any capable AI can code with EkkoJS without prior training by following live runtime guidance from the runtime itself.&lt;/p&gt;
&lt;/blockquote&gt;

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




&lt;h2&gt;
  
  
  But Is a Vibe-Coded Web App Secure?
&lt;/h2&gt;

&lt;p&gt;A random vibe-coded web app with no framework discipline, no access control, no middleware, no permission model, and no structure can absolutely become insecure.&lt;/p&gt;

&lt;p&gt;That is not a reason to reject AI-assisted coding.&lt;/p&gt;

&lt;p&gt;That is a reason to give the AI a better runtime.&lt;/p&gt;

&lt;p&gt;With EkkoJS, full-stack web development is not left as an empty playground where every project starts by assembling random packages.&lt;/p&gt;

&lt;p&gt;EkkoJS ships with &lt;strong&gt;Rune&lt;/strong&gt;, a full-stack web framework built into the runtime.&lt;/p&gt;

&lt;p&gt;Rune gives you, out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSR on first load, so SEO is preserved.&lt;/li&gt;
&lt;li&gt;Client-side navigation after hydration, so the app feels fast.&lt;/li&gt;
&lt;li&gt;File-based routing.&lt;/li&gt;
&lt;li&gt;API routes in the same process.&lt;/li&gt;
&lt;li&gt;SSR cache and invalidation.&lt;/li&gt;
&lt;li&gt;SEO helpers.&lt;/li&gt;
&lt;li&gt;Secure-by-default runtime permissions.&lt;/li&gt;
&lt;li&gt;A clean full-stack mental model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of starting from nothing, your AI assistant starts from a runtime that already has structure.&lt;/p&gt;

&lt;p&gt;That matters.&lt;/p&gt;

&lt;p&gt;Security is not magic. But better defaults reduce the surface for mistakes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Built-In Security Foundations
&lt;/h2&gt;

&lt;p&gt;EkkoJS is designed to reduce dependency chaos and give developers safer primitives earlier in the project.&lt;/p&gt;

&lt;p&gt;For web apps and services, EkkoJS includes familiar backend capabilities such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP routing.&lt;/li&gt;
&lt;li&gt;CORS middleware.&lt;/li&gt;
&lt;li&gt;Secure headers through Helmet-style middleware.&lt;/li&gt;
&lt;li&gt;Rate limiting.&lt;/li&gt;
&lt;li&gt;Compression.&lt;/li&gt;
&lt;li&gt;Runtime permissions.&lt;/li&gt;
&lt;li&gt;Testing.&lt;/li&gt;
&lt;li&gt;Native I/O APIs.&lt;/li&gt;
&lt;li&gt;Database access through one ORM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rune also follows a deny-by-default permission approach: the app only touches files, hosts, and environment variables that you explicitly grant.&lt;/p&gt;

&lt;p&gt;That is important for AI-assisted coding because the model should not just be able to write code quickly.&lt;/p&gt;

&lt;p&gt;It should be guided into writing code inside boundaries.&lt;/p&gt;




&lt;h2&gt;
  
  
  One ORM, Multiple Databases
&lt;/h2&gt;

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

&lt;p&gt;Most developers do not want to rewrite their application because the storage choice changes.&lt;/p&gt;

&lt;p&gt;EkkoJS includes an ORM designed to reduce the frontier between SQL and NoSQL usage.&lt;/p&gt;

&lt;p&gt;The goal is simple: write your application logic once, then target different database drivers with minimal friction.&lt;/p&gt;

&lt;p&gt;EkkoJS ORM supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;Microsoft SQL Server&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means a project can start simple, grow naturally, and avoid turning every database decision into a full rewrite.&lt;/p&gt;

&lt;p&gt;For AI-assisted development, this is even more important.&lt;/p&gt;

&lt;p&gt;The less fragmented the backend surface is, the less opportunity there is for the model to mix incompatible patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  Asgard: A Real React Component Suite
&lt;/h2&gt;

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

&lt;p&gt;A full-stack framework is not enough if every UI still starts from scratch.&lt;/p&gt;

&lt;p&gt;EkkoJS also comes with &lt;strong&gt;Asgard&lt;/strong&gt;, the official React component suite for Rune applications.&lt;/p&gt;

&lt;p&gt;Asgard is not just a few buttons.&lt;/p&gt;

&lt;p&gt;It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inputs and forms.&lt;/li&gt;
&lt;li&gt;Pickers.&lt;/li&gt;
&lt;li&gt;Data display.&lt;/li&gt;
&lt;li&gt;Feedback and overlays.&lt;/li&gt;
&lt;li&gt;Navigation and chrome.&lt;/li&gt;
&lt;li&gt;Layout components.&lt;/li&gt;
&lt;li&gt;Docking and IDE-style workspaces.&lt;/li&gt;
&lt;li&gt;Theme support.&lt;/li&gt;
&lt;li&gt;Accessibility foundations.&lt;/li&gt;
&lt;li&gt;Server-rendered components that hydrate cleanly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because many applications do not fail because the developer cannot write a button.&lt;/p&gt;

&lt;p&gt;They fail because building a coherent UI system takes time, discipline, and consistency.&lt;/p&gt;

&lt;p&gt;Asgard gives the AI and the developer a shared design surface from the start.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Can You Build With EkkoJS?
&lt;/h2&gt;

&lt;p&gt;EkkoJS is not limited to one kind of project.&lt;/p&gt;

&lt;p&gt;It is a runtime for modern JavaScript and TypeScript development, with zero configuration and direct TypeScript execution.&lt;/p&gt;

&lt;p&gt;You can build:&lt;/p&gt;

&lt;h3&gt;
  
  
  Web Client Apps
&lt;/h3&gt;

&lt;p&gt;For interactive frontends where the browser experience matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full-Stack Web Apps
&lt;/h3&gt;

&lt;p&gt;With Rune, you get fast first render, SEO-friendly HTML, then client-side navigation after hydration.&lt;/p&gt;

&lt;h3&gt;
  
  
  APIs and Backend Services
&lt;/h3&gt;

&lt;p&gt;With built-in routing, middleware, permissions, native APIs, testing, and database access.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLI Tools
&lt;/h3&gt;

&lt;p&gt;For rich developer tools, automation scripts, internal workflows, and project utilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  TUI Applications
&lt;/h3&gt;

&lt;p&gt;For terminal-first experiences with real UX ambition, the kind of interfaces developers now expect from tools like coding agents, assistants, and modern terminal workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Native Desktop GUI Applications
&lt;/h3&gt;

&lt;p&gt;EkkoJS can target native desktop-style applications with system windows, menus, and system tray integration.&lt;/p&gt;

&lt;p&gt;One runtime. &lt;br&gt;
One language family. &lt;br&gt;
One mental model.&lt;/p&gt;




&lt;h2&gt;
  
  
  JavaScript and TypeScript, Out of the Box
&lt;/h2&gt;

&lt;p&gt;EkkoJS does not ask developers to learn an exotic language before they can build.&lt;/p&gt;

&lt;p&gt;It uses the standards people already know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;ESM modules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TypeScript runs directly.&lt;/p&gt;

&lt;p&gt;No build ritual before you can start.&lt;/p&gt;

&lt;p&gt;No configuration wall before your first useful result.&lt;/p&gt;

&lt;p&gt;Just write, run, iterate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters for Non-Deep-Technical Builders
&lt;/h2&gt;

&lt;p&gt;Not everyone building software wants to spend their life buried under tooling complexity.&lt;/p&gt;

&lt;p&gt;Some people have product taste. &lt;br&gt;
Some have business intuition. &lt;br&gt;
Some understand user pain. &lt;br&gt;
Some are motivated enough to iterate every day.&lt;/p&gt;

&lt;p&gt;They do not need a runtime that makes them feel stupid before they even start.&lt;/p&gt;

&lt;p&gt;They need a runtime that lowers the entry barrier without hiding the truth.&lt;/p&gt;

&lt;p&gt;EkkoJS gives them a faster path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The runtime is documented for humans and AI.&lt;/li&gt;
&lt;li&gt;The model can access live guidance.&lt;/li&gt;
&lt;li&gt;The stack is integrated.&lt;/li&gt;
&lt;li&gt;The defaults are stronger.&lt;/li&gt;
&lt;li&gt;The feedback loop is shorter.&lt;/li&gt;
&lt;li&gt;Token consumption can drop because the model does not need to rediscover or guess everything.&lt;/li&gt;
&lt;li&gt;The developer spends more time shaping the product and less time fighting boilerplate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not about replacing engineering judgment.&lt;/p&gt;

&lt;p&gt;It is about giving builders a better floor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Vibe Coding Needs Better Infrastructure
&lt;/h2&gt;

&lt;p&gt;The future of AI-assisted development will not be won by saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never use AI to code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It will be won by building tools where AI can code responsibly.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better runtime guidance.&lt;/li&gt;
&lt;li&gt;Better defaults.&lt;/li&gt;
&lt;li&gt;Better security boundaries.&lt;/li&gt;
&lt;li&gt;Better documentation.&lt;/li&gt;
&lt;li&gt;Better error feedback.&lt;/li&gt;
&lt;li&gt;Better full-stack integration.&lt;/li&gt;
&lt;li&gt;Better primitives for real applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;EkkoJS is my answer to that.&lt;/p&gt;

&lt;p&gt;A runtime that can guide the model. &lt;br&gt;
A framework that can structure the app. &lt;br&gt;
A component suite that can shape the UI. &lt;br&gt;
An ORM that can simplify persistence. &lt;br&gt;
A permission model that can define boundaries. &lt;br&gt;
A JavaScript and TypeScript experience that starts fast.&lt;/p&gt;




&lt;h2&gt;
  
  
  EkkoJS Is Built for Builders
&lt;/h2&gt;

&lt;p&gt;EkkoJS is free because the goal is bigger than selling access to another tool.&lt;/p&gt;

&lt;p&gt;The goal is to lower the entry barrier of coding.&lt;br&gt;
The goal is to make AI-assisted development less fragile.&lt;/p&gt;

&lt;p&gt;The goal is to help capable builders move from idea to working software with fewer artificial walls.&lt;/p&gt;

&lt;p&gt;If you have motivation, taste, discipline, and the will to iterate, you should not be blocked by boilerplate, tooling fragmentation, or a model guessing APIs from memory.&lt;/p&gt;

&lt;p&gt;You should be able to build.&lt;br&gt;
That is why EkkoJS exists.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Thought
&lt;/h2&gt;

&lt;p&gt;Vibe coding is not automatically insecure.&lt;br&gt;
Unguided coding is more dangerous than having ideas.&lt;/p&gt;

&lt;p&gt;EkkoJS is built around a different belief:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best AI coding experience is not a model that pretends to know everything. &lt;br&gt;
It is a runtime that can teach the model exactly what it needs to know.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the future EkkoJS is betting on.&lt;/p&gt;

&lt;p&gt;Write once. &lt;br&gt;
Resonate everywhere.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Link&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://ekkojs.com" rel="noopener noreferrer"&gt;EkkoJS&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The main website for EkkoJS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://rune.ekkojs.com" rel="noopener noreferrer"&gt;Rune&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dedicated documenattion for Rune&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://asgard.ekkojs.com" rel="noopener noreferrer"&gt;Asgard&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Dedicated documentation and example for Asgard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>vibecoding</category>
      <category>ai</category>
      <category>javascript</category>
      <category>coding</category>
    </item>
    <item>
      <title>EkkoJS, the new challenger</title>
      <dc:creator>Hello</dc:creator>
      <pubDate>Thu, 18 Jun 2026 17:24:54 +0000</pubDate>
      <link>https://dev.to/e-mc2/ekkojs-the-new-challenger-1h6d</link>
      <guid>https://dev.to/e-mc2/ekkojs-the-new-challenger-1h6d</guid>
      <description>&lt;p&gt;Somewhere between the third config file and the second build step, I stopped having fun.&lt;/p&gt;

&lt;p&gt;It crept up on me slowly. The work I actually wanted to do, writing code that solves a problem, kept getting pushed further and further behind the work of getting ready to write that code. Scaffolding, configuring, wiring tools together, then maintaining all of it. I have been writing JavaScript since 1999, so I had collected a lot of opinions about what was wrong and very little to show for them.&lt;/p&gt;

&lt;p&gt;So I built the runtime I always wanted to use. Three years ago I took the decision to start, in 2024 I sealed the name and took the domain, and now, in the middle of 2026, EkkoJS is finally here, at &lt;a href="https://ekkojs.com" rel="noopener noreferrer"&gt;ekkojs.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fresh start
&lt;/h2&gt;

&lt;p&gt;If I am going to build a new runtime, then I am going to start fresh. No dragging the past along just to make a few people feel at home on day one. Every decision below is one I made on purpose, knowing it would cost me some compatibility, because the whole point was to stop paying for the old mistakes.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Bye bye CommonJS
&lt;/h3&gt;

&lt;p&gt;The future is modular, so let's cut the bridge with the past. EkkoJS is, and stays, ESM only. No compromise.&lt;/p&gt;

&lt;p&gt;Yes, that alone walks away from the CommonJS world, and from the easy interop everyone else keeps alive. I am fine with that. The two module systems were never meant to live together. CommonJS loads synchronously, ESM loads asynchronously, and that single difference is why every runtime that supports both ends up with a pile of special cases to paper over the seam.&lt;/p&gt;

&lt;p&gt;I did not want that pile. One way in, one way out. A static import, top to bottom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ekko:fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// built-in module, ekko: prefix&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ekko:db/orm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// built-in, sub-path&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ekko/asgard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// a package from the store&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;formatUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./lib/user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// local file, extensionless&lt;/span&gt;

&lt;span class="c1"&gt;// No require(), no module.exports, no __dirname. There is nothing else to learn.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`Hello, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imports are always extensionless. Whether the file is &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.ts&lt;/code&gt;, &lt;code&gt;.jsx&lt;/code&gt;, &lt;code&gt;.tsx&lt;/code&gt; or &lt;code&gt;.mjs&lt;/code&gt;, you import it by name and the runtime resolves the rest. The runtime enforces it at build time, so writing the extension is an error. One rule, no exceptions, nothing to argue about in a review.&lt;/p&gt;

&lt;p&gt;And when you genuinely need to load something at runtime, dynamic &lt;code&gt;import()&lt;/code&gt; is there too, same rules, same resolution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// load it only when you actually need it&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;runMigration&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./db/migrate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bye bye node_modules
&lt;/h3&gt;

&lt;p&gt;Here is the one most people will trip over, so let me be direct. EkkoJS does not have a &lt;code&gt;node_modules&lt;/code&gt;. Dependencies do not get copied into your project folder, ever.&lt;/p&gt;

&lt;p&gt;When you add a package, it goes into a single local store on your machine, one copy per version, shared by every project that asks for it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko add @ekko/asgard          &lt;span class="c"&gt;# resolves, downloads, installs into the store&lt;/span&gt;
ekko add @ekko/asgard@1.0.0    &lt;span class="c"&gt;# a specific version&lt;/span&gt;
ekko add &lt;span class="nt"&gt;--build&lt;/span&gt; some-tool     &lt;span class="c"&gt;# a build-only dependency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your project keeps a short list of what it depends on in &lt;code&gt;ekko.json&lt;/code&gt;, and the exact versions are pinned in &lt;code&gt;ekko.lock&lt;/code&gt;. That is it. No folder with thousands of nested directories, no copy of the same library sitting in fifteen different projects, no waiting for the disk to finish writing a small country's worth of files before you can start.&lt;/p&gt;

&lt;p&gt;The mental model is simple. Your project declares what it needs. The store holds the bytes. The same version is installed once and reused everywhere, instead of being copied so many times the folder grows its own gravity.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript is a first class citizen
&lt;/h3&gt;

&lt;p&gt;TypeScript is a first class citizen here, treated exactly like JavaScript, with no configuration needed.&lt;/p&gt;

&lt;p&gt;There is no &lt;code&gt;tsconfig.json&lt;/code&gt; to write, no compiler to install, no build step to wire up before you can run a single line. You point EkkoJS at a &lt;code&gt;.ts&lt;/code&gt; file and it runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko run main.ts
ekko run main        &lt;span class="c"&gt;# the extension is optional, same as everywhere else&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can mix &lt;code&gt;.ts&lt;/code&gt; and &lt;code&gt;.js&lt;/code&gt; in the same project without thinking about it, because imports are extensionless and the runtime resolves the right file for you. Types are there while you write, and they get out of the way when you run.&lt;/p&gt;

&lt;p&gt;We never had to configure JavaScript to make it run. With EkkoJS, you do not configure TypeScript either. It just runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  More than a runtime
&lt;/h2&gt;

&lt;p&gt;A runtime that only runs scripts gets dull fast. What I wanted was a single tool that could build the things I actually build, without dragging in a different stack for each one.&lt;/p&gt;

&lt;p&gt;So EkkoJS ships the targets out of the box, all from the same runtime, the same language, and the same store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Libraries.&lt;/strong&gt; Write a package, pack it into a single file, share it. The thing you build is the thing other projects depend on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web, full stack.&lt;/strong&gt; React on the front, a real backend behind it, SEO handled. This is Rune, and it gets its own section below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI.&lt;/strong&gt; Real command line tools, with argument parsing, options and colored output, in a handful of lines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TUI.&lt;/strong&gt; Rich terminal applications with panels, layouts and live updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desktop.&lt;/strong&gt; Native desktop applications, with no Electron and no rebuilding all your native dependencies just to ship a window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this comes from the runtime itself, not from a pile of third party packages glued together and prayed over. One install, and you can reach for any of these the moment you need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  One file to ship: the .ekl
&lt;/h2&gt;

&lt;p&gt;When a project is ready to leave your machine, you pack it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko pack
&lt;span class="c"&gt;# → my-project-1.0.0.any.any.ekl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single &lt;code&gt;.ekl&lt;/code&gt; file is the whole project: your transpiled sources, the native libraries it needs, the assets it reads, and the &lt;code&gt;ekko.json&lt;/code&gt; and &lt;code&gt;ekko.lock&lt;/code&gt; so it resolves its dependencies exactly the way it did on your disk. Everything is compressed per entry, checksummed with SHA-256, and optionally signed with ECDSA. One file to ship, one file to run, and a &lt;code&gt;dist&lt;/code&gt; folder you never have to babysit.&lt;/p&gt;

&lt;p&gt;A runnable project starts straight from the archive, with no extraction step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko run &lt;span class="nt"&gt;--ekl&lt;/span&gt; my-app.ekl &lt;span class="nt"&gt;--allow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An &lt;code&gt;.ekl&lt;/code&gt; is more than something you publish to a registry. Anything you can run in EkkoJS runs from one just as well, a CLI tool, a server, a full Rune site, all from that single file.&lt;/p&gt;

&lt;h3&gt;
  
  
  The .ekl is the filesystem
&lt;/h3&gt;

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

&lt;p&gt;Which leads to the part I find elegant. When an app runs from its &lt;code&gt;.ekl&lt;/code&gt;, the archive becomes its filesystem.&lt;/p&gt;

&lt;p&gt;Every &lt;code&gt;ekko:fs&lt;/code&gt; read resolves against an in-memory virtual filesystem built from everything you packed. Reads look in that VFS first and only fall back to the real disk if the path was not packed. So the app always finds its own bundled assets, wherever you copied the file, and reading its own resources needs no &lt;code&gt;fs&lt;/code&gt; permission, because it is reading itself, not the host's disk.&lt;/p&gt;

&lt;p&gt;Writes are the mirror image. They always go to the real filesystem, rooted next to the archive, so the app can read its sealed contents and still write where it is allowed to. The bundle stays read-only and honest, and the host stays in control of what gets touched.&lt;/p&gt;

&lt;h2&gt;
  
  
  A rich standard library
&lt;/h2&gt;

&lt;p&gt;Like any runtime worth using, EkkoJS ships a deep standard library, so you can start building immediately instead of shopping for a dependency every time you need to hash a string or open a socket. Every module lives behind the &lt;code&gt;ekko:&lt;/code&gt; prefix, and every one of them answers to the permission system.&lt;/p&gt;

&lt;p&gt;Here is the surface, grouped by what you would reach for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System and I/O&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:fs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;File system access, synchronous and CWD-relative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:fs/path&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Path building and normalization, cross-platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:net&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Raw TCP and UDP sockets and DNS, client and server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:process&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Spawn child processes, read env, args, signals, exit codes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:ffi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Call into native C-ABI libraries directly from JS or TS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Data, text and time&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:crypto&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hashing, AES and RSA encryption, key derivation, ECDSA signatures, secure random&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:compress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Compression and decompression, gzip, deflate and brotli&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:datetime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dates, durations and timezones with real IANA support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Image decoding, encoding, resizing and transformation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:text/json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSON parsing and serialization beyond the built-in &lt;code&gt;JSON&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:text/encoding&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Base64, hex and UTF-8 encoders and decoders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:text/regex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Regular-expression helpers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Databases&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:db&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low-level access across SQLite, Postgres, MySQL, SQL Server and Mongo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:db/orm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A typed query builder over the same drivers, swap the driver without rewriting your queries&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Web and real time&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP and WebSocket server with security middleware built in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:web/validate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Schema validation for bodies, params and queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:web/graphql&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A GraphQL server that plugs into &lt;code&gt;ekko:web&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:web/realtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Real-time channels and rooms over WebSocket&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Auth and access control&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:auth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sessions, JWT and password hashing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:auth/rbac&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Role-based access control, roles, permissions and policy checks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Full stack (Rune)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:rune&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The full-stack framework, &lt;code&gt;createApp&lt;/code&gt;, pages and middleware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:rune/router&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SSR-first then client-side routing, &lt;code&gt;Link&lt;/code&gt; and &lt;code&gt;useRouter&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:rune/mimir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mimir, the cross-frontier state management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:rune/seo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SEO helpers, canonical URLs, sitemap and robots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:ssr&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The standalone server-side rendering engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:ssr/css&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scoped Sass and CSS modules for server rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Application targets&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:app/cli&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CLI framework, command parser, colored output and prompts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:app/tui&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TUI framework for rich terminal applications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:app/gui&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;GUI framework for native desktop applications&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Jobs, logging and testing&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Module&lt;/th&gt;
&lt;th&gt;What it gives you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:job/cron&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cron-style scheduled jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:job/queue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Background job queues with retries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Structured logging with levels and formats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The built-in test runner, &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;expect&lt;/code&gt;, mocks and coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ekko:test/assert&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A standalone assertion library&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On top of all of these sits the global &lt;code&gt;Ekko&lt;/code&gt; namespace for the runtime itself, with &lt;code&gt;Ekko.spawn&lt;/code&gt;, &lt;code&gt;Ekko.parallel&lt;/code&gt; and &lt;code&gt;Ekko.Channel&lt;/code&gt; for threading, plus &lt;code&gt;Ekko.args&lt;/code&gt; and &lt;code&gt;Ekko.env&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native code, the easy way
&lt;/h2&gt;

&lt;p&gt;Calling into a native library should be boring, so in EkkoJS it is. You point &lt;code&gt;ekko:ffi&lt;/code&gt; at a shared library, declare the functions you want with their argument and return types, and call them like any other function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dlopen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ekko:ffi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// The C math library has a different name on each OS, so pick it from Ekko.platform.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;win32&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;msvcrt.dll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;darwin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;libSystem.B.dylib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nx"&gt;Ekko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;libm.so.6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;libm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;f64&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;libm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;144&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// 12&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;libm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;  &lt;span class="c1"&gt;// 1024&lt;/span&gt;
&lt;span class="nx"&gt;libm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole ceremony. The runtime handles the conversions across the boundary, numbers, strings, buffers and pointers, and FFI still answers to the permission system, so a package can call its own bundled binary while anything external stays behind a deliberate, named grant.&lt;/p&gt;

&lt;p&gt;And here is where it pays off on the desktop. Anyone who has built a desktop app on the usual stack knows the native rebuild dance, where the moment Node and Electron disagree on an ABI you are recompiling native modules and praying. EkkoJS ships its own native layer and packs the right binary straight into your &lt;code&gt;.ekl&lt;/code&gt;, so the desktop app carries the native code it needs and runs. No rebuild step, no version roulette between two runtimes that were never quite in sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing is part of the deal
&lt;/h2&gt;

&lt;p&gt;If I want everything I need out of the box, then testing has to be in the box too. Fully. So EkkoJS ships a complete test framework and a coverage reporter inside the runtime, with nothing to install and nothing to configure.&lt;/p&gt;

&lt;p&gt;The API is the one you already know. &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;expect&lt;/code&gt;, plus mocks when you need them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// math.test.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ekko:test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;addition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;adds two numbers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// async tests are awaited for you&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resolves a value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Name your files &lt;code&gt;*.test.ts&lt;/code&gt; and run them. The runner discovers them on its own, needs no permissions, and exits non-zero when something fails, so it drops straight into CI without ceremony.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko &lt;span class="nb"&gt;test&lt;/span&gt;                  &lt;span class="c"&gt;# discover and run every *.test.ts&lt;/span&gt;
ekko &lt;span class="nb"&gt;test &lt;/span&gt;math.test.ts     &lt;span class="c"&gt;# run a single file&lt;/span&gt;
ekko &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--coverage&lt;/span&gt;       &lt;span class="c"&gt;# collect a coverage report while you are at it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Coverage is built in the same way. One flag produces an lcov report and an HTML view you can open in a browser, for both JavaScript and TypeScript, with no extra tooling to bolt on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security first, deny by default
&lt;/h2&gt;

&lt;p&gt;A program in EkkoJS starts with nothing. No file system, no network, no environment, no process spawning, no crypto, no FFI. The first time the code reaches for a native capability it was not granted, it gets a &lt;code&gt;PermissionError&lt;/code&gt; and stops.&lt;/p&gt;

&lt;p&gt;You decide what it can touch, with one flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko run app.ts                          &lt;span class="c"&gt;# no grants, native calls throw&lt;/span&gt;
ekko run &lt;span class="nt"&gt;--allow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fs,net,crypto app.ts    &lt;span class="c"&gt;# grant whole categories&lt;/span&gt;
ekko run &lt;span class="nt"&gt;--allow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;all app.ts              &lt;span class="c"&gt;# grant everything, for when you are just hacking&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While you are building, &lt;code&gt;--allow=all&lt;/code&gt; keeps you out of your own way. When you ship, you grant exactly what the code needs, and you can scope each grant down to a path, a host or a single variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko run &lt;span class="nt"&gt;--allow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fs:./data/&lt;span class="k"&gt;**&lt;/span&gt; app.ts            &lt;span class="c"&gt;# the file system, but only under ./data&lt;/span&gt;
ekko run &lt;span class="nt"&gt;--allow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;net:api.example.com app.ts     &lt;span class="c"&gt;# the network, but only to one host&lt;/span&gt;
ekko run &lt;span class="nt"&gt;--allow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;env&lt;/span&gt;:DATABASE_URL app.ts        &lt;span class="c"&gt;# one environment variable, nothing else&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The path checks resolve symlinks before they decide, so a link inside an allowed folder that points somewhere it should not goes nowhere. A &lt;code&gt;./data/link&lt;/code&gt; aimed at &lt;code&gt;/etc/passwd&lt;/code&gt; is denied even with &lt;code&gt;fs:./data/**&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also write the grants once in &lt;code&gt;ekko.json&lt;/code&gt; so you never retype a flag, and the CLI still wins when you need to override:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"net"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"DATABASE_URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"API_KEY"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The doctrine behind it is simple. Developer tools like &lt;code&gt;ekko test&lt;/code&gt; and &lt;code&gt;ekko dev&lt;/code&gt; run with full trust, because that is your machine and your code. Shipped code, run with &lt;code&gt;ekko run&lt;/code&gt;, gets the smallest set of capabilities that lets it do its job. The runtime makes the safe path the easy one, so locking things down is the default rather than the heroic afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rune, the full stack framework
&lt;/h2&gt;

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

&lt;p&gt;We have all lived this one. You build a slick client-side app, everything is fast and smooth, and then someone asks the obvious question: how does Google see it? So you bolt on server-side rendering, and suddenly every navigation is a round trip to the server, and the snappy app you were proud of feels like it is wading through mud. You traded performance for SEO, and nobody is happy.&lt;/p&gt;

&lt;p&gt;Or the other classic. The app is gorgeous and client-side first, and then a user presses F5 halfway through a flow and the whole thing forgets who it is. Empty screen, lost context, back to the start. One tap of the refresh key and your app has amnesia.&lt;/p&gt;

&lt;p&gt;Rune is my answer to both. You can see it at &lt;a href="https://rune.ekkojs.com" rel="noopener noreferrer"&gt;rune.ekkojs.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The philosophy fits in one line: server-rendered on the first load, fully client side after. The first paint comes from the server, so any URL you land on is real and indexable, which keeps SEO happy. From there you are a single-page app, navigation stays on the client, and nothing does a useless round trip just to redraw a page. You get the SEO without paying for it in performance.&lt;/p&gt;

&lt;p&gt;A page is a React component, plus an optional &lt;code&gt;ssr()&lt;/code&gt; that runs on the server for that first load and feeds the metadata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// pages/index.tsx&lt;/span&gt;
&lt;span class="c1"&gt;// ssr() runs on the server, on first load only, and sets the page metadata,&lt;/span&gt;
&lt;span class="c1"&gt;// so the URL is fully indexable before any JavaScript runs.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home, EkkoJS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Server-rendered, then client side.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// After that first paint, this is a normal React app, navigation stays on the client.&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello from Rune&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the refresh problem? Rune ships Mimir, a state library that lives across the frontier. The same state flows out of the server render, into the client, and keeps going there, surviving a refresh. So F5 stops being the button that wipes your app's memory.&lt;/p&gt;

&lt;p&gt;That is the whole idea. SEO without sacrificing performance, and a client-side app that does not panic the moment someone reaches for refresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asgard, the component suite
&lt;/h2&gt;

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

&lt;p&gt;A framework is more pleasant when you are not drawing every button from scratch, so EkkoJS has an official component suite, Asgard.&lt;/p&gt;

&lt;p&gt;It is a batteries-included React component library made for Rune apps. Buttons, text fields, selects and switches, date and color pickers, data tables, tree views, alerts, toasts, tooltips and drawers, a real layout engine, and an IDE-grade docking system for the kind of app that has panels you drag and split. The components render on the server with Rune and hydrate cleanly on the client, so they fit the SSR-first model without a fight.&lt;/p&gt;

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

&lt;p&gt;You add it like any other package and wrap your app in a theme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ThemeProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ekko/asgard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;themes&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@ekko/asgard/theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ThemeProvider&lt;/span&gt; &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;themes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nord&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt; &lt;span class="na"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"filled"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Get started&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ThemeProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Theming runs deep. There are 27 built-in palettes, Nord, Dracula, Tokyo Night, Catppuccin and more, or you bring your own, and a bridge that re-themes your own SCSS the moment you switch. Keyboard navigation, focus management and ARIA roles come built in, so accessibility is the starting point rather than a later cleanup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bifrost, the registry
&lt;/h2&gt;

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

&lt;p&gt;A package format is only half the story. The other half is somewhere to send it, so EkkoJS has its own registry, Bifrost.&lt;/p&gt;

&lt;p&gt;The flow is the one you would expect. You pack your project into a single &lt;code&gt;.ekl&lt;/code&gt;, you log in once, and you publish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko login                  &lt;span class="c"&gt;# stores a token in ~/.ekko/config.json&lt;/span&gt;
ekko publish &lt;span class="nt"&gt;--dry-run&lt;/span&gt;      &lt;span class="c"&gt;# see exactly what would be uploaded, no surprises&lt;/span&gt;
ekko publish                &lt;span class="c"&gt;# pack and push to Bifrost&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other side, installing it is the same one command as any other dependency, and it lands in the shared store rather than in a folder inside the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko add @me/app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every package is versioned, and if you have a signing key it is signed with ECDSA on the way up, so what you publish is what people install, provably. The same crypto runs in the CLI and in the registry, one implementation on both ends, so there is no seam where a signature means one thing here and another thing there.&lt;/p&gt;

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

&lt;p&gt;Visibility is yours to set in &lt;code&gt;ekko.json&lt;/code&gt;, public or private, and the registry checks quota and validity before a single byte is uploaded. You always know what is going out before it goes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero-shot runtime coding
&lt;/h2&gt;

&lt;p&gt;I can already hear the objection. "A brand new runtime in 2026? My AI assistant has never heard of it. I will be flying blind, autocompleting into the void, fighting a model that keeps trying to write me a &lt;code&gt;package.json&lt;/code&gt;."&lt;/p&gt;

&lt;p&gt;It is a fair fear. It is also the first thing I solved.&lt;/p&gt;

&lt;p&gt;The entire documentation ships inside the binary. &lt;code&gt;ekko doc&lt;/code&gt; browses it right in your terminal, across three topics: the runtime, the Asgard components, and the Rune framework. You list a topic's pages, then open any one of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko doc js                 &lt;span class="c"&gt;# list the runtime's pages, each one numbered&lt;/span&gt;
ekko doc js 007             &lt;span class="c"&gt;# open a page (here, Permissions)&lt;/span&gt;
ekko doc js 007 &lt;span class="nt"&gt;--llm&lt;/span&gt;       &lt;span class="c"&gt;# the same page as raw markdown, written for a machine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last flag is the one that matters for tooling. &lt;code&gt;--llm&lt;/code&gt; prints the page as clean markdown, so an AI assistant can list the pages and pull whichever ones it needs, on demand, as plain text.&lt;/p&gt;

&lt;p&gt;Drop the flag and you get the same page rendered for a human, formatted right there in the terminal, with headings, tables and syntax-highlighted code. And if you would rather read and explore than type page numbers, &lt;code&gt;-i&lt;/code&gt; opens a full interactive browser, a split-pane TUI you navigate with the keyboard.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko doc js 007             &lt;span class="c"&gt;# human-friendly, rendered in the terminal&lt;/span&gt;
ekko doc js &lt;span class="nt"&gt;-i&lt;/span&gt;              &lt;span class="c"&gt;# full interactive TUI, browse the whole topic&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No fine-tuning, no prior training, no waiting for the next model to maybe learn about EkkoJS. Any capable AI can read the live, exact documentation for the version you are actually running, and code against it from a standing start. Point your assistant at &lt;code&gt;ekko doc&lt;/code&gt; and it learns the runtime as well as the docs do, today, not whenever a training cut-off catches up.&lt;/p&gt;

&lt;p&gt;So the runtime being new stops being a problem and starts being the point. It documents itself, for you and for the machine sitting next to you, and the guidance is always current because it comes from the same binary that runs your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it stands
&lt;/h2&gt;

&lt;p&gt;Let me be honest about the stage we are at. EkkoJS is a technology preview until October. Breaking changes are already on the roadmap, on purpose, because I would rather get the design right in the open than freeze the wrong decisions early.&lt;/p&gt;

&lt;p&gt;So here is my ask. Test it. Build something real with it. Push on it and tell me where it hurts. But please, do not ship it to production yet. That day is coming, and this is not it.&lt;/p&gt;

&lt;p&gt;Stay tuned. A lot of articles and tutorials are on the way, and I will be walking through every part of this in more depth. This was the overview. The rest is coming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Installing is a single command, and that command is the whole toolchain. It runs your code, manages your packages, runs your tests, and builds your projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS / Linux&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ekkojs.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Windows (PowerShell)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://ekkojs.com/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then write your first line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.ts&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, EkkoJS!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ekko run main.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. No &lt;code&gt;tsconfig&lt;/code&gt;, no bundler, no folder full of dependencies. If you have read this far, the best thing you can do is install it, build something small, and tell me what you think. EkkoJS is born from the Norwegian word for echo, so write once, and let it resonate.&lt;/p&gt;

&lt;p&gt;Enjoy using it.&lt;/p&gt;

&lt;p&gt;Francois, creator of EkkoJS.&lt;/p&gt;

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