<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Odyn Blog</title>
        <link>https://razkar.codeberg.page/odyn/blog</link>
        <description>Odyn Blog</description>
        <lastBuildDate>Sat, 04 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[When Your App Learns to Touch Itself]]></title>
            <link>https://razkar.codeberg.page/odyn/blog/when-self-modification</link>
            <guid>https://razkar.codeberg.page/odyn/blog/when-self-modification</guid>
            <pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[There is a moment, if you work on software long enough, where something clicks into place and feels genuinely strange. Not bad strange. More like the first time you realized a mirror is showing you a reversed version of your face and you spent a few seconds unable to look away.]]></description>
            <content:encoded><![CDATA[<p>There is a moment, if you work on software long enough, where something clicks into place and feels genuinely strange. Not bad strange. More like the first time you realized a mirror is showing you a reversed version of your face and you spent a few seconds unable to look away.</p>
<p>That moment, for a lot of developers, is the first time they watch their application do something to itself.</p>
<p>Not to a user's data. Not to an external service. To its own running body.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-git-fetch-moment">The git fetch Moment<a href="https://razkar.codeberg.page/odyn/blog/when-self-modification#the-git-fetch-moment" class="hash-link" aria-label="Direct link to The git fetch Moment" title="Direct link to The git fetch Moment" translate="no">​</a></h2>
<p>The most common version of this goes something like: you are setting up a deployment script, and you add a line where the service calls <code>git fetch</code> before starting. The application reaches out to the origin, compares its own current state against the remote, and decides whether to pull and restart. You run it. You watch the output. The SHA updates. The process restarts with a newer version of its own code.</p>
<p>You sit there for a second just staring at the terminal.</p>
<p>What you have just built is a system that asks, in functional terms, whether it is still current. Whether it is still the right version of itself. And then it acts on the answer.</p>
<p>That is a very different thing from reading a config file or querying a database. Those operations treat the world as external. This one turns inward.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="projectception-when-the-tool-clones-itself">Projectception: When the Tool Clones Itself<a href="https://razkar.codeberg.page/odyn/blog/when-self-modification#projectception-when-the-tool-clones-itself" class="hash-link" aria-label="Direct link to Projectception: When the Tool Clones Itself" title="Direct link to Projectception: When the Tool Clones Itself" translate="no">​</a></h2>
<p>And then there is the version of this that stops people cold the first time they realize it works.</p>
<p><code>git</code> is open source. Its source code lives in a repository, like any other project. Which means you can run:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">git clone https://github.com/git/git</span><br></span></code></pre></div></div>
<p>And <code>git</code> will go out, contact a remote server, download the source code for <code>git</code>, and store it on your machine. The tool is fetching the instructions for how to build itself. You used the thing to get the thing.</p>
<p>There is no trick here, no special case, nothing unusual about how it works technically. Git does not know or care that it is cloning its own source code. It just follows the same protocol it always does. But that is exactly what makes it feel so odd. The mundaneness of the mechanism does not cancel out the strangeness of what is happening. A hammer cannot be used to forge the steel that made it. A compiler, famously, can compile itself, and the first people who made that work were reportedly unsettled by it too.</p>
<p>This specific flavor of self-reference has a name in developer circles: <em>Projectception</em>. The project, within itself, contains instructions for rebuilding the project. Pull the thread long enough and you get something that loops back on itself in a way that is hard to look at directly.</p>
<p>My project, Odyn, the project this exact website is made for, is also no exception of Odynception. Odyn is open-source, on Codeberg. Which means even if Odyn is not an Odin library, you can still run:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">odyn get razkar/odyn --platform codeberg</span><br></span></code></pre></div></div>
<p>And it'll fetch Odyn's source code, put them to <code>odyn_deps/</code>, add an entry to <code>Odyn.lock</code>, and it'll work fine. You can even go into <code>odyn_deps/odyn/</code>, build Odyn from source inside, and do the same thing again. Over and over.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="self-modification-is-everywhere-once-you-notice-it">Self-Modification Is Everywhere, Once You Notice It<a href="https://razkar.codeberg.page/odyn/blog/when-self-modification#self-modification-is-everywhere-once-you-notice-it" class="hash-link" aria-label="Direct link to Self-Modification Is Everywhere, Once You Notice It" title="Direct link to Self-Modification Is Everywhere, Once You Notice It" translate="no">​</a></h2>
<p>Once you start paying attention, you see this pattern all over infrastructure. Watchtower watches your Docker containers and redeploys them when newer images appear in the registry. Kubernetes operators reconcile the state of a cluster, including the specs for their own pods. A GitHub Actions workflow that bumps a version number and commits it back to the same repository it is running from.</p>
<p>These are all examples of systems that take themselves as the subject of an operation, not just the executor of one.</p>
<p>The line between "a tool that does things" and "a thing that maintains itself" is thin, and crossing it feels different every time. There is something almost biological about it. A cell that can repair its own DNA. A script that can upgrade its own dependencies. You are not writing code anymore. You are writing behavior.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-it-feels-odd">Why It Feels Odd<a href="https://razkar.codeberg.page/odyn/blog/when-self-modification#why-it-feels-odd" class="hash-link" aria-label="Direct link to Why It Feels Odd" title="Direct link to Why It Feels Odd" translate="no">​</a></h2>
<p>Part of what makes this feeling hard to shake is that we are trained, as programmers, to think of a program as a static artifact. You write it, you compile it, you run it. The code is the author; the process is the execution. Those two things are supposed to stay separate.</p>
<p>Self-referential systems break that assumption. When a running process modifies its own source, updates its own config, or decides to restart itself with different arguments, the author and the execution are no longer cleanly separated. The process has become, in a small way, a participant in its own authorship.</p>
<p>Douglas Hofstadter spent a whole book on this idea. Strange loops, he called them. A system that, through a sequence of steps, ends up back at a level where it can reference itself. He was mostly writing about consciousness and Godel's incompleteness theorems, but the feeling transfers. When you watch a process that watches itself, your brain registers something similar to what it registers when you point a camera at a monitor showing the camera's feed. It recurses. It loops.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="practical-weirdness">Practical Weirdness<a href="https://razkar.codeberg.page/odyn/blog/when-self-modification#practical-weirdness" class="hash-link" aria-label="Direct link to Practical Weirdness" title="Direct link to Practical Weirdness" translate="no">​</a></h2>
<p>Beyond the philosophy, there are real engineering consequences to systems that act on themselves, and most of them are worth thinking about before you are staring at a production incident at 2am.</p>
<p>Self-modifying systems can get into states that are very hard to reason about. If a deployment script has a bug in the part that updates itself, you may end up with a broken updater that cannot update itself out of its own broken state. You have to reach in from outside, which is always a little humbling.</p>
<p>There is also the question of atomicity. When a process modifies its own config and then reads that config, you need to be careful about the ordering. The same concerns show up in database migrations that run as part of the application startup, another extremely common pattern, and one that bites people constantly.</p>
<p>And then there is the human factor. Automated self-updating systems are powerful, but they can also be alarming to work with, especially on a team where not everyone set them up. Someone wakes up to find the application is running a version from three hours ago because a scheduled job auto-reverted a failed deploy. That is correct behavior. It is also going to cause some confusion before the coffee kicks in.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-part-that-stays-with-you">The Part That Stays With You<a href="https://razkar.codeberg.page/odyn/blog/when-self-modification#the-part-that-stays-with-you" class="hash-link" aria-label="Direct link to The Part That Stays With You" title="Direct link to The Part That Stays With You" translate="no">​</a></h2>
<p>Despite all of that, there is something worth sitting with in the experience of watching a system manage itself. It represents a shift in how you think about software. A program that can only do what you explicitly command it to do in the moment is a tool. A program that observes its own state and responds to what it finds there is something closer to an agent.</p>
<p>Most production systems live somewhere on that spectrum. The further toward the "agent" end they move, the more interesting and the more unsettling they get to work with.</p>
<p>That first <code>git fetch</code> in a deployment script is, for a lot of developers, the first step in that direction. It is a small thing. Probably thirty seconds of work, tucked into a bash script somewhere. But you watch the output scroll by, and for just a moment, the app is not doing what you told it to do. It is doing what it determined it needed to do.</p>
<p>That is a different kind of software. And once you have written some of it, you start seeing the possibilities everywhere.</p>]]></content:encoded>
            <category>Command-Line Interface</category>
            <category>App</category>
            <category>Self-modification</category>
            <category>Projectception</category>
        </item>
        <item>
            <title><![CDATA[Context-Aware Outputs Are Cool, Actually]]></title>
            <link>https://razkar.codeberg.page/odyn/blog/context-aware-outputs</link>
            <guid>https://razkar.codeberg.page/odyn/blog/context-aware-outputs</guid>
            <pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A program that outputs something is cool. But you know something even cooler?]]></description>
            <content:encoded><![CDATA[<p>A program that outputs something is cool. But you know something even cooler?
A program that outputs something different based on the context. This trait is called <em>context-aware</em>,
and in this case, I like to call it a <em>"context-aware output"</em> for an output that has this trait.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-does-context-aware-mean">What Does "Context-Aware" Mean?<a href="https://razkar.codeberg.page/odyn/blog/context-aware-outputs#what-does-context-aware-mean" class="hash-link" aria-label="Direct link to What Does &quot;Context-Aware&quot; Mean?" title="Direct link to What Does &quot;Context-Aware&quot; Mean?" translate="no">​</a></h2>
<p>A context-aware output is one that adapts to <em>who</em> is running it and <em>how</em>.</p>
<p>The most common example you've probably already seen is color: a program that prints colored text when
you're in a terminal, but plain text when piped into a file. That's context-awareness, the program
knows it's being redirected and adjusts accordingly.</p>
<p>But context doesn't have to mean "is my output a TTY?" It can mean anything the program knows about
its environment: the OS, the architecture, how it was installed, whether it's a nightly build, etc. The
point is that the output becomes <em>meaningful to the specific person running it</em>.</p>
<p>Certain things are better context-aware, but not all of them should be if they slow things down. Too many context
awareness is also scary, and is leaning towards telemetry, a fancy word for surveillance, which is not cool.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="odyns---version-flag">Odyn's <code>--version</code> Flag<a href="https://razkar.codeberg.page/odyn/blog/context-aware-outputs#odyns---version-flag" class="hash-link" aria-label="Direct link to odyns---version-flag" title="Direct link to odyns---version-flag" translate="no">​</a></h2>
<p>Most CLI tools have a <code>--version</code> flag. Most of them output something like:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">mytool 1.2.3</span><br></span></code></pre></div></div>
<p>That's fine, it does what you expect it to do, which is outputting the version.
It's functional, but often forgettable.</p>
<p>But Odyn's <code>--version</code> does something a little different. Try it yourself, the output changes depending
on <em>how Odyn was installed</em>. Let me elaborate:</p>
<p><strong>From a release binary</strong> (the recommended install path):</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Odyn vX.X.X Linux x86_64</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Reproducible vendoring tool for the Odin programming language.</span><br></span></code></pre></div></div>
<p>The OS and architecture are shown in color, specific to <em>your</em> platform. Linux is yellow, Windows is
blue, macOS is gray, Android is green, FreeBSD is red, NetBSD is orange. You get a quick visual
confirmation that you have the right binary for your machine.</p>
<p><strong>From <code>cargo install odyn</code></strong>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Odyn vX.X.X Cargo Edition</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Reproducible vendoring tool for the Odin programming language.</span><br></span></code></pre></div></div>
<p>You know you're running the crates.io release, compiled for your local machine.</p>
<p><strong>Built from source</strong>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Odyn vX.X.X Nightly, commit a1b2c3d</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Reproducible vendoring tool for the Odin programming language.</span><br></span></code></pre></div></div>
<p>You get the short commit hash, handy when reporting bugs or checking if you're on the latest main.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How It Works<a href="https://razkar.codeberg.page/odyn/blog/context-aware-outputs#how-it-works" class="hash-link" aria-label="Direct link to How It Works" title="Direct link to How It Works" translate="no">​</a></h2>
<p>This is all handled at <strong>compile time</strong>, not at runtime. Odyn's <code>build.rs</code> sets an
<code>ODYN_INSTALL_METHOD</code> environment variable when the binary is compiled:</p>
<ul>
<li class="">If <code>ODYN_INSTALL_METHOD</code> is set in the environment (e.g. by the release CI), it's used as-is.</li>
<li class="">If a <code>.git</code> directory exists, it's assumed to be a source build, and <code>git rev-parse --short HEAD</code>
is called to capture the commit hash.</li>
<li class="">Otherwise, it falls back to <code>"cargo"</code>.</li>
</ul>
<p>The version command then reads this baked-in value with Rust's <code>env!()</code> macro, and branches on it.
In this case, there's no runtime overhead nor any detection logic. The binary just <em>knows</em> how it was born.</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">let</span><span class="token plain"> extra </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">match</span><span class="token plain"> </span><span class="token macro property">env!</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"ODYN_INSTALL_METHOD"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"cargo"</span><span class="token plain">   </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Cargo Edition"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">to_string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"source"</span><span class="token plain">  </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token macro property">format!</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"Nightly, commit {}"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token macro property">env!</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"ODYN_GIT_HASH"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"release"</span><span class="token plain"> </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token macro property">format!</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"{} {}"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:rgb(248, 248, 242)">::</span><span class="token namespace">env</span><span class="token namespace punctuation" style="color:rgb(248, 248, 242)">::</span><span class="token namespace">consts</span><span class="token namespace punctuation" style="color:rgb(248, 248, 242)">::</span><span class="token constant" style="color:rgb(189, 147, 249)">OS</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:rgb(248, 248, 242)">::</span><span class="token namespace">env</span><span class="token namespace punctuation" style="color:rgb(248, 248, 242)">::</span><span class="token namespace">consts</span><span class="token namespace punctuation" style="color:rgb(248, 248, 242)">::</span><span class="token constant" style="color:rgb(189, 147, 249)">ARCH</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    _         </span><span class="token operator">=&gt;</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">""</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">to_string</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></span></code></pre></div></div>
<p><em>(Simplified slightly for clarity.)</em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-bother">Why Bother?<a href="https://razkar.codeberg.page/odyn/blog/context-aware-outputs#why-bother" class="hash-link" aria-label="Direct link to Why Bother?" title="Direct link to Why Bother?" translate="no">​</a></h2>
<blockquote>
<p>Why do you really need a <code>--version</code> flag, of all features, to be context-aware in the first place?</p>
</blockquote>
<p>Because when something breaks and someone pastes their <code>--version</code> output into an issue, you
immediately know whether they're on a release binary for the right platform, or if they accidentally
compiled a source build from a week-old commit.</p>
<p>It's a small thing. But small things add up, and they're the difference between a tool that feels
polished and one that just works.</p>
<p>Context-aware outputs are cool. Now you know why.</p>]]></content:encoded>
            <category>Command-Line Interface</category>
            <category>Developer-Experience</category>
            <category>Context Aware</category>
            <category>App</category>
        </item>
        <item>
            <title><![CDATA[First Blog Post]]></title>
            <link>https://razkar.codeberg.page/odyn/blog/first-blog-post</link>
            <guid>https://razkar.codeberg.page/odyn/blog/first-blog-post</guid>
            <pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Hello, Odyn!]]></description>
            <content:encoded><![CDATA[<p>Hello, Odyn!</p>
<p>...hey.</p>]]></content:encoded>
            <category>Hola</category>
        </item>
    </channel>
</rss>