<?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: Andrea Debernardi</title>
    <description>The latest articles on DEV Community by Andrea Debernardi (@debba).</description>
    <link>https://dev.to/debba</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F23999%2F8993394e-b845-4933-a1d3-ebfa2e954992.jpeg</url>
      <title>DEV Community: Andrea Debernardi</title>
      <link>https://dev.to/debba</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/debba"/>
    <language>en</language>
    <item>
      <title>Databases Are Not Becoming Chatbots</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Fri, 17 Apr 2026 11:30:38 +0000</pubDate>
      <link>https://dev.to/debba/databases-are-not-becoming-chatbots-15gg</link>
      <guid>https://dev.to/debba/databases-are-not-becoming-chatbots-15gg</guid>
      <description>&lt;p&gt;Over the last two months, while building a database tool and adding AI features to it, I started realizing that I was not just shipping product work. I was bumping into a larger question: what happens to databases when software no longer just reads and writes records, but also interprets schema, suggests queries, explains plans, preserves context, and collaborates with language models?&lt;/p&gt;

&lt;p&gt;My current view is simple: databases are not becoming chatbots.&lt;/p&gt;

&lt;p&gt;The real change is happening in the layer around the database.&lt;/p&gt;

&lt;p&gt;Databases still matter because structured truth still matters. LLMs do not replace the need for schemas, constraints, transactions, and systems of record. If anything, they make those things more valuable.&lt;/p&gt;

&lt;p&gt;What AI changes is interpretation, navigation, and action around the database.&lt;/p&gt;

&lt;p&gt;That became very concrete to me while building &lt;code&gt;Tabularis&lt;/code&gt;, especially once AI, notebooks, visual explainability, MCP, and plugins started living in the same workflow.&lt;/p&gt;

&lt;p&gt;Here are the main bets I find myself making:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI should not become the source of truth&lt;/li&gt;
&lt;li&gt;AI should stay optional&lt;/li&gt;
&lt;li&gt;preserved context matters more than one-shot generation&lt;/li&gt;
&lt;li&gt;the future is probably composable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are the mistakes I think I may be making:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using AI where better UX would be enough&lt;/li&gt;
&lt;li&gt;overestimating generation and underestimating control&lt;/li&gt;
&lt;li&gt;underestimating auditability and reproducibility&lt;/li&gt;
&lt;li&gt;designing too much for the future&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote the full version here, with more detail on the technical decisions and the mistakes behind them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://tabularis.dev/blog/building-tabularis-future-of-databases-ai" rel="noopener noreferrer"&gt;Read the full article on tabularis.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>From 0 to 1,000 GitHub Stars in 10 Weeks: What Actually Worked</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Tue, 14 Apr 2026 07:24:09 +0000</pubDate>
      <link>https://dev.to/debba/from-0-to-1000-github-stars-in-10-weeks-what-actually-worked-59a6</link>
      <guid>https://dev.to/debba/from-0-to-1000-github-stars-in-10-weeks-what-actually-worked-59a6</guid>
      <description>&lt;p&gt;Ten weeks ago I pushed the first binary of &lt;a href="https://github.com/debba/tabularis" rel="noopener noreferrer"&gt;Tabularis&lt;/a&gt; to GitHub. A cross-platform database client built with Tauri (Rust + React/TypeScript). One person, a late-night frustration, and a SQL editor.&lt;/p&gt;

&lt;p&gt;Last week the repo crossed &lt;strong&gt;1,000 stars&lt;/strong&gt;. Today there are 1,086 stars, 70 forks, 15 contributors, 41 releases, and a plugin ecosystem that didn't exist eight weeks ago.&lt;/p&gt;

&lt;p&gt;No marketing budget. No growth hacks.&lt;/p&gt;

&lt;p&gt;I wrote a detailed post about what actually worked, what didn't, and what I'd do differently. Here are the highlights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ship fast, ship broken
&lt;/h2&gt;

&lt;p&gt;The first week produced &lt;strong&gt;fifteen releases&lt;/strong&gt;. Some were embarrassing. I shipped anyway. Nobody remembers your v0.3.0. People remember whether the tool was useful when they tried it, and whether it got better when they came back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build an extension point early
&lt;/h2&gt;

&lt;p&gt;The decision that changed the trajectory: shipping a &lt;strong&gt;plugin system&lt;/strong&gt; (language-agnostic JSON-RPC protocol) at the one-month mark. Within two weeks the community had added Redis, ClickHouse, CSV, and a Hacker News plugin. It turned users into builders.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI factor
&lt;/h2&gt;

&lt;p&gt;I need to be honest: Tabularis would not exist without AI-assisted development. Specifically, &lt;a href="https://claude.ai/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;41 releases in eleven weeks, one person. That math doesn't work without a force multiplier. But AI doesn't replace experience. It amplifies it. Claude Code didn't design the plugin architecture or decide that JSON-RPC was the right protocol. Those decisions came from years of building software.&lt;/p&gt;

&lt;p&gt;What AI did was collapse the distance between a decision and its implementation. Once I knew &lt;em&gt;what&lt;/em&gt; to build, I could build it in hours instead of days.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers at week 11
&lt;/h2&gt;

&lt;p&gt;The 1,000-star milestone landed at week ten. Here's where things stand today, one week later:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Week 4&lt;/th&gt;
&lt;th&gt;Week 10&lt;/th&gt;
&lt;th&gt;Week 11 (today)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stars&lt;/td&gt;
&lt;td&gt;~270&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,086&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contributors&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Releases&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forks&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugins&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Languages&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Issues&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;~70&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;81&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull Requests&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;~35&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Downloads&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;~6,000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7,100+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  72 countries and counting
&lt;/h2&gt;

&lt;p&gt;One thing that surprised me: where those stars come from. About half of our stargazers have a public location on their GitHub profile, and they span &lt;strong&gt;72 countries&lt;/strong&gt; across every continent.&lt;/p&gt;

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

&lt;p&gt;The United States and China lead, but what stands out is the long tail: South Korea, Germany, France, Brazil, Indonesia, Vietnam. Tabularis isn't a tool for one market. It's a tool for developers, and developers are everywhere.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Read the full story
&lt;/h2&gt;

