# Base42 Blog
> Thoughts, stories and ideas.
Public Ghost content for AI and LLM tooling. This file includes a bounded export of public pages first, then recent public posts.
Append `.md` to any post or page URL to get the content in Markdown (for example, `/example-post.md`).
## Pages
### About this site
URL: https://blog.42.mk/about/
Last updated: 2026-06-30T10:12:15.000Z
Base42 Blog is an independent publication launched in June 2026 by Aleksandar Filipovski. If you subscribe today, you'll get full access to the website as well as email newsletters about new content when it's available. Your subscription makes this site possible, and allows Base42 Blog to continue to exist. Thank you!
### Access all areas
By signing up, you'll get access to the full archive of everything that's been published before and everything that's still to come. Your very own private library.
### Fresh content, delivered
Stay up to date with new content sent straight to your inbox! No more worrying about whether you missed something because of a pesky algorithm or news feed.
### Meet people like you
Join a community of other subscribers who share the same interests.
---
### Start your own thing
Enjoying the experience? Get started for free and set up your very own subscription business using [Ghost](https://ghost.org/?ref=blog.42.mk), the same platform that powers this website.
## Posts
### Segment: From a Student Project to an Open-Source Font
URL: https://blog.42.mk/segment-from-a-student-project-to-an-open-source-font/
Last updated: 2026-07-27T12:19:46.000Z
Some projects begin as carefully planned ideas. Others start almost by accident, during a moment of frustration, curiosity, and experimentation.
The font initially then-named Split, belongs to the second group.
The story started exactly ten years ago, during my graphic design studies and a Typography class assignment. The task was to create a font from scratch. Not a fully professional typeface with perfect spacing, kerning, and all the invisible details that make a font truly polished, but an exercise in creativity, observation, consistency, and learning how to work more precisely in Illustrator.
The first font I created for that assignment was called Chinese Teardrop.

It was inspired by calligraphy, handwritten serif letters, and the kind of decorative writing that had always been part of my visual world. Since childhood, I enjoyed practicing beautiful handwriting, creating titles on big sheets of paper, and making school projects look more carefully designed. That interest naturally led me toward a more elegant, decorative, and complicated font style.
Chinese Teardrop was a good starting point because I wanted to recreate the effect of ink when writing handwritten letters. When you write with ink, some parts of the stroke become thicker, while others slowly become thinner. I wanted the font to have that same feeling: a line that changes, breathes, and carries a handmade quality.
The main visual motive of the font came from a simple circle, which I transformed into a teardrop shape. That teardrop became the base element that gave the font its character and connected the letters visually.
Of course, Chinese Teardrop was far from perfect. At the time, I did not have the knowledge, experience, or time to create a fully polished handwritten font. But I wanted to make something unique, something that felt different from the usual student exercises and carried a recognizable visual idea. Looking back, I can see many flaws in it, but I am still proud of the work I put into it, especially the use of the Pen Tool in Illustrator.
It was a detailed and demanding process, especially for a beginner. The letter S was definitely the most difficult one. As our mentors had warned us, it was one of the hardest letters to get right, and I spent around two hours working on that letter alone.
At some point, after a lot of time spent with the Pen Tool and a lot of frustration, I needed a break.
That break became the beginning of something completely different.

While experimenting with Photoshop’s 3D tools and trying out different shapes, I started thinking about letters again. I created a few forms that felt sharp, futuristic, and unexpected. They reminded me of Star Wars, even though that aesthetic was not really part of my usual interests at the time.
Back in Illustrator, I decided to try a technically simpler direction. Instead of curves, serifs, and delicate handwritten details, I started drawing lines, rectangles, and geometric forms. I added a small rectangle to each letter as a visual detail. The letters became sharp, cut, and split in half.
That is how Segment started.
Although it looked very different from my usual style, there was something strangely familiar in it. The font reminded me of the way my mother taught me to write titles in elementary school: tall letters with a narrow structure. That small visual memory from childhood came back naturally while drawing the letters, making the font feel personal even though its style was more technical and futuristic.
Compared to Chinese Teardrop, Segment was created very quickly. With Vikings playing in the background, the main letters were finished in around two hours. The next day, the work continued on Chinese Teardrop, while Split stayed unfinished, with only the letters completed and the numbers left for another time.

At the time, I did not think too much about it. I was simply happy that in a short period, I had explored two completely different typefaces: one elegant, decorative, and inspired by calligraphy, and one sharp, geometric, and futuristic.
Years passed.
Computers changed, jobs changed, and the font remained somewhere in an old folder, almost forgotten.
Then Base42 happened.
During the process of creating the visual identity for Base42, the inspiration came from hackerspaces around the world: their websites, logos, communities, and the visual language around them. That was when Split came back to mind. A font created years earlier, almost accidentally, suddenly felt like it belonged perfectly to the spirit of the space.
There was only one problem: the file was stored on an old laptop that was no longer usable. The laptop case was broken, and repairing it made no sense. In a very hackerspace-like moment, another laptop was found, the old hard drive was placed inside it, and the search for the Split files began.
After an entire Sunday afternoon of searching, the file was finally found.
I opened it again after all those years, finished the numbers 4 and 2, and the Base42 logo was ready.
Three years later, Base42 had grown into a lively community space filled with meetups, workshops, conferences, collaborations, experiments, and people building things together. The font, too, started growing beyond its original student-project form.
Many of you know Dare from the BeerJS community or have seen him at Base42, where he is often involved in different projects and activities. He helped turn Split into a real, usable font and finally gave it the form it had been missing for years. Mila Jovanović, an architecture student who recently joined the Base42 team, continued the work and finished the numbers and s icons. Ilija created the website for the Base42 font, giving it a proper home and making it easier for people to discover and use it.
A big thank you goes to everyone who invested their time, knowledge, and energy into making this font a reality. Split may have started as a student project, but it became an open-source font because people helped shape it, finish it, and bring it to life.
Like everything in Base42, the font is made to be shared. Anyone can use it, modify it, improve it, learn from it, or build something new with it.
Segment started as a break from frustration during a Typography class.
Today, it is part of the visual identity of Base42\.
And from now on, Segment belongs to the community.
**Let’s take a closer look at the font and how you can get it.**
---
## How to get it?
Segment is a display typeface: geometric, tall, narrow, with the small rectangular cut that gives it its name. It is made for headlines, logos, and posters, not for paragraphs of text.
It currently ships 62 glyphs in one weight: A to Z, a to z, and 0 to 9.
- Try it and see every glyph: [42dotmk.github.io/segment](https://42dotmk.github.io/segment/?ref=blog.42.mk)
- Source code: [github.com/42dotmk/segment](https://github.com/42dotmk/segment?ref=blog.42.mk)
- Package: [@42mk/segment](https://www.npmjs.com/package/@42mk/segment?ref=blog.42.mk)
- Download the font files: [latest release](https://github.com/42dotmk/segment/releases/latest?ref=blog.42.mk)
## How to get it, for designers
Go to the [latest release](https://github.com/42dotmk/segment/releases/latest?ref=blog.42.mk) and download segment.ttf. It is right there on the page, no unzipping needed. (The segment-font-v1.0.2.zip next to it holds every format at once, if you want them all.)
- **macOS:** double-click segment.ttf, then click Install Font.
- **Windows:** right-click segment.ttf and choose Install.
- **Linux:** copy segment.ttf into \~/.local/share/fonts/, then run fc-cache -f.
After that, Segment shows up in your font list like any other font: Illustrator, Photoshop, Affinity, InDesign, Word, Canva desktop.
For Figma, install the .ttf first, then use the Figma desktop app, which reads the fonts on your machine directly. If you work in Figma in the browser, you also need to install the Figma Font Helper, otherwise the browser cannot see your local fonts.
One thing to know before you start: Segment has one weight and no italic. If you press the bold or italic button, your design tool will fake it and the letters will not look the way they were drawn. Set size and letter-spacing instead.
## How to get it, for hackers
With npm:
```bash
npm install @42mk/segment
```
```css
@import "@42mk/segment/css";
.title {
font-family: "Segment", sans-serif;
}
```
That import brings the @font-face with it, so nothing else is needed. It also gives you a .segment class you can drop straight on an element.
Straight from a CDN, with no install at all:
```html
```
Self-hosted: the release zip has woff2, woff, ttf, and svg plus a ready-made segment.css. Drop the folder in your project, link the CSS, done.
Or build it from the letters yourself:
```bash
git clone https://github.com/42dotmk/segment.git
cd segment
npm install
npm run build
npm run demo
```
## How to contribute
The font lives on GitHub as a set of editable SVG letters, one file per character, so contributing does not require font software. Draw a letter, export it as an SVG, name it after its character, and open a pull request. The rest is automated.
The most useful thing anyone could add right now is Cyrillic. Segment covers Latin and digits only, so it cannot set Macedonian yet. Punctuation and diacritics are missing too.
Issues and pull requests: [github.com/42dotmk/segment](https://github.com/42dotmk/segment?ref=blog.42.mk).
Segment is released under the SIL Open Font License 1.1, the standard license for open typefaces. Use it, sell work made with it, change it, and pass it on. Just keep the license with the files and give your modified version a different name.
---
The next font we hope to make open-source is Chinese Teardrop. And hopefully, this is only the beginning.
We would love to see more people contribute to the open-source community with Macedonian fonts, because the library of fonts that properly support Macedonian is still very small. Every new font, every improvement, and every shared project helps make our language more visible, more usable, and more present in design and technology.
### From Scam SMS to First Place at the First Blockchain Hackathon in Skopje
URL: https://blog.42.mk/from-scam-sms-to-first-place-at-the-first-blockchain-hackathon-in-skopje/
Last updated: 2026-06-30T11:24:47.000Z
# From Scam SMS to First Place at the First Blockchain Hackathon in Skopje
> How five students built SafeChain to help citizens verify Safe City fines

The win meant a lot to us, of course, but the whole experience meant even more because of the idea, the pressure, the teamwork, and the fact that the problem we worked on was something people around us were actually dealing with.
We are Tamara Stojanoska, Sara Andonovska, Hristina Gjorgjievska and Ognen Mladenovski from FINKI, and Dragan Stojchevski from Brainster Next. Four of us are third-year students, while Sara is in her second year, and our team came together through mutual friends while we were preparing for another hackathon.
We met in the same room, started talking over coffee, shared opinions, compared ideas, and very quickly realized that we worked well together and enjoyed the way each person approached problems. After that first hackathon, joining another one together became the next logical step, so when the Blockchain Skopje Hackathon came around, all of us wanted to take part as the same team again.
## The Idea
Many good solutions start with a real problem that annoys people enough to make them act, and for us that problem started with an SMS message. During the past month, almost everyone in Macedonia received or heard about a message claiming that they had an unpaid fine from the Safe City system, with a link that looked official and created pressure to pay immediately.
The message looked believable enough to confuse people, and with one wrong click, their money could end up in the hands of someone very difficult to trace. In one afternoon, more than 10,000 fake messages were sent, exposing thousands of citizens to fraud in a single wave, and that made us think that simply telling people to “be careful” still leaves too much room for confusion.
So we started looking at the problem from a different angle and asked why citizens should have to guess whether a message is real in the first place. That question became the starting point for SafeChain, a blockchain-based platform built as a direct response to this exact type of scam.
The main rule behind SafeChain is simple: the official message contains only a verification code, while the citizen opens the official platform themselves, enters the code, and sees all the information there. Each fine is stored as an NFT record with a blockchain transaction hash and a cryptographic signature, which makes the record verifiable, secure, and protected from changes.
The citizen can then see the violation photo, fine details, payment options, and digital appeal process in one place, without being pushed toward a suspicious link in a text message. Removing links from official messages removes the main tool used in these scams, and moving verification to one trusted platform makes the process much clearer for ordinary citizens. At the same time, the platform also reduces bureaucracy because payments, appeals, evidence, and records are all connected in one system and can be accessed quickly.
## Building Under Pressure
**We came into the hackathon with a clear problem and a strong idea, while blockchain was a new area for us and something we had to learn quickly during the weekend.** That pressure was difficult, but it also made the experience valuable because we had to understand the technology well enough to use it for a real case, instead of only talking about it in theory.
The bigger challenge was the product itself, because SafeChain is meant for everyday citizens, including people who receive a suspicious SMS and simply want a clear answer about whether they should trust it. Every decision had to be checked from that point of view, because the platform had to look secure, stay simple, and make sense even to someone hearing the word blockchain for the first time.
During those 48 hours, we moved from five people working on separate parts of the same project into a team that trusted each other’s decisions and understood how to divide the work without making it feel divided. Some of us focused more on programming, others worked on the machine learning aspects, while others developed the business plan and presentation, but in practice we all helped each other whenever something needed attention.
That part made a big difference, because the project improved fastest when we listened, challenged ideas in a constructive way, and gave space to the person who had the clearest solution at that moment.
## Technology
The technical foundation of SafeChain was built around one main requirement: the data had to be secure, verifiable, and protected from changes. Each fine is stored on the blockchain as an NFT record, which gives it a permanent and publicly verifiable proof of existence.
On top of that, we built a secure code-verification system, digitally signed PDF appeals, support for card and crypto payments, and a multilingual mobile PWA so citizens can use the platform easily from their phones. All of those features were designed to work as one simple flow, because the technology behind the system matters most when it helps people trust what they are seeing.
The part we are most proud of is the idea of anti-phishing by design, meaning security was built into the process from the beginning and shaped the whole system. SafeChain works because the official communication model itself changes, and when citizens verify information through one trusted platform, scams based on fake payment links lose their power.
## Judges & Winning
We came to the hackathon focused on the problem and on making the solution strong enough to explain clearly in front of the judges. During the Q&A with the mentors, the whole idea became even stronger because they asked practical questions, challenged details, and pushed us to think about what SafeChain would need in a real institutional setting.
That conversation helped us understand that the topic was relevant, the timing was right, and the solution was clear enough for people to immediately understand the value behind it. After the presentation, we could see that the project had reached people in the room because everyone understood the problem from personal experience. When the result was announced, the win became recognition of the idea, but also of the way we had worked through the pressure together.
When our team’s name was called first after 48 hours of stress, coding, fixing problems, preparing the pitch, and running on very little sleep, the first reaction was just silence for a second because all five of us were trying to understand that we had actually won. Then everything came out at once, with laughing, hugging, relief, and that strange mix of exhaustion and excitement that comes after you spend a whole weekend building something with people who care about the same goal.
## Real-World Impact
SafeChain was built for a very ordinary situation: a person receives a text message, feels unsure if it is real, and wants a safe way to check it without risking their money or personal information. That person could be a student, a parent, a grandparent, or anyone who uses a phone and deals with official payments.
The value is also important for institutions, because many public systems still deal with fragmented records, manual processes, slow communication, and declining public trust. SafeChain gives both citizens and institutions a secure and transparent communication channel where every fine, payment, appeal, and piece of evidence can be verified.
We started with traffic violations because the recent scam made that problem urgent and visible, but the same model can also be used for taxes, healthcare, banking, utilities, and other services where people need to know that a message or record is official. For us, SafeChain is a trust infrastructure, built around a simple idea: citizens should have one clear place to verify official information.
## Future Plans
After the hackathon, we finally got some sleep, processed what had happened, and then quickly started thinking about what should come next. SafeChain solves a real problem that people are facing right now, which makes it difficult to treat it only as a hackathon project or a trophy on a shelf.
We are open to partners, collaborators, institutions, and anyone who sees the same potential in the idea. Six months from now, we want SafeChain to be used in practice and supported by the right partners, because the platform is live, tested, and already built to protect people from this kind of fraud.
The project started during a hackathon, but the problem is happening in real life right now, and that is why we want to push SafeChain beyond the competition stage.
## Personal Reflection
What surprised us most was how much we changed as a team while trying to make the project work. In 48 hours, we learned how to think faster, make decisions with limited time, explain our ideas clearly, trust each other under pressure, and stay calm enough to fix problems when they appeared.
The blockchain, the platform, and the win are all important to us, but the way we worked together is the part we will carry into everything we do next. To anyone thinking about joining a hackathon, our advice is simple: go with people you respect, choose a problem that actually matters to you, and give yourself fully to the process.
A trophy is great, but the real value comes from building something useful with people who make the hard parts easier.
"***Don't come in trying to win. Come in trying to solve something. The trophy follows the purpose, never the other way around.***" - quote from the team.

### Representing Macedonia at the Robotics Olympics:
URL: https://blog.42.mk/representing-macedonia-at-the-robotics-olympics/
Last updated: 2026-06-30T11:25:14.000Z
# Representing Macedonia at the Robotics Olympics:
> Meet The National Team by Jakov Spirovski

Every year, as the competition season rolls around, the excitement in our workspace is impossible to ignore. We are the team that represents Macedonia on the biggest robotics stage in the world. As a closely connected group of mentors and 14 to 18 year old students, we carry a unique kind of weight on our shoulders, the responsibility of showcasing our country’s talent, innovation, and culture to the rest of the globe.
But if you were to walk into one of our build sessions, you probably would not see a tense or highly stressed environment. As a team, we purposely keep things relaxed and outgoing. We strongly believe that prioritizing team chemistry is the secret ingredient to a good robot. When everyone feels comfortable and supported, creativity has the space it needs to truly grow. Guiding all of this is Jakov, our main organizer and the official partner with FIRST Global in Macedonia, who leads the charge in bringing the national team together and turning these big ideas into reality.

### **What is FIRST Global?**
If you are not familiar with FIRST Global, the easiest way to picture it is as the Olympic Games for robotics.
It is a massive, annual international robotics challenge that brings together high school students from over 190 countries. But it is about much more than just wires, motors, and code. FIRST Global is designed to start a passion for Science, Technology, Engineering, and Mathematics (STEM) across the world, framing these fields as the ultimate tools for solving global issues. Instead of a traditional open tournament, the competition is built around a 3v3 alliance format. This means we constantly have to team up, communicate, and strategize with other nations to win matches.

### **FGC Panama 2025 Experience**
Our time competing in Panama was, simply put, unforgettable. It was a beautiful mixing of cultures in the best way possible.
Having the chance to meet people from over 190 different countries completely changes how you see the world. We spent a ton of time hanging out and swapping stories with Team Norway, proving that robotics is just as much about building international friendships as it is about engineering. We also learned so much just by talking with other teams about how they built their robots and solved the same problems we were facing.
When it came time to hit the arena, Panama was our opportunity to showcase everything we had worked so hard on back home. We were incredibly proud to secure 32nd place in the individual rankings against a massive and highly competitive global field. On top of our performance in the arena, we also took home two major honors: the Social Media Award and the Cinematic Video Award. The entire event was an amazing mix of diverse cultures, late night strategy sessions, and very important lessons that we have carried forward into our current designs.


### **Biggest Achievements so Far**
While Panama was a fantastic showing for our media and individual ranking, our most significant competitive achievement to date happened at the Geneva 2022 FIRST Global Challenge.
Because the matches are always 3v3, your ability to collaborate with your alliance partners is just as important as the robot you built. You have to make quick decisions and trust each other completely. In Geneva, everything clicked perfectly. We fought our way to securing 3rd place overall as an alliance. Standing on that podium and knowing our team had played a critical role in one of the top three alliances in the entire world was an amazing milestone. It proved that a small team from Macedonia can compete with the absolute best, and it remains our proudest achievement.

### **Our Struggles with Sponsorships**
Getting to that global stage, however, is not easy. And right now, we are facing a reality that many local tech projects struggle with a lack of resources.
As we gear up for the 2026 FIRST Global Challenge in South Korea, any kind of financial support or sponsorship will help us out a great deal. When people hear the word sponsorship, they often think of plane tickets, but our actual needs hit much closer to home. We need funding for the fundamental preparations. Building a robot from scratch requires specific materials, components, to help us recreate and build the playing field. We also need a dedicated and equipped space to actually build and test our robot safely.
We are proudly carrying the Macedonian flag on a world stage, proving that our youth can compete with the best engineers from across the globe. But doing this with very little backing is incredibly difficult. We believe our country's talent deserves the right tools to succeed.
### **Looking Forward**
Our goals do not stop when the international competitions end. We have a clear, long term vision for the future of robotics right here at home.
Ultimately, we want to implement the FIRST Tech Challenge in Macedonia. By establishing local competitions, we can give countless more students the chance to experience the thrill of building a robot and solving complex problems. Beyond that, our ultimate goal is to grow into the central hub for STEM and robotics in the country. We want to be the place where the next generation of Macedonian innovators gets their start.
We have the talent, the chemistry, and the drive. Now, we are just looking for the partners who want to help us build the future.
If you are interested in supporting our journey, contact us via email or any of our social media platforms, and you might as well check out our website, while you are still here!
Socials:
INSTAGRAM: @fgc.macedonia
EMAIL: [firstglobalmacedonia@gmail.com](mailto:firstglobalmacedonia@gmail.com)
Facebook: @fgcmacedonia
[https://firstglobal.mk/](https://firstglobal.mk/?ref=blog.42.mk)
### From College Friends to CASSINI Winners:
URL: https://blog.42.mk/from-college-friends-to-cassini-winners/
Last updated: 2026-06-30T11:24:45.000Z
# From College Friends to CASSINI Winners:
> The Story Behind CodeLeap’s Red Tide Solution

Winning the local CASSINI Hackathon still feels surreal to us. The whole experience was a mix of confidence and euphoria that still hasn’t completely worn off.
Our story as a team started back in our first year of college. Three of us, Jakov, Darko, and Bojan, signed up for the CodeFu hackathon because we were competitive and wanted to try something outside the classroom. We thought, why not? A week later, we ended up winning third place, and after that we got completely hooked on hackathons.
As time passed, our team grew from three people to five when Filip and Nikita joined. For CASSINI, we wanted to build a team with as many different perspectives as possible, so we also invited Simona and Teona to join us. Having people from different fields helped us approach problems from multiple angles and rely on each other’s expertise throughout the competition.
For the hackathon itself, we decided to tackle the challenge of tracking and preventing water pollution. While brainstorming different ideas, our medical expert introduced us to the concept of Red Tide, and immediately we knew we wanted to build something around it. What drew us to the idea was the fact that it was unique and barely anyone else was talking about it.
Our solution combined satellite data with an IoT device to predict algae blooms before they became dangerous. We used publicly available Copernicus satellite data, specifically oxygen and chlorophyll concentrations, and processed them through machine learning models that calculated the probability of algae blooms forming and reaching shorelines. We also designed the system to help hospitals, insurance companies, and local businesses prepare early and minimize damage before the situation escalated.
We felt from the start that other teams probably wouldn’t approach the challenge this way. Most people didn’t even know what Red Tide was, and we were also the only team using an IoT device alongside satellite data.
One of the hardest parts during the 48 hours was managing our time. We were balancing research, development, business planning, and preparing the final presentation all at the same time. At one point during the hackathon, we also discovered that similar solutions already existed in several European countries. For a moment, that stressed us out, but after researching more deeply, we realized our approach was still different enough because of the way we combined technologies and focused on predictive impact analysis.
Everyone on the team had a specific role. Our medical expert helped shape the idea and focused on the human impact behind the project. The business side worked on profitability and the business plan. The engineering team handled the machine learning models and IoT device, while the computer science side focused on the software and connecting all the parts into one working system.
What helped us most as a team was the fact that everyone contributed with their own knowledge and skills. Whenever disagreements came up, we tried to solve them by talking things through and looking at the problem from every possible perspective.
Beyond the technical side, the biggest goal of our project was raising awareness about Red Tide and the danger it poses to marine life, animals, businesses, and people living near affected areas. We believe the product could help hospitals, tourism businesses, farmers, insurance companies, and many other industries react faster and reduce potential losses.
Right now, we still don’t know if we’ll continue building the project, but if the opportunity comes up again, we’d definitely love to continue working on it.
The hackathon taught us much more than just technical skills. We learned teamwork, communication, adaptability, fast decision making, and how to work under pressure. At the same time, we also learned a huge amount about Red Tide itself from biological, technical, and economic perspectives.
One thing that genuinely surprised us was the atmosphere between teams. Everyone was encouraging each other and sharing knowledge. There was a lot of support throughout the event, and every team learned something from the others.
For students thinking about joining hackathons like CASSINI, our advice is simple. As a college student, it’s easy to focus only on academics, but experiences like this help you grow in completely different ways. You learn how to think like an engineer, work with people, solve real problems, and push yourself outside your comfort zone.
That’s one of the best ways to grow as a person.
And if we had to leave one final message, it would be this:
> “Innovation doesn’t happen because of a single person. It’s the direct result of people coming together to solve a problem they’re all tired of carrying. When everyone feels the weight of the same struggle, that’s when the real work starts.” — CodeLeap
### How We Won ETHGlobal with a Project Called “Shawarma Orchestrate”
URL: https://blog.42.mk/how-we-won-ethglobal-with-a-project-called-shawarma-orchestrate/
Last updated: 2026-06-30T11:24:49.000Z
# How We Won ETHGlobal with a Project Called “Shawarma Orchestrate”

# **How We Won ETHGlobal with a Project Called “Shawarma Orchestrate”**
It all started in a pretty normal way, sitting at a lecture in Skopje about zero-knowledge proofs, not really expecting anything life-changing, when the speaker, Jordan Stojanovski, casually mentioned that he’s “retired” and now just spends his time going to hackathons around the world. That one sentence stuck in our heads longer than anything else from the talk, and at some point the idea just came up naturally—why don’t we try one ourselves?
We didn’t spend too much time overthinking it, and since ETHGlobal is one of the biggest names in the space, we figured it made sense to jump straight into something serious instead of easing into smaller events.
The team itself came together pretty organically, since most of us already knew each other in some way, even though we had never actually worked as a full team before. Three of us are based in Skopje, and Andrea, who’s from Italy, is an old friend and former colleague, so there was already some level of trust and understanding before we even started building anything.
Everyone had a slightly different path into blockchain, which actually helped a lot once we got into the hackathon. Dushan had been exploring things on his own, building small projects and learning step by step while studying at FCSE and working as a full stack developer. Oliver brought a mix of design and engineering experience, especially from working on DeFi products, which made a big difference when it came to making things look clean and usable. Gorjan started out through trading and gradually moved deeper into the technical side, getting into smart contracts, automation, and more advanced topics like MEV and high-frequency trading strategies. Andrea added another layer with his background in both economics and software engineering, along with experience in Web3 and hackathons, which gave the team a bit more direction when things got intense.
Going into the hackathon, we already had a rough idea in mind, something related to market research and automation, although once the event started it quickly evolved into something more practical and more interesting to build within such a short timeframe. That’s how we ended up with a multi-agent system for DeFi, where instead of relying on a single bot or script, multiple agents work together, analyze information, and collectively decide whether an action should be taken.
We didn’t really sit down and choose the 0G track in a strategic way, it just happened naturally since their compute and storage solutions fit perfectly with what we were trying to build, so we leaned into that without forcing anything.
The name of the project is probably the least serious part of the whole story, since it came up completely randomly while we were creating the repository. Someone said “shawarma,” someone else added “orchestrate,” partly inspired by Andrea, and we just went with it without thinking too much, which somehow led to a project with one of the most unserious names winning first place.
When it comes to what we actually built, the idea sounds complex on the surface, although the core concept is quite simple once you look at it from the right angle, since everything revolves around coordination instead of a single smart component trying to do everything alone. Each agent in the system runs in a loop where it observes the current state, decides what to do next, uses tools if needed, and then feeds the result back into the system, which creates a continuous cycle of reasoning instead of a one-time response.
The orchestration layer sits on top of that and is built using a graph-based approach, where flows define how agents move through different steps, and a supervisor component keeps everything aligned by deciding what happens next, reusing context when needed, and shaping the final outcome. This supervisor acts like a coordinator that prevents the system from drifting and makes sure all parts are working toward the same goal.
On the backend side, we kept things simple in structure so we could move fast, using Node.js with TypeScript and a plain HTTP server, although the logic itself became quite layered. The system exposes endpoints for running agents, handling approvals, discovering providers, and even integrating with Telegram so that you can interact with it outside the main interface. At the same time, updates are streamed in real time using server-sent events, so you can actually see what the system is doing instead of waiting for a final result.
For the AI part, everything runs through 0G Compute using an OpenAI-compatible setup, with an additional layer that handles request routing and processing behind the scenes. Storage is handled separately through 0G as well, where results are uploaded dynamically, which fits nicely with the way the system produces data during execution.
One of the more interesting parts is how agents interact with tools, since every tool is defined with a clear structure, which means agents operate within known boundaries instead of making random calls. When outputs become too large, they are summarized and fed back into the system, which keeps everything running smoothly without losing important information.
The final decision-making step is based on a voting system, where multiple agents contribute their opinion, and only when enough of them agree does the system move forward. This makes the outcome more reliable, since it avoids relying on a single perspective. Once a decision is made, the system can actually execute actions, like performing trades through Uniswap, which turns it from an idea into something that can interact with real-world systems.
On top of everything, we built a frontend in React that visualizes the workflow, so instead of trying to explain the system with words, you can actually see how agents move, think, and interact, which made a big difference during the demo.
The hackathon itself had a really good atmosphere, with people being open and easy to talk to, whether they were other participants or sponsors, which made the whole experience feel more like a shared building environment than a strict competition. We managed to get a bit of sleep each night, around four to five hours, which felt like a good balance between staying productive and not completely losing energy.
At no point during the event did we seriously think we were going to win, since the focus was mostly on building something that works, making it look clean, and being able to explain it clearly.
Finding out that we actually won happened in a way that matched the rest of the experience, slightly chaotic and completely unexpected. Andrea was watching the livestream and realized what happened, although in the process he missed his train stop and almost missed his flight, while the rest of us were trying to figure out a ticket machine in France. Somewhere in the middle of that, we got the message that we had taken first place, and it didn’t really feel real at the time.
Looking back, a big reason the project stood out is probably that it was fully working and accessible, with a clean interface and a clear demo, so it wasn’t just an idea, it was something people could actually try and understand.
---
## **So how does it actually work?**
If you ignore all the technical details and just look at the big picture, the system works like a loop where agents think, share information, and slowly move toward a decision together.
It starts with a shared state, which holds everything the system knows at that moment, and each agent looks at that state and decides what to do next, whether that means pulling market data, analyzing trends, or checking risk. Since each agent focuses on a different angle, the system ends up exploring the problem more deeply than a single agent would.
As agents produce results, a supervisor component coordinates everything, deciding which step comes next and making sure the process stays on track, while also combining outputs into something meaningful.
Once enough information is gathered, the system moves into a decision phase where agents effectively vote, and only if the combined result passes a certain threshold does the system take action.
At that point, execution happens, which can include real operations like trades, while results are stored and streamed to the interface so everything is visible in real time.
---
## **Why this approach matters**
What makes this interesting is not just that it works, although the way it works, since instead of building one very smart agent, we focused on coordination between multiple agents, which opens the door to more flexible and reliable systems.
It’s a small step, although it points toward a future where systems are less about single outputs and more about structured collaboration between different components.
---
## **Final thoughts**
The biggest lesson from all of this is how important it is to have a team that works well together, especially in an environment where time is limited and pressure is high, since good collaboration makes everything easier.
We also realized how large and active the builder community is, with many people creating things simply because they enjoy it, which makes the whole space feel more open and motivating.
As for what’s next, we’re still figuring it out, although this experience definitely made us want to keep going, join more hackathons, and continue building.
If there’s one simple piece of advice we would give, it’s to choose your team carefully and enjoy the process, since that combination tends to lead to the best outcomes.
### Migrating from Next.js to SolidStart: An Opinionated Guide
URL: https://blog.42.mk/migrating-from-next-js-to-solidstart-an-opinionated-guide/
Last updated: 2026-06-30T11:24:55.000Z
# Migrating from Next.js to SolidStart: An Opinionated Guide
> A practical guide to migrating from Next.js to SolidStart — focusing on the primitives, the mental model shift, and why it might be worth your time.

If you're looking for alternatives to Next.js - whether for ideological, practical, or curiosity-driven reasons - I think SolidStart is one of the best options out there. SolidStart is to [SolidJS](https://www.solidjs.com/?ref=blog.42.mk) what Next.js is to React: the metaframework that adds routing, SSR, server functions, and deployment on top of the UI library. This guide covers both layers - the primitives and the metaframework - so you can evaluate whether it's the right move.
But first, the elephant in the room: **Solid is not React.** It *looks* like React, and that's both a blessing and a trap.
## The one thing you need to internalize
> **In Solid, the component function is a constructor, not a render function.**
In React, your component function re-runs on every state change. Every. Single. Time. Hooks, variables, derived values - all re-evaluated. In Solid, the component function runs **once**. It sets things up, wires the reactive graph together, and never runs again. All subsequent updates happen through signal subscriptions that surgically update the specific DOM nodes that care about the change.
Once you truly get this, every other difference clicks into place. Signals are getter functions because you need *live references*. Effects auto-track because they subscribe at call-time. Props can't be destructured because that reads values eagerly outside a tracking scope. `` and `` exist because there's no virtual DOM to diff.
Let that sink in. Now let's get practical.
---
## Solid vs. React: the primitives
On the surface, Solid and React feel similar - which is a good thing if you're coming from React land. Both use [JSX](https://en.wikipedia.org/wiki/JavaScript%5FXML?ref=blog.42.mk) to output HTML. But the similarities are surface-level. How they handle state, effects, iteration, conditional rendering, and lifecycle is fundamentally different.
Let's go through each, side by side.
### 1\. State: `useState` vs `createSignal`
**React:**
```
function Counter() {
// This entire function re-runs on every setCount call
const [count, setCount] = useState(0);
console.log("rendered"); // fires every time
return ;
}
```
**Solid:**
```
function Counter() {
// This function runs ONCE
const [count, setCount] = createSignal(0);
console.log("setup"); // fires exactly once
return ;
}
```
The gotcha that'll bite you first: `count` **is a function in Solid.** You call `count()` to read the value. Writing `{count}` without the parentheses will render the function reference itself - not the number. This is, by far, the most common mistake React developers make when starting with Solid.
### 2\. Effects: `useEffect` vs `createEffect`
React requires you to manually declare dependencies. Solid tracks them automatically.
**React:**
```
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
fetchUser(userId).then(data => {
if (!cancelled) setUser(data);
});
return () => { cancelled = true; }; // cleanup via return
}, [userId]); // manual deps - forget this and you have a bug
return
;
}
```
Key differences to watch for:
- **No deps array.** Solid tracks what you read inside the effect automatically. If it reads `props.userId`, it re-runs when that changes. Period.
- **Cleanup uses** `onCleanup()`**,** not a return value. Import it from `solid-js`.
- **No empty deps array pattern.** In React, `useEffect(() => {...}, [])` means "run once on mount." In Solid, use `onMount()` for that.
- **Timing is different.** `createEffect` runs synchronously after the reactive graph updates - closer in spirit to React's `useLayoutEffect` than `useEffect`, though the exact timing relative to browser paint depends on when the signal change was triggered. If you need explicit dependency control, Solid has `on()`:
```
import { on } from "solid-js";
createEffect(on(count, (value, prev) => {
console.log("count changed from", prev, "to", value);
}));
```
### 3\. Memos: `useMemo` vs `createMemo`
React's `useMemo` is [a performance optimization, not a semantic guarantee](https://react.dev/reference/react/useMemo?ref=blog.42.mk) \- React may discard cached values. Solid's `createMemo` is a reactive primitive that creates a derived signal. It's guaranteed to be lazy and cached.
**React:**
```
function FilteredList({ items, filter }) {
const filtered = useMemo(
() => items.filter(i => i.category === filter),
[items, filter]
);
return
;
}
```
Same deal: `createMemo` returns a getter function - call `filtered()`, not `filtered`.
### 4\. Conditional rendering: ternaries vs ``
In React, ternaries work because the virtual DOM diffs everything anyway - it papers over the cost for you. In Solid, there's no virtual DOM hiding that cost. Raw ternaries can cause DOM nodes to be torn down and recreated on every toggle. `` gives you efficient conditional rendering without the diffing overhead.
**React:**
```
function Greeting({ user }) {
return (
{user ? (
Welcome back, {user.name}!
) : (
Please sign in.
)}
);
}
```
**Solid:**
```
function Greeting(props) {
return (
Please sign in.}>
{(user) =>
Welcome back, {user().name}!
}
);
}
```
The callback child form `{(user) => ...}` gives you a narrowed, guaranteed-truthy value. But note: `user` is a getter function in Solid, hence `user().name`.
For multiple conditions, `` / `` is your friend:
```
Not found
}>
```
### 5\. List rendering: `.map()` vs ``
In React, `.map()` recreates the virtual DOM array every render, then diffs with keys. In Solid, `` tracks each item by reference - only affected DOM nodes get created, moved, or removed.
**React:**
```
function TodoList({ todos }) {
return (
{todos.map(todo => (
{todo.text}
))}
);
}
```
**Solid:**
```
function TodoList(props) {
return (
{(todo, index) =>
{todo.text}
}
);
}
```
A couple of things:
- **No** `key` **prop needed.** `` tracks by reference automatically.
- `index` **is a signal.** Call `index()` to get the number. The item itself (`todo`) is *not* a signal - it's the raw value.
- Using `.map()` in Solid *works* \- it won't crash your app - but it creates a non-keyed list that re-renders everything on every update. Essentially, it makes Solid behave like a slow React app (and if you do, I have questions). `` is the correct tool for the job.
### 6\. Refs: `useRef` vs… just a variable
This one's refreshingly simple.
**React:**
```
function AutoFocus() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return ;
}
```
**Solid:**
```
function AutoFocus() {
let inputRef;
onMount(() => {
inputRef.focus(); // no .current - it IS the element
});
return ;
}
```
No `.current` indirection. No hook. Just a variable. Since Solid components run once, a plain `let` persists for the component's lifetime. This also means you don't need `useRef` as a "mutable box" - any `let` variable already serves that purpose.
### 7\. Props: the destructuring trap
This is the gotcha that bites hardest, because it works perfectly in React.
**React - destructuring is totally safe:**
```
function Greeting({ name, age }) {
return
{name} is {age} years old
;
}
```
**Solid - destructuring BREAKS reactivity:**
```
// BAD - values captured once, never update
function Greeting({ name, age }) {
return
{name} is {age} years old
;
}
// GOOD - reactive access through the props proxy
function Greeting(props) {
return
{props.name} is {props.age} years old
;
}
```
Why? Solid props are a Proxy. Accessing `props.name` inside JSX creates a reactive subscription. Destructuring eagerly reads the values during component setup (which runs once), severing the reactive connection forever.
When you need defaults or to split props for forwarding, use `mergeProps` and `splitProps`:
```
import { splitProps, mergeProps } from "solid-js";
function Button(props) {
const merged = mergeProps({ variant: "primary", size: "md" }, props);
const [local, rest] = splitProps(merged, ["variant", "size"]);
return (
);
}
```
### 8\. Building your own primitives
This is where Solid's "primitives, not frameworks" philosophy really pays off. In React, custom hooks are functions that call other hooks - but they re-run on every render, so you're always thinking about memoization and stale closures. In Solid, a custom primitive is just a function that wires up signals - it runs once, and the reactive graph handles the rest.
Here's a practical example: a `createFetch` primitive that handles loading, error, success, and data states.
```
import { createSignal, createEffect, onCleanup } from "solid-js";
function createFetch(urlFn) {
const [data, setData] = createSignal(null);
const [error, setError] = createSignal(null);
const [loading, setLoading] = createSignal(true);
createEffect(() => {
const url = urlFn(); // tracked - re-runs when URL changes
const controller = new AbortController();
setLoading(true);
setError(null);
fetch(url, { signal: controller.signal })
.then((res) => {
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json();
})
.then((json) => {
setData(() => json);
setLoading(false);
})
.catch((err) => {
if (err.name !== "AbortError") {
setError(() => err);
setLoading(false);
}
});
onCleanup(() => controller.abort());
});
return { data, error, loading };
}
```
Use it in a component:
```
function UserProfile(props) {
const { data, error, loading } = createFetch(
() => `/api/users/${props.userId}`
);
return (
Error: {error().message}
{/* data() is the resolved JSON */}
{data().name}
{data().email}
);
}
```
Notice what's *not* here: no dependency arrays, no memoization, no stale closure bugs. The URL is a getter function (`urlFn()`), so it's tracked automatically. When `props.userId` changes, the effect re-runs, the previous request is aborted, and the new one fires. All of this wired up in a reusable primitive that composes like a building block.
This is the pattern you'll reach for constantly in Solid - extract reactive logic into composable primitives that return signals. The [Solid Primitives](https://primitives.solidjs.community/?ref=blog.42.mk) community library is built entirely on this idea.
---
## Quick reference cheat sheet
| Concept | React | Solid | Gotcha |
| ------------ | ------------------------------- | ----------------------------------- | ------------------------------------ |
| State | const \[v, setV\] = useState(0) | const \[v, setV\] = createSignal(0) | v() not v |
| Effects | useEffect(() => {}, \[deps\]) | createEffect(() => {}) | No deps array; onCleanup for cleanup |
| Memo | useMemo(() => x, \[deps\]) | createMemo(() => x) | Returns getter: memo() |
| Refs | useRef(null) \+ .current | let ref; | No .current |
| Conditionals | {cond ? : } | ... | Callback child for narrowing |
| Lists | arr.map(x => ) | {x => } | No key; index is a signal |
| Props | Destructure freely | **Never destructure** | Use splitProps / mergeProps |
| Component fn | Re-runs every render | Runs once | Derived values need () => wrapper |
---
## Next.js vs SolidStart: the metaframework layer
With the primitives covered, let's zoom out. You're not just migrating from React to Solid - you're migrating from Next.js to SolidStart. That means routing, SSR, server-side code execution, API endpoints, data fetching, and all the other metaframework concerns. This is the part where I could just give you a table and call it a day. But some of these differences are subtle enough so that it warrants drawing a clearer line between the two.
### Routing
Both frameworks use file-based routing, but the conventions differ.
**Next.js (App Router):**
```
app/
page.tsx → /
blog/
page.tsx → /blog
[slug]/
page.tsx → /blog/:slug
(marketing)/
about/
page.tsx → /about
layout.tsx → root layout
loading.tsx → loading UI
error.tsx → error boundary
```
Next.js uses special file conventions - `page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx` \- each with specific roles. Route groups use parentheses `(group)`. Layouts are implicit: a `layout.tsx` wraps all pages in its directory and below. Dynamic segments use `[param]`, catch-all uses `[...param]`.
**SolidStart:**
```
routes/
index.tsx → /
blog/
index.tsx → /blog
[slug].tsx → /blog/:slug
about.tsx → /about
blog.tsx → layout for /blog/*
```
SolidStart keeps it simpler. A file's name *is* the route - no `page.tsx` convention. Dynamic segments use `[param]`, optional params use `[[param]]`, catch-all uses `[...param]`. Layouts work by naming a file the same as a directory - `blog.tsx` alongside a `blog/` folder makes `blog.tsx` the layout. Child routes render via `props.children`:
```
// routes/blog.tsx - layout for all /blog/* routes
export default function BlogLayout(props) {
return (
{props.children}
);
}
```
Route groups use parentheses `(group)/`, same idea as Next.js - directories wrapped in `()` that organize routes without affecting URL structure.
**The key difference:** Next.js has more special files with implicit behavior (loading states, error boundaries, not-found pages are all file-convention driven). SolidStart gives you the routing structure and lets you compose ``, ``, and `` yourself. Fewer conventions to memorize, more explicit control. 8/10 physicians agree that less magic in your code can have a positive impact on one's mental health.
### SSR and rendering modes
**Next.js** gives you a buffet of rendering strategies:
- **Static (SSG)** \- pages pre-rendered at build time
- **Server-side (SSR)** \- rendered on each request
- **Incremental Static Regeneration (ISR)** \- static pages that revalidate after a set time
- **Partial Pre-rendering (PPR)** \- static shell with streaming dynamic holes (React 19.2)
- **React Server Components** \- components that run on the server and ship zero client JS
The rendering mode is determined by what you do in the component. Use `"use cache"`? Cached. Read `cookies()` or `headers()`? Dynamic. Five rendering strategies, and you don't pick one - the framework infers it from your code. What could possibly go wrong.
**SolidStart** is more straightforward:
- **SSR is on by default** (`ssr: true`). Every route is server-rendered.
- **SSG/prerendering** is opt-in via config:
```
// app.config.ts
export default defineConfig({
server: {
prerender: {
routes: ["/", "/about"],
// or: crawlLinks: true
},
},
});
```
- **SPA mode** if you want it: `ssr: false`.
- Streaming SSR is supported out of the box - `` boundaries become streaming boundaries automatically.
No ISR, no PPR, no implicit mode switching. You pick a mode and that's what you get. If you need per-route control, you handle it with server functions and caching primitives, not framework magic.
### Server-side code execution
This is where the philosophies diverge most.
**Next.js** has three main mechanisms for running code on the server:
1. Server Components (the default in App Router) - your component function runs on the server. It can await data, touch the filesystem, query databases. The rendered output streams to the client as RSC Flight payload. The client never sees the component's JavaScript.
```
// This is a Server Component by default
async function ProductPage({ params }) {
const { id } = await params;
const product = await db.products.find(id);
return ;
}
```
1. Server Actions - functions marked with "use server" that handle mutations. Invoked from forms or client code, executed on the server.
```
"use server";
export async function addToCart(formData) {
const productId = formData.get("productId");
await db.cart.add(productId);
revalidatePath("/cart");
}
```
1. Route Handlers - traditional API endpoints in app/api/\*/route.ts files.
The boundary between server and client is managed by directives: `"use client"` marks a component as client-side, `"use server"` marks a function as server-only. The mental model of *what runs where* is the number one source of confusion in the App Router, per community surveys.
**SolidStart** uses a single, consistent mechanism: **server functions.**
Any function annotated with `"use server"` runs on the server. That's it. No Server Components, no implicit server/client boundary - you explicitly opt into server execution per function.
```
// A server function for reading data
const getProduct = query(async (id) => {
"use server";
return await db.products.find(id);
}, "product");
// A server function for mutations
const addToCart = action(async (formData) => {
"use server";
const productId = formData.get("productId");
await db.cart.add(productId);
});
```
On the component side, you consume these with `createAsync`:
```
function ProductPage(props) {
const product = createAsync(() => getProduct(props.params.id));
return (
{(p) => }
);
}
```
The difference in mental model is significant. If you've ever stared at a Next.js component wondering whether it runs on the server, the client, or both depending on the phase of the moon - yeah, that goes away. In SolidStart, all components run in the same context (SSR'd on the server, hydrated on the client) - you only think about which *functions* run on the server. One boundary to manage instead of two.
### Data fetching
**Next.js:**
```
// Server Component - just await (server only)
async function Posts() {
const posts = await db.posts.findMany();
return ;
}
// With caching (v16+)
"use cache";
async function CachedPosts() {
const posts = await db.posts.findMany();
return ;
}
// Client-side - use SWR or TanStack Query
"use client";
function LivePosts() {
const { data } = useSWR("/api/posts", fetcher);
return ;
}
```
Next.js has gone through three caching models in three major versions. v14 cached `fetch()` calls aggressively by default (which confused everyone). v15 removed default caching. v16 introduced `"use cache"` as an explicit opt-in. On top of that, there are four distinct cache layers: Request Memoization, Data Cache, Full Route Cache, and Router Cache. If you've ever felt like you needed a PhD in cache invalidation just to fetch a list of blog posts, you're not alone.
**SolidStart:**
```
// Define a cached query with a key
const getPosts = query(async () => {
"use server";
return await db.posts.findMany();
}, "posts");
// Preload in route config
export const route = {
preload: () => getPosts(),
};
// Consume in component
function Posts() {
const posts = createAsync(() => getPosts());
return (
}>
{(post) => }
);
}
```
One caching primitive (`query`), one consumption primitive (`createAsync`), explicit cache keys, and `` for loading states. Mutations go through `action()`. Cache invalidation targets specific keys. That's the whole model.
#### Cache invalidation, cookies, and revalidation
Three things you'll need almost immediately after setting up data fetching:
**Invalidating cache from an action:**
When a mutation succeeds, you want to bust the relevant cache. In Next.js, you call `revalidatePath()` or `revalidateTag()`. In SolidStart, you use `revalidate()` with the cache key:
```
import { revalidate, action } from "@solidjs/router";
const addPost = action(async (formData) => {
"use server";
await db.posts.create({
title: formData.get("title"),
body: formData.get("body"),
});
revalidate("posts"); // bust the "posts" cache key
});
```
The cache key is the second argument you passed to `query()`. This is why explicit cache keys matter - you can surgically invalidate exactly what changed.
**Cookies and cached queries:**
In Next.js, reading `cookies()` or `headers()` inside a cached function implicitly makes it dynamic - the cache key includes the cookie values, but this behavior is invisible and easy to get wrong.
In SolidStart, if your server function reads cookies (via the request event), you need to be aware that `query()` caches by arguments only. The cookie value isn't automatically part of the cache key. If different users should see different data, pass a user identifier as an argument to the query, or use `revalidate()` on auth state changes:
```
const getUserData = query(async (userId) => {
"use server";
const session = getSession(); // read from cookie
if (!session) throw redirect("/login");
return await db.users.find(userId);
}, "userData");
```
**Revalidation timing:**
Next.js has ISR with `revalidate: 60` for time-based cache expiry. SolidStart doesn't have a built-in time-based revalidation primitive. Your options:
- **Explicit invalidation** via `revalidate()` in actions (the recommended approach)
- `revalidate()` on the client to force a refresh of specific cache keys
- **HTTP cache headers** on your server functions if you want CDN-level caching:
```
const getPosts = query(async () => {
"use server";
const event = getRequestEvent();
event.response.headers.set("Cache-Control", "s-maxage=60, stale-while-revalidate");
return await db.posts.findMany();
}, "posts");
```
This is more explicit than ISR, but it's also more predictable - you know exactly what's cached and for how long.
### API endpoints
**Next.js** uses Route Handlers:
```
// app/api/posts/route.ts
export async function GET(request: Request) {
const posts = await db.posts.findMany();
return Response.json(posts);
}
export async function POST(request: Request) {
const body = await request.json();
const post = await db.posts.create(body);
return Response.json(post, { status: 201 });
}
```
**SolidStart** uses API routes in the same `routes/` directory:
```
// routes/api/posts.ts
import { type APIEvent } from "@solidjs/start/server";
export async function GET(event: APIEvent) {
const posts = await db.posts.findMany();
return Response.json(posts);
}
export async function POST(event: APIEvent) {
const body = await event.request.json();
const post = await db.posts.create(body);
return Response.json(post, { status: 201 });
}
```
Pretty similar on the surface, but there's an important difference hiding underneath. SolidStart uses the standard `Request`/`Response` Web APIs directly. Next.js *also* uses them in Route Handlers, but in practice you'll quickly run into `NextRequest` and `NextResponse` \- extended wrappers that add things like `nextUrl`, `cookies()`, and `geo`. They're not standard, they don't exist outside Next.js, and they leak into your code in ways that make it non-portable. If you've ever tried to extract a Route Handler into a standalone function or test it without the Next.js runtime, you've felt this pain.
SolidStart gives you the event object with some extras (locals, request, response headers), but it's all built on Web APIs. The main difference is that SolidStart's API routes live alongside your page routes - no separate `api/` directory convention needed (though you can organize them that way if you want).
### Middleware
**Next.js 16** introduced `proxy.ts` as the recommended path for heavy server-side logic - auth, redirects, rewrites - running on the Node.js runtime. The old `middleware.ts` isn't fully deprecated, but it's now specialized for Edge Runtime only. For self-hosted setups (think Hetzner, Coolify, Docker), `proxy.ts` is what you want.
**SolidStart** has `createMiddleware`:
```
import { createMiddleware } from "@solidjs/start/middleware";
export default createMiddleware({
onRequest: [authMiddleware, loggingMiddleware],
onBeforeResponse: [metricsMiddleware],
});
```
One important caveat with SolidStart's middleware: **it does NOT run during client-side navigation.** Only on the initial server request. So don't use it as your sole auth check - put auth logic in your server functions too. Next.js has the same nuance with `proxy.ts`, but it's less obvious.
**What about** `after()`**?** Next.js 15 introduced `after()` \- a way to schedule work (logging, analytics, cache warming) that runs after the response has been sent to the client. SolidStart doesn't have a direct equivalent. Your best options are firing off a non-awaited promise in your server function (the response won't wait for it), or using the `onBeforeResponse` middleware hook to queue background work. If you're on a platform that supports it (like Cloudflare Workers with `waitUntil()`), you can tap into that directly via the platform's API. It's less ergonomic than `after()`, but it works - and you're not locked into a framework-specific API.
**A note on auth in middleware:** this is a broader anti-pattern that's worth calling out. Vercel spent years implicitly encouraging auth checks in Next.js middleware (their templates did it, their docs showed it), then pivoted to "we never said to do auth in middleware" when the Edge Runtime limitations became undeniable. The reality is that middleware auth is fine *if* it's asymmetric - checking a JWT signature or reading a session cookie without making additional network requests (no database lookups, no token introspection calls). The moment you need to hit an external service to validate, you're adding latency to every single request and creating a single point of failure. Put the real auth logic in your server functions where it belongs, and use middleware only for cheap, fast checks like redirecting unauthenticated users to a login page.
### Deployment
**Next.js** works best on Vercel (unsurprisingly). Self-hosting has improved - the Build Adapters API is now stable, and Node.js/Docker deployments are better supported than before. But some optimizations are still Vercel-specific, and Turbopack remains Next.js-only - not the general-purpose bundler it was initially marketed as.
**SolidStart** deploys anywhere Nitro can target - and that's a long list: **Node, Deno, Bun, Cloudflare (Workers, Pages), Netlify, Vercel, AWS Lambda, Deno Deploy**, and more. Switch targets with a single config line:
```
export default defineConfig({
server: {
preset: "cloudflare_pages", // or "netlify", "node", "deno", etc.
},
});
```
No vendor lock-in. Vite is framework-agnostic with a massive ecosystem. This is the "primitives, not frameworks" philosophy applied to infrastructure.
### Metaframework cheat sheet
| Concern | Next.js 16 | SolidStart |
| ------------- | ------------------------------------------------------------- | --------------------------------------------------------------- |
| Routing | File-based, special files (page.tsx, layout.tsx, loading.tsx) | File-based, file name = route, layouts via same-name convention |
| SSR | Default for Server Components, implicit mode switching | On by default, explicit config for SSG/SPA |
| Server code | Server Components + Server Actions + Route Handlers | Server functions ("use server") - one mechanism |
| Data fetching | async Server Components, "use cache", SWR/TanStack for client | query() \+ createAsync() \- one model |
| Caching | "use cache" \+ Cache Components (4 layers historically) | query() with explicit cache keys |
| Mutations | Server Actions via "use server" in functions | action() with "use server" |
| API routes | app/api/\*/route.ts | routes/api/\*.ts |
| Middleware | proxy.ts (Node) + middleware.ts (Edge) | createMiddleware (server-only) |
| Self-hosting | Stable Adapter API | Nitro presets (native) |
| Optimization | React Compiler (auto-memoization) | No compiler needed (signals) |
| Bundler | Turbopack (Next.js-only) | Vite (framework-agnostic) |
| Deployment | Best on Vercel, Adapter API for others | Anywhere via Nitro presets |
---
## Primitives, not frameworks
Before we get into the "why bother" section, it's worth understanding the philosophy behind Solid. There's a mantra in the Solid community: **"Primitives, not frameworks."**
*A note on origins:* the phrase itself was actually coined by [Werner Vogels](https://www.allthingsdistributed.com/?ref=blog.42.mk), AWS CTO, in the context of cloud infrastructure during a Re:Invent keynote. [Ryan Carniato](https://dev.to/ryansolid/5-ways-solidjs-differs-from-other-js-frameworks-1g63?ref=blog.42.mk) ran with it and applied it to UI frameworks, where it's taken on a meaning of its own. It's a bit of an appropriation - Vogels was talking about composable cloud services, not reactive UI primitives - but the core idea translates well: give developers building blocks, not opinionated monoliths.
The idea is simple: instead of giving you a monolithic framework with opinions about every layer of the stack, Solid gives you small, composable, reactive building blocks that you combine however you need. To paraphrase Ryan's approach: here are a few powerful concepts - learn them, combine them, build on top of them. That's the whole thing.
This shows up everywhere in the ecosystem:
- [**Solid Primitives**](https://primitives.solidjs.community/?ref=blog.42.mk) \- a community library of composable building blocks organized by domain (inputs, media, browser APIs, network, animation). Each one is tree-shakeable, SSR-safe, and individually useful.
- **SolidStart's architecture** \- v2 replaced its custom server layer (Vinxi) with Vite 6's Environment API, leveraging an existing ecosystem primitive rather than maintaining bespoke infrastructure.
- **The plugin model** \- features like image optimization are opt-in plugins, not baked into the framework. You compose what you need.
Contrast this with React's trajectory. [React 19](https://react.dev/blog/2024/12/05/react-19?ref=blog.42.mk) shipped with Actions, `useActionState`, `useOptimistic`, `use()`, Server Components, Server Actions. [React 19.2](https://react.dev/blog/2025/10/01/react-19-2?ref=blog.42.mk) added `` (for hiding UI while preserving state and unmounting effects) and `useEffectEvent`. The [React Compiler hit v1.0](https://react.dev/blog/2025/10/07/react-compiler-1?ref=blog.42.mk), auto-memoizing your code at build time. And that's before you add [Next.js 16](https://nextjs.org/blog/next-16?ref=blog.42.mk) on top with `"use cache"` directives, `proxy.ts` for server-side logic, Turbopack, and Build Adapters.
It's a lot. The React Compiler is genuinely impressive engineering - it makes React faster without changing the fundamental model. But in a sense, it's a patch on an architecture that other frameworks have moved past. Solid solves the performance problem at the architectural level via fine-grained reactivity, making a compiler unnecessary. [Angular](https://blog.openreplay.com/reactivity-react-vue-angular-svelte/?ref=blog.42.mk), [Vue](https://vuejs.org/guide/extras/reactivity-in-depth?ref=blog.42.mk), and [Svelte](https://svelte.dev/blog/runes?ref=blog.42.mk) have all moved toward signals too. React is the outlier choosing to solve it with tooling rather than primitives. (Though it's worth noting that React itself has [moved to an independent foundation](https://react.dev/blog/2026/02/24/the-react-foundation?ref=blog.42.mk) under the Linux Foundation - a governance change that may influence its future direction.)
Neither approach is "wrong." But they lead to very different developer experiences.
---
## Why bother? Performance and DX
So, that's a lot of "this works differently." Why go through the trouble?
### Bundle size
Solid's core clocks in at [\~7KB min+gzip](https://bundlephobia.com/package/solid-js?ref=blog.42.mk). React + ReactDOM sits at [\~45KB min+gzip](https://bundlephobia.com/package/react-dom?ref=blog.42.mk). That's roughly a 6x difference at the framework level, and the gap compounds in real-world apps as you add routing, state management, and other dependencies. Less JavaScript shipped means faster load times. Simple math.
### No virtual DOM overhead
React diffs a virtual tree on every state change, even with the Compiler auto-memoizing what it can. Solid compiles JSX to direct DOM operations. When a signal updates, only the specific DOM nodes that read that signal get touched. No diffing, no reconciliation, no wasted work. This is why Solid consistently ranks at or near the top of the [JS Framework Benchmark](https://krausest.github.io/js-framework-benchmark/?ref=blog.42.mk), performing close to vanilla JavaScript.
### The DX angle
Next.js has grown into a complex beast. Four layers of caching, three different caching models across three major versions (v14's aggressive implicit caching, v15's opt-out, v16's `"use cache"` opt-in), the server/client boundary dance, the middleware-to-proxy.ts migration… the [State of JS 2025 survey](https://2025.stateofjs.com/en-US/libraries/meta-frameworks/?ref=blog.42.mk) showed Next.js with the largest satisfaction drop of any meta-framework (from 68% to 55%), landing as both the 13th most-loved and 5th most-hated project - uniquely polarizing. A commonly cited complaint? *"Too complex."* (paraphrased)
And then there was [React2Shell](https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components?ref=blog.42.mk) (CVE-2025-55182) - a CVSS 10.0 critical RCE vulnerability in the React Server Components Flight protocol. A single malicious POST request to any server function endpoint could execute arbitrary code. Default `create-next-app` deployments were vulnerable out of the box. It was [patched across all React 19.x lines](https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components?ref=blog.42.mk) (19.0.1, 19.1.2, and 19.2.1 - make sure you're on the right patch for your minor version), and Next.js shipped corresponding fixes. But the architectural debate about the [Flight protocol](https://www.wiz.io/blog/critical-vulnerability-in-react-cve-2025-55182?ref=blog.42.mk) \- and the attack surface of running component deserialization on the server - remains a valid concern when evaluating RSC-heavy architectures.
SolidStart, by contrast, is refreshingly lean. File-based routing, `"use server"` directives for server functions, `query()` for cached data fetching, `action()` for mutations, and Vite under the hood. It leans on the web platform and doesn't try to reinvent every wheel. You write the reactive primitives we covered above, and the metaframework gets out of your way.
That said - SolidStart's ecosystem is smaller. You won't find the same breadth of third-party integrations, and the community, while active and growing ([35K+ GitHub stars](https://github.com/solidjs/solid?ref=blog.42.mk), [\~1.5M weekly npm downloads](https://www.npmjs.com/package/solid-js?ref=blog.42.mk)), is not React-sized. It's a tradeoff worth being honest about - however, in my personal experience, that hasn't been a big deal. I've already shipped 5+ Solid-based projects of various complexity levels. I can't say the ecosystem size was a huge problem.
---
## Can LLMs help with the migration?
Short answer: yes, but trust and verify.
LLMs like Claude, ChatGPT, and tools like Cursor are genuinely useful for the mechanical parts of migration. They'll convert `useState` to `createSignal`, swap `className` for `class`, strip out `React.memo` and `useCallback` (neither are needed in Solid), and handle the basic boilerplate. For a large codebase, that saves real time.
But here's the catch: LLMs are trained on *way* more React code than Solid code. Their muscle memory defaults to React patterns, and the places where they fail are exactly the places where Solid differs most:
1. **Props destructuring** \- the #1 failure. Every LLM will write `({ name, onClick })` by default. In Solid, this kills reactivity. You need `props.name` or `splitProps()`.
2. **Control flow** \- LLMs leave `.map()`, ternaries, and `&&` in JSX instead of converting to ``, ``, and ``/``. The JS patterns "work" but defeat Solid's fine-grained updates.
3. **The "runs once" model** \- LLMs generate code that assumes the component function re-runs on state changes. It doesn't in Solid.
4. **Async in effects** \- LLMs will happily write `createEffect(async () => {...})`, which breaks reactive tracking after the first `await`.
There's a [documented case](https://github.com/solidjs/solid/discussions/1866?ref=blog.42.mk) of ChatGPT confidently telling a user that a bug in their `` usage was a Solid framework bug. It wasn't. The LLM just didn't understand Solid's reactivity model.
### Making it work
The good news is you can steer LLMs in the right direction:
- **SolidJS now ships an** [**official llms.txt**](https://docs.solidjs.com/llms.txt?ref=blog.42.mk) that you can feed to your AI tool as context. If you're using Cursor, add it via `@Docs`.
- [**solidjs-context-llms**](https://github.com/ysdede/solidjs-context-llms?ref=blog.42.mk) is a community-maintained, LLM-optimized documentation suite organized by domain (reactivity, routing, SSR, primitives).
- **Cursor users** can grab SolidJS-specific [.cursorrules files](https://github.com/PatrickJS/awesome-cursorrules?ref=blog.42.mk) that enforce the right patterns.
- **Claude Code users** can add Solid rules to their `CLAUDE.md` to prevent the common mistakes.
But the real safety net is [**eslint-plugin-solid**](https://github.com/solidjs-community/eslint-plugin-solid?ref=blog.42.mk). Run it after every AI-assisted conversion. It catches reactivity violations that LLMs introduce: destructured props, conditional logic outside JSX, incorrect imports. Think of it as the linter that keeps the AI honest.
My recommended workflow: convert one component at a time, review the output for the known failure patterns, and run the linter before moving on. LLMs get you 70-80% of the way there. The last 20% is where understanding the mental model matters, and that's something you have to bring yourself.
---
## A note on SolidStart v2
If you're evaluating SolidStart right now, you should know where things stand. [SolidStart v2 is in late alpha](https://github.com/solidjs/solid-start/discussions/2119?ref=blog.42.mk) and already being deployed in production by early adopters. The big change: it replaces Vinxi (v1's custom server layer) with [Vite's Environment API](https://github.com/solidjs/solid-start/discussions/1743?ref=blog.42.mk), giving you a leaner, more debuggable stack that leverages Vite's existing ecosystem. [Nitro 3 integration](https://github.com/solidjs/solid-start/discussions/1960?ref=blog.42.mk) is a separate effort, still in progress.
The migration from v1 to v2 is minimal - mostly config changes. Your component code and server functions stay the same. Everything in this guide covers the fundamentals that apply to both versions.
---
## Where to go from here
If you want to get your hands dirty:
- [SolidJS docs](https://docs.solidjs.com/?ref=blog.42.mk) \- genuinely well-written
- [SolidJS Tutorial](https://www.solidjs.com/tutorial/introduction%5Fbasics?ref=blog.42.mk) \- interactive, takes about an hour
- [SolidStart docs](https://docs.solidjs.com/solid-start?ref=blog.42.mk) \- for when you're ready to build an app
- [Solid Primitives](https://primitives.solidjs.community/?ref=blog.42.mk) \- community library of composable building blocks
- [SolidStart v2 status](https://github.com/solidjs/solid-start/discussions/2119?ref=blog.42.mk) \- late alpha, heading toward beta, already deployed in production by early adopters
---
## Takeaway
Migrating from React to Solid isn't a find-and-replace job. The JSX similarity is a double-edged sword - it makes the syntax feel familiar while hiding a fundamentally different execution model. But once the "runs once" mental model clicks, you'll find that Solid's approach is simpler and more predictable. And on a personal note, it makes my brain hurt less.
We're also witnessing a convergence on fine-grained reactivity as the right model - [Angular adopted signals](https://blog.openreplay.com/reactivity-react-vue-angular-svelte/?ref=blog.42.mk), [Vue has ref() and reactive()](https://vuejs.org/guide/extras/reactivity-in-depth?ref=blog.42.mk), [Svelte 5 moved to runes](https://svelte.dev/blog/runes?ref=blog.42.mk). Solid has been doing this from day one. The primitives are mature, the metaframework is production-ready, and the philosophy of composable building blocks over monolithic abstractions means you're not fighting the framework - you're using it as intended.
Whether you're moving away from Next.js for practical reasons, performance reasons, or just because you're curious about what fine-grained reactivity feels like in practice - give SolidStart a shot. The learning curve is real but short, and the payoff is worth it.
Happy hacking!
---
*Originally published at* [*darko.io*](https://darko.io/posts/next-to-solidstart-migration-guide/?ref=blog.42.mk) *by Darko Bozhinovski. Licensed under* [*CC BY 2.0*](https://creativecommons.org/licenses/by/2.0/?ref=blog.42.mk)*.*
### Software engineering enters its accounting era
URL: https://blog.42.mk/software-engineering-enters-its-accounting-era/
Last updated: 2026-06-30T11:25:15.000Z
# Software engineering enters its accounting era
> Have you ever heard of someone having accounting as a hobby?

If you have ever done accounting, you probably know it is not much fun. If not here is a brief summary. There are bunch of rules to follow, coded into local, national, and international standards, and many modern ERP systems have them at least partially implemented and automated. There is not really creativity in the work – well not unless you want to work in organised crime, and the profession is highly regulated. There is a lot of gate keeping about who can do the job, or who can do which part of the job, and what kind of certificates one must have, although the core of the accounting process is largely unchanged since it was codified sometime during the [renaissance or thereabouts](https://en.wikipedia.org/wiki/Luca%5FPacioli?ref=blog.42.mk).
No one has accounting as a hobby. There is no cool project in accounting you can share with your friends, and there aren’t any interesting or thought provoking conferences or meetups where the topic is accounting. Was there ever an accountant speaking at TED? I haven’t check, but if there was he/she was probably speaking about something else.

So what has this have to do with software engineering? To use Don McMillan’s funny diagram, we are now seeing a shift away from problem solving in software engineering. Instead of solving problems we are writing markdown documents that tell agents to solve a problem. And, even in these early days we see projects popping up with default `.md` files to do a certain tasks, or write in certain language. I think it is not before long we see a standard `.md` file to build an R package, or to build a FastAPI, or something else, with complexity of the problem being solved increasing over time.
There is a trajectory in which agent skill will become something akin to International Financial Reporting Standards. I think we are not far away from having the big companies producing “verified” skill (as I went to LinkedIn to post this I was greeted by a [post by Anton Abyzov](https://www.linkedin.com/posts/antonabyzov%5Fai-developertools-buildinpublic-share-7438679148476125184-8lnk?ref=blog.42.mk) that talks about a [verified skill tool](https://verified-skill.com/?ref=blog.42.mk) :) to do certain things in their ecosystem. Think for example “AWS verified skills for infrastructure”, and maybe these will start to come with a price tag on a tier level, or even on regional level around the world.
Then if you are a company working in software auditing, you will probably have a skill that will instruct your agent to audit the work of another agent. I would not be surprised if the Big 4 are already thinking about this.
Where does this leave software engineers? No more problem solving, more OCD? I think it is not difficult to imagine future work being mostly reading `.md` files and trying to catch inconsistencies that slip through spell checkers or similar tools. Think someone typing `cat` instead of `car` in some `.md` file, and someone else trying to figure out where is the error coming from. That to me sounds much closer to tracking the stray balance mismatch on the balance sheet, than to improving a poorly implemented function that sometimes crashes the user’s computer.
Is this good or bad? I guess it depends on being good or bad for whom or what. I think that even if this trajectory takes place, it will probably not affect the current generation of software engineers.
However, not thinking about the other issues being raised (such as overall environmental concerns, employment outlook, and the stock market bubble), I think over time we are very likely to witness [tragedy of the commons](https://en.wikipedia.org/wiki/Tragedy%5Fof%5Fthe%5Fcommons?ref=blog.42.mk) unraveling in the free software world.
Then maybe a lot of the software becomes like the cheap umbrellas you buy on the street form ad-hoc sellers when it suddenly starts to rain, and then they break after the second use and you toss them away. And maybe a lot of the software becomes a problem similar to the plastic in the oceans and [some engineers re-skill to deal with that](https://www.theguardian.com/world/2026/mar/15/cairo-fishers-catching-plastic-bottles?ref=blog.42.mk).
For the current generation I think it will put pressure on community building around software, hobby projects, and events. Think about it: why would I want to come to a meetup if we are to discuss your latest `.md` file? It is not meant for people anyway. Or why would I bother with reporting a bug or offering a pull request on a project that is largely build by a coding agent? The intrinsic motivation to help and be involved with people is simply gone. I would even say there is no motivation to send my agent subscription to do a pull request on your agent driven project. What would my lighting talk be at the next conference: how to format your `.md` file in 10 easy steps? There is a skill for that too.
After all have you ever heard of an accounting community?
### Just put the QR in the bag bro
URL: https://blog.42.mk/just-put-the-qr-in-the-bag-bro/
Last updated: 2026-06-30T11:24:53.000Z
# Just put the QR in the bag bro
> Or: how a €9.99/month hostage situation spawned qr.42.mk

**TLDR:** Frustrated by BS hostage-happy websites for generating QR codes, I built/vibed [https://qr.42.mk](https://qr.42.mk/?ref=blog.42.mk) in an hour or so, go ahead, use it, and whenever you need a QR code, just go there, grab it and move on with your life.
Now, while the tool was 100% AI generated with very minor tweaks from my side, this post was 99% human written, 1% being the titles for more manageable reading, I'm by no means a good writer, if you want to read the story, thank you, and go right ahead!
You can find me on the Base42 Discord if you want to chat about the blog, the universe or anything.
## Step 1: You Just Need a QR Code
Picture this - you're building promotional materials for your event, venue or whatever, you have your design ready to go, a placeholder in the middle for a QR code, your guests will scan it and learn more about your event, it will be great!
You, being the well-prepared designer that you are, prepare your media materials months ahead, painstakingly designing and detailing everything, "It's perfect!" you exclaim, then you remember that you still have a placeholder in your QR code slot, so you do what anyone would do:
1. Type in QR code generator into [google.com](http://google.com/?ref=blog.42.mk)
2. Paste your link
3. A popup comes up prompting you to sign in
4. It has Login with Google available, so why not
5. You login
6. You click free plan or something
7. Download the QR code
8. You get your QR Code
9. ???
10. Profit
Victory! Now that whole side quest is complete, you put the cherry on top, your QR code is finally placed into the placeholder, the whole picture finally tied together, feng shui in place and all that. Being the diligent designer that you are, you test it and validate it works, huzzah!
Ship it! You send it to the print company, they print it and a few days later, you have your beautiful designs ready to be passed around as fliers, stickers or whatever other physical media may be. A week or so later you start your campaign and the flyers get passed around, people are scanning, conversions are happening, yay!
## The Hostage Email
Then a few days later, you get this:

Oh yeah, that QR code you generated, plopped into your design, shipped to printing and paid the invoice for - it's being held hostage by one of the many predatory QR code generators out there, all of which seem to rank pretty high on Google. I could write an entire blog post on the predatory tactics and dark patterns they use to cling onto any desperate attempt at monetizing something that is at best a single use app. Sure, they provide tracking and analytics, but that's not what you need every time, and it should certainly not be the default.
To continue, pay up, friend:

Just $9.99/month, what a steal!
## I'll Build My Own, With Clankers and Prompting
If you've been following Base42, you know what we are - a hackerspace, where people hack on different projects, experiment and so on. If you're following us on socials, are in the Base42 Discord server, or just maybe stumbled upon [Vasilaki's last post](https://blog.42.mk/everything-remote-as-all-things-should-be) you would know that last month we held NSND, a sort of un-conference, where you just come, talk about random stuff and maybe something comes out of it.
So we did. Someone mentioned generating a QR code and immediately triggered flashbacks of every time I've fallen victim to this exact hustle.
## One Wish, One Hour
There's this magic black box called AI that you can throw your wishes into, something clanks along and voila, you have your very own app, vibes and all. That's what I did - while everything else was happening during NSND, people showing off home infrastructure setups, talking about what we'd host on the new Base42 server rack and so on, I put my wish into the wishing well that is a coding agent.
Here's what my wish was:
> "Build a QR code generator, should work fully in the browser, make it available as a PWA, no server, make no mistakes"
And it did. Very little mistakes, pretty much a 1-shot from the get-go, and around 1h in it was fully deployed.
## Meet QR Canvas
I present to you QRC - let's call it QR Canvas, the pronunciation makes it funny.

It supports everything you would need and more - fully customize your QR code, add a logo, pick from templates, all for free, all within your browser. You can even install the PWA on your phone, tablet, laptop and take it with you offline.

There's even support for adding a logo!

## Goes without saying, it's Open Source
The code is all there if you want to poke around, contribute, or just verify that yes, it really is just a browser and nothing else. Fork it, improve it, make it yours. Heed my warning though, the codebase IS AI SLOP, essentially, but it's AI slop that totally works, does the job and doesn't need further updates as far as I'm concerned. If you have a better coding agent that would like to rewrite this in the JS framework dejure, go ahead and open a PR, I'll tell my AI to check your AI's work! 🤣
[github.com/42dotmk/qrc](https://github.com/42dotmk/qrc?ref=blog.42.mk)
## Go Use It
No account. No popup. No hostage email three weeks from now. Just [qr.42.mk](https://qr.42.mk/?ref=blog.42.mk) \- open it, generate your code, download it, done.
If you find a bug, fix it yourself.
### Everything remote, as all things should be
URL: https://blog.42.mk/everything-remote-as-all-things-should-be/
Last updated: 2026-06-30T11:24:44.000Z
# Everything remote, as all things should be

In the spirit of the hacker culture of Base42, we held the [unconference](https://en.wikipedia.org/wiki/Unconference?ref=blog.42.mk) **NSND**(*Ništa se neće dogoditi*).
Macedonian NSND has it's own [wiki](https://wiki.spodeli.org/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%98%D0%B0:%D0%9D%D0%A1%D0%9D%D0%94?ref=blog.42.mk), where you can learn more about what it is and what has happened over the years in each city it was held in(reading back it seems pretty fun and I am sure there were crazy adventures).
Shortly, it's a gathering of tech enthusiasts and geeks from the Balkan region, but sometimes there are guests from abroad, there aren't predefined/predetermined topics nor speakers, everything happens on the spot. People come, introduce themselves, say what they can speak and listen to about and after a vote, the talks/workshops start.
It's like an organized chaos, breeze of fresh air for the people that are used to structured talks and events.
---
### Skopje 2026 NSND
We voted for the topics we proposed at the start of the event and the second most anticipated topic was mine:
## Decrypt LUKS through SSH
### *SSHing into the machine before the system is booted to decrypt the LUKS-encrypted drive*
When the drive is decrypted, the drive boots and runs the installed operating system into which we can practice the normal everyday SSHing(remotely accessing).
---
## Motive
We started working on a 3D printer server @ Base42(more on that in some other upcoming blog), but stumbled upon a challenge. Few times, in the course of three days, the server was unplugged from the power outlet and couldn't be accessed remotely via SSH even if immediately plugged in, soooo annoying. You may ask why? - LUKS is the answer.
If you want your entire disk to be encrypted for security and privacy, on Linux, that's done using [Linux Unified Key Setup(LUKS)](https://en.wikipedia.org/wiki/Linux%5FUnified%5FKey%5FSetup?ref=blog.42.mk). You must be in front of your computer to unlock LUKS-protected disks by providing a passphrase at boot time. However, the machine I was working with was not at my premise, so I wasn’t able to unlock and boot it, at least that's what I thought at first.
The old workflow went like this:
1. server was working properly(normal SSH would work) → someone unplugs the cable(SSH timing out on my machine)
2. I would need to come physically → decrypt the LUKS
3. system boots, SSH works again → go to step 1
Because I was furious about it, I said to myself-"There must be a way to remotely do this. I am sure the DevOps of big companies are not coming physically to the encrypted servers everytime they restart them just to decrypt them", so I searched the internet for my thought, and there it was again, someone else did it, the usual.
There are always exceptions(sad), as in our case, if the cable is left unplugged, I MUST come physically to the server.
PLEASE DON'T LEAVE THE CABLES UNPLUGGED IN BASE42
---
## Execution
When I read that there's such thing as remote unlocking a LUKS encrypted drive, as every hobby project, I said-"I am going to do this one day" and it just waited for the right moment.
The perfect moment was NSND.
But I wasn't prepared for it. I just proposed the topic, it was voted, but I didn't know how to do it exactly.
Luckily, that's what the unconference was about-everyone was involved into it and wanted to help to do it. After seeing that it will take a lot of time, more than a quick talk, we decided to make it like a separate workshop, projected to the secondary projector @ Base42.
The biggest credit goes to Damjan Georgievski.
And here's what we learned from the process:
### Choosing the SSH server
TinySSH and Dropbear are both lightweight SSH servers designed for embedded systems and minimalist environments, but they prioritize different goals.
**Dropbear is more feature-rich** and compatible, supporting password authentication, older algorithms, and scp/sftp, making it a better general-purpose [**OpenSSH**](https://www.openssh.org/?ref=blog.42.mk) replacement and is perfect for routers, IoT, and embedded Linux with limited resources.
**TinySSH focuses on extreme security/simplicity** by supporting only modern, secure cryptography (Ed25519/ECDSA, no RSA/DSA), has extremely small codebase aimed at minimizing attack surface and is ideal for highly secure, modern **initramfs** unlocking.
**TinySSH** looked like the exact tool we need.
### initramfs
What if I told you that there's a full second operating system(although very small) that runs before your known main OS, *I am using Arch, btw*.
Well, that happens in the early boot of a Linux machine, where the only directory that's not encrypted by default is the */boot/.*
This secondary OS is not accessing the LUKS-encrypted drive/s, is loaded from a compressed archive file in */boot/* called `initrd`, which stands for “initramdisk”, which is another word for our *initramfs* system and it contains all the boot-related things for the system, of which most important for us to have are the **drivers** and the **ssh server**.
It is ran from **RAM**, that's why it's called **initramfs** (initial RAM filesystem).
In it, a copy of *systemd* is running and its state is passed to the state in the primary OS, so that means we can install a whole collection of stuff in `mkinitcpio-systemd-extras` (`mkinitcpio` is the tool Arch uses to regenerate **initramfs**).
Here's a link to see what's available: [https://github.com/wolegis/mkinitcpio-systemd-extras](https://github.com/wolegis/mkinitcpio-systemd-extras?ref=blog.42.mk). Since it's AUR, use your prefered way to add them to your Arch packages.
Of those, we need two: [sd-tinyssh](https://github.com/wolegis/mkinitcpio-systemd-extras/blob/main/sd-tinyssh?ref=blog.42.mk) and [sd-network](https://github.com/wolegis/mkinitcpio-systemd-extras/blob/main/sd-network?ref=blog.42.mk). They are added in the `/etc/mkinitcpio.conf`'s `HOOKS`, where its comment reads:
> The HOOKS control the modules and scripts added to the image, and what happens at boot time.
>
> Order is important, and it is recommended that you do not change the
>
> order in which HOOKS are added.
Here's our `HOOKS`:
```
HOOKS=(base systemd autodetect microcode modconf kms keyboard keymap sd-vconsole block mdadm_udev sd-network sd-resolve sd-tinyssh sd-encrypt filesystems fsck)
```
To ensure the tinySSH server only decrypts the LUKS, we have created the file `/etc/mkinitcpio.conf.d/tinyssh.conf` with the content:
```
SD_TINYSSH_COMMAND="systemd-tty-ask-password-agent --query --watch"
```
For the tinySSH to work, we need the public keys into `/root/.ssh/authorized_keys`.
In our case, I also needed to edit `/etc/systemd/network/en.network` to put the leased static internal IP address via DHCP Reservation, because when we used the default `DHCP=yes`, the tinySSH server was given a different IP address every time and wasn't accessible:
```
[Match]
Name=en* eth*
[Network]
Address=192.168.x.x/24
Gateway=192.168.x.1
DNS=8.8.8.8
```
Finally, run `mkinitcpio -P` to rebuild the *initramfs*.
---
## Result

> Disclaimer: I am using alias commands( `printon`/ `printonLuks`), you would need to use your own parameters e.g. `ssh -p {server_ssh_port} -i "{path_to_private_ssh_key}" {user}@{server_ip_address}`
### PxBadge - Dynamically generated Pixel Art Badges
URL: https://blog.42.mk/pxbadge-dynamically-generated-pixel-art-badges/
Last updated: 2026-06-30T11:24:58.000Z
# PxBadge - Dynamically generated Pixel Art Badges
> Written by Lorddeathunter

As both Developer and Pixel Artist, I often find myself creating pixel art for my projects, be it placeholders, icons or even as larger parts of some application or game. My latest such project came from the wish to showcase technologies I'm fond of on my GitHub profile. Instead of looking for specific technology logos, then manually editing the images, I wanted to have badges with a consistent style, that can be dynamically generated and tweaked in the future for different needs, as well as a way for anyone to create their own badges.

From looking around, I was unable to find any existing pixel art online for the majority of the techs I needed, and I hope with this project, future adventurers don't run into the same issues as me 😊

I drew pixel art of a few logos, made a custom badge and stars, and created a Python script that generates a badge with the desired logo and the specified rating underneath. I created a web API so anyone can make their own badges for whatever they desire, profile, portfolio, home page, game project, etc.

With all the different badge material, technology and rating options, there are **over 4000** possible badge combinations. If we include the different scale options, this number jumps to **over 80,000**.

## Implementation
The project implementation is quite simple and consists of a Vanilla JS frontend (as there is nothing fancy going on there), and a FastAPI backend. The backend loads all the sprites from the assets folder initially and from then onwards they are stored in-memory, with an additional (protected) endpoint existing if I need to reload the loaded files. Further optimizations were considered with caching, but ultimately skipped because of the sheer number of badge combinations.

## Usage
The project is currently hosted [here](https://badge.deathunter.com/?ref=blog.42.mk), and has an interactive live badge editor. For API users, the endpoint for getting the list of technologies is [https://badge.deathunter.com/techs](https://badge.deathunter.com/techs?ref=blog.42.mk), and the list of badge backgrounds is: [https://badge.deathunter.com/materials](https://badge.deathunter.com/materials?ref=blog.42.mk)
There are **over 100** different techs, each one being hand-drawn, including (but not limited to): - Programming languages - Frameworks - Engines - Tools/apps - Browsers - Operating Systems - Website logos - Company logos

### 🚀 Base42 Recap 2025
URL: https://blog.42.mk/base42-recap-2025/
Last updated: 2026-06-30T11:23:47.000Z
# 🚀 Base42 Recap 2025

Sorry for the late post — we travelled through the multiverse. Git conflicts were involved. Possibly on purpose.
There is a traditional marketing rule that says you should publish your yearly recap sometime in early January, ideally when everyone is still pretending they will stick to their New Year’s resolutions. As a hackerspace that lives in a garage and occasionally bends the laws of physics, we decided to ignore that rule completely. Instead, we are publishing our 2025 recap at the end of the Chinese New Year, as a small tribute to our lovely Asian community, Pagoda, which is an essential part of the Base42 story.
This year is the Year of the Fire Horse, a sign that appears only once every 60 years, last seen in 1966\. The Fire Horse is associated with boldness, speed, high energy, and the potential for dramatic change. Honestly, that sounds suspiciously like our event calendar. Also, today is the Lantern Festival, which marks the official end of the New Year season before life returns to daily routines. The wish behind it remains simple and universal: peace and happiness for family and friends. Considering the state of the world, that wish feels more relevant than ever.
So this is officially our last chance for a recap. Let’s do it properly.
## 🛠 About Base42
Base42 is a basement hackerspace, born in a garage and named after The Hitchhiker's Guide to the Galaxy. As you may remember, 42 is the answer to life, the universe, and everything. Inspired by Douglas Adams, we decided that if 42 is the answer, then we might as well dedicate ourselves to building the question together. Our core principle is simple: together we are building the meaning, trying to create something good for society, for our friends, and for the open-source community.
The probability of success for a garage full of geeks attempting to influence the local tech culture was approximately 0.00000042 percent. The actual result was somehow, undeniably, yes.
The purpose of Base42 has never been just to host events. It is to create moments that make a difference, generate positive energy, and leave a lasting impact. It is a place with chill vibes and informal energy, the kind that reminds you why you fell in love with technology in the first place. It takes you back to the first time you built something from scratch, learned a new skill, or fixed a bug at 3 a.m. and felt proud to belong to the geeky world.

## 🎮 Global Game Jam
We started 2025 the only logical way: with Global Game Jam organized by MGI, because many of us entered the world of technology through games in the first place. Before we were engineers, designers, cybersecurity experts, we were players trying to understand how things worked. Games were our first debugger and our first design document.
For 48 intense hours, around one hundred participants filled the garage with laptops, cables, caffeine, and dangerously ambitious ideas. Mechanics were invented at 2 a.m., redesigned at 4 a.m., and heroically patched at 7 a.m. It is the kind of event where you start by asking deep philosophical questions about gameplay, narrative, and whether 42 is truly the answer to life, the universe, and everything. By hour 36, however, the real question becomes whether the answer is actually a hot shower and six uninterrupted hours of sleep.
Somewhere between those two questions, magic happens. Strangers become teammates, ideas become prototypes, and exhaustion becomes a shared badge of honor. And by the end, when you stand there presenting something that did not exist 48 hours earlier, you remember exactly why you fell in love with building things in the first place.
The energy from that weekend could power a small country, or at least keep us motivated until the next registration opens.

## 🎨 UX/UI Conference
Shortly after that, we helped organize the first major UX/UI conference together with the amazing crew from UXplore, led by a powerhouse team of brilliant ladies and supported by a few brave gentlemen who successfully survived rooms full of strong design opinions. With more than 250 participants, it marked a milestone for the design and tech communities in our country. Developers and designers shared one stage, and for a brief, beautiful moment, everyone agreed on spacing, typography, and user flows. We can confidently say the conference itself had excellent user experience, which might be the highest compliment a room full of designers can give.

## 💔 A Difficult Spring
As spring arrived, the tone of the year shifted. In March, tragedy struck Kochani, and the entire country was left in shock. Nearly 70 lives were lost, most of them young people, and for weeks it felt as if time itself had slowed down. In the face of tragedy, technology, events, and everyday discussions suddenly felt small in comparison to the weight of reality.
In May, together with the Macedonian .NET Community, we helped organize a humanitarian Global Azure Day in honor of the victims and in support of the affected families and survivors. Around 200 participants gathered not only to discuss cloud technologies and modern architectures, but also to donate and contribute in a meaningful way. It was powerful moment when the tech community came together not for networking or innovation, but for solidarity and compassion. It reminded us that behind every line of code, there are people — and that community matters most when it shows up for each other.

## 🤖 Meetups, AI & Tech Communities
Throughout the year, Base42 ran at full capacity with monthly meetups. PyData alone hosted nine gatherings, with artificial intelligence and large language models dominating the conversations. We discussed how AI is changing the way we build software, how to use it responsibly, and how to stay curious instead of scared. Some people were experimenting with fine-tuning models, others were integrating APIs into real products, and a few were just trying to explain to their parents that no, ChatGPT does not actually “know everything.”
And while AI sounded futuristic and complex, somehow the real drama still came from Python versions and broken environments. It turns out that even in the age of machine learning, the most powerful force in the universe might still be a properly configured virtual environment.
BeerJS, .NET meetups, cybersecurity sessions, AWS talks, Google Developers Group events, Angular Macedonia gatherings, ProdACT meetups, Microsoft Dynamics discussions, Advent of Code, and many more filled the calendar. Somewhere along the way, we stopped asking whether we should host another event and started asking how many chairs we needed this time.
Many weekends throughout the year, Base42 quietly transformed into a global Capture The Flag battleground. A dedicated group of cybersecurity enthusiasts gathered with one mission: compete at the highest level. Their focus and persistence paid off with impressive accomplishments and high scores on the global leaderboard. We are incredibly proud of this crew. They achieved impressive results and high rankings in global competitions, proving that a small garage can produce world-class talent.

## 💻 Doniraj Kompjuter & Open Source
One of our favorite communities, Doniraj Kompjuter, donated nearly 4,000 computers this year, helping bridge the digital gap and give devices a second life in the hands of students and families who truly need them. If you have an old laptop or computer collecting dust, bring it to Base42\. We will make sure it finds a better purpose. On top of that, Doniraj Kompjuter donated an incredible server rack with 1TB of RAM to our space, which instantly upgraded our definition of “overkill” and “future-proof.”
With the new rack in place, we launched open-source projects into the wild, built a QR code generator, a competitive programming platform, a text editor, a new mobile application, and even worked on a drone project. Of course, there are also a few projects that are technically still not finished. They are not abandoned. They are simply in extended beta. Possibly waiting for the right alignment of planets. Or a free weekend.

## 🎲 Gaming, Tabletop & Community
Somewhere between all of this, a new community rolled into Base42\. Warden Gaming brought trading card games and board games into the garage with a simple but powerful mission: shuffling cards and making friends. What began as a few decks on a table became regular gatherings full of strategy, laughter, and very serious debates about rules that were absolutely interpreted correctly.
Every weekend, Warhammer armies are carefully assembled, painted with monk-like precision, and deployed across tabletops like miniature sci-fi operas. Strategies are calculated with the seriousness of production deployments, and dice rolls are treated like high-stakes system calls. Alongside the Warhammer battles, Zandana sessions brought even more tactical energy to the tables, while Dungeons & Dragons campaigns opened portals to entirely different worlds. Character sheets were studied as intensely as documentation, and storytelling blended seamlessly with strategy.
It turns out that whether we are optimizing code, tuning AI models, or planning battlefield formations in a fantasy universe, geeks will optimize everything.


## 🎤 What The Stack 2026
Did we forget about the biggest event? No. We organized the biggest developer gathering of the year, an event that honestly deserves its own blog post. Together with DevEd, Angular Macedonia, and the entire IT community, we helped create a conference that brought together more than 800 people. There were four stages, 32 speakers, great coffee, beer (because engineers) music, and a game corner showcasing titles from Macedonian publishers. The afterparty escalated beautifully with rock and metal music by Why Not, and when speaker Domagoj unexpectedly grabbed a guitar and joined the stage, it became one of those legendary moments no schedule could have predicted. Students, senior programmers, engineers, and gamers all shared the same space, proving that the community is united by passion more than anything else.

## 🎮 Game Dev Rev & Milestones
Later in the year, we proudly supported Game Dev Rev, the first national game development conference organized with MGI and the local gaming community. The event brought together regional studios, indie developers, industry veterans, and representatives connected to the European gaming ecosystem. North Macedonia officially became part of The European Games Developer Federation. It is still slightly surreal that a small garage basement helped contribute to such a milestone. Apparently, even big federations sometimes start in small rooms.

## 🎨 Art, Podcasts & Workshops
Art found its permanent home in the garage as well. Three new graffiti pieces transformed the walls, thanks to Nikola. Pagoda organized four Gunpla workshops, which absolutely count as precision engineering. They organized a cyberpunk art exhibition and promoted Kalajdziev’s book. We welcomed two 3D art exhibitions and presentations by Zafir. Base42 became a place where soldering irons and spray cans coexisted peacefully.
Podcasts were recorded within our walls, including episodes by Debeli Gikovi, and we quietly started preparing our own geeky podcast. The studio is already painted, the microphones are set, and we are currently in the extremely complex process of choosing the name. As every developer knows, naming things is one of the hardest problems in computer science. Let’s just say, it is coming soon.
The year wrapped up with another game jam organized by Galactic Omnivore and MUGI, themed around white hats. During that same intense month, we organized an electronics workshop that sold out in a single day, with half of the participants being women, which made us especially proud.
We also hosted two cybersecurity workshops with Bozidar. The first sold out immediately, and the second lasted four full days with six trainers guiding participants deep into ethical hacking and digital defense. Neon lights. Hacking. Mind-blown.

## 🧠 Hackathons & Ecosystem Support
There were so many events happening that at times the calendar looked like a production server under heavy load. Among them, we hosted the Strip Trip Hackathon, where participants were pushed to think creatively under pressure and make things that were anything but ordinary. It was intense, chaotic in the best possible way, and full of ideas that refused to stay inside the box.
At the same time, we proudly supported our friends who organized the Ecommerce Conference and the AI Summit. Because for us, community is never competition. When one event grows, the entire ecosystem grows with it.
Some prototypes almost worked. Some projects definitely worked. A few experiments violated at least three known laws of physics. Thousands of humans and possibly a few aliens visited Base42\. Thousands of coffees and beers were consumed. One arcade machine remains broken but emotionally supported. There was also at least one solution that mysteriously only worked on Fridays, and we decided not to question it.

## 🚀 Looking Ahead
In 2026, we will continue our primary mission: figuring out the right questions. As Deep Thought once calculated, finding the ultimate answer takes time. Fortunately, we are patient, slightly chaotic, and well supplied with snacks.
We are already three months into 2026\. We have organized new events: LAN party, Trivia Night, monthly meetups, chess tournament, internships for high school students who will end up teaching us…Many surprises are on the way. The universe is clearly not done with us yet.
Base42 remains a small garage with a jacuzzi and sauna unused for their original purpose, but it is also a living, breathing organism made of communities, ideas, experiments, friendships, and late-night discussions. It proves that you do not need a shiny building or a perfect marketing strategy to create impact. You need people, curiosity, courage, effort, and maybe a towel.
So thank you to every community that called Base42 home in 2025\. Thank you to those who trusted us with your ideas, your events, and your time. Thank you to our friends who built conferences and invited us to support them. Thank you to everyone who shuffled a card, rolled a dice, wrote a line of code, painted a miniature, plugged in a server, recorded a podcast test episode, or stayed late just to help move chairs.
The universe may still be calculating the ultimate question, but one thing is clear: it is much more fun when we calculate it together.
And yes, the answer is still 42\. ✨
### Why I Made Jack (of All Trades)
URL: https://blog.42.mk/why-i-made-jack/
Last updated: 2026-06-30T11:25:16.000Z
# Why I Made Jack (of All Trades)
> TLDR: I kept opening random web tools for tiny tasks, so I created a CLI for them.

We all do it. Maybe you *just* started using curl instead of those GUI HTTP clients like Postman or Insomnia, and you had to copy the response body and paste it into a browser-based JSON formatter to make sense of it. Perhaps you wanted to inspect a JWT, so you go to jwt.io, and although the site says it doesn’t transmit tokens, pasting credentials into any webpage is a habit worth avoiding. Or you needed some IDs for those tests, so you googled “UUID generator“. Maybe you also wanted to generate a QR code - same story. Not to mention the ads you usually see on the websites.
Of course, there are various solutions for this - right in your terminal:
- `jq` for JSON formatting and processing
- `qrencode` for generating QR codes
- `uuidgen`(Unix) and `New-Guid` (Windows) for all your UUID needs
And you can always just google what you need and use some web app instead. I did that too, who am I to judge? But this is all too fractured and inconsistent.
I personally use some of these tools myself. And I’ve noticed a common trend among my colleagues: many default to web-based tools, even though terminal apps are often faster and easier once you get the hang of them. I sometimes recommend some specific CLI tool, but it rarely sticks. And with CLI tools there’s also the issue of compatibility across platforms, you can use one tool on your Linux system, but when you switch to Windows you need to suppress that muscle memory and write another command in PowerShell instead. It’s just too frustrating and fragmented.
Wouldn’t it just be easier to have a single tool, that you could install once on your system, would work across different platforms? No need to remember and install different tools, or search for alternatives for your Windows machine. Imagine it all centralized: `jack json`, `jack qr`, `jack uuid generate`, `jack jwt` \- all just working, in a single package, across platforms.
That’s why I decided to make a sort of Swiss Army Knife tool for developers that’s portable and accessible. Initially, I actually named it factotum - a word for a general handyman. Then, my friend [Nikola Dinevski](https://hashnode.com/@ndinevski?ref=blog.42.mk) came over and suggested **jack** \- as in, jack of all trades. I thought that it was perfect! It’s exactly what it is, a multi-tool for all trades - but a master of none. What’s often omitted from that saying though, is that it’s oftentimes better than a master of one! Besides, jack is a pretty memorable name and easy to type in your terminal.
Jack removes the friction from remembering all those different tools, you just type in `jack` and find the tool you need, on all your systems! No need to install multiple tools, or lookup something online. It’s easy and intuitive to use, with no fancy and complicated options that you may find in more specific tools which, let’s be honest, you’ll only ever need a fraction of the time. It’s composable, simple, and helps with most of your day-to-day tools needs.
The intention is not to replace all the other tools I mentioned, of course they’ll have their use-cases. I don’t expect jack to have feature parity with dedicated tools. No, the aim is to have jack as the easy default tool you go to when you need something so you don’t have to juggle multiple tools.
Jack is made with Kotlin. *Why?* Because I want to be unique! No, but really - I wanted to try out the language for something else than backend services. It’s cross-platform, and is overall very nice to work with. Additionally, I had recently read about [clikt](https://ajalt.github.io/clikt/?ref=blog.42.mk), a CLI library for Kotlin, and I wanted to take it for a spin.
I’d love for you to contribute! If you have a feature in mind you can always submit a PR or open an issue if you want me to put it on the to-do list. You can find the repository at [https://github.com/dimeskigj/jack-cli](https://github.com/dimeskigj/jack-cli?ref=blog.42.mk).
Jack has a lot more features, and you can try them out for yourself!
On Linux/MacOS, you can install jack with:
```
curl -fsSL https://raw.githubusercontent.com/dimeskigj/jack-cli/main/scripts/install.sh | bash
```
If you’re on Windows, use PowerShell instead:
```
iwr https://raw.githubusercontent.com/dimeskigj/jack-cli/main/scripts/install.ps1 -useb | iex
```
Let me know what you think! I would be glad if you find jack useful.
### Announcing Base42 Advent of Code 2024
URL: https://blog.42.mk/announcing-base42-advent-of-code-2024/
Last updated: 2026-06-30T11:23:18.000Z
# Announcing Base42 Advent of Code 2024

We’re excited to start the **Base42 Advent of Code 2024 Competition**, a unique event that combines programming challenges, friendly competition, and charitable giving. This year, Base42 is not only bringing you the thrill of solving coding puzzles but also giving you a chance to make a real impact through donations to charitable causes.
Here’s everything you need to know about the competition, the rules, the prize pool, and how you can participate.
## How It Works:
- **Advent of Code** is a yearly event that challenges coders to solve 25 puzzles over the course of December. Our competition is based around the official leaderboard for the event. Whether you’re a skilled programmer or just starting out, you’re invited to join us for a fun and impactful month of problem-solving.
- **Leaderboard**: Participants will be ranked on the official Advent of Code leaderboard based on their progress (number of stars earned) each day.
- **Charity Focus**: For each star you earn, **Base42 will donate 5 MKD directly to a charity chosen by the first-place winner of the leaderboard.**
- **Prize Pool**: A portion of the prize pool will go to the top 3 participants based on their leaderboard performance, and another portion will be donated to charity.
## Who Can Participate?
- **Individual Participants**: Anyone can join the competition and participate in the official Advent of Code leaderboard. Whether you're a beginner or an experienced developer, this event is open to everyone. You can compete for fun, or if you choose to pay the participation fee, you'll be eligible for the prize pool.
- **Company Participation and Sponsorship**: Companies are encouraged to get involved as sponsors and donors of the event! By sponsoring the competition, your company can contribute to the prize pool, which will be distributed among top participants and donated to charity.
## How to participate
- Join the [Discord server](https://discord.gg/424xxTZVYX?ref=blog.42.mk), you can find the leaderboard join code in the #advent-of-code channel
- Enter the leaderboard code you got from the Discord server into the [Advent of Code](https://adventofcode.com/2024/leaderboard/private?ref=blog.42.mk) website
- Fill out the [participation form](https://forms.gle/MNJoPoyj1fqKYVMdA?ref=blog.42.mk)
- Pay the optional participation fee of 200 MKD by buying a participation ticket at [this link](https://drugastrana.mk/event/advent-of-code-42-2024/?ref=blog.42.mk).
- Code away for the next 25 days, and may the best coder win!
## Prize Distribution:
The total prize pool is divided as follows:
- **40% of the prize pool** will be donated to charity, with the final recipient chosen by the first-place winner.
- **60% of the prize pool** will be split among the top 3 participants.
- **1st place**: 50% of the prize pool
- **2nd place**: 30% of the prize pool
- **3rd place**: 20% of the prize pool
In addition, for each star you earn during the Advent of Code, **Base42 will donate 5 MKD directly to the charity of choice.**
## Participation Fee:
- **Optional Fee**: There is a participation fee to enter the prize pool, which will go directly into the prize fund. **The fee is 200 MKD**. However, you can still join the leaderboard without paying the fee. If you choose not to pay, you'll be excluded from the prize pool but can still participate and compete for fun and donation.
- **Deadline for entering the competition**: December 15th.
## Rules:
- **Code of Ethics**: While AI tools are prohibited in the competition, we recognize that it’s not always possible to prevent the use of such tools. We trust participants to follow the honor system and compete fairly. Please keep the spirit of the event in mind and avoid using AI to solve the puzzles. Let’s keep it a challenge of skill and creativity!
- **Joining the Competition**: To enter, join the [Base42 Discord server](https://discord.gg/424xxTZVYX?ref=blog.42.mk), sign up, and join the official Advent of Code leaderboard.
- **Sponsorship**: Companies are invited to sponsor the event and contribute to the prize pool. Sponsors can contribute any amount, and their donation will be added to the prize pool, following the same distribution rules as above.
- **Charity Selection**: The first-place winner will have the privilege of selecting the charity that will receive the 40% donation from the prize pool as well as the donation of the contributions from stars.
- **Fair Play**: Participants are expected to compete with integrity and in accordance with the rules of Advent of Code. Any attempt to exploit loopholes or cheat will result in disqualification.
- **Online**: The competition will mostly be online as it's very long running, but you're welcome and encouraged to group up and come by in Base42 IRL and solve challenges together.
## Get Involved:
- **Compete**: Solve the daily puzzles, earn stars, and climb the leaderboard. Every star counts towards increasing our charity donation!
- **Support a Cause**: Help us make a real difference in the world by contributing through your coding skills. Every time you solve a puzzle, you’re helping to fund a charity chosen on the final day.
- **Sponsor the Event**: If you're part of a company that wants to get involved, consider sponsoring the competition! For more info, contact us at [base42mk@gmail.com](mailto:base42mk@gmail.com).
## Why Participate?
- **For the Thrill of Coding**: Challenge yourself with daily puzzles and see how you stack up against other talented developers.
- **For a Good Cause**: Not only will you be competing for great prizes, but you'll also be contributing to a worthy charity chosen by the first-place winner.
- **For Being Awesome**: Do you even need a reason to flex your 1337 coding skillz?
We can’t wait to see who takes the top spot this year and to see how much we can raise for charity! Let’s make this the best Advent of Code yet. Good luck and happy hacking!
## Questions?
If you have any questions about the competition or need more information on how to join, feel free to reach out to us on the Discord server, social media, or via email at [base42mk@gmail.com](mailto:base42mk@gmail.com). Let’s code for a cause!