<?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: WhatShipped</title>
    <description>The latest articles on DEV Community by WhatShipped (@whatshipped).</description>
    <link>https://dev.to/whatshipped</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%2F3848949%2Ffb354381-542f-4483-be9a-4fe36865f30f.png</url>
      <title>DEV Community: WhatShipped</title>
      <link>https://dev.to/whatshipped</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whatshipped"/>
    <language>en</language>
    <item>
      <title>What I learned building a solo product</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Tue, 07 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/whatshipped/what-i-learned-building-a-solo-product-in-a-month-of-evenings-3905</link>
      <guid>https://dev.to/whatshipped/what-i-learned-building-a-solo-product-in-a-month-of-evenings-3905</guid>
      <description>&lt;p&gt;I shipped &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; in about a week.&lt;/p&gt;

&lt;p&gt;Not because I'm exceptionally fast. Because I've spent years making the mistake of optimizing for building instead of for shipping — and I finally stopped.&lt;/p&gt;

&lt;p&gt;This is what actually changed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The old pattern
&lt;/h2&gt;

&lt;p&gt;The cycle I used to run:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Have an idea&lt;/li&gt;
&lt;li&gt;Build the full version in my head&lt;/li&gt;
&lt;li&gt;Start building&lt;/li&gt;
&lt;li&gt;Keep building until it felt "ready"&lt;/li&gt;
&lt;li&gt;Launch&lt;/li&gt;
&lt;li&gt;Silence&lt;/li&gt;
&lt;li&gt;Lose motivation, move on&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The problem wasn't the execution. It was the framing. I was treating "done" as a quality threshold I set internally. By the time I shipped, I'd answered every question except the one that mattered: do people actually want this?&lt;/p&gt;




&lt;h2&gt;
  
  
  WhatShipped started from a real frustration
&lt;/h2&gt;

&lt;p&gt;I'd been building &lt;a href="https://geentoo.com" rel="noopener noreferrer"&gt;Geentoo&lt;/a&gt; — an Italian platform for co-founders — for months. Great commit history? No. It was full of &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;wip&lt;/code&gt;, &lt;code&gt;ok this works&lt;/code&gt;, &lt;code&gt;ok this actually works&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When I wanted to communicate what had changed to users, I had nothing coherent to show. I wanted a tool that could look at a messy git history and generate a readable, structured changelog automatically.&lt;/p&gt;

&lt;p&gt;It didn't exist in the form I wanted. So I built it.&lt;/p&gt;

&lt;p&gt;That's the only origin story that produces something worth shipping: solve a problem you've personally experienced. Everything else is speculation.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I cut to ship in a week
&lt;/h2&gt;

&lt;p&gt;The list of things I explicitly chose not to build for v1:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OAuth for every platform on day one (started with GitHub only)&lt;/li&gt;
&lt;li&gt;Custom domain support per user&lt;/li&gt;
&lt;li&gt;Team and collaboration features&lt;/li&gt;
&lt;li&gt;A usage analytics dashboard&lt;/li&gt;
&lt;li&gt;A polished UI&lt;/li&gt;
&lt;li&gt;Public changelog hosting pages&lt;/li&gt;
&lt;li&gt;Webhook integrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those were necessary to answer the core question: &lt;em&gt;does connecting a repo and generating a changelog from AI actually solve the problem?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Everything else is iteration. You can't iterate on something you haven't shipped.&lt;/p&gt;




&lt;h2&gt;
  
  
  The hardest part of building solo
&lt;/h2&gt;

&lt;p&gt;The hardest part isn't the code.&lt;/p&gt;

&lt;p&gt;It's the absence of external structure. No product manager deciding priorities. No standup creating accountability. No teammate pushing back on scope creep.&lt;/p&gt;

&lt;p&gt;When you're working alone, you can build features forever. There's always something that seems worth adding before launch. The constraint has to come from inside.&lt;/p&gt;

&lt;p&gt;The question I use to cut scope: &lt;em&gt;"Is this needed to test whether the core thing works?"&lt;/em&gt; If the answer is no, it goes on a list for later. Not in the backlog. On a separate list, so it stops pulling at my attention.&lt;/p&gt;




&lt;h2&gt;
  
  
  The metric that keeps me honest
&lt;/h2&gt;

&lt;p&gt;Not star count. Not signup volume. Not revenue (not yet).&lt;/p&gt;

&lt;p&gt;The question I ask every week: &lt;em&gt;"Did I have a real conversation with a user this week?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If the answer is no, nothing else matters. Everything is speculation until it's confirmed by someone who isn't me using the product to solve their problem.&lt;/p&gt;

&lt;p&gt;This sounds obvious. It's surprisingly easy to spend a week shipping improvements based on assumptions and feel productive.&lt;/p&gt;




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

&lt;p&gt;The product works. The next phase is distribution — specifically, reaching the people who need it most: open source maintainers with active projects and no changelog.&lt;/p&gt;

&lt;p&gt;That means direct outreach, content, and building in public about what's actually working versus what isn't.&lt;/p&gt;

&lt;p&gt;If you maintain an open source project without a changelog, I'd genuinely like to hear what the friction point is for you. Feel free to comment or reach out.&lt;/p&gt;

&lt;p&gt;And if you want to generate a changelog from your existing git history — messy commits and all — there's 1 free generation at &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;whatshipped.dev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>buildinpublic</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Semantic versioning explained - and why most projects get it wrong</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Mon, 06 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/whatshipped/semantic-versioning-explained-and-why-most-projects-get-it-wrong-2ig5</link>
      <guid>https://dev.to/whatshipped/semantic-versioning-explained-and-why-most-projects-get-it-wrong-2ig5</guid>
      <description>&lt;p&gt;"v2.0 is out!"&lt;/p&gt;

&lt;p&gt;Does that mean you should upgrade immediately? Will it break your integration? What actually changed?&lt;/p&gt;

&lt;p&gt;Semantic versioning (SemVer) was designed to answer these questions through the version number itself. Most projects use the number format without following the meaning — which defeats the whole point.&lt;/p&gt;




&lt;h2&gt;
  
  
  The spec in 30 seconds
&lt;/h2&gt;

&lt;p&gt;SemVer is three numbers: &lt;code&gt;MAJOR.MINOR.PATCH&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2.4.1
│ │ └── PATCH: backward-compatible bug fixes
│ └──── MINOR: new features, backward compatible
└────── MAJOR: breaking changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If every project followed this consistently, the version number alone would tell you whether an upgrade is safe. That's the goal.&lt;/p&gt;