&lt;p&gt;The full post covers every phase week by week, what didn't work, and advice for anyone starting an open source project today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://tabularis.dev/blog/from-zero-to-1000-github-stars" rel="noopener noreferrer"&gt;Read the full post on tabularis.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/debba/tabularis" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://discord.gg/YrZPHAwMSG" rel="noopener noreferrer"&gt;Join the Discord&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you're building something in the open, I'd love to hear your story. Drop a comment or find me on &lt;a href="https://x.com/debba_92" rel="noopener noreferrer"&gt;X&lt;/a&gt; or &lt;a href="https://discord.gg/YrZPHAwMSG" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>github</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I am building a Notebook Environment for SQL Inside a Database Client</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Fri, 03 Apr 2026 06:42:43 +0000</pubDate>
      <link>https://dev.to/debba/i-am-building-a-notebook-environment-for-sql-inside-a-database-client-22j7</link>
      <guid>https://dev.to/debba/i-am-building-a-notebook-environment-for-sql-inside-a-database-client-22j7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This post is also available on &lt;a href="https://tabularis.dev/blog/notebooks-sql-analysis-reimagined" rel="noopener noreferrer"&gt;tabularis.dev&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You know the drill. Write a query, get a table. Need to build on that result? Copy-paste into the next query. Need a chart? Export CSV, open a spreadsheet. Want to document the analysis? Paste SQL into a doc and pray nothing drifts.&lt;/p&gt;

&lt;p&gt;I got tired of this loop, so I'm building &lt;strong&gt;Notebooks&lt;/strong&gt; into &lt;a href="https://tabularis.dev" rel="noopener noreferrer"&gt;Tabularis&lt;/a&gt; — a cell-based SQL analysis environment that lives inside the database client. No Jupyter, no Python runtime, no context switching. Just SQL + markdown cells, inline charts, and a few features that make multi-query analysis way less painful.&lt;/p&gt;

&lt;p&gt;It's still in development, but the core works. Here's what it looks like and how it's shaping up.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;A notebook is a sequence of &lt;strong&gt;cells&lt;/strong&gt; — SQL or markdown. SQL cells run against your database and show results inline with the same data grid from the query editor (sorting, filtering, resizable panels). Markdown cells are for documentation between queries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcc5x8ehq4qbbe84eui4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcc5x8ehq4qbbe84eui4.png" alt="Tabularis notebook with SQL cell, data grid results, and inline pie chart" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Cell References via CTEs
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most excited about.&lt;/p&gt;

&lt;p&gt;Any SQL cell can reference another cell's query with &lt;code&gt;{{cell_N}}&lt;/code&gt;. At execution time, it gets resolved as a CTE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Cell 1: Base query&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;

&lt;span class="c1"&gt;-- Cell 3: References Cell 1&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="n"&gt;cell_1&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;cell_1&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
  &lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;cell_1&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No temp tables, no copy-paste. Change the base query, re-run downstream cells, everything stays in sync. You can chain across multiple cells and every intermediate result stays visible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2xdegvdfdo5gxtcf5g59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2xdegvdfdo5gxtcf5g59.png" alt="Two SQL cells with cell reference — Cell 11 filters results from Cell 10 using CTE syntax" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Inline Charts
&lt;/h2&gt;

&lt;p&gt;Any result with 2+ columns and at least one row can be charted — bar, line, or pie — directly in the cell. Pick a label column and value columns, done. Config is saved with the cell.&lt;/p&gt;

&lt;p&gt;Not meant to replace BI tools. It's for when you're exploring and want a quick visual check before writing the next query.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5txfz5f8214gzvxnkef5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5txfz5f8214gzvxnkef5.png" alt="SQL cell with bar chart and label column selector dropdown open showing chart configuration" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy9on5xsv0ffhtuthiyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcy9on5xsv0ffhtuthiyp.png" alt="Pie chart and line chart in separate notebook cells showing chart type variety" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Parameters
&lt;/h2&gt;

&lt;p&gt;Define once, use everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@start_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2024-01-01'&lt;/span&gt;
&lt;span class="vi"&gt;@end_date&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2024-12-31'&lt;/span&gt;
&lt;span class="vi"&gt;@min_amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every SQL cell with &lt;code&gt;@start_date&lt;/code&gt; gets it substituted before execution. Change the value, re-run — all queries pick it up. Great for monthly reports, cohort comparisons, anything where the logic stays the same but inputs change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frq61kpp9sasm6oz2jalq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frq61kpp9sasm6oz2jalq.png" alt="Notebook parameters panel with productCategory and orderStatus variables defined" width="800" height="104"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Parallel Execution
&lt;/h2&gt;

&lt;p&gt;Not every cell depends on the previous one. Mark independent cells with the lightning bolt icon and they run &lt;strong&gt;concurrently&lt;/strong&gt; during "Run All" instead of waiting in sequence. For notebooks with heavy queries against different tables, this makes a real difference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fox4o8psia8dvk4o5zuvd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fox4o8psia8dvk4o5zuvd.png" alt="Two SQL cells with parallel execution lightning bolt icons enabled for concurrent running" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Run All + Stop on Error
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Ctrl+Shift+Enter&lt;/code&gt; runs every SQL cell top to bottom. &lt;strong&gt;Stop on Error&lt;/strong&gt; controls whether it halts at the first failure or keeps going. After execution, a summary card shows succeeded/failed/skipped counts — click a failed cell to jump straight to it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multi-Database in One Notebook
&lt;/h2&gt;

&lt;p&gt;Each SQL cell can target a different database connection. Pull from production PostgreSQL in one cell, compare with your analytics SQLite in the next. Works across MySQL, MariaDB, PostgreSQL, and SQLite.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp97yaeegksu7zaxpuqpr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp97yaeegksu7zaxpuqpr.png" alt="SQL cell with database selector dropdown showing multiple MySQL, PostgreSQL, and SQLite connections" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Execution History
&lt;/h2&gt;

&lt;p&gt;Every cell keeps its last 10 runs — timestamp, duration, row count. You can restore any previous query version. Useful when you've been iterating and need to go back.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1227tdrkigchk05swslw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1227tdrkigchk05swslw.png" alt="Execution history panel showing timestamp, duration, and row count for previous query runs" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  AI Assist
&lt;/h2&gt;

&lt;p&gt;Each SQL cell has &lt;strong&gt;AI&lt;/strong&gt; and &lt;strong&gt;Explain&lt;/strong&gt; buttons — describe what you want, get SQL back, or break down an existing query. There's also an auto-naming feature: click the sparkles icon and AI generates a cell name based on the content. Named cells show up in a &lt;strong&gt;notebook outline&lt;/strong&gt; for navigation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmzzqx94hfof1d0y2tse.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjmzzqx94hfof1d0y2tse.png" alt="SQL cell with AI and Explain buttons, execution history, and collapsed cells overview" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7qm9f3ko34m4llabfhqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7qm9f3ko34m4llabfhqv.png" alt="Notebook outline panel with AI-generated cell names and markdown headings as table of contents" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Organization
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collapse&lt;/strong&gt; cells to show just headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drag and drop&lt;/strong&gt; to reorder&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cell names&lt;/strong&gt; (manual or AI-generated) for identity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown cells&lt;/strong&gt; as section dividers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgy0u3arpwo9qlrsst2aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgy0u3arpwo9qlrsst2aj.png" alt="Notebook with collapsed and expanded SQL and markdown cells showing organization" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Import / Export
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.tabularis-notebook&lt;/code&gt;&lt;/strong&gt; — JSON with cells, parameters, charts. No result data. Share it, import it, connect to a different DB, run it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML export&lt;/strong&gt; — self-contained document with rendered markdown, syntax highlighting, embedded result tables. Dark-themed.&lt;/li&gt;
&lt;li&gt;Individual results export as &lt;strong&gt;CSV&lt;/strong&gt; or &lt;strong&gt;JSON&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's Not Done Yet
&lt;/h2&gt;

