<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel>
        <title>Writing · Ilyas Turki</title>
        <link>https://ilyasturki.com/en/writing/</link>
        <description>What I write about my tools, the terminal and AI.</description>
        <language>en</language>
        <image>
            <url>https://ilyasturki.com/ilyas-portrait.jpg</url>
            <title>Writing · Ilyas Turki</title>
            <link>https://ilyasturki.com/en/writing/</link>
        </image>
        <lastBuildDate>Mon, 26 Oct 2026 00:00:00 GMT</lastBuildDate>
        <atom:link href="https://ilyasturki.com/en/feed.xml" rel="self" type="application/rss+xml" />
        <item>
            <title>I dropped cold calling for cold email</title>
            <link>https://ilyasturki.com/en/writing/cold-email/</link>
            <guid isPermaLink="true">https://ilyasturki.com/en/writing/cold-email/</guid>
            <pubDate>Mon, 26 Oct 2026 00:00:00 GMT</pubDate>
            <dc:creator>Ilyas Turki</dc:creator>
            <description>112 tradespeople called, 32 conversations, zero trials. The phone doesn&#39;t scale, so Aplorio now prospects by email: ten separate domains, three weeks of warm-up, and a first message that sells nothing.</description>
            <content:encoded>&lt;p&gt;112 numbers dialed, 32 conversations, zero trials. That’s the tally of my two cold calling slots for Aplorio, in late July, over the lunch break, calling building tradespeople. On 30 September, I closed the channel.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-panik.jpg&quot; alt=&quot;Panik Kalm Panik meme: “18,811 tradespeople to prospect”, panik; “cold email: 600 sends a day without lifting a finger”, kalm; “three weeks of warm-up before the first send”, panik&quot; height=&quot;817&quot; width=&quot;600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-phone-doesnt-scale&quot;&gt;The phone doesn’t scale&lt;/h2&gt;
&lt;p&gt;What bothered me about cold calling is that it’s very manual and very time-consuming. It takes a huge amount of time for very little. And above all, you can’t scale it. With cold email, you can. You reach way, way more people, at a speed you’ll never get on the phone, without even doing anything.&lt;/p&gt;
&lt;p&gt;It’s a lazy person’s solution, so to speak. But on small 12 euro a month subscriptions, it makes total sense.&lt;/p&gt;
&lt;h2 id=&quot;ten-separate-domains&quot;&gt;Ten separate domains&lt;/h2&gt;
&lt;p&gt;Rule number one is never to send from &lt;code&gt;aplorio.fr&lt;/code&gt;. A burned domain would take the client reminders and the app’s emails down with it. So I bought ten &lt;code&gt;.fr&lt;/code&gt; domains on the side for 59.88 euros a year including VAT, one Google Workspace mailbox per domain at 8.10 euros a month before VAT, and Instantly on the Growth plan at 47 dollars a month to send.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/schema-envoi.svg&quot; alt=&quot;Diagram of the sending setup: aplorio.fr stays apart, kept for the app and client reminders; prospecting goes out from ten separate domains, one Google mailbox each, plugged into Instantly, which warms up the mailboxes and spreads the sends to the RGE tradespeople in the ADEME directory&quot; width=&quot;960&quot; height=&quot;545&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If a domain gets burned, I lose one out of ten. Not the brand.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Instantly also offers pre-warmed accounts for rent. I saw them once I was logged in. Fixed personas, something like “Joseph Lewis”, on generic &lt;code&gt;.org&lt;/code&gt; domains, and a sender name you can’t change. No thanks. We warmed up our mailboxes ourselves, three weeks before the first real send, plus real email threads with family and friends: the mailbox writes, the relative checks their spam folder, pulls the message out if it’s there, and replies.&lt;/p&gt;
&lt;p&gt;SPF, DKIM and DMARC aligned on every domain, Postmaster Tools hooked up to all ten. In the placement test on 30 September, out of 474 sends to seed mailboxes, 6 landed in spam, all of them at consumer Gmail.&lt;/p&gt;
&lt;h2 id=&quot;the-first-email-sells-nothing&quot;&gt;The first email sells nothing&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-change-my-mind.jpg&quot; alt=&quot;Change My Mind meme: a man sitting behind a table with a sign saying “the first email should sell nothing”&quot; height=&quot;578&quot; width=&quot;754&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;The list comes from ADEME’s RGE directory (the French register of certified energy renovation tradespeople), where each tradesperson publishes their own address. That’s 18,811 businesses in my file, and the source is written in a P.S. on every first email, as GDPR requires.&lt;/p&gt;
&lt;p&gt;The sequence is three emails, plain text, signed, no tracking pixel, and not a single link in the first one. That first email comes in two versions, tested against each other: one asks a question about how they do their quotes, the other offers them a sample quote in their name. Both end on a question you can answer in one word. Four days later, the quote. Ten days later, the offer: a 30-day trial with no card, then 12 euros a month for life for the first 100 customers.&lt;/p&gt;
&lt;h2 id=&quot;the-bar-is-set-beforehand&quot;&gt;The bar is set beforehand&lt;/h2&gt;
&lt;p&gt;Before the first send, I wrote down what decides what comes next, so the time already sunk never gets a vote. At a 5% reply rate or more, we scale up the volume. Between 3 and 5%, we rework the first email. Below 3%, the channel goes passive, and the debate doesn’t reopen. Verdict on 24 November.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/schema-sequence.svg&quot; alt=&quot;The three-email sequence, Day 0, Day 4 and Day 10, and below it the reply rate bar: under 3% the channel goes passive, from 3 to 5% we rework the first email, at 5% and up we scale up the volume&quot; width=&quot;960&quot; height=&quot;520&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Everything is written before the first send. After that, I don’t negotiate with myself anymore.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The campaign is still running, with over 2,000 emails already sent without me having to pick up a phone. The numbers, I’ll keep for the verdict.&lt;/p&gt;
</content:encoded>
        </item>
        <item>
            <title>I went to 100 commits a day</title>
            <link>https://ilyasturki.com/en/writing/cent-commits/</link>
            <guid isPermaLink="true">https://ilyasturki.com/en/writing/cent-commits/</guid>
            <pubDate>Sun, 25 Oct 2026 00:00:00 GMT</pubDate>
            <dc:creator>Ilyas Turki</dc:creator>
            <description>In early September I made 24 commits a day. Since late September it&#39;s 94. Two skills did it: one commits each change on its own, one runs my agents in parallel.</description>
            <content:encoded>&lt;p&gt;3,617 commits between 27 September and 25 October, across all repos. That’s 94 a day, and that’s without counting 20 October. For the first 26 days of September, I was at 24.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/schema-commits.svg&quot; alt=&quot;Histogram of my commits per day from 1 September to 25 October 2026: around 24 a day until 26 September, then 94 on average, with peaks above 300 and a bar cut off at 977 on 20 October&quot; width=&quot;1100&quot; height=&quot;540&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;On 20 October, I launched a bunch of experiments at once, just to see what breaks. The rest is a normal month now.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-overthinker&quot;&gt;The overthinker&lt;/h2&gt;
