2025: I Shipped 3 OSS Projects — “This Was Actually Fine”
Source: Dev.to
Hi everyone!
I’m a frontend engineer, @nyaomaru.
Recently, for dieting purposes, I’ve been taking walks while carrying a backpack weighing over 10 kg, kind of like Master Roshi’s (Kame‑Sennin) training from Dragon Ball 🐢.
Another year flew by before I noticed it…
It’s already the end of the year.
At the end of the year we have cleaning, shopping, and reflection.
In Japanese, December is called “Shiwasu (師走)”, meaning “even teachers run because they’re so busy.”
As for me, I’ve been running around so much that I feel like a completely worn‑out rag.
Anyway, let’s clean up this year’s mess within this year and organize our thoughts while we’re at it 🧹.
So, I’d like to look back on 2025 from the perspective of the OSS projects I released.
Note: there are no viral success stories here.
🎯 OSS Projects I Released in 2025
This year I released the following three OSS projects:
| Project | Screenshot | Repo |
|---|---|---|
is-kit | ![]() | |
changelog-bot | ![]() | |
divider | ![]() |
I continue maintaining and releasing updates for all of them.
🤔 Why Did I Build Them?
Simply put: because I wanted them myself.
| Project | Motivation |
|---|---|
is-kit | “There must be a cleaner way to write user‑defined type guards…” |
changelog-bot | “Writing CHANGELOG.md every time is honestly annoying…” |
divider | “I just want to split strings more cleanly…” |
Each project started from a small frustration. I asked myself, “How can I remove this discomfort?” and started building.
Of course it’s great when others use your OSS, but my main focus was always: can this solve my own problem properly?
Let’s briefly look back at each project.
is-kit
If you use TypeScript you probably write user‑defined type guards fairly often.
Before is-kit
type User = {
id: string;
age: number;
role: 'admin' | 'guest' | 'trial';
};
function isUser(value: unknown): value is User {
if (typeof value !== 'object' || value === null) return false;
const record = value as Record;
return (
typeof record.id === 'string' &&
typeof record.age === 'number' &&
(record.role === 'admin' ||
record.role === 'guest' ||
record.role === 'trial')
);
}
I kept thinking: “Can’t this be simpler?”
That’s when the idea of LEGO blocks came to mind: compose small logical pieces to build complex guards.
After is-kit
import { struct, isString, isNumber, oneOfValues } from 'is-kit';
const isUser = struct({
id: isString,
age: isNumber,
role: oneOfValues('admin', 'guest', 'trial'),
});
More declarative, more readable, and still type‑safe — sounds nice, right?
You can also compose guards further:
import { and, narrowKeyTo, predicateToRefine } from 'is-kit';
type AdminUser = Readonly & { role: 'admin' };
const byRole = narrowKeyTo(isUser, 'role');
const isAdminUser = byRole('admin');
const isAdultAdmin = and(
isAdminUser,
predicateToRefine((user: AdminUser) => user.age >= 18)
);
What Worked Well with is-kit
- Lots of people checked it out and gave it stars – thank you so much 🙏🙏🙏
- Discovered
tsd, a library for testing TypeScript type definitions, which was genuinely fun to work with. - The API stayed fairly simple, and overall I’m happy with how it turned out.
Planned Improvements
- More primitive presets
- More combinators
- Additional enhancements around
struct
If you like it, feel free to give it a ⭐️!
The goal was never magic — just composability and readability.
changelog-bot
When you release an OSS project you usually write release notes and update CHANGELOG.md.
But… it’s kind of a hassle, right? At least it was for me 🤮
There are tools that generate changelogs from conventional commits, but I wondered:
“Could AI classify changes based on content instead?”
That question led to changelog-bot.
You can use it via CLI with OpenAI or Anthropic API keys (AI is optional).
(Further details omitted for brevity – the original post continues with usage examples, what worked, and future plans.)
Closing Thoughts
2025 was a productive year for my personal OSS toolbox.
Even without viral success, each project solved a real pain point for me, and the community’s feedback kept me motivated.
Here’s to a cleaner, more organized 2026 – both in code and in life! 🎉
Happy cleaning, and happy coding!
CI‑Driven Changelog Updates
It’s mainly designed to run in CI.
Once a release is published, your CHANGELOG.md can be updated automatically.
name: Update Changelog
on:
release:
types: [published]
jobs:
changelog:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: nyaomaru/changelog-bot@v0
with:
changelog-path: CHANGELOG.md
base-branch: main
provider: openai
release-tag: ${{ github.event.release.tag_name }}
release-name: ${{ github.event.release.tag_name }}
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
You can also run it locally via CLI if you want. Details are in the README.
What Worked Well with changelog‑bot
- It completely removed the manual effort of maintaining
CHANGELOG.mdfor my projects. - Releasing became much easier 🚀
- I personally enjoyed designing the preprocessing logic that extracts and scores features before passing data to the AI.
That said, there’s still room for improvement, and contributions are welcome!
One note though:
Writing changelogs became easier. But… life itself didn’t magically become easier.
That part is still under observation.
divider – A Cleaner Way to Slice Strings
Sometimes you end up slicing strings over and over with substring, and it gets messy.
I wanted a cleaner way, so I built divider, which lets you split strings in one shot using indices.
import { divider } from '@nyaomaru/divider';
const [a, b, c] = divider(text, 3, 6);
What I Learned from divider
- A great engineer contributed; I’m truly grateful 🙏
- I learned the basics of OSS hygiene:
CODE_OF_CONDUCT.md,CONTRIBUTING.md,CHANGELOG.md,DEVELOPER.md, etc.
However, there was a clear downside: I couldn’t demonstrate a strong advantage over string.split().
That’s reflected in the number of stars, and honestly, it was a design mistake.
In short, this project was a “useful failure.”
Still, it was a valuable learning experience, and I’m glad I built it.
✨ Goals for 2026
2025 Highlights
- Released OSS projects
- Started writing technical articles
- Moved to the Netherlands 🇳🇱
It was a year full of new challenges.
Looking Ahead to 2026
- Release OSS applications related to DSA
- Publish a small game project
But above all, my main goal is simple:
Don’t burn out. Keep going. 🏃♂️
That applies to OSS, systems, and life itself.
Thank you for reading, and I hope you have a great year ahead.
See you in 2026 🐈