&lt;p&gt;Being honest about rough edges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Large notebooks&lt;/strong&gt; (30+ cells) need better virtualization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circular reference detection&lt;/strong&gt; is missing — needs a dependency graph&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chart customization&lt;/strong&gt; is minimal (no axis labels, no color palettes)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard navigation&lt;/strong&gt; between cells is partially implemented&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notebook-level undo/redo&lt;/strong&gt; doesn't exist yet (cell-level works via Monaco)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Build This?
&lt;/h2&gt;

&lt;p&gt;Database clients haven't really evolved beyond "connect, query, see table." Analysis tooling moved forward — Jupyter, Observable, dbt — but the DB client stayed behind.&lt;/p&gt;

&lt;p&gt;Notebooks in Tabularis bet that the database client is the right place for exploratory SQL analysis. You already have the connection, the schema, autocomplete, query history. Cells, charts, references and parameters on top of that means the whole workflow — first query to shareable report — happens without switching tools.&lt;/p&gt;

&lt;p&gt;It's not a Jupyter replacement. No Python, no R. It's purpose-built for SQL, and for the kind of work most people actually do with their database every day — ad-hoc exploration, report building, data validation, performance investigation — that focus is a feature.&lt;/p&gt;

&lt;p&gt;Landing soon. If you want to try it, check out &lt;a href="https://tabularis.dev" rel="noopener noreferrer"&gt;Tabularis&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>One Month Building in Public — Here's What I Shipped</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Thu, 26 Feb 2026 09:32:38 +0000</pubDate>
      <link>https://dev.to/debba/one-month-building-in-public-heres-what-i-shipped-10c3</link>
      <guid>https://dev.to/debba/one-month-building-in-public-heres-what-i-shipped-10c3</guid>
      <description>&lt;p&gt;Tabularis was born on the night of January 25th, 2026. A solo project — one person, a frustration turned into code, a binary pushed to GitHub.&lt;/p&gt;

&lt;p&gt;Today is exactly one month since that first release. And in one month, it stopped being a solo project.&lt;/p&gt;

&lt;p&gt;I believe deeply in what this can become. Not just as a database tool, but as proof that a small team — or even a single person — can build something genuinely useful, genuinely open, and genuinely worth growing. That belief hasn't wavered for a single day. If anything, watching people show up and contribute has made it stronger.&lt;/p&gt;

&lt;p&gt;A lot has happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

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

&lt;p&gt;~&lt;strong&gt;280 stars&lt;/strong&gt;. &lt;strong&gt;5 contributors&lt;/strong&gt;. Around &lt;strong&gt;1,000 downloads&lt;/strong&gt;. Around twenty issues opened by people who actually tried the product, pull requests reviewed, bugs squashed.&lt;/p&gt;

&lt;p&gt;For a one-month-old open source project, that's not nothing — that's a community. And communities don't happen by accident. They happen because people show up.&lt;/p&gt;

&lt;p&gt;So: thank you. Genuinely.&lt;/p&gt;

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

&lt;p&gt;A month ago, Tabularis could connect to PostgreSQL, MySQL, and SQLite. It had a SQL editor, a data grid, and not much else.&lt;/p&gt;

&lt;p&gt;Since then, we've shipped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Plugin System&lt;/strong&gt; — the biggest release of the month. A language-agnostic JSON-RPC protocol that lets anyone build a new database driver without touching the core app. The first plugin, &lt;a href="https://github.com/debba/tabularis-duckdb-plugin" rel="noopener noreferrer"&gt;tabularis-duckdb-plugin&lt;/a&gt;, was ready on day one. This is the feature that changes what Tabularis can become: not a tool that supports three databases, but a platform that can support any database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI Assistant&lt;/strong&gt; — generate SQL from natural language, get explanations for complex queries. Integrated with OpenAI, Anthropic, OpenRouter, and Ollama for those who want to keep everything local.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Visual Query Builder&lt;/strong&gt; — build JOINs and filters without writing a line of SQL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSH Tunneling&lt;/strong&gt; — connect to remote databases through SSH with key and password auth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Split View&lt;/strong&gt; — work with two connections simultaneously, side by side.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Schema Management&lt;/strong&gt; — ER diagrams, inline column editing, table creation wizards.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MCP Server&lt;/strong&gt; — expose your database to Claude and other AI agents via the Model Context Protocol.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;10+ Themes&lt;/strong&gt; — because your tools should feel good to use.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One month. That's the velocity the community made possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Wiki Is Open
&lt;/h3&gt;

&lt;p&gt;Starting today, the &lt;a href="https://tabularis.dev/wiki" rel="noopener noreferrer"&gt;Tabularis Wiki&lt;/a&gt; is live and open for contributions. Every page has an &lt;strong&gt;Edit on GitHub&lt;/strong&gt; link.&lt;/p&gt;

&lt;p&gt;This is intentional. Documentation written only by the maintainers reflects only the maintainers' perspective. If you've figured out a non-obvious workflow, found a gotcha during setup, or have a tip that saved you time — the wiki is the right place for it.&lt;/p&gt;




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

&lt;p&gt;The plugin ecosystem is still young. We want drivers for &lt;strong&gt;ClickHouse, CockroachDB&lt;/strong&gt;, and more. We want the registry to grow. We want the community to build things we haven't thought of yet.&lt;/p&gt;

&lt;p&gt;On the core side: better query history, smarter autocomplete, a more complete ER diagram, and performance improvements are all in flight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/debba/tabularis" rel="noopener noreferrer"&gt;github.com/debba/tabularis&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discord:&lt;/strong&gt; &lt;a href="https://discord.gg/YrZPHAwMSG" rel="noopener noreferrer"&gt;discord.gg/YrZPHAwMSG&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brew install --cask tabularis&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Snap: &lt;code&gt;snap install tabularis&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;AUR: &lt;code&gt;yay -S tabularis-bin&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Tabularis has been useful to you — tell someone. Open source lives and dies by word of mouth.&lt;/p&gt;