&lt;p&gt;I really used to be the guy who overthought and didn’t ship. On Neovim, I always wanted to customize my config, and so I wasn’t productive.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/meme-shipping.jpg&quot; alt=&quot;Overthinking Engineer vs Shipping Engineer meme: on the left, the dev who spends three weeks choosing a stack and runs 12 microservices on localhost; on the right, the one who tells Claude “build me an app” and is already asking for 9 dollars a month&quot; height=&quot;567&quot; width=&quot;680&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;For a long time I was the one on the left.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today I ship several things at once, no problem at all. And there’s nothing magic about it, just two Claude Code skills.&lt;/p&gt;
&lt;h2 id=&quot;one-commit-per-change&quot;&gt;One commit per change&lt;/h2&gt;
&lt;p&gt;The first one is &lt;code&gt;commit&lt;/code&gt;. When I tell the agent to commit, it goes through it: conventional commits, a single line, and one commit per change. It looks like atomic commits, without the dogma. If two things have to go together, they go together. If splitting takes too much work, we don’t split, no big deal.&lt;/p&gt;
&lt;p&gt;Because by default, AI does the opposite. It adds Claude as a co-author, which I’m not a fan of. And it churns out one big commit with an unhinged description, super long, super boring to read. Here’s what my skill produces over an evening of work on Aplorio’s invoice import:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;9b45598 test(api): free the taken number once its refusal is proven
9923a29 fix(import): carry on a yearless série as continuous numbering
827240c refactor(numbering): share the taken-number refusal and numbers query
f965143 fix(import): count the run before a trailing year as the counter
6b81992 fix(import): read a two-digit year when offering to continue numbering
4fb6b78 feat(numbering): refuse an émission whose number is already taken
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Six commits, six things. The history reads in one go, and it stays maintainable in the future. Even for AI. When it reads back through the past, it sees concretely what was done, and it finds exactly what it’s looking for.&lt;/p&gt;
&lt;h2 id=&quot;i-let-the-agents-loose&quot;&gt;I let the agents loose&lt;/h2&gt;
&lt;p&gt;The second skill is the one that really changed everything: &lt;code&gt;dispatch&lt;/code&gt;. I give it a pile of features, tasks and bugs. It interviews me once at the start, splits it all into briefs, then launches one Claude Code session per brief, each in its own worktree. The sessions work on their own and commit as they go with &lt;code&gt;commit&lt;/code&gt;. A queue stacks the ready branches, runs the checks and merges what passes. Me, I read a report at the end.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/schema-dispatch.svg&quot; alt=&quot;The dispatch pipeline: a pile of features, tasks and bugs, one interview at the start, one Claude Code session per brief in its worktree, ten at a time, then a queue that runs the checks and merges to main, and a report at the end&quot; width=&quot;960&quot; height=&quot;490&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Me, I step in at the start, and at the end.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In between, I answer questions now and then, bit by bit. The rest, I leave to them as much as I can.&lt;/p&gt;
&lt;p&gt;The jump in the chart is exactly when I started really using them, &lt;code&gt;dispatch&lt;/code&gt; on one side and automatic commits on the other. The Aplorio run launched on 20 October was 41 briefs, capped at 10 sessions at once because my 30 GB of RAM can’t keep up beyond that.&lt;/p&gt;
&lt;h2 id=&quot;getting-my-moneys-worth&quot;&gt;Getting my money’s worth&lt;/h2&gt;
&lt;p&gt;I have one subscription at 200 and another at 100. In September, what my agents used was worth 18,000 dollars at API prices. And I get every cent out of them. If you pay for it, it has to run, all the time, even while you sleep.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-fine.jpg&quot; alt=&quot;This Is Fine meme: the dog sitting in the burning room, “10 agents breaking stuff at the same time”, “that’s the point”&quot; height=&quot;578&quot; width=&quot;617&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;That’s the 20 October spike. Not 977 things shipped, but lots of leads started at once in the background, to see what holds. AI makes you go faster, ok. But above all, it makes you fail faster. And a mistake found in an afternoon is a week you don’t lose looking for it.&lt;/p&gt;
</content:encoded>
        </item>
        <item>
            <title>I tried every Linux launcher, so I made my own</title>
            <link>https://ilyasturki.com/en/writing/universe/</link>
            <guid isPermaLink="true">https://ilyasturki.com/en/writing/universe/</guid>
            <pubDate>Sun, 25 Oct 2026 00:00:00 GMT</pubDate>
            <dc:creator>Ilyas Turki</dc:creator>
            <description>Steam, Heroic, Lutris, Pegasus, Big Picture. They all have a problem on Linux, so I built Universe, a launcher you drive with a controller, in-game overlay included.</description>
            <content:encoded>&lt;p&gt;Steam, Heroic, Lutris, Pegasus, and even Steam Big Picture. I tried them all on Linux, and they all have a problem. I just wanted a solution that was actually decent. I’d been thinking about it for a few years, and in September I got down to it. It’s called &lt;a href=&quot;https://ilyasturki.com/en/projects/universe/&quot;&gt;Universe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-astronaute.jpg&quot; alt=&quot;Always Has Been meme: an astronaut, controller in hand, looks at the Earth and asks “wait, it’s all desktop apps?”, the other one, labeled “gaming on Linux”, points a gun at him and answers “always has been”&quot; height=&quot;578&quot; width=&quot;1066&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;steam-and-lutris-first&quot;&gt;Steam and Lutris, first&lt;/h2&gt;