&lt;h2&gt;
  
  
  What each number means in practice
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PATCH (1.0.0 → 1.0.1)&lt;/strong&gt;&lt;br&gt;
A bug was fixed. Existing behavior is the same or better. Safe to update without reading anything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MINOR (1.0.0 → 1.1.0)&lt;/strong&gt;&lt;br&gt;
A new feature was added. Existing code continues to work exactly as before. Update if you want access to the new functionality; skip it if you don't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MAJOR (1.0.0 → 2.0.0)&lt;/strong&gt;&lt;br&gt;
Something changed in a way that may break existing code. Read the changelog before upgrading. You may need to update your integration.&lt;/p&gt;

&lt;p&gt;When a project follows this consistently, users develop accurate intuition about upgrades: patches are safe, minors are low-risk, majors require attention.&lt;/p&gt;




&lt;h2&gt;
  
  
  The most common mistake
&lt;/h2&gt;

&lt;p&gt;Bumping MAJOR for anything that feels "big."&lt;/p&gt;

&lt;p&gt;A complete internal rewrite that doesn't change the public API is still a MINOR bump. A major visual redesign of a library's output that doesn't change how you call it is still MINOR. A significant new feature set is still MINOR.&lt;/p&gt;

&lt;p&gt;MAJOR is specifically for breaking changes — changes that will cause existing code using your package to fail or behave incorrectly without modification.&lt;/p&gt;

&lt;p&gt;Your sense of how significant the work was doesn't determine the version. The impact on existing users does.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 0.x convention
&lt;/h2&gt;

&lt;p&gt;While your major version is 0 (&lt;code&gt;0.y.z&lt;/code&gt;), you're sending a signal: &lt;em&gt;this is pre-stable, the API may change at any time.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;0.x&lt;/code&gt;, it's acceptable to make breaking changes in minor version bumps. The convention acknowledges that early-stage projects iterate on their API before committing to stability.&lt;/p&gt;

&lt;p&gt;When should you move to &lt;code&gt;1.0&lt;/code&gt;? When you're prepared to maintain backward compatibility and follow the MAJOR/MINOR/PATCH contract. It doesn't mean the software is perfect — it means you're committing to a contract with your users.&lt;/p&gt;




&lt;h2&gt;
  
  
  SemVer and changelogs are a pair
&lt;/h2&gt;

&lt;p&gt;SemVer answers: &lt;em&gt;how risky is this upgrade?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
A changelog answers: &lt;em&gt;what specifically changed?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One without the other is incomplete. The version number gives users a risk signal. The changelog gives them the information to act on it. Together, they enable users to make fast, confident decisions about whether and when to upgrade.&lt;/p&gt;

&lt;p&gt;A MAJOR bump with no changelog that explains what broke and how to migrate is as frustrating as a breaking change with no version bump at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  The decision rule
&lt;/h2&gt;

&lt;p&gt;If you're ever unsure which number to bump, there's a single question that resolves it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does code that currently uses my library/tool still work after this change, without modification?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes, and it's a bug fix&lt;/strong&gt; → PATCH&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yes, and it's a new feature&lt;/strong&gt; → MINOR&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No&lt;/strong&gt; → MAJOR&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole decision. The spec is detailed, but the practical rule is this simple.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making the release worth reading
&lt;/h2&gt;

&lt;p&gt;Once you've decided on the version bump, the changelog is what makes the release useful. A formatted, scannable CHANGELOG.md that groups changes by type (Added, Fixed, Breaking) paired with a clear SemVer bump is the complete picture.&lt;/p&gt;

&lt;p&gt;If writing that changelog is the friction that causes you to skip it, &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; generates it from your git history. There's 1 free generation — enough to produce the changelog for your next release without any manual work.&lt;/p&gt;




&lt;p&gt;Version numbers are a communication protocol between you and your users. When you use them correctly, you reduce confusion, reduce support overhead, and build trust. It's one of the lowest-effort, highest-signal things a maintainer can do.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to get your first 100 real users for an open source project</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Sun, 05 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/whatshipped/how-to-get-your-first-100-real-users-for-an-open-source-project-46k3</link>
      <guid>https://dev.to/whatshipped/how-to-get-your-first-100-real-users-for-an-open-source-project-46k3</guid>
      <description>&lt;p&gt;Building an open source project is the easy part.&lt;/p&gt;

&lt;p&gt;Getting people to find it, use it, and keep using it — that's the challenge. And it's one most developers never seriously address until the initial launch momentum fades and the stars stop coming.&lt;/p&gt;

&lt;p&gt;Here's what actually moves the needle.&lt;/p&gt;




&lt;h2&gt;
  
  
  The distribution mistake
&lt;/h2&gt;

&lt;p&gt;The default assumption: publish to GitHub, wait for organic discovery.&lt;/p&gt;

&lt;p&gt;The reality: GitHub's search is weak for finding new tools. Trending is unpredictable and short-lived. Unless your project hits a major aggregator or gets shared by someone with a large following, GitHub organic traffic alone won't build a user base.&lt;/p&gt;

&lt;p&gt;You have to go to where developers already are. Actively, not once.&lt;/p&gt;




&lt;h2&gt;
  
  
  The channels that work for early traction
&lt;/h2&gt;

&lt;p&gt;Not all distribution channels are equal for dev tools. Based on what consistently works for early-stage OSS projects:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hacker News "Show HN"&lt;/strong&gt; — High signal audience, genuinely interested in new tools. A well-written Show HN post for the right project can drive thousands of visits. The key: lead with the problem, not the solution. "Show HN: I built X" is weaker than "Show HN: I kept forgetting to write changelogs, so I automated it."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relevant subreddits&lt;/strong&gt; — r/programming, r/webdev, and language-specific communities (r/rust, r/python, etc.) have large audiences who actively look for new tools. Share something useful, not just a link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dev.to and Hashnode&lt;/strong&gt; — Both platforms index well on Google and have active developer audiences. A post that genuinely solves a problem can generate inbound traffic for years. Write about the &lt;em&gt;problem your tool solves&lt;/em&gt;, not the tool itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Direct outreach&lt;/strong&gt; — More on this below, but targeted personal outreach to people who'd genuinely benefit is one of the highest-ROI activities for early adoption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discord and Slack communities&lt;/strong&gt; — Framework-specific communities, language communities, and dev tool communities all have people actively looking for solutions to specific problems.&lt;/p&gt;