&lt;p&gt;Here's to month two.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building Tabularis: A Developer's Database Tool That Doesn't Suck</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Mon, 09 Feb 2026 09:56:35 +0000</pubDate>
      <link>https://dev.to/debba/building-tabularis-a-developers-database-tool-that-doesnt-suck-4k73</link>
      <guid>https://dev.to/debba/building-tabularis-a-developers-database-tool-that-doesnt-suck-4k73</guid>
      <description>&lt;p&gt;I've been managing databases for years, and I'm tired of the same two options: heavyweight enterprise tools that feel like flying a 747 to get groceries, or stripped-down CLI utilities that make even simple tasks a chore. There had to be a middle ground—something fast, clean, and actually enjoyable to use.&lt;/p&gt;

&lt;p&gt;So I built Tabularis, starting from a vibe-coding session with Claude Code, and then it evolved as I really put my mind into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With Database Tools
&lt;/h2&gt;

&lt;p&gt;Like everyone else, I spent years bouncing between phpMyAdmin, MySQL Workbench, DBeaver, and whatever else was popular that quarter. They all had the same issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Too heavy&lt;/strong&gt;: Enterprise tools pack in features I'll never touch, eating RAM and taking forever to start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poor UX&lt;/strong&gt;: Clunky interfaces designed by committee, not for actual daily use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vendor lock-in&lt;/strong&gt;: Tools optimized for one database, awkward for others&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing modern features&lt;/strong&gt;: No AI assistance, no visual query building, no MCP integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real frustration came when I just wanted to quickly check production data or test a query—it shouldn't require launching a 500MB Electron app and waiting 30 seconds for it to connect.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes Tabularis Different
&lt;/h2&gt;

&lt;p&gt;Tabularis is what I actually wanted to use every day. It's built with Tauri (not Electron), so it's genuinely lightweight—the entire app is under 20MB. Starts in under a second. Feels native because it is native.&lt;/p&gt;

&lt;p&gt;But being lightweight doesn't mean being limited. Here's what actually matters:&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Management That Makes Sense
&lt;/h3&gt;

&lt;p&gt;SSH tunneling with automatic readiness detection. No more "is the tunnel up yet?" guessing games. Secure password storage in your system keychain, not some custom encrypted file. Clone connection profiles instead of manually recreating them.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  The Database Explorer I Always Wanted
&lt;/h3&gt;

&lt;p&gt;A proper tree view that shows everything—tables, views, stored procedures, functions, foreign keys, indexes. Not hidden in submenus or separate windows. Right-click context actions for common operations. Want to see the row count? It's one click, not three windows deep.&lt;/p&gt;

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

&lt;p&gt;The ER diagram generator is particularly useful. It's not trying to be a full diagramming tool—it just shows your schema interactively. Pan, zoom, select specific tables. When you're debugging a complex query join, being able to visually trace the relationships saves real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Query Builder (That Actually Works)
&lt;/h3&gt;

&lt;p&gt;Most visual query builders are toys. They work for &lt;code&gt;SELECT * FROM users&lt;/code&gt; and fall apart at the first JOIN. I needed something that could handle real queries—multiple joins, aggregates, WHERE clauses, HAVING filters.&lt;/p&gt;

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

&lt;p&gt;The builder uses ReactFlow for drag-and-drop table connections. Create visual relationships between tables, and it generates proper JOIN syntax. Add filters, aggregates, sorting—all visually—and watch the SQL update in real-time. When you need to switch to the SQL editor, you're not starting from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Integration (Optional, But Useful)
&lt;/h3&gt;

&lt;p&gt;This is where it gets interesting. I didn't want to force cloud AI on anyone—privacy matters—so Tabularis supports multiple AI providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI, Anthropic, OpenRouter for cloud options&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ollama for completely local inference&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;OpenAI-compatible APIs (Groq, Perplexity, LocalAI, etc.)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The AI features are straightforward: text-to-SQL generation and query explanation. Type "show me users who signed up last week" and get working SQL. Or paste a complex query and get a plain-English explanation of what it's doing.&lt;/p&gt;

&lt;p&gt;But here's the part I'm most excited about: &lt;strong&gt;MCP Server support&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MCP Server: Exposing Databases to AI Agents
&lt;/h2&gt;

&lt;p&gt;Tabularis includes a built-in Model Context Protocol (MCP) server. Run &lt;code&gt;tabularis --mcp&lt;/code&gt; and your database connections become available to any MCP-compatible AI agent—Claude Desktop, Cursor, or custom tools.&lt;/p&gt;

&lt;p&gt;This means AI agents can query your databases directly. Not through screenshots or copy-paste, but actual programmatic access. I've been using it with Claude Desktop to analyze production data, generate reports, and debug queries—all without leaving my chat window.&lt;/p&gt;

&lt;p&gt;The architecture is simple: Tabularis runs as an MCP server, exposes your saved connections through a standard protocol, and handles authentication and query execution. The AI agent just sees a set of available databases and can query them like any other data source.&lt;/p&gt;

&lt;p&gt;It's surprisingly powerful. I recently had Claude help me optimize a slow query by letting it inspect the actual table structures, existing indexes, and query execution patterns—all through MCP. It generated three optimization strategies, I tested them, and cut query time by 60%. That workflow wasn't possible with traditional database tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building It All
&lt;/h3&gt;

&lt;p&gt;I started Tabularis about six months ago, mostly as a weekend project to scratch my own itch. The tech stack choices were deliberate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tauri v2&lt;/strong&gt; instead of Electron (smaller bundle, better performance, native feel)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React 19&lt;/strong&gt; with TypeScript (familiar, fast development)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS v4&lt;/strong&gt; (rapid UI iteration without CSS bloat)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust backend&lt;/strong&gt; with SQLx (type-safe queries, excellent performance)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The Rust backend handles all database operations through SQLx, which provides compile-time verification of SQL queries. No more runtime surprises about typos in column names. SSH tunneling is handled with native Rust libraries, not shelling out to external processes.&lt;/p&gt;

&lt;p&gt;One interesting challenge was supporting multiple database types (MySQL, PostgreSQL, SQLite) with a unified interface. SQLx helps here with its database-agnostic query builder, but each database has quirks—MySQL's information_schema differs from PostgreSQL's pg_catalog, and SQLite is its own thing entirely.&lt;/p&gt;

&lt;p&gt;The solution was a trait-based provider system in Rust. Each database implements a common &lt;code&gt;DatabaseProvider&lt;/code&gt; trait that defines operations like "fetch tables," "execute query," "get foreign keys." The frontend doesn't care which database it's talking to—it just calls methods on the trait.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Using Tabularis
&lt;/h2&gt;

&lt;p&gt;Getting started is intentionally simple:&lt;/p&gt;

&lt;h3&gt;
  
  
  macOS (Homebrew)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap debba/tabularis
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; tabularis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Arch Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yay &lt;span class="nt"&gt;-S&lt;/span&gt; tabularis-bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Everyone Else
&lt;/h3&gt;