&lt;p&gt;At first, I used Lutris and Steam a lot. And both have the same issue, each in its own way.&lt;/p&gt;
&lt;p&gt;Steam is great for Steam games. For the rest, much less so. A GOG game, an Epic game or an emulator, you add it as a shortcut by hand, with no cover art, and you need tools on the side to make it look like anything. And on the desktop, the Steam client is a desktop app with menus, lists and a store bolted on.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/steam-bibliotheque.jpg&quot; alt=&quot;The Steam client’s library: a column listing games on the left, shelves of cover art on the right, and the Store, Library and Community tabs at the top&quot; height=&quot;1026&quot; width=&quot;1200&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A desktop app. Great with a mouse, much less so from the couch.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Lutris is the opposite. It handles everything: Wine, emulators, GOG, Epic, with install scripts for pretty much any game. It’s super powerful, but it’s a GTK app, a grid of cover art with menus, buttons and settings panels. You don’t drive it with a controller. It’s a tool to install and configure things, not a place where you want to pick your game.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/lutris-bibliotheque.jpg&quot; alt=&quot;Lutris’s library: a grid of cover art for free games, and a sidebar with the sources, the Wine and Linux runners, and the platforms&quot; height=&quot;836&quot; width=&quot;1600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Lutris: everything’s there, but everything’s done with the mouse.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Heroic is the same idea for Epic and GOG. And Big Picture really is driven with a controller, but it’s still designed for Steam first.&lt;/p&gt;
&lt;p&gt;That’s the underlying problem. On PC, launchers are made for a desk, a keyboard and a mouse. On console, everything is designed for the TV, the couch and the controller. I wanted the second, with all my games in it. A real, modern video game interface, where you grab your controller and play, without ever touching the keyboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-pooh.jpg&quot; alt=&quot;Tuxedo Winnie the Pooh meme: in a t-shirt, “launching a game with the mouse”; in a tuxedo, “launching it with a controller from the couch”&quot; height=&quot;578&quot; width=&quot;1000&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;pegasus-almost&quot;&gt;Pegasus, almost&lt;/h2&gt;
&lt;p&gt;Then I really went with Pegasus. It was the best one for me, and it’s actually what got me to start. But Pegasus is a crazy power user solution, so you have to maintain a lot of what you do.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/pegasus-grid.jpg&quot; alt=&quot;Pegasus with a grid theme: Castlevania’s cover art large on the left with its summary and a screenshot of the game, and a grid of NES cover art on the right, under one tab per console&quot; height=&quot;710&quot; width=&quot;1366&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Pegasus, already controller-driven. But everything is set up by hand, in files.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Same story with themes. The ones I found were very often a bit old, not very well maintained. So I made my own, &lt;a href=&quot;https://github.com/ilyasturki/pegasus-theme-reprise&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Reprise&lt;/a&gt;, a truly modern theme.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/pegasus-reprise.jpg&quot; alt=&quot;Reprise, my Pegasus theme: Donkey Kong Country Returns large on the home screen, the Continue and Details buttons, and a row of cover art at the bottom with the controller buttons shown in the footer&quot; height=&quot;900&quot; width=&quot;1600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Reprise, my Pegasus theme. Universe started from there.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And as I went, the list grew. I’d have liked extensions; Pegasus has none. More up-to-date themes. My own stores, GOG, Steam and the rest, plugged in directly. And then there was this thing: when I launched a game, Pegasus’s window closed, and there was a small delay before the game’s window opened.&lt;/p&gt;
&lt;h2 id=&quot;what-consoles-do&quot;&gt;What consoles do&lt;/h2&gt;
&lt;p&gt;All those little things on console are so handy. On a Linux PC, you don’t get them.&lt;/p&gt;
&lt;p&gt;The biggest one is the in-game overlay. You press HOME, the game pauses and Universe opens on top. From there, you take a screenshot, turn on MangoHud, cap the FPS, set the volume, reconnect a controller or quit. All with the controller, without leaving the couch. Universe is one of the only launchers that has this, along with Steam Big Picture.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/universe-home-jeu.jpg&quot; alt=&quot;Dead Cells paused under Universe’s overlay: the dock at the bottom, and the Performance menu open with MangoHud on, the FPS limit and pause on HOME&quot; height=&quot;900&quot; width=&quot;1600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Dead Cells paused, MangoHud one button away.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And launching no longer cuts anything off: Universe doesn’t close, it stays under the game, and HOME brings it back on top.&lt;/p&gt;
&lt;h2 id=&quot;whats-inside&quot;&gt;What’s inside&lt;/h2&gt;
&lt;p&gt;GOG, Steam, Epic and itch.io in a single library, installed and updated from Universe. On first launch, it picks up the games already installed by Lutris and Heroic, and the emulators’ ROM folders, without moving anything. Proton, Wine and 21 emulators install and update from the settings.&lt;/p&gt;
&lt;p&gt;There are three looks. The default one is a port of Reprise, my Pegasus theme. The other two take after the Switch 2 home screen and the PS5’s. And what Pegasus was missing is here: modules, stores and themes made by other people install as add-ons.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/universe-accueil.jpg&quot; alt=&quot;Universe’s home screen with the default look: GTA V artwork in the background, the Continue and Game page buttons, and a row of cover art at the bottom&quot; height=&quot;900&quot; width=&quot;1600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The default look is Reprise, ported from Pegasus.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;its-first-stars&quot;&gt;Its first stars&lt;/h2&gt;
&lt;p&gt;It’s still early, we’re at 0.0.13. It installs on Arch through the AUR, on Fedora through COPR, and on SteamOS or Bazzite with a script. It runs on a Steam Deck, or in a dedicated session, with no desktop, like a console. It’s also the project that got the most out of &lt;a href=&quot;https://ilyasturki.com/en/writing/cent-commits/&quot;&gt;my 100 commits a day&lt;/a&gt;: 1,263 commits between 11 September and 25 October.&lt;/p&gt;
&lt;p&gt;Today it has its first stars on GitHub, and it’s slowly making its way.&lt;/p&gt;
</content:encoded>
        </item>
        <item>
            <title>Why I write my prompts in the terminal</title>
            <link>https://ilyasturki.com/en/writing/prompts-terminal/</link>
            <guid isPermaLink="true">https://ilyasturki.com/en/writing/prompts-terminal/</guid>
            <pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate>
            <dc:creator>Ilyas Turki</dc:creator>
            <description>I feel at home in the terminal, and I write better there. The IKEA effect explains half of it, interface consistency explains the rest.</description>
            <content:encoded>&lt;p&gt;It’s not that my prompts are worse outside the terminal. It’s that I have more fun in it. Inspiration comes more easily, the writing goes faster, and for a long time I couldn’t say why. Now I know: I feel at home there.&lt;/p&gt;
