<?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: Art</title>
    <description>The latest articles on DEV Community by Art (@artanidos).</description>
    <link>https://dev.to/artanidos</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%2F3817798%2Fc8737449-667c-4095-b2ec-393e198fbfb4.jpg</url>
      <title>DEV Community: Art</title>
      <link>https://dev.to/artanidos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/artanidos"/>
    <language>en</language>
    <item>
      <title>A CMS with no database and no build step: your site is just a Git repo</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Wed, 30 Sep 2026 06:55:05 +0000</pubDate>
      <link>https://dev.to/artanidos/a-cms-with-no-database-and-no-build-step-your-site-is-just-a-git-repo-3855</link>
      <guid>https://dev.to/artanidos/a-cms-with-no-database-and-no-build-step-your-site-is-just-a-git-repo-3855</guid>
      <description>&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%2Fm40lwevubaliwud489e1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm40lwevubaliwud489e1.jpg" alt=" " width="800" height="291"&gt;&lt;/a&gt;&lt;br&gt;
Recently Angela, a musician, sent me the link to her new website: &lt;a href="https://music.angela-mahr.de" rel="noopener noreferrer"&gt;music.angela-mahr.de&lt;/a&gt;. She built it herself. She didn't use a page builder or a WordPress theme. She told Claude Code what she wanted, and it wrote the pages for &lt;strong&gt;ForgeCMS&lt;/strong&gt;, the small CMS I've been building since March. Then she built a second one: &lt;a href="https://lebe-dich.info" rel="noopener noreferrer"&gt;lebe-dich.info&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's when I realized the design decisions behind ForgeCMS might be interesting to other developers too. This post explains how it works and why it's built this way.&lt;/p&gt;
&lt;h2&gt;
  
  
  The whole architecture in one line
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser → Caddy (TLS) → forgecms → Codeberg (SML + Markdown)
                                   ↘ local cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;ForgeCMS is a single Go binary. Your site is a folder in a public Git repo: pages in SML, longer texts in Markdown, images in &lt;code&gt;static/&lt;/code&gt;. When a request comes in, ForgeCMS fetches the files it needs from Codeberg, caches them, and renders HTML.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No database.&lt;/strong&gt; Your history, backups and reviews all happen in Git.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No build step.&lt;/strong&gt; Commit a change (even in Codeberg's web editor), and it's live within a few minutes. There's no CI pipeline and nothing to regenerate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No admin backend&lt;/strong&gt; to patch, and no plugin ecosystem to keep compatible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One process, many domains.&lt;/strong&gt; Put one config per domain in &lt;code&gt;sites/&amp;lt;domain&amp;gt;/app.sml&lt;/code&gt;, and ForgeCMS switches to multi-site mode. Our production box serves eight sites from one process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dependencies are the Go standard library, &lt;a href="https://github.com/yuin/goldmark" rel="noopener noreferrer"&gt;goldmark&lt;/a&gt; for Markdown (with chroma for code highlighting), and &lt;a href="https://codeberg.org/CrowdWare/sml-go" rel="noopener noreferrer"&gt;sml-go&lt;/a&gt; for the page language.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pages in SML, not JSON or YAML
&lt;/h2&gt;

&lt;p&gt;Pages are written in SML: elements with properties and children. Here's a complete page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Page {
    title: "My Bakery"

    Heading { level: "1" text: "Fresh bread, every morning" }
    Markdown { src: "main.md" }

    Cards {
        Card { title: "Sourdough" text: "Baked daily from a 12-year-old starter." }
        Card { title: "Opening hours" text: "Tue–Sat, 7:00–13:00" }
    }

    ContactForm { }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need HTML, CSS or JavaScript. SML is also a format that language models get right on the first try. It has no indentation rules to break, no quoting puzzles like YAML, and no trailing-comma errors like JSON. Every element is written the same way, so a model that has seen three examples can write a fourth.&lt;/p&gt;

&lt;p&gt;That's the real reason Angela could build her site. The repo contains an &lt;a href="https://codeberg.org/CrowdWare/ForgeCMS/src/branch/main/AI.md" rel="noopener noreferrer"&gt;AI.md&lt;/a&gt; that explains the whole system to a coding agent: the elements, the folder layout, how languages work, and how to deploy. You point Claude Code at it and describe the site you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Why not a static site generator?"
&lt;/h2&gt;

&lt;p&gt;I get this question a lot, and it's a fair one. Hugo and friends are great. What bothered me is the part between "I changed a sentence" and "it's live": a build, a pipeline, an artifact, a deploy. For the people I build sites for (small associations, therapists, musicians), that pipeline is exactly where things break and where they need me.&lt;/p&gt;

&lt;p&gt;With ForgeCMS the repo &lt;em&gt;is&lt;/em&gt; the deployment. Anyone who can edit a file on Codeberg can update their site. If they break the syntax, the last good version keeps being served. A typo never takes the site down.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned the hard way: caching against a Git host
&lt;/h2&gt;

&lt;p&gt;Fetching content from Codeberg at request time sounds fragile, and the first version was. On September 25, after a routine restart, a burst of bot traffic made ForgeCMS fetch the same &lt;code&gt;404.sml&lt;/code&gt; about 800 times. Codeberg allows 250 raw-file requests per 10 minutes per IP. We got a &lt;code&gt;429&lt;/code&gt; with &lt;code&gt;Retry-After: 600&lt;/code&gt;, and three sites returned &lt;code&gt;503&lt;/code&gt; for about 20 minutes.&lt;/p&gt;

&lt;p&gt;The fix was three rules that I now think every "fetch from origin" system needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Revalidate at most every 5 minutes&lt;/strong&gt; per file, no matter how many requests come in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use one shared backoff for the whole origin&lt;/strong&gt;, and respect &lt;code&gt;Retry-After&lt;/code&gt;. When Codeberg says "wait", every file waits, not just the one that got the 429.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always serve the stale copy&lt;/strong&gt; when the origin fails. A slightly old page is better than an error page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With those rules, Codeberg can have a bad day and visitors don't notice. The same fallback also works for static files: if an image isn't deployed on the server, ForgeCMS fetches it from the repo's &lt;code&gt;static/&lt;/code&gt; folder. This morning I added the banner at the top of this post to our developer page with nothing but a &lt;code&gt;git push&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modules for the boring-but-necessary parts
&lt;/h2&gt;

&lt;p&gt;The core covers pages, menus, themes, several languages per site (a &lt;code&gt;de/&lt;/code&gt;, &lt;code&gt;es/&lt;/code&gt;, … subfolder with fallback), per-page SEO descriptions and embeds. The things that need server-side state are modules in the same binary. You switch them on with a block in &lt;code&gt;app.sml&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blog&lt;/strong&gt; with photos, Atom feed and share buttons without trackers (&lt;a href="https://art.ubuntu-pirates.com" rel="noopener noreferrer"&gt;live&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt; with flyers, event pages and &lt;code&gt;.ics&lt;/code&gt; export (&lt;a href="https://crowdware.info/events-demo" rel="noopener noreferrer"&gt;demo&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contact form and newsletter&lt;/strong&gt; with form fields defined in SML, double opt-in and mailings written in Markdown (&lt;a href="https://crowdware.info/contact" rel="noopener noreferrer"&gt;live&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shop&lt;/strong&gt; paid in Ğ1 or euros, with digital delivery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature requests&lt;/strong&gt; with voting and magic-link login (&lt;a href="https://crowdware.info/forgecms/features" rel="noopener noreferrer"&gt;live&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whatever these modules need to store, like orders or subscribers, is written as small SML files on the server. There's still no database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quickstart
&lt;/h2&gt;

&lt;p&gt;You need Go 1.22 or newer and a public repo on Codeberg for your content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://codeberg.org/CrowdWare/ForgeCMS.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ForgeCMS
go build &lt;span class="nt"&gt;-o&lt;/span&gt; forgecms &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# point the Site { } block at your content repo&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;app-demo.sml app.sml

./forgecms &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put Caddy in front for HTTPS and you're done. For a real multi-site setup, our production repo is public: &lt;a href="https://codeberg.org/CrowdWare/sites" rel="noopener noreferrer"&gt;CrowdWare/sites&lt;/a&gt; contains the content, the per-domain configs and the deploy script for every site mentioned here. The page describing ForgeCMS for developers is &lt;a href="https://codeberg.org/CrowdWare/sites/src/branch/main/crowdware/forgecms-developers.sml" rel="noopener noreferrer"&gt;one SML file&lt;/a&gt; in that repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;ForgeCMS is free under the GPLv3 for non-commercial use. If you make money with it, for example by hosting sites for paying customers, there's a &lt;a href="https://codeberg.org/CrowdWare/ForgeCMS/src/branch/main/LICENSE-COMMERCIAL.md" rel="noopener noreferrer"&gt;commercial license&lt;/a&gt;. Profits aren't paid out to individuals. They go into &lt;a href="https://ubuntu-pirates.com" rel="noopener noreferrer"&gt;UBUNTU land projects&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it, break it, tell me
&lt;/h2&gt;

&lt;p&gt;Everything in one place: &lt;strong&gt;&lt;a href="https://crowdware.info/forgecms/developers" rel="noopener noreferrer"&gt;crowdware.info/forgecms/developers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source: &lt;a href="https://codeberg.org/CrowdWare/ForgeCMS" rel="noopener noreferrer"&gt;codeberg.org/CrowdWare/ForgeCMS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Missing something? &lt;a href="https://crowdware.info/forgecms/features" rel="noopener noreferrer"&gt;Propose a feature or vote&lt;/a&gt;. The most-voted requests get built first, and four of the first five are already done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd especially like to hear from people who run sites for others: what would you need before you'd move a client off WordPress?&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>ForgeCMS: a CMS without a database, and our users decide what gets built next</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Tue, 29 Sep 2026 08:03:02 +0000</pubDate>
      <link>https://dev.to/artanidos/forgecms-a-cms-without-a-database-and-our-users-decide-what-gets-built-next-5ghj</link>
      <guid>https://dev.to/artanidos/forgecms-a-cms-without-a-database-and-our-users-decide-what-gets-built-next-5ghj</guid>
      <description>&lt;p&gt;Six months ago &lt;a href="https://crowdware.info/forgecms" rel="noopener noreferrer"&gt;ForgeCMS&lt;/a&gt; was a weekend experiment: can a website run without WordPress, without a database and without a build step? Today it runs several real sites, and it covers most of what a small business, an association or a creator needs from a website.&lt;/p&gt;

&lt;p&gt;This post gives an overview of what's there, how it works, and how you can tell us what should come next.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea in one paragraph
&lt;/h2&gt;

&lt;p&gt;ForgeCMS is a single Go binary. Your content lives as Markdown and small SML files in a Git repo on &lt;a href="https://codeberg.org" rel="noopener noreferrer"&gt;Codeberg&lt;/a&gt;. The server fetches the files at request time, caches them, and renders HTML. There's no database, no admin backend to keep patched, and no build pipeline. You edit a file in Git, and a few minutes later the change is live.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a page looks like
&lt;/h2&gt;

&lt;p&gt;Pages are written in SML, a simple markup of nested blocks with properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sml"&gt;&lt;code&gt;&lt;span class="n"&gt;Page&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"My Bakery"&lt;/span&gt;

    &lt;span class="n"&gt;Heading&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Fresh bread, every morning"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Family-owned bakery in Wittenberg. Stone oven, no additives."&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Cards&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Sourdough"&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Baked daily from a 12-year-old starter."&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;Card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Opening hours"&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Tue–Sat, 7:00–13:00"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"mailto:hallo@meinebaeckerei.de"&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Get in touch"&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;Longer texts are plain Markdown. You can read SML in seconds, and it turns out an AI can write it just as easily. That was a deliberate choice: many of our sites are edited by describing the change to Claude Code on the server, and it gets SML right on the first try.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's already in the box
&lt;/h2&gt;

&lt;p&gt;The free core covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pages in SML and Markdown, menu, footer, themes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;multiple languages&lt;/strong&gt;: a &lt;code&gt;de/&lt;/code&gt;, &lt;code&gt;en/&lt;/code&gt;, &lt;code&gt;es/&lt;/code&gt; … subfolder per language, with fallback to the default&lt;/li&gt;
&lt;li&gt;menu, footer and routes can live in the content repo too, so editing the site never requires touching the server&lt;/li&gt;
&lt;li&gt;sliders, cards, tables, images, YouTube embeds, privacy-friendly analytics (Umami)&lt;/li&gt;
&lt;li&gt;a content cache that keeps serving the last good copy if Git hosting is slow or down&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of that there are &lt;strong&gt;modules&lt;/strong&gt;, each built for a real site:&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 does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Posts with photos, pages, Atom feed, drafts and scheduled posts, share buttons without third-party scripts, several languages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Events&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dates and gigs with flyer thumbnails, an event page per date, past events, &lt;code&gt;.ics&lt;/code&gt; calendar export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Contact form&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Text fields, checkboxes, radio buttons, selection lists; messages go by email and are not stored&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Newsletter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Double opt-in, mailings written in Markdown in a small admin page, one-click unsubscribe (RFC 8058)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Physical and digital products, paid in &lt;a href="https://duniter.org/g1/" rel="noopener noreferrer"&gt;June (Ğ1)&lt;/a&gt; or by euro bank transfer, no payment provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Feature requests&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Visitors propose features and vote, one vote per person&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Everything that needs to be stored, like orders or newsletter addresses, is stored as small SML files on the server. Still no database.&lt;/p&gt;

&lt;p&gt;A few of these are running in public:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the blog: &lt;a href="https://art.ubuntu-pirates.com" rel="noopener noreferrer"&gt;art.ubuntu-pirates.com&lt;/a&gt;, a travel blog of a bike trip to Spain, written on the road&lt;/li&gt;
&lt;li&gt;the events demo: &lt;a href="https://crowdware.info/events-demo" rel="noopener noreferrer"&gt;crowdware.info/events-demo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;the shop demo: &lt;a href="https://crowdware.info/shop-module" rel="noopener noreferrer"&gt;crowdware.info/shop-module&lt;/a&gt; (the demo orders are real, you get a handwritten postcard)&lt;/li&gt;
&lt;li&gt;contact form and newsletter: &lt;a href="https://crowdware.info/contact" rel="noopener noreferrer"&gt;crowdware.info/contact&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Login without passwords
&lt;/h2&gt;

&lt;p&gt;The modules that need a login (feature voting, newsletter admin) use &lt;strong&gt;magic links&lt;/strong&gt;. You enter your email address and get a link, and that's it. There are no passwords to leak and no accounts to manage. Login tokens live only in memory.&lt;/p&gt;

&lt;p&gt;We use the email address for one more thing: it keeps feature voting fair. One address, one vote per request, and you can take your vote back any time. Nobody sees who voted for what.&lt;/p&gt;

&lt;h2&gt;
  
  
  You decide what we build next
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most happy with. On &lt;a href="https://crowdware.info/forgecms/features" rel="noopener noreferrer"&gt;crowdware.info/forgecms/features&lt;/a&gt; anyone can propose a feature for ForgeCMS or vote for the ones they want. The requests with the most votes get built first.&lt;/p&gt;

&lt;p&gt;It works. So far five features have been proposed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contact form&lt;/strong&gt; — done&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event calendar&lt;/strong&gt; — done&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blogging module&lt;/strong&gt; — done (comments are not in yet)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mailing list&lt;/strong&gt; — done, as the newsletter module&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Online course&lt;/strong&gt; (lessons with videos and texts, saved progress) — open&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's four out of five done within a few days of being proposed. The online course is the next candidate, and if it matters to you, a vote helps.&lt;/p&gt;

&lt;p&gt;The voting page itself is the feature-request module, so you're testing it while you use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting: small and cheap
&lt;/h2&gt;

&lt;p&gt;ForgeCMS needs very little. All our sites share one small VPS with a single &lt;code&gt;forgecms&lt;/code&gt; process behind Caddy, which takes care of HTTPS. A €1/month VPS is enough for a small site. The &lt;a href="https://codeberg.org/CrowdWare/ForgeCMS" rel="noopener noreferrer"&gt;README&lt;/a&gt; walks you through setting one up with Claude Code doing the work, even if you've never run a server.&lt;/p&gt;

&lt;h2&gt;
  
  
  License and pricing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The core is open source under &lt;strong&gt;GPLv3&lt;/strong&gt;. For commercial use there's a commercial license.&lt;/li&gt;
&lt;li&gt;Modules are a &lt;strong&gt;one-time license&lt;/strong&gt; of €19 to €39, with no subscription. All six together cost €139.&lt;/li&gt;
&lt;li&gt;If you'd rather not do it yourself, we build the site for you at €130/hour (or 130 Ğ1). Small sites are often done in an hour.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we ever make a profit, it isn't paid out to individuals. It goes into &lt;a href="https://ubuntu-pirates.com" rel="noopener noreferrer"&gt;UBUNTU land projects&lt;/a&gt; that take land out of speculation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it, and tell us what's missing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Propose or vote for a feature:&lt;/strong&gt; &lt;a href="https://crowdware.info/forgecms/features" rel="noopener noreferrer"&gt;https://crowdware.info/forgecms/features&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overview and modules:&lt;/strong&gt; &lt;a href="https://crowdware.info/forgecms" rel="noopener noreferrer"&gt;https://crowdware.info/forgecms&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source code:&lt;/strong&gt; &lt;a href="https://codeberg.org/CrowdWare/ForgeCMS" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare/ForgeCMS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get in touch:&lt;/strong&gt; &lt;a href="https://crowdware.info/contact" rel="noopener noreferrer"&gt;https://crowdware.info/contact&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear what you would need before you'd move a site off WordPress. The best place for that is the feature request page, because there it gets votes.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>cms</category>
    </item>
    <item>
      <title>A web shop without a database or payment provider: the ForgeCMS shop module</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Sat, 26 Sep 2026 15:14:42 +0000</pubDate>
      <link>https://dev.to/artanidos/a-web-shop-without-a-database-or-payment-provider-the-forgecms-shop-module-5e3n</link>
      <guid>https://dev.to/artanidos/a-web-shop-without-a-database-or-payment-provider-the-forgecms-shop-module-5e3n</guid>
      <description>&lt;p&gt;Today the &lt;strong&gt;shop module&lt;/strong&gt; for &lt;a href="https://crowdware.info/forgecms" rel="noopener noreferrer"&gt;ForgeCMS&lt;/a&gt; went live. Your customers can pay in two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in &lt;strong&gt;June (Ğ1)&lt;/strong&gt;, a free currency, or&lt;/li&gt;
&lt;li&gt;in &lt;strong&gt;euros by plain bank transfer&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's no database, no payment provider taking a cut, and no monthly fee. The money goes straight from the buyer to the seller.&lt;/p&gt;

&lt;p&gt;This afternoon I paid for my own test order with 1 Ğ1. Three minutes later the shop had marked the order as paid and sent me my download link.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;How it works for shop owners:&lt;/strong&gt; &lt;a href="https://crowdware.info/shop-module" rel="noopener noreferrer"&gt;https://crowdware.info/shop-module&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Some context: what ForgeCMS is
&lt;/h2&gt;

&lt;p&gt;ForgeCMS is a small CMS written in Go. It has no database and no build step. Pages are small SML files plus Markdown in a Git repo on Codeberg. The server fetches them at request time, caches them, and renders HTML. You edit a page in Git, and a minute later it's live.&lt;/p&gt;

&lt;p&gt;I wanted a shop that fits into this. It shouldn't need a database, it shouldn't need an account with a payment company, and it shouldn't hand buyers' data to anyone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why June (Ğ1)?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://duniter.org/g1/" rel="noopener noreferrer"&gt;Ğ1&lt;/a&gt; is a libre currency that has been running since 2017. Every member creates a small share of new money each day, the &lt;em&gt;universal dividend&lt;/em&gt;, so it works a bit like a basic income built into the currency. Since March 2026 it has been running on Duniter v2, a Substrate-based blockchain. It's not a speculative token, and people in the network use it to pay for goods and services.&lt;/p&gt;

&lt;p&gt;For a shop, what matters is that &lt;strong&gt;every transfer is public and carries a comment&lt;/strong&gt;. The buyer puts the order number in the comment, and the shop can find the payment without any access to the seller's wallet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The catalogue is one text file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sml"&gt;&lt;code&gt;&lt;span class="n"&gt;Catalog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"honey-500"&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"Honey 500 g"&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"12.50"&lt;/span&gt; &lt;span class="n"&gt;priceEur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"9.90"&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"honey.jpg"&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"From our own bees."&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"ebook"&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"My e-book"&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"20"&lt;/span&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="kt"&gt;:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="kt"&gt;digital&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="kt"&gt;text:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="kt"&gt;PDF&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;120&lt;/span&gt; &lt;span class="kt"&gt;pages&lt;/span&gt;&lt;span class="err"&gt;."&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;price&lt;/code&gt; is the price in Ğ1, and &lt;code&gt;priceEur&lt;/code&gt; the price in euros. A product with both prices lets the buyer choose. A product with only one price is sold only in that currency. On a page, &lt;code&gt;Products { }&lt;/code&gt; renders the product cards with an &lt;strong&gt;Order&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;The price always comes from the catalogue, never from the order form.&lt;/p&gt;

&lt;h2&gt;
  
  
  How an order flows
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The buyer fills in a short form: quantity, name, email, and for physical goods a shipping address. Then they click &lt;strong&gt;Place order (payment required)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The server writes the order as a small SML file to disk, e.g. &lt;code&gt;G1-7KQ2MXRA.sml&lt;/code&gt;, and sends two emails, one to the buyer and one to the seller.&lt;/li&gt;
&lt;li&gt;The buyer sees a payment page with the address, the exact amount and the order number.&lt;/li&gt;
&lt;li&gt;The buyer pays and puts the order number into the transfer comment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Detecting Ğ1 payments
&lt;/h3&gt;

&lt;p&gt;A watcher goroutine asks the public Duniter indexer once a minute for new transfers to the shop's address. The indexer has a GraphQL API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="err"&gt;transfers(filter:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;toId&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="n"&gt;equalTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;wallet&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blockNumber&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="n"&gt;greaterThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&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="n"&gt;nodes&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="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blockNumber&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fromId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comment&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="n"&gt;remark&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;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;A transfer is matched to its order by the comment. The watcher waits 10 blocks of confirmations (about a minute) before it counts a payment. Split payments add up, and overpayments are recorded. A transfer without a matching order doesn't get lost: the seller gets an email and sorts it out by hand. The last processed block is stored in a small state file, so a restart doesn't skip or double-count anything.&lt;/p&gt;

&lt;p&gt;The server &lt;strong&gt;never holds a wallet key&lt;/strong&gt;. It only reads public data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Euro payments: one click by the seller
&lt;/h3&gt;

&lt;p&gt;For euros the shop doesn't connect to any bank. There's no banking API and nobody else sees your account. The seller's order email contains a secret confirmation link. When the money is on the account, the seller clicks it, checks the amount on the confirmation page and confirms. From there everything runs the same way as with Ğ1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Digital delivery
&lt;/h3&gt;

&lt;p&gt;For downloads, the paid email contains a license key and a personal download link:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The link is valid for 30 days and 5 downloads.&lt;/li&gt;
&lt;li&gt;The server stores only a SHA-256 hash of the link's token, never the token itself.&lt;/li&gt;
&lt;li&gt;The files don't live in the public content repo. They live in a data folder on the server, and the download handler rejects path traversal and symlinks.&lt;/li&gt;
&lt;li&gt;Before ordering a digital product, the buyer ticks a box saying delivery may start immediately. German and EU law require this so the right of withdrawal ends with the download.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it deliberately doesn't do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;no shopping cart: one product per order, any quantity&lt;/li&gt;
&lt;li&gt;no credit cards, PayPal or Stripe&lt;/li&gt;
&lt;li&gt;no stock management and no automatic invoices&lt;/li&gt;
&lt;li&gt;euro payments need one click from the seller&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a small shop, a creator, a farm shop or a community project, that's usually enough. Every feature I left out is one less thing that can break.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tested for real
&lt;/h2&gt;

&lt;p&gt;Before going public, I ran the whole flow on the live site with a hidden test page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Euro:&lt;/strong&gt; a transfer of 0.01 EUR, confirmed with the link. The order was marked as paid and the emails went out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ğ1:&lt;/strong&gt; 1 Ğ1 for a digital test product. It was detected after 10 confirmations, the order was marked as paid, and the download link arrived by email and worked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I removed the test page.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;See how it works:&lt;/strong&gt; &lt;a href="https://crowdware.info/shop-module" rel="noopener noreferrer"&gt;https://crowdware.info/shop-module&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is June?&lt;/strong&gt; &lt;a href="https://crowdware.info/june" rel="noopener noreferrer"&gt;https://crowdware.info/june&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ForgeCMS source (GPLv3):&lt;/strong&gt; &lt;a href="https://codeberg.org/CrowdWare/ForgeCMS" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare/ForgeCMS&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The shop module is a one-time &lt;strong&gt;€39&lt;/strong&gt; license, with no subscription. If you'd like a shop on your own website, whether you sell in June, in euros or both, &lt;a href="https://crowdware.info/process" rel="noopener noreferrer"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you already use Ğ1, I'd love to hear how you currently sell things with it and what's missing.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>ForgeDesigner Alpha: an AI assistant that builds websites on your own machine</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Thu, 24 Sep 2026 06:49:12 +0000</pubDate>
      <link>https://dev.to/artanidos/forgedesigner-alpha-an-ai-assistant-that-builds-websites-on-your-own-machine-2mdg</link>
      <guid>https://dev.to/artanidos/forgedesigner-alpha-an-ai-assistant-that-builds-websites-on-your-own-machine-2mdg</guid>
      <description>&lt;p&gt;Today I'm releasing the first &lt;strong&gt;alpha of ForgeDesigner&lt;/strong&gt; for &lt;strong&gt;macOS (Apple Silicon)&lt;/strong&gt; and &lt;strong&gt;Linux (x86_64)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;ForgeDesigner is a small desktop app where you describe a website in plain words and an AI assistant builds it: it creates the pages, writes the Markdown, and shows you a live preview. The result is plain files in a folder on your disk. You don't need a hosting account, you don't get locked into a page builder, and nothing lives in somebody else's cloud unless you put it there.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Download:&lt;/strong&gt; &lt;a href="https://codeberg.org/CrowdWare/Forge4D/releases/tag/v2026.9.23-forgedesigner-linux" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare/Forge4D/releases/tag/v2026.9.23-forgedesigner-linux&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I wanted something between "hand-write HTML" and "rent a website builder". The things people use today, WordPress, website builders and IDEs, all ask you to learn their world first. I wanted a single place where I can say &lt;em&gt;"make me a landing page with a short intro and a contact section"&lt;/em&gt;, then look at the files, change a sentence by hand, and ask for the next step.&lt;/p&gt;

&lt;p&gt;ForgeDesigner is built on &lt;strong&gt;&lt;a href="https://codeberg.org/CrowdWare/Forge4D" rel="noopener noreferrer"&gt;Forge 4D&lt;/a&gt;&lt;/strong&gt;, an open platform where apps are written in two small languages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SML&lt;/strong&gt; (Simple Markup Language): declarative UI and content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SMS&lt;/strong&gt; (Simple Script): event handlers and logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole designer UI, including the docks, the file tree, the editor and the assistant tab, is itself an SML/SMS app running on the native Forge runner (C++ on top of Godot 4.6). A few lines from its layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight qml"&gt;&lt;code&gt;&lt;span class="kt"&gt;DockingContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;rightDock&lt;/span&gt;
    &lt;span class="nl"&gt;dockSide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;

    &lt;span class="kt"&gt;VBoxContainer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;preview&lt;/span&gt;
        &lt;span class="nl"&gt;rightDock.title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabPreview&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What works in this alpha
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI assistant with tools.&lt;/strong&gt; The assistant can &lt;code&gt;list_files&lt;/code&gt;, &lt;code&gt;read_file&lt;/code&gt;, &lt;code&gt;write_file&lt;/code&gt; and &lt;code&gt;run_command&lt;/code&gt; inside your workspace folder (&lt;code&gt;~/ForgeWorkspace/...&lt;/code&gt;). You watch it work in the transcript, and the file tree updates as files appear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ForgeCMS plugin.&lt;/strong&gt; The first output target: pages as SML plus Markdown, ready to be pushed to a Git repo and served as a static site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live preview.&lt;/strong&gt; Select a page or a Markdown file and see a layout preview next to the editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editor that stays in sync.&lt;/strong&gt; Every keystroke is saved, and changes the assistant makes show up in the editor right away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline by default.&lt;/strong&gt; Out of the box the assistant runs against a built-in mock: it's free and sends nothing anywhere. Switching to a real model is one config line (see below).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retries.&lt;/strong&gt; If the model provider answers with "overloaded", the request is retried automatically; after that there's a &lt;em&gt;Retry&lt;/em&gt; button.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security model
&lt;/h2&gt;

&lt;p&gt;An AI that can write files and run commands on your machine needs guard rails. ForgeDesigner has these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Permissions are declared and confirmed.&lt;/strong&gt; The app lists what it needs (workspace files, running programs after asking, network access to &lt;code&gt;openrouter.ai&lt;/code&gt;), and the runner asks you once on first start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands are argv, not shell strings.&lt;/strong&gt; A small set (&lt;code&gt;git&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;ssh&lt;/code&gt;, &lt;code&gt;scp&lt;/code&gt;) runs directly. Everything else opens a dialog where you decide, once or for good.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API keys stay in the runner.&lt;/strong&gt; Your key lives in a &lt;code&gt;chmod 600&lt;/code&gt; file in the runner's data folder and is never handed to the app or the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prompt injection is still a real risk. The trusted commands can reach whatever your user can. That's a big part of why this is an alpha.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;macOS (Apple Silicon):&lt;/strong&gt; unzip, then remove the quarantine flag once. The alpha is only ad-hoc signed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xattr &lt;span class="nt"&gt;-dr&lt;/span&gt; com.apple.quarantine ForgeDesigner.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Linux (x86_64):&lt;/strong&gt;&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="nb"&gt;tar &lt;/span&gt;xzf ForgeDesigner-2026.9.23-linux-x86_64.tar.gz
./ForgeDesigner/ForgeDesigner.x86_64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect a real model (OpenRouter)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a key on &lt;a href="https://openrouter.ai" rel="noopener noreferrer"&gt;openrouter.ai&lt;/a&gt; (&lt;em&gt;Keys → Create Key&lt;/em&gt;). Models ending in &lt;code&gt;:free&lt;/code&gt; need no credit.&lt;/li&gt;
&lt;li&gt;Open the app's data folder:

&lt;ul&gt;
&lt;li&gt;macOS: &lt;code&gt;~/Library/Application Support/Godot/app_userdata/ForgeDesigner/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Linux: &lt;code&gt;~/.local/share/godot/app_userdata/ForgeDesigner/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Put the key into &lt;code&gt;forge_ai_keys.sml&lt;/code&gt; and run &lt;code&gt;chmod 600 forge_ai_keys.sml&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;Keys&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="err"&gt;openrouter:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sk-or-v1-..."&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;ol&gt;
&lt;li&gt;In &lt;code&gt;forge_ai.sml&lt;/code&gt;, switch the provider:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;Ai&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="err"&gt;provider:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openrouter"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="err"&gt;chatModels:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qwen/qwen3.8-27b:free, nvidia/nemotron-3-super-120b-a12b:free"&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 first model is used, and the others are fallbacks. Free models come and go, so check the current ones &lt;a href="https://openrouter.ai/models?max_price=0&amp;amp;supported_parameters=tools" rel="noopener noreferrer"&gt;with tool support&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send your next message. No restart needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Known rough edges
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;macOS build is Apple Silicon only and not notarized; Linux build is x86_64 only. No Windows build yet.&lt;/li&gt;
&lt;li&gt;ForgeCMS is the only output plugin so far.&lt;/li&gt;
&lt;li&gt;Free models are sometimes overloaded or change without notice.&lt;/li&gt;
&lt;li&gt;The UI still has a few leftovers from its origins as an SML editor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Deploying a site straight from the app (Git push + SSH)&lt;/li&gt;
&lt;li&gt;More output plugins: HTML, Android, macOS apps, and &lt;strong&gt;books&lt;/strong&gt; (chapters by prompt, export to PDF/EPUB)&lt;/li&gt;
&lt;li&gt;Finer-grained "always allow" rules for commands like &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;ssh&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code is open source (GPLv3, with a commercial license available) on Codeberg: &lt;a href="https://codeberg.org/CrowdWare/Forge4D" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare/Forge4D&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it, I'd love to hear what broke, what felt wrong, and what you'd build with it. Issues and comments welcome! 🌱&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>godot</category>
    </item>
    <item>
      <title>Sustainable Web Design with the Help of AI (Workshop)</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Thu, 17 Sep 2026 09:36:30 +0000</pubDate>
      <link>https://dev.to/artanidos/sustainable-web-design-with-the-help-of-ai-workshop-11bp</link>
      <guid>https://dev.to/artanidos/sustainable-web-design-with-the-help-of-ai-workshop-11bp</guid>
      <description>

&lt;h2&gt;
  
  
  Your website probably weighs more than it should
&lt;/h2&gt;

&lt;p&gt;Page builders with a hundred plugins. Subscription fees stacked on subscription fees. Hosting bills that make no sense for a five page site. Most of the modern web is built on foundations that waste energy, waste money and waste your time.&lt;/p&gt;

&lt;p&gt;I'm running a hands on workshop that takes the opposite approach: &lt;strong&gt;lean by default&lt;/strong&gt;. No database, no plugin jungle, no bloated hosting, and AI used as a real tool, not a crutch that writes code you don't understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you'll actually learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A practical approach to sustainable, low overhead web design&lt;/li&gt;
&lt;li&gt;How to use AI effectively in the design and build process, without losing control over the result&lt;/li&gt;
&lt;li&gt;The mindset behind &lt;a href="https://crowdware.info/forgecms" rel="noopener noreferrer"&gt;ForgeCMS&lt;/a&gt;: no database, no plugin jungle, no subscription trap&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;Freelancers, small teams, or anyone maintaining a website who is tired of the usual bloat and curious about a leaner, AI assisted alternative to conventional web development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Format and pricing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One day:&lt;/strong&gt; 4 hours, 130 EUR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekend:&lt;/strong&gt; 2 x 4 hours, 250 EUR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(plus venue rental)&lt;/p&gt;

&lt;h2&gt;
  
  
  Want in?
&lt;/h2&gt;

&lt;p&gt;Details and contact here: &lt;a href="https://crowdware.info/workshop" rel="noopener noreferrer"&gt;crowdware.info/workshop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No obligation, I reply personally, usually within a day.&lt;/p&gt;

&lt;p&gt;Built with love, coffee, and a stubborn focus on simplicity. That's the whole philosophy, and it's what you'll walk away with.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>cms</category>
    </item>
    <item>
      <title>Code &amp; Koje: Building Software with AI, Aboard a Sailboat in the Mediterranean</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Sun, 23 Aug 2026 21:53:19 +0000</pubDate>
      <link>https://dev.to/artanidos/code-koje-building-software-with-ai-aboard-a-sailboat-in-the-mediterranean-5eal</link>
      <guid>https://dev.to/artanidos/code-koje-building-software-with-ai-aboard-a-sailboat-in-the-mediterranean-5eal</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmwj3xrrw382i7wu0fe2d.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmwj3xrrw382i7wu0fe2d.webp" alt="Code &amp;amp; Koje: Building Software with AI, Aboard a Sailboat in the Mediterranean" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
I'm Olaf, a freelance software architect with over four decades of IT experience, an open source developer at CrowdWare, and starting in September I'll be sailing my ketch Deep Blue toward the Mediterranean.&lt;/p&gt;

&lt;p&gt;And I'm bringing people along.&lt;/p&gt;

&lt;p&gt;(Koje is German for a ship's bunk, hence the name.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;A weekend on board, somewhere in a marina in the Mediterranean. No seminar room, no slide deck, just a real boat, real remote work vibes, and hands on work building software with AI as a tool.&lt;/p&gt;

&lt;p&gt;For 3 to 4 people: students, aspiring developers, or anyone already in software who wants to see what working with AI actually looks like instead of just reading about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You'll Build
&lt;/h2&gt;

&lt;p&gt;This first weekend is all about ForgeCMS: build your own website, no WordPress bullshit anymore. Later sessions will move into Forge4D, building actual apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hands on experience developing with AI assistance&lt;/li&gt;
&lt;li&gt;Insight into cross platform development and open source workflows&lt;/li&gt;
&lt;li&gt;An Android tablet (worth about 120 EUR) and a solar panel (worth about 80 EUR) to keep, so you're set up to keep working and learning afterward&lt;/li&gt;
&lt;li&gt;A weekend that feels like a change of scenery, not a course&lt;/li&gt;
&lt;li&gt;Conversations about remote work, self employment, and life outside the classic office job&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cost
&lt;/h2&gt;

&lt;p&gt;A deposit of 200 to 250 EUR is due in advance, covering your Android tablet and solar panel. The course itself is around 250 EUR per person, on top of the deposit.&lt;/p&gt;

&lt;h2&gt;
  
  
  When and Where
&lt;/h2&gt;

&lt;p&gt;Departure is early September, first leg heading south. There's a good chance the first sessions could happen along the way, even before the boat finds its winter berth in the Mediterranean. Exact dates and locations to follow here and on my channels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interested?
&lt;/h2&gt;

&lt;p&gt;Reach out if you want to join or just have questions. Happy to chat either way, whether it turns into a booking or not.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code &amp;amp; Koje: where software development meets sailing romance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codeberg.org/CrowdWare" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>beginners</category>
    </item>
    <item>
      <title>ForgeIL Has Been Self-Hosting Since May. Nobody Found It</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Mon, 22 Jun 2026 23:53:38 +0000</pubDate>
      <link>https://dev.to/artanidos/forgeil-has-been-self-hosting-since-may-nobody-found-it-4772</link>
      <guid>https://dev.to/artanidos/forgeil-has-been-self-hosting-since-may-nobody-found-it-4772</guid>
      <description>&lt;h1&gt;
  
  
  ForgeIL Has Been Self-Hosting Since May. Nobody Found It Yet.
&lt;/h1&gt;

&lt;p&gt;It got quiet here for a month. Not because the project stalled, but because life moved.&lt;/p&gt;

&lt;p&gt;I moved aboard my ketch, Deep Blue, now anchored in Rostock. A new band started rehearsing at a spot near the Admiralbrücke in Kreuzberg, we even found a proper rehearsal room now. Friends, a new city for some of it, a different rhythm. Good kind of busy.&lt;/p&gt;

&lt;p&gt;But here is the thing I noticed once I surfaced again: ForgeIL has been sitting there, self-hosting, since the Sprint 4 post in May. 62 tests passing. The SMS compiler compiling itself to LLVM IR. And in a month, basically nobody picked it up.&lt;/p&gt;

&lt;p&gt;That is not a complaint. It is just true, and it bugs me a little. Not because I need the attention, but because the thing is actually useful and almost nobody knows it exists yet.&lt;/p&gt;

&lt;p&gt;So this post is not a new technical milestone. It is a reminder, and an invitation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ForgeIL Actually Is
&lt;/h2&gt;

&lt;p&gt;ForgeIL is the language family behind the Forge ecosystem at CrowdWare. Two parts, one intention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SML&lt;/strong&gt; (Simple Markup Language) describes structure. UI layout, app shape, content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SMS&lt;/strong&gt; (Simple Multiplatform Script) describes behavior. Logic, compiled ahead of time through LLVM to native code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No virtual machine. No garbage collector. Events resolve at compile time, not through a runtime dispatcher, which is part of why SMS event dispatch measured at 4.6 nanoseconds in earlier benchmarks, ahead of C++, C# and Kotlin Native, with only Kotlin JVM's JIT still ahead.&lt;/p&gt;

&lt;p&gt;And as of Sprint 4, the compiler compiles itself. Lexer, parser and LLVM IR emitter, all written in SMS, all proven self-hosting. No C++ toolchain required to keep developing SMS itself anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why That Matters More Than It Sounds
&lt;/h2&gt;

&lt;p&gt;A self-hosting compiler is a small thing to read about and a real threshold to cross. It means the language is no longer just describing other programs, it can fully describe and rebuild itself. That is the point where a language stops being a personal project and starts being able to outlive its author.&lt;/p&gt;

&lt;p&gt;This is built under CWUP, the workflow I use across the whole stack: Claude as architect, Codex as coder, Claude back for review. Each sprint specified, implemented, checked, before the next one starts. If you are curious how far AI-assisted development can responsibly go on something as precise as a compiler, this is a working example, not a pitch.&lt;/p&gt;

&lt;p&gt;And underneath all of it sits one constraint that never gets compromised: Ahimsa, do no harm to any living being. No telemetry by design, no dark patterns, no lock-in. Dual licensed, GPL3 for the community, commercial for those who need it, same model Qt has used for years.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Actual Ask
&lt;/h2&gt;

&lt;p&gt;I am not looking for employees or a funding round. I am looking for people who read "self-hosting compiler that compiles itself through LLVM, in a language with zero-cost UI events" and feel a small pull toward it.&lt;/p&gt;

&lt;p&gt;If that is you, here is where to start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code lives at &lt;a href="https://codeberg.org/CrowdWare" rel="noopener noreferrer"&gt;codeberg.org/CrowdWare&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Look at the ForgeIL repo for the language docs and the self-hosting compiler source&lt;/li&gt;
&lt;li&gt;Try compiling something small, break something, open an issue, ask a question, anything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do not need permission to poke around in open source. You need a reason to. Maybe this is it.&lt;/p&gt;

&lt;p&gt;Aho 🌱&lt;/p&gt;




&lt;p&gt;&lt;em&gt;ForgeIL is the language layer of Forge 4D, a cross-platform app framework built around SML and SMS, native compiled, targeting Android ARM today with more platforms ahead. Dual licensed GPL3/commercial. Everything developed in the open.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>compilers</category>
      <category>llvm</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Why SML/SMS doesn't run on Windows - and why that's a feature</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Mon, 11 May 2026 17:31:46 +0000</pubDate>
      <link>https://dev.to/artanidos/why-smlsms-doesnt-run-on-windows-and-why-thats-a-feature-3plf</link>
      <guid>https://dev.to/artanidos/why-smlsms-doesnt-run-on-windows-and-why-thats-a-feature-3plf</guid>
      <description>&lt;p&gt;Let me tell you a story.&lt;/p&gt;

&lt;p&gt;I was leading a raid in World of Warcraft. 24 people. Everyone waiting on me. And Windows decided that exact moment was the perfect time for an update. No warning. No mercy. Just a reboot.&lt;/p&gt;

&lt;p&gt;I switched to Mac the next day.&lt;/p&gt;

&lt;p&gt;For years it was great. Steve Jobs understood something most tech CEOs never will: the user is not the product. The user is the guest. You treat guests with respect.&lt;/p&gt;

&lt;p&gt;Then Steve left us.&lt;/p&gt;

&lt;p&gt;And slowly - update by update, policy by policy - Apple became just another corporation. A beautiful one. But one that now decides what software you can run, what hardware you can repair, and what belongs to you and what belongs to them.&lt;/p&gt;

&lt;p&gt;So here we are.&lt;/p&gt;

&lt;p&gt;We are building SMS - a programming language that compiles to native binaries via LLVM. Open source. GPL-3. &lt;strong&gt;No telemetry. No stakeholders. No investors.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It runs on Mac and Linux. Not on Windows - and that is not an oversight. That is a choice.&lt;/p&gt;

&lt;p&gt;Because we are not building for a world where your OS reboots your raid.&lt;br&gt;
We are not building for a world where a corporation decides what runs on your machine.&lt;br&gt;
&lt;strong&gt;We are building for the world we actually want to live in.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ahimsa. Do no harm. Not even to your users.&lt;/p&gt;

&lt;p&gt;If you are on Windows and want to try SMS - WSL2 works fine. One small rebellion inside the machine.&lt;/p&gt;

&lt;p&gt;But if you are tired of building software on platforms that belong to someone else - come build with us.&lt;/p&gt;

&lt;p&gt;SMS is free. Linux is free. Your time is not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://codeberg.org/CrowdWare/sms-cpp" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare/sms-cpp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>opensource</category>
      <category>linux</category>
      <category>showdev</category>
    </item>
    <item>
      <title>ForgeOS Dojo - learn AI-assisted development, build something that matters</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Mon, 11 May 2026 17:08:06 +0000</pubDate>
      <link>https://dev.to/artanidos/forgeos-dojo-learn-ai-assisted-development-build-something-that-matters-9fg</link>
      <guid>https://dev.to/artanidos/forgeos-dojo-learn-ai-assisted-development-build-something-that-matters-9fg</guid>
      <description>&lt;p&gt;&lt;em&gt;"No Stakeholders. No Investors. Just Users."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In 28 days we built a new programming language from scratch.&lt;br&gt;
Today it compiles itself.&lt;/p&gt;

&lt;p&gt;Now we want to go further - together.&lt;/p&gt;

&lt;p&gt;We are opening the ForgeOS Dojo: a learning community where you will master AI-assisted software architecture while building something real.&lt;/p&gt;

&lt;p&gt;Not a todo app. Not another CRUD API.&lt;/p&gt;

&lt;p&gt;An entire mobile OS. Free. No ads. No forced updates. No spyware.&lt;/p&gt;

&lt;p&gt;You will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to work with AI as your architect (Claude) and your coder (Codex)&lt;/li&gt;
&lt;li&gt;Sustainable software design - less code, more intention&lt;/li&gt;
&lt;li&gt;SMS - our scripting language that now compiles itself to native binaries&lt;/li&gt;
&lt;li&gt;How to ship real software that respects its users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What we build together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ForgeOS - a mobile OS built on SMS and C++&lt;/li&gt;
&lt;li&gt;Ahimsa as the single constitutional principle: do no harm - not even to your users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No prior OS experience needed. Just curiosity and the will to build something that matters.&lt;/p&gt;

&lt;p&gt;If you are tired of building software for companies that spy on their users - this is your Dojo.&lt;/p&gt;

&lt;p&gt;Drop a comment or follow CrowdWare on Codeberg:&lt;br&gt;
&lt;a href="https://codeberg.org/CrowdWare" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>opensource</category>
      <category>career</category>
      <category>showdev</category>
    </item>
    <item>
      <title>We Wrote a Compiler in the Language It Compiles. It Works.</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Mon, 11 May 2026 16:49:00 +0000</pubDate>
      <link>https://dev.to/artanidos/we-wrote-a-compiler-in-the-language-it-compiles-it-works-46p</link>
      <guid>https://dev.to/artanidos/we-wrote-a-compiler-in-the-language-it-compiles-it-works-46p</guid>
      <description>&lt;p&gt;&lt;em&gt;Four sprints. One afternoon. 62 tests, all green.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ForgeIL is the compiler layer of Forge - an open source UI framework built around&lt;br&gt;
a radical simplicity: one language, one binary, no runtime installation.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;There is a test every language eventually faces. Not a benchmark. Not a syntax&lt;br&gt;
comparison. A question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the language compile itself?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A self-hosted compiler is the closest thing software has to a proof of maturity.&lt;br&gt;
If the language can express a lexer, a parser, and a code generator - and the&lt;br&gt;
result of running that code is a working binary - then the language has crossed&lt;br&gt;
a threshold. It is no longer a demo. It is a tool.&lt;/p&gt;

&lt;p&gt;SMS is the scripting language at the heart of Forge. It is interpreted at&lt;br&gt;
development time and compiled to LLVM IR at release time. We decided to test&lt;br&gt;
whether SMS could implement its own compiler front-end: a lexer, a parser, and&lt;br&gt;
an LLVM IR emitter - all written in SMS itself.&lt;/p&gt;

&lt;p&gt;Four sprints. One afternoon. It works.&lt;/p&gt;


&lt;h2&gt;
  
  
  What We Built
&lt;/h2&gt;

&lt;p&gt;The self-hosted compiler lives in the &lt;code&gt;forgeil/&lt;/code&gt; directory of&lt;br&gt;
&lt;a href="https://codeberg.org/CrowdWare/sms-cpp" rel="noopener noreferrer"&gt;sms-cpp&lt;/a&gt; - three SMS source files that&lt;br&gt;
together form a complete compilation pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SMS Source
    |
    v
tokenize(src)        sprint1-lexer.sms     -&amp;gt;  array of Token
    |
    v
parse(tokens)        sprint2-parser.sms    -&amp;gt;  AST of Node
    |
    v
codegen(ast)         sprint3-codegen.sms   -&amp;gt;  LLVM IR text
    |
    v
clang                                      -&amp;gt;  native binary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single convenience function wraps it all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun compile(src) {
    return codegen(parse(tokenize(src)))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the entire public API. Give it SMS source text. Get back LLVM IR.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sprint 1: Lexer
&lt;/h2&gt;

&lt;p&gt;The lexer turned out to be the place where SMS's integer-character API became&lt;br&gt;
a design constraint rather than a limitation. &lt;code&gt;str.charAt(i)&lt;/code&gt; returns the&lt;br&gt;
integer char code of the character at position &lt;code&gt;i&lt;/code&gt;. So the entire lexer is&lt;br&gt;
built on integer comparisons - no regex, no character class library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun isAlpha(code) {
    return (code &amp;gt;= 65 &amp;amp;&amp;amp; code &amp;lt;= 90) || (code &amp;gt;= 97 &amp;amp;&amp;amp; code &amp;lt;= 122) || code == 95
}

fun isDigit(code) {
    return code &amp;gt;= 48 &amp;amp;&amp;amp; code &amp;lt;= 57
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two-character operators (&lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;) are handled with&lt;br&gt;
a single lookahead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (ch == 61) {  // '='
    if (i + 1 &amp;lt; len &amp;amp;&amp;amp; src.charAt(i + 1) == 61) {
        tokens.add(Token("OP", "==", line))
        i = i + 2
    } else {
        tokens.add(Token("ASSIGN", "=", line))
        i = i + 1
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result: &lt;code&gt;tokenize(src)&lt;/code&gt; returns an array of &lt;code&gt;Token(type, value, line)&lt;/code&gt; data&lt;br&gt;
class instances. 12 tests, all green on the first run.&lt;/p&gt;


&lt;h2&gt;
  
  
  Sprint 2: Parser
&lt;/h2&gt;

&lt;p&gt;A recursive descent parser, written in SMS, for SMS.&lt;/p&gt;

&lt;p&gt;The interesting constraint here: SMS does not allow forward declarations. Every&lt;br&gt;
function must be defined before it is called - except at the top level, where&lt;br&gt;
all definitions are registered before &lt;code&gt;main()&lt;/code&gt; runs. So mutual recursion between&lt;br&gt;
&lt;code&gt;parseExpr&lt;/code&gt; and &lt;code&gt;parseStmt&lt;/code&gt; works perfectly, because both are defined at the&lt;br&gt;
module level before any call site is reached.&lt;/p&gt;

&lt;p&gt;The precedence chain follows the standard pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parsePrimary -&amp;gt; parsePostfix -&amp;gt; parseUnary -&amp;gt; parseMul -&amp;gt;
parseAdd -&amp;gt; parseCompare -&amp;gt; parseEquality -&amp;gt; parseAnd -&amp;gt; parseOr -&amp;gt; parseExpr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One non-obvious detail: the parser cursor is a single-element array used as a&lt;br&gt;
mutable integer box. SMS arrays are passed by shared reference - field&lt;br&gt;
assignments inside helper functions are visible to the caller. This is how the&lt;br&gt;
cursor advances across the recursive descent without needing a global variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fun curTok(cur, tokens) { return tokens[cur[0]] }
fun advance(cur)         { cur[0] = cur[0] + 1 }
fun consume(cur, tokens, expected) {
    var tok = curTok(cur, tokens)
    if (tok.type != expected) { ... }
    advance(cur)
    return tok
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;24 tests. All green.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sprint 3: LLVM IR Emitter
&lt;/h2&gt;

&lt;p&gt;The code generator takes an AST and produces a complete LLVM IR text string.&lt;br&gt;
Integer-only subset: every SMS value is &lt;code&gt;i64&lt;/code&gt;, variables use alloca (memory-form&lt;br&gt;
SSA), and &lt;code&gt;clang&lt;/code&gt;/&lt;code&gt;llc&lt;/code&gt; applies &lt;code&gt;mem2reg&lt;/code&gt; in the optimization pipeline.&lt;/p&gt;

&lt;p&gt;The context object accumulates emitted instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Ctx(tempCnt, labelCnt, code, terminated, loops)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because SMS data class instances use shared references (&lt;code&gt;shared_ptr&lt;/code&gt; under the&lt;br&gt;
hood), every helper function that mutates &lt;code&gt;ctx.code&lt;/code&gt; or &lt;code&gt;ctx.tempCnt&lt;/code&gt; has its&lt;br&gt;
changes visible to every other function holding the same &lt;code&gt;ctx&lt;/code&gt;. This is the&lt;br&gt;
foundation of the entire emitter design.&lt;/p&gt;

&lt;p&gt;A comparison compiles to an &lt;code&gt;icmp&lt;/code&gt; followed by a &lt;code&gt;zext&lt;/code&gt; - because LLVM&lt;br&gt;
comparisons produce &lt;code&gt;i1&lt;/code&gt; and SMS uses &lt;code&gt;i64&lt;/code&gt; everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (op == "&amp;lt;") { emit(ctx, cmpReg $ " = icmp slt i64 " $ left $ ", " $ right) }
emit(ctx, reg $ " = zext i1 " $ cmpReg $ " to i64")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a function like &lt;code&gt;fun add(a, b) { return a + b }&lt;/code&gt;, the emitter produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight llvm"&gt;&lt;code&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="vg"&gt;@sms_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="nv"&gt;%_p_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="nv"&gt;%_p_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;entry:&lt;/span&gt;
    &lt;span class="nv"&gt;%a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;alloca&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;
    &lt;span class="k"&gt;store&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="nv"&gt;%_p_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;%a&lt;/span&gt;
    &lt;span class="nv"&gt;%b&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;alloca&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;
    &lt;span class="k"&gt;store&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="nv"&gt;%_p_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;%b&lt;/span&gt;
    &lt;span class="nv"&gt;%t0&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;load&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;%a&lt;/span&gt;
    &lt;span class="nv"&gt;%t1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;load&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt;&lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;%b&lt;/span&gt;
    &lt;span class="nv"&gt;%t2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt;  &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="nv"&gt;%t0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;%t1&lt;/span&gt;
    &lt;span class="k"&gt;ret&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="nv"&gt;%t2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the source contains a &lt;code&gt;fun main()&lt;/code&gt;, a C-compatible entry point is appended:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight llvm"&gt;&lt;code&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt; &lt;span class="vg"&gt;@main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;entry:&lt;/span&gt;
    &lt;span class="nv"&gt;%ret64&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="vg"&gt;@sms_main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nv"&gt;%ret32&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;trunc&lt;/span&gt; &lt;span class="kt"&gt;i64&lt;/span&gt; &lt;span class="nv"&gt;%ret64&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt;
    &lt;span class="k"&gt;ret&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt; &lt;span class="nv"&gt;%ret32&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;19 tests. All green.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sprint 4: End-to-End
&lt;/h2&gt;

&lt;p&gt;The final sprint is the proof. A new C API function -&lt;br&gt;
&lt;code&gt;sms_native_execute_string_result&lt;/code&gt; - captures the string value produced by the&lt;br&gt;
SMS interpreter, instead of the integer it previously returned. This lets the&lt;br&gt;
host application receive the generated IR text directly.&lt;/p&gt;

&lt;p&gt;The test then does exactly what you would do on the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 1. Run the SMS compiler in the interpreter, capture the IR string&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_ir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;load_all&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"fun main() { return 42 }"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Write to a temp .ll file&lt;/span&gt;
&lt;span class="c1"&gt;// 3. Run: clang -O0 -o /tmp/test_bin /tmp/test.ll&lt;/span&gt;
&lt;span class="c1"&gt;// 4. Run the binary, check exit code == 42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exit code 42. Not chosen at random. The compiler's first words are a nod to&lt;br&gt;
the only question that ever mattered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;forgeil_sprint4_tests: all tests passed (7)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipeline holds for arithmetic, if/else branches, and while loops. The tests&lt;br&gt;
skip gracefully when &lt;code&gt;clang&lt;/code&gt; is not available, so they run cleanly in any CI&lt;br&gt;
environment.&lt;/p&gt;


&lt;h2&gt;
  
  
  What the Numbers Look Like
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sprint 1 - Lexer        12 tests  v
Sprint 2 - Parser       24 tests  v
Sprint 3 - Code gen     19 tests  v
Sprint 4 - Self-host     7 tests  v
---------------------------------
Total                   62 tests  all green
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What This Is Not
&lt;/h2&gt;

&lt;p&gt;SMS is not trying to replace LLVM's front-end infrastructure. The self-hosted&lt;br&gt;
compiler covers the integer-only subset of the language: functions, variables,&lt;br&gt;
if/else, while, break/continue, arithmetic, and comparisons. Strings, arrays,&lt;br&gt;
data classes, and the standard library are outside its current scope.&lt;/p&gt;

&lt;p&gt;The point is not feature completeness. The point is that the language has&lt;br&gt;
enough expressive power to reason about itself. That is a different claim - and&lt;br&gt;
a meaningful one.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;Everything is open source under GPL-3.0 (with a commercial option):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;sms-cpp&lt;/strong&gt;: &lt;a href="https://codeberg.org/CrowdWare/sms-cpp" rel="noopener noreferrer"&gt;codeberg.org/CrowdWare/sms-cpp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Lexer: &lt;code&gt;forgeil/sprint1-lexer.sms&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Parser: &lt;code&gt;forgeil/sprint2-parser.sms&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Code gen: &lt;code&gt;forgeil/sprint3-codegen.sms&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tests: &lt;code&gt;tests/forgeil_sprint{1..4}_tests.cpp&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to try it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://codeberg.org/CrowdWare/sms-cpp.git
git clone https://codeberg.org/CrowdWare/sml-cpp.git
cmake &lt;span class="nt"&gt;-B&lt;/span&gt; build &lt;span class="nt"&gt;-DBUILD_TESTING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ON &lt;span class="nt"&gt;-DSML_CPP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;../sml-cpp
cmake &lt;span class="nt"&gt;--build&lt;/span&gt; build
&lt;span class="nb"&gt;cd &lt;/span&gt;build &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ctest &lt;span class="nt"&gt;-R&lt;/span&gt; forgeil &lt;span class="nt"&gt;--output-on-failure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;*Forge is being built in public at &lt;a href="https://crowdware.info" rel="noopener noreferrer"&gt;crowdware.info&lt;/a&gt;.&lt;br&gt;
SMS, ForgeIL, and the self-hosted compiler are part of a longer project:&lt;br&gt;
a UI framework that runs anywhere without asking anything of the user's machine.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>opensource</category>
      <category>cpp</category>
      <category>compiling</category>
    </item>
    <item>
      <title>ListenCircle: A Digital Talking Circle for Real Human Connection</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Wed, 22 Apr 2026 19:13:27 +0000</pubDate>
      <link>https://dev.to/artanidos/listencircle-a-digital-talking-circle-for-real-human-connection-3aj0</link>
      <guid>https://dev.to/artanidos/listencircle-a-digital-talking-circle-for-real-human-connection-3aj0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyk4excn0ivgnilkaq9l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyk4excn0ivgnilkaq9l.jpg" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We built &lt;strong&gt;ListenCircle&lt;/strong&gt; to bring the ancient practice of the Talking Circle into the digital world.&lt;/p&gt;

&lt;p&gt;It’s a space where every human being can speak and be heard — regardless of where they come from or what they believe.&lt;/p&gt;

&lt;p&gt;No accounts. No logins. No stored identities. Just real people, listening.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌿 What is a Talking Circle?
&lt;/h2&gt;

&lt;p&gt;A Talking Circle is an ancient form of conversation:&lt;/p&gt;

&lt;p&gt;People sit in a circle.&lt;br&gt;&lt;br&gt;
Whoever speaks holds the &lt;em&gt;Talking Stick&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
The others listen — without interrupting.&lt;/p&gt;

&lt;p&gt;When the speaker is done, the stick passes to the next person.&lt;/p&gt;

&lt;p&gt;ListenCircle brings this practice into the digital age — for Rainbow Gatherings, community meetings, and anywhere people want to truly listen.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙️ How it works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a circle
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Choose a language
&lt;/li&gt;
&lt;li&gt;Set a topic (or keep it open)
&lt;/li&gt;
&lt;li&gt;Decide:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open Circle&lt;/strong&gt; — anyone can join
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Closed Circle&lt;/strong&gt; — invite only
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limit participants (default: 13)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Joining a circle
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open circles appear in the lobby
&lt;/li&gt;
&lt;li&gt;Join instantly — no account needed
&lt;/li&gt;
&lt;li&gt;New participants must listen through one full round before speaking&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🪶 The Talking Stick
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Hold button → speak (push-to-talk)
&lt;/li&gt;
&lt;li&gt;Release → stick moves to next person
&lt;/li&gt;
&lt;li&gt;Strict order — no interruptions
&lt;/li&gt;
&lt;li&gt;Max speaking time: &lt;strong&gt;3 minutes&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  💛 Reactions
&lt;/h3&gt;

&lt;p&gt;While someone speaks, others can respond with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌿 Aho
&lt;/li&gt;
&lt;li&gt;♥ Thanks
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The speaker sees them live.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔐 Privacy by design
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No accounts
&lt;/li&gt;
&lt;li&gt;No stored identities
&lt;/li&gt;
&lt;li&gt;No IP tracking
&lt;/li&gt;
&lt;li&gt;No persistent data
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Audio runs &lt;strong&gt;peer-to-peer (WebRTC)&lt;/strong&gt; — never through a server.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏗️ Architecture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go backend&lt;/strong&gt; for real-time logic
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSockets&lt;/strong&gt; for signaling
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebRTC&lt;/strong&gt; for direct audio
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ForgeCMS&lt;/strong&gt; for rendering UI via SML
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separation of concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend = logic
&lt;/li&gt;
&lt;li&gt;CMS = UI
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛡️ Abuse protection (without logins)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Session tokens (not IP-based)
&lt;/li&gt;
&lt;li&gt;Rate limiting
&lt;/li&gt;
&lt;li&gt;Join throttling
&lt;/li&gt;
&lt;li&gt;Speaking timeout
&lt;/li&gt;
&lt;li&gt;Stick timing rules
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All without breaking anonymity.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Why this matters
&lt;/h2&gt;

&lt;p&gt;Most online communication is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chaotic
&lt;/li&gt;
&lt;li&gt;interrupt-driven
&lt;/li&gt;
&lt;li&gt;attention-seeking
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ListenCircle creates something different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one voice at a time
&lt;/li&gt;
&lt;li&gt;real listening
&lt;/li&gt;
&lt;li&gt;no identity games
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not just a tool.&lt;br&gt;&lt;br&gt;
It’s a different &lt;em&gt;culture of communication&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔗 Open Source
&lt;/h2&gt;

&lt;p&gt;👉 &lt;a href="https://codeberg.org/CrowdWare/ListenCircle" rel="noopener noreferrer"&gt;https://codeberg.org/CrowdWare/ListenCircle&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🌱 Final thought
&lt;/h2&gt;

&lt;p&gt;What happens when people are truly heard?&lt;/p&gt;

&lt;p&gt;That’s what ListenCircle is exploring.&lt;/p&gt;




&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;It's not yet ready...we just started it today, but I just wanted to start a discussion and you may add feature requests. Just think about the outcome. Are we able to stop wars this way?&lt;/p&gt;

&lt;p&gt;Btw...it's free and open source...host your own server on a 1,- EUR VPS.&lt;/p&gt;

</description>
      <category>community</category>
      <category>privacy</category>
      <category>showdev</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>AI Writes Your App. You Lose Your Job. Good.</title>
      <dc:creator>Art</dc:creator>
      <pubDate>Sun, 19 Apr 2026 19:03:34 +0000</pubDate>
      <link>https://dev.to/artanidos/ai-writes-your-app-you-lose-your-job-good-1ekj</link>
      <guid>https://dev.to/artanidos/ai-writes-your-app-you-lose-your-job-good-1ekj</guid>
      <description>&lt;h1&gt;
  
  
  AI Writes Your App. You Lose Your Job. Good.
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Before you close this tab — read the second sentence.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You will not be jobless. You will be work-free. Those are not the same thing.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Fear Is Real
&lt;/h2&gt;

&lt;p&gt;Let us not pretend it is not.&lt;/p&gt;

&lt;p&gt;A developer spends years learning React, Kotlin, Swift, C#.&lt;br&gt;
They build a career on that knowledge.&lt;br&gt;
Then an AI arrives that can generate working code from a sentence.&lt;/p&gt;

&lt;p&gt;The fear is legitimate. The question is whether the conclusion is correct.&lt;/p&gt;


&lt;h2&gt;
  
  
  What AI Actually Does to Development
&lt;/h2&gt;

&lt;p&gt;Here is what happens when you ask an AI to build a React app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It generates plausible-looking code&lt;/li&gt;
&lt;li&gt;The hooks are slightly wrong&lt;/li&gt;
&lt;li&gt;The state management is from a blog post written in 2021&lt;/li&gt;
&lt;li&gt;The dependency array is missing two items&lt;/li&gt;
&lt;li&gt;It works in the demo, breaks in production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React is complex enough that AI-generated code requires a developer&lt;br&gt;
to review, fix, and understand every line. The developer is still fully employed.&lt;br&gt;
They are just a reviewer now instead of an author.&lt;/p&gt;

&lt;p&gt;This is not liberation. This is the same job with extra steps.&lt;/p&gt;


&lt;h2&gt;
  
  
  What Happens With a Simpler Language
&lt;/h2&gt;

&lt;p&gt;SML and SMS are intentionally minimal.&lt;/p&gt;

&lt;p&gt;SML has no lifecycle methods. No virtual DOM. No reconciler.&lt;br&gt;
A Column contains children. A Button has text. An ID identifies an element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sml"&gt;&lt;code&gt;&lt;span class="n"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;

    &lt;span class="n"&gt;Label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"0"&lt;/span&gt;
        &lt;span class="n"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;btnAdd&lt;/span&gt;
        &lt;span class="n"&gt;text&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;SMS has no async/await. No promises. No event bubbling.&lt;br&gt;
Something happened. Here is what to do about it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var count = 0

on btnAdd.clicked() {
    count = count + 1
    counter.text = count
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire rule set fits in a single system prompt.&lt;br&gt;
Including the things that trip up AI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;IDs are not strings. Write &lt;code&gt;id: counter&lt;/code&gt;, not &lt;code&gt;id: "counter"&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Event handlers use dot notation. &lt;code&gt;on btn.clicked()&lt;/code&gt;, not &lt;code&gt;onClick&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Variables are global to the script. No closures, no scope confusion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An AI given this context generates correct Forge apps on the first try.&lt;br&gt;
Not approximately correct. Actually correct. Deployable.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Loop Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;When AI can generate a complete, deployable app from a description,&lt;br&gt;
the development loop changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before:
  User idea → Designer → Review → Developer → QA → Staging → Production
  Time: weeks

With AI + Forge:
  User describes → AI writes SML + SMS → Push to Codeberg → Live
  Time: minutes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer is no longer the bottleneck between idea and reality.&lt;/p&gt;

&lt;p&gt;This is where the fear comes from.&lt;br&gt;
This is also where the opportunity comes from.&lt;/p&gt;




&lt;h2&gt;
  
  
  "But That Means I Lose My Job"
&lt;/h2&gt;

&lt;p&gt;Let us be honest about what that job actually was.&lt;/p&gt;

&lt;p&gt;Translating human intent into machine instructions.&lt;br&gt;
That is the core of software development.&lt;br&gt;
A human has an idea. A developer translates it into code the computer understands.&lt;/p&gt;

&lt;p&gt;AI is getting very good at that translation.&lt;/p&gt;

&lt;p&gt;But notice what disappears when the translation is instant:&lt;br&gt;
the gap between thinking and building.&lt;br&gt;
The weeks of meetings, handoffs, misunderstandings, revisions.&lt;br&gt;
The user who forgot what they wanted.&lt;br&gt;
The developer who built the wrong thing for three months.&lt;/p&gt;

&lt;p&gt;That gap was not valuable. It was waste.&lt;br&gt;
We called it "the development process" because we had no other way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Arbeitslos vs. Die Arbeit Los
&lt;/h2&gt;

&lt;p&gt;There is a distinction that English handles clumsily but the idea is clear.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jobless&lt;/strong&gt; — without income, without purpose, without dignity.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Work-free&lt;/strong&gt; — freed from labor that a machine can do better.&lt;/p&gt;

&lt;p&gt;These are not the same condition.&lt;/p&gt;

&lt;p&gt;A farmer who gets a tractor is not jobless.&lt;br&gt;
They are freed from breaking their back with a hand plow.&lt;br&gt;
The question is whether they have land to farm with the tractor.&lt;/p&gt;

&lt;p&gt;The question for developers is not "will AI take my job?"&lt;br&gt;
The question is "what will I do with the time AI gives back?"&lt;/p&gt;




&lt;h2&gt;
  
  
  UBI Is the Bridge
&lt;/h2&gt;

&lt;p&gt;Universal Basic Income — BGE in German — is the infrastructure&lt;br&gt;
that makes this transition survivable.&lt;/p&gt;

&lt;p&gt;Without it: AI replaces jobs, income disappears, people suffer.&lt;br&gt;
With it: AI replaces jobs, basic needs are covered, time is returned.&lt;/p&gt;

&lt;p&gt;The technology already exists to feed, house, and care for everyone.&lt;br&gt;
The question has never been whether we can afford it.&lt;br&gt;
The question has always been whether we choose to.&lt;/p&gt;

&lt;p&gt;When a developer no longer needs to spend 40 hours a week&lt;br&gt;
translating requirements into React components —&lt;br&gt;
what does that time become?&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Time Becomes
&lt;/h2&gt;

&lt;p&gt;Time for the things that were always more important and always got postponed.&lt;/p&gt;

&lt;p&gt;Being present with the people you love.&lt;br&gt;&lt;br&gt;
Learning something because it is beautiful, not because it is marketable.&lt;br&gt;&lt;br&gt;
Walking 12 kilometers into a forest to sit with strangers around a fire.&lt;br&gt;&lt;br&gt;
Doing your Kundalini practice before the day starts instead of at 11pm.&lt;br&gt;&lt;br&gt;
Building something because it should exist, not because someone is paying for it.&lt;/p&gt;

&lt;p&gt;Software was never the point.&lt;br&gt;&lt;br&gt;
The point was always what software made possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Risk
&lt;/h2&gt;

&lt;p&gt;We should not pretend this transition will be painless.&lt;/p&gt;

&lt;p&gt;Between "AI can now do this" and "everyone has UBI" there is a gap.&lt;br&gt;
People will lose income before the safety net exists.&lt;br&gt;
That is real. That is happening now. It should not be minimized.&lt;/p&gt;

&lt;p&gt;The answer is not to slow down the technology.&lt;br&gt;
The answer is to build the safety net faster than the disruption spreads.&lt;/p&gt;

&lt;p&gt;That is a political problem, not a technical one.&lt;br&gt;
Developers who understand both the technology and its consequences&lt;br&gt;
are exactly the people who should be in that conversation.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Forge Is Actually For
&lt;/h2&gt;

&lt;p&gt;Forge was built for a world where the gap between idea and running app&lt;br&gt;
is measured in minutes, not months.&lt;/p&gt;

&lt;p&gt;SML and SMS are simple by design — not because simplicity is a virtue in itself,&lt;br&gt;
but because a language that a human can learn in a day&lt;br&gt;
is also a language that an AI can generate correctly in a second.&lt;/p&gt;

&lt;p&gt;The sandbox is not a technical feature.&lt;br&gt;
It is a commitment: the technology will not be used to harm.&lt;br&gt;
Ahimsa. Do no harm. Written into the license, not the README.&lt;/p&gt;

&lt;p&gt;When AI generates a Forge app and a user runs it,&lt;br&gt;
they are running sandboxed code that cannot reach outside its permission boundary.&lt;br&gt;
The AI cannot weaponize the app. The developer cannot weaponize the app.&lt;br&gt;
The architecture enforces the ethics.&lt;/p&gt;

&lt;p&gt;That is the kind of technology worth building.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Different Question
&lt;/h2&gt;

&lt;p&gt;Instead of "will AI take my job?" —&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What would you build if the translation problem were solved?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What has been in your head for years that you never had time to make real?&lt;br&gt;
What would you create if creation cost minutes instead of months?&lt;/p&gt;

&lt;p&gt;That question is more interesting than the fear.&lt;br&gt;
And the answer to it is what comes after the transition.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Forge is open source.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;The tools exist. The time is coming.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Use both well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sat Nam. 🌱&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Previous posts in this series:&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;→ We Benchmarked SMS Against C++, C#, and Kotlin. Here's What Happened.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;→ From Request to Production in One Push. No Mockup Tool Required.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
