alemi.dev hi! i'm alemi, this is my web space. here you can find info about me, my favourite projects and some loger thoughts i write down sometimes Zola 2026-03-03T06:52:32+02:00 https://alemi.dev/atom.xml Subsonic TUI player 2026-01-01T14:07:02+01:00 2026-01-01T14:07:02+01:00 alemi https://alemi.dev/projects/navrs/ <h1 id="navrs">navrs</h1> <p>Spotify is ethically questionable, technically unimpressive and quality-wise underwhelming. While it is very convenient, switching off was always a matter of time.</p> <p>While bandcamp lasts (hopefully a while longer...) having my own files streamed by my own server sounds quite nice, and <a rel="noopener" target="_blank" href="https://www.navidrome.org/">navidrome</a> does just that! It serves a subsonic-compatible API, which means many existing applications can connect to it!</p> <p>But while on Android there's quite a selection of fully featured clients, desktop offers are not as good. Often buggy and oversized electron blobs, i neded up using the web client for a while.</p> <p>Recently I moved to a place with worse internet and suddenly having caching work became a necessity. So I made my own player, and since I tend to prefer terminal interfaces, it had to be a TUI!</p> <p>It is still quite rough around the edges, but definitely usable. It's become my default way to listen to music while on desktop.</p> <p>By the way, I wanted to call this <code>subtui</code> but it was already in use...</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/navrs.git">source code</a></p> </blockquote> Uptime Monitor 2024-12-10T22:14:41+02:00 2024-12-10T22:14:41+02:00 alemi https://alemi.dev/projects/upp/ <h1 id="upp">upp</h1> <p>While trying to deploy, publicize and monitor a new website, we encountered some DNS issues. This was unacceptable: we were reachable less than 70% of the time!</p> <p>But to solve such issue, we would first need to actually measure it and check for patterns.</p> <p>So I made <code>upp</code>: a very simple, batteries-included uptime monitor which can just keep everything in memory (or store in an sqlite db if desired).</p> <p><code>upp</code> may not be as sophisticated as other uptime monitors but the interface integrates with my website's style and it's super easy to add sites to monitor, or even hack in more protocols!</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://up.alemi.dev">my monitor</a> -- <a rel="noopener" target="_blank" href="https://git.alemi.dev/upp.git">source code</a></p> </blockquote> An Open remote-development framework 2024-09-18T17:11:00+02:00 2024-09-18T17:11:00+02:00 alemi https://alemi.dev/projects/codemp/ <div align="center"> <a href="https://code.mp" target="_blank"><img src="https://code.mp/static/banner.png" alt="codemp logo" style="max-width: 100%" /></a> </div> <blockquote> <p><code>codemp</code> is a <strong>collaborative</strong> text editing solution to work remotely.</p> </blockquote> <p>It seamlessly integrates in your editor providing remote cursors and instant text synchronization, as well as a remote virtual workspace for you and your team.</p> <blockquote> <p><code>codemp</code> is build with state-of-the-art CRDT technology, guaranteeing eventual consistency.</p> </blockquote> <p>This means that all agents are guaranteed to converge to a consistent state once all changes are received, <em>no matter their order or timing</em>, while preserving each operation's original intention. On top of this baseline, <code>codemp</code>'s protocol is optimized for speed and low network footprint, meaning even slow connections or dated hardware can provide stable real-time editing.</p> <h1 id="making-remote-development-as-pleasant-as-on-site">making remote development as pleasant as on-site</h1> <p>I'm a fan of remote working: offices are distracting and having two sets of computer gear is wasteful and commuting wastes a lot of time (and also pollutes if you don't walk or bike to work!).</p> <p>Most employers told me that "being in office makes working together easier", that "I need to be close with my colleagues to effectively work", but I believe these are false claims.</p> <p>My work is mostly developing software and systems, and can be split in</p> <ul> <li>actually making the thing</li> <li>explaining the thing</li> </ul> <p>While the explaining part requires interaction (<em>of course</em>), a call with virtual blackboard is perfect and often better because each colleague has their PC at hand and can help me search or test things, rather than just looking at me explain.</p> <p>For actually making the thing instead I usually work best alone: making software is mostly thinking, writing is hopefully the least time-intensive part of the job. I think while writing thanks to the compiler/LSP feedback loop, but it's mostly exploring and thinking.</p> <p>Actual collaborative work is usually debugging, or modeling features. These require us all to be in our dev environments, otherwise it quickly becomes someone debugging/modeling and everyone else watching (<em>or not even that</em>)</p> <h1 id="exploring-the-competition">exploring the competition</h1> <p>There are some available solutions, such as LiveShare by Microsoft or CodeWithMe by JetBrains, but these are all locked in their own ecosystems, mostly offered as tools to complete the suite they're selling.</p> <p>A collaborative tool <strong>must not</strong> lock you in, otherwise colleagues with different tastes will be left out as their environment isn't compatible.</p> <p>I want a truly cross-editor solution, to be able to work with anyone without having to comprimise or my editor (or having them switch for me).</p> <h1 id="introducing-codemp">introducing <code>codemp</code></h1> <p>Fed up with these limitations, around 2022 I started working on "Code Multi Player", my solution for remote development. By mid 2023 I had onboarded some friends and we were all working hard on different sides of this project.</p> <p><code>codemp</code> has many parts: we have a core library which is used to build many different clients, and a reference server which handles both GRPC and web traffic. Distributing work, researching deeply and generally doing our best, we never gave up and made something we're proud of.</p> <p>As of October 2024, <code>codemp</code> is almost ready for public release. We plan to offer commercial subscriptions to fund our infrastructure and ongoing development, but we are deeply committed to making an <strong>Open</strong> solution, to connect any environment and allow seamless remote development.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://code.mp">website</a> -- <a rel="noopener" target="_blank" href="https://git.alemi.dev/codemp/lib.git">core</a> -- <a rel="noopener" target="_blank" href="https://git.alemi.dev/codemp/proto.git">proto</a> -- <a rel="noopener" target="_blank" href="https://git.alemi.dev/codemp/nvim.git">nvim</a> -- <a rel="noopener" target="_blank" href="https://git.alemi.dev/codemp/vscode.git">vscode</a> -- <a rel="noopener" target="_blank" href="https://git.alemi.dev/codemp/intellij.git">intellij</a> -- <a rel="noopener" target="_blank" href="https://git.alemi.dev/codemp/sublime.git">sublime</a></p> </blockquote> Cleaning up your git history 2024-07-02T01:16:13+02:00 2026-03-03T05:45:09+02:00 alemi https://alemi.dev/blog/cleaning-up-git-history/ <p>As writing code becomes more and more accessible, the number of software developers is growing steadily and more of them start at younger ages. This is great!</p> <p>But a side effect of starting to work on one's software portfolio earlier is that often choices may be... <em>not very professional</em>. Maybe an old email address you'd rather make disappear, maybe throwing in your full legal name, maybe vulgar commit messages, it happened to <strong>everyone</strong>. What to do? Hide the project? Delete git history and re-commit as a single "initial commit"??</p> <p>None of this really was acceptable for me so I decided to look into better solutions. Git is such an awesome tool, <em>there must be a perfect solution, right????</em></p> <h1 id="the-problem">The problem</h1> <p>Sorry, there will be compromises. <a href="/img/get-used-to-disappointment.jpg" title="if you didn't get this reference find 1h 38m of free time and plug this line into google">Get used to disappointment</a>.</p> <p>Git repositories are chains of commits: every new one builds cryptographically on top of previous commits. This makes impossible to just go and change something in the first commit: <em>you need to redo them all</em>! While a few dozens of commits are manageable, hundreds are really hard to fix and trying to fix thousands manually is plain madness.</p> <p>Commits store both an "author" and a "committer". What you see is usually the "author", but both fields are there. Remade commits may replace the "committer" field, making your rewrite obvious, be wary!</p> <p>Similarly, commits have an "author date" and a "commit date". We want to preserve the "author date", as it is displayed and shows our project timeline, but we should probably be fine updating the "commit date" to current time.</p> <p>So, without further ado, let's list our needs and dive into possible solutions</p> <h3 id="desiderata">Desiderata</h3> <ul> <li><input disabled="" type="checkbox"/> <strong>replace authors</strong>: must be able to change commit authors</li> <li><input disabled="" type="checkbox"/> <strong>preserve original time</strong>: while "committed" date can change, "created" date shouldn't</li> <li><input disabled="" type="checkbox"/> <strong>fine-grained editing</strong>: allow changing only some commits</li> <li><input disabled="" type="checkbox"/> <strong>commits signature</strong>: keep commits signed, if signed</li> <li><input disabled="" type="checkbox"/> <strong>automatic</strong>: there should be no need for manual tweaking while rewriting</li> <li><input disabled="" type="checkbox"/> <strong>fast</strong>: ideally this shouldn't take hours or days to complete</li> </ul> <h1 id="our-options">Our options</h1> <blockquote> <p>note that this is not a complete list, just what i am aware of! <a href="/about/contacts">get in touch</a> if you know more or have notes on these!</p> </blockquote> <h2 id="mailmap">Mailmap</h2> <p>The simplest and built-in way to do this is with git's <code>mailmap</code>. Just create a <code>.mailmap</code> in your repository root directory with every occurrence to replace.</p> <p>For example, this will replace all commits by <code>old-user</code> (with or without mail) to <code>your-user</code> with mail:</p> <pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>your-user &lt;[email protected]&gt; old-user &lt;[email protected]&gt; </span><span>your-user &lt;[email protected]&gt; old-user &lt;&gt; </span></code></pre> <p>This file can then be placed in the repository root, and git will use it to replace old authors in every command it runs.</p> <p>This method doesn't rewrite history, rather registers "an alias" that git uses. This is by far the cleanest and fastest method (as it doesn't really rewrite anything), but also the worst method as it doesn't really rewrite history. If you're trying to hide sensitive information, this isn't useful for you, but if you just want to remove an old dead email go for .mailmap.</p> <h3 id="summary">summary</h3> <ul> <li><input disabled="" type="checkbox"/> <strong>replace authors</strong>: this doesn't rewrite history</li> <li><input disabled="" type="checkbox" checked=""/> <strong>preserve original time</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>fine-grained editing</strong>: literal matching via .mailmap file</li> <li><input disabled="" type="checkbox" checked=""/> <strong>commits signature</strong>: as commits are not rewritten, signatures are unchanged</li> <li><input disabled="" type="checkbox" checked=""/> <strong>automatic</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>fast</strong></li> </ul> <h2 id="rebase-amend">Rebase + Amend</h2> <p>This method is the simplest for very small repos and will give the best results, but as repository complexity increases it quickly becomes excessively hard to make work.</p> <p>Basically this starts from the first commit and rebases + amends all commits, resetting author to your current <code>.gitconfig</code> values and updating the date to the original value (as it otherwise would get updated to now).</p> <p>This works extremely well for small repos with a single non complicated branch and where all commits are yours, but if this isn't the case avoid using this method as it will rewrite even other contributors' commits, and won't automatically handle merges, requiring manual intervention.</p> <pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> git rebase</span><span style="color:#bf616a;"> -r --root --exec </span><span>&#39;</span><span style="color:#a3be8c;">env GIT_COMMITTER_DATE=&quot;$(git log -n 1 --format=%aD)&quot; git commit --amend --no-edit --reset-author --no-verify --date=&quot;$(git log -n 1 --format=%aD)&quot;</span><span>&#39; </span></code></pre> <p>Since this is a big command, let's break it down:</p> <ul> <li><code>git rebase</code> will start a new rebase</li> <li><code>-r</code> tells git to attempt to keep branching structure while rebasing</li> <li><code>--root</code> tells git to rebase from this branch root, allowing us to redo the first commit</li> <li><code>--exec</code> will run given command for each commit being rebased: <ul> <li><code>env GIT_COMMITTER_DATE="$(git log -n 1 --format=%aD)"</code> gets commit date from log and sets env var<sup>1</sup></li> <li><code>git commit --amend</code> amends this commit, so we can change its metadata</li> <li><code>--no-edit</code> we don't want to change the commit itself</li> <li><code>--reset-author</code> we want to reset this commit's author to our configured values</li> <li><code>--no-verify</code> we are changing signatures, verification will fail, skip it and put new signatures in place (if configured to do so)</li> <li><code>--date="$(git log -n 1 --format=%aD)"</code> we want to keep the author date as the original value (which we get from git log), otherwise it would get updated to current time</li> </ul> </li> </ul> <p><em><sup>1</sup>: if I remember correctly, there is no command line argument to set committer date, so we need to use an env var</em></p> <blockquote> <p>this is taken and adapted from a <a rel="noopener" target="_blank" href="https://stackoverflow.com/questions/750172/how-do-i-change-the-author-and-committer-name-email-for-multiple-commits">stack overflow answer</a>, you may be interested in reading the original context for more tips</p> </blockquote> <h3 id="summary-1">summary</h3> <ul> <li><input disabled="" type="checkbox" checked=""/> <strong>replace authors</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>preserve original time</strong></li> <li><input disabled="" type="checkbox"/> <strong>fine-grained editing</strong>: will overwrite everything unconditionally</li> <li><input disabled="" type="checkbox" checked=""/> <code>!</code> <strong>sign commits</strong>: commits will all be signed again if your git is configured to do so, but signatures will be different from original ones and <em>all</em> commits will be signed</li> <li><input disabled="" type="checkbox"/> <strong>automatic</strong>: merges are not handled automatically</li> <li><input disabled="" type="checkbox"/> <strong>fast</strong>: as every commit is actually redone, this takes longer than mailmap method</li> </ul> <h2 id="git-filter-repo">Git Filter Repo</h2> <p>If neither of above methods works for you, a dedicated tool exists for precise in-depth repository rewriting: <a rel="noopener" target="_blank" href="https://github.com/newren/git-filter-repo">git-filter-repo</a>.</p> <p><code>git filter-repo</code> likely is in your distro's repositories for installation, but if not can be run as a python script (more <a rel="noopener" target="_blank" href="https://github.com/newren/git-filter-repo/blob/main/INSTALL.md">here</a>)</p> <p>This tool allows writing arbitrary python callbacks which will be run for each commit and can do filtering and rewriting. For example, this command will change all commits which don't have <code>[email protected]</code> as mail but start with <code>your-user</code> as author:</p> <pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> git filter-repo</span><span style="color:#bf616a;"> --commit-callback </span><span>&#39; </span><span style="color:#a3be8c;"> if commit.author_name.startswith(b&quot;your-user&quot;) and commit.author_email != b&quot;[email protected]&quot;: </span><span style="color:#a3be8c;"> print(f&quot;changing commit by {commit.author_name} &lt;{commit.author_email}&gt;&quot;) </span><span style="color:#a3be8c;"> commit.author_email = b&quot;[email protected]&quot; </span><span style="color:#a3be8c;"> commit.author_name = b&quot;your-user&quot; </span><span style="color:#a3be8c;"> commit.committer_email = b&quot;[email protected]&quot; </span><span style="color:#a3be8c;"> commit.committer_name = b&quot;your-user&quot; </span><span>&#39; </span></code></pre> <p>sky is the limit! be sure to check its <a rel="noopener" target="_blank" href="https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html">man pages</a> if you plan to do more complex rewriting.</p> <p>note that <code>filter-repo</code> can also work with mailmap files: just <code>git filter-repo --mailmap .mailmap</code> to rewrite your repo history applying mailmap changes.</p> <h3 id="summary-2">summary</h3> <ul> <li><input disabled="" type="checkbox" checked=""/> <strong>replace authors</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>preserve original time</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>fine-grained editing</strong></li> <li><input disabled="" type="checkbox"/> <strong>sign commits</strong>: because all signatures change, <code>filter-repo</code> will just remove commit and tags signatures</li> <li><input disabled="" type="checkbox" checked=""/> <strong>automatic</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>fast</strong>: <code>filter-repo</code> is made to be fast and efficient</li> </ul> <h2 id="bonus-bfg">Bonus: BFG</h2> <p>This is another very convenient cleaning method, but it won't replace commit authors, instead it replaces content at each relevant revision. Say you committed something... angry, how do get rid of it without changing that commit and rebasing completely on it? <a rel="noopener" target="_blank" href="https://rtyley.github.io/bfg-repo-cleaner/">BFG repo cleaner</a> comes to the rescue! Apart from clearing large objects from your repo (which is super useful), BFG allows removing sensitive data from previous revisions.</p> <p><strong>Be warned that</strong> BFG won't change anything present in current revision! It's important to commit away whatever must be deleted <em>before</em> running BFG.</p> <p>Using BFG for this purpose is super simple: first make a plaintext file with your words to be replaced, one per line. Then just:</p> <pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> java</span><span style="color:#bf616a;"> -jar</span><span> bfg.jar</span><span style="color:#bf616a;"> --replace-text</span><span> replacements.txt path/to/repo </span></code></pre> <p>and done! BFG is super fast and will show you detailed informations on what it did</p> <h3 id="summary-3">summary</h3> <ul> <li><input disabled="" type="checkbox"/> <strong>replace authors</strong>: doesn't touch commit authors</li> <li><input disabled="" type="checkbox" checked=""/> <strong>preserve original time</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>fine-grained editing</strong></li> <li><input disabled="" type="checkbox"/> <strong>sign commits</strong>: BFG strips all signatures</li> <li><input disabled="" type="checkbox" checked=""/> <strong>automatic</strong></li> <li><input disabled="" type="checkbox" checked=""/> <strong>fast</strong></li> </ul> <h1 id="wrapping-up">Wrapping up</h1> <p>As usual it's better preventing than curing. Including as little personal identifying information as possible in your git stuff, honestly in your online presence in general, should be the default.</p> <p>Git is awesome and we often are put off by its complexity. It's easy to get started with git, but as stuff won't merge it's easier to delete and clone again rather than understanding what happened. Gaining more insights about how git works under the hood allows to use it more efficiently: git is your best friend!</p> My take on ActivityPub 2024-03-14T17:57:20+02:00 2024-03-14T17:57:20+02:00 alemi https://alemi.dev/projects/upub/ <h1 id="mpub">μpub</h1> <p><a rel="noopener" target="_blank" href="https://www.w3.org/TR/activitypub/">ActivityPub</a> is a W3C decentralized protocol for social networks (but not only!). The most famous implementation is <a rel="noopener" target="_blank" href="https://joinmastodon.org/">Mastodon</a>, which powers over half of the network (which is called the <code>Fediverse</code>).</p> <p>A few years ago I was actively looking for alternative social media: I don't want to pump out content for the big gatekeepers, so that they can monetize it behind my back while building an accurate profile of me and my interests (<a rel="noopener" target="_blank" href="https://www.justice.gov/usao-sdny/pr/united-states-attorney-resolves-groundbreaking-suit-against-meta-platforms-inc-formerly">which could be used to discriminate</a>).</p> <p>The Fediverse really caught my interest: being decentralized I can completely own my data and decide where it flows and how long it stays up. This is awesome! I've been a <a rel="noopener" target="_blank" href="https://joinmastodon.org/">Mastodon</a> user since the end of 2022 and later in 2023 migrated to <a rel="noopener" target="_blank" href="https://akkoma.social/">Akkoma</a>. I've had a splendid time on both but neither really fit all my needs.</p> <p>One of my biggest gripes with current Fediverse is that different platform aren't fully intercompatible: articles posted on <a rel="noopener" target="_blank" href="https://join-lemmy.org/">Lemmy</a> (a reddit alternative) don't federate nicely, often lacking link or picture or replies. Another big issue is privacy and content addressing: while AP allows to finely control who (<em>in theory</em>) has access to your content, most implementations just offer 4 (or less) "levels of privacy".</p> <p>So I decided to try and cook my own implementation: <code>μpub</code>!</p> <p>This is quite an ambitious project, but nonetheless I dove right in! I'm making my own frontend and backend, both completely in Rust.</p> <p>This is an ongoing effort: it likely will never really be done as the Fediverse keeps evolving, but as of july 2024 it's definitely usable! Be sure to check out the dev instance to get a feel of how it looks and works.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/upub.git">source code</a></p> </blockquote> Collecting Comments 2023-10-15T04:27:14+02:00 2023-10-15T04:27:14+02:00 alemi https://alemi.dev/projects/guestbook/ <h1 id="guestbook-rs">guestbook.rs</h1> <p>I'm starting to learn and love the <a rel="noopener" target="_blank" href="https://indieweb.org/">IndieWeb</a>: the small and cute sites are lovely and so many! Some are simple blogs, others are full blown role-playing-games! Sometimes i find a really great site and i'd love to leave a comment showing my awe, but there usually isn't a guestbook.</p> <p>I also really wanted to collect comments from people visiting my site. I know it's not many, and I know they usually won't bother, but I still want to leave the chance and hope (: So i decided to get to work and cook something myself! And thus <code>guestbook.rs</code> was born.</p> <p><code>guestbook.rs</code> is an all-in-one solution: it works with an sqlite database, requires zero config and bundles a web interface to read and post comments. You can check how it looks by default <a rel="noopener" target="_blank" href="https://guestbook.alemi.dev">here</a>.</p> <p>But it doesn't end here: <code>guestbook.rs</code> is quite configurable! It can be deployed as a bare API (like I do <a rel="noopener" target="_blank" href="https://alemi.dev">on this site</a>) and then used with a simple HTML form.</p> <p>The underlying infinite-scroll script is <a rel="noopener" target="_blank" href="https://cdn.alemi.dev/web/guestbook.js">publicly available</a> and can be used for other projects: it has jsdocs and is tiny!</p> <p>If you like what you see, check it out and deploy it on your site! Maybe even leave a comment <a rel="noopener" target="_blank" href="https://alemi.dev">on the frontpage</a> :3</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/guestbook.rs.git">source code</a></p> </blockquote> An (even more) minimal way to test API routes 2023-05-21T18:35:02+02:00 2024-10-20T15:41:02+02:00 alemi https://alemi.dev/projects/postwoman/ <h1 id="postwoman">postwoman</h1> <p>I have seen <a rel="noopener" target="_blank" href="https://www.postman.com/">postman</a> used in a lot of places and by a lot of people, but I've never really understood it. Wouldn't I be better off using <code>curl</code> and maybe scripting some requests from the terminal? Why would I need to download a dedicated software for that? Also electron isn't exactly lightweight, so I've always steered away.</p> <p>My current job at the time however put a lot of emphasis on testing, and introduced me to test-heavy workflows. At that point I saw postman usefulness: most value comes from the underlying collection! Developers share one and added routes they would work on. Once we had tested our code "from the inside" with unit and integration tests, we would send it to staging and test if "from the outside", running all requests in the postman collection.</p> <p>This is great! However newer postman versions require me to register an account to be able to use the collection features, and once you're logged in, everything is kept in sync with their servers automatically.</p> <p>This is awful! Why would you do that! I could not find an option to disable such feature at the time, and it was a huge dealbreaker: we can't have company internal structure and tokens just sitting on postman servers like that. What the hell!</p> <p>So I decided to write my own solution. The collection format is just a json file, with proper documentation. Making requests is easy enough. Loading secrets can be done from the shell environment. And just like that, the first version of <code>postwoman</code> was born! Why postwoman? Because we need more women in tech (:</p> <p>I eventually found a rust library handling postman collection deserialization, so I could focus on running all tests.</p> <p>This doesn't provide all features postman supports, only a subset is actually used, and it's not scriptable due to the weird print format. But it works, if you have a simple collection and would rather not use postman, consider using postwoman! If it doesn't do what you need, send a PR my way!</p> <h2 id="reborn">reborn</h2> <p>Original attempt ended up not being as useful as i'd like: making a CLI interface that works well for both sending and building requests is rather complex and the postman collection format is a mess.</p> <p>So I decided to start anew: the <code>v0.3</code> version completely dumped postman format and json, starting from scratch. Routes are now defined in <code>toml</code> files, way easier to manage by hand, and can be structured in a tree thanks to import statements.</p> <p>The main CLI tool no longer attempts to maintain your collection for you, it just reads it and runs it!</p> <p>I'm way more fond of this approach: editing endpoints in GUI apps is annoying and now I can leverage my editor to quickly define all I need. Plus, because it's just a plain file tree, it's super easy to keep organized and even put it in git!</p> <p>There is a super simple testing framework built in with extractors and expected results: just select your fields with JQ syntax and assert it equals to your expectations. It's also possible to just check status code, or to not check at all and just extract response fields or headers.</p> <p>Just like before, all routes can contain variables which will be replaced at runtime from current environment.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/postwoman.git">source code</a></p> </blockquote> Why I don't trust AI code completion 2023-05-07T02:55:13+02:00 2023-10-28T17:14:45+02:00 alemi https://alemi.dev/blog/dont-trust-ai-completion/ <p>While I could be making cheap points about how Copilot suggests <a rel="noopener" target="_blank" href="https://caselaw.findlaw.com/court/us-dis-crt-n-d-cal/2200493.html">copyrighted</a> or <a rel="noopener" target="_blank" href="https://arxiv.org/abs/2108.09293">vulnerable</a> code, I want to focus more on the Developer Experience.</p> <blockquote> <p>edit: <a rel="noopener" target="_blank" href="https://arxiv.org/abs/2211.03622">another interesting publication</a></p> </blockquote> <h1 id="searching-but-faster">Searching but faster</h1> <p>AI assistants are usually just search engines in your editor. They don't produce new algorithms or solutions, instead fitting other's work to your specific case.</p> <p>LLMs have incredible potential as writing aids: I never know how to end an email and getting the machine to write those for me is <em>pure bliss</em>.</p> <p>But when used as search-engine replacements, I believe they are more an issue than a tool.</p> <h1 id="context-matters">Context Matters</h1> <p>Searching on the web is an art. Knowing some Google tricks will make your searches way easier, and discarding machine-generated results just from the results list is becoming extremely necessary.</p> <p>But even once you find your solution, it's important to vet the authenticity. Is this a blog post? Who wrote it? How long ago? Maybe it's a tutorial instead, made by the library maintainer.</p> <p>Or maybe it's some step-by-step guide which glosses over unknown details. Context matters! Many times I find a result which looks sort of valid, and then discover that many API functions/endpoints don't exist anymore. Or maybe a guide on how to set up a specific toolchain, which changed so much in just 1 year that the guide makes no sense anymore (<em>cough Android cough</em>) Or maybe the solution itself is not perfect, and somebody left a comment improving it, but it gets skipped by the LLM and you never actually read it.</p> <blockquote> <p>It could as well be some "eight-hand tutorial", from someone with very limited understanding repeating what they saw in another "seventh-hand tutorial".</p> </blockquote> <p>Separating the reply from its context removes very important information, which may save some later debugging.</p> <p>Some very popular libraries may be new and hyped, with good documentations and few releases, but something like Java has so much material written and so many changes over the years that you better make sure which version is the target of the article you're reading!</p> <h1 id="skipping-parts-makes-it-harder">Skipping parts makes it harder</h1> <p>It may sound very convenient when asking "how to compile my program" to read <code>gcc -o a.out &lt;your_file.c&gt;</code>. But that strips away the learning, and as soon as you want to link in pthreads or math you're back googling.</p> <p>Spending time learning more than <em>exactly the answer you need</em> will dramatically improve your efficiency down the line, because you will know how it works and how to debug things.</p> <blockquote> <p>Adding more layers of tooling or libraries increases the project complexity dramatically, and the biggest cost you are going to pay down the line is maintainability.</p> </blockquote> <p>Learning what you're adopting <strong>when you're adopting it</strong> is imperative if you plan to also maintain your project, because learning how your middleware library works once you have all the auth handlers hooked and solidified will drive you mad.</p> <h1 id="convenience-isn-t-enough-of-a-reason">Convenience isn't enough of a reason</h1> <p>A superficial point might be that with the time saved by googling, you can try more solutions and see which one works.</p> <p>This is a very valid approach for quick prototypes, like some backend boilerplate, but I'd argue that using a language/framework with less boilerplate would be cutting the issue at the root, rather than throwing a new tool at it.</p> <p>If your go-to framework requires you to write a lot of useless lines and configuration to get going, consider trying something with more batteries included: prototyping with <a rel="noopener" target="_blank" href="https://flask.palletsprojects.com/en/latest/">flask</a> is incredibly fast, and you can later swap it with <a rel="noopener" target="_blank" href="https://fastapi.tiangolo.com/">FastAPI</a> or (if you really need to get fast) something like <a rel="noopener" target="_blank" href="https://github.com/tokio-rs/axum">axum</a>.</p> <p>If you often find yourself writing <code>isOdd()</code> or <code>pickRandom()</code> or <code>formatTime()</code> you probably should be using a language with a richer standard library for your prototyping.</p> <blockquote> <p>Don't make copilot reinvent the wheel for you every time! Very qualified and experienced people already wrote excellent software you can leverage.</p> </blockquote> <p>I don't think a code assistant should help you prototype, it's a bandaid on an underlying problem, and once you are writing production software, a code assistant cannot be held responsible for its mistakes, do the plumbing yourself!</p> <h1 id="am-i-a-luddite">Am I a Luddite?</h1> <p>Maybe. I really dislike code-assistants because they are trained on public code. There's way more bad code than good code, I really don't trust software by default.</p> <p>This may sound elitist, but I say it without judgement: just like some art is great and most is average, not all code <em>must</em> be great, but losing the ability to judge and evaluate is not acceptable for me.</p> <p>I read some articles about how a "modern AI-powered junior engineer" beats a "senior experienced software architect" because it gets it done incredibly faster, but maintenance is weirdly never considered in these articles. I don't need to throw in "AI" to make the same statement: an inexperienced junior engineer could be able to make a proof of concept way faster, ignoring problems and edge cases which will blow in their face later on. An experience software architect may take their time, but will probably be able to identify pain points, and address them early.</p> <h3 id="should-you-use-code-assistants">Should you use code-assistants?</h3> <p>Not up to me to say, really. I hope I made my stance clear: this isn't a valuable tool for me. Your experience may differ from mine and while you may find such tooling relevant and convenient, please respect my opinion and choice to not wanting them anywhere near my work.</p> Infecting foreing processes 2023-03-25T13:26:00+02:00 2023-03-25T13:26:00+02:00 alemi https://alemi.dev/projects/pox/ <h1 id="pox">pox</h1> <p>I have always been fascinated by the way my Operating System makes my hardware work.</p> <p>I understand transistors and logic gates, and I'm familiar in writing userspace programs. But what happens in between those? While my job started teaching me about kernels, I stumbled upon "<a rel="noopener" target="_blank" href="https://youtu.be/xN5WjaeeklA">i'm in ur address space</a>".</p> <p>This video blew my mind and I absolutely had to do something like that myself! I thus decided to work on <code>pox</code>: an infection framework for processes.</p> <p>My initial design works with PTRACE syscall (and thus only linux), but Windows injectors are easier due to <code>CreateRemoteThread</code> anyway. I built a set of tools to help mess with remote processes, and then an injector.</p> <p>The naming comes from diseases (-pox being a common suffix, and injector being a transmission "vector"), because these things will make your processes ill! (:</p> <p>This is still very much work in progress: it works, but only with root privileges and on unhardened kernels.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/pox.git">source code</a></p> </blockquote> <h1 id="cordy">cordy</h1> <p>Once I could load custom shared object inside arbitrary processes, I needed something to infect them with!</p> <p>I built cordy, named from a <a rel="noopener" target="_blank" href="https://en.wikipedia.org/wiki/Ophiocordyceps_unilateralis">zombie fungus</a>: it will spawn a new thread in affected process and expose a LUA repl over TCP.</p> <p>This allows me to "shell into" other processes and dump their stack/heap, allocate/deallocate regions or even overwrite their memory.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/cordy.git">source code</a></p> </blockquote> TUI Oscilloscope 2022-12-24T03:04:00+01:00 2022-12-24T03:04:00+01:00 alemi https://alemi.dev/projects/scope-tui/ <h1 id="scope-tui">scope-tui</h1> <p>I love watching the waveform of what I'm listening to and I'm also a big fan of terminal UIs, so when I found <a rel="noopener" target="_blank" href="https://github.com/fdehau/tui-rs">a TUI library</a> for Rust with a builtin chart widget, I <strong>immediately</strong> had to try making an <em>oscilloscope</em> with it.</p> <p>In just some days of work, I got a nice application ready to be used, built on top of tui-rs and pulseaudio simple API.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/scope-tui.git">source code</a></p> </blockquote> Enforcing Commit Style 2022-10-09T02:37:13+02:00 2022-10-11T13:45:06+02:00 alemi https://alemi.dev/blog/commit-style/ <p>I write ugly commit messages more often than I'd like to admit: too long, too deep, too obscure, too messy, too angry...</p> <p>To help me improve, it would be really helpful if git just wouldn't accept "<em>bad</em>" commit messages. While objectively defining (and identifying) "<em>bad</em>" is a subjective and potentially complex task, having git prevent me from committing is pretty easy thanks to git hooks.</p> It's Not Bikeshedding! 2022-10-07T10:54:21+02:00 2022-10-10T02:04:19+02:00 alemi https://alemi.dev/blog/its-not-bikeshedding/ <p>I often find myself reasoning on variable names or code style to an extent which may be classified as "bikeshedding", but I believe that my efforts are always worth the extra time investment in the long term.</p> <p>Refactoring is annoying and rarely a priority, but code is shared and read constantly. "<em>I'll fix it later</em>" most of the time is just not going to happen soon enough or at all.</p> Oxidizing Arduino 2022-10-07T00:55:56+02:00 2022-10-16T02:36:41+02:00 alemi https://alemi.dev/blog/arduino-rust/ <p>I wanted to build myself a small pc monitor, something simple with an oled display driven by an arduino. I'm not very fond of the Arduino IDE, and some quick research shows that Rust can compile for AVR.</p> <p>Since I really like Rust, this seemed like a perfect small project to take on, with much to learn in the making.</p> PC Monitor 2022-08-10T03:44:00+02:00 2022-08-10T03:44:00+02:00 alemi https://alemi.dev/projects/pc-monitor/ <h1 id="pc-monitor">PC Monitor</h1> <p>I wanted an hardware resource monitor for my desktop PC but I didn't want to spend much on some fancy or very specific solution, so I decided to make my own.</p> <p>I designed some basic firmware for an Arduino nano (rust) and a pcb to hold the MCU, some leds and a tiny OLED display. The firmware code is freely available on my github.</p> <p>I wrote a small blog post detailing the basics of arduino development in rust.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/pc-monitor.git">source code</a> -- <a rel="noopener" target="_blank" href="https://alemi.dev/blog/arduino-rust/">blog post</a></p> </blockquote> Dashboard 2022-06-03T02:01:00+02:00 2022-06-03T02:01:00+02:00 alemi https://alemi.dev/projects/dashboard/ <h1 id="dashboard">Dashboard</h1> <p>I wanted to gather some statistics but setting up a complete solution like Graphana + Prometheus was too much effort for my little data needs. I built a monolithic GUI application powered by an SQLite embedded db to fetch and display data. I then added a CLI interface to run distribuited daemonized data collectors archiving into a single db accessed by individual client guis.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/dashboard.git">source code</a></p> </blockquote> Minecraft protocol library 2021-09-30T17:05:54+02:00 2021-09-30T17:05:54+02:00 alemi https://alemi.dev/projects/aiocraft/ <h1 id="aiocraft">aiocraft</h1> <p>I like Minecraft, and due to its licensing, reverse-engineering the software is allowed and well documented. I made <code>aiocraft</code>, a client from scratch implementing its protocol, binding both rust and python for performant serialization and simple high-level development. The main struggle of this project was codegen: writing definitions for all types and versions in the game would be an enormous effort, so a way to auto generate them is needed. As of now, the codegen results are pushed as individual files to make LSPs and committing happier, but they will eventually be generated on demand upon installing.</p> <p>Not all protocol versions are supported, but 1.12 and 1.16 have all types implemented.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/aiocraft.git">source code</a></p> </blockquote> <h1 id="treepuncher">treepuncher</h1> <p>After creating types and bindings for the core minecraft flows and types, a more developer-friendly way to bots development was necessary. I built <code>treepuncher</code>, an hackable minecraft framework, which easily loads plugins, exposes event hooks and a scheduler and provides persistent storage for credentials.</p> <p>The client is still incomplete but simple automations can already be built, and at worst it's possible to directly hook on packet events.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/treepuncher.git">source code</a></p> </blockquote> Telegram bot framework 2020-11-10T18:10:00+01:00 2020-11-10T18:10:00+01:00 alemi https://alemi.dev/projects/abot/ <h1 id="abot">abot</h1> <p>I <small><i>(used to)</i></small> like Telegram because it allows me to deeply automate actions very easily. I developed some tools to make it more convenient for me to deploy bots.</p> <p>This eventually became the base for other people's projects, so I invested time in making it easily deployable to Heroku when it still had a free tier.</p> <p>It has a dockerfile and should still be runnable on most PaaS.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/abot/core.git">source code</a></p> </blockquote> <table class="center mt-2 w-100"> <tr> <td> <p><code class="color">these bots are discontinued</code></p> <p class="moreinfo" title="official announcements are superficial and deliberately unclear, new features are less geared towards instant messaging and more towards social media, some official messages by the team contained very distasteful dogwhistles">i don't feel aligned with telegram values anymore</p> <p class="moreinfo" title="deeper and deeper monetization and involvement with its own crypto makes telegram solidity dubious, as the little dev team focuses on weird new features rather than fixing old protocol weaknesses">the platform grows less trustworthy as days go by</p> <p>i'm trying to leave this behind and move to better alternatives</p> </td> </tr> </table> <h2 id="multiwordlebot">multiWordleBot</h2> <p>I find Wordle pretty fun but I'm incredibly bad at it. English is not my first language so my dictionary isn't super complete. I also wanted to be able to play together, not just compare afterwards. So I made myself a bot to be able to play multiple times a day without word limit and with friends. @multiwordle_bot can be added to groups and played together. Who can find the word first? It will track your attempts and give you the word definition once you're done. You can still enforce an attempts limit or make the match private. Check all options with /help wordle</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://t.me/multiwordle_bot">@multiwordle_bot</a></p> </blockquote> <h2 id="revwhisperbot">revWhisperBot</h2> <p>I never really understood the reason for whisper bots: can't you just send a DM? Why do you need to flex to everyone that you send a whisper just to that somebody? So I made the opposite: @revWhisperBot. It allows you to send, via inline, a message hidden from just some people.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://t.me/revwhisperbot">@revwhisperbot</a></p> </blockquote> <h2 id="trivia-robot">trivia_robot</h2> <p>I like quizzes from now and then, and I wanted to make a simple bot myself. I made this bot to play with friends in groups, revive conversations or laugh about impossible questions. All quiz parameters can be specified, and correct/wrong answers are tracked for each quiz. Powered by <a rel="noopener" target="_blank" href="https://opentdb.com/">opentdb.com</a></p> <blockquote> <p><a rel="noopener" target="_blank" href="https://t.me/trivia_robot">@trivia_robot</a></p> </blockquote> Breaking the Minecraft client 2020-06-06T18:50:00+02:00 2020-06-06T18:50:00+02:00 alemi https://alemi.dev/projects/bscv/ <h1 id="learning-reversing-with-minecraft">Learning reversing with Minecraft</h1> <p>I have always loved Minecraft: the lack of goal but complete freedom it gives makes it very appealing to me.</p> <p>Like everyone I started by punching trees but quickly moved to "modpacks" introducing complex relations and recipes. When that was no longer enough, I started discovering the potential of builtin game concepts: did you know minecraft redstone can be used to <a rel="noopener" target="_blank" href="https://www.pcworld.com/article/559794/8-bit-computer-processor-built-in-minecraft-can-run-its-own-games.html">make turing-complete machines</a>? Eventually automating the game from inside wasn't enough for me, I really wanted to make external tools.</p> <p>I started by messing with the network: once I found <a rel="noopener" target="_blank" href="https://wiki.vg/Protocol">the protocol spec</a>, I started building some simple scripts to keep the player online, then some crude proxies and automated bots.</p> <p>But the real fun started once I moved to injecting modifications at runtime. After learning what <a rel="noopener" target="_blank" href="https://docs.minecraftforge.net/en/latest/">Forge</a> is and what it does, I had a simple but complete framework to modify the game behavior directly.</p> <p>But Forge has its limitations: it provides some "hooks" which can call your code, but not everything is possible. I needed to go deeper.</p> <p>Bytecode modification frameworks exist in the minecraft developer world, and the most widely used is <a rel="noopener" target="_blank" href="https://github.com/SpongePowered/Mixin">Spongepowered Mixin</a>. This allows to rewrite whole methods in classes at the bytecode level at runtime, but using "plain" java. As interesting as it sounded, I felt like it would be "another Forge", where I would eventually hit the brick wall. So I decided to skip this step and go deeper.</p> <p>Thanks to <a rel="noopener" target="_blank" href="https://asm.ow2.io/">objectweb ASM</a> library and some modloader magic (specific to minecraft), it's possible to write JVM assembly and insert that wherever you want. It's possible to rewrite access modifiers, completely reroute methods and mess up the stack in so many extremely obscure ways (array errors when you pop too much are just soooooo fun to debug!).</p> <p>But this was it: I could now do anything I wanted, from rendering the tablist larger, to detaching the camera from the player, even making the client believe water is solid. I was so proud of my new skills I had to put them to use.</p> <p>I started participating in developing <del>hacks</del> <em>mods</em> for the game. It was so fun it quickly became addictive: the server source code is available for reading, and there are <strong>so many</strong> weird edge cases to find in Mojang messy Java! Spot a weird bug, make a <em>mod</em> which abuses it, enjoy an easier game, rinse and repeat!</p> <p>I want to stress that I <strong>never</strong> abused these <em>mods</em> against unknowing people: while it's just a game, I really would hate to ruin the experience to others thanks to unfair advantages. I'm doing this to <strong>learn</strong>, not to <strong>win</strong>!</p> <h1 id="bscv">BSCV</h1> <p>After helping for some time other projects, I decided I didn't just want to add mods here and there, refactor badly written implementations and clean up messy settings. I wanted to build a whole new environment. I thus decided to make a new <em>utility mod</em> from scratch, together with a lightweight patching framework. This fresh project aims to suit exactly my use cases while being modular and hackable. While it's nowhere as complete as my previous solutions were, it's <strong>clean</strong> and <strong>minimal</strong>, two features I really care about.</p> <p>This is a cooperative project with some friends, and all source code is hosted on our shared server.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/bscv.git">bscv</a> -- <a rel="noopener" target="_blank" href="https://git.fantabos.co/zaaarf/lillero.git">lll</a> -- <a rel="noopener" target="_blank" href="https://git.fantabos.co/zaaarf/lillero-loader.git">loader</a></p> </blockquote> neoVim config 2019-10-22T11:49:00+02:00 2019-10-22T11:49:00+02:00 alemi https://alemi.dev/projects/tinker-nvim/ <h1 id="tinker-nvim">tinker.nvim</h1> <p>I really like continuously optimizing my editor, and automatically installing/updating my config onto new systems became necessary to avoid keeping track of where is which feature. I made a github repository with my <code>.config/neovim</code> folder, so that it can be easily bootstrapped and updated by just cloning the config onto your pc.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/tinker.nvim.git">source code</a></p> </blockquote> <h1 id="peak-nvim">peak.nvim</h1> <p>A warm colorscheme with blue and red tones, to keep you cozy at night.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/peak.nvim.git">source code</a></p> </blockquote> <h1 id="vim-combo">vim-combo</h1> <p>A simple and silly vim plugin to keep track of your code streaks. Inspired from the "power mode" of Google Colab (and many other editors).</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/vim-combo.git">source code</a></p> </blockquote> DIY Controller Sequencer 2018-10-31T17:17:00+01:00 2018-10-31T17:17:00+01:00 alemi https://alemi.dev/projects/midi-controller/ <h1 id="cvkeyboard">CVKeyboard</h1> <p>I like music and always wanted my own MIDI controller. I decided I'd try to build it myself, powered by an old electric organ keyboard and an Arduino.</p> <p>But just a controller was not enough: I tried to program a comfortable sequencer built around playing the keyboard live. The controls are kind of clunky but it was very fun playing while it lasted!</p> <p>This was one of my first programming projects, and it taught me bit-packing, multiplexing and soldering. This was originally meant to be a CV keyboard but I never got my hands on any modular synth gear so I had to settle with MIDI.</p> <blockquote> <p><a rel="noopener" target="_blank" href="https://git.alemi.dev/cv-keyboard.git">source code</a></p> </blockquote>