<?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: Antony Nyagah</title>
    <description>The latest articles on DEV Community by Antony Nyagah (@nyagah).</description>
    <link>https://dev.to/nyagah</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F987887%2F1090cb66-d4da-4d33-bb38-16b038d053d0.jpg</url>
      <title>DEV Community: Antony Nyagah</title>
      <link>https://dev.to/nyagah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nyagah"/>
    <language>en</language>
    <item>
      <title>I Tried to Learn RAG and Got Stuck on API Costs. Turns Out My CPU Could Do the Expensive Bit.</title>
      <dc:creator>Antony Nyagah</dc:creator>
      <pubDate>Mon, 14 Sep 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/nyagah/i-tried-to-learn-rag-and-got-stuck-on-api-costs-turns-out-my-cpu-could-do-the-expensive-bit-1o6h</link>
      <guid>https://dev.to/nyagah/i-tried-to-learn-rag-and-got-stuck-on-api-costs-turns-out-my-cpu-could-do-the-expensive-bit-1o6h</guid>
      <description>&lt;p&gt;A few months ago, I started building a &lt;a href="https://en.wikipedia.org/wiki/Retrieval-augmented_generation" rel="noopener noreferrer"&gt;Retrieval-Augmented Generation&lt;/a&gt; application because I wanted to understand what was actually happening underneath all the buzzwords. The project I built was appropriately named &lt;a href="https://github.com/tony-nyagah/simple_rag" rel="noopener noreferrer"&gt;simple_rag&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea was simple enough: upload a PDF, ask questions about it, and have an LLM answer using information from the document. I got it working. Then I mostly abandoned it.&lt;/p&gt;

&lt;p&gt;The thing I couldn't figure out how to handle cleanly was running the embedding model locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  I accidentally made a simple project expensive
&lt;/h2&gt;

&lt;p&gt;My original implementation used Gemini for both embeddings and generation. Later, I switched it to Mistral. Both worked, but the more I played with the project, the more I disliked one part of the architecture: every time I wanted to turn some text into embeddings, I was calling somebody else's API, with its own rate limits and its own costs.&lt;/p&gt;

&lt;p&gt;That meant another API key, another service to depend on, another rate limit to think about, and potentially another bill. For a production application where the trade-off makes sense, fine. For a tiny side project whose entire purpose was basically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Antony would like to understand RAG.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...it felt ridiculous.&lt;/p&gt;

&lt;p&gt;Embeddings are fundamental to how this implementation works. When you upload a document, the text gets split into chunks, and each chunk gets converted into an embedding: a numerical representation of its meaning. That embedding gets compared against the question's embedding, and whichever chunks are most semantically similar get sent to the LLM as context. That is basically the retrieval part of Retrieval-Augmented Generation.&lt;/p&gt;

&lt;p&gt;So if creating embeddings depended on an API I didn't want to keep paying for, the whole experiment got a lot less interesting. The repository sat there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then I discovered I was overcomplicating the problem
&lt;/h2&gt;

&lt;p&gt;Recently I came back to the project and discovered &lt;a href="https://github.com/qdrant/fastembed" rel="noopener noreferrer"&gt;fastembed&lt;/a&gt;, and had one of those slightly embarrassing engineering moments where you realize the problem that made you abandon something months ago never actually needed the solution you'd assumed it needed.&lt;/p&gt;

&lt;p&gt;I could generate the embeddings locally, on my CPU, without touching an embedding API, a GPU, or a heavy PyTorch install, and without a per-embedding bill.&lt;/p&gt;

&lt;p&gt;I'm currently using &lt;code&gt;BAAI/bge-small-en-v1.5&lt;/code&gt; through FastEmbed. It runs on ONNX Runtime and is small enough that my completely ordinary laptop handles it without breaking a sweat.&lt;/p&gt;

&lt;p&gt;That changed the architecture quite a bit. The current flow is basically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PDF / EPUB
    ↓
Extract text
    ↓
Split text into chunks
    ↓
Generate embeddings locally on my CPU
    ↓
Store the vectors in memory
    ↓
User asks question
    ↓
Embed question locally
    ↓
Compare it with document embeddings
    ↓
Retrieve the most relevant chunks
    ↓
Send those chunks + question to the LLM
    ↓
Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;That's it. And weirdly, stripping things away helped me understand RAG much better than adding more AI tooling ever did.&lt;/p&gt;

&lt;h2&gt;
  
  
  I don't even have a vector database
&lt;/h2&gt;

&lt;p&gt;This was another thing I had mentally associated with RAG.&lt;/p&gt;

&lt;p&gt;Embeddings mean vectors. Vectors mean vector databases. Therefore RAG means I need Pinecone, Qdrant, Chroma, pgvector, or something similar.&lt;/p&gt;