&lt;p&gt;Yet I have everything I need to do otherwise. Claude Desktop is installed on this machine, the web app sits in a tab. I try not to use them. When I want to talk to an agent, I open a black window.&lt;/p&gt;
&lt;h2 id=&quot;i-didnt-choose-the-terminal&quot;&gt;I didn’t choose the terminal&lt;/h2&gt;
&lt;p&gt;Linux forced me. I started out as the guy who was always in VS Code; I rarely opened the terminal, and I didn’t like it at all. Except the more you use Linux, the closer it pulls you to the terminal. And the more you live in the terminal, the closer it pulls you to Neovim and tmux. Especially when, like me, you love customizing and always having the perfect setup.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-gru.jpg&quot; alt=&quot;Gru’s plan meme: install Linux, get forced to use the terminal, can’t write anywhere else anymore, then Gru reading the last panel, dismayed&quot; height=&quot;578&quot; width=&quot;936&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;Today everything runs in Ghostty: Claude Code, Codex, Neovim, lazygit. Leaving it to write takes effort.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&quot;https://ilyasturki.com/blog/ghostty-claude.webp&quot; type=&quot;image/webp&quot;&gt;&lt;img src=&quot;https://ilyasturki.com/blog/ghostty-claude.png&quot; alt=&quot;Claude Code open in Ghostty, with a four-line prompt being typed in French in the input field&quot; width=&quot;1700&quot; height=&quot;1300&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The black window in question. The prompt is four lines long because Shift+Enter does what I told it to do.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;it-looks-like-code&quot;&gt;It looks like code&lt;/h2&gt;
&lt;p&gt;IosevkaTerm, size 11. A prompt typed in there doesn’t look like a message: it’s code, well, it looks like it, and I liked code. Since I’m used to coding in the terminal, writing in the same place comes naturally. I rattle it off, on and on. And there’s less fear of starting over from scratch.&lt;/p&gt;
&lt;h2 id=&quot;every-site-knows-better&quot;&gt;Every site knows better&lt;/h2&gt;
&lt;p&gt;Everywhere else, every textarea has an opinion. Some format markdown automatically, some couldn’t care less. In some, Shift+Enter adds a new line, in others it sends the message right away. Each one tells you: me, I know better than the others. And all those differences add up to something annoying that keeps you from feeling at home there.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-deux-boutons.jpg&quot; alt=&quot;Two buttons meme: a sweating man hesitates between “Enter adds a new line” and “Enter sends the message”&quot; height=&quot;874&quot; width=&quot;600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;Usability has a name for this: the mode error, the same key doing two different things depending on context. The rule it breaks is called consistency, and the HCI literature calls it its &lt;a href=&quot;https://asktog.com/atc/principles-of-interaction-design/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;golden rule&lt;/a&gt;. My annoyance has references.&lt;/p&gt;
&lt;p&gt;In the terminal, the question goes away. No difference from one tool to the next: same font, same colors, same Enter. It’s easier on the eyes and on the brain.&lt;/p&gt;
&lt;h2 id=&quot;the-ikea-effect&quot;&gt;The IKEA effect&lt;/h2&gt;
&lt;p&gt;Digging further, I came across a second name: the &lt;a href=&quot;https://thedecisionlab.com/biases/ikea-effect&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;IKEA effect&lt;/a&gt;. We value what we put together ourselves more; effort creates ownership, ownership creates attachment. Researchers file it under cognitive biases. I’m happy to be biased.&lt;/p&gt;
&lt;p&gt;Because I built this terminal piece by piece. Two lines from my &lt;code&gt;ghostty.nix&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-nix&quot;&gt;&lt;span class=&quot;tok-comment&quot;&gt;# Ctrl+Backspace deletes a word everywhere (default sends ^H which collides with Ctrl+H)&lt;/span&gt;
&lt;span class=&quot;tok-string&quot;&gt;&quot;ctrl+backspace=text:\\x17&quot;&lt;/span&gt;
&lt;span class=&quot;tok-comment&quot;&gt;# Shift+Enter: raw Meta+Enter so Codex/Claude newlines survive tmux&lt;/span&gt;
&lt;span class=&quot;tok-string&quot;&gt;&quot;shift+enter=text:\\x1b\\x0d&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set once, inherited everywhere: by Claude Code, by Codex, by Neovim, and by whatever I install next year.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/schema-grammaire.svg&quot; alt=&quot;Diagram in two areas: on the left, four sites that each have their own rule for the Enter key; on the right, the terminal, where Claude Code, Neovim, lazygit, Codex, fish and Starship share a single grammar set once in Nix&quot; width=&quot;960&quot; height=&quot;540&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;The reverse test exists too. I SSH into a machine, land on the default bash, without my fish, without my Starship: I don’t like it at all. Nothing works worse there, though. It’s just not home. Research on flow says the same thing in other words: to get absorbed in a task, you need a familiar, well-practiced environment that you feel in control of. A different textarea on every site is exactly the opposite.&lt;/p&gt;
&lt;h2 id=&quot;the-phone-still&quot;&gt;The phone, still&lt;/h2&gt;
&lt;p&gt;I’m no purist. When I’m away from home with only my phone, I open the Claude app, and for typing something quick, it’s easier that way. A stopgap. As soon as I’m back at a keyboard, I’m back in the black window.&lt;/p&gt;
&lt;p&gt;It’s like beds, really. At home I feel good, I fall asleep easily in my bed; in a hotel or abroad, I sleep less easily. The terminal is my bed. Every other text field is a hotel room.&lt;/p&gt;
</content:encoded>
        </item>
        <item>
            <title>Back to Neovim, two years later</title>
            <link>https://ilyasturki.com/en/writing/retour-neovim/</link>
            <guid isPermaLink="true">https://ilyasturki.com/en/writing/retour-neovim/</guid>
            <pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate>
            <dc:creator>Ilyas Turki</dc:creator>
            <description>Left for VS Code, then a year on Zed. I live in the terminal now, and Neovim was already there.</description>
            <content:encoded>&lt;p&gt;I loved Neovim so much. And I left it anyway. The reason is nothing original: I spent too much time editing my plugins instead of doing real work. So I moved to VS Code, out of discipline. You tinker with your config there too, but it matters less: you change it quickly, everything works, no big bugs. It was better.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-boyfriend.jpg&quot; alt=&quot;Distracted boyfriend meme: “me” turns to look at “keymaps.lua” while “real work” sulks&quot; height=&quot;578&quot; width=&quot;900&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-zed-detour&quot;&gt;The Zed detour&lt;/h2&gt;