&lt;p&gt;Pick two channels. Work them consistently. Spreading thin across five channels is less effective than doing two well.&lt;/p&gt;




&lt;h2&gt;
  
  
  Direct outreach done right
&lt;/h2&gt;

&lt;p&gt;Direct outreach has a bad reputation because most of it is done badly.&lt;/p&gt;

&lt;p&gt;The difference between spam and a welcome message:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spam:&lt;/strong&gt; "Hey, I built a tool for developers, check it out: [link]"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Welcome:&lt;/strong&gt; "I noticed your project doesn't have a CHANGELOG — I built something that generates one from your git history automatically. Might save you 20 minutes per release."&lt;/p&gt;

&lt;p&gt;The welcome version is specific, relevant, and makes a clear case for why this particular person would benefit. It's not a broadcast. It's a targeted observation.&lt;/p&gt;

&lt;p&gt;For this to work at scale, you need a way to find people who match the profile. For WhatShipped, I built a script that queries the GitHub API for repos with moderate star counts, recent activity, and no CHANGELOG file — then the outreach is relevant by construction.&lt;/p&gt;




&lt;h2&gt;
  
  
  Content compounds. Outreach doesn't.
&lt;/h2&gt;

&lt;p&gt;Cold outreach produces results proportional to effort. When you stop sending, it stops working.&lt;/p&gt;

&lt;p&gt;Content is different. A good dev.to article that ranks for "how to write a changelog" will generate inbound traffic in two years without any additional effort from you. A good X thread that gets shared can drive hundreds of profile visits in a day.&lt;/p&gt;

&lt;p&gt;The formula: write about the &lt;em&gt;problem&lt;/em&gt;, not the &lt;em&gt;product&lt;/em&gt;. Developers search for problems ("how to automate changelogs") and discover products in the process. If your content answers the problem, the product discovery is natural.&lt;/p&gt;




&lt;h2&gt;
  
  
  The star count trap
&lt;/h2&gt;

&lt;p&gt;Stars feel meaningful. They're mostly vanity.&lt;/p&gt;

&lt;p&gt;A repository with 800 stars and no activity in six months has fewer real users than a 60-star project that ships weekly and responds to issues within a day.&lt;/p&gt;

&lt;p&gt;Stars measure a moment of interest. Active users, download counts, and issue volume measure real adoption. Track what matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  The asset nobody builds early enough
&lt;/h2&gt;

&lt;p&gt;An email list.&lt;/p&gt;

&lt;p&gt;100 people who explicitly asked to hear from you when you ship something new are worth more than 1,000 GitHub stars. You own that list. It doesn't depend on an algorithm. You can reach them directly.&lt;/p&gt;

&lt;p&gt;Put a simple opt-in in your README: "Get notified of new releases → [link]". A mailing list of 100 engaged users is a real distribution channel for every release you ship.&lt;/p&gt;

&lt;p&gt;And when you do email them, have something worth sending. A well-formatted changelog — what's new, what's fixed, what changed — is the most credible thing you can include. If generating that changelog is the friction point, &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; automates it from your git history. One free generation to try it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The compounding loop
&lt;/h2&gt;

&lt;p&gt;The projects that grow consistently tend to have the same loop running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ship something real&lt;/li&gt;
&lt;li&gt;Communicate it clearly (changelog, release post)&lt;/li&gt;
&lt;li&gt;Share it where the audience is&lt;/li&gt;
&lt;li&gt;Respond to the people who show up&lt;/li&gt;
&lt;li&gt;Repeat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these steps is complicated. The compounding comes from doing all of them consistently, not from any single one being exceptional.&lt;/p&gt;

&lt;p&gt;Start with the next release.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>career</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to maintain an open source project without burning out</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Sat, 04 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/whatshipped/how-to-maintain-an-open-source-project-without-burning-out-4jl2</link>
      <guid>https://dev.to/whatshipped/how-to-maintain-an-open-source-project-without-burning-out-4jl2</guid>
      <description>&lt;p&gt;Maintaining an open source project is one of the most underrated skills in software development.&lt;/p&gt;

&lt;p&gt;It's not about writing the best code. It's about keeping something alive, useful, and sustainable over time — often with limited energy and an inbox that never stops growing.&lt;/p&gt;

&lt;p&gt;This is what actually works.&lt;/p&gt;




&lt;h2&gt;
  
  
  The #1 mistake new maintainers make
&lt;/h2&gt;

&lt;p&gt;Saying yes to everything.&lt;/p&gt;

&lt;p&gt;Every feature request, every PR, every issue gets a response, a kind explanation, an attempt at accommodation. It feels like good stewardship. In practice, it attracts more of the same, and it's unsustainable within months.&lt;/p&gt;

&lt;p&gt;Scope is a feature. Saying no — clearly and respectfully — is one of the most important skills a maintainer can develop. A project with a clear purpose and explicit boundaries is easier to maintain, easier to contribute to, and more trustworthy to users.&lt;/p&gt;




&lt;h2&gt;
  
  
  A triage system that scales
&lt;/h2&gt;

&lt;p&gt;The feeling of being overwhelmed by issues usually isn't about volume — it's about the issues being unstructured. Triage doesn't resolve things, but it makes the workload feel finite and actionable.&lt;/p&gt;

&lt;p&gt;A minimal label system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bug&lt;/code&gt; — broken behavior, should be fixed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;enhancement&lt;/code&gt; — potential addition, depends on scope&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wontfix&lt;/code&gt; — explicitly out of scope, close with a brief explanation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;good first issue&lt;/code&gt; — low-stakes change, great for new contributors&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;needs-repro&lt;/code&gt; — can't investigate until a reproduction is provided&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;question&lt;/code&gt; — support request, not a bug or feature&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apply labels on first touch. Even if nothing gets resolved immediately, every issue now has a clear status. The backlog stops feeling infinite.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your README is doing more work than you think
&lt;/h2&gt;

&lt;p&gt;A significant portion of maintainer overhead comes from questions that a good README would answer. Installation issues, usage questions, "is this still maintained?" pings — most of these can be eliminated with a clear, up-to-date README.&lt;/p&gt;