&lt;p&gt;Except... not necessarily. My application currently stores embeddings as plain Python data and uses NumPy to calculate cosine similarity. For every question, it compares the question's vector against the chunk vectors, sorts by similarity, and grabs the best matches.&lt;/p&gt;

&lt;p&gt;Is that how I'd build a system with millions of documents? Absolutely not. Is it enough for a PDF, an EPUB, or a few hundred pages while I'm trying to understand retrieval? Absolutely.&lt;/p&gt;

&lt;p&gt;That distinction has become increasingly important to me when learning new technology. There's a huge difference between asking what do I need to understand this, and what would I need to operate this at serious production scale. The internet has a habit of giving you the second architecture while you're still trying to answer the first question.&lt;/p&gt;

&lt;h2&gt;
  
  
  The LLM is now the only remote part
&lt;/h2&gt;

&lt;p&gt;I still needed a model to generate the final answer, and this is where I found &lt;a href="https://groq.com/" rel="noopener noreferrer"&gt;Groq&lt;/a&gt; particularly interesting.&lt;/p&gt;

&lt;p&gt;For my current side-project level of usage, their free tier is enough to experiment with. I created an API key without even adding a credit card, pointed the OpenAI-compatible client at Groq, and that was basically it. I'm currently using &lt;code&gt;openai/gpt-oss-120b&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So now the parts have a much cleaner separation.&lt;/p&gt;

&lt;p&gt;My machine handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extracting the document text.&lt;/li&gt;
&lt;li&gt;Chunking it.&lt;/li&gt;
&lt;li&gt;Creating embeddings.&lt;/li&gt;
&lt;li&gt;Storing those embeddings.&lt;/li&gt;
&lt;li&gt;Embedding the question.&lt;/li&gt;
&lt;li&gt;Retrieving the relevant chunks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Taking the question plus retrieved context.&lt;/li&gt;
&lt;li&gt;Producing a useful, human-readable answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That separation made another thing click for me: RAG isn't really about making the LLM know your data, since the model doesn't suddenly learn my PDF. I'm building a retrieval system that finds useful information first, then handing that information to the model at generation time.&lt;/p&gt;

&lt;p&gt;The retrieval is doing a lot more of the work than I originally appreciated.&lt;/p&gt;

&lt;h2&gt;
  
  
  I wanted the implementation to stay boring
&lt;/h2&gt;

&lt;p&gt;The core RAG logic is only a few hundred lines of Python. That's deliberate.&lt;/p&gt;

&lt;p&gt;There's a FastAPI API around it and a small browser UI, plus a CLI because apparently I cannot make a Python project without eventually wanting to run it from the terminal. But the actual interesting bit is separate from all that.&lt;/p&gt;

&lt;p&gt;The RAG module handles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Text extraction.&lt;/li&gt;
&lt;li&gt;Chunking.&lt;/li&gt;
&lt;li&gt;Embedding.&lt;/li&gt;
&lt;li&gt;Similarity search.&lt;/li&gt;
&lt;li&gt;Retrieval.&lt;/li&gt;
&lt;li&gt;Generation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The interfaces just call it. I also added an evaluation script using a paper I already had lying around, &lt;em&gt;Attention Is All You Need&lt;/em&gt;, with questions of varying difficulty.&lt;/p&gt;

&lt;p&gt;Again, the point was not to build some enterprise RAG platform. I wanted something small enough that I could open &lt;code&gt;rag.py&lt;/code&gt;, read it top to bottom, and understand what every part was doing. I learn better that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local AI is becoming much more interesting to me
&lt;/h2&gt;

&lt;p&gt;The embedding discovery also changed how I think about adding AI features to my own applications. My default assumption used to be that "adding AI" meant sending everything to some massive remote model. That assumption is becoming less useful. There are increasingly parts of the pipeline I can run locally or self-host:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embeddings.&lt;/li&gt;
&lt;li&gt;Classification.&lt;/li&gt;
&lt;li&gt;Reranking.&lt;/li&gt;
&lt;li&gt;Transcription.&lt;/li&gt;
&lt;li&gt;Smaller language models.&lt;/li&gt;
&lt;li&gt;Various forms of semantic search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That leaves paid inference for the bits that actually benefit from a larger model, which matters for side projects, and matters even more when building software in places where throwing $50 or $100 a month at every interesting API isn't a particularly attractive development strategy.&lt;/p&gt;

&lt;p&gt;I already like self-hosting normal infrastructure. Apparently I'm slowly becoming the person who wants to self-host chunks of the AI stack too. This was probably inevitable.&lt;/p&gt;

&lt;h2&gt;
  
  
  More importantly, I want to actually use this stuff
&lt;/h2&gt;