&lt;p&gt;Then Zed, and that was serious. A good week getting used to the shortcuts and cleaning up my config, then a year using it a lot, on my desktop as well as my laptop. It got very powerful, and I was able to reimplement all the shortcuts I had on Neovim, the ones I missed so much on VS Code.&lt;/p&gt;
&lt;p&gt;One gap remained: my server. There I work over SSH, straight in the terminal, so I kept Neovim there as a backup. The backup was about to become the main one.&lt;/p&gt;
&lt;h2 id=&quot;tmux-brought-me-back&quot;&gt;tmux brought me back&lt;/h2&gt;
&lt;p&gt;The real trigger was Claude Code. The more I used it, the more I lived in the terminal. At first I ran it inside Zed, but I didn’t like that workflow much, and I ended up on tmux. And once I’m in tmux full time, opening Zed bugs me, opening VS Code bugs me even more, because you have to grab the mouse and I don’t want to grab the mouse. An editor that already lives in the terminal, between lazygit and Claude Code: the perfect thing.&lt;/p&gt;
&lt;p&gt;I didn’t rebuild anything, by the way. My old config was still there, working, and I brought back into it everything I’d worked out on Zed. The result is more minimal than before, but nothing is lost. That’s why coming back was so easy: I already had something good.&lt;/p&gt;
&lt;h2 id=&quot;good-enough&quot;&gt;Good enough&lt;/h2&gt;
&lt;p&gt;A config is never finished. Not on Neovim, not on VS Code, not on Zed: if you feel like tinkering, you’ll tinker. At some point you have to tell yourself ok, it’s good enough, let’s get to work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are a billion things to change in my config. That’s fine. I’m sticking with what I have.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s in git, so I can check what I’m saying instead of trusting my impression: nothing in weeks. I’m productive with it. And anyway, Claude Code makes most of my edits these days.&lt;/p&gt;
&lt;h2 id=&quot;the-bare-minimum-of-ai&quot;&gt;The bare minimum of AI&lt;/h2&gt;
&lt;p&gt;So I expect almost nothing from AI in the editor. Since the agents write the bulk of the code, no need for a built-in chat or one more agent: just a fast autocomplete that saves me time when I type. I know it’s not the trend anymore: even at Cursor, autocomplete isn’t the flagship anymore, everyone’s focused on agents, and tools like Claude Code or Codex don’t even offer it. For me, it’s minuet hooked up to DeepSeek, paid per token and tuned to stay light: a single suggestion per request, little context. It gets the job done, and it’s really cheap.&lt;/p&gt;
&lt;h2 id=&quot;the-config-thats-left&quot;&gt;The config that’s left&lt;/h2&gt;
&lt;p&gt;Nothing fancy: neo-tree in a floating window, lualine at the bottom, bufferline at the top, treesitter and the LSP doing the heavy lifting, 38 plugins pinned in &lt;code&gt;lazy-lock.json&lt;/code&gt;. The theme follows the system: onedark in dark mode, catppuccin latte in light mode.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&quot;https://ilyasturki.com/blog/nvim-telescope.webp&quot; type=&quot;image/webp&quot;&gt;&lt;img src=&quot;https://ilyasturki.com/blog/nvim-telescope.png&quot; alt=&quot;Telescope open in live grep over my Neovim config, the list of results in the middle and the file preview on the right&quot; width=&quot;1800&quot; height=&quot;1087&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Telescope in live grep. Once you navigate like this, clicking through a sidebar feels slow again.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Everything starts from the space bar as leader. The rest is ergonomics so my hands never leave the home row.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lua&quot;&gt;&lt;span class=&quot;tok-comment&quot;&gt;-- jk / kj to leave insert mode, everywhere&lt;/span&gt;
&lt;span class=&quot;tok-fn&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;tok-string&quot;&gt;&quot;i&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;jk&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;&amp;lt;Esc&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;tok-fn&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;tok-string&quot;&gt;&quot;i&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;kj&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;&amp;lt;Esc&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;tok-comment&quot;&gt;-- U to redo (the default U is useless)&lt;/span&gt;
&lt;span class=&quot;tok-fn&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;tok-string&quot;&gt;&quot;n&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;U&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;&amp;lt;C-r&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;tok-comment&quot;&gt;-- c deletes into the black hole, not the clipboard&lt;/span&gt;
&lt;span class=&quot;tok-fn&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;n&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;v&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;x&quot;&lt;/span&gt; &lt;span class=&quot;tok-punct&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&#39;&quot;_c&#39;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;tok-comment&quot;&gt;-- H / L jump to the first / last non-blank character&lt;/span&gt;
&lt;span class=&quot;tok-comment&quot;&gt;-- (usable as motions: dH, dL)&lt;/span&gt;
&lt;span class=&quot;tok-fn&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;n&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;v&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;o&quot;&lt;/span&gt; &lt;span class=&quot;tok-punct&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;H&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;^&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;tok-fn&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;n&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;v&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;o&quot;&lt;/span&gt; &lt;span class=&quot;tok-punct&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;L&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;g_&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;tok-comment&quot;&gt;-- AZERTY: ù sits right under the fingers, so it replaces %&lt;/span&gt;
&lt;span class=&quot;tok-fn&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;n&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;v&quot;&lt;/span&gt; &lt;span class=&quot;tok-punct&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;ù&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;tok-string&quot;&gt;&quot;%&quot;&lt;/span&gt;&lt;span class=&quot;tok-punct&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&quot;https://ilyasturki.com/blog/nvim-whichkey.webp&quot; type=&quot;image/webp&quot;&gt;&lt;img src=&quot;https://ilyasturki.com/blog/nvim-whichkey.png&quot; alt=&quot;The which-key menu that shows up after pressing the leader key, listing the available shortcuts&quot; width=&quot;1800&quot; height=&quot;1087&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;which-key. I press space, and it reminds me of everything that starts from there.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Two years elsewhere, and the comeback wasn’t about the editor itself: I live in the terminal now, and Neovim was already there. The config is good enough. Well, until next time.&lt;/p&gt;
</content:encoded>
        </item>
        <item>
            <title>AI makes average designs, and you can tell</title>
            <link>https://ilyasturki.com/en/writing/design-moyen/</link>
            <guid isPermaLink="true">https://ilyasturki.com/en/writing/design-moyen/</guid>
            <pubDate>Thu, 02 Jul 2026 00:00:00 GMT</pubDate>
            <dc:creator>Ilyas Turki</dc:creator>
            <description>Claude Design was supposed to break us out of the default, and I spot its sites at a glance. Blame laziness: we ship the model&#39;s first output and never iterate.</description>
            <content:encoded>&lt;p&gt;I can spot a site made with Claude Design. No need to look hard, you can tell. And it’s pretty ironic, because Claude Design exists precisely for that: breaking out of the norm, getting a design a bit more incredible than what the model would put out on its own. Except everyone started using it, with pretty much the same prompt. When everyone asks the same tool for the same originality, originality becomes just another norm.&lt;/p&gt;