&lt;p&gt;The sections worth prioritizing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One-sentence description of what it does&lt;/li&gt;
&lt;li&gt;Quick install / quick start&lt;/li&gt;
&lt;li&gt;Explicit statement of project status (active, maintenance-only, archived)&lt;/li&gt;
&lt;li&gt;Link to CONTRIBUTING.md&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; that explains what kinds of PRs you'll accept — and what's out of scope — filters contributors before they spend time on something you won't merge. It's not unwelcoming. It's respectful of their time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Release often, even for small changes
&lt;/h2&gt;

&lt;p&gt;A project that releases every six weeks looks more alive than one that releases every six months — even if the total code change is equivalent.&lt;/p&gt;

&lt;p&gt;Frequent small releases signal: &lt;em&gt;someone is here, paying attention, and shipping&lt;/em&gt;. That signal matters to users deciding whether to adopt or continue using your project.&lt;/p&gt;

&lt;p&gt;The friction that prevents frequent releases is usually not writing code — it's writing release notes. The fix is maintaining your changelog incrementally, adding entries as you merge changes rather than reconstructing history at release time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Protecting yourself from burnout
&lt;/h2&gt;

&lt;p&gt;Maintainer burnout is well-documented and genuinely common. The pattern: a project gains traction, issues multiply, the maintainer tries to keep up, eventually disappears, and the project either forks or slowly dies.&lt;/p&gt;

&lt;p&gt;Some practices that help:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set response windows.&lt;/strong&gt; Only triage issues on certain days. Off-hours expectations compound into exhaustion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find trusted collaborators early.&lt;/strong&gt; One or two people with merge access distributes the load and reduces the single point of failure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Archive rather than abandon.&lt;/strong&gt; If you need to step away, archiving the project is a clean, honest signal to users. It's better than a repo that looks active but hasn't had a real response in two years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separate identity from the project.&lt;/strong&gt; Your work is valuable. The maintenance burden of a popular project does not scale with how much you care. Boundaries aren't failures.&lt;/p&gt;




&lt;h2&gt;
  
  
  The mindset that separates projects that last
&lt;/h2&gt;

&lt;p&gt;The open source projects that survive long-term tend to share one trait: the maintainer treats it like a product, not a hobby.&lt;/p&gt;

&lt;p&gt;That means intentional scope decisions, regular releases, clear documentation, and honest communication about what the project is and isn't. Not because it's required, but because it makes the whole thing sustainable.&lt;/p&gt;

&lt;p&gt;A changelog is the cheapest version of this signal — it shows users that someone is in charge and paying attention. If you want to generate one from your existing git history, &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; can do it in about a minute. There's 1 free generation to try it.&lt;/p&gt;




&lt;p&gt;Maintaining a project well is hard. It's also one of the most compounding skills you can build — because the habits that make a project sustainable tend to make everything around it better too.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>productivity</category>
      <category>career</category>
      <category>git</category>
    </item>
    <item>
      <title>AI dev tools — what's actually useful and what's just hype</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Fri, 03 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/whatshipped/ai-dev-tools-whats-actually-useful-and-whats-just-hype-di2</link>
      <guid>https://dev.to/whatshipped/ai-dev-tools-whats-actually-useful-and-whats-just-hype-di2</guid>
      <description>&lt;p&gt;There are more AI-powered developer tools launching every week than most people can track. Some of them are genuinely useful. Some are autocomplete with a GPT badge and a $20/month price tag.&lt;/p&gt;

&lt;p&gt;This post is about how to tell the difference — and where AI actually earns its place in a development workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  The hype vs the reality
&lt;/h2&gt;

&lt;p&gt;The marketing version: "AI writes your code for you."&lt;/p&gt;

&lt;p&gt;The actual experience: AI writes &lt;em&gt;a draft&lt;/em&gt; of code that you still need to read, evaluate, test, debug, and maintain. If you can't assess the quality of what it generates, you're not going faster — you're accumulating invisible technical debt.&lt;/p&gt;

&lt;p&gt;This isn't an argument against AI tools. It's an argument for using them with accurate expectations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where AI is genuinely useful in dev workflows
&lt;/h2&gt;

&lt;p&gt;After using these tools seriously for the past couple of years, the pattern that holds up is this: &lt;strong&gt;AI is good at translation and drafting. It's not good at understanding and deciding.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Concrete examples where AI earns its place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Boilerplate&lt;/strong&gt; — repetitive, predictable code (CRUD endpoints, form validation, test stubs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explanation&lt;/strong&gt; — "what does this unfamiliar code do?" is a great AI prompt&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Translation&lt;/strong&gt; — turning intent ("I want to paginate this query") into a working starting point&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Summarization&lt;/strong&gt; — condensing logs, diffs, commit history into human-readable language&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First drafts of tests&lt;/strong&gt; — the structure is usually right, the edge cases need your judgment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread: you know what good looks like, and AI handles the mechanical part of getting there.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where AI fails (and people don't say it enough)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deep codebase knowledge&lt;/strong&gt; — AI has no idea how your specific system is wired together&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architectural decisions&lt;/strong&gt; — AI can propose patterns, but can't weigh long-term consequences for your context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security-sensitive code&lt;/strong&gt; — generated code often &lt;em&gt;looks&lt;/em&gt; correct and isn't. Don't skip review here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tasks where "probably right" isn't enough&lt;/strong&gt; — financial logic, data migrations, auth flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The failure mode isn't dramatic. It's subtle: code that works in tests, passes review, and causes a production incident six months later because the AI pattern didn't account for your specific edge case.&lt;/p&gt;




&lt;h2&gt;
  
  
  The right mental model
&lt;/h2&gt;

&lt;p&gt;The best AI dev tools reduce friction on tasks you already understand, freeing your attention for the parts that require actual judgment.&lt;/p&gt;

&lt;p&gt;Not: &lt;em&gt;"AI will do this for me."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
But: &lt;em&gt;"AI will handle the mechanical part so I can focus on the interesting part."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When a tool is designed around this — augmenting capability rather than replacing judgment — it's usually worth using. When it's designed to skip understanding entirely, it's usually not.&lt;/p&gt;




&lt;h2&gt;
  
  
  A concrete example: generating changelogs
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; to generate changelogs from git history. It's a small but illustrative case.&lt;/p&gt;