&lt;p&gt;Download from &lt;a href="https://github.com/debba/tabularis/releases" rel="noopener noreferrer"&gt;releases&lt;/a&gt; for Windows, Linux (AppImage), or macOS (DMG).&lt;/p&gt;

&lt;p&gt;Connect to your database, start exploring. The interface is designed to be obvious—if you've used any database tool before, you'll figure it out in 30 seconds.&lt;/p&gt;

&lt;p&gt;All configuration lives in &lt;code&gt;~/.config/tabularis/&lt;/code&gt; (or your OS equivalent)—connections, saved queries, themes, settings. Plain JSON files, easy to back up or edit manually if needed.&lt;/p&gt;

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

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

&lt;p&gt;Tabularis is fully functional today, but there's more to build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Better PostgreSQL &amp;amp; SQLite support&lt;/strong&gt;: MySQL is solid, but Postgres and SQLite need more love&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query history&lt;/strong&gt;: Track and revisit past queries across sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance monitoring&lt;/strong&gt;: Built-in query profiling and execution plan visualization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code is on GitHub, Apache 2.0 licensed. It's built by a developer, for developers. No telemetry, no accounts, no subscriptions. Just a tool that works.&lt;/p&gt;




&lt;p&gt;If you're tired of database tools that feel like they're fighting you instead of helping you, give Tabularis a try. It's what I wish I had years ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download&lt;/strong&gt;: &lt;a href="https://tabularis.dev" rel="noopener noreferrer"&gt;tabularis.dev&lt;/a&gt; | &lt;strong&gt;Source&lt;/strong&gt;: &lt;a href="https://github.com/debba/tabularis" rel="noopener noreferrer"&gt;github.com/debba/tabularis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;tabularis --mcp&lt;/code&gt; to enable MCP server mode and start connecting your databases to AI agents.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>database</category>
      <category>rust</category>
      <category>ai</category>
    </item>
    <item>
      <title>I was tired of database tools — so I started building my own</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Tue, 27 Jan 2026 12:04:22 +0000</pubDate>
      <link>https://dev.to/debba/i-was-tired-of-database-tools-so-i-started-building-my-own-3kia</link>
      <guid>https://dev.to/debba/i-was-tired-of-database-tools-so-i-started-building-my-own-3kia</guid>
      <description>&lt;p&gt;Repo url: &lt;a href="https://github.com/debba/debba.sql" rel="noopener noreferrer"&gt;https://github.com/debba/debba.sql&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At some point, I realized I was spending more energy &lt;strong&gt;fighting my database tools&lt;/strong&gt; than actually working with databases.&lt;/p&gt;

&lt;p&gt;Most of the popular DB managers are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;closed source
&lt;/li&gt;
&lt;li&gt;heavy as hell
&lt;/li&gt;
&lt;li&gt;UX-wise… questionable
&lt;/li&gt;
&lt;li&gt;clearly not built with Linux developers in mind
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And yes, some of them &lt;em&gt;look&lt;/em&gt; nice (👀 DataGrip), but they feel like bringing a tank to open a bottle of water.&lt;/p&gt;

&lt;p&gt;So one night, instead of complaining on Twitter or Discord, I did the most dangerous thing a developer can do:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I started vibe coding my own DB manager.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  It started as a hack (literally)
&lt;/h2&gt;

&lt;p&gt;This wasn’t a “vision”, or a “startup idea”.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;late at night
&lt;/li&gt;
&lt;li&gt;Rust open in my editor
&lt;/li&gt;
&lt;li&gt;Tauri + React on the side
&lt;/li&gt;
&lt;li&gt;a strong feeling of &lt;em&gt;“how hard can it be?”&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I just wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;something fast
&lt;/li&gt;
&lt;li&gt;something local
&lt;/li&gt;
&lt;li&gt;something that doesn’t feel like a bloated enterprise product
&lt;/li&gt;
&lt;li&gt;something I can actually understand end-to-end
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No roadmap.&lt;br&gt;&lt;br&gt;
No design doc.&lt;br&gt;&lt;br&gt;
Just hacking.&lt;/p&gt;




&lt;h2&gt;
  
  
  From vibe coding to “wait, this might actually work”
&lt;/h2&gt;

&lt;p&gt;After the first hacky prototype, something unexpected happened.&lt;/p&gt;

&lt;p&gt;I kept adding things.&lt;/p&gt;

&lt;p&gt;Slowly.&lt;br&gt;&lt;br&gt;
Incrementally.&lt;br&gt;&lt;br&gt;
Scratching my own itch.&lt;/p&gt;

&lt;p&gt;What started as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Let me just connect to a DB”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;became:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multi-database support (SQLite, Postgres, MySQL…)
&lt;/li&gt;
&lt;li&gt;a cleaner mental model
&lt;/li&gt;
&lt;li&gt;better performance than I expected
&lt;/li&gt;
&lt;li&gt;an app that feels &lt;em&gt;mine&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point I thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ok, either I stop now… or I open-source it and see what happens.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  debba.sql (name pending 😅)
&lt;/h2&gt;

&lt;p&gt;The project is currently called &lt;strong&gt;debba.sql&lt;/strong&gt; — &lt;em&gt;debba&lt;/em&gt; is my nickname and, conveniently, contains &lt;code&gt;db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Is the name final?&lt;br&gt;&lt;br&gt;
Probably not.&lt;/p&gt;

&lt;p&gt;Is the project done?&lt;br&gt;&lt;br&gt;
Absolutely not.&lt;/p&gt;

&lt;p&gt;Right now it’s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧩 a &lt;strong&gt;side project&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🦀 written in &lt;strong&gt;Rust&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🖥️ wrapped with &lt;strong&gt;Tauri&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;⚛️ frontend in &lt;strong&gt;React&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🐧 built with Linux devs in mind
&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;open source&lt;/strong&gt;, repo public
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No company.&lt;br&gt;&lt;br&gt;
No monetization (for now).&lt;br&gt;&lt;br&gt;
Just a tool I actually want to use.&lt;/p&gt;




&lt;h2&gt;
  
  
  This is not a manifesto (yet)
&lt;/h2&gt;

&lt;p&gt;I’m not claiming this will “replace” anything.&lt;br&gt;&lt;br&gt;
I’m not claiming it’s better than your favorite tool.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;am&lt;/em&gt; saying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dev tools should feel empowering
&lt;/li&gt;
&lt;li&gt;open source matters
&lt;/li&gt;
&lt;li&gt;UX is not optional
&lt;/li&gt;
&lt;li&gt;Linux users deserve first-class experiences
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And sometimes, the best way to stop complaining…&lt;br&gt;&lt;br&gt;
is to build.&lt;/p&gt;




&lt;h2&gt;
  
  
  I want your feedback
&lt;/h2&gt;