&lt;p&gt;Same story with images. Everyone eventually noticed that the visuals ChatGPT generates all look alike. Shops use them for their ads instead of a graphic designer, and they’re not bad, but you spot them at a glance.&lt;/p&gt;
&lt;h2 id=&quot;a-model-aims-for-the-center&quot;&gt;A model aims for the center&lt;/h2&gt;
&lt;p&gt;A model puts out the most likely answer, literally the center of everything it swallowed. Training pushes the same way: it rewards what pleases the most people, so the consensus, never the weird. And on top of all that, we all use the same tool with pretty much the same prompt, so we all draw the same point from the same distribution.&lt;/p&gt;
&lt;p&gt;AI knows what’s bad: it won’t do it. It doesn’t know what’s exceptional: it won’t do that either. What’s left in between is the average.&lt;/p&gt;
&lt;h2 id=&quot;yesterdays-exceptional&quot;&gt;Yesterday’s exceptional&lt;/h2&gt;
&lt;p&gt;The funniest part: the designs we call vibecoded today, we thought they were incredible back then. The big gradients of ten years ago, the glassmorphism of five or six years ago: those were the best designs, the ones people showed me as examples. They haven’t gotten worse since. We’ve just seen far too many of them, and after a while we realized they were kind of lame.&lt;/p&gt;
&lt;p&gt;Average isn’t ugly. It’s yesterday’s exceptional, worn out by repetition.&lt;/p&gt;
&lt;h2 id=&quot;three-versions-of-kilorep&quot;&gt;Three versions of Kilorep&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ilyasturki.com/en/projects/&quot;&gt;Kilorep&lt;/a&gt;, my strength training tracker, started exactly like that: a first version designed entirely by Claude Design, still online at &lt;a href=&quot;https://v1.kilorep.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;v1.kilorep.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&quot;https://ilyasturki.com/blog/kilorep-v1-claude-design.webp&quot; type=&quot;image/webp&quot;&gt;&lt;img src=&quot;https://ilyasturki.com/blog/kilorep-v1-claude-design.png&quot; alt=&quot;The first version of Kilorep, generated by Claude Design&quot; width=&quot;2610&quot; height=&quot;1624&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;At first I was impressed. I was thinking wow, incredible, it makes really original stuff. Then I generated other designs, on other projects, and no: it does the same thing every time. The style changes, the colors change, the borders change, but it’s the same vibe, and you notice.&lt;/p&gt;
&lt;p&gt;And that’s only the visible problem. By default, the interface comes out cluttered, with useless elements all over the place, never minimal enough. The real problem is the user experience: a disaster if nobody takes care of it. So I iterated. A first redesign in Claude Design, a second with Claude Code, and it’s this third version that runs today on &lt;a href=&quot;https://kilorep.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;kilorep.com&lt;/a&gt;. Iterate, iterate, iterate until it’s properly usable, then test it thoroughly to check it really is.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/kilorep-v2-claude-design.jpg&quot; alt=&quot;The first redesign, in Claude Design&quot; height=&quot;771&quot; width=&quot;1567&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/kilorep-v3-claude-code.jpg&quot; alt=&quot;The final version, the one on kilorep.com&quot; height=&quot;688&quot; width=&quot;319&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;this-site-too&quot;&gt;This site too&lt;/h2&gt;
&lt;p&gt;The one you’re reading doesn’t escape it. Its main inspiration is &lt;a href=&quot;https://wondermake.xyz/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Wondermake&lt;/a&gt;, a design agency’s site I found gorgeous and redid my own way.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/wondermake-home.jpg&quot; alt=&quot;Wondermake’s home page: monochrome, huge type, a visible grid&quot; height=&quot;910&quot; width=&quot;1440&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;Monochrome is a choice: effective, no need to bother with colors, and timeless, so it will hold up. And there are vibecoded bits here too, mostly on the design side. It’s not perfect, but it’s still decent, it doesn’t bother me that much, and I don’t think it jumps out at you.&lt;/p&gt;
&lt;h2 id=&quot;the-problem-is-laziness&quot;&gt;The problem is laziness&lt;/h2&gt;
&lt;p&gt;The problem was never vibecoding, or letting AI draw. The problem is laziness: shipping the model’s first output without ever iterating, when you have to. That’s how we end up with ten identical apps, full of bugs on top of that, which is a pain.&lt;/p&gt;
&lt;p&gt;AI won’t make what’s bad, but it won’t make what’s exceptional either. The average, it hands you. The exceptional, you have to go and get.&lt;/p&gt;
</content:encoded>
        </item>
        <item>
            <title>Open source doesn&#39;t make AI free</title>
            <link>https://ilyasturki.com/en/writing/locataires/</link>
            <guid isPermaLink="true">https://ilyasturki.com/en/writing/locataires/</guid>
            <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
            <dc:creator>Ilyas Turki</dc:creator>
            <description>The most expensive plan went from 20 to 300 dollars in two and a half years. I installed Ollama to see: you always pay for compute, but without the landlord&#39;s tax.</description>
            <content:encoded>&lt;p&gt;The 100 euro a month subscription has become the new 20 euros. Today people sign up at 200. And I can’t see what would stop the climb: next it’s 500, then 1,000. We got well and truly had, and the worst part is we say thank you.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/prix-plafond.svg&quot; alt=&quot;The price of the most expensive consumer plan on the market: 20 dollars in early 2023, 200 in late 2024, 300 in mid-2025, then a dotted projection towards 500 and 1,000&quot; width=&quot;960&quot; height=&quot;560&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;From 20 to 300 dollars in two and a half years. The dotted line is my bet.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And for that price, we don’t even know what we’re buying. Private model, private data, private code. As I write this, Opus 4.8 has just come out, and plenty of people are convinced Opus 4.5 got worse in the weeks before: A/B testing, reasoning_effort turned down on the sly, everyone has their theory. Maybe they’re right, maybe not, and that’s exactly the problem: the box is closed, all you have left is a feeling. Meanwhile, the limits run out a little faster with every model update. The rent goes up, the flat shrinks, and nobody ever comes round to inspect it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-anakin.jpg&quot; alt=&quot;Anakin and Padmé meme: “We improved the model” “And I can check that, right?”, silence, “And I can check that, right?”&quot; height=&quot;600&quot; width=&quot;600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;Let’s be clear: I love Claude. I spend my days in it and I prefer it to everything else. The problem was never the product. The problem is being a tenant.&lt;/p&gt;