&lt;p&gt;The AI doesn't decide what matters. You do. It reads the diff, groups commits by type, and translates technical messages into user-facing language. You get a structured draft in about a minute.&lt;/p&gt;

&lt;p&gt;You still review. You still edit. But the blank-page problem — staring at 40 commits trying to figure out what actually changed for users — is gone.&lt;/p&gt;

&lt;p&gt;That's the pattern: AI eliminates the mechanical friction, human judgment handles the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  The question to ask about any AI dev tool
&lt;/h2&gt;

&lt;p&gt;Before paying for or building around an AI tool, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does this make me faster at things I understand, or does it let me skip understanding things?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If it's the former, it's probably worth it. If it's the latter, the speed is an illusion — and the debt will surface eventually.&lt;/p&gt;




&lt;p&gt;The best AI dev tools don't make you a better developer by doing the work for you. They make you a more effective one by removing the parts of the work that don't require you.&lt;/p&gt;

&lt;p&gt;That's a meaningful distinction. Worth keeping in mind as the space gets more crowded.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The changelog format that actually works (and why most devs get it wrong)</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Thu, 02 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/whatshipped/the-changelog-format-that-actually-works-and-why-most-devs-get-it-wrong-4bh4</link>
      <guid>https://dev.to/whatshipped/the-changelog-format-that-actually-works-and-why-most-devs-get-it-wrong-4bh4</guid>
      <description>&lt;p&gt;There's a 10-year-old document at &lt;a href="https://keepachangelog.com" rel="noopener noreferrer"&gt;keepachangelog.com&lt;/a&gt; that answers most questions about how to write release notes. Most developers have never read it.&lt;/p&gt;

&lt;p&gt;This post is the gist — plus the practical habits that make it stick.&lt;/p&gt;




&lt;h2&gt;
  
  
  The core principle
&lt;/h2&gt;

&lt;p&gt;A changelog is for humans, not machines.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;git log&lt;/code&gt; is a machine-readable (and developer-readable) record of every change. Your changelog is something different: it's for the person deciding whether to upgrade a dependency, update a package, or trust that a bug they hit last month is finally fixed.&lt;/p&gt;

&lt;p&gt;Different audiences. Different documents. Don't conflate them.&lt;/p&gt;




&lt;h2&gt;
  
  
  The format
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://keepachangelog.com" rel="noopener noreferrer"&gt;Keep a Changelog&lt;/a&gt; format has become a de facto standard for good reason — it's simple, scannable, and answers the key question ("should I upgrade?") in under 10 seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## [1.4.0] - 2025-03-28&lt;/span&gt;

&lt;span class="gu"&gt;### Added&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Dark mode support across all views

&lt;span class="gu"&gt;### Fixed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Login failing silently on Safari 16
&lt;span class="p"&gt;-&lt;/span&gt; Session not persisting after password reset

&lt;span class="gu"&gt;### Deprecated&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Legacy XML export endpoint (will be removed in v2.0)

&lt;span class="gu"&gt;### Breaking&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`init()`&lt;/span&gt; now requires a config object instead of positional args
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Added&lt;/strong&gt; — new features your users can use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed&lt;/strong&gt; — bugs that are now resolved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changed&lt;/strong&gt; — behavior changes that don't break existing usage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breaking&lt;/strong&gt; — changes that will break existing integrations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deprecated&lt;/strong&gt; — things that still work but are going away&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removed&lt;/strong&gt; — things that are already gone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; — always call these out explicitly, even for minor patches&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You won't need all of them every release. Pick what applies. Skip the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  The mistake most devs make
&lt;/h2&gt;

&lt;p&gt;Writing changelog entries that describe what &lt;em&gt;you&lt;/em&gt; did, not what &lt;em&gt;changed for the user&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;❌ &lt;code&gt;Refactored auth module to use new token architecture&lt;/code&gt;&lt;br&gt;&lt;br&gt;
✅ &lt;code&gt;Fixed: sessions no longer expire unexpectedly after 30 minutes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Both describe the same change. Only one is useful to someone reading your changelog.&lt;/p&gt;

&lt;p&gt;This is the hardest mental shift, and it's worth internalizing: every entry should be written from the user's perspective. What did they experience before? What do they experience now?&lt;/p&gt;


&lt;h2&gt;
  
  
  The Unreleased section
&lt;/h2&gt;

&lt;p&gt;One of the most underused features of this format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## [Unreleased]&lt;/span&gt;

&lt;span class="gu"&gt;### Added&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Real-time notifications (in progress)

&lt;span class="gu"&gt;### Fixed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Avatar not loading in dark mode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep this section at the top of your &lt;code&gt;CHANGELOG.md&lt;/code&gt;. Add entries to it as you merge pull requests or commit changes. When you cut a release, rename it to the version number and date.&lt;/p&gt;

&lt;p&gt;This way your changelog is always in sync with your work, and writing it never feels like a big catch-up task.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to write the entry
&lt;/h2&gt;

&lt;p&gt;The answer most developers resist: at the same time you write the commit.&lt;/p&gt;

&lt;p&gt;Not after the release. Not during the release prep. During the commit, while the context is fresh.&lt;/p&gt;

&lt;p&gt;It takes 30 seconds. The alternative is staring at &lt;code&gt;git log&lt;/code&gt; a week later trying to reconstruct what you actually changed for the user.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tools that help
&lt;/h2&gt;

&lt;p&gt;If your history is already messy — commits like &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;wip&lt;/code&gt;, &lt;code&gt;final&lt;/code&gt;, &lt;code&gt;ok this time&lt;/code&gt; — or if you just want to reduce the manual work, AI tools can generate a changelog draft from your git history.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; specifically for this: connect your GitHub, GitLab, or Bitbucket repo and get a formatted changelog in about a minute. There's 1 free generation to try it without signing up for anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;A changelog isn't paperwork. It's the cheapest trust signal a maintained project can send.&lt;/p&gt;

&lt;p&gt;Users who can see what changed between versions are more likely to upgrade. They open fewer "is this fixed?" issues. They recommend your project to others.&lt;/p&gt;

&lt;p&gt;The format is simple. The habit is what takes work. Start with the next release.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>git</category>
      <category>productivity</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Write commit messages your future self will thank you for</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Wed, 01 Apr 2026 06:00:00 +0000</pubDate>
      <link>https://dev.to/whatshipped/write-commit-messages-your-future-self-will-thank-you-for-2864</link>
      <guid>https://dev.to/whatshipped/write-commit-messages-your-future-self-will-thank-you-for-2864</guid>
      <description>&lt;p&gt;You know the feeling. You open &lt;code&gt;git log&lt;/code&gt; three weeks after a sprint and see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix
wip
ok
asdf
finally
please work
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have no idea what you were doing. Your changelog is going to be a nightmare. Your coworker's PR review is going to take twice as long.&lt;/p&gt;

&lt;p&gt;This is the commit message problem — and the fix is simpler than you think.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why commit messages matter more than you think
&lt;/h2&gt;

&lt;p&gt;A commit message isn't just a label. It's a unit of communication that travels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Into your &lt;code&gt;git log&lt;/code&gt; and &lt;code&gt;git blame&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Into PR descriptions and code reviews&lt;/li&gt;
&lt;li&gt;Into your changelog and release notes&lt;/li&gt;
&lt;li&gt;Into your team's understanding of &lt;em&gt;why&lt;/em&gt; something exists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When commit messages are bad, everything downstream gets harder. When they're good, a lot of things become almost automatic.&lt;/p&gt;




&lt;h2&gt;
  
  
  The format that works
&lt;/h2&gt;

&lt;p&gt;The simplest improvement you can make is adopting a consistent structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;type&amp;gt;: &amp;lt;what changed, in plain English&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;type&lt;/code&gt; is one of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;feat&lt;/code&gt; — new feature&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fix&lt;/code&gt; — bug fix&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs&lt;/code&gt; — documentation only&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refactor&lt;/code&gt; — no behavior change, just restructuring&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chore&lt;/code&gt; — maintenance, dependency updates&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;breaking&lt;/code&gt; — something that changes existing API or behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Real examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat: add CSV export to dashboard
fix: prevent session expiring early on mobile browsers
refactor: extract auth logic into useAuth hook
chore: upgrade eslint to fix security warning
breaking: rename config.apiKey to config.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are searchable, parseable, and readable six months later.&lt;/p&gt;




&lt;h2&gt;
  
  
  The three questions to ask before committing
&lt;/h2&gt;

&lt;p&gt;Before you type the message, ask yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What does this change for the user?&lt;/strong&gt; Not for you — for them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Would a teammate understand this without context?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Could this become a changelog line as-is?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the answer to all three is yes, you have a good commit message. If not, rewrite until it is.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conventional Commits is worth the 10 minutes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.conventionalcommits.org/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt; is a lightweight spec built around the format above. The benefit of adopting a standard (rather than your own variation) is tooling.&lt;/p&gt;

&lt;p&gt;Semantic versioning tools can bump your version automatically. Changelog generators can group and format entries. CI pipelines can validate messages before merge.&lt;/p&gt;

&lt;p&gt;The spec is simple enough to internalize in one reading. The compounding benefit is significant.&lt;/p&gt;




&lt;h2&gt;
  
  
  The compound effect
&lt;/h2&gt;

&lt;p&gt;Good commits → readable git log → fast PR reviews → easier changelogs → better release notes → users who understand what changed between versions.&lt;/p&gt;

&lt;p&gt;It all starts at the commit message. The earlier in a project you adopt this, the more you get back.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to do if your history is already a mess
&lt;/h2&gt;

&lt;p&gt;Don't backfill. It's not worth the time.&lt;/p&gt;

&lt;p&gt;Just start with the next commit. One good message today is worth more than a weekend of rewriting old ones.&lt;/p&gt;

&lt;p&gt;If you need to generate a changelog from a messy history right now — for a release that's going out this week — tools can help. &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; reads your git history and uses AI to produce a readable changelog even when the commits are rough. There's 1 free generation to try it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The habit
&lt;/h2&gt;

&lt;p&gt;The goal isn't perfection. It's consistency.&lt;/p&gt;

&lt;p&gt;Pick the format. Apply it to the next commit. Then the next. After a week it's automatic, and your future self — and your users — will notice.&lt;/p&gt;

</description>
      <category>git</category>
      <category>opensource</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Why your open source project needs a changelog (and why you keep skipping it)</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Tue, 31 Mar 2026 12:37:17 +0000</pubDate>
      <link>https://dev.to/whatshipped/why-your-open-source-project-needs-a-changelog-and-why-you-keep-skipping-it-155a</link>
      <guid>https://dev.to/whatshipped/why-your-open-source-project-needs-a-changelog-and-why-you-keep-skipping-it-155a</guid>
      <description>&lt;p&gt;You pushed the fix. You tagged the release. You moved on.&lt;/p&gt;

&lt;p&gt;Somewhere, a user is opening an issue asking if the bug you fixed three weeks ago is "still being looked at." Another one stopped updating your package because they can't tell what changed and don't want surprises in production.&lt;/p&gt;

&lt;p&gt;This is the changelog problem — and it's not about discipline.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real cost of no changelog
&lt;/h2&gt;

&lt;p&gt;Most developers know they &lt;em&gt;should&lt;/em&gt; write changelogs. The intention is there. The execution isn't.&lt;/p&gt;

&lt;p&gt;The cost is invisible until it compounds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support issues about things you already fixed&lt;/li&gt;
&lt;li&gt;Users stuck on old versions because updating feels risky&lt;/li&gt;
&lt;li&gt;Contributors who can't tell what's in scope&lt;/li&gt;
&lt;li&gt;Your project looking abandoned even when it isn't&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A changelog doesn't just document history. It communicates trust. It tells users: &lt;em&gt;someone is in charge here, and they're paying attention.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why devs skip it
&lt;/h2&gt;

&lt;p&gt;It's not laziness. It's timing and friction.&lt;/p&gt;

&lt;p&gt;By the time a release is ready, you've been heads-down for hours or days. Writing a changelog means context-switching back into "communicator mode" at exactly the moment your brain wants to move on.&lt;/p&gt;

&lt;p&gt;Add a messy git history — commits like &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;wip&lt;/code&gt;, &lt;code&gt;typo&lt;/code&gt;, &lt;code&gt;ok now&lt;/code&gt;, &lt;code&gt;actually ok now&lt;/code&gt; — and the task feels impossible. Where do you even start?&lt;/p&gt;




&lt;h2&gt;
  
  
  The format that works
&lt;/h2&gt;