&lt;p&gt;I have zero interest in adding an AI button to every application just because investors have collectively decided that everything now needs AI. What I &lt;em&gt;am&lt;/em&gt; increasingly interested in is finding places where these models genuinely improve an existing workflow.&lt;/p&gt;

&lt;p&gt;RAG is interesting because there are obvious uses for it. Documentation is one: imagine an internal application with years of manuals, procedures, policies and reports. Instead of manually searching through them, you ask a question and the relevant sections get retrieved before the answer is generated. That's useful.&lt;/p&gt;

&lt;p&gt;Another thing I want to experiment with next is databases. I've spent years building systems where somebody eventually asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can you give me a report showing X, grouped by Y, for these dates?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...and then somebody has to write SQL, add a report screen, export something to Excel, or build yet another dashboard. I want to experiment with a safer natural-language interface where somebody can ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How many registrations did we receive per month this year?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and the system understands the database schema, generates a read-only query, validates it, executes it, and explains the result.&lt;/p&gt;

&lt;p&gt;That's not necessarily the same problem as RAG. Structured databases need different techniques, and I definitely do not want an LLM firing random &lt;code&gt;DELETE&lt;/code&gt; statements at production. But it's exactly the kind of AI experimentation I'm interested in now: giving the application another interface to capabilities it already has.&lt;/p&gt;

&lt;h2&gt;
  
  
  The useful lesson wasn't actually about RAG
&lt;/h2&gt;

&lt;p&gt;I started this project because I wanted to understand embeddings, retrieval and RAG. I did learn those things, but I think the more useful lesson was about how easily we confuse the infrastructure around a technology with the technology itself.&lt;/p&gt;

&lt;p&gt;You do not need a vector database to understand vector search.&lt;/p&gt;

&lt;p&gt;You do not need an embedding API to create embeddings.&lt;/p&gt;

&lt;p&gt;You do not need an enormous framework to understand RAG.&lt;/p&gt;

&lt;p&gt;And you definitely do not need to start by building the architecture meant to serve ten million users.&lt;/p&gt;

&lt;p&gt;Sometimes you need a Python file, NumPy, a small model running on your CPU, and enough curiosity to keep poking at the thing until it stops looking like magic. That is what &lt;code&gt;simple_rag&lt;/code&gt; has become for me.&lt;/p&gt;

&lt;p&gt;The repository is still called simple RAG. This time, I think it actually deserves the name.&lt;/p&gt;




&lt;p&gt;The project is on GitHub: &lt;a href="https://github.com/tony-nyagah/simple_rag" rel="noopener noreferrer"&gt;tony-nyagah/simple_rag&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am going to keep experimenting with practical AI integrations and documenting what I learn, especially the boring, useful stuff between "call an LLM" and "build an autonomous superintelligence."&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Self-Hosting is easier than you think: A guide to open source PaaS</title>
      <dc:creator>Antony Nyagah</dc:creator>
      <pubDate>Wed, 24 Jun 2026 09:30:00 +0000</pubDate>
      <link>https://dev.to/nyagah/self-hosting-is-easier-than-you-think-a-guide-to-open-source-paas-1pl4</link>
      <guid>https://dev.to/nyagah/self-hosting-is-easier-than-you-think-a-guide-to-open-source-paas-1pl4</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What I Was Looking For&lt;/li&gt;
&lt;li&gt;What Dokploy Actually Is&lt;/li&gt;
&lt;li&gt;What I Actually Run on It&lt;/li&gt;
&lt;li&gt;The Trade-offs&lt;/li&gt;
&lt;li&gt;Ten Minutes to Your Own Platform&lt;/li&gt;
&lt;li&gt;Should You Switch?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A while back I built an email verifier using Go while learning the language and wanted to deploy it. Sadly, &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; did not support Go at the time. None of the other platform-as-a-service providers supported it either at the time. Most of them supported only JavaScript, TypeScript and maybe Python.&lt;/p&gt;

&lt;p&gt;So I went looking.&lt;/p&gt;

&lt;p&gt;In the process of looking for something similar to the PaaS I was used to, I came across various self-hosted solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I was looking for
&lt;/h2&gt;