&lt;p&gt;This is the part where I shut up and listen.&lt;/p&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;have strong opinions about DB tools
&lt;/li&gt;
&lt;li&gt;build dev tools yourself
&lt;/li&gt;
&lt;li&gt;care about open source UX
&lt;/li&gt;
&lt;li&gt;are tired of bloated software
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’d love your feedback.&lt;br&gt;&lt;br&gt;
Issues, comments, brutal honesty — all welcome.&lt;/p&gt;

&lt;p&gt;This started as vibe coding at night.&lt;br&gt;&lt;br&gt;
Let’s see where it goes.&lt;/p&gt;

&lt;p&gt;🧪🔥&lt;/p&gt;

&lt;p&gt;Repo url: &lt;a href="https://github.com/debba/debba.sql" rel="noopener noreferrer"&gt;https://github.com/debba/debba.sql&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>rust</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>From VS Code to Zed: building a FreeMarker extension because I needed one</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Thu, 15 Jan 2026 12:37:57 +0000</pubDate>
      <link>https://dev.to/debba/from-vs-code-to-zed-building-a-freemarker-extension-because-i-needed-one-4hm9</link>
      <guid>https://dev.to/debba/from-vs-code-to-zed-building-a-freemarker-extension-because-i-needed-one-4hm9</guid>
      <description>&lt;h1&gt;
  
  
  From VS Code to Zed: building a FreeMarker extension because I needed one
&lt;/h1&gt;

&lt;p&gt;A few months ago, I switched from VS Code to &lt;strong&gt;Zed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not because VS Code is bad — it’s still an amazing editor — but because it slowly became… heavy.&lt;br&gt;&lt;br&gt;
My setup had turned into a Frankenstein monster of freemium extensions, background processes, upsells, and “just one more helper” that somehow made everything slower.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpy377wa75co87sk76hfo.gif" 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%2Fpy377wa75co87sk76hfo.gif" alt="My VS Code setup: I feel thin, sort of stretched, like butter scraped over too much bread." width="360" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wanted something:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fast
&lt;/li&gt;
&lt;li&gt;open-source
&lt;/li&gt;
&lt;li&gt;opinionated
&lt;/li&gt;
&lt;li&gt;boring in the best possible way
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zed checked all the boxes.&lt;/p&gt;

&lt;p&gt;Until I had to start working with &lt;strong&gt;FreeMarker&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  FreeMarker is still very much alive
&lt;/h2&gt;

&lt;p&gt;If you work in Java or enterprise environments, you already know this.&lt;/p&gt;

&lt;p&gt;FreeMarker isn’t trendy.&lt;br&gt;&lt;br&gt;
It’s not on Hacker News every week.&lt;br&gt;&lt;br&gt;
But it’s &lt;strong&gt;everywhere&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In my case, I’m using it in a project that integrates &lt;strong&gt;Keycloak&lt;/strong&gt;, where FreeMarker templates are still a core part of the customization flow.&lt;/p&gt;

&lt;p&gt;So yes — FreeMarker is old.&lt;br&gt;&lt;br&gt;
And yes — it’s still critical.&lt;/p&gt;

&lt;p&gt;Which made this part a bit painful:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Zed had no FreeMarker support.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No syntax highlighting.&lt;br&gt;&lt;br&gt;
No understanding of directives.&lt;br&gt;&lt;br&gt;
Nothing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw65xsrry74fshtr9bb7p.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%2Fw65xsrry74fshtr9bb7p.jpg" alt="Fine, I’ll do it myself" width="648" height="385"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The “fine, I’ll do it myself” moment
&lt;/h2&gt;

&lt;p&gt;Zed is fast enough that once you get used to it, going back feels… wrong.&lt;/p&gt;

&lt;p&gt;So instead of switching editors again, I thought:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How hard can it be to write a FreeMarker extension?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(Last words before opening a tree-sitter grammar.)&lt;/p&gt;

&lt;p&gt;I already knew that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zed uses &lt;strong&gt;tree-sitter&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Syntax highlighting is grammar-driven&lt;/li&gt;
&lt;li&gt;Extensions are lean and explicit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also had a starting point:&lt;br&gt;&lt;br&gt;
a &lt;strong&gt;FreeMarker extension for VS Code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The idea was simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reuse what I could&lt;/li&gt;
&lt;li&gt;adapt what I had to&lt;/li&gt;
&lt;li&gt;learn the Zed extension model along the way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With some help from &lt;strong&gt;vibe-coding&lt;/strong&gt; and a lot of trial &amp;amp; error, I started porting it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The actual journey (a.k.a. tree-sitter reality check)
&lt;/h2&gt;

&lt;p&gt;Some things were easier than expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zed’s extension model is refreshingly clean&lt;/li&gt;
&lt;li&gt;Tree-sitter forces you to think properly about structure&lt;/li&gt;
&lt;li&gt;No magic, no hidden layers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some things were… not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FreeMarker syntax is flexible in &lt;em&gt;annoying&lt;/em&gt; ways&lt;/li&gt;
&lt;li&gt;Directives, interpolations, nested expressions&lt;/li&gt;
&lt;li&gt;Edge cases you only notice after breaking everything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Porting from VS Code wasn’t a copy–paste job.&lt;br&gt;&lt;br&gt;
It was more like translating between two different mental models.&lt;/p&gt;

&lt;p&gt;But honestly?&lt;br&gt;&lt;br&gt;
That’s what made it fun.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9voqy2s8etwue9cwelw.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%2Fs9voqy2s8etwue9cwelw.jpg" alt="The actual journey" width="666" height="500"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The result: early, but usable
&lt;/h2&gt;

&lt;p&gt;The extension is live here:&lt;br&gt;&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://github.com/debba/zed-freemarker" rel="noopener noreferrer"&gt;https://github.com/debba/zed-freemarker&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What it supports today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FreeMarker syntax highlighting&lt;/li&gt;
&lt;li&gt;Directives&lt;/li&gt;
&lt;li&gt;Interpolations&lt;/li&gt;
&lt;li&gt;A solid base for further improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is it perfect? No.&lt;br&gt;&lt;br&gt;
Is it production-grade? Not yet.&lt;br&gt;&lt;br&gt;
Is it &lt;strong&gt;good enough to work daily without hating your editor&lt;/strong&gt;? Absolutely.&lt;/p&gt;

&lt;p&gt;And for an editor like Zed, that already feels like a win.&lt;/p&gt;




&lt;h2&gt;
  
  
  Thoughts on Zed and niche tooling
&lt;/h2&gt;

&lt;p&gt;Zed feels like an editor for people who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;enjoy understanding how their tools work&lt;/li&gt;
&lt;li&gt;prefer fewer abstractions&lt;/li&gt;
&lt;li&gt;don’t mind building missing pieces themselves&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing this extension reminded me of something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Open source doesn’t move forward only with big features —&lt;br&gt;&lt;br&gt;
it also grows through small, boring, niche tools that solve real problems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;FreeMarker isn’t cool.&lt;br&gt;&lt;br&gt;
But someone still has to maintain it.&lt;/p&gt;