&lt;p&gt;Stop thinking of a changelog as documentation. Think of it as a three-question summary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What did users gain? → &lt;strong&gt;Added&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What did you fix? → &lt;strong&gt;Fixed&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What changed that might break things? → &lt;strong&gt;Breaking / Changed&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A good changelog entry looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## [1.4.0] — 2025-03-28&lt;/span&gt;

&lt;span class="gu"&gt;### Added&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Export to CSV from the dashboard

&lt;span class="gu"&gt;### Fixed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Session expiring too early on mobile browsers

&lt;span class="gu"&gt;### Breaking&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`config.apiKey`&lt;/span&gt; renamed to &lt;span class="sb"&gt;`config.key`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's 6 lines. It takes 5 minutes. It answers every question a user might have about upgrading.&lt;/p&gt;




&lt;h2&gt;
  
  
  The "messy commits" problem
&lt;/h2&gt;

&lt;p&gt;Clean commit history helps, but it's not required. The changelog documents &lt;em&gt;user-facing changes&lt;/em&gt;, not your internal process.&lt;/p&gt;

&lt;p&gt;A practical approach:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your last 20–30 commits&lt;/li&gt;
&lt;li&gt;Filter by what a user would actually notice&lt;/li&gt;
&lt;li&gt;Group into Added / Fixed / Changed&lt;/li&gt;
&lt;li&gt;Write one plain-English line per item&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You're translating from developer time to user time. The commit message is for you. The changelog entry is for them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Make it automatic
&lt;/h2&gt;

&lt;p&gt;If you want to reduce the friction to near zero, tools can help. I built &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; specifically for this: connect your GitHub, GitLab, or Bitbucket repo, and it reads your git history to generate a formatted changelog using AI.&lt;/p&gt;

&lt;p&gt;It handles the messy commits. You review and ship.&lt;/p&gt;

&lt;p&gt;There's 1 free generation when you sign up — enough to see if it works for your project before committing to anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start with the next release
&lt;/h2&gt;

&lt;p&gt;You don't need to backfill everything. Pick the next release and write five lines before you tag it.&lt;/p&gt;

&lt;p&gt;That's the habit. Once it's there, users notice. Issues go down. Trust goes up.&lt;/p&gt;

&lt;p&gt;Your code deserves to be understood. A changelog is how that happens.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>productivity</category>
      <category>git</category>
      <category>devtools</category>
    </item>
    <item>
      <title>How to integrate WhatShipped into your project</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Mon, 30 Mar 2026 12:18:06 +0000</pubDate>
      <link>https://dev.to/whatshipped/how-to-integrate-whatshipped-into-your-project-4m9h</link>
      <guid>https://dev.to/whatshipped/how-to-integrate-whatshipped-into-your-project-4m9h</guid>
      <description>&lt;p&gt;You shipped something. Your users have no idea what changed.&lt;/p&gt;

&lt;p&gt;WhatShipped turns your git history into a readable changelog — but the real question is: &lt;strong&gt;how do you actually get that changelog into your product?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's every way you can do it today, and what's coming.&lt;/p&gt;




&lt;h2&gt;
  
  
  The simplest path: Markdown export
&lt;/h2&gt;

&lt;p&gt;Every changelog you generate on &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;WhatShipped&lt;/a&gt; can be exported as a &lt;code&gt;.md&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Drop it in your repo, your docs folder, your Notion workspace — wherever your users look for updates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/your-project
  ├── CHANGELOG.md   ← just paste it here
  ├── src/
  └── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zero friction. Works with any stack, any deployment, any workflow. If you just want &lt;em&gt;something&lt;/em&gt; out the door, this is your path.&lt;/p&gt;




&lt;h2&gt;
  
  
  One step up: the WhatShipped API
&lt;/h2&gt;

&lt;p&gt;Generate your changelog programmatically. Hit the API, get structured output, render it however you want.&lt;/p&gt;

&lt;p&gt;Your design system, your components, your branding. WhatShipped handles the content — you own the presentation.&lt;/p&gt;

&lt;p&gt;A minimal example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://whatshipped.dev/api/v1/release-notes/generate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;provider&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;repoFullName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;owner/repo-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fromRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;v1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toRef&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;v1.1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;versionTag&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;v1.1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;productName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;professional&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;changelog&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get back structured content you can render anywhere — a &lt;code&gt;/changelog&lt;/code&gt; route, a modal, a sidebar widget. Whatever fits your product.&lt;/p&gt;




&lt;h2&gt;
  
  
  A pattern I like for Next.js projects
&lt;/h2&gt;

&lt;p&gt;Here's a concrete integration that works well:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call the WhatShipped API at &lt;strong&gt;build time&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Store the response as a &lt;strong&gt;static JSON file&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Render a &lt;code&gt;/changelog&lt;/code&gt; route from it
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/fetch-changelog.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://whatshipped.dev/api/v1/release-notes/generate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./public/changelog.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/changelog/page.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;changelog&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/public/changelog.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ChangelogPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;changelog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your changelog is always in sync with your latest release. No manual work, no copy-pasting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Coming next: webhooks
&lt;/h2&gt;

&lt;p&gt;The goal is &lt;strong&gt;full automation&lt;/strong&gt; — push to &lt;code&gt;main&lt;/code&gt;, changelog gets generated and delivered wherever you need it.&lt;/p&gt;

&lt;p&gt;The planned webhook flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push → WhatShipped webhook → your endpoint
                                      ↓
                          update your changelog page
                          post to Slack
                          update your docs site
                          ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No human in the loop. The changelog becomes a side effect of shipping, not a task on your to-do list.&lt;/p&gt;

&lt;p&gt;If this would unblock your workflow, &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;let me know&lt;/a&gt; — real demand shapes the roadmap.&lt;/p&gt;




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

&lt;p&gt;👉 &lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;whatshipped.dev&lt;/a&gt; — 1 free generation on signup, no credit card required.&lt;/p&gt;

&lt;p&gt;Connect your GitHub repo, point it at a date range or set of commits, and you'll have a changelog in under a minute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What integration would unblock you the most?&lt;/strong&gt; Drop a comment — I read everything and it directly influences what I build next.&lt;/p&gt;