&lt;p&gt;I wanted three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A nice UI + dashboard. Managing apps and services on the terminal is fun and all but I am a more visual person. I wanted a dashboard that would let me see all my apps and services at a glance.&lt;/li&gt;
&lt;li&gt;Git-push deploys. I got used to that flow from Vercel and I wasn't giving it up.&lt;/li&gt;
&lt;li&gt;No lock-in. If the platform died tomorrow, I want to move on quickly to another solution.&lt;/li&gt;
&lt;li&gt;Ease of use. I wanted something that I could get up and running with little issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I tried a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://coolify.io" rel="noopener noreferrer"&gt;Coolify&lt;/a&gt; is the most mature. It supports something like 50 different services and is very feature-rich.    But I found myself lost when trying to set it up on my VPS. This might have changed since I last tried it.&lt;br&gt;&lt;br&gt;
The UI was also a bit overwhelming in terms of what I had to configure to get my projects running.    &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://caprover.com" rel="noopener noreferrer"&gt;CapRover&lt;/a&gt; is the opposite. Nice and simple. Does exactly what you want. This has greatly improved since I last tried it a few years ago. Very simple and to the point.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://kamal-deploy.org" rel="noopener noreferrer"&gt;Kamal&lt;/a&gt; is interesting. It's 37signals' tool for deploying Basecamp and HEY. All CLI, no web UI. If you live in a terminal and you trust yourself with YAML at 2am, it's solid. I wanted something between "bare metal CLI" and "kitchen sink platform."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker Compose + GitHub/GitLab actions. I still use this on some projects. But I wanted a better way to monitor what's happening with my software.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I finally settled on &lt;a href="https://dokploy.com" rel="noopener noreferrer"&gt;Dokploy&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Dokploy" rel="noopener noreferrer"&gt;
        Dokploy
      &lt;/a&gt; / &lt;a href="https://github.com/Dokploy/dokploy" rel="noopener noreferrer"&gt;
        dokploy
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Open Source Alternative to Vercel, Netlify and Heroku.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
  &lt;a href="https://dokploy.com" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FDokploy%2Fdokploy%2FHEAD%2F.github%2Fsponsors%2Flogo.png" alt="Dokploy - Open Source Alternative to Vercel, Heroku and Netlify." width="100%"&gt;
  &lt;/a&gt;
  &lt;br&gt;
  &lt;br&gt;
  &lt;p&gt;Join us on Discord for help, feedback, and discussions!&lt;/p&gt;
  &lt;a href="https://discord.gg/2tBnJ3jDJc" rel="nofollow noopener noreferrer"&gt;
    &lt;img src="https://camo.githubusercontent.com/549d5a6607c79fd013118f147306d06b38a8fa642cd288199e3e91f6681f8106/68747470733a2f2f646973636f72646170702e636f6d2f6170692f6775696c64732f313233343037333236323431383536333131322f7769646765742e706e673f7374796c653d62616e6e657232" alt="Discord Shield"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;p&gt;Dokploy is a free, self-hostable Platform as a Service (PaaS) that simplifies the deployment and management of applications and databases.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Features&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Dokploy includes multiple features to make your life easier.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Applications&lt;/strong&gt;: Deploy any type of application (Node.js, PHP, Python, Go, Ruby, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Databases&lt;/strong&gt;: Create and manage databases with support for MySQL, PostgreSQL, MongoDB, MariaDB, libsql, and Redis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backups&lt;/strong&gt;: Automate backups for databases to an external storage destination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose&lt;/strong&gt;: Native support for Docker Compose to manage complex applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi Node&lt;/strong&gt;: Scale applications to multiple nodes using Docker Swarm to manage the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates&lt;/strong&gt;: Deploy open-source templates (Plausible, Pocketbase, Calcom, etc.) with a single click.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traefik Integration&lt;/strong&gt;: Automatically integrates with Traefik for routing and load balancing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Monitoring&lt;/strong&gt;: Monitor CPU, memory, storage, and network usage for every resource.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Management&lt;/strong&gt;: Easily deploy…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Dokploy/dokploy" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpp361mopg41es5td0a7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpp361mopg41es5td0a7.png" alt="A dashboard showing the Dokploy interface with various running apps and real-time logs" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Dokploy actually is
&lt;/h2&gt;

&lt;p&gt;One binary. You SSH into a fresh VPS, run a single curl command, and you get a dashboard on port 3000. Behind the scenes it's Docker and &lt;a href="https://traefik.io" rel="noopener noreferrer"&gt;Traefik&lt;/a&gt; doing the actual work. Dokploy is the UI layer on top.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; dokploy.com/install.sh | bash
&lt;span class="c"&gt;# That's it. Open port 3000.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Git integration.&lt;/strong&gt; Connect GitHub or GitLab, push to main, it builds and deploys. Same flow as Vercel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose support.&lt;/strong&gt; I didn't have to learn a new config format. It reads my existing compose files. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto SSL.&lt;/strong&gt; I have never once manually configured an SSL cert with Dokploy. Let's Encrypt via Traefik, zero touching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in monitoring.&lt;/strong&gt; Logs, resource usage, healthchecks. I can see if my Telegram bot crashed without opening a terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the most interesting parts is the &lt;strong&gt;Templates for common apps&lt;/strong&gt; such as Anubis, AppSmith, Listmonk, ERPNext, Ghost, GitLab, Bugsink and many more. The list is &lt;a href="https://templates.dokploy.com/" rel="noopener noreferrer"&gt;massive.&lt;/a&gt;&lt;br&gt;
The templates give you an editable Docker Compose file so you can customize the app to your needs. So you're not forced to use a specific setup.&lt;/p&gt;

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

&lt;p&gt;Of note is that most of these solutions depend on Docker. Most of them are essentially a UI on top of a standard Docker + Docker Compose + Traefik configuration. This means you can seamlessly move from one self-hosted solution to another. No lock-in whatsoever.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually run on it
&lt;/h2&gt;

&lt;p&gt;I have been using Dokploy in production for a few month now to run some open source applications including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://listmonk.app/" rel="noopener noreferrer"&gt;Listmonk&lt;/a&gt; - email marketing campaigns for an SME&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://umami.is/" rel="noopener noreferrer"&gt;umami&lt;/a&gt; - website analytics to track user behavior on a new project&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bugsink.com/" rel="noopener noreferrer"&gt;Bugsink&lt;/a&gt; - error tracking for a legacy project we're maintaining&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far the setup was simple and straightforward. Pick a template, point a domain at it, edit the configurations such as environment variables and secrets, and press the deploy button.&lt;/p&gt;

&lt;p&gt;I also have some personal projects running on it. Mainly projects built while learning new technologies or experimenting with new ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trade-offs
&lt;/h2&gt;

&lt;p&gt;Self-hosting isn't all upside. I'm not going to pretend it is.&lt;/p&gt;

&lt;p&gt;You don't get a global edge network. Your server is in one region. If your users are in Australia and your VPS is in Germany, they'll feel it. Vercel's edge network is genuinely good at this. For most side projects this doesn't matter. But if you're building something global, keep it in mind.&lt;/p&gt;

&lt;p&gt;You manage capacity. If you get posted on Hacker News and your traffic goes 10x in an hour, Dokploy won't auto-scale. You'll need to handle that. For most side projects? Won't happen. But be honest with yourself.&lt;/p&gt;

&lt;p&gt;You're responsible for uptime. If the server goes down at 3am, nobody's fixing it but you. I use &lt;a href="https://uptime.kuma.pet" rel="noopener noreferrer"&gt;Uptime Kuma&lt;/a&gt; for monitoring and I get Telegram alerts. Works for me. Might not work for you.&lt;/p&gt;

&lt;p&gt;Database backups are on you. Dokploy makes it easy to provision handle that though. Your Docker volumes can be backed up to an S3 bucket or equivalent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But here's what you get:&lt;/strong&gt; fixed monthly cost. No surprise bills. Run "unlimited" projects. Full control over your infrastructure. Data stays wherever you want it. And the DevOps skills you pick up? They transfer everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ten minutes to your own platform
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get a VPS.&lt;/strong&gt; I use &lt;a href="https://www.hetzner.com/cloud" rel="noopener noreferrer"&gt;Hetzner&lt;/a&gt;. &lt;a href="https://www.digitalocean.com" rel="noopener noreferrer"&gt;DigitalOcean&lt;/a&gt; and &lt;a href="https://www.linode.com" rel="noopener noreferrer"&gt;Linode&lt;/a&gt; work too. Latest Ubuntu.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH in and run the install command.&lt;/strong&gt; That's it. Dokploy sets up Docker, Traefik, and the dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Point your domain.&lt;/strong&gt; A record to the VPS IP. SSL happens automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy something.&lt;/strong&gt; Connect a GitHub repo, paste a compose file, or pick a template.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ten minutes. Then you have a platform that costs less than lunch, runs "unlimited" apps, and you actually own.&lt;/p&gt;

&lt;p&gt;And if there's any issues, the &lt;a href="https://docs.dokploy.com/docs/core" rel="noopener noreferrer"&gt;Dokploy documentation&lt;/a&gt; is fantastic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you switch?
&lt;/h2&gt;

&lt;p&gt;If you're happy on Vercel or Heroku or something similar and you don't hit their limits, stay. They're good products.&lt;/p&gt;

&lt;p&gt;But if you've ever opened a surprise bill, or hit a timeout limit that broke your app, or wanted to run something that didn't fit the platform's mold — try Dokploy. Spin up a VPS for a month and deploy one or two or ten side projects. Worst case, you're out less than $10. Best case, you realize you don't need the closed source PaaS platforms.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devex</category>
      <category>opensource</category>
    </item>
    <item>
      <title>You Don't Need Docker Desktop on Linux</title>
      <dc:creator>Antony Nyagah</dc:creator>
      <pubDate>Wed, 17 Jun 2026 08:00:00 +0000</pubDate>
      <link>https://dev.to/nyagah/you-dont-need-docker-desktop-on-linux-1n8b</link>
      <guid>https://dev.to/nyagah/you-dont-need-docker-desktop-on-linux-1n8b</guid>
      <description>&lt;p&gt;Docker Desktop was using 4GB of RAM on my machine. Sitting there. Doing nothing. No containers running. Just the daemon.&lt;/p&gt;

&lt;p&gt;I don't know about you, but 4 gigs for a container runtime that isn't running any containers is a hard no from me.&lt;/p&gt;

&lt;p&gt;I'm on Fedora, but this applies to Ubuntu, Debian, whatever. If you're running Linux, you don't need Docker Desktop.&lt;/p&gt;

&lt;p&gt;So I started looking at what I actually needed. Turns out: not much.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Docker Desktop actually is
&lt;/h2&gt;

&lt;p&gt;Docker Desktop is a GUI wrapper around a VM that runs the Docker Engine. On Linux, the VM part is unnecessary. Docker runs natively on Linux. The VM exists because Windows and macOS don't have a native Linux kernel. But on Linux? You're running a VM to run something that already runs natively on your system. That's the bloat.&lt;/p&gt;

&lt;p&gt;What you actually need on Linux:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Docker Engine&lt;/strong&gt; — the daemon that runs containers (&lt;code&gt;docker-ce&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Compose&lt;/strong&gt; — the plugin, not the old Python binary (&lt;code&gt;docker compose&lt;/code&gt;, not &lt;code&gt;docker-compose&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The CLI&lt;/strong&gt; — &lt;code&gt;docker&lt;/code&gt; commands, which come with the engine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. No GUI. No VM. No 4GB idle footprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  The auto-start nonsense
&lt;/h2&gt;

&lt;p&gt;Here's what really pushed me over the edge. Every time I rebooted my Fedora machine, Docker Desktop wouldn't auto-start. I had to manually launch it. Every single time.&lt;/p&gt;

&lt;p&gt;This is supposed to "just work." It's a desktop application. Starting on boot is table stakes. But nope — I'd boot up, try to run &lt;code&gt;docker ps&lt;/code&gt;, get a "cannot connect to daemon" error, and have to go find Docker Desktop in my app launcher and start it manually. Like it's 2012 and I'm starting a service by hand.&lt;/p&gt;

&lt;p&gt;Compare that to the Docker Engine installed natively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. Starts on boot. Every time. No manual launching. No GUI to hunt down. It just works. Because it's a system service, not a desktop app cosplaying as one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Podman is right there
&lt;/h2&gt;

&lt;p&gt;While I was figuring all this out, I also realized Podman Desktop exists. And it does basically the same thing Docker Desktop does — a GUI for managing containers, images, volumes — but it uses Podman under the hood. Which is daemonless. Which means even less overhead.&lt;/p&gt;

&lt;p&gt;Podman Desktop on my machine: about 800MB idle. Docker Desktop: 4GB. Same machine. Same workload (nothing). Five times the memory for the same thing.&lt;/p&gt;

&lt;p&gt;Now, I still use Docker for most things. My docker-compose files, my CI pipelines, my multi-arch builds — they're all Docker. I'm not saying everyone should switch to Podman. I'm saying if you're on Linux and you're using Docker Desktop, you're paying a VM tax for no reason. The engine is already there.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually run
&lt;/h2&gt;

&lt;p&gt;Here's my setup. Pick your distro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fedora / RHEL&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io docker-compose-plugin

&lt;span class="c"&gt;# Ubuntu / Debian&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io docker-compose-plugin

&lt;span class="c"&gt;# Then for both:&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No Docker Desktop. No VM. No 4GB idle. No manual launching. &lt;code&gt;docker&lt;/code&gt; commands work. &lt;code&gt;docker compose&lt;/code&gt; works. Everything I need.&lt;/p&gt;

&lt;p&gt;(If Docker's repos aren't set up yet: &lt;a href="https://docs.docker.com/engine/install/fedora/" rel="noopener noreferrer"&gt;Fedora guide&lt;/a&gt; or &lt;a href="https://docs.docker.com/engine/install/ubuntu/" rel="noopener noreferrer"&gt;Ubuntu guide&lt;/a&gt;. It's three commands.)&lt;/p&gt;

&lt;p&gt;And if I want a GUI for browsing images or checking logs? Podman Desktop. It connects to Docker's socket just fine. Best of both worlds: Docker engine under the hood (because that's what my CI and my compose files expect), Podman Desktop when I want a visual overview, and neither one is eating my RAM for breakfast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you actually need Docker Desktop?
&lt;/h2&gt;

&lt;p&gt;If you're on Windows or macOS: probably yes. Docker Engine needs a Linux kernel, and Docker Desktop provides that VM. It's doing real work on those platforms.&lt;/p&gt;

&lt;p&gt;If you're on Linux: probably no. The engine runs natively. You don't need a VM. You don't need a GUI (the CLI is better once you learn 10 commands). And if you occasionally want a GUI, Podman Desktop is lighter and free.&lt;/p&gt;

&lt;p&gt;Docker Desktop on Linux is like installing a virtual machine to run Firefox. Firefox already runs on Linux. Just install Firefox.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 10 commands you actually need
&lt;/h2&gt;

&lt;p&gt;If the CLI is what's holding you back, here's what covers 90% of daily use. It's not that many:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps                 &lt;span class="c"&gt;# what's running?&lt;/span&gt;
docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;              &lt;span class="c"&gt;# what exists (including stopped)?&lt;/span&gt;
docker logs &amp;lt;container&amp;gt;   &lt;span class="c"&gt;# what's it saying?&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;      &lt;span class="c"&gt;# start my stack&lt;/span&gt;
docker compose down       &lt;span class="c"&gt;# stop my stack&lt;/span&gt;
docker compose pull       &lt;span class="c"&gt;# update images&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--build&lt;/span&gt;  &lt;span class="c"&gt;# rebuild and restart&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;container&amp;gt; sh  &lt;span class="c"&gt;# get a shell inside&lt;/span&gt;
docker system prune &lt;span class="nt"&gt;-a&lt;/span&gt;    &lt;span class="c"&gt;# clean up everything unused&lt;/span&gt;
docker stats              &lt;span class="c"&gt;# what's eating my RAM?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ten commands. You'll use maybe five of them regularly. The GUI is nice to have but not worth 4GB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just try it
&lt;/h2&gt;

&lt;p&gt;Remove Docker Desktop. Install &lt;code&gt;docker-ce&lt;/code&gt; and the compose plugin. Systemctl enable it. See if you miss the GUI. If you do, install Podman Desktop. You can always reinstall Docker Desktop — but I don't think you will.&lt;/p&gt;

&lt;p&gt;I haven't opened Docker Desktop in over a year. My containers run fine. My RAM is happier. My machine boots and Docker is just... there. Working. Like it should.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>podman</category>
      <category>devops</category>
      <category>linux</category>
    </item>
    <item>
      <title>How I Built a Real-Time DDoS Detection Engine That Learns What Normal Looks Like</title>
      <dc:creator>Antony Nyagah</dc:creator>
      <pubDate>Wed, 29 Apr 2026 22:56:24 +0000</pubDate>
      <link>https://dev.to/nyagah/how-i-built-a-real-time-ddos-detection-engine-that-learns-what-normal-looks-like-2fei</link>
      <guid>https://dev.to/nyagah/how-i-built-a-real-time-ddos-detection-engine-that-learns-what-normal-looks-like-2fei</guid>
      <description>&lt;p&gt;Imagine your web server suddenly starts getting hammered by thousands of requests from one IP address. Without any protection, your server slows down, legitimate users get blocked out, and you have no idea it's even happening until it's too late. That's the problem I set out to solve by building a real-time anomaly detection engine alongside a Nextcloud server. The tool watches every single HTTP request coming through Nginx, learns what "normal" traffic looks like over time, and automatically blocks attackers using iptables — the Linux firewall built into every server. No third-party tools, no Fail2Ban, just pure detection logic built from scratch in Python.&lt;/p&gt;

&lt;p&gt;The core of the system is two ideas working together: a sliding window and a rolling baseline. The sliding window is a Python &lt;code&gt;deque&lt;/code&gt; that holds the timestamps of every request in the last 60 seconds — one per IP, one globally. When a new request arrives, its timestamp is added to the back; anything older than 60 seconds is evicted from the front. Dividing the count by 60 gives the current requests-per-second rate. The baseline is a 30-minute rolling average of per-second rates, recalculated every 60 seconds, with separate slots for each hour of the day so the system knows that midnight traffic is naturally lighter than noon. When a new request comes in, the detector computes a z-score: &lt;code&gt;(current_rate - mean) / stddev&lt;/code&gt;. If that score exceeds 3.0, or the rate is more than 5 times the baseline mean, the IP is flagged as an attacker. The response is immediate — the system runs &lt;code&gt;iptables -I INPUT -s &amp;lt;attacker_ip&amp;gt; -j DROP&lt;/code&gt;, which tells the Linux kernel to silently drop every packet from that IP at the network level, before it even reaches the application. A Slack alert fires within seconds, and the ban is automatically lifted on a backoff schedule: 10 minutes for the first offense, 30 minutes for the second, 2 hours for the third, and permanent after that.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>linux</category>
      <category>monitoring</category>
      <category>python</category>
    </item>
    <item>
      <title>How to Leverage Git and AI to View Your Achievements as a Developer</title>
      <dc:creator>Antony Nyagah</dc:creator>
      <pubDate>Wed, 30 Oct 2024 11:00:00 +0000</pubDate>
      <link>https://dev.to/nyagah/how-to-leverage-git-and-ai-to-view-your-achievements-as-a-developer-26f2</link>
      <guid>https://dev.to/nyagah/how-to-leverage-git-and-ai-to-view-your-achievements-as-a-developer-26f2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As developers, we often move from one task to the next without much time to reflect. But periodically assessing what you’ve accomplished can be a great motivator and help you communicate your value to teams, managers, or potential employers. &lt;br&gt;
Here’s a simple approach to using your Git commit history to track your achievements over time, with the help of AI to make sense of it all.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Filter Your Git Logs
&lt;/h2&gt;

&lt;p&gt;The first step is to look back at your commits over the past year (or a specific timeframe). Git makes it easy to search through your history by date and author. This command will give you a list of commits from the past year, authored by you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1 year ago"&lt;/span&gt; &lt;span class="nt"&gt;--author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_email@example.com"&lt;/span&gt; &lt;span class="nt"&gt;--pretty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;format:&lt;span class="s2"&gt;"%h - %an, %ar : %s"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a breakdown of this command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--since="1 year ago"&lt;/code&gt; limits results to commits from the past year.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--author="your_email@example.com"&lt;/code&gt; filters commits to only those you made.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--pretty=format:"%h - %an, %ar : %s"&lt;/code&gt; displays commit hash, author, relative date, and message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example of what my logs looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8abe2e3 - Antony Nyagah, 5 days ago : feat(dashboard/*): add link for downloading packaging list
0409dac - Antony Nyagah, 5 days ago : feat(dashboard/*): add a link for downloading delivery notes from the frontend
0c199f9 - Antony Nyagah, 5 days ago : test(api/*): update tests for document_exporter app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Export Your Commit Log
&lt;/h2&gt;

&lt;p&gt;For easier analysis, you can export your commit history to a text file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1 year ago"&lt;/span&gt; &lt;span class="nt"&gt;--author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your_email@example.com"&lt;/span&gt; &lt;span class="nt"&gt;--pretty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;format:&lt;span class="s2"&gt;"%h - %an, %ar : %s"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; commit_log.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Leverage AI for a Detailed Analysis
&lt;/h2&gt;

&lt;p&gt;After exporting the commit log, I pasted the commits into ChatGPT(you can use any number of AI tool that are out there) to get a detailed summary and insights into the types of tasks I’ve accomplished.&lt;/p&gt;

&lt;p&gt;The prompt I used was "Can you look at these commits and help me come up with a list of my achievements throughout this year?". The prompt itself can be improved 😅&lt;/p&gt;

&lt;p&gt;This helped me uncover trends and group my work into categories like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infrastructure &amp;amp; CI/CD Enhancements&lt;/li&gt;
&lt;li&gt;Frontend Development &amp;amp; Refactoring&lt;/li&gt;
&lt;li&gt;Backend API Development &amp;amp; Maintenance&lt;/li&gt;
&lt;li&gt;Database and Data Handling Improvements&lt;/li&gt;
&lt;li&gt;Testing and Code Quality&lt;/li&gt;
&lt;li&gt;Documentation &amp;amp; Project Management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ChatGPT’s analysis made it easy to see where I added value and what skills I honed over the past year, even bringing out details I might have overlooked. By using AI this way, you can turn your commit log into a meaningful narrative about your contributions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Keeping Commit Messages Meaningful
&lt;/h2&gt;

&lt;p&gt;To make sure my commit messages are succinct and relevant, I personally use &lt;a href="https://commitizen-tools.github.io/commitizen/" rel="noopener noreferrer"&gt;Commitizen&lt;/a&gt;. This tool helps maintain consistency by following a commit message convention that describes the "why" and "what" of each change.&lt;/p&gt;

&lt;p&gt;Meaningful commit messages make logs easier to review, and there are other specifications and tools like &lt;a href="https://www.conventionalcommits.org/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt; and &lt;a href="https://typicode.github.io/husky/" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; that can also keep your commit history clean and purposeful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Summarize and Reflect
&lt;/h2&gt;

&lt;p&gt;Reviewing your contributions with AI insights can be both motivating and insightful. Write a brief summary for each category. This can serve as a reference for future performance reviews, portfolio updates, or simply as a reminder of your growth as a developer.&lt;/p&gt;

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

&lt;p&gt;Using Git as a reflection tool is quick but effective. And with the added support of AI, you can see the big picture more clearly, connecting technical achievements with your overall development. Keep this record for yourself or share it in your performance reviews or job applications.&lt;/p&gt;

</description>
      <category>git</category>
      <category>ai</category>
      <category>codequality</category>
      <category>career</category>
    </item>
  </channel>
</rss>