&lt;h2&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%2Fdro8l7o289ws7rnjhv34.jpg" alt="The actual journey" width="612" height="408"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;Possible next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better grammar coverage&lt;/li&gt;
&lt;li&gt;error handling&lt;/li&gt;
&lt;li&gt;maybe an LSP in the future (no promises)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use FreeMarker
&lt;/li&gt;
&lt;li&gt;use Zed
&lt;/li&gt;
&lt;li&gt;enjoy hacking on developer tools
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback, issues, and PRs are more than welcome.&lt;/p&gt;

&lt;p&gt;Sometimes the best extensions start with a simple need:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“I just want my editor to understand this file.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that’s exactly how this one was born 🚀&lt;/p&gt;

</description>
      <category>tooling</category>
      <category>software</category>
      <category>coding</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building AuthPress: From Simple Telegram 2FA to Extensible WordPress Security Platform</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Tue, 16 Sep 2025 12:50:53 +0000</pubDate>
      <link>https://dev.to/debba/building-authpress-from-simple-telegram-2fa-to-extensible-wordpress-security-platform-258h</link>
      <guid>https://dev.to/debba/building-authpress-from-simple-telegram-2fa-to-extensible-wordpress-security-platform-258h</guid>
      <description>&lt;p&gt;&lt;em&gt;How I evolved a single-provider WordPress 2FA plugin into a comprehensive, developer-friendly authentication system&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem 🔐
&lt;/h2&gt;

&lt;p&gt;WordPress powers 43% of the web, but most sites still rely on password-only authentication. While there are 2FA plugins available, they're often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited to specific providers&lt;/li&gt;
&lt;li&gt;Hard to extend or customize&lt;/li&gt;
&lt;li&gt;Not developer-friendly&lt;/li&gt;
&lt;li&gt;Missing modern authentication methods&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Journey 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AuthPress&lt;/strong&gt; started as a simple idea: "What if I could get my WordPress 2FA codes via Telegram?" Three years and multiple iterations later, it's become a comprehensive authentication platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Version 4.0: The Extensible Platform
&lt;/h3&gt;

&lt;p&gt;Now it supports multiple providers through a clean architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Modern extensible system&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Abstract_Provider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;send_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;verify_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;render_user_settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Register custom providers&lt;/span&gt;
&lt;span class="nf"&gt;add_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'authpress_register_providers'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$providers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$providers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'my_sms'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'MyPlugin\\SMS_Provider'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$providers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'push_notification'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'MyPlugin\\Push_Provider'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$providers&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;
  
  
  Technical Architecture 🏗️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Provider Support&lt;/strong&gt;: Telegram, Email, TOTP, Recovery Codes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible API&lt;/strong&gt;: Clean interfaces for custom providers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional Logging&lt;/strong&gt;: WordPress-native admin tables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security First&lt;/strong&gt;: Rate limiting, encrypted storage, brute force protection&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Provider System
&lt;/h3&gt;

&lt;p&gt;Each authentication method is a provider class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Telegram_Provider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Abstract_Provider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;send_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Telegram API integration&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;send_telegram_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;verify_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$submitted_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Validate against stored code&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;validate_stored_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$submitted_code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;render_user_settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// User configuration interface&lt;/span&gt;
        &lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="s1"&gt;'templates/telegram-settings.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Developer Experience 👨‍💻
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating Custom Providers
&lt;/h3&gt;

&lt;p&gt;Want SMS via Twilio? Here's how simple it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Twilio_SMS_Provider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Abstract_Provider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$twilio_client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;twilio_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Twilio\Rest\Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;send_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$phone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_user_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;twilio_client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'from'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'+1234567890'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Your WordPress login code: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="si"&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;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;verify_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;verify_stored_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WordPress Integration
&lt;/h3&gt;

&lt;p&gt;Follows WordPress best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses hooks and filters extensively&lt;/li&gt;
&lt;li&gt;Proper nonce verification&lt;/li&gt;
&lt;li&gt;WP_List_Table for admin interfaces&lt;/li&gt;
&lt;li&gt;Standard WordPress coding standards&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next? 🔮
&lt;/h2&gt;

