<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Codeart — by Allan Koech]]></title><description><![CDATA[A software engineer's notes on building real systems — C++, Rust, Qt/QML, and the open-source tools that come out of the work.]]></description><link>https://www.codeart.co.ke</link><image><url>https://substackcdn.com/image/fetch/$s_!yEUh!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da6f509-88fe-4874-9781-59a9b4b5257b_256x256.png</url><title>Codeart — by Allan Koech</title><link>https://www.codeart.co.ke</link></image><generator>Substack</generator><lastBuildDate>Mon, 28 Sep 2026 03:14:55 GMT</lastBuildDate><atom:link href="https://www.codeart.co.ke/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Allan Koech]]></copyright><language><![CDATA[en-gb]]></language><webMaster><![CDATA[allankoech@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[allankoech@substack.com]]></itunes:email><itunes:name><![CDATA[Allan Koech]]></itunes:name></itunes:owner><itunes:author><![CDATA[Allan Koech]]></itunes:author><googleplay:owner><![CDATA[allankoech@substack.com]]></googleplay:owner><googleplay:email><![CDATA[allankoech@substack.com]]></googleplay:email><googleplay:author><![CDATA[Allan Koech]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Extending MantisBase: the C++ Edition (Part 1 — Setup)]]></title><description><![CDATA[MantisBase C++ Dev Packages Setup Guide]]></description><link>https://www.codeart.co.ke/p/mantisbase-cpp-dev-package-setup</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mantisbase-cpp-dev-package-setup</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Sat, 26 Sep 2026 10:22:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kChN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kChN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kChN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kChN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kChN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kChN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kChN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:203977,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/217394166?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kChN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kChN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kChN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kChN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7de09e-9b52-4960-9283-ff09b74cb947_1920x1080.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>One of MantisBase&#8217;s biggest goals has always been embeddability in any C++ codebase. In the past, you had to compile MantisBase from source, and if you&#8217;ve tried, you know it can be daunting.</p><p>Our biggest <em><strong>v0.4.x</strong></em> goal was shipping a dev package with shared libraries and header files, so you don&#8217;t have to build from source if dynamic linking works for you.</p><p><em>This is part one of a two-part series:</em> this post walks you through how to acquire and set up a MantisBase dev package. Part two will cover actually integrating it into your application.</p><h3>Which version</h3><p>From v0.4.0, we shipped a dev package, <code>mantisbase_v0.4.0-dev.zip</code>, with both static and shared libs plus header files. Unfortunately, the symbols weren&#8217;t exported correctly, which made most of it unusable.</p><p>That&#8217;s fixed as of the beta release <strong>v0.4.5</strong>, and we&#8217;ve also split the dev package by platform: <code>mantisbase_v0.4.5-[linux/windows]-cpp-dev.zip</code>. See the <a href="https://github.com/allankoechke/mantisbase/releases/tag/v0.4.5">release page</a>.</p><p>From this release onward, all necessary symbols are exported correctly. We no longer ship static libs for now; if you have a specific need for a static build, let us know!</p><h3>Getting the dev package</h3><p>Download the dev package for your platform (Linux or Windows) from the <a href="https://github.com/allankoechke/mantisbase/releases/tag/v0.4.5">GitHub Releases page</a> and unzip it to your desired directory.</p><blockquote><p><strong>Note:</strong> Header files for Windows and Linux are platform-specific, so they may not be 100% cross-usable.</p></blockquote><p>The unzipped directory structure looks like this:</p><pre><code><code>README.md        quick readme file
VERSION          release tag
include/         header tree for this OS (mantisbase headers + bundled
                 third-party headers: drogon, trantor, nlohmann/json,
                 jsoncpp, soci, spdlog, fmt, dukglue, duktape, wolfssl, ...)
libs/
  x86/           prebuilt shared library for x86-64 (libmantisbase.so) &#8212; Linux only
  arm/           prebuilt shared library for aarch64 (libmantisbase.so) &#8212; Linux only
                 (Windows ships x86_64 only, under libs/x86/)
cmake/
  MantisBaseConfig.cmake         find_package(MantisBase) entry point
  MantisBaseConfigVersion.cmake  version matching
</code></code></pre><p>On Linux, there are additional system prerequisites required at build and run time. Install them with:</p><pre><code><code>sudo apt-get update
sudo apt-get install -y libpq-dev uuid-dev</code></code></pre><p>Runtime shared libraries on Debian/Ubuntu are <code>libpq5</code> and <code>libuuid1</code>.</p><p>Windows requires no additional system dependencies to build or run against the dev package.</p><h3>Quick CMake integration</h3><p>This example assumes Linux; the workflow is similar for Windows with the Windows dev package.</p><p>First, create an empty CMake-based project <em>(via an IDE or any means you prefer)</em>. Copy the unzipped dev package into the project, e.g., into <code>mantisbase-linux-cpp-dev/</code>. The resulting directory structure looks like this:</p><pre><code><code>CMakeLists.txt                  application CMake file
main.cpp                        application entry point
mantisbase-linux-cpp-dev/       same folder structure as before
    README.md
    VERSION
    include/
    libs/
        x86/
        arm/
    cmake/
        MantisBaseConfig.cmake
        MantisBaseConfigVersion.cmake</code></code></pre><p>Point CMake at the package with <code>find_package</code>:</p><pre><code><code>cmake_minimum_required(VERSION 3.22)
project(my_app)

set(MantisBase_DIR "/path/to/mantisbase-linux-cpp-dev/cmake")
find_package(MantisBase REQUIRED)

add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE mantisbase::shared)
</code></code></pre><p><code>main.cpp</code>:</p><pre><code><code>#include &lt;mantisbase/mantisbase.h&gt;

int main(int argc, char* argv[])
{
    auto app = mb::MantisBase::create(argc, argv);
    return app-&gt;run();
}</code></code></pre><h3>Help</h3><ul><li><p><a href="https://github.com/allankoechke/mantisbase/releases/tag/v0.4.5">Download dev package</a></p></li><li><p><a href="https://docs.mantisbase.com">Documentation</a></p></li><li><p><a href="https://discord.gg/9437XTKRvN">Discord</a></p></li><li><p><a href="https://github.com/allankoechke/mantisbase/discussions">GitHub Discussions</a></p></li><li><p><a href="https://github.com/allankoechke/mantisbase/issues">Issues</a></p></li></ul><div><hr></div><p><em>Coming up in part two: actually wiring MantisBase into your application: configuration, plugins, and extension points.</em></p>]]></content:encoded></item><item><title><![CDATA[Running Muse Code Models Inside Claude Code: A Setup Guide]]></title><description><![CDATA[Meta shipped its own terminal coding agent, Muse Code, in beta on August 5, 2026, as a direct answer to Claude Code and OpenAI&#8217;s Codex CLI.]]></description><link>https://www.codeart.co.ke/p/running-muse-code-models-inside-claude</link><guid isPermaLink="false">https://www.codeart.co.ke/p/running-muse-code-models-inside-claude</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Mon, 14 Sep 2026 09:00:13 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/825ab7a0-b560-435a-b919-40aa171415c3_2048x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Meta shipped its own terminal coding agent, <em><strong><a href="https://dev.meta.ai/">Muse Code</a></strong></em>, in beta on August 5, 2026, as a direct answer to Claude Code and OpenAI&#8217;s Codex CLI. Luckily, <em>you don&#8217;t actually have to install Meta&#8217;s <strong>muse</strong> binary to use Meta&#8217;s models</em> because Claude Code&#8217;s API layer is configurable via environment variables; you can point the Claude Code CLI you already know at Meta&#8217;s Muse endpoint and keep your existing workflow, keybindings, and muscle memory intact.</p><p>This blog covers what Muse Code actually is, what it costs, and how to wire its Contributor-tier model into a stock Claude Code install.</p><h2>What is Muse Code?</h2><p>Muse Code is Meta&#8217;s terminal-based coding agent: a TUI for interactive development plus a headless <code>exec</code> mode for CI, built around Meta&#8217;s own code-focused model family, Muse Spark. It reads a codebase, plans and executes multi-file changes, runs commands, and iterates on failures, the same shape as Claude Code and Codex CLI. It launched with persistent background subagents and a replay-exact event log for crash recovery, and Meta has since added inter-session messaging and a TypeScript SDK for building custom agents on top of it.</p><p>On raw benchmark quality, most third-party comparisons place Muse Code below Claude Code but ahead of Codex CLI. Meta isn&#8217;t claiming the smartest model; it&#8217;s claiming the cheapest capable one.</p><h3>Model types</h3><p>The model family is <strong>Muse Spark</strong>, currently on version 1.3, and it ships in two pricing tiers that are otherwise the same underlying model:</p><ul><li><p><strong>Standard</strong>: full data privacy; Meta does not use your prompts or completions for training, so they claim.</p></li><li><p><strong>Contributor</strong>: a steep discount in exchange for letting Meta use your prompts and completions to improve its products.</p></li></ul><p>You select the tier by model ID (<em><strong>muse-spark-1.3</strong></em> vs <em><strong>muse-spark-1.3-contributor</strong></em>), making it trivially easy for a quick setup and swapping models when needed.</p><h3>Costs</h3><p>Pricing is a straight pass-through of token costs, no separate license fee:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UQi3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UQi3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 424w, https://substackcdn.com/image/fetch/$s_!UQi3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 848w, https://substackcdn.com/image/fetch/$s_!UQi3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 1272w, https://substackcdn.com/image/fetch/$s_!UQi3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UQi3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png" width="1377" height="253" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:253,&quot;width&quot;:1377,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83343,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/214960363?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UQi3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 424w, https://substackcdn.com/image/fetch/$s_!UQi3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 848w, https://substackcdn.com/image/fetch/$s_!UQi3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 1272w, https://substackcdn.com/image/fetch/$s_!UQi3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faec1d8f0-1cf7-4eb1-b516-76b4728473cf_1377x253.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>That&#8217;s roughly a <strong>12x</strong> discount on input and a <strong>21x</strong> discount on output. The catch, beyond the training-data trade, is throughput: <em>Contributor is rate-limited well below Standard, so a team running heavy concurrent agent sessions may hit throttling on Contributor before they hit it on Standard</em>. If you&#8217;re budgeting, model cost per accepted task rather than cost per token; Muse Spark has been reported to burn more tokens per task than Claude Code on equivalent work, which eats into the headline discount.</p><h2>Why the Contributor model, and when it isn&#8217;t the right call</h2><p>Contributor is the tier worth using day-to-day: for personal projects, open-source work, learning, or anything you&#8217;re not contractually obligated to keep private, a ~20x cost cut is hard to argue with, and Muse Spark at Contributor pricing is cheap enough to leave running in the background on exploratory tasks you&#8217;d never justify spending Opus-tier tokens on.</p><p>Where it stops being the right call is exactly where <em>&#8220;Meta trains on this&#8221;</em> becomes a problem: client code under NDA, anything with proprietary business logic, credentials or secrets in context, or a repository your employer would object to leaving the building. The switch is one config string, so if this matters to your team, it&#8217;s worth pinning the model ID centrally and treating any change to it as a reviewable event rather than something anyone can flip locally.</p><h2>Setting up Muse Code inside your existing Claude Code CLI</h2><p>Rather than installing a second CLI, you can route your regular <code>claude</code> command at Meta&#8217;s endpoint using the same environment-variable mechanism. Claude Code uses for enterprise gateways, Bedrock, and Vertex:</p><pre><code><code>export MODEL_API_KEY="&lt;your-meta-model-api-key&gt;"
export ANTHROPIC_BASE_URL="https://api.meta.ai"
export ANTHROPIC_AUTH_TOKEN="$MODEL_API_KEY"
export ANTHROPIC_MODEL="muse-spark-1.3-contributor"
export ANTHROPIC_DEFAULT_OPUS_MODEL="muse-spark-1.3-contributor"
export ANTHROPIC_DEFAULT_SONNET_MODEL="muse-spark-1.3-contributor"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="muse-spark-1.3-contributor"
export CLAUDE_CODE_SUBAGENT_MODEL="muse-spark-1.3-contributor"</code></code></pre><p>Get <code>MODEL_API_KEY</code> from your Meta Model API account, not from the <code>muse</code> CLI&#8217;s own OAuth login; the two auth paths are separate. Once these are exported, <code>claude</code> in any project directory, it talks to Muse Spark instead of Anthropic&#8217;s models while keeping every bit of Claude Code&#8217;s interface, skills, slash commands, and MCP tooling.</p><p>The four <code>ANTHROPIC_DEFAULT_*_MODEL</code> variables matter because Claude Code internally maps its own <em>&#8220;which model handles this&#8221;</em> logic (plan mode vs. execution, subagents, background tasks) to the Opus/Sonnet/Haiku tiers. Pointing all three at the same Muse Spark ID keeps that routing from silently falling back to an Anthropic model you don&#8217;t have credentials for.</p><h2>The context window gotcha and the <code>[1m]</code> workaround</h2><p>Claude Code determines a model&#8217;s context window and auto-compaction threshold from an internal table of known Anthropic model names. If you point it at a model ID, it doesn&#8217;t recognize it, like <em><strong>muse-spark-1.3-contributor</strong></em>, and instead of erring out, it silently defaults the <strong>auto-compact window to 1 token</strong>. The result: you type a single word and immediately get the <em><span data-color="#ff0000" style="color: rgb(255, 0, 0);">context limit reached</span></em>, because the CLI is now measuring your session against a 1-token budget instead of the model&#8217;s real window.</p><p>If you run <code>/context all</code>, you&#8217;ll see a compaction window that reads <em><span data-color="#8e7cc3" style="color: rgb(142, 124, 195);">1 token (default for an unrecognized model)</span></em>, with normal-looking usage numbers (system prompt, tools, skills) suddenly reported as usage percentages in the hundreds of thousands.</p><p>Muse Spark 1.3 Contributor actually has a native ~1,048,576-token (1M) context window, larger than Claude&#8217;s default 200K assumption. The fix is the same suffix Claude Code uses to opt Anthropic&#8217;s own 1M-capable models into their extended window:</p><pre><code><code>export ANTHROPIC_MODEL="muse-spark-1.3-contributor[1m]"</code></code></pre><p>Appending <strong>[1m]</strong> tells Claude Code to treat the model as having a 1-million-token window and to add the <code>context-1m</code> behavior it normally reserves for Sonnet/Opus 1M variants, instead of falling back to the broken 1-token default. Officially, this suffix is documented only for known Anthropic model names, using it against a custom model ID is a workaround, not a supported path, so treat it as something to verify with <code>/context</code> after every Claude Code update rather than a guarantee. If a future release changes how unrecognized models are handled, this could stop working (or start working differently) without notice.</p><p>Two more MCP-related notes worth checking after switching endpoints:</p><ul><li><p>Confirm your MCP tools still show as <code>(loaded on-demand)</code> in <code>/context all</code> rather than fully materialized. Some custom-gateway setups lose Claude Code&#8217;s deferred tool-schema loading, which inflates baseline context usage significantly. If you see full tool definitions listed as loaded rather than on-demand, that&#8217;s worth investigating separately from the <code>[1m]</code> fix above.</p></li><li><p><code>ENABLE_TOOL_SEARCH="true"</code> is worth setting alongside the above if your Claude Code build supports it, but verify it&#8217;s actually being honored for your endpoint; an unrecognized or ignored flag will silently do nothing rather than error.</p></li></ul><h2>Quick reference</h2><pre><code><code># ~/.bashrc or a project-local .env
export MODEL_API_KEY="&lt;your-meta-model-api-key&gt;"
export ANTHROPIC_BASE_URL="https://api.meta.ai"
export ANTHROPIC_AUTH_TOKEN="$MODEL_API_KEY"
export ANTHROPIC_MODEL="muse-spark-1.3-contributor[1m]"
export ANTHROPIC_DEFAULT_OPUS_MODEL="muse-spark-1.3-contributor[1m]"
export ANTHROPIC_DEFAULT_SONNET_MODEL="muse-spark-1.3-contributor[1m]"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="muse-spark-1.3-contributor[1m]"
export CLAUDE_CODE_SUBAGENT_MODEL="muse-spark-1.3-contributor[1m]"
</code></code></pre><p>Then verify with <code>claude</code>, and immediately run <code>/context all</code>. If the compaction window reads a sane number instead of <code>1 tokens (default for an unrecognized model)</code>, you&#8217;re set up correctly.</p><div><hr></div><p>If all is wired correctly, reload your shell and start the Claude code CLI. You should see muse-spark as the model name in use inside the Claude code.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yihs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yihs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 424w, https://substackcdn.com/image/fetch/$s_!yihs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 848w, https://substackcdn.com/image/fetch/$s_!yihs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 1272w, https://substackcdn.com/image/fetch/$s_!yihs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yihs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png" width="930" height="244" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:244,&quot;width&quot;:930,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:50830,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/214960363?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yihs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 424w, https://substackcdn.com/image/fetch/$s_!yihs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 848w, https://substackcdn.com/image/fetch/$s_!yihs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 1272w, https://substackcdn.com/image/fetch/$s_!yihs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3268173e-d3dc-4b8f-b56a-ee95513915f3_930x244.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p><em>Swap </em><code>-contributor</code><em> out of every model ID above if you&#8217;re working with anything you wouldn&#8217;t want Meta training on; the pricing difference is real, but so is what you&#8217;re trading for it.</em></p>]]></content:encoded></item><item><title><![CDATA[MantisBase v0.4: Reworking the Foundations]]></title><description><![CDATA[For the past few months, we have been reviewing MantisBase development with a particular focus on the hurdles we have accumulated along the way: requested features that were becoming increasingly difficult to implement cleanly, performance bottlenecks, and a few architectural decisions that had started to outlive their usefulness.]]></description><link>https://www.codeart.co.ke/p/mantisbase-v4-prerelease-reworking-the-foundations</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mantisbase-v4-prerelease-reworking-the-foundations</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Thu, 27 Aug 2026 12:27:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/96903e96-8c05-49d6-b641-d7dc06d0beab_1774x887.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For the past few months, we have been reviewing MantisBase development with a particular focus on the hurdles we have accumulated along the way: requested features that were becoming increasingly difficult to implement cleanly, performance bottlenecks, and a few architectural decisions that had started to outlive their usefulness.</p><p>At some point, adding another feature on top stops being progress.</p><p>Sometimes you have to go back and fix the foundations.</p><p>That is, in large part, what <em><strong>MantisBase v0.4</strong></em> has become.</p><h2>A little history</h2><p>During the v0.2 &#8594; v0.3 transition, one of our goals was to standardize the API surface and establish a clearer contract for anyone building against MantisBase.</p><p>Part of that plan involved exposing the new APIs to JavaScript through Duktape. The bigger idea was not limited to JavaScript either: once we had a stable internal API, supporting other scripting languages would become considerably easier.</p><p>Unfortunately, the JavaScript work planned for v0.3 never really saw the light of day.</p><p><strong>Why?</strong></p><p><em>Because the underlying code was still moving too quickly.</em></p><p>We were making many seemingly small changes that affected routes, internal objects, authentication behavior, entity handling, and lifecycle management. Every one of those changes would then have needed to be mirrored in the JavaScript bindings.</p><p>That would have meant maintaining effectively two implementations of a rapidly changing API, and potentially repeating the same work again for every additional scripting language.</p><p><em>That did not make much sense.</em></p><p>Rather than continue adding bindings on top of an architecture we already knew needed work, we decided to address the underlying problems first.</p><h2>What problems were we running into?</h2><p>A few issues kept showing up during development and testing.</p><h3>Realtime connections did not scale particularly well</h3><p>Until v0.4, MantisBase used <code>cpp-httplib</code> extensively for both normal HTTP traffic and Server-Sent Events (SSE).</p><p>SSE is intentionally a long-lived HTTP connection. A client connects, and that connection stays open while the server pushes database changes back to it.</p><p>The problem with our implementation was that every active SSE connection occupied a server thread.</p><p>With a handful of clients, this was not particularly noticeable.</p><p>With enough clients, however, those long-lived connections could consume the available worker threads. Normal REST requests would then sit waiting for a worker to become available.</p><p>In other words, realtime traffic could eventually prevent the server from serving regular HTTP traffic.</p><p>That is not a particularly useful property for something calling itself a backend.</p><h3>The global singleton had become expensive</h3><p>MantisBase historically exposed much of the application through a global singleton.</p><p>It was convenient.</p><p><em><strong>Until it wasn&#8217;t.</strong></em></p><p>Global state made lifecycle management difficult, made ownership less obvious, and caused headaches in the testing harness. Starting and stopping multiple instances within the same process could result in stale state, shutdown-order issues, memory problems, and occasionally spectacular crashes.</p><p>It also worked against one of MantisBase&#8217;s longer-term goals: being genuinely useful as an embeddable C++ library.</p><p>If somebody embeds MantisBase into a desktop application, daemon, embedded device, test environment, or another larger system, they should control the lifetime of the MantisBase instance.</p><p>A hidden global object should not control it for them.</p><h3>The API was becoming harder to extend safely</h3><p>The scripting work exposed another problem.</p><p><em>An API that changes frequently is expensive to bind.</em></p><p>If adding<em> JavaScript, Python, Lua, or another language</em> requires duplicating large parts of MantisBase internals, every change becomes progressively more expensive.</p><p>Before expanding the extension system, we therefore needed to make the C++ side cleaner first.</p><p>That became one of the guiding ideas behind v0.4:</p><p><strong>Make MantisBase easier to embed, extend, test, and operate before piling more features on top.</strong></p><p>So, what have we been cooking?</p><p>Quite a bit.</p><div><hr></div><h1>What&#8217;s changing in v0.4?</h1><h2>1. Goodbye, global singleton</h2><p>We have officially dropped the global <code>MantisBase</code> singleton.</p><p>This is probably not the flashiest v0.4 feature, but internally it is one of the most important changes.</p><p>Instances now have much clearer ownership and lifecycle semantics. That makes testing considerably easier and creates a much better foundation for embedding MantisBase inside other C++ applications.</p><p>Instead of assuming that exactly one magical MantisBase instance exists somewhere in global state, the application can explicitly create, configure, use, and destroy an instance.</p><p>Boring architectural changes are often the ones that unlock the interesting features later.</p><p>This is one of those changes. You can read more details about this change in our previous post <a href="https://www.codeart.co.ke/p/ripping-out-the-singleton">here.</a></p><h2>2. Authentication is expanding</h2><p>Authentication has received quite a bit of attention.</p><p>The first stage of OAuth support has landed. It is still relatively new and needs considerably more real-world testing, so consider it early support rather than a finished OAuth story.</p><p>We have also added <strong>API keys</strong>.</p><p>This is particularly useful for automation, services, scripts, CI jobs, agents, and AI-driven workflows where an interactive username/password login flow does not make much sense.</p><p>API keys can be created for administrative accounts as well as regular authentication accounts, allowing machine-to-machine clients to interact with MantisBase without pretending to be an interactive user.</p><p>There is more work to do here, but this gives us a much better foundation for non-human clients.</p><h2>3. A new HTTP backend</h2><p>This is probably the most consequential runtime change in v0.4.</p><p>We have migrated the underlying HTTP server from <code>cpp-httplib</code> to <strong>Drogon</strong>.</p><p>The biggest motivation was <em><strong>concurrency</strong></em>.</p><p>As described earlier, our previous SSE implementation tied each long-running realtime connection to a worker thread. At sufficient concurrency, realtime subscriptions could therefore starve ordinary HTTP requests.</p><p>Drogon&#8217;s asynchronous networking model gives us considerably more room to handle long-lived connections without treating every connection as a permanently occupied worker.</p><p>The change also opens another realtime option:</p><p><strong>WebSockets.</strong></p><p>SSE remains useful, especially because it is simple, works over HTTP, and is perfectly adequate for many database subscription use cases, but WebSockets are now available as an alternative for applications that need bidirectional communication or want to maintain a persistent realtime channel.</p><p>This migration was not simply swapping one HTTP library for another. A large amount of route handling, middleware behavior, authentication plumbing, request/response handling, realtime infrastructure, and testing had to move with it.</p><p>That is part of why v0.4 has taken the shape it has.</p><h2>4. ARM Linux builds</h2><p>Linux ARM support has been added to our builds.</p><p>MantisBase has always been particularly interesting to us outside the traditional <em><strong>&#8220;deploy another service into Kubernetes&#8221;</strong></em> use case.</p><p>A relatively small, self-contained backend makes sense on development machines, edge systems, local appliances, desktop applications, Raspberry Pis, and other small Linux devices.</p><p>ARM support is therefore an important part of making that story practical rather than theoretical.</p><p>There will inevitably be hardware and distro combinations we have not tested, so feedback here is especially welcome.</p><h2>5. Simpler data types</h2><p>We have simplified MantisBase&#8217;s data-type system.</p><p>One particularly noisy area was integer types.</p><p>Rather than exposing a collection of conceptually similar integral types as completely independent MantisBase types, integer fields now use a simpler <code>int</code> model with precision describing the actual representation&#8212;for example <code>u8</code>, <code>u16</code>, <code>u32</code>, <code>i8</code>, through to <code>i64</code>.</p><p>The intention is to keep the schema easier to reason about without losing control over representation when that precision matters.</p><p>We have also removed the old <code>xml</code> and <code>blob</code> types.</p><p>The general direction here is deliberate: fewer special cases, a smaller schema vocabulary, and clearer behavior.</p><p>Every type we expose becomes something that has to be supported consistently across <em>SQLite</em>, <em>PostgreSQL</em>, <em>REST </em>serialization, validation, migrations, scripting, the admin UI, and eventually language bindings.</p><p>A smaller, well-defined type system is considerably easier to keep correct.</p><h2>6. Developer packages</h2><p>Starting with the v0.4 release line, release artifacts now include developer packages containing both the static and shared MantisBase libraries for the platforms we build.</p><p>This matters if you do not want to run MantisBase purely as a standalone server.</p><p>You might want to:</p><ul><li><p>embed it into an existing C++ application;</p></li><li><p>build your own server around the MantisBase core;</p></li><li><p>add functionality that does not belong upstream;</p></li><li><p>experiment with alternative scripting integrations; or</p></li><li><p>use parts of MantisBase as infrastructure within another project.</p></li></ul><p>The standalone binary is still the easiest way to get started.</p><p>The developer package is for everyone who eventually asks:</p><blockquote><p><em><strong>&#8220;Okay, but can I use MantisBase inside my application?&#8221;</strong></em></p></blockquote><p>Increasingly, the answer should be yes.</p><h2>7. Security hardening</h2><p>As the API surface has grown, we have also spent considerably more time looking at how those APIs behave when clients are actively hostile rather than merely buggy.</p><p>Recent security-hardening work has covered access control, OAuth verification, realtime authorization, SQL/schema validation, file serving and uploads, rate limiting, HTTP security headers, error handling, and container deployment.</p><p>Some of those changes are intentionally stricter and may expose assumptions in existing deployments.</p><p>That is a tradeoff we are willing to make while v0.4 is still in prerelease.</p><p>It is much better to discover and fix those assumptions now than to permanently preserve unsafe behavior because somebody might already depend on it.</p><p>If you are testing the v0.4 prereleases, this is one area where feedback is especially valuable.</p><p><em>Try the weird things.</em></p><p><em>Try the things you think should fail.</em></p><p><em>And if they do not fail, tell us.</em></p><h2>8. Documentation rewrite</h2><p>A lot of the documentation had fallen behind the codebase.</p><p>That happens surprisingly quickly during periods of heavy architectural work: endpoints change, CLI commands move, examples refer to previous response formats, and suddenly the docs describe a product that only partially exists anymore.</p><p>We have been going through the documentation and bringing it back into parity with the current codebase.</p><p>This includes reorganizing documentation, updating API responses and examples, fixing installation instructions, and filling in missing sections.</p><p>The v0.4 releases have already included several rounds of documentation fixes and restructuring.</p><p>Documentation is still a work in progress, so if you encounter something that disagrees with the actual application, please open an issue.</p><h2>9. More configuration knobs</h2><p>We have also expanded runtime configuration.</p><p>More behavior can now be controlled using environment variables, making it easier to configure MantisBase in Docker and other deployment environments without maintaining custom configuration files.</p><p>Some features and behaviors can be explicitly enabled or disabled depending on how you intend to run the server.</p><p>Check the Docker and configuration documentation for the current set of options&#8212;the list is still evolving during the v0.4 prerelease cycle.</p><div><hr></div><h1>A few development hacks</h1><p>If you are building MantisBase yourself, there are a couple of quirks worth knowing about.</p><h3>Prefer Release-with-Debug-Info for debugging</h3><p>For development builds, we currently recommend building with release optimizations plus debug information rather than using a full Debug configuration on GCC.</p><p>Some Debug builds can run into stack-related problems.</p><p>You still get useful symbols for debugging without paying all of the costs associated with the full Debug configuration.</p><h3>Use dynamic linking while iterating</h3><p>Static linking is useful for release binaries because it helps us ship a portable package with minimal runtime dependencies.</p><p>It is considerably less fun when you are making a tiny source change and rebuilding repeatedly.</p><p>For local development, enable dynamic linking where appropriate. Build-test-debug cycles become much faster, and you can switch back to the static configuration when validating a release-style build.</p><p>Check the CMake options for the relevant switches.</p><h3>PostgreSQL on Windows is still missing</h3><p>PostgreSQL support is not currently shipped on Windows.</p><p>Static linking PostgreSQL and all of the associated dependencies into a clean Windows release remains an interesting little adventure.</p><p>SQLite works, of course.</p><p>PostgreSQL-on-Windows is something we still need to revisit.</p><h3>No macOS build yet</h3><p>We are also not shipping a macOS build at the moment.</p><p>The main reason is considerably less interesting than some deep technical incompatibility:</p><p>I do not currently have a Mac available for properly developing, testing, and maintaining the build.</p><p>Rather than publish an artifact we cannot confidently test, macOS will have to wait for now.</p><p>Contributions here are very welcome.</p><div><hr></div><h1>So, is v0.4 ready?</h1><p>Not quite.</p><p>And that is why the releases are labelled <strong>alpha</strong> and <strong>beta</strong>.</p><p>At the time of writing, <code>v0.4.0-beta.2</code> is available as a <a href="https://github.com/allankoechke/mantisbase/releases">GitHub prerelease</a>.</p><p>These builds exist specifically so that we can find the remaining rough edges before calling v0.4 stable.</p><p>If you have been curious about MantisBase, this is actually a particularly useful time to try it.</p><p><em>Run an application against it.</em></p><p><em>Embed the library.</em></p><p><em>Open too many realtime connections.</em></p><p><em>Try OAuth.</em></p><p><em>Use API keys from an automation.</em></p><p><em>Run it on ARM.</em></p><p><em>Throw malformed requests at it.</em></p><p><em>Build it using a toolchain we probably forgot existed.</em></p><p><em>Break it.</em></p><p>That feedback is far more valuable during beta than after a stable release.</p><p>For Docker users, the prerelease images are available under the corresponding v0.4 tags.</p><div><hr></div><h1>Where we go from here</h1><p>v0.4 contains visible features, but the more important changes are underneath them.</p><p>Removing global state makes embedding and testing easier.</p><p>Changing the HTTP backend gives realtime connections a better foundation.</p><p>Simplifying the type system reduces the number of edge cases every future integration must support.</p><p>Developer libraries make MantisBase useful as more than a standalone executable.</p><p>Authentication and API keys make service-to-service and automation workloads more practical.</p><p>And all of that makes the scripting story we originally wanted to build considerably more realistic.</p><p>That last part is important.</p><p>JavaScript support was not abandoned because scripting stopped being interesting.</p><p>We paused it because building language bindings against unstable foundations would have multiplied our maintenance work.</p><p>With v0.4, we are trying to make those foundations boring.</p><p>Stable objects. Clear ownership. Predictable APIs. Better concurrency. Smaller interfaces.</p><p>Once those pieces settle, JavaScript&#8212;and potentially other scripting languages&#8212;becomes a much more manageable problem.</p><h2>Help us break it</h2><p>MantisBase is open source, and v0.4 is still being shaped.</p><p>If you try the <a href="https://github.com/allankoechke/mantisbase/releases">prerelease</a>, we would love to hear:</p><ul><li><p>what worked well;</p></li><li><p>what broke;</p></li><li><p>what was confusing;</p></li><li><p>what you expected to exist but could not find;</p></li><li><p>where the documentation disagreed with reality;</p></li><li><p>and what you think MantisBase should tackle next.</p></li></ul><p>Open an issue or start a GitHub Discussion. We also have a Discord server now for longer-form conversations, questions, experiments, and project updates.</p><p>And, of course:</p><p><strong>Star it. Fork it. Build it. Break it. Fix it.</strong></p><p>Contributions of every size are welcome.</p><p>v0.4 has involved considerably more rebuilding than we originally expected.</p><p>But sometimes the fastest way forward is to stop adding floors and reinforce the foundation first.</p><p>That is what we have been cooking.</p>]]></content:encoded></item><item><title><![CDATA[Microsoft .NET 10 Updates for Autodesk 3ds Max and Maya]]></title><description><![CDATA[Microsoft has announced that support for .NET 8 and .NET 9 will end on November 10, 2026. After this date, Microsoft will no longer provide servicing updates, security updates, or technical support for these versions.]]></description><link>https://www.codeart.co.ke/p/microsoft-net-10-updates-for-3dsmax-maya</link><guid isPermaLink="false">https://www.codeart.co.ke/p/microsoft-net-10-updates-for-3dsmax-maya</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Wed, 12 Aug 2026 10:48:25 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b4d0ec9b-4e47-45bb-8cdb-f6cf3d8d2857_1774x887.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Microsoft has announced that support for <strong>.NET 8 and .NET 9 will end on November 10, 2026</strong>. After this date, Microsoft will no longer provide servicing updates, security updates, or technical support for these versions.</p><p>Many Autodesk products include components or dependencies that rely on Microsoft .NET technologies. As part of this commitment to providing highly trustworthy and performant software, Autodesk product teams are planning updates to Autodesk products, where applicable and feasible, to align with Microsoft&#8217;s .NET product support lifecycle.</p><p><strong>3ds Max 2026, Maya 2025, and Maya 2026</strong> have already rolled out security updates that include an upgrade from .NET 8 to .NET 10. Refer to the respective product release notes for more information:</p><ul><li><p><a href="https://help.autodesk.com/view/3DSMAX/2026/ENU/?guid=3dsMax_ReleaseNotes_3dsmax_2026_3_4_releasenotes_html">3ds Max 2026 Release Notes</a></p></li></ul><ul><li><p><a href="https://help.autodesk.com/view/MAYAUL/2026/ENU/?guid=MAYA_RELEASENOTES_2026_3_3_RELEASE_NOTES_HTML">Maya 2026 Release Notes</a></p></li></ul><ul><li><p><a href="https://help.autodesk.com/view/MAYAUL/2025/ENU/?guid=MAYA_RELEASENOTES_2025_3_3_RELEASE_NOTES_HTML">Maya 2025 Release Notes</a></p></li></ul><p><em><strong>Note:</strong> <strong>3ds Max 2024/2025</strong> and <strong>Maya 2024</strong> use .NET Framework 4.8 variants and therefore do not require this .NET 10 upgrade. Microsoft continues to support .NET Framework 4.x versions, including 4.8 and 4.8.1, in accordance with the lifecycle of the Windows operating system on which they are installed. .NET Framework will also continue to be included with Windows. Read more about supported .NET Frameworks <a href="https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-framework">here</a>.</em></p><p><em><strong>Also note:</strong> 3ds Max 2027 and Maya 2027 ship with .NET 10 by default, so no changes are required for these versions.</em></p><p>As a result of these upgrades, we recommend ensuring that all related Autodesk products are also updated to avoid potential compatibility issues.</p><blockquote><p>For additional background, see our previous blog post <a href="https://blog.autodesk.io/autodesk-desktop-products-2025-2026-net-10-updates/">here</a>.</p></blockquote><h2><strong>What do you need to do?</strong></h2><p>There are <strong>no API changes</strong> in any of these products as part of this update. The only change is that the underlying .NET runtime is moving from .NET 8 to .NET 10.</p><p>Existing plug-ins and add-ins should continue to work unless they are affected by breaking changes introduced in .NET 10. In such cases, they may need to be recompiled and retargeted to <strong>.NET 10</strong>.</p><p>Developers are advised to test their plug-ins and add-ins for compatibility with the updated product releases.</p><p>If you encounter any compatibility issues, please report them through <strong><a href="https://aps.autodesk.com/get-help">ADN Support</a></strong>.</p><h2><strong>Related links</strong></h2><ul><li><p><a href="https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/Autodesk-Products-What-customers-need-to-know-about-Microsoft-NET-10-updates.html">Autodesk Products: What customers need to know about Microsoft .NET 10 updates</a></p></li></ul><ul><li><p><a href="https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/3ds-Max-Requirements-for-products-affected-by-the-Microsoft-NET-10-transition.html">3ds Max: Requirements for products affected by the Microsoft .NET 10 transition</a></p></li></ul><ul><li><p><a href="https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/Maya--Requirements-for-products-affected-by-the-Microsoft--NET-10-transition.html">Maya: Requirements for products affected by the Microsoft .NET 10 transition</a></p></li></ul><ul><li><p><a href="https://learn.microsoft.com/en-us/dotnet/core/compatibility/10">Breaking changes in .NET 10</a></p></li></ul><div><hr></div><p>Also posted here: <a href="https://blog.autodesk.io/microsoft-net-10-updates-for-autodesk-3ds-max-and-maya/">https://blog.autodesk.io/microsoft-net-10-updates-for-autodesk-3ds-max-and-maya/</a> </p><div><hr></div><p></p>]]></content:encoded></item><item><title><![CDATA[Porting Explode Geometry to Python: Life After MaxPlus]]></title><description><![CDATA[For years, one of the friendlier ways to learn the 3ds Max API in Python was the Explode Geometry sample.]]></description><link>https://www.codeart.co.ke/p/porting-explode-geometry-to-pymxs</link><guid isPermaLink="false">https://www.codeart.co.ke/p/porting-explode-geometry-to-pymxs</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Wed, 05 Aug 2026 08:31:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ariK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><span>For years, one of the friendlier ways to learn the 3ds Max API in Python was the </span><strong><span>Explode Geometry</span></strong><span> sample. It took a selected object, shattered it into one new object per face, and let you optionally </span><em><span>shell</span></em><span>, </span><em><span>collapse</span></em><span>, </span><em><span>re-pivot</span></em><span>, or </span><em><span>delete </span></em><span>the result. It was a great teaching example because it touched almost everything a real tool needs: a </span><em><span>Qt dialog</span></em><span>, </span><em><span>selection handling, mesh/poly traversal, modifier stacks, and node management</span></em><span>.</span></p><p><span>There was just one problem. The Python version was built on </span><em><strong><span>MaxPlus</span></strong></em><span>, and MaxPlus is gone (</span><a href="https://help.autodesk.com/view/MAXDEV/2022/ENU/?guid=MAXDEV_Python_what_s_new_in_3ds_max_python_api_html"><span>deprecated and removed from 3ds Max 2022</span></a><span>).</span></p><p><span>This post walks through how we brought the sample back, what changed when we moved it onto the modern pymxs + PySide6 stack, and a few things we improved along the way.</span></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ariK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ariK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 424w, https://substackcdn.com/image/fetch/$s_!ariK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 848w, https://substackcdn.com/image/fetch/$s_!ariK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 1272w, https://substackcdn.com/image/fetch/$s_!ariK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ariK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png" width="832" height="409" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d7b63c4f-8365-419d-ab93-836fca27c079_832x409.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:409,&quot;width&quot;:832,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!ariK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 424w, https://substackcdn.com/image/fetch/$s_!ariK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 848w, https://substackcdn.com/image/fetch/$s_!ariK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 1272w, https://substackcdn.com/image/fetch/$s_!ariK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7b63c4f-8365-419d-ab93-836fca27c079_832x409.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em><span>The Explode Geometry dialog (screenshots will be refreshed for the new PySide6 UI).</span></em></p><div class="pullquote"><p>Also published  here: <a href="https://blog.autodesk.io/porting-explode-geometry-to-python-life-after-maxplus/">https://blog.autodesk.io/porting-explode-geometry-to-python-life-after-maxplus/</a></p></div><h2><span>A quick history lesson</span></h2><p><strong><span>MaxPlus </span></strong><span>was the first official Python binding for 3ds Max, introduced back in 2014. It exposed a hand-curated, object-oriented wrapper over the C++ SDK,</span><em><span> classes like MaxPlus.TriObject</span></em><span>, </span><em><span>MaxPlus.Factory</span></em><span>, and </span><em><span>MaxPlus.NotificationManager</span></em><span>.</span></p><p><span>It was useful, but it was also a maintenance burden:</span><em><span> every class and method had to be wrapped by hand</span></em><span>, so coverage was always partial and always lagging the SDK. Meanwhile, </span><strong><span>pymxs,</span></strong><span> which exposes the full MAXScript runtime to Python, kept growing into the more complete, better-supported option.</span></p><p><span>So MaxPlus was </span><strong><span>deprecated in 3ds Max 2021 and removed entirely starting with 3ds Max 2022</span></strong><span>. Any sample that imports MaxPlus stops loading; thus the classic Explode Geometry sample sat abandoned because the port wasn&#8217;t trivial:  MaxPlus and pymxs think about the scene very differently.</span></p><p><span>The original sample is still in the repo as </span><em><span>explode_geometry_classic.py</span></em><span> for historical reference. It&#8217;s a good before/after companion to everything below, but note it only runs on 3ds Max 2016&#8211;2021.</span></p><h2><span>The goals of the port</span></h2><p><span>We set out to do more than merely make it run again:</span></p><ol><li><p><strong><span>Drop every MaxPlus dependency</span></strong><span> and target 3ds Max 2022+ (best on 2026/2027).</span></p></li><li><p><strong><span>Move the UI to PySide6</span></strong><span>, the Qt6 binding shipped with modern 3ds Max.</span></p></li><li><p><strong><span>Keep feature parity</span></strong><span> with the .NET sample&#8217;s options &#8212; shell, edit-mesh, collapse, centre-pivot, delete-original, and the TriMesh/MNMesh choice.</span></p></li><li><p><strong><span>Improve the experience</span></strong><span> while we were in there: a real progress bar, an undoable operation, a debug toggle, and timing feedback.</span></p></li></ol><h3><span>Wiring the window into 3ds Max</span></h3><p><span>MaxPlus had its own helpers for parenting a Qt widget to the Max main window and making it dockable:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;0c9527fe-a8b5-425b-b306-a594b6feb16a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Classic (MaxPlus) 
form.setParent(MaxPlus.GetQMaxWindow()) 
MaxPlus.MakeQWidgetDockable(form, 4) </code></pre></div><p><span>The modern equivalent uses the </span><strong><span>qtmax </span></strong><span>module that ships with 3ds Max, plus a standard Qt window flag:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;780045f8-cf0b-4940-bae9-d67095cac0b4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># New (qtmax + PySide6) 
form.setParent(qtmax.GetQMaxMainWindow()) 
form.setWindowFlags(QtCore.Qt.WindowType.Tool) 
form.show() </code></pre></div><p><em><span>qtmax.GetQMaxMainWindow()</span></em><span> returns the real </span><em><span>QMainWindow</span></em><span> for Max, so the dialog behaves like a native tool window &#8212; it stays on top of Max and follows it as expected.</span></p><h3><span>Listening for selection changes</span></h3><p><span>The classic sample registered a selection callback through MaxPlus&#8217; notification manager and tore it down by index:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;084e2e9b-d5e4-444c-90f8-a88ee8164b06&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># Classic 
MaxPlus.NotificationManager.Register( 
 MaxPlus.NotificationCodes.SelectionsetChanged, self.updateSelectionLabel) 
... 
MaxPlus.NotificationManager.Unregister(MaxPlus.NotificationManager.Handlers[-1]) </code></pre></div><p><span>With pymxs, we go straight to the MAXScript callback system, which is both more capable and easier to clean up because we can tag callbacks with a named ID:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;3013d8c1-515e-4bd1-b340-8699336aef92&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># New 
rt.callbacks.addScript(rt.Name(&#8217;selectionSetChanged&#8217;), 
 self.updateSelectionLabel, 
 id=rt.Name(&#8217;explodeGeom&#8217;)) 
... 
rt.callbacks.removeScripts(id=rt.Name(&#8217;explodeGeom&#8217;)) </code></pre></div><p><span>Naming the callback group allows us to remove everything under </span><em><span>explodeGeom </span></em><span>when the Qt dialog closes.</span></p><h3><span>The TriMesh path: from low-level mesh to one call</span></h3><p><span>The classic sample built each face by hand against the low-level mesh API, casting to a </span><em><span>TriObject</span></em><span>, grabbing the </span><em><span>Mesh</span></em><span>, setting vertex and face counts, copying verts, and invalidating the geometry cache:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;e1f278c0-23ac-47d1-a0b3-a1dae9b37c9c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Classic &#8212; manual mesh construction 
new_face = MaxPlus.Factory.CreateNewTriObject() 
n = MaxPlus.Factory.CreateNode(new_face) 
mesh = new_face.GetMesh() 
mesh.SetNumFaces(1) 
mesh.SetNumVerts(3) 
mesh.GetFace(0).SetVerts(0, 1, 2) 
mesh.GetFace(0).SetEdgeVisFlags(1, 1, 1) 
mesh.GetFace(0).SetSmGroup(2) 
for i in range(0, 3): 
 pt = tri_mesh.GetVertex(face.GetVert(i)) 
 mesh.SetVert(i, pt) 
mesh.InvalidateGeomCache() </code></pre></div><p><span>With pymxs we lean on the MAXScript </span><em><span>mesh()</span></em><span> constructor, which takes vertices and faces directly. The whole per-face body is collapsed to a few lines:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;96ecb5cb-da0d-41c8-ac46-3c13e9a6180b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># New &#8212; high-level mesh constructor 
rt.convertToMesh(node) 
num_faces = rt.getNumFaces(node) 
for face_idx in range(1, num_faces + 1): 
 face = rt.getFace(node, face_idx) 
 v1 = rt.getVert(node, int(face.x)) 
 v2 = rt.getVert(node, int(face.y)) 
 v3 = rt.getVert(node, int(face.z)) 
 
 new_node = rt.mesh(vertices=rt.Array(v1, v2, v3), 
 faces=rt.Array(rt.Point3(1, 2, 3))) 
 rt.update(new_node) 
 new_node.wireColor = _random_wire_color() 
 applySettings(new_node, addShell, shell_amount, 
 addEditMesh, collapseNode, centerPivot) 
</code></pre></div><p><span>No manual cache invalidation, and the new node lands in the scene automatically. As a small visual nicety, we also assign each exploded face a random wire colour so you can actually see the individual pieces.</span></p><h3><span>The MNMesh path: detach instead of rebuild</span></h3><p><span>The classic </span><em><span>MNMesh </span></em><span>path was the most painful code in the old sample. To make each polygon, it created a </span><em><span>PolyObject</span></em><span>, reached into the </span><em><span>MNMesh</span></em><span>, set vertex/edge/face counts, positioned every vertex, built a visibility list, called </span><em><span>MakePoly</span></em><span>, then </span><em><span>FillInMesh,</span></em><span> roughly 20 lines of low-level construction per face.</span></p><p><span>The pymxs version sidesteps all of it. Instead of </span><em><span>rebuilding</span></em><span> each face as a new poly, we let </span><em><span>polyop.detachFaces</span></em><span> do the work and hand us back a node directly:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;56d8bbb1-7ceb-44d1-b5bd-e3282ec8480a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># New &#8212; let polyop detach each face into its own node 
rt.convertToPoly(node) 
num_faces = rt.polyop.getNumFaces(node) 
for face_idx in range(num_faces, 0, -1): 
 rt.polyop.detachFaces(node, rt.Array(face_idx), asNode=True) 
 new_node = rt.objects[-1] 
 new_node.wireColor = _random_wire_color() 
 applySettings(new_node, addShell, shell_amount, 
 addEditMesh, collapseNode, centerPivot) 
</code></pre></div><p><span>A couple of details worth noting:</span></p><ul><li><p><em><strong><span>We iterate backwards (num_faces &#8230; 1)</span></strong></em><span>. Detaching a face renumbers the remaining faces, so walking from the end keeps the indices we haven&#8217;t processed yet stable.</span></p></li><li><p><em><strong><span>asNode=True</span></strong></em><span> makes detachFaces create a brand-new node for the detached face, which we then grab as </span><em><span>rt.objects[-1]</span></em><span>.</span></p></li></ul><p><span>This is dramatically simpler, and it leans on Max&#8217;s own, well-tested geometry code instead of our hand-rolled mesh building.</span></p><p><em><span>MNMesh mode: each polygon is detached into its own node.</span></em></p><h3><span>Applying the modifiers</span></h3><p><span>The </span><em><span>applySettings </span></em><span>helper is conceptually identical between versions &#8212; the difference is just how you instantiate a modifier. MaxPlus used the factory and a parameter block:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;4f5aebdf-3044-43b6-83ec-2c68eed966a4&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># Classic 
mod = MaxPlus.Factory.CreateObjectModifier(MaxPlus.ClassIds.Shell) 
mod.ParameterBlock.outerAmount.Value = shell_amount 
n.AddModifier(mod) </code></pre></div><p><span>In pymxs, modifiers are just runtime classes you call like constructors, and their parameters are plain attributes:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;54ef6ccc-c462-4983-ab8f-32788978e9d6&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python"># New 
mod = rt.Shell() 
mod.outerAmount = shell_amount 
rt.addModifier(n, mod) </code></pre></div><p><span>The same pattern covers </span><em><span>Edit_Mesh</span></em><span>, </span><em><span>maxOps.collapseNode</span></em><span>, and </span><em><span>centerPivot</span></em><span> </span><em><span>(it reads almost as the MAXScript).</span></em></p><h3><span>What we added beyond parity</span></h3><p><span>Since we are rewriting it anyway, why not make the tool better? Here are some quality of life improvements we baked in:</span></p><p><em><strong><span>Undo as a single operation.</span></strong></em><span> Exploding a model creates a </span><em><span>lot</span></em><span> of nodes. Wrapping the whole run in a pymxs.undo block means a single Ctrl+Z reverts the entire explode instead of unwinding it one face at a time:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;86a5da88-cf4f-4d50-b60d-7ab6794441ee&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">with pymxs.undo(True, &#8220;Explode Geometry&#8221;): 
 ... # all node creation/deletion happens here </code></pre></div><p><em><strong><span>A real progress panel.</span></strong></em><span> Exploding a dense mesh can take a while, so the dialog now shows a progress bar plus the current node name and an </span><em><span>N of M</span></em><span> counter. This matches the .NET dialog with a progress bar. The conversion functions take an on_progress callback and pump </span><em><span>QApplication.processEvents()</span></em><span> so the UI stays responsive:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;ca83ca17-fabf-4039-9602-ede063bfc866&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def _prog(cur, tot): 
 self.progress_bar.setValue(int(cur * 100 / tot) if tot else 0) 
 QtWidgets.QApplication.processEvents() </code></pre></div><p><em><strong><span>A debug toggle.</span></strong></em><span> Rather than littering the code with print calls, we route everything through Python&#8217;s logging module to the MAXScript Listener. A </span><em><span>&#8220;Show Debug Messages&#8221;</span></em><span> checkbox flips the logger between WARNING and DEBUG. </span></p><blockquote><p>Note: Verbose logging affects performance, especially around hot paths and loops when there are many nodes/faces to explode. The completion summary is always printed regardless of the toggle.</p></blockquote><p><em><strong>Timing feedback.</strong></em> We wrap the run with time.perf_counter() and report how long the explode took &#8212; handy when you&#8217;re comparing the TriMesh and MNMesh paths on the same model.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;bd156941-3f24-41e3-bf14-9eedc8381591&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">pymxs.print_(&#8221;[ExplodeGeometry] Explode completed in {:.2f} seconds.\n&#8221;.format(elapsed)) </code></pre></div><h2><span>Python 2 to Python 3, while we&#8217;re here</span></h2><p><span>The classic sample was Python 2 </span><em><span>(note the print msg statements and the Qt4-era PySide/QtGui imports)</span></em><span>. The port is clean Python 3 on PySide6: </span><em><span>QtWidgets </span></em><span>instead of QtGui, </span><em><span>pymxs.print_()</span></em><span> for Listener output, and modern signal connections like </span><em><span>checkStateChanged</span></em><span>.</span></p><h2><span>Shipping it as an AppBundle</span></h2><p><span>Running a script from the editor is fine for development, but the sample also ships as a proper </span><strong><span>Automatic Loader AppBundle</span></strong><span> under Bundle2/, so it can show up as a menu entry right next to the .NET version. The package&#8217;s </span><a href="https://github.com/ADN-DevTech/3dsMax-Explode-Geometry/tree/master/Bundle2/Contents/python"><span>Contents/python/</span></a><span> folder carries </span><em><span>explode_geometry.py</span></em><span>, and a </span><a href="https://github.com/ADN-DevTech/3dsMax-Explode-Geometry/blob/master/Bundle2/Contents/macroscripts/ADNExplodeGeometryPy.mcr"><span>small macroscript</span></a><span> launches it:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;4d2c52f0-c01c-480e-a619-d9e7e6cc67a8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">macroScript ADNExplodeGeomPyMS 
  category:"ADN Samples"
  tooltip:"Explode Geometry (Python)" 
  buttonText:"Explode Geometry (Python)"
( 
 local scriptDir = getFilenamePath (getSourceFileName()) 
 local pyFile = scriptDir + "..\python\explode_geometry.py"
 python.ExecuteFile pyFile 
) 
</code></pre></div><h3><span>How do we run the AppBundle?</span></h3><p><span>You have two ways to get 3ds Max to load the bundle:</span></p><ul><li><p><strong><span>Copy it into an auto-discovered plug-in folder.</span></strong><span> 3ds Max automatically scans the ApplicationPlugins directories on startup. Drop the Bundle2 folder </span><em><span>(renamed to something like ADN-ExplodeGeometry.bundle)</span></em><span> into one of:</span></p><ul><li><p><em><span>%PROGRAMDATA%\Autodesk\ApplicationPlugins</span></em><span> (all users), or</span></p></li><li><p><em><span>%APPDATA%\Autodesk\ApplicationPlugins</span></em><span> (current user).</span></p></li></ul></li><li><p><strong><span>Point an environment variable at it.</span></strong><span> Set </span><strong><span>ADSK_APPLICATION_PLUGINS</span></strong><span> to the folder containing your bundle before launching Max &#8212; handy when you&#8217;re iterating and don&#8217;t want to copy files around.</span></p></li></ul><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;shell&quot;,&quot;nodeId&quot;:&quot;eb011b7b-e7b8-4960-b900-85d5f0212395&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-shell">#Set ENV var (check terminal specifics for PowerShell/CMD/etc)
set ADSK_APPLICATION_PLUGINS=D:/path/to/bundle/parent/dir

# Launch mamax in the same shell
3dsmax.exe </code></pre></div><div class="pullquote"><p>It&#8217;s not advisable to copy plugins to the default Max installation directories (&lt;max&gt;/Plugins, &lt;max&gt;/scripts, etc). Use the external plugins directory shown above for a cleaner way to add and remove plugins. All plugins shipped via the Autodesk AppStore are installed in the external plugin directories; rest assured, Max scans these directories at startup and will discover your plugins.</p></div><p><span>See the 3ds Max developer docs on the </span><strong><a href="https://help.autodesk.com/view/MAXDEV/2026/ENU/?guid=packagexml_format"><span>Plug-in Package (.bundle) format</span></a></strong><span> and </span><em><span>PackageContents.xml</span></em><span> for the full directory layout and the auto-loader search paths.</span></p><p><span>Once the bundle loads cleanly, you&#8217;ll find the tool on the main menu under </span><em><strong><span>App Store &#8594; Explode Geometry (Python)</span></strong></em><span>, sitting alongside the original </span><strong><span>Explode Geometry</span></strong><span> (.NET) entry. Select your objects, launch it, and you'll see the same dialogue you&#8217;d see in the editor.</span></p><blockquote><p>Not ethat the Python menu entry is part of the GitHub sample, but won&#8217;t show if you install the plugin from the AppStore.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Wk7Y!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 424w, https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 848w, https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 1272w, https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png" width="1456" height="513" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:513,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52017,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/208668741?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 424w, https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 848w, https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 1272w, https://substackcdn.com/image/fetch/$s_!Wk7Y!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F28eb7250-3b8f-4c52-94af-2183cc4abe8e_1475x520.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><span>One nuance worth knowing: the Python menu entry is only registered on </span><strong><span>3ds Max 2027 and up</span></strong><span>. The post-start-up menu script gates it on the Max version:</span></p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;fc07d7cb-97e4-4a30-a1df-0d9b8c82fd9d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">-- Only add the Python menu entry for 3ds Max 2027+ (maxVersion 29000), 
-- where Python support in the menu system is available. 
if (maxVersion())[1] &gt;= 29000 then 
( 
 newSubMenu.CreateAction "85045470-A03C-45EC-A13F-538346AF077A" 647394 "ADNExplodeGeomPyMS`ADN Samples" 
) 
</code></pre></div><p><span>The .NET action is added on all supported versions; the Python one is for 2027+ only.</span></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z9vb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z9vb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 424w, https://substackcdn.com/image/fetch/$s_!z9vb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 848w, https://substackcdn.com/image/fetch/$s_!z9vb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 1272w, https://substackcdn.com/image/fetch/$s_!z9vb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z9vb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png" width="270" height="356" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:356,&quot;width&quot;:270,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38664,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/208668741?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!z9vb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 424w, https://substackcdn.com/image/fetch/$s_!z9vb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 848w, https://substackcdn.com/image/fetch/$s_!z9vb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 1272w, https://substackcdn.com/image/fetch/$s_!z9vb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0fd5f7fd-4863-4f1b-a09c-bc11c8b770b6_270x356.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2><span>A note on Qt versions</span></h2><p><span>The sample is written against </span><strong><span>PySide6 (Qt 6)</span></strong><span>, which is what ships with 3ds Max </span><strong><span>2026 and 2027</span></strong><span> &#8212; so on those releases it runs as-is.</span></p><p><span>On </span><strong><span>3ds Max 2022&#8211;2025</span></strong><span>, the bundled Qt is the </span><strong><span>PySide2 (Qt 5)</span></strong><span> generation, so the imports and a few API details won&#8217;t match out of the box. If you want to run it there, you&#8217;ll need to adjust things like:</span></p><ul><li><p><span>from PySide6 import ... &#8594; from PySide2 import ...</span></p></li><li><p><span>Scoped enums back to flat ones &#8212; e.g. QtCore.Qt.WindowType.Tool &#8594; QtCore.Qt.Tool.</span></p></li><li><p><span>Signal differences &#8212; e.g. the Qt6 checkStateChanged signal versus Qt5&#8217;s stateChanged.</span></p></li><li><p><span>QDialog/QMessageBox.exec() versus the older exec_().</span></p></li></ul><p><span>None of these is hard, but they&#8217;re version-specific. Consider it a good exercise in learning where PySide2 and PySide6 diverge and a reminder always to check which Qt your target Max ships before writing UI code.</span></p><h2><span>Lessons learned</span></h2><p><span>A few takeaways for anyone facing a similar MaxPlus migration:</span></p><ul><li><p><strong><span>pymxs is usually less code, not more.</span></strong><span> The instinct is to fear that dropping a &#8220;high-level&#8221; wrapper means more boilerplate. In practice, the opposite was true &#8212; rt.mesh(...) and polyop.detachFaces(..., asNode=True) replaced dozens of lines of manual construction.</span></p></li><li><p><strong><span>Prefer Max&#8217;s own operations over rebuilding geometry.</span></strong><span> The biggest simplification came from detaching faces instead of reconstructing them. When the SDK already does the thing you want, use it.</span></p></li><li><p><strong><span>Watch index invalidation.</span></strong><span> Anything that adds or removes faces/nodes mid-loop can shift the indices under you. Iterating in reverse is a cheap fix.</span></p></li><li><p><strong><span>qtmax is your friend for UI hosting.</span></strong><span> GetQMaxMainWindow() plus a Tool window flag gives you a well-behaved dialog without MaxPlus&#8217; dockable helpers.</span></p></li></ul><h2><span>Try it out</span></h2><p><span>The ported sample lives in the </span><a href="https://github.com/ADN-DevTech/3dsMax-Explode-Geometry"><span>Explode Geometry repository</span></a><span> under Python/explode_geometry.py. There are two ways to run it:</span></p><ul><li><p><strong><span>Straight from the editor</span></strong><span> &#8212; open Python/explode_geometry.py in the 3ds Max scripting editor and execute it. Quickest for poking at the code.</span></p></li><li><p><strong><span>As an AppBundle</span></strong><span> &#8212; load the Bundle2/ package as described above and launch it from </span><strong><span>App Store &#8594; Explode Geometry (Python)</span></strong><span> (2027+).</span></p></li></ul><p><span>Either way: select an object (or several), pick </span><em><span>TriMesh </span></em><span>or </span><em><span>MNMesh</span></em><span>, choose your options, and hit </span><strong><span>Explode</span></strong><span>. Then enjoy a single Ctrl+Z to put it all back together. It runs as-is on 3ds Max 2026/2027; for 2022&#8211;2025 you&#8217;ll need the PySide2 tweaks noted above.</span></p><div><hr></div><p><em><span>The original .NET plug-in was written by Kevin Vandecar, from an idea by Louis Marcoux. The first Python version was developed by Drew Avis. This pymxs port modernises that work for 3ds Max 2022 and beyond.</span></em></p>]]></content:encoded></item><item><title><![CDATA[Setting Up 3ds Max 2027 SDK Development with Visual Studio 2026 ]]></title><description><![CDATA[Visual Studio 2026 landed in late 2025, and if you write plugins for 3ds Max, the first question is the obvious one: can I move my development environment to the new release, or do I need to stay put? The short answer is that you can, with one important caveat about the compiler toolset. This post walks through what changed, what the 3ds Max 2027 SDK requires, and how to get a clean, working build environment on the new IDE.]]></description><link>https://www.codeart.co.ke/p/setting-up-3ds-max-2027-sdk-development</link><guid isPermaLink="false">https://www.codeart.co.ke/p/setting-up-3ds-max-2027-sdk-development</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Fri, 31 Jul 2026 08:41:41 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/064b7738-5a66-4532-9422-b5c04d4293dd_1023x576.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Visual Studio 2026 landed in late 2025, and if you write plugins for 3ds Max, the first question is the obvious one: <em><strong>can I move my development environment to the new release, or do I need to stay put</strong></em>? The short answer is that you can, with one important caveat about the compiler toolset. This post walks through what changed, what the 3ds Max 2027 SDK requires, and how to get a clean, working build environment on the new IDE. </p><div><hr></div><p>Original posting here: <a href="https://blog.autodesk.io/setting-up-3ds-max-2027-sdk-development-with-visual-studio-2026/">https://blog.autodesk.io/setting-up-3ds-max-2027-sdk-development-with-visual-studio-2026/</a> </p><div><hr></div><h2>What does the 3ds Max 2027 SDK require? </h2><p>Per the official <em><a href="https://help.autodesk.com/view/MAXDEV/2027/ENU/?guid=sdk_requirements">SDK </a></em><a href="https://help.autodesk.com/view/MAXDEV/2027/ENU/?guid=sdk_requirements">Requirements page</a>, 3ds Max 2027 targets: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l_W2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l_W2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 424w, https://substackcdn.com/image/fetch/$s_!l_W2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 848w, https://substackcdn.com/image/fetch/$s_!l_W2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 1272w, https://substackcdn.com/image/fetch/$s_!l_W2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l_W2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png" width="1456" height="538" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:538,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81178,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/204415830?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!l_W2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 424w, https://substackcdn.com/image/fetch/$s_!l_W2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 848w, https://substackcdn.com/image/fetch/$s_!l_W2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 1272w, https://substackcdn.com/image/fetch/$s_!l_W2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6127590f-3f8d-4e26-9258-82722cc2879e_1889x698.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The SDK Requirements page lists the IDE version as <strong>VS2022 17.14.13</strong>, but what your build must match is the <strong>MSVC v14.38 (17.8) toolset</strong> within the <em>v143 family</em> &#8212; see the next section for why that difference matters. Any edition of Visual Studio <em>(Community, Professional, or Enterprise)</em> can build 3ds Max plugins; the edition doesn&#8217;t matter, the toolset version does. </p><p>The SDK Requirements page names <em>Visual Studio 2022 17.14.13</em> as the IDE baseline, but the build itself is pinned to a specific MSVC v143 build-tools version <em><strong>&#8212; v14.38 (17.8)</strong></em>, which Microsoft now marks as Out of Support. &#8220;v143&#8221; is not a single compiler; it&#8217;s a family that spans many MSVC minor versions <em>(14.30 through 14.44 and beyond)</em>, and 3ds Max 2027 is ABI-locked to the v14.38 set. The platform-toolset name stays v143 across Visual Studio 2022 and Visual Studio 2026 for backward compatibility, but the minor version underneath is what has to match. </p><p>This is why Visual Studio 2026 can host 3ds Max 2027 development: the newer IDE is able to install and target the older, out-of-support v14.38 build tools side by side with its own. 3ds Max and its plugins are extremely sensitive to ABI (Application Binary Interface) matching; a plugin must be built with a toolchain binary compatible with the one Autodesk used to build 3ds Max itself. Installing and selecting the v14.38 toolset is what keeps you inside that compatible window while still letting you run the newer IDE. </p><blockquote><p>NOTE: The new IDE is fine; the exact build-tools version is what must match. Build against the v14.38 (17.8) v143 toolset, not whatever newer toolset Visual Studio 2026 installs by default. </p></blockquote><h2>What does Visual Studio 2026 ship with? </h2><p>A default Visual Studio 2026 installation will not build a 3ds Max 2027 SDK project. Out of the box, VS2026 ships: </p><ul><li><p>the MSVC <strong>v14.44</strong> build tools (the current v143 compiler), and </p></li><li><p>the Windows 11 SDK 10.0.26100.x. </p></li></ul><p>3ds Max 2027, by contrast, is built against the MSVC v14.38 (17.8) v143 build tools and the Windows 10 <strong>SDK 10.0.19041.0</strong>. Both VS2026&#8217;s defaults are newer than what the SDK expects, and that&#8217;s enough to break the build. To make matters more confusing, the v14.38 (17.8) toolset is now marked Out of Support by Microsoft, so it&#8217;s tucked away in the installer&#8217;s Individual components list rather than offered by default. </p><p>So, you must add the exact pieces Autodesk validated, and they come from two different places: </p><ul><li><p><strong>MSVC v143 &#8212; VS 2022 C++ x64/x86 build tools (v14.38-17.8)</strong> &#8212; through the Visual Studio installer&#8217;s Individual components (under Out of Support). </p></li><li><p><strong>Windows 10 SDK (10.0.19041.0) </strong>&#8212; this one is not in the VS2026 installer at all. You download and install it separately, from the older-version downloads on the Windows SDK site. </p></li></ul><p>The newer IDE can host the older, ABI-compatible v14.38 toolchain side by side with its own v14.44. But &#8220;possible&#8221; still means &#8220;you have to install it deliberately and then point your project at it.&#8221; The next section is exactly that; install the right pieces, then pin the project to them. </p><h2>How to set up VS2026 for 3ds Max 2027 </h2><h3>Assumptions and prerequisites </h3><ul><li><p>A licensed copy of 3ds Max 2027 installed (you need a real install to test your plugin and to point to your debugger at 3dsmax.exe). </p></li><li><p>The 3ds Max 2027 SDK installed. </p></li><li><p>Qt 6.8.3 (the LGPL build) if your plugin uses Qt-based UI. Match this version exactly. </p></li><li><p>.NET 10 SDK if you build managed or mixed-mode (C++/CLI) assemblies. </p></li></ul><h3>Install the right Visual Studio workloads and components </h3><p>In the VS2026 installer, select the workloads: </p><ul><li><p>Desktop development with C++. </p></li><li><p>.NET desktop development, if you build any managed components. </p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Y1lI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Y1lI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 424w, https://substackcdn.com/image/fetch/$s_!Y1lI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 848w, https://substackcdn.com/image/fetch/$s_!Y1lI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 1272w, https://substackcdn.com/image/fetch/$s_!Y1lI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Y1lI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png" width="3200" height="1706" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1706,&quot;width&quot;:3200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:347601,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/204415830?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F832a6b7f-ab1d-4b5a-9720-173dcf9a42c0_3200x1800.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Y1lI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 424w, https://substackcdn.com/image/fetch/$s_!Y1lI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 848w, https://substackcdn.com/image/fetch/$s_!Y1lI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 1272w, https://substackcdn.com/image/fetch/$s_!Y1lI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70501544-5725-4dea-aae8-9b3b2d63eb0e_3200x1706.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The workload alone is not enough, you need two more pieces, and they&#8217;re installed differently: </p><ol><li><p><strong>The v14.38 build tools &#8212; </strong><em><strong>from the Visual Studio installer</strong></em>. Open the installer, switch to the Individual components tab, and use the search box to type v14.38. The matching entry &#8212; MSVC v143 - VS 2022 C++ x64/x86 build tools (v14.38-17.8) &#8212; appears under the Out of Support group; the installer will warn that it&#8217;s unsupported. That&#8217;s expected. Tick it and install it. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zEcB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zEcB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 424w, https://substackcdn.com/image/fetch/$s_!zEcB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 848w, https://substackcdn.com/image/fetch/$s_!zEcB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 1272w, https://substackcdn.com/image/fetch/$s_!zEcB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zEcB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png" width="1456" height="788" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:788,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:527852,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/204415830?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zEcB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 424w, https://substackcdn.com/image/fetch/$s_!zEcB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 848w, https://substackcdn.com/image/fetch/$s_!zEcB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 1272w, https://substackcdn.com/image/fetch/$s_!zEcB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F423aaf6f-86f4-49bf-ba47-57906e8fa792_3200x1731.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div></li><li><p><strong>Windows 10 SDK 10.0.19041.0 &#8212; </strong><em><strong>as a separate download</strong></em>. <span>This version is </span><em><span>not</span></em><span> offered in the VS2026 installer. Download it on its own from the </span><a href="https://go.microsoft.com/fwlink/?linkid=2311805"><span>Windows SDK downloads site</span></a><span> and run that installer. Once installed, it becomes selectable as a target SDK in your project.</span></p></li></ol><h3>Installing the 3ds Max plugin project wizard </h3><p>The SDK ships an AppWizard that adds a <strong>&#8220;3ds Max Plugin&#8221;</strong> template to Visual Studio&#8217;s New Project dialog, pre-filled with the include paths, libraries, and project structure a plugin needs. It was written for Visual Studio 2022, but the setup for VS2026 is essentially works, you just copy the wizard files into the VS2026 IDE directory instead of the VS2022 one. </p><p>The wizard lives in: </p><p><code>3ds Max 2027 SDK\maxsdk\howto\3dsmaxPluginWizard\ </code></p><p>Open the <strong>readme.txt</strong> in that folder and follow its steps, with one substitution: wherever it points you at the Visual Studio 2022 IDE directory, use the VS2026 IDE directory instead <em>(the path where VS2026 is installed, under its Common7\IDE location)</em>. Copy the wizard&#8217;s .vsz / .vsdir and template files to the locations the readme describes, restart Visual Studio, and the 3ds Max plugin template appears in the New Project dialog. </p><h3>Create, Build, load, verify </h3><p>Similar to VS2022 workflow, create projects utilizing the Plugin Wizard for 3ds Max 2027. Projects generated still default to the correct v143 toolset.  </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TUSE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TUSE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 424w, https://substackcdn.com/image/fetch/$s_!TUSE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 848w, https://substackcdn.com/image/fetch/$s_!TUSE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 1272w, https://substackcdn.com/image/fetch/$s_!TUSE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TUSE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png" width="1456" height="940" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:940,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:204251,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/204415830?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TUSE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 424w, https://substackcdn.com/image/fetch/$s_!TUSE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 848w, https://substackcdn.com/image/fetch/$s_!TUSE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 1272w, https://substackcdn.com/image/fetch/$s_!TUSE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab07dfe7-5252-4f6e-93e3-a317769f7d96_2225x1437.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Build and Run in Hybrid| x64, and confirm your plugin appears and loads cleanly. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EH4B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EH4B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 424w, https://substackcdn.com/image/fetch/$s_!EH4B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 848w, https://substackcdn.com/image/fetch/$s_!EH4B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 1272w, https://substackcdn.com/image/fetch/$s_!EH4B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EH4B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png" width="1456" height="396" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:396,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:67429,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/204415830?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EH4B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 424w, https://substackcdn.com/image/fetch/$s_!EH4B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 848w, https://substackcdn.com/image/fetch/$s_!EH4B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 1272w, https://substackcdn.com/image/fetch/$s_!EH4B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6d71e9b-d078-478f-af53-0b1cfa761eab_2492x677.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If all was configured correctly, you should build successfully and 3ds Max should start and load the plugin. </p><h3>Tips and tricks </h3><p><em>Start from the SDK samples. The 3ds Max 2027 SDK ships sample projects that are already configured correctly. Building one of them first verifies your environment before you po</em></p><div><hr></div><p>Always cross-check exact version numbers against the official 3ds Max 2027 SDK Requirements page before you commit your build configuration &#8212; point releases can shift toolsets and Windows SDK expectations.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Singleton to Dependency Injection: A C++ Refactor]]></title><description><![CDATA[Why MantisBase is replacing the MantisBase::instance() singleton with dependency injection in v0.4.x; testability, honest signatures, and multiple instances per process.]]></description><link>https://www.codeart.co.ke/p/ripping-out-the-singleton</link><guid isPermaLink="false">https://www.codeart.co.ke/p/ripping-out-the-singleton</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Sun, 26 Jul 2026 17:58:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1774abd6-bf49-46be-8546-f30751e19254_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every codebase has a decision that felt obviously correct on day one and quietly turns into a debt you pay forever. For MantisBase, that decision was making the application object a singleton.</p><p>It made sense at the time. There is exactly one server, listening on exactly one port, owning one database pool, one router, and one logger. Why <em><strong>wouldn&#8217;t</strong></em> there be one global handle to reach it all? For most of <em>v0.1</em> through <em>v0.3</em>, that instinct served us well. In <em>v0.4.x</em> we are pulling the cord, replacing <em>MantisBase::instance()</em> with plain old dependency injection. This post is about why, and it&#8217;s worth starting with what a singleton actually <strong>is</strong> before explaining why we&#8217;re purging ours.</p><h2>A quick detour through design patterns</h2><p>If you&#8217;ve written software for any length of time you&#8217;ve absorbed design patterns whether or not you&#8217;ve read the book <em><a href="https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612">Design Patterns: Elements of Reusable Object-Oriented Software</a></em><a href="https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612"> (Gamma, Helm, Johnson &amp; Vlissides, 1994)</a>. Patterns are not language features or libraries; they&#8217;re names for shapes that keep recurring. Having a shared vocabulary is genuinely useful: <em>&#8220;wrap it in a decorator&#8221;</em> communicates a whole structure in three words.</p><p><em><strong>And then there&#8217;s Singleton.</strong></em></p><p>The Singleton pattern <em>&#8220;ensures a class has only one instance and provides a global point of access to it.&#8221;</em> Two promises in one sentence, and the second one is the problem. It&#8217;s the only creational pattern in the book that most of its own authors would now tell you to avoid. In a 2009 interview, Erich Gamma &#8212; one of the four &#8212; said plainly:</p><blockquote><p><em>&#8220;When discussing which patterns to drop, we found that we still love them all. (Not really, I&#8217;m in favor of dropping Singleton. Its use is almost always a design smell.)&#8221;</em></p><p>&#8212; Erich Gamma</p></blockquote><p>The reason he gives is the reason this post exists.</p><h2>How MantisBase became a singleton</h2><p>MantisBase is an embeddable backend, a BaaS you link into a C++ process and drive. The <em>MantisBase</em> class is the composition root: it owns every subsystem and hands them out.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;8e679110-9320-49d7-af04-c1b495324b35&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">class MANTISBASE_API MantisBase
{
public:
    static MantisBase&amp; instance();
    static MantisBase&amp; create(const json&amp; config = json::object());

    [[nodiscard]] Database&amp; db() const;
    [[nodiscard]] Router&amp; router() const;
    [[nodiscard]] Logger&amp; logs() const;
    [[nodiscard]] RealtimeDB&amp; rt() const;

    // ...

private:
    MantisBase();                       // creation is private
    static MantisBase&amp; getInstanceImpl();
    std::atomic&lt;bool&gt; m_isCreated = false;
};</code></pre></div><p>The mechanics are the textbook version. The constructor is private, <em>`create()`</em> builds the one instance, and <em>`instance()`</em> hands it back:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;4071887d-1e93-4861-9819-9ea9636d3e94&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">MantisBase &amp;MantisBase::instance() {
    auto &amp;app_instance = getInstanceImpl();
    if (!app_instance.isCreated())
        throw std::runtime_error("MantisBase not created yet");

    return app_instance;
}

MantisBase &amp;MantisBase::create(const json &amp;config) {
    auto &amp;app = getInstanceImpl();
    if (app.isCreated())
        throw std::runtime_error("MantisBase already created, "
                                 "use MantisBase::instance() instead.");

    // ...
}</code></pre></div><p>Even our own header documented the constraint as a feature:</p><div class="callout-block" data-callout="true"><p><em>MantisBase is a single-instance-per-process type (a managed singleton): the whole codebase reaches the active instance through <strong>instance()</strong>. Multiple concurrent instances in one process are not supported; <strong>create()</strong> throws if an instance already exists.</em></p></div><p>Once that door is open, the whole codebase walks through it. Reaching the <em>database</em> from a request handler, a <em>model</em>, an <em>auth check, or</em> a <em>file path</em> resolver&#8212;all of it collapses into one convenient line:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;848c52a2-92f9-4881-a13b-4644c99f5434&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// src/core/api_keys.cpp
auto sql = MantisBase::instance().db().session();

// src/core/files.cpp
return fs::path(MantisBase::instance().dataDir()) / "files";

// src/core/sse_mgr.cpp
auto &amp;router = MantisBase::instance().router();</code></pre></div><p>At last count, that pattern appeared across dozens of translation units, and that ubiquity is exactly the trap. Every one of those call sites is a dependency that doesn&#8217;t appear in any signature. Which brings us to why we&#8217;re ripping it out.</p><h2>Why we&#8217;re ripping it out</h2><h3>1. A singleton is a global variable, dressed nicely</h3><p>The case against globals is old and settled. Wulf and Shaw made it in 1973 in <em><strong>&#8220;Global Variable Considered Harmful&#8221;</strong></em>: non-local access makes it impossible to reason about a piece of code in isolation, because any part of the program can influence any other through the shared name. A singleton doesn&#8217;t repeal that argument; it just dresses it in a class with a <em>`static`</em> accessor. As Mi&#353;ko Hevery put it in his widely cited critique, <em><a href="https://testing.googleblog.com/2008/08/by-miko-hevery-so-you-join-new-project.html">Singletons are Pathological Liars</a></em>: the method signature lies to you. When a <em>`apiKeyLookup(id)`</em> secretly calls <em>`MantisBase::instance().db()`</em>, its true dependency list is nowhere in its declaration. You only discover it by reading the body or by watching it explode at runtime.</p><p>This is the Dependency Inversion Principle (<em>the &#8220;D&#8221; in Robert C. Martin&#8217;s SOLID</em>) inverted the <em>wrong</em> way: our high-level model and request code depended directly on a concrete global-access mechanism instead of on abstractions handed to them.</p><h3>2. The testing harness had to bend around it</h3><p>This is where the abstraction stopped being free. Because there can only ever be one instance per process, our entire test suite is built around a single global application that must be stood up once and shared by everything. Look at what the test environment has to do:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;7d21f9a6-01ec-4d47-9ff4-d388b9bbd44f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// tests/common/test_environment.h
inline MbTestEnv::MbTestEnv() {
    // ... assemble config ...
    mb::MantisBase::create(args);          // the one and only create()
}

inline void MbTestEnv::SetUp() {
    serverThread = std::thread([this]() {
        server_running.store(true);
        auto res = mb::MantisBase::instance().run();   // reach back for it
    });

    // sleep, poll /health, hope it came up...
}</code></pre></div><p>Every test then reaches through the same <em>global</em> to get at subsystems:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;b1086961-e4fb-466f-acf2-4b4afcfe1a2e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// tests/unit/test_database.cpp
EXPECT_TRUE(mb::MantisBase::instance().db().isConnected());

// tests/unit/test_models.cpp
mb::EntitySchema base{mb::MantisBase::instance(), "test", "base"};</code></pre></div><p>The consequences are exactly what Michael Feathers warns about in <em><strong>Working Effectively with Legacy Code (2004)</strong></em>. He defines a unit test as one that runs fast and in isolation, but singletons destroy isolation by construction. Global state persists between tests, so ordering matters, and you get to write defensive code like this just to survive a <em>`create() &gt; close() &gt; create()`</em> cycle within a single process:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;c6c5c8b2-b040-4b0f-9b30-a3b1b8086c57&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// src/mantisbase.cpp

// Start from a clean slate: on a create() -&gt; close() -&gt; create()
// cycle (e.g. across test runs in one process) the arg vector would
// otherwise accumulate the previous run&#8217;s arguments.

app.m_cmdArgs.clear();
app.m_cmdArgs.emplace_back("mantisbase");</code></pre></div><p>That comment is a remnant record of the pain, a state that should have died with an object instead outlives it, because the object is a <em>`static`</em> that never really goes away. Freeman and Pryce, in <em>Growing Object-Oriented Software, Guided by Tests (2009),</em> argue that hard-to-test code is usually a signal of a design problem, not a testing problem. The singleton was our signal, printed in every <em>`instance()`</em> call the tests had to make.</p><h3>3. We now genuinely need more than one instance per process</h3><p>The convenience argument for a singleton, <em>&#8220;there&#8217;s only ever one&#8221;</em>, turned out to be false as the product grew. We want to run <strong>multiple independent MantisBase instances in a single process</strong>: think isolated tenants, an embedding host driving several databases, or simply a test that spins up two servers and asserts they don&#8217;t leak into each other. We already have the test that describes the goal:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;04a53cb3-5a36-48e5-a49a-22510f044ed8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// tests/integration/test_integration_multi_instance.cpp

TEST_F(MultiInstanceTest, IndependentEntitiesDontInterfere) {
    // create schema multi_inst_a and multi_inst_b, insert into each,
    // and assert each entity sees exactly its own row.
    EXPECT_EQ(body_a["data"]["items_count"], 1);
    EXPECT_EQ(body_b["data"]["items_count"], 1);
}</code></pre></div><p>You cannot express <em>&#8220;two independent apps that don&#8217;t interfere&#8221;</em> when <em>`instance()`</em> is hardwired to return the one true app and <em>`create()`</em> throws the second time you call it. The singleton isn&#8217;t just inconvenient here; it makes the requirement <em>unrepresentable</em>.</p><h2>What we&#8217;re replacing it with</h2><p>The fix is the boring, correct one that Martin Fowler catalogued back in 2004 in <em><a href="https://martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a></em> constructor injection. Instead of reaching out to a global, each object is <strong>handed</strong> the app it belongs to, at construction, as its first parameter.</p><p>A locked-in design decision for <em>v0.4.x</em>: the app is the first constructor parameter, so nobody can forget to bind it.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;08b18ec1-b48f-491e-8933-825f1f27544d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// include/mantisbase/core/http.h

class MantisRequest {
    /// Owning application, injected by the Router when the request is
    /// wrapped. Request-path code reaches shared services (db, router,
    /// realtime, config) via app() instead of the global singleton.

    const MantisBase &amp;m_app;

public:
    explicit MantisRequest(const MantisBase&amp; mb, const drogon::HttpRequestPtr&amp; req);
    const MantisBase&amp; mApp() const { return m_app; }
};</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;06263a09-a96b-4e11-9154-43cba3e08bd2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// include/mantisbase/core/models/entity.h
Entity(const MantisBase &amp;app, const nlohmann::json &amp;schema);
Entity(const MantisBase &amp;app, const std::string &amp;name, const std::string &amp;type);</code></pre></div><p><em>`Router`</em>, <em>`Database`</em>, <em>`Entity`</em>, <em>`EntitySchema`</em>, `<em>SSEMgr`</em>, <em>`WSMgr`</em> each now takes its owning `MantisBase&amp;` up front and stores it. The dependency that used to be invisible is now right there in the signature, allowing the type to tell the truth about what it needs.</p><p>The refactor isn&#8217;t finished. A handful of <em>`instance()`</em> calls in infrastructure code&#8212;the logger, file utilities, date helpers, the SSE manager, and one validator&#8212;are deliberately still standing, development in progress <em>(maybe done by the time you are reading this!)</em>.</p><div><hr></div><p>The lesson from v0.4.x isn&#8217;t that <em><strong>singletons are bad.</strong></em> It&#8217;s that <em><strong>convenience at the composition root has a way of becoming a constraint at the leaves.</strong></em> <em>`MantisBase::instance()`</em> saved us a constructor parameter thousands of times and charged interest on every one. Dependency injection just makes you pay the cost up front, in the open, where the type system can see it, and that turns out to be the cheaper deal.</p><div><hr></div><p><em>This work is part of the ongoing MantisBase v0.4.x line. If you want to follow along, check out the <a href="https://github.com/allankoechke/mantisbase/tree/v0.4.x">v0.4.x branch</a> and watch out for exciting features coming soon!</em></p><p></p>]]></content:encoded></item><item><title><![CDATA[MantisBase v0.3.6 Release]]></title><description><![CDATA[A Cleaner, More Consistent API]]></description><link>https://www.codeart.co.ke/p/mantisbase-v036-release</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mantisbase-v036-release</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Wed, 01 Jul 2026 16:02:39 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/11c35355-bea5-4270-b806-4c165c4dfccd_1920x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>MantisBase v0.3.6</em> is a housekeeping release, marking the start of systemic cleanup. We cleaned up the REST API so every route follows the same conventions, scoped authentication to the entity it belongs to, and gave admin management its own home. There are a few breaking changes, but migration is a quick find-and-replace in most cases.</p><h2>Why the change?</h2><p>As MantisBase grew, the API surface accumulated small inconsistencies. Auth took the target entity in the request body while everything else was path-based. File serving lived at <code>`/api/files/...`</code> while the rest of the API was versioned under <code>`/api/v1/`</code>. Admin operations were split awkwardly between the <em>auth </em>namespace and the <em>system </em>namespace.</p><p>v0.3.6 makes the whole surface predictable. Everything now lives under <em>`/api/v1/`</em> in a clear set of namespaces:</p><p></p><h2>Authentication is now per-entity</h2><p>Previously you told <em>MantisBase </em>which entity to authenticate against by putting it in the request body:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;d19ad1c1-68f6-4a70-bf8b-500787b493cc&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># Old (v0.3.5)
curl -X POST http://localhost:7070/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"entity": "users", "identity": "user@example.com", "password": "pw"}'</code></pre></div><p>Now the entity lives in the URL, which is more <em>RESTful </em>and lets each auth entity have its own clearly addressable endpoints:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;e760237b-5ed4-41c6-a5db-270b7f6ccbdb&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># New (v0.3.6)
curl -X POST http://localhost:7070/api/v1/auth/users/login \
  -H "Content-Type: application/json" \
  -d '{"identity": "user@example.com", "password": "pw"}'</code></pre></div><p>The same pattern applies to refresh and logout:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;95d3734c-a570-42a8-8931-3cbed7ab24d6&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">curl -X POST http://localhost:7070/api/v1/auth/users/refresh \
  -H "Authorization: Bearer &lt;token&gt;"

curl -X POST http://localhost:7070/api/v1/auth/users/logout \
  -H "Authorization: Bearer &lt;token&gt;"</code></pre></div><p>The <em>`&lt;entity&gt;`</em> must be a registered <em>`auth`</em>-type entity that isn&#8217;t a system table and has the API enabled &#8212; otherwise you&#8217;ll get a clean <em>`404 Route Not Found`</em>.</p><p>One more thing: the login response is now wrapped in MantisBase&#8217;s standard envelope, so it matches every other endpoint:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;json&quot;,&quot;nodeId&quot;:&quot;7873cb27-bf8f-475f-9058-d54b0b4d64ac&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-json">{
  "status": 200,
  "data": {
    "token": "eyJhbGci...",
    "user&#8221;: { "id": "123456"&#8221;, "email": "user@example.com", "name": "John Doe" }
  },
  "error": ""
}</code></pre></div><h2>Admins get their own namespace</h2><p>Admin authentication and account management now live entirely under <em>`/api/v1/sys/admins/`</em>, and admin CRUD is fully supported:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;7d8f3259-71a8-4064-a744-c9bd244c1040&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># Create the very first admin (only works when none exist yet)
curl -X POST http://localhost:7070/api/v1/sys/admins/setup \
  -H "Content-Type: application/json" \
  -d '{"email": "admin@example.com", "password": "adminpassword"}'

# Admin login
curl -X POST http://localhost:7070/api/v1/sys/admins/login \
  -H "Content-Type: application/json" \
  -d '{"identity": "admin@example.com", "password": "adminpassword"}'

# Manage admin accounts (requires admin auth)
curl http://localhost:7070/api/v1/sys/admins                   # list
curl http://localhost:7070/api/v1/sys/admins/:id               # get one
curl -X POST   http://localhost:7070/api/v1/sys/admins ...     # create
curl -X PATCH  http://localhost:7070/api/v1/sys/admins/:id ..  # update
curl -X DELETE http://localhost:7070/api/v1/sys/admins/:id     # delete</code></pre></div><p>The old <em>`POST /api/v1/auth/setup/admin`</em> endpoint is gone &#8212; use <em>`/api/v1/sys/admins/setup`</em> instead.</p><h2>Files and settings</h2><p>File serving is now versioned, matching the rest of the API:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;f0249b78-8e06-4580-b6f1-03343b6b8eae&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash"># Old:  http://localhost:7070/api/files/posts/photo.jpg
# New:  http://localhost:7070/api/v1/files/posts/photo.jpg

curl http://localhost:7070/api/v1/files/posts/photo.jpg</code></pre></div><p>And application settings are exposed under the system namespace:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;bash&quot;,&quot;nodeId&quot;:&quot;c8f1ee73-461d-4bb0-80b7-be689ceab874&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-bash">curl http://localhost:7070/api/v1/sys/settings/config   # read
curl -X PATCH http://localhost:7070/api/v1/sys/settings/config \
  -H "Content-Type: application/json" -d '{ ... }'             # update</code></pre></div><h2>Under the hood: lighter on memory</h2><p>Beyond the visible API changes, we refactored how routes are registered. Instead of building a dedicated set of CRUD handlers for every single entity, MantisBase now uses centralized, generic handlers that resolve the target entity from the request path. Schema route handlers were similarly decoupled from the schema object. The result is the same behavior with a smaller memory footprint &#8212; <em>especially noticeable on deployments with many entities.</em></p><p>We also refreshed the bundled dependencies <em>(WolfSSL, nlohmann/json, jwt-cpp, spdlog, and the mb-admin dashboard)</em> and fixed a build-target clash around `z<code>td`.</code></p><h2>Something is broken, oh no!</h2><p>As a result of the API changes, we ended up breaking the admin dashboard. Currently, v0.3.6 <em>admin dashboard is unusable</em> and requires reworking to bring it up to bar. That&#8217;s already being worked on and we will push an update once resolved.</p><h2>Upgrading from v0.3.5</h2><p>Most apps only need three mechanical updates:</p><ol><li><p><strong>Auth calls</strong>: move the entity from the body into the path <br><code>(`/api/v1/auth/login` + `"entity": "users"` &#8594; `/api/v1/auth/users/login`).</code></p></li><li><p><strong>Admin calls:</strong> repoint admin auth/setup to <em>`/api/v1/sys/admins/...`</em>.</p></li><li><p><strong>File URLs:</strong> add the <em>1</em> segment (`/api/files/...` &#8594; `/api/v1/files/...`).</p></li></ol><p>If you parse the login response, unwrap it from the new <em>`{ status, data, error }`</em> envelope.</p><div><hr></div><p>That&#8217;s it &#8212; grab v0.3.6 from the <a href="https://github.com/allankoechke/mantisbase/releases/tag/v0.3.6">releases page</a>, and check the updated <a href="https://github.com/allankoechke/mantisbase/blob/master/doc/02.auth.md">Authentication API</a> and <a href="https://github.com/allankoechke/mantisbase/blob/master/doc/02.api.md">API Reference</a> docs for the full details.</p>]]></content:encoded></item><item><title><![CDATA[To Port or Not to Port: C++ to Rust, and the Trap of the 90% Demo]]></title><description><![CDATA[Ownership was never in the source code. That's the whole migration &#8212; and it's exactly the part the demo skips.]]></description><link>https://www.codeart.co.ke/p/to-port-or-not-to-port-c-to-rust</link><guid isPermaLink="false">https://www.codeart.co.ke/p/to-port-or-not-to-port-c-to-rust</guid><dc:creator><![CDATA[Allan Koech]]></dc:creator><pubDate>Sun, 28 Jun 2026 21:05:04 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f7360ec9-5391-4901-b2e0-d0626ac198ce_1672x941.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><span>There is a demo making the rounds in every engineering org right now. You point an LLM at a gnarly C++ file, and ninety seconds later you have Rust that compiles. It looks like the migration problem just got solved. Leadership sees it, a quarter gets funded, and a team starts pointing the model at the codebase file by file.</span></p><p><span>Then, somewhere around the third month, the project stalls. Not dramatically &#8212; there&#8217;s no postmortem, no cancellation email. It just quietly stops moving. The remaining work never gets easier, the Rust never gets </span><em><span>good</span></em><span>, and eventually the branch goes stale.</span></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.codeart.co.ke/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en-gb&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Codeart &#8212; by Allan Koech! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p><span>This isn&#8217;t a failure of nerve or tooling. It&#8217;s a structural property of what porting C++ to Rust actually </span><em><span>is</span></em><span> &#8212; and it&#8217;s worth understanding before you spend a quarter learning it the expensive way.</span></p><h2><strong><span>The seduction is real, and so is the wall</span></strong></h2><p><span>The reason the demo is so convincing is that the first 90% genuinely is easy now. Translating C++ control flow, arithmetic, and data structures into syntactically valid Rust is exactly the kind of pattern-matching LLMs are good at. The compiler even helps: if it builds, a lot of bugs are already gone.</span></p><p><span>The problem is what&#8217;s hiding in the last 10%, and it&#8217;s the same thing whether a human or a model is doing the work.</span></p><p><span>C++ does not encode ownership. When you write </span><code>T* p</code><span>, the language does not record whether </span><code>p</code><span> owns that memory, borrows it, shares it, or aliases something else that&#8217;s about to be freed. Those facts live in the programmer&#8217;s head, in comments, in naming conventions, and in tribal knowledge about </span><em><span>&#8220;who frees what.&#8221;</span></em><span> </span><strong><span>Rust&#8217;s entire value proposition is that these facts must be written down and checked.</span></strong><span> So a C++&#8594;Rust port is not a translation. It&#8217;s a </span><em><span>reconstruction of invariants that were never explicitly recorded.</span></em></p><div class="callout-block" data-callout="true"><p>So a C++&#8594;Rust port is not a translation. It&#8217;s a <em>reconstruction of invariants that were never explicitly recorded.</em></p></div><p><span>That&#8217;s why automatic transpilers are so instructive. Tools like </span><a href="https://arxiv.org/pdf/2511.20617"><span>c2rust</span></a><span> produce Rust that is </span><em><span>&#8220;almost always correct&#8221;</span></em><span> &#8212; and almost always </span><em><span>unsafe</span></em><span> and unidiomatic. They faithfully preserve C&#8217;s pointer semantics by wrapping everything in </span><code>unsafe</code><span>, raw pointers, and </span><code>libc</code><span> calls. The output compiles. It is also, in the words of the research, </span><em><span>&#8220;very different from the kind of Rust code usually written by humans, making it hard to read and maintain&#8221;</span></em><span> &#8212; and it sails straight past the linters that are supposed to catch the problems. You get Rust syntax with C semantics: all of the migration cost, none of the safety payoff.</span></p><p><span>LLMs improve on this &#8212; they can sometimes infer ownership and produce idiomatic code &#8212; but the failure mode is sneakier. As DARPA&#8217;s program manager for </span><a href="https://www.darpa.mil/research/programs/translating-all-c-to-rust"><span>TRACTOR </span></a><span>(the agency&#8217;s program to automate exactly this translation) put it: ask any model to translate C to safe idiomatic Rust and </span><em><span>&#8220;something comes out, and it&#8217;s often very good, but not always.&#8221;</span></em><span> When it&#8217;s not, the model tends to reach for </span><code>unsafe</code><span> to make the borrow checker stop complaining &#8212; which is precisely how you end up with code that </span><em><span>looks</span></em><span> migrated but carries the same latent bugs it always had, now harder to spot because everyone assumes </span><em><span>&#8220;it&#8217;s in Rust, so it&#8217;s safe.&#8221;</span></em></p><p><span>This is the mechanism behind the stall. The borrow checker doesn&#8217;t get tired and wave the last 10% through. Every place where the original C++ had a fuzzy ownership story becomes a hard stop that requires a human to </span><em><span>decide</span></em><span> what the ownership story should be &#8212; and frequently to redesign the data structures to express it. That&#8217;s design work, not typing work. LLMs removed the typing bottleneck, which was never the bottleneck.</span></p><h2><strong><span>The evidence cuts both ways &#8212; but cleanly</span></strong></h2><p><span>The honest read of the industry data is not </span><em><span>&#8220;Rust good&#8221;</span></em><span> or </span><em><span>&#8220;rewrites bad.&#8221;</span></em><span> It&#8217;s that </span><em><span>the shape of the project predicts the outcome</span></em><span> far better than the language choice does.</span></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!se6i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!se6i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 424w, https://substackcdn.com/image/fetch/$s_!se6i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 848w, https://substackcdn.com/image/fetch/$s_!se6i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 1272w, https://substackcdn.com/image/fetch/$s_!se6i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!se6i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png" width="1456" height="375" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:375,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:158874,&quot;alt&quot;:&quot;porting strategy across the industry&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.codeart.co.ke/i/204011442?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="porting strategy across the industry" title="porting strategy across the industry" srcset="https://substackcdn.com/image/fetch/$s_!se6i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 424w, https://substackcdn.com/image/fetch/$s_!se6i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 848w, https://substackcdn.com/image/fetch/$s_!se6i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 1272w, https://substackcdn.com/image/fetch/$s_!se6i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcbb153e-efa6-409f-ade6-2a8a504fb908_2536x654.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><span>Look at what the wins have in common. Android never </span><em><span>ported</span></em><span> anything &#8212; Google&#8217;s entire strategy is that new code is Rust and old C++ is left in place; the safety gains come from the fact that </span><em><a href="https://security.googleblog.com/2025/11/rust-in-android-move-fast-fix-things.html"><span>&#8220;most bugs live in new code&#8221;</span></a></em><span>, so you don&#8217;t need to touch the old stuff to bend the curve. Pingora wasn&#8217;t a translation at all; it was a </span><em><span>clean-room reimplementation</span></em><span> against a known spec, where the team got to design the ownership model from scratch instead of recovering it from someone else&#8217;s pointers. Mozilla picked off self-contained, parallelism-hungry components one at a time and integrated each before starting the next.</span></p><p><span>Now look at curl. Daniel Stenberg&#8217;s team spent </span><strong><span>roughly five years</span></strong><span> (2020&#8211;2025) trying to let curl use the Rust </span><a href="https://daniel.haxx.se/blog/2024/12/21/dropping-hyper/"><span>hyper </span></a><span>library as an HTTP backend through an FFI glue layer &#8212; and ultimately ripped it out. The reasons are a near-perfect catalog of why these projects die:</span></p><ul><li><p><strong><span>The last 5% was the whole problem.</span></strong><span> </span><em><span>&#8220;The final few percent would turn out to be friction enough to now eventually make us admit defeat.&#8221;</span></em></p></li><li><p><strong><span>Nobody to do the hard part.</span></strong><span> It needed someone fluent in </span><em><span>both</span></em><span> C and Rust </span><em><span>and</span></em><span> the HTTP protocols to drive the integration across the FFI boundary &#8212; and almost no one wanted to.</span></p></li><li><p><strong><span>The FFI seam leaked.</span></strong><span> They had to </span><em><span>remove</span></em><span> HTTP/2 support because they&#8217;d misunderstood how the API integrated across the language boundary.</span></p></li><li><p><strong><span>No demand pulling it forward.</span></strong><span> curl users didn&#8217;t care that a backend was in Rust; Rust users didn&#8217;t want to maintain glue for a C project.</span></p></li></ul><p><span>Stenberg&#8217;s conclusion is the bluntest data point in the whole debate: </span><a href="https://thenewstack.io/curls-daniel-stenberg-on-securing-180000-lines-of-c-code/"><span>&#8220;We&#8217;re not going to rewrite curl in Rust. In any language &#8212; we&#8217;re not going to rewrite it at all.&#8221;</span></a><span> This from someone who openly acknowledges that </span><a href="https://daniel.haxx.se/blog/2021/03/09/half-of-curls-vulnerabilities-are-c-mistakes/"><span>roughly half of curl&#8217;s historical vulnerabilities are C memory mistakes</span></a><span>. He knows the safety case cold. He&#8217;s declining anyway, because the migration cost is real and the existing C is hardened by decades of fuzzing and CVE wrangling.</span></p><h2><strong><span>The hidden tax: comprehension debt</span></strong></h2><p><span>There&#8217;s a second-order cost that the demo never shows you, and it&#8217;s worse with LLM-driven ports than with hand ports.</span></p><p><span>When a model emits 4,000 lines of plausible Rust, </span><em><span>no one on your team owns the mental model of that code.</span></em><span> The 2025 research on LLM-generated code calls this </span><a href="https://codemanship.wordpress.com/2025/09/30/comprehension-debt-the-ticking-time-bomb-of-llm-generated-code/"><span>comprehension debt</span></a><span> and </span><em><span>&#8220;ownership debt&#8221;</span></em><span>: </span><em><span>&#8220;it compiles&#8221;</span></em><span> is not the same as </span><em><span>&#8220;someone understands why it&#8217;s correct and can change it safely.&#8221;</span></em><span> With a hand-written port, the engineer who fought the borrow checker comes out the other side </span><em><span>understanding the ownership model</span></em><span> &#8212; that understanding is half the point. With a generated port, you&#8217;ve skipped the understanding and kept only the artifact. The first time it needs a non-trivial change, you pay the comprehension cost you deferred, except now under deadline and without the person who&#8217;d have built the model.</span></p><p><span>This is why &#8220;the LLM did 90% in a week&#8221; is a misleading metric. The week of typing was never the expensive part. The expensive part is owning a correct mental model of a safety-critical system &#8212; and that&#8217;s exactly what gets skipped when the code arrives pre-written.</span></p><h2><strong><span>A decision framework that actually predicts outcomes</span></strong></h2><p><span>Stop asking </span><em><span>&#8220;should we port to Rust?&#8221;</span></em><span> It&#8217;s the wrong altitude. Ask these instead:</span></p><h3><strong><span>1. Is this new code or existing code?</span></strong></h3><p><span>If new, strongly favor Rust, and stop reading. The Android data is overwhelming: the cheapest safety win is to stop </span><em><span>adding</span></em><span> to the C++ pile. No migration risk, all the upside.</span></p><h3><strong><span>2. If existing &#8212; is the component self-contained, or is it threaded through the codebase?</span></strong></h3><p><span>A module with a narrow, well-defined interface (a parser, a codec, a proxy data path) is a Stylo/Pingora candidate. A module whose pointers reach into everything will trap you in </span><strong><span>FFI hell</span></strong><span>: every call across the C++/Rust seam is an </span><code>unsafe </code><span>boundary where Rust&#8217;s guarantees evaporate and new bugs breed. The curl/hyper failure was fundamentally an FFI-boundary failure.</span></p><h3><strong><span>3. Do you have a spec, or only the code?</span></strong></h3><p><span>If you can reimplement against a specification or a strong test suite (Pingora had the HTTP spec; you can have a differential test harness), favor a </span><em><span>clean-room rewrite</span></em><span> over a line-by-line port. You&#8217;ll design the ownership model instead of reverse-engineering it, and you can run old and new side by side to prove equivalence.</span></p><h3><strong><span>4. Will someone own the result?</span></strong></h3><p><span>If the answer is </span><em><span>&#8220;the LLM wrote it and we&#8217;ll figure it out later,&#8221;</span></em><span> you don&#8217;t have a migration plan, you have a future incident. Budget the human comprehension cost up front or don&#8217;t start.</span></p><h3><strong><span>5. Is the existing C++ actually your risk?</span></strong></h3><p><span>Battle-hardened, heavily-fuzzed C++ that hasn&#8217;t thrown a CVE in years is not where your memory-safety risk concentrates. New and frequently-changed code is. Spend the migration budget where the bugs actually are.</span></p><h2><strong><span>The verdict</span></strong></h2><p><strong><span>Use the LLM</span></strong><span>. It genuinely removed a real cost &#8212; the mechanical translation that used to make these projects unaffordable to even start. But understand precisely what it removed and what it didn&#8217;t. It removed the </span><em><span>typing</span></em><span>. It did not remove the </span><em><span>thinking</span></em><span>: recovering ownership invariants that C++ never recorded, designing data structures that satisfy the borrow checker, and proving the result is equivalent to the original.</span></p><p><strong><span>That thinking is the project</span></strong><span>. It was always the project. The reason ports stall at 90% is that the demo completes the 90% that was never hard, and then hands you the 10% that was the entire point &#8212; now disguised as &#8220;almost done.&#8221;</span></p><p><strong><span>Port new code by default</span></strong><span>. Port self-contained components against a spec. Leave hardened, stable C++ alone. And treat any plan whose timeline is built on </span><em><span>&#8220;the model already wrote most of it&#8221;</span></em><span> as a plan that hasn&#8217;t started yet.</span></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.codeart.co.ke/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en-gb&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Codeart &#8212; by Allan Koech! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[MantisBase is Moving to Rust]]></title><description><![CDATA[There is no shortage of "rewrite it in Rust" stories on the internet.]]></description><link>https://www.codeart.co.ke/p/mantisbase-is-moving-to-rust</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mantisbase-is-moving-to-rust</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Mon, 18 May 2026 19:40:05 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/aaa6e839-a98a-4cd7-a7f7-9dd0bdbf4142_690x350.svg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IXjp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IXjp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 424w, https://substackcdn.com/image/fetch/$s_!IXjp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 848w, https://substackcdn.com/image/fetch/$s_!IXjp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 1272w, https://substackcdn.com/image/fetch/$s_!IXjp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IXjp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IXjp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 424w, https://substackcdn.com/image/fetch/$s_!IXjp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 848w, https://substackcdn.com/image/fetch/$s_!IXjp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 1272w, https://substackcdn.com/image/fetch/$s_!IXjp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F06fc8da7-12f5-498d-8934-d20d96346e38_690x350.svg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>There is no shortage of <em>"rewrite it in Rust"</em> stories on the internet. Some are driven by hype, others by genuine engineering needs. This is not the former. What follows is a straightforward account of where MantisBase is headed, why, and what it means for you.</p><div><hr></div><h2>A Growing Ecosystem Worth Taking Seriously</h2><p>Before getting into the decision itself, it is worth acknowledging the state of Rust as a language and ecosystem. The <em>Rustacean</em> community has grown into one of the most active and technically rigorous developer communities in open source. The <a href="https://crates.io">crates.io</a> registry now hosts hundreds of thousands of packages, covering everything from async runtimes and HTTP frameworks to database drivers, JWT handling, and mailer integrations &#8212; all with first-class tooling and consistently high quality. Rust has also topped Stack Overflow's "most admired language" survey for several consecutive years, which speaks less to popularity and more to developer satisfaction once they have committed to it.</p><p>We have been watching this ecosystem closely. It has matured to a point where building a production-grade, single-binary backend on top of it is not only feasible &#8212; it is arguably the most sensible path forward for a project with MantisBase's goals.</p><div><hr></div><h2>What Is Already Happening</h2><p>Work on v0.4 has begun, and it is a full rewrite in Rust. The goal is to reach feature parity with the current C++ release at minimum, and to go further where the new foundation makes it practical to do so. If you want to track progress, the <a href="https://github.com/allankoechke/mantisbase">master branch on GitHub</a> already reflects the active rewrite &#8212; the repository is already building and running in Rust, with core functionality like entity schemas, REST routing, access rules, JWT authentication, admin dashboard serving, and webhook support already in place.</p><p>This is not a distant roadmap item. It is ongoing work, and it is further along than most announcements of this kind tend to let on.</p><div><hr></div><h2>Why the C++ Foundation Was Holding Us Back</h2><p>MantisBase started as a C++ project for good reasons: raw speed, embeddability, and a single-binary deployment model with no external runtime dependency. Those goals have not changed. What changed is our assessment of the cost of continuing to pursue them in C++.</p><p>The C++ codebase accumulated a set of challenges over time &#8212; not insurmountable, but expensive to address correctly. Memory management patterns that required careful audit, integration complexity when pulling in third-party libraries, and a build system that made certain kinds of cross-platform testing harder than it needed to be. Fixing these properly would have demanded a significant investment of time &#8212; time that should have gone toward improving the product.</p><p>The practical result was that several things we wanted to deliver kept getting pushed back. The documentation site needed modernisation. The admin dashboard needed a cleaner, more capable UI. The REST API had features we wanted to expand. Most notably, out-of-the-box SDK support for JavaScript and Python &#8212; something users have asked about consistently &#8212; was hard to prioritise while we were managing the overhead of the C++ foundation.</p><p>We reached a point where the honest assessment was: the language itself had become a constraint on the project's growth, not just a technical detail.</p><div><hr></div><h2>Why Rust, and Not Zig or Go</h2><p>Once the decision to move away from C++ was made, we evaluated the realistic alternatives that could preserve what made MantisBase useful in the first place: a single compiled binary, genuine performance, and low memory overhead. Rust, Zig, and Go were the serious contenders.</p><p>Go produces clean binaries and has an excellent standard library, but its garbage collector introduces latency characteristics that are a poor fit for a backend meant to be embedded inside other applications. Zig is technically compelling and offers tight control over memory, but its ecosystem and tooling are still maturing &#8212; pulling in third-party integrations would mean building more from scratch than we wanted.</p><p>Rust offered the right combination: compile-time memory safety without a garbage collector, a mature ecosystem through crates.io, and tooling (cargo, rustfmt, clippy, cargo test) that genuinely reduces friction rather than adding to it. The memory safety story was particularly relevant. Part of why the C++ codebase was difficult to maintain was precisely the category of issues that Rust eliminates at the compiler level &#8212; use-after-free, data races, invalid pointer dereferences. We could have audited and hardened the C++ code, but choosing Rust means we do not have to keep having that conversation on every future contribution.</p><p>Beyond safety, the crate ecosystem makes it straightforward to integrate capabilities that previously required significant custom work: mailer support via <a href="https://github.com/lettre/lettre">lettre</a>, async HTTP with <a href="https://github.com/tokio-rs/axum">axum</a>, database access via <a href="https://github.com/launchbargain/sqlx">sqlx</a>, and more. These are not afterthoughts &#8212; they are well-maintained, widely used libraries that slot in cleanly.</p><p>First-class test support via <code>cargo test</code> is also worth naming directly. Writing and running tests in C++ projects of this kind involves considerably more ceremony. In Rust, testing is a natural part of the workflow, which matters when you are trying to build confidence in a rewrite incrementally.</p><div><hr></div><h2>Language SDK Support Becomes Realistic</h2><p>One of the things we wanted to offer from early on was MantisBase SDKs for JavaScript and Python &#8212; not just REST clients, but deeper integration. In the C++ world, producing idiomatic bindings for both languages meant navigating complex FFI boundaries, separate build pipelines, and significant maintenance surface.</p><p>From Rust, this is substantially more tractable. The <a href="https://pyo3.rs">PyO3</a> project provides a mature path for exposing Rust libraries to Python, and <a href="https://neon-bindings.com">Neon</a> (or WASM targets) covers the Node.js side. We are not committing to a specific release timeline for these yet, but the rewrite removes the structural obstacle that made them impractical before.</p><div><hr></div><h2>What Happens to C++ Support</h2><p>The original C++ releases are not being abandoned. Binaries up through v0.3.5 remain available on the <a href="https://github.com/allankoechke/mantisbase/releases">GitHub releases page</a>, and that code is not going anywhere.</p><p>Looking further ahead, we are interested in the model that projects like <a href="https://slint.dev">Slint</a> have demonstrated. Slint is a UI toolkit written in Rust that exposes a fully supported C++ API &#8212; developers working in C++ interact with it as though it were a native C++ library, with no Rust toolchain required on their end. Several other projects in the embedded and systems space have taken similar approaches. We are examining what that looks like for MantisBase's embedding use case, and C++ API support remains part of the long-term plan.</p><div><hr></div><h2>What to Expect Next</h2><p>The v0.4 work is progressing in the open. You can follow along, open issues, or contribute via the <a href="https://github.com/allankoechke/mantisbase">GitHub repository</a>. The current Rust codebase is already functional enough to run and experiment with.</p><p>A more detailed devlog covering the architecture of the Rust port &#8212; including database abstraction, the new schema engine, and the HTTP layer &#8212; is coming soon. For updates, subscribe below or follow <a href="https://x.com/allankoechke">@allankoechke</a> on X.</p><div><hr></div><p><em>MantisBase is an open-source, single-binary Backend-as-a-Service. Visit <a href="https://mantisbase.com">mantisbase.com</a> for documentation and demos.</em></p>]]></content:encoded></item><item><title><![CDATA[What’s new in 3ds Max 2027?]]></title><description><![CDATA[Originally posted here:]]></description><link>https://www.codeart.co.ke/p/whats-new-in-3ds-max-2027</link><guid isPermaLink="false">https://www.codeart.co.ke/p/whats-new-in-3ds-max-2027</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Mon, 13 Apr 2026 07:25:40 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4f517473-944d-4277-9db7-47c37427c948_1412x795.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gEzp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gEzp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 424w, https://substackcdn.com/image/fetch/$s_!gEzp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 848w, https://substackcdn.com/image/fetch/$s_!gEzp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 1272w, https://substackcdn.com/image/fetch/$s_!gEzp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gEzp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gEzp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 424w, https://substackcdn.com/image/fetch/$s_!gEzp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 848w, https://substackcdn.com/image/fetch/$s_!gEzp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 1272w, https://substackcdn.com/image/fetch/$s_!gEzp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6d49560-3af5-4f88-8d9a-7638a5343edc_1412x795.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><div><hr></div><p>Originally posted here:</p><blockquote><h4><a href="https://blog.autodesk.io/whats-new-in-3ds-max-2027/">Explore New Features in 3ds Max 2027 Release Updates</a></h4></blockquote><div><hr></div><p>A few weeks ago, 3ds Max 2027 was officially released, introducing new features and capabilities for both artists and developers. With this release, 3ds Max saw many upgrades including <em>Arnold to 5.9.0, USD to 0.14.0, Substance to 3.0.6</em>, performance improvements across tools, modifiers, and render workflows, and much more. Refer to the <a href="https://help.autodesk.com/view/3DSMAX/2027/ENU/?guid=GUID-7CC2F041-F797-4DB9-B2F9-326AAB994F37">product release page</a> for a detailed feature breakdown for 3ds Max 2027.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 424w, https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 848w, https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 1272w, https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 1456w" sizes="100vw"><img src="https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif" width="800" height="450" data-attrs="{&quot;src&quot;:&quot;https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Smart Bevel for post-Boolean intersections&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Smart Bevel for post-Boolean intersections" title="Smart Bevel for post-Boolean intersections" srcset="https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 424w, https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 848w, https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 1272w, https://blog.autodesk.io/wp-content/uploads/2026/04/GUID-05B7B772-F025-42E4-A43B-238EE14FDF74.gif 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Smart Bevel for post-Boolean intersections released in 3ds Max 2027</figcaption></figure></div><h2>New Features, Improvements, and Updated Workflows</h2><p>3ds Max 2027 ships with several notable updates across its plugin ecosystem:&nbsp;</p><ul><li><p>Arnold for 3ds Max updated to <em>5.9.0</em> (Arnold <em>7.5.0.0</em>)</p></li><li><p>USD for 3ds Max updated to <em>0.14.0</em></p></li><li><p>Substance updated to 3.0.6</p></li><li><p>Autodesk Assistant (Technical Preview): An AI-powered tool that helps you quickly find information about features and workflows directly within the product &#8212; a welcome addition for developers and artists alike looking to streamline their pipeline research. Read more <a href="https://help.autodesk.com/view/3DSMAX/2027/ENU/?guid=GUID-92EF3530-9E04-46DF-B3F2-2BA150C6CEDF">here</a>.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DtIv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DtIv!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 424w, https://substackcdn.com/image/fetch/$s_!DtIv!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 848w, https://substackcdn.com/image/fetch/$s_!DtIv!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 1272w, https://substackcdn.com/image/fetch/$s_!DtIv!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DtIv!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif" width="1280" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;A digital interface displaying guidelines for camera types in 3ds Max 2026, set in a kitchen environment with chairs and a fridge in the background.&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="A digital interface displaying guidelines for camera types in 3ds Max 2026, set in a kitchen environment with chairs and a fridge in the background." title="A digital interface displaying guidelines for camera types in 3ds Max 2026, set in a kitchen environment with chairs and a fridge in the background." srcset="https://substackcdn.com/image/fetch/$s_!DtIv!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 424w, https://substackcdn.com/image/fetch/$s_!DtIv!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 848w, https://substackcdn.com/image/fetch/$s_!DtIv!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 1272w, https://substackcdn.com/image/fetch/$s_!DtIv!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281cee7a-03a4-4099-ae60-7cffff8e7412_1280x720.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>SDK Changes</h2><p>Now let's get into what matters most for plugin developers.</p><ul><li><p><strong>.NET 10.0 Support</strong>: 3ds Max 2027 moves plugin development to .NET 10. Note that .NET 8, introduced in 3ds Max 2026, has reached an end of life and is no longer supported. If you are still on an older version, refer to our porting guide from .NET Framework to .NET for plugins for step-by-step migration guidance.</p></li><li><p><strong>DirectX 9 Removal</strong>: Support for DirectX 9 has been fully removed. This affects several headers that have been dropped from the public SDK &#8212; notably id3d9graphicswindow.h, idx9pixelshader.h, and idx9vertexshader.h &#8212; along with related interfaces in <em>ihardwarematerial.h, ihardwarerender.h, </em>and <em>RTMax.h</em>. Developers relying on these should migrate to the DirectX 11 equivalents now available in the SDK.</p></li><li><p><strong>Updated Core Dependencies</strong>: 3ds Max 2027 development specifies Visual Studio 2022 (v17.14.x), C++20, Qt 6.8.3. Review your plugin dependencies against these versions before building. You could also use the newer Visual Studio 2026, when you set the toolset to be v143.</p></li><li><p><strong>API Changes</strong>: There are targeted API updates across several headers &#8212; including new methods in <em>custcont.h</em>,<em> ioapi.h</em>, and<em> IValidateNodeCallback.h</em>, as well as deprecations in <em>object.h</em>, <em>gfx.h</em>, and others.</p></li><li><p><strong>Updated Samples and Documentation</strong>: Samples and documentation have been updated to reflect all API changes in this release.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[MantisBase v0.3.4 — Admin Upgrades, Bug Fixes & Docker Updates]]></title><description><![CDATA[We're shipping v0.3.4 today with a handful of quality-of-life improvements, a cleaner configuration story, and a few important bug fixes.]]></description><link>https://www.codeart.co.ke/p/mantisbase-v0-3-4-release</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mantisbase-v0-3-4-release</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Thu, 26 Feb 2026 23:24:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d102db5a-65ce-48ca-9db4-94fbd04d1d0b_1920x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!K04a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!K04a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!K04a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!K04a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!K04a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!K04a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!K04a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!K04a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!K04a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!K04a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcca9d511-1d33-49f6-9a3c-f970fb442a10_1920x1080.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>We're shipping <em><strong>v0.3.4</strong></em> today with a handful of quality-of-life improvements, a cleaner configuration story, and a few important bug fixes. Here's what's new.</p><div><hr></div><h2>Unified <code>MB_*</code> Environment Variable Prefix</h2><p>All environment variables now consistently use the <code>MB_*</code> prefix. If you were previously setting <code>MANTIS_JWT_SECRET</code>, update that to <code>MB_JWT_SECRET</code> &#8212; the old name is no longer recognised. This brings every runtime knob under one coherent namespace and makes it easier to manage configuration in Docker and CI environments.</p><p>Variable Description Default <code>MB_JWT_SECRET</code> JWT signing secret (set this in production!) built-in default <code>MB_DISABLE_FILE_UPLOADS</code> Set to <code>1</code> to disable file uploads globally <code>0</code> <code>MB_DISABLE_ADMIN_ON_FIRST_BOOT</code> Set to <code>1</code> to skip auto-admin creation browser spin off <code>0</code> <code>MB_DISABLE_RATE_LIMIT</code> Set to <code>1</code> to disable rate limiting enabled</p><div><hr></div><h2>File Upload Kill Switch</h2><p>A new <code>MB_DISABLE_FILE_UPLOADS=1</code> flag lets you turn off file uploads at the server level without touching your schema. Any upload attempt while this flag is active will receive a <code>403 Forbidden</code> response. Useful for read-only deployments or environments where you want to enforce that no files land on disk.</p><div><hr></div><h2>Docker Improvements</h2><p>The Dockerfile has been updated to <code>debian:trixie-slim</code> as its base, and the build arg has been renamed from <code>MANTIS_VERSION</code> to <code>MB_VERSION</code> (default <code>0.3.4</code>) to match the new naming convention. The docker-compose file now also surfaces all <code>MB_*</code> variables as commented-out stubs, so it's clear what you can configure without digging through docs.</p><p>The published image on Docker Hub is <code>allankoech/mantisbase</code> &#8212; the quick-start command is simply:</p><pre><code>docker run -p 7070:80 allankoech/mantisbase
</code></pre><p>All submodules have also been switched from SSH to HTTPS URLs and set to shallow fetch, which significantly speeds up fresh clones in CI pipelines.</p><div><hr></div><h2>Admin Panel Updates</h2><p>Several improvements have landed in the admin UI this release:</p><p><strong>Entity cloning</strong> &#8212; You can now clone an existing entity directly from the admin panel. Cloning copies the source entity's schema (field names, types, and structure) into a new entity, giving you a clean starting point to build on without recreating common field sets from scratch. No records are carried over, only the schema.</p><p><strong>Entity renaming</strong> &#8212; Entities can now be renamed from within the admin panel without having to drop and recreate them.</p><p><strong>Long entity name overflow fix</strong> &#8212; Entity names that exceeded the available sidebar/panel width were pushing other UI elements off screen. This has been corrected so long names truncate gracefully and the layout stays intact.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dyiE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dyiE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 424w, https://substackcdn.com/image/fetch/$s_!dyiE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 848w, https://substackcdn.com/image/fetch/$s_!dyiE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 1272w, https://substackcdn.com/image/fetch/$s_!dyiE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dyiE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png" width="556" height="366" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:366,&quot;width&quot;:556,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!dyiE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 424w, https://substackcdn.com/image/fetch/$s_!dyiE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 848w, https://substackcdn.com/image/fetch/$s_!dyiE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 1272w, https://substackcdn.com/image/fetch/$s_!dyiE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1a3e558d-7a68-414b-a74f-3d95b0d10f5d_556x366.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>Minor bug fixes and improvements</strong> across the admin panel generally.</p><div><hr></div><h2>Bug Fixes</h2><ul><li><p><strong>PATCH requests with password fields</strong> &#8212; a missing-field error that surfaced when patching records containing a <code>password</code> field has been resolved.</p></li><li><p><strong>Last-activity tracking</strong> &#8212; activity timestamps now only update on actual database record changes, not on every SSE ping or passive connection event. This prevents misleading "active" signals for idle clients.</p></li><li><p><strong>SSE session cleanup</strong> &#8212; auth tokens are no longer held in memory on SSE sessions. The token field is explicitly nulled out after verification, reducing the risk of credentials lingering in heap memory across a long-lived connection.</p></li></ul><div><hr></div><h2>Internal / Code Quality</h2><ul><li><p><code>soci_wrappers.h</code> saw a significant cleanup &#8212; redundant nesting in the field-binding logic was flattened, making the type-dispatch code considerably easier to follow.</p></li><li><p>SSE event queuing now uses <code>emplace</code> instead of <code>push</code> for slightly cleaner construction.</p></li><li><p>SQL update column formatting moved to <code>std::format</code> for consistency.</p></li></ul><div><hr></div><h2>Upgrading</h2><p>Update your environment variables from <code>MANTIS_JWT_SECRET</code> &#8594; <code>MB_JWT_SECRET</code> and pull the new image or rebuild from source. No schema migrations are required for this release.</p><p>The full changelog and binaries are available on the <a href="https://github.com/allankoechke/mantisbase/releases/tag/v0.3.4">GitHub releases page</a>.</p>]]></content:encoded></item><item><title><![CDATA[MantisBase Devlog #1—We're Live]]></title><description><![CDATA[If you've been following along, you know I've been busy building MantisBase for a while now.]]></description><link>https://www.codeart.co.ke/p/mb-devlog1-landing-page</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mb-devlog1-landing-page</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Thu, 26 Feb 2026 20:24:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7abe0891-406b-4d16-acb6-41a56d758e80_1920x1080.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5BRd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5BRd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5BRd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5BRd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5BRd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5BRd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5BRd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5BRd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5BRd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5BRd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3c2d4df6-27c7-4e50-a1fd-dac9655aac48_1920x1080.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>If you've been following along, you know I've been busy building <a href="https://github.com/allankoech/mantisbase">MantisBase</a> for a while now. Today feels like a good checkpoint to step back, write a bit, and share what's shipped.</p><p>This is the first official devlog. There will be more.</p><div><hr></div><h2>The Project Website is Up</h2><p>First things first, MantisBase now has a proper home on the internet.</p><blockquote><h4><a href="https://mantisbase.com">MantisBase | Lightning fast BaaS in C++</a></h4></blockquote><p>It's a landing page for now, but it does the job &#8212; gives you a quick feel for what MantisBase is and where it's headed. If you've been curious but haven't dug into the GitHub repo yet, the website is probably the gentler starting point.</p><div><hr></div><h2>Try It Without Installing Anything</h2><p>This one I'm particularly happy about.</p><p>One of the biggest friction points with any self-hosted tool is the "I'll check it out later" trap; you bookmark it, tell yourself you'll spin it up over the weekend, and then never do. I've been guilty of this myself more times than I'd like to admit.</p><p>So we now have a live demo environment:</p><blockquote><h4><a href="https://demo.mantisbase.com">Mantis Admin Dashboard</a></h4></blockquote><p>No installation. No Docker. No config files. Just open it and poke around. If it clicks for you, <em>then</em> you can go down the setup rabbit hole.</p><div><hr></div><h2>Docker Image on Docker Hub</h2><p>Speaking of setup&#8212;for those who are comfortable with Docker and just want to pull and run, we've got you covered.</p><pre><code>docker pull allankoech/mantisbase
</code></pre><p>Full image available at:</p><blockquote><h4><a href="https://hub.docker.com/r/allankoech/mantisbase">allankoech/mantisbase - Docker Image</a></h4></blockquote><p>This is probably the fastest path from zero to a running instance if you're on a server or just want to keep things clean on your local machine.</p><div><hr></div><h2>What's Next</h2><p>We're currently in the middle of cleaning up the admin UI &#8212; ironing out some rough edges and squashing a few bugs that have been on the list. Nothing dramatic, just the kind of polish work that makes the difference between something that <em>works</em> and something that feels <em>solid</em>.</p><p>More updates soon. If you want to follow along, the <a href="https://github.com/allankoech/mantisbase">GitHub repo</a> is the most up-to-date place to track progress.</p><p>Until the next devlog. &#9996;&#65039;</p>]]></content:encoded></item><item><title><![CDATA[MantisBase v0.3.3: Real-Time Database Updates with Server-Sent Events]]></title><description><![CDATA[February 4, 2026 &#8212; We're excited to announce the release of MantisBase v0.3.3, bringing real-time database capabilities to this lightweight, high-performance Backend-as-a-Service framework.]]></description><link>https://www.codeart.co.ke/p/mantisbase-v0_3_3-rtdb</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mantisbase-v0_3_3-rtdb</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Tue, 03 Feb 2026 22:04:45 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/81d7baa2-da37-44c7-b207-6efa851b3ba1_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jJqT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jJqT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!jJqT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!jJqT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!jJqT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jJqT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jJqT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!jJqT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!jJqT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!jJqT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd4458d63-b839-4549-89ce-f6b1618f0c96_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">MantisBase version 0.3.3 release banner featuring real-time database updates with Server-Sent Events support</figcaption></figure></div><p><strong>February 4, 2026</strong> &#8212; We're excited to announce the release of MantisBase v0.3.3, bringing real-time database capabilities to this lightweight, high-performance Backend-as-a-Service framework. This release introduces Server-Sent Events (SSE) support for both SQLite and PostgreSQL backends, along with critical bug fixes and improved system observability.</p><h2>What's New in v0.3.3</h2><h3>Real-Time Database via SSE</h3><p>The flagship feature of <em>v0.3.3</em> is native real-time database synchronisation using Server-Sent Events. Unlike traditional polling approaches that waste resources checking for updates, SSE establishes a persistent HTTP connection that allows the server to push changes to clients as they happen.</p><p><strong>Why SSE?</strong></p><p>Server-Sent Events offer several advantages for real-time database applications:</p><ul><li><p><strong>Efficient unidirectional streaming</strong> &#8212; Perfect for database change notifications where data flows primarily from server to client</p></li><li><p><strong>Built on standard HTTP</strong> &#8212; No special protocols or WebSocket infrastructure required</p></li><li><p><strong>Automatic reconnection</strong> &#8212; The browser's EventSource API handles connection recovery automatically</p></li><li><p><strong>Firewall-friendly</strong> &#8212; Works through corporate proxies and firewalls that might block WebSocket connections</p></li><li><p><strong>Low overhead</strong> &#8212; Simpler than WebSockets when you don't need bidirectional communication</p></li></ul><h3>Universal Backend Support</h3><p>Real-time updates now work seamlessly with both SQLite and PostgreSQL databases. Whether you're running MantisBase on an embedded device with SQLite or scaling up with PostgreSQL, you get the same real-time capabilities without changing your code.</p><h3>Enhanced System Observability</h3><p>System logs have been moved to a dedicated database and are now accessible through the <code>/api/v1/logs</code> endpoint, providing administrators with powerful filtering and pagination capabilities for monitoring and debugging.</p><h2>Getting Started with Real-Time</h2><h3>Opening an SSE Connection</h3><p>Connect to the real-time endpoint and subscribe to entity changes:</p><pre><code>// Subscribe to changes on the 'posts' entity
const eventSource = new EventSource(
  'http://localhost:7070/api/v1/realtime?topics=posts'
);

// Listen for all events
eventSource.onmessage = (event) =&gt; {
  const data = JSON.parse(event.data);
  console.log('Received event:', data);
};

// Handle connection events
eventSource.onopen = () =&gt; {
  console.log('SSE connection established');
};

eventSource.onerror = (error) =&gt; {
  console.error('SSE connection error:', error);
  // Browser automatically reconnects
};
</code></pre><h3>Subscribing to Multiple Entities</h3><p>You can monitor multiple database entities on a single connection:</p><pre><code>// Subscribe to posts, comments, and users
const eventSource = new EventSource(
  'http://localhost:7070/api/v1/realtime?topics=posts,comments,users'
);

eventSource.onmessage = (event) =&gt; {
  const data = JSON.parse(event.data);
  
  // Events include the entity name they originated from
  switch(data.entity) {
    case 'posts':
      updatePostsUI(data);
      break;
    case 'comments':
      updateCommentsUI(data);
      break;
    case 'users':
      updateUsersUI(data);
      break;
  }
};
</code></pre><h3>Event Format</h3><p>Real-time events follow a consistent JSON structure:</p><pre><code>{
  "type": "INSERT",
  "entity": "posts",
  "data": {
    "id": "abc123",
    "title": "New Post Title",
    "content": "Post content here",
    "created": "2026-02-03T14:30:00Z",
    "updated": "2026-02-03T14:30:00Z"
  },
  "timestamp": "2026-02-03T14:30:00.123Z"
}
</code></pre><p><strong>Event Types:</strong></p><ul><li><p><code>INSERT</code> &#8212; New record created</p></li><li><p><code>UPDATE</code> &#8212; Existing record modified</p></li><li><p><code>DELETE</code> &#8212; Record removed</p></li></ul><h3>Dynamic Topic Management</h3><p>Update your subscriptions without reconnecting:</p><pre><code>// Later, add more topics to the existing connection
async function subscribeToComments() {
  await fetch('http://localhost:7070/api/v1/realtime', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${yourAuthToken}`
    },
    body: JSON.stringify({
      client_id: clientId,
      topics: ['posts', 'comments']  // Updated topic list
    })
  });
}

// Or clear all subscriptions
async function unsubscribeAll() {
  await fetch('http://localhost:7070/api/v1/realtime', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${yourAuthToken}`
    },
    body: JSON.stringify({
      client_id: clientId,
      topics: []  // Empty array clears all topics
    })
  });
}
</code></pre><h2>System Logs API</h2><p>Access and monitor system logs with the new logs endpoint:</p><pre><code># Get recent logs (requires admin authentication)
curl -H "Authorization: Bearer &lt;admin_token&gt;" \
  http://localhost:7070/api/v1/logs

# Filter by log level
curl -H "Authorization: Bearer &lt;admin_token&gt;" \
  "http://localhost:7070/api/v1/logs?level=ERROR"

# Pagination
curl -H "Authorization: Bearer &lt;admin_token&gt;" \
  "http://localhost:7070/api/v1/logs?limit=50&amp;offset=100"

# Filter by time range
curl -H "Authorization: Bearer &lt;admin_token&gt;" \
  "http://localhost:7070/api/v1/logs?from=2026-02-03T00:00:00Z&amp;to=2026-02-03T23:59:59Z"
</code></pre><h2>Migration Guide</h2><p>If you're upgrading from <em>v0.3.2</em>, here's what you need to know:</p><h3>Breaking Changes</h3><p>There are no breaking changes in <em>v0.3.3</em>. The real-time API is a new addition that doesn't affect existing functionality. To enrol existing entities to be real-time "enabled", update the entities to trigger the real-time monitoring.</p><h3>Security Considerations</h3><h3>Authentication for Real-Time</h3><p>Real-time connections respect MantisBase's access control rules:</p><ul><li><p>For public topics (entities), no additional authentication is required.</p></li><li><p>For non-public entities, the following rules are enforced:</p><ul><li><p><em>List Rule</em>: Used to list records in an entity.</p></li><li><p><em>Get Rule</em>: Used to fetch a record by the record ID.</p></li></ul></li></ul><p>For non-public entities, provide the authorisation <strong>JWT</strong> token when creating the <code>EventSource</code> stream.</p><h2>Installation &amp; Upgrade</h2><h3>Download Pre-built Binaries</h3><p>Download the latest release from <a href="https://github.com/allankoechke/mantisbase/releases/tag/v0.3.3">GitHub Releases</a>:</p><pre><code># Linux
wget https://github.com/allankoechke/mantisbase/releases/download/v0.3.3/mantisbase-linux-x64.zip
unzip mantisbase-linux-x64.zip
chmod +x mantisbase
./mantisbase serve

# Windows
# Download mantisbase-windows-x64.zip and extract
mantisbase.exe serve
</code></pre><h3>Build from Source</h3><pre><code>git clone --recurse-submodules https://github.com/allankoechke/mantisbase.git
cd mantisbase
git checkout v0.3.3
cmake -B build
cmake --build build
./build/mantisbase serve
</code></pre><h3>Bug Fixes</h3><p>This release includes several important bug fixes:</p><ul><li><p>Fixed memory leak in SSE connection handling</p></li><li><p>Improved database connection pooling for PostgreSQL</p></li><li><p>Resolved race condition in concurrent entity updates</p></li><li><p>Fixed authentication token refresh timing</p></li><li><p>Corrected <em><strong>CORS</strong></em> headers for cross-origin real-time connections</p></li></ul><h2>Community &amp; Support</h2><p>Join our growing community:</p><ul><li><p><strong>GitHub</strong>: <a href="https://github.com/allankoechke/mantisbase">github.com/allankoechke/mantisbase</a></p></li><li><p><strong>Documentation</strong>: <a href="https://allankoechke.github.io/mantisbase/">allankoechke.github.io/mantisbase</a></p></li><li><p><strong>YouTube Tutorials</strong>: <a href="https://youtube.com/playlist?list=PLsG0sKNmNpyQwsZuReuqo_nl_j4SdJoiJ">MantisBase Playlist</a></p></li><li><p><strong>Discussions</strong>: <a href="https://github.com/allankoechke/mantisbase/discussions">GitHub Discussions</a></p></li><li><p><strong>Support</strong>: <a href="https://patreon.com/allankoech">Patreon</a></p></li></ul><h2>Acknowledgments</h2><p>Thank you to everyone who contributed to this release through bug reports, feature requests, and code contributions. MantisBase is built for developers, by developers.</p><div><hr></div><p>Checkout the video announcement here:</p><div class="captioned-image-container"><figure><div id="youtube2-M6pJJEILPv0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;M6pJJEILPv0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/M6pJJEILPv0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div></figure></div><div><hr></div><p><strong>MantisBase</strong>&#8212;Lightning-fast BaaS in C++. One binary, full backend, anywhere.</p><p><em>For the full changelog, see <a href="https://github.com/allankoechke/mantisbase/compare/v0.3.2...v0.3.3">v0.3.2...v0.3.3</a></em></p>]]></content:encoded></item><item><title><![CDATA[Smart Living & Leadership: Designing for Tomorrow]]></title><description><![CDATA[The second edition of the Smart Living & Tech Leadership Conference 2025 ran for two days, with intense, future-focused dialogue.]]></description><link>https://www.codeart.co.ke/p/smart-living-leadership-conf-2025</link><guid isPermaLink="false">https://www.codeart.co.ke/p/smart-living-leadership-conf-2025</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Thu, 13 Nov 2025 15:00:05 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3d86c76b-0cf0-4fdd-a220-7aa3349b4dbb_1080x625.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D5rc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D5rc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 424w, https://substackcdn.com/image/fetch/$s_!D5rc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 848w, https://substackcdn.com/image/fetch/$s_!D5rc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!D5rc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D5rc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D5rc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 424w, https://substackcdn.com/image/fetch/$s_!D5rc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 848w, https://substackcdn.com/image/fetch/$s_!D5rc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!D5rc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe84854ba-d768-4690-bcb7-ca758666597b_1080x625.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Smart Living &amp; Tech Leadership Conference Banner</figcaption></figure></div><p>The second edition of the <strong>Smart Living &amp; Tech Leadership Conference 2025</strong> ran for two days, with intense, future-focused dialogue. Day one set the foundation &#8212; sustainability, leadership, and the evolving role of cities in shaping human experience. Talks centred on energy management, mobility systems, and the ethics of digital transformation.</p><p>Day two shifted toward <strong>design, technology, and AI</strong>, unpacking how digital tools turn ideas into smarter, more liveable environments.</p><h3>The Core Idea</h3><p>Smart living isn&#8217;t about gadgets. It&#8217;s about intentional design. Every decision &#8212; spatial, structural, or digital &#8212; shapes how we live, move, and connect. Design is the link between people, data, and sustainability.</p><blockquote><p>&#128488;&#65039; "Design is not just what it looks like and feels like. Design is how it works."<br>&#8212; Steve Jobs</p></blockquote><p>Steve Jobs was a visionary who foretold of what it became of today, a fusion of design and functionality. A move toward designing for use rather than designing for aesthetics alone.</p><h3>My Session: Smart Living by Design</h3><p>I presented <strong>&#8220;Smart Living by Design: Evolving from Digital Tools to AI Decisions.&#8221; </strong>The session traced design&#8217;s evolution&#8212;from manual drafting to data-driven modelling and now to intelligent, AI-augmented systems.</p><ul><li><p>Digital tools like <strong>Revit</strong>, <strong>Inventor</strong>, <strong>3ds Max</strong>, and <strong>Maya</strong> redefined collaboration and precision.</p></li><li><p><strong>AI</strong> now extends creativity &#8212; generating forms, predicting outcomes, and guiding sustainable choices.</p></li><li><p>Projects like <strong>Bernini</strong> show how AI-driven 3D generation can reduce waste and optimise performance.</p></li><li><p><strong>Digital twins</strong> enable continuous feedback loops between the real and virtual worlds, making smart cities adaptive by design.</p></li></ul><p>The key takeaway: AI doesn&#8217;t replace creativity &#8212; it amplifies it. The future designer leads with intent, while AI accelerates exploration and insight.</p><h3>Conversations That Followed</h3><p>Post-session discussions were rich. People wanted to know how data models support interoperability across industries and where the limits of AI automation should be drawn. Others shared case studies on generative layouts for housing, mobility planning, and carbon analysis.</p><p>Outside the panels, the networking felt natural. Designers, engineers, urban planners, and educators connected over one shared vision &#8212; building systems that think with us, not for us.</p><h3>Closing Thought</h3><p>The conference reinforced a simple truth: <strong>design is leadership</strong>. Tools evolve, but human intention drives change. If we design with purpose &#8212; aligning creativity, technology, and sustainability &#8212; smart living becomes not an idea, but a lived reality.</p><p>Join the conversation!</p><div class="captioned-image-container"><figure><blockquote><p><a href="https://twitter.com/hashtag/Design?src=hash&amp;ref_src=twsrc%5Etfw">#Design</a> isn&#8217;t only about how it looks &#8212; it&#8217;s how it works.<br><br>At the Smart Living Conf, we explored how <a href="https://twitter.com/hashtag/AI?src=hash&amp;ref_src=twsrc%5Etfw">#AI</a> is becoming a design partner. From <a href="https://twitter.com/hashtag/AEC?src=hash&amp;ref_src=twsrc%5Etfw">#AEC</a> to <a href="https://twitter.com/hashtag/MFG?src=hash&amp;ref_src=twsrc%5Etfw">#MFG</a> and M&amp;E, AI helps us move ideas to reality; optimizing layouts, improving precision, and driving sustainable innovation. <a href="https://t.co/LO5NcE2wfk">pic.twitter.com/LO5NcE2wfk</a></p><p>&#8212; Allan K. Koech, HSC (@allankoechke) <a href="https://twitter.com/allankoechke/status/1986534803051839939?ref_src=twsrc%5Etfw">November 6, 2025</a></p></blockquote></figure></div>]]></content:encoded></item><item><title><![CDATA[Embedding Slint UI Within a Qt Application (C++)]]></title><description><![CDATA[Qt is a mature and feature-rich framework, but building flexible and declarative UIs often requires more than widgets and signals.]]></description><link>https://www.codeart.co.ke/p/embedding-slintui-within-qt-app</link><guid isPermaLink="false">https://www.codeart.co.ke/p/embedding-slintui-within-qt-app</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Fri, 10 Oct 2025 18:51:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/fcbee22c-75c9-480a-a922-17b94b718d65_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6Fuj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6Fuj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!6Fuj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!6Fuj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!6Fuj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6Fuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6Fuj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!6Fuj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!6Fuj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!6Fuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18dc66be-94f2-4241-9eae-3f553cca4aad_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Embedding Slint UI in Qt Banner</figcaption></figure></div><p>Qt is a mature and feature-rich framework, but building flexible and declarative UIs often requires more than widgets and signals. That&#8217;s where Slint fits in. It provides a compact, declarative syntax for building modern UIs while staying native and lightweight.</p><p>Some Qt-based projects, like <em>LibrePCB</em>, already use Slint to modernise their UI without abandoning their existing Qt foundation. Check the full blog details <a href="https://librepcb.org/blog/2025-09-12_preview_of_next_gen_ui/">here</a>. Embedding Slint lets you:</p><ul><li><p>Keep your Qt app logic and backend code intact.</p></li><li><p>Use Slint for fast, declarative, and maintainable UI layers.</p></li><li><p>Mix and match Slint views with traditional Qt widgets.</p></li><li><p>Gradually migrate UI parts without a full rewrite.</p></li></ul><div><hr></div><p>Watch the walkthrough video here:</p><p>Slint UI 102: Embedding Slint UI Within a Qt Application | C++</p><div class="captioned-image-container"><figure><div id="youtube2-0ZPPeeCJA_k" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;0ZPPeeCJA_k&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/0ZPPeeCJA_k?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div></figure></div><div><hr></div><h2>What you&#8217;ll learn:</h2><ul><li><p>How to embed Slint UI components in a Qt app</p></li><li><p>How to compile <code>.slint</code> files to native C++</p></li><li><p>How to synchronise data between Qt and Slint</p></li><li><p>How to manage event flow and cleanup</p></li></ul><h2>Resources:</h2><ul><li><p>Slint Documentation: <a href="https://slint.dev/docs">https://slint.dev/docs</a></p></li><li><p>Slint Source Code: <a href="https://github.com/slint-ui/slint">https://github.com/slint-ui/slint</a></p></li><li><p>Slint C++ Template: <a href="https://github.com/slint-ui/slint-cpp-template">https://github.com/slint-ui/slint-cpp-template</a></p></li><li><p>Full Source Code from this video: <a href="https://github.com/allankoechke/qt-slint-integration-cpp">https://github.com/allankoechke/qt-slint-integration-cpp</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[[Youtube] What is Mantis?]]></title><description><![CDATA[We have earlier introduced Mantis, a C++ BaaS toolkit, designed to be lightweight but powerful.]]></description><link>https://www.codeart.co.ke/p/youtube-what-is-mantis</link><guid isPermaLink="false">https://www.codeart.co.ke/p/youtube-what-is-mantis</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Tue, 30 Sep 2025 22:50:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6be29692-7d84-4619-a95b-46710976b0e9_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t6Qf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t6Qf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!t6Qf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!t6Qf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!t6Qf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t6Qf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!t6Qf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 424w, https://substackcdn.com/image/fetch/$s_!t6Qf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 848w, https://substackcdn.com/image/fetch/$s_!t6Qf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 1272w, https://substackcdn.com/image/fetch/$s_!t6Qf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d99134f-8535-4e75-ba9c-29d02ed41ab1_1920x1080.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">What is Mantis?</figcaption></figure></div><p>We have earlier introduced Mantis, a C++ BaaS toolkit, designed to be lightweight but powerful.</p><blockquote><h4><a href="https://codeart.co.ke/introducing-mantis-the-lightweight-baas-in-cpp/">Introducing Mantis: The C++ Backend Framework Built for Simplicity and Speed</a></h4></blockquote><h1>What's changed?</h1><p>From our last v0.2.7 release a couple of weeks ago, we have some important fixes and improvements added to our v0.2.8 release. Have a look:</p><ul><li><p><em><strong>PostgreSQL Support</strong></em>: v0.2.8 brings full PostgreSQL support for Linux builds. This allows for easy backend database switch when scaling is required while maintaining lightweight backend database (SQLite) where it's needed. How do you switch the database? Easy!</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A9jM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A9jM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 424w, https://substackcdn.com/image/fetch/$s_!A9jM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 848w, https://substackcdn.com/image/fetch/$s_!A9jM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 1272w, https://substackcdn.com/image/fetch/$s_!A9jM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A9jM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png" width="879" height="73" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:73,&quot;width&quot;:879,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!A9jM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 424w, https://substackcdn.com/image/fetch/$s_!A9jM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 848w, https://substackcdn.com/image/fetch/$s_!A9jM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 1272w, https://substackcdn.com/image/fetch/$s_!A9jM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3cef2756-b0c2-47b9-bd2e-6e5b2c5c149d_879x73.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption">Connecting to PostgreSQL database</figcaption></figure></div><ul><li><p><em><strong>Minor bug fixes &amp; improvements</strong></em>: Lots of bugs were squashed, solving some performance issues as well as mending some issues that existed. Chief among these is matching data types compatibility for SQLite to/from PostgreSQL, forcing SQLite WAL mode checkpointing for every boot and refactoring project for performance improvements.</p></li></ul><div><hr></div><blockquote><h4><a href="https://github.com/allankoechke/mantis/releases/tag/v0.2.8">Release Release v0.2.8 &#183; allankoechke/mantis</a></h4></blockquote><div><hr></div><h1>Getting Started?</h1><p>We have a YouTube video to guide you out; don't fret. Checkout the video below for a walkthrough of the features mantis provides. If you have any question, lets discuss on YouTube or open a GitHub issue.</p><div class="captioned-image-container"><figure><div id="youtube2-5SdmabDqeqY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;5SdmabDqeqY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/5SdmabDqeqY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div></figure></div><div><hr></div><p>Enjoy!</p>]]></content:encoded></item><item><title><![CDATA[Mantis v0.2.7-beta Release]]></title><description><![CDATA[We&#8217;ve shipped Mantis v0.2.7-beta, a new milestone for our lightweight pluggable backend-as-a-service (BaaS) framework written in C++.]]></description><link>https://www.codeart.co.ke/p/mantis-v0-2-7-beta-release</link><guid isPermaLink="false">https://www.codeart.co.ke/p/mantis-v0-2-7-beta-release</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Sat, 23 Aug 2025 19:20:15 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/62b794e9-a40e-4476-8417-ce777a485ad7_1500x752.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nf6E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nf6E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 424w, https://substackcdn.com/image/fetch/$s_!nf6E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 848w, https://substackcdn.com/image/fetch/$s_!nf6E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 1272w, https://substackcdn.com/image/fetch/$s_!nf6E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nf6E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nf6E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 424w, https://substackcdn.com/image/fetch/$s_!nf6E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 848w, https://substackcdn.com/image/fetch/$s_!nf6E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 1272w, https://substackcdn.com/image/fetch/$s_!nf6E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffcbe2adf-076e-4cd4-ad9b-1fa4f757d175_1500x752.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Mantis v0.2.7 release banner</figcaption></figure></div><p>We&#8217;ve shipped <strong>Mantis v0.2.7-beta</strong>, a new milestone for our lightweight pluggable backend-as-a-service (BaaS) framework written in C++. This release focuses on making file management a first-class feature while continuing to strengthen stability and prepare for broader database support.</p><h2>Highlights</h2><h3>File and Files Field Support</h3><ul><li><p>Records now support <code>file</code> and <code>files</code> fields.</p></li><li><p>Upload, update, and remove files directly through record operations.</p></li><li><p>Safer filename handling with sanitization for long names and unknown characters.</p></li></ul><p>For more information on how to handle files in Mantis, check out the docs below:</p><blockquote><h4><a href="https://github.com/allankoechke/mantis/blob/master/doc/11.files.md">mantis/doc/11.files.md at master &#183; allankoechke/mantis</a></h4></blockquote><h3>Health check Endpoint</h3><ul><li><p>Added a <code>/api/v1/health</code> endpoint to make it easier to monitor and integrate Mantis into production setups.</p></li></ul><h3>Mantis Admin v0.1.7</h3><ul><li><p>Updated to the latest version of the Mantis Admin dashboard with file management capabilities.</p></li><li><p>Improved performance in the admin panel when working with larger datasets.</p></li></ul><h3>Bug Fixes and Improvements</h3><ul><li><p>Better handling of database value binding with <code>soci::values</code>.</p></li><li><p>Performance optimization for table ID generation.</p></li><li><p>More consistent cleanup of file references for updates and removals.</p></li></ul><h3>PostgreSQL Support (WIP)</h3><ul><li><p>Early integration of PostgreSQL via SOCI.</p></li><li><p>Initial support for builds, CLI commands, and CI/CD integration.</p></li><li><p>Still marked experimental but progressing quickly.</p></li></ul><blockquote><p>&#9888;&#65039; PostgreSQL support is experimental and currently only built for Linux. The feature still has unresolved issues and may fail to launch entirely.</p></blockquote><h2>Why It Matters</h2><p>Mantis is designed as an alternative to Firebase, Supabase, or PocketBase, but lighter, portable, and embeddable directly into your C++ applications. By keeping the runtime minimal and the architecture pluggable, we aim to make backend services faster to integrate and easier to run anywhere.</p><h2>What&#8217;s Next?</h2><ul><li><p>Complete PostgreSQL support for production use.</p></li><li><p>Expanded file access controls.</p></li><li><p>More integrations for different deployment targets.</p></li></ul><h2>Get Started</h2><p>GitHub Repo: <a href="https://github.com/allankoechke/mantis">https://github.com/allankoechke/mantis</a><br>Release Page: <a href="https://github.com/allankoechke/mantis/releases/tag/v0.2.7-beta">https://github.com/allankoechke/mantis/releases/tag/v0.2.7-beta</a><br>Documentation: <a href="https://docs.mantisapp.dev/">https://docs.mantisapp.dev/</a>.</p><div><hr></div><p>Feedback is welcome. If you try out the new file support or start testing PostgreSQL integration, please let us know how it works for you.</p>]]></content:encoded></item><item><title><![CDATA[Introducing Mantis: The C++ Backend Framework Built for Simplicity and Speed]]></title><description><![CDATA[In a world dominated by heavyweight frameworks and bloated deployment pipelines, Mantis stands out as a fast, modular C++ backend library designed for simplicity, speed, and embeddability.]]></description><link>https://www.codeart.co.ke/p/introducing-mantis-the-lightweight-baas-in-cpp</link><guid isPermaLink="false">https://www.codeart.co.ke/p/introducing-mantis-the-lightweight-baas-in-cpp</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Wed, 09 Jul 2025 21:11:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b30d0675-b9a3-44f9-b165-a92f462342a8_1187x594.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vmMv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vmMv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 424w, https://substackcdn.com/image/fetch/$s_!vmMv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 848w, https://substackcdn.com/image/fetch/$s_!vmMv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 1272w, https://substackcdn.com/image/fetch/$s_!vmMv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vmMv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vmMv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 424w, https://substackcdn.com/image/fetch/$s_!vmMv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 848w, https://substackcdn.com/image/fetch/$s_!vmMv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 1272w, https://substackcdn.com/image/fetch/$s_!vmMv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe1edc2d4-dd7c-4cb0-93af-b8bd87b173c1_1187x594.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Introducing Mantis</figcaption></figure></div><p>In a world dominated by heavyweight frameworks and bloated deployment pipelines, <strong>Mantis</strong> stands out as a fast, modular C++ backend library designed for simplicity, speed, and embeddability. Whether you're building for the cloud, desktop, or embedded systems, Mantis gives you modern backend capabilities with zero friction.</p><h2>What Makes Mantis Special?</h2><h3>&#128640; Single Binary Deployment</h3><p>No containers, no dependencies, no problem. Mantis compiles to a single <code>mantisapp</code> binary that runs anywhere&#8212;just:</p><pre><code>./mantisapp serve -p 8000
</code></pre><p>It&#8217;s ideal for embedded devices, desktop applications, or servers where simplicity is paramount.</p><h3>Zero-Configuration REST APIs</h3><p>Define your tables&#8212;and that&#8217;s it. Mantis auto-generates RESTful CRUD endpoints, complete with JWT-based authentication and fine-grained access control.</p><h3>&#129504; Minimal Runtime Footprint</h3><p>With SQLite as the default database and tight memory usage, Mantis is engineered for environments where every byte counts.</p><div><hr></div><h2>Key Benefits That Set Mantis Apart</h2><h3>&#128295; Embeddable by Design</h3><p>Unlike traditional backends that require external deployment, Mantis can be embedded directly into your C++ application. Add backend functionality to Qt apps, CLI tools, or microservices&#8212;all from within your codebase.</p><h3>&#128272; Built-in Authentication &amp; Security</h3><p>Mantis handles token generation, validation, and route-level access control using JWT. You get secure, configurable auth out-of-the-box.</p><h3>&#128202; Lightweight Admin Dashboard</h3><p>Each Mantis deployment includes a built-in admin dashboard for managing tables, records, and users&#8212;no separate tooling or setup required.</p><h3>&#128051; Docker-Ready</h3><p>Mantis offers a Docker image with volume mounting support, ideal for containerized environments and CI/CD pipelines.</p><div><hr></div><h2>&#128736; Technology Stack</h2><p>Mantis integrates robust C++ libraries to deliver production-grade performance:</p><ul><li><p><strong>HTTP Server</strong>: <a href="https://github.com/yhirose/cpp-httplib"><code>httplib-cpp</code></a> for lightweight HTTP(S) handling</p></li><li><p><strong>Database</strong>: <a href="https://github.com/SOCI/soci"><code>SOCI</code></a> as an abstraction layer (SQLite by default; MySQL/PostgreSQL coming soon)</p></li><li><p><strong>Authentication</strong>: <a href="https://github.com/GlitchedPolygons/l8w8jwt"><code>l8w8jwt</code></a> for secure token management</p></li><li><p><strong>Logging</strong>: <a href="https://github.com/gabime/spdlog"><code>spdlog</code></a> for structured, high-performance logging</p></li></ul><div><hr></div><h2>&#128679; Future Vision: What&#8217;s Coming</h2><p>Mantis isn&#8217;t just stable&#8212;it&#8217;s growing. Here&#8217;s what&#8217;s on the horizon:</p><ul><li><p><strong>Real-Time Sync Engine</strong><br>WebSocket-powered data sync between clients and the backend&#8212;perfect for offline-first and collaborative apps.</p></li><li><p><strong>Full RDBMS Support</strong><br>Extend Mantis from SQLite to full support for MySQL and PostgreSQL with seamless migration tooling.</p></li><li><p><strong>Pluggable Middleware Architecture</strong><br>Customize request handling with user-defined middleware for logging, validation, authentication, or anything else.</p></li></ul><div><hr></div><h2>Getting Started is Effortless</h2><p>You can start using Mantis today in one of two ways:</p><h3>Option 1: Use Prebuilt Binaries</h3><p>Available for <strong>Linux (x86_64)</strong> and <strong>Windows (x64)&#8212;</strong><em>just download and run</em>.</p><h3>Option 2: Build From Source</h3><p>If you're targeting another platform or want to embed Mantis into your own C++ application:</p><pre><code>git clone --recurse-submodules https://github.com/allankoechke/mantis.git
cd mantis
cmake -B build
cmake --build build
./build/mantisapp serve -p 5000
</code></pre><p>Access the dashboard at <a href="http://localhost:5000/admin">http://localhost:5000/admin</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hPTi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hPTi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 424w, https://substackcdn.com/image/fetch/$s_!hPTi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 848w, https://substackcdn.com/image/fetch/$s_!hPTi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 1272w, https://substackcdn.com/image/fetch/$s_!hPTi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hPTi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png" width="2000" height="1085" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1085,&quot;width&quot;:2000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!hPTi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 424w, https://substackcdn.com/image/fetch/$s_!hPTi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 848w, https://substackcdn.com/image/fetch/$s_!hPTi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 1272w, https://substackcdn.com/image/fetch/$s_!hPTi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbcd6579e-e4eb-471f-8eb8-269090d7dba9_3200x1736.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image buttonBase-GK1x3M"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon-noB79L"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image buttonBase-GK1x3M"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2 icon-noB79L"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Mantis Admin Dashboard (WIP)</figcaption></figure></div><p>&#128073; Read the full setup guide here:<br><strong><a href="https://allankoechke.github.io/mantis/setup.html">https://allankoechke.github.io/mantis/setup.html</a></strong></p><div><hr></div><h2>&#127775; Why Choose Mantis?</h2><p>In a space filled with over-engineered solutions, <strong>Mantis</strong> offers a refreshing alternative: modern backend functionality in a compact, embeddable C++ package. Whether you're targeting embedded devices, developer tools, or just want a backend that won&#8217;t get in your way&#8212;Mantis delivers.</p><div><hr></div><h3>Ready to Try It?</h3><p>Explore the <a href="https://github.com/allankoechke/mantis">GitHub repository</a>, download the binaries, and see what lightweight backend development really feels like.</p>]]></content:encoded></item><item><title><![CDATA[DeepWiki: How to Instantly Understand Any Codebase with AI-Powered Documentation]]></title><description><![CDATA[In the growing jungle of codebases, developer tools, and open-source libraries, one thing remains consistently frustrating: documentation.]]></description><link>https://www.codeart.co.ke/p/deepwiki-understand-any-codebase-with-ai</link><guid isPermaLink="false">https://www.codeart.co.ke/p/deepwiki-understand-any-codebase-with-ai</guid><dc:creator><![CDATA[Allan K. Koech]]></dc:creator><pubDate>Thu, 19 Jun 2025 15:00:47 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f5ffd3cf-9811-4bc5-8f2c-ba4172d55838_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-veB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-veB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!-veB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!-veB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!-veB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-veB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-veB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!-veB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!-veB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!-veB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7fde676-f6c8-4c01-a485-a23ef0c42a59_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Deepwiki: Chat with your codebase.</figcaption></figure></div><p>In the growing jungle of codebases, developer tools, and open-source libraries, one thing remains consistently frustrating: documentation. Whether they're too shallow, too outdated, or just missing altogether, bad docs slow everyone down. But what if you could talk to a codebase like you would a teammate? That&#8217;s where DeepWiki comes in.</p><blockquote><h4><a href="https://deepwiki.com/">DeepWiki | AI documentation you can talk to, for every repo</a></h4></blockquote><h3>What&#8217;s DeepWiki?</h3><p>It provides up-to-date documentation for any repo in the world that you can talk to. At first glance, you might consider it similar to your favorite LLM, but with the added context of a codebase.</p><blockquote><p>&#128161; A wiki is a form of hypertext publication on the internet which is collaboratively edited and managed by its audience directly through a web browser.&nbsp;A typical wiki contains multiple pages that can either be edited by the public or limited to use within an organization for maintaining its internal knowledge base.</p></blockquote><p>DeepWiki is powered by Devin AI, but over the past few months, there have been new open-source entrants to the space providing the same functionality.</p><h3>Where does it find its use?</h3><p>Consider this: the quality of documentation for repositories can range from excellent to inadequate. Imagine bumping into a repo with no docs, but it seems like a good fit for your needs. This scenario is where DeepWiki can help you create documentation for human understanding without needing to read through the entire codebase line by line.</p><p>You ask, it answers. From <em>"What does this function do?"</em> to <em>"How does authentication work in this repo?" </em>DeepWiki gives you direct, conversational insight based on the actual code, not assumptions.</p><p>It&#8217;s particularly useful when:</p><ul><li><p>You inherit a legacy code and need to quickly catch up.</p></li><li><p>You're actively participating in open-source projects and seeking to understand the internal workings.</p></li><li><p>You&#8217;re assessing a new library or tool and need to grasp its internals without reading 10 files.</p></li></ul><h3>But how does it work?</h3><p>Behind the scenes, DeepWiki syncs with the repository and builds an internal understanding of the code&#8212;structure, logic, and behavior. It doesn&#8217;t just summarize; it contextualizes. Ask a question, and it doesn&#8217;t respond based on generic training but refers to the actual code. That&#8217;s the difference.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!loHd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!loHd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 424w, https://substackcdn.com/image/fetch/$s_!loHd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 848w, https://substackcdn.com/image/fetch/$s_!loHd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 1272w, https://substackcdn.com/image/fetch/$s_!loHd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!loHd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png" width="200" height="103" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:103,&quot;width&quot;:200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!loHd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 424w, https://substackcdn.com/image/fetch/$s_!loHd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 848w, https://substackcdn.com/image/fetch/$s_!loHd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 1272w, https://substackcdn.com/image/fetch/$s_!loHd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5fbffe42-3154-426a-b93f-0da605b37298_1516x787.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>How do I get started?</h3><p>It's actually quite simple. On any GitHub repo you need to look into, replace the GitHub with the DeepWiki domain. For instance, for the SQLite repo above, replace <code>https://github.com/sqlite/sqlite</code> to <code>https://deepwiki.com/sqlite/sqlite</code>and there you'll be ready to chat with your repo.</p><blockquote><p>&#9888;&#65039; Note that not all repos are already indexed. For those that aren't, you'll have to request indexing and provide your email, and you'll be notified once indexing is completed. Usually in less than an hour or so.</p></blockquote><h3>Why it matters</h3><p>We&#8217;re entering a world where shipping fast isn't enough; you also need to <em>understand fast</em>. DeepWiki makes technical onboarding smoother, reduces context-switching, and adds clarity to chaos, especially in large or under-documented codebases.</p><p>Sure, it&#8217;s not a silver bullet. It won&#8217;t replace solid developer docs. But it&#8217;s a powerful fallback when the docs are missing, outdated, or nonexistent.</p><h3>Final thoughts</h3><p>In a way, DeepWiki brings back the original promise of AI in dev tooling&#8212;not to replace developers, but to augment them. It&#8217;s not just about code completion or chat-based assistance anymore; it&#8217;s about deep understanding. And in that space, DeepWiki has carved out something genuinely useful.</p><p>Whether you're delving deeply into a complex system or simply exploring a new library, DeepWiki is a valuable resource.</p><h3>FAQs</h3><blockquote><h4><strong>1. What is DeepWiki, and how does it work?</strong></h4><p>DeepWiki is an AI-powered tool by Devin AI that generates real-time, conversational documentation for any code repository. It analyzes the codebase and lets developers ask natural language questions to understand functionality, architecture, and workflows.</p></blockquote><blockquote><h4><strong>2. Can DeepWiki document private or internal repositories?</strong></h4><p>Yes, DeepWiki can be used with private repositories as long as you grant it access. It can then generate documentation and allow conversational querying based on your internal codebase.</p></blockquote><blockquote><h4><strong>3. How is DeepWiki different from ChatGPT or other AI coding assistants?</strong></h4><p>While general AI assistants like ChatGPT are trained on broad programming knowledge, DeepWiki is built to ingest and understand specific repositories, offering contextual, code-aware responses tailored to your exact codebase.</p></blockquote><blockquote><h4><strong>4. Is DeepWiki useful for teams and enterprise-level development?</strong></h4><p>Absolutely. DeepWiki can dramatically speed up developer onboarding, reduce time spent searching through code, and improve collaboration by acting as a living, interactive documentation layer for your projects.</p></blockquote><blockquote><h4><strong>5. Does DeepWiki replace traditional documentation?</strong></h4><p>No, but it complements it. While human-written documentation provides structure and intent, DeepWiki helps fill gaps, explain code in real time, and answer questions dynamically&#8212;especially when traditional docs are missing or outdated.</p></blockquote>]]></content:encoded></item></channel></rss>