&lt;h2 id=&quot;i-tried-the-emergency-exit&quot;&gt;I tried the emergency exit&lt;/h2&gt;
&lt;p&gt;So I installed Ollama. No horror story to tell: ROCm, a GFX version override in my Nix config for my RX 7900 GRE, and it runs. gpt-oss:20b, gemma3:12b, qwen3.5:9b, deepseek-r1:8b. Local, free, offline, sending nothing back to anyone.&lt;/p&gt;
&lt;p&gt;These are middle tier models. They get the job done, but it’s not Opus 4.8, and nobody trades Opus for a 20b for very long. The really interesting models need a machine the average PC isn’t. On the laptop, forget it: it runs even smaller versions, and you can tell.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/ollama-transcript.svg&quot; alt=&quot;Ollama session on my laptop, in French: qwen3.5:4b thinks for five minutes, introduces itself as a Google assistant, then answers with three sentences of corporate jargon&quot; width=&quot;780&quot; height=&quot;480&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;qwen3.5:4b on my laptop, genuine output, in French because I asked in French. Five minutes of thinking, an identity crisis, and an answer straight out of a sales brochure.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;On my machine, Ollama doesn’t even start at boot. &lt;code&gt;systemctl start ollama&lt;/code&gt; when I need it, and I rarely need it. It’s a backup. An emergency exit, not a front door: you’re very glad it exists, you don’t want to live in it.&lt;/p&gt;
&lt;h2 id=&quot;you-always-pay-for-compute&quot;&gt;You always pay for compute&lt;/h2&gt;
&lt;p&gt;A myth to kill on the way: open source doesn’t make AI free. The weights are free, the compute never is. Either you buy the GPU or you rent someone else’s, and either way the bill comes.&lt;/p&gt;
&lt;p&gt;Look at &lt;a href=&quot;http://z.ai&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;z.ai&lt;/a&gt;. GLM is open weights, you can download the model tonight. Their Coding Plan, though: 18, 80 and 168 dollars a month. The same tiers as Claude Code, from the champion of open source.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&quot;https://ilyasturki.com/blog/glm-coding-plan.webp&quot; type=&quot;image/webp&quot;&gt;&lt;img src=&quot;https://ilyasturki.com/blog/glm-coding-plan.png&quot; alt=&quot;The three tiers of z.ai’s GLM Coding Plan: Lite at 18 dollars, Pro at 80 dollars and Max at 168 dollars a month&quot; width=&quot;1568&quot; height=&quot;768&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;GLM Coding Plan pricing. Remind you of anything?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And yet, tier for tier, it’s cheaper: 80 instead of 100, 168 instead of 200. That gap has a name: the landlord’s margin. The Anthropic tax, the OpenAI tax. On an open model it disappears, and all that’s left is the price of the cards and the power. Rent without the agency fees.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-compute.jpg&quot; alt=&quot;Expanding brain meme: paying 20 dollars a month for an AI, then 100, then 200, and finally buying a 600 buck GPU to run a free AI&quot; height=&quot;826&quot; width=&quot;600&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-only-ones-who-can-slash-prices&quot;&gt;The only ones who can slash prices&lt;/h2&gt;
&lt;p&gt;Owning the model means you can sell the subscription for less than what everyone else pays for the API. That’s why Claude Code and Codex are unbeatable on price: OpenAI and Anthropic sell at cost what the rest of the market buys at retail.&lt;/p&gt;
&lt;p&gt;OpenCode tries to play the same game without owning a model, and it shows. The subscriptions are less generous, and I wouldn’t bet a cent on their margin the day people start seriously getting their money’s worth out of them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://ilyasturki.com/blog/en/meme-pigeon.jpg&quot; alt=&quot;“Is this a pigeon?” meme: an AI startup points at API access and asks if it’s a moat&quot; height=&quot;578&quot; width=&quot;999&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;&lt;/p&gt;
&lt;p&gt;A wrapper, when you get down to it, is subletting. You collect from your subtenants, hand most of the rent to the landlord, and pray the landlord never starts renting direct.&lt;/p&gt;
&lt;h2 id=&quot;i-still-want-open-source-to-win&quot;&gt;I still want open source to win&lt;/h2&gt;
&lt;p&gt;So yes, we’re tenants, and the rent is going up. Yes, compute costs money, open weights or not. But I want open source to win, and not out of tinkerer nostalgia. It’s better for us: a box you can open and run at home. It’s better for transparency: nobody turns down the reasoning_effort on the sly on a model whose weights you have. And it’s better for the bill: even when it’s expensive, it’s still cheaper, because the landlord’s tax is the one line we can still refuse to pay.&lt;/p&gt;
&lt;p&gt;Stay a tenant if the rent suits you. I pay for Max 20x every month, and I’ll probably still pay for it at 500. But I keep a spare set of keys on my disk: four open models and a &lt;code&gt;systemctl start ollama&lt;/code&gt;, just to check now and then that the lock still turns.&lt;/p&gt;
</content:encoded>
        </item>
    </channel>
</rss>