&lt;p&gt;Working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Passkey/WebAuthn integration&lt;/strong&gt; (already in beta)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware token support&lt;/strong&gt; (YubiKey, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Open Source &amp;amp; Community 💝
&lt;/h2&gt;

&lt;p&gt;AuthPress is GPL-licensed and available on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WordPress.org&lt;/strong&gt;: &lt;a href="https://wordpress.org/plugins/two-factor-login-telegram/" rel="noopener noreferrer"&gt;Official plugin directory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/dueclic/authpress" rel="noopener noreferrer"&gt;dueclic/authpress&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Contributing
&lt;/h3&gt;

&lt;p&gt;We welcome contributions! Especially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New provider implementations&lt;/li&gt;
&lt;li&gt;Security audits&lt;/li&gt;
&lt;li&gt;Documentation improvements&lt;/li&gt;
&lt;li&gt;Translation updates&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons Learned 📚
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start simple, architect for growth&lt;/strong&gt; - The extensible design saved massive refactoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security can't be an afterthought&lt;/strong&gt; - Built-in from day one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer experience matters&lt;/strong&gt; - Clean APIs lead to better ecosystem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WordPress standards exist for a reason&lt;/strong&gt; - Following them made everything easier&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;Try AuthPress&lt;/strong&gt; on your WordPress site and let me know what custom providers you'd build! The extensibility system makes it possible to integrate with virtually any authentication service.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What 2FA method would you want to see next? Drop your ideas in the comments! 👇&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  WordPress #2FA #Security #PHP #OpenSource
&lt;/h1&gt;

</description>
      <category>php</category>
      <category>showdev</category>
      <category>wordpress</category>
      <category>security</category>
    </item>
    <item>
      <title>Building rewindtty – a terminal session recorder in C with PTY support</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Wed, 30 Jul 2025 19:04:21 +0000</pubDate>
      <link>https://dev.to/debba/building-rewindtty-a-terminal-session-recorder-in-c-with-pty-support-5gik</link>
      <guid>https://dev.to/debba/building-rewindtty-a-terminal-session-recorder-in-c-with-pty-support-5gik</guid>
      <description>&lt;p&gt;Have you ever needed to record what happens inside a terminal — with timing, full output, and possibly even ANSI sequences?&lt;/p&gt;

&lt;p&gt;That’s what I’m building with &lt;a href="https://github.com/debba/rewindtty" rel="noopener noreferrer"&gt;rewindtty&lt;/a&gt;, a simple yet powerful terminal session recorder written in pure C. It spawns CLI commands inside a pseudo-terminal (PTY), and logs the output in structured JSON format with timestamps.&lt;/p&gt;

&lt;p&gt;✅ It already records:&lt;br&gt;
• stdout and stderr&lt;br&gt;
• command execution and timestamps&lt;br&gt;
• logs you can replay or analyze later&lt;/p&gt;

&lt;p&gt;🔧 I just opened a feature request to support recording ANSI escape sequences, so that full-screen TUI programs like vim, htop, and others can be captured and replayed accurately.&lt;/p&gt;

&lt;p&gt;🎯 Use cases:&lt;br&gt;
• Debugging interactive programs&lt;br&gt;
• Sharing reproducible CLI workflows&lt;br&gt;
• Building in-browser replayers (with e.g. xterm.js)&lt;/p&gt;

&lt;p&gt;🧠 I’d love your feedback, especially if you’ve worked with PTY APIs in C, terminal emulation, ANSI sequence parsing or rendering&lt;/p&gt;

</description>
      <category>c</category>
      <category>terminal</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built rewindtty: a C tool to record and replay terminal sessions as JSON logs (like a black box for your CLI)</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Mon, 28 Jul 2025 16:25:44 +0000</pubDate>
      <link>https://dev.to/debba/i-built-rewindtty-a-c-tool-to-record-and-replay-terminal-sessions-as-json-logs-like-a-black-box-2boo</link>
      <guid>https://dev.to/debba/i-built-rewindtty-a-c-tool-to-record-and-replay-terminal-sessions-as-json-logs-like-a-black-box-2boo</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%2Fmk3ihz4mtkbsrbdyohdz.gif" 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%2Fmk3ihz4mtkbsrbdyohdz.gif" alt="rewindtty" width="2558" height="728"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hey folks! 👋&lt;/p&gt;

&lt;p&gt;Over the past few weeks, I’ve been working on a little tool in C called &lt;a href="https://github.com/debba/rewindtty" rel="noopener noreferrer"&gt;rewindtty&lt;/a&gt; — it's like a black box for your terminal.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;rewindtty record&lt;/code&gt;: Launches a shell (or any program), records all your inputs and outputs to a JSON log.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rewindtty replay&lt;/code&gt;: Replays that session step-by-step in a terminal-like environment.&lt;/p&gt;

&lt;p&gt;Here’s an example of what the recorded JSON looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-07-28T14:01:03Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ls -la"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"total 4&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;-rw-r--r-- file.txt&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stderr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;I wanted a dead-simple way to:&lt;/p&gt;

&lt;p&gt;-Capture what really happened in a CLI session, without overengineering.&lt;br&gt;
-Debug or share reproducible steps with colleagues (like "here’s exactly what I typed and what I got").&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a foundation for visual or animated terminal playback (think GIFs or asciinema-style exports).&lt;/li&gt;
&lt;li&gt;How it works&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Under the hood:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uses fork() to launch a subprocess in a pseudo-terminal.&lt;/li&gt;
&lt;li&gt;Intercepts both stdin and stdout/stderr, recording them with precise timestamps.&lt;/li&gt;
&lt;li&gt;Clean JSON output makes it easy to transform, diff, analyze, or visualize.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cool ideas I’m playing with next:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;--timing flag to replay with realistic delays&lt;/li&gt;
&lt;li&gt;Export to .cast format (asciinema)&lt;/li&gt;
&lt;li&gt;GIF or SVG animations using svg-term&lt;/li&gt;
&lt;li&gt;Auto-record hooks for Git or critical scripts&lt;/li&gt;
&lt;li&gt;Comparing two sessions for debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why not use asciinema?
&lt;/h2&gt;

&lt;p&gt;Great question! I love asciinema, but: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I wanted full control over the data format (and stderr!)&lt;/li&gt;
&lt;li&gt;JSON logs are easier to post-process for my use case&lt;/li&gt;
&lt;li&gt;I wanted to build it in C for fun and for low-level control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/debba/rewindtty" rel="noopener noreferrer"&gt;Project URL&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>DBSeeker - MySQL Search Script (Alpha) : Search Across All Databases!</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Wed, 12 Mar 2025 06:39:15 +0000</pubDate>
      <link>https://dev.to/debba/dbseeker-mysql-search-script-alpha-search-across-all-databases-3na8</link>
      <guid>https://dev.to/debba/dbseeker-mysql-search-script-alpha-search-across-all-databases-3na8</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/dueclic/dbseeker" rel="noopener noreferrer"&gt;Project URL&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve built a tiny script that lets you search for a string across every database on a MySQL server. It outputs results in a table format, showing which database and table contain the term, how many rows were found, and the search time.&lt;/p&gt;

&lt;p&gt;It’s still in alpha, so expect some bugs and missing features. Feedback and suggestions are welcome!&lt;/p&gt;

&lt;p&gt;Would you find this useful? Let me know what you think! 🚀&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
      <category>database</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Angular 18.1: Template Local Variables with @let</title>
      <dc:creator>Andrea Debernardi</dc:creator>
      <pubDate>Thu, 11 Jul 2024 20:36:56 +0000</pubDate>
      <link>https://dev.to/debba/angular-181-template-local-variables-with-let-3mh9</link>
      <guid>https://dev.to/debba/angular-181-template-local-variables-with-let-3mh9</guid>
      <description>&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Syntax&lt;/strong&gt;: let variableName = expression;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope&lt;/strong&gt;: The variable is only available within the HTML element or block where it's declared.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Common scenarios&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Reduce repetition of complex expressions.&lt;/li&gt;
&lt;li&gt;Better handle type narrowing.&lt;/li&gt;
&lt;li&gt;Define complex styling options.&lt;/li&gt;
&lt;li&gt;Improve template readability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use let to minimize repetition.&lt;/li&gt;
&lt;li&gt;Use let to improve type narrowing.&lt;/li&gt;
&lt;li&gt;Use let to define complex styling options.&lt;/li&gt;
&lt;li&gt;Carefully consider using let for calculations or business rules.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The let declaration is a welcome addition that simplifies variable management in templates and improves code readability. It's particularly useful for reducing repetition and defining complex styling options. However, it's important to carefully consider using let for calculations or business rules, as it could make the code harder to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official Angular documentation on the let declaration: &lt;a href="https://blog.angular.dev/introducing-let-in-angular-686f9f383f0f?gi=63f5b3e52822" rel="noopener noreferrer"&gt;https://blog.angular.dev/introducing-let-in-angular-686f9f383f0f?gi=63f5b3e52822&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you plan to use the let declaration in your Angular projects? &lt;/p&gt;

&lt;p&gt;Leave a comment below and share your thoughts!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>angular</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