</description>
      <category>devtools</category>
      <category>webdev</category>
      <category>changelog</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>I built a SaaS for 2 years and never wrote a single changelog. So I automated it.</title>
      <dc:creator>WhatShipped</dc:creator>
      <pubDate>Sun, 29 Mar 2026 08:54:41 +0000</pubDate>
      <link>https://dev.to/whatshipped/i-built-a-saas-for-2-years-and-never-wrote-a-single-changelog-so-i-automated-it-50kj</link>
      <guid>https://dev.to/whatshipped/i-built-a-saas-for-2-years-and-never-wrote-a-single-changelog-so-i-automated-it-50kj</guid>
      <description>&lt;p&gt;Let me be upfront about something embarrassing.&lt;/p&gt;

&lt;p&gt;I've been running Geentoo — a platform for connecting project ideas with co-founders and collaborators — for almost two years. Real users, real features shipped, real bugs fixed.&lt;/p&gt;

&lt;p&gt;And I have never written a changelog. Not once.&lt;br&gt;
Not a release note. Not a "what's new" email. Not even a pinned post saying "hey, here's what changed this month." Nothing.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why though?
&lt;/h2&gt;

&lt;p&gt;It's not that I don't care about communicating with users. I do.&lt;br&gt;
The problem is my git history. Here's a completely honest sample of what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fix
wip
test
ok now it works
PLEASE work
final
final2
ok this is the real final
asdfgh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sound familiar?&lt;br&gt;
Every time I thought "I should write a changelog", I'd open the git log, stare at 300+ commits that looked like the above, and immediately feel exhausted. Then I'd close the terminal and go work on something else.&lt;br&gt;
The gap between raw git history and readable release notes is enormous. You have to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter out the noise (CI runs, version bumps, merge commits, "fix" x47)&lt;/li&gt;
&lt;li&gt;Group related changes into something coherent&lt;/li&gt;
&lt;li&gt;Rewrite everything in plain language your users actually understand&lt;/li&gt;
&lt;li&gt;Do this for every release, forever&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nobody has time for that. So I just never did it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the thing I needed
&lt;/h2&gt;

&lt;p&gt;A few months ago I decided to stop feeling guilty about it and just automate it.&lt;/p&gt;

&lt;p&gt;The idea was simple: connect to a git repo, pick two refs (a tag, a branch, a SHA — anything), fetch the commits in between, and use an LLM to generate structured release notes from them.&lt;/p&gt;

&lt;p&gt;Simple in theory. A few interesting problems in practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  The filtering problem
&lt;/h2&gt;

&lt;p&gt;The first thing I learned: you can't just dump raw commits into an LLM and expect good output.&lt;br&gt;
A typical commit range for a real project contains a lot of noise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Merge commits (&lt;code&gt;Merge branch 'feature/x' into main&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Version bumps (&lt;code&gt;chore: bump version to 2.3.1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;CI/CD commits (&lt;code&gt;ci: update pipeline config&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Dependency updates (&lt;code&gt;update lockfile&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;And of course, the legendary &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;wip&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you feed all of that to an LLM, you get bloated, incoherent output. Garbage in, garbage out.&lt;/p&gt;

&lt;p&gt;So WhatShipped has a filtering layer that runs before the model ever sees anything. Noise commits are stripped out. Where available, PR titles are preferred over raw commit messages — they tend to be much more descriptive and intentional.&lt;/p&gt;

&lt;p&gt;What reaches the LLM is a clean, curated list of meaningful changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The scale problem
&lt;/h2&gt;

&lt;p&gt;Another real issue: large commit ranges.&lt;/p&gt;

&lt;p&gt;If you're generating release notes covering 6 months of work, you might have 500+ commits even after filtering. That's too much to process in a single LLM call reliably.&lt;/p&gt;

&lt;p&gt;WhatShipped chunks the commits and processes them in parallel, then merges the outputs into a single coherent document. This makes it reliable on large ranges without sacrificing speed.&lt;/p&gt;




&lt;h2&gt;
  
  
  The provider problem
&lt;/h2&gt;

&lt;p&gt;I didn't want to be locked into one LLM provider, and I suspected users wouldn't either.&lt;/p&gt;

&lt;p&gt;WhatShipped supports both Claude (Anthropic) and OpenAI. You choose which one generates your notes. Same filtering pipeline, same output format — just different models under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dogfooding it immediately
&lt;/h2&gt;

&lt;p&gt;The first thing I did when the tool was working was run Geentoo's commit history through it.&lt;/p&gt;

&lt;p&gt;Two years of &lt;code&gt;wip&lt;/code&gt; and &lt;code&gt;fix&lt;/code&gt; and &lt;code&gt;ok this is the real final&lt;/code&gt; — turned into structured, readable release notes with sections for new features, bug fixes, and performance improvements.&lt;/p&gt;

&lt;p&gt;It worked. Actually worked, on a real messy project, not a clean toy repo.&lt;/p&gt;

&lt;p&gt;That was the moment I felt confident enough to call it a product.&lt;/p&gt;




&lt;h2&gt;
  
  
  The business model
&lt;/h2&gt;

&lt;p&gt;I didn't want to build another subscription SaaS that charges $20/month for something you might use twice.&lt;/p&gt;

&lt;p&gt;WhatShipped runs on credits. 1 credit = 1 generation. You buy what you need, when you need it.&lt;/p&gt;

&lt;p&gt;New accounts get 1 free credit on signup — no card required. Try it on real repos and see if it's useful before spending anything.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it looks like today
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Connects to GitHub, GitLab and Bitbucket&lt;/li&gt;
&lt;li&gt;Pick any two git refs as your range&lt;/li&gt;
&lt;li&gt;Outputs clean Markdown — ready to paste into your changelog, README, or release page&lt;/li&gt;
&lt;li&gt;Works on messy real-world histories, not just clean conventional commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try it at &lt;strong&gt;&lt;a href="https://whatshipped.dev" rel="noopener noreferrer"&gt;whatshipped.dev&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'm looking for
&lt;/h2&gt;

&lt;p&gt;I'm at the very beginning of this. The product is live, the core flow works, and I'm now focused on getting real users and real feedback.&lt;/p&gt;

&lt;p&gt;If you've ever skipped writing a changelog because your git history was too messy — I'd genuinely love for you to try it and tell me what you think. What's missing, what's confusing, what would make it actually useful for your workflow.&lt;/p&gt;

&lt;p&gt;Every piece of feedback right now is worth more than any feature I could build.&lt;/p&gt;

&lt;p&gt;Thanks for reading 🙏&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>buildinpublic</category>
      <category>devtools</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
