<?xml version="1.0" encoding="utf-8"?>
<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>Matrix AI Blog</title>
        <link>https://matrix.ai/learn/blog</link>
        <description>Matrix AI Blog</description>
        <lastBuildDate>Thu, 18 Sep 2025 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[Pop-up Civilization: Protocols & Resilience-Tech for Rewilding Agency]]></title>
            <link>https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency</link>
            <guid>https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency</guid>
            <pubDate>Thu, 18 Sep 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[In 2011, as part of an interdisciplinary course at the Australian National]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>In 2011, as part of an interdisciplinary course at the Australian National
University (VCUG2002<sup><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#user-content-fn-1-84387a" id="user-content-fnref-1-84387a" data-footnote-ref="true" aria-describedby="footnote-label">1</a></sup>), I wrote an article about the relationship between
efficiency, redundancy, vulnerability, and trust.
<a href="https://cmcdragonkai.wordpress.com/2011/10/25/efficiency-vs-redundancy-vs-vulnerability-vs-trust/" target="_blank" rel="noopener noreferrer">That post is still online</a><sup><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#user-content-fn-2-84387a" id="user-content-fnref-2-84387a" data-footnote-ref="true" aria-describedby="footnote-label">2</a></sup>.
The basic principle was focusing on efficiency often meant squeezing out
redundancy and buying systemic fragility. Fifteen years later, those notes came
back to audit our own systems that we've been building, but the pattern is
fractally repeated across our entire technological civilisation.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/efficiency-vs-redundancy-vs-trust-vs-vulnerability-blog-post-header-3c920d2ed9388805779d21a0ec21de41.png" width="892" height="720" class="img_ev3q"></p>
<p>Whether it is information or operational technology, fragility is systemic. A
transactional incentive stack optimized for neat dashboards and KPI theater
drove just-in-time supply, platform centralization, and brittle dependencies. In
IT, knowledge was open but platforms enclosed. In OT, platforms are less
centralized, but knowledge, integration, and supply are gated behind vendors,
institutions and system integrators.</p>
<p>Both paths hollow out the crucial 'missing middle' of talent: the technicians,
integrators, and applied engineers who turn prototypes into reliable
infrastructure and products. These are hybrid thinkers and doers. Without this
layer, capability centralizes into a barbell: a few hyper-scale production
giants on one end, and a long tail of hobbyists on the other. This fragile
structure, lacking a broad, adaptive ecosystem, is then shattered by real-world
shocks: pandemics, port closures, energy spikes, sanctions, floods, brownouts.
The lesson is simple: resilience isn't a vibe. It is a set of design choices,
supply chains, and what still works when the internet sneezes or the maintainer
goes hiking.</p>
<p>This post lays out a practical stack for that world. Think pop‑up civilization
instead of mega‑projects: modular capabilities that communities can deploy
themselves in energy, comms, making, and logistics. We start with solar because
it forces the whole conversation: sourcing, manufacturability, numbers, and why
verifiable outcomes (receipts) are the missing coordination layer that ties
physical work to capital and incentives so the missing middle actually gets
built and paid.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>We are presenting this post's content as part of the first in-person pop-up
protocol study group in Kuala Lumpur, Malaysia, called
<a href="https://seapunkstudios.notion.site/college" target="_blank" rel="noopener noreferrer">Seapunk Proto-College</a>, itself an
experiment towards decentralizing education. It was later also presented as
during a <a href="https://desci.world/" target="_blank" rel="noopener noreferrer">Desci World</a> meeting.</p><p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/seapunk-proto-college-explainer-b27c301f21fa35df0315077b146127d3.webp" width="2047" height="1145" class="img_ev3q"></p></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="efficiency-vs-redundancy">Efficiency vs Redundancy<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#efficiency-vs-redundancy" class="hash-link" aria-label="Direct link to Efficiency vs Redundancy" title="Direct link to Efficiency vs Redundancy">​</a></h2>
<p>We're starting to shift from worshiping hyper-efficiency to building resilience,
but let's be precise: the pendulum has barely begun to swing. In mid-2025, the
center of gravity for our critical systems still sits with a handful of compute,
cloud, fab, and discovery hubs. "Resilience" remains mostly narrative unless it
shows up in open interfaces, procurement terms, and operational drills.</p>
<p>This isn't a theoretical risk; it's a reality laid bare by a series of
spectacular, real-world failures that revealed the two parallel paradoxes
driving our systemic fragility:</p>
<ul>
<li>The IT Paradox: The foundational knowledge of IT is more accessible than ever,
yet the economic reality is one of hyper-centralization. This was made
painfully clear during the 2021 AWS outage, where a single failure at a
US-East server farm bricked smart homes, robot vacuums, and doorbells across
the globe, these are cloud connections that are entirely unnecessary. We have
open protocols, but we've built a world where you can't turn on your own
lights if a distant server trips. This is the new digital enclosure: open in
principle, but closed and fragile in practice.</li>
<li>The OT Paradox: The world of operational technology is less centralized at the
platform level, but the knowledge and supply chains are highly gated. This was
the story of the great semiconductor shortage. Automotive production lines
didn't stop for lack of shipping containers; they stopped for a lack of
dollar-chips from a handful of foundries. It was a failure born from
just-in-time inventories coupled with a supply chain so specialized and opaque
that no single actor had a complete picture. This is the other enclosure:
fragmented in platform, but closed and fragile in practice.</li>
</ul>
<p>These twin paradoxes, stress-tested by events like the Suez Canal blockage (a
physical chokepoint) and the Texas power grid collapse (an infrastructure
monoculture), have produced the same outcome: a barbell structure that hollows
out the missing middle. This isn't just an economic abstraction; it's the
tangible absence of the technicians, integrators, and applied engineers who can
turn prototypes into reliable products, integrate multi-vendor systems, and
repair them when they break.</p>
<p>In Austin, during the
<a href="https://en.wikipedia.org/wiki/February_13%E2%80%9317,_2021_North_American_winter_storm" target="_blank" rel="noopener noreferrer">February 2021 freeze</a>,
this wasn't an abstract theory. Neighbors pooled resources in the few homes that
kept power. Others didn't make it; the official state-wide death toll was 246.
This is what happens when resilience is outsourced. The incentives for a
centralized provider to hold spare capacity for extreme events are weak, so when
the shock arrives, it's the community's own margin that decides the outcome.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Why "Efficient" Loses in a Volatile Non-Ergodic World</div><div class="admonitionContent_BuS1"><p>The math is unforgiving. In a stable system, optimizing for the average
(efficiency) wins. In a volatile system, optimizing to control variance
(resilience) and avoid ruin wins.</p><ul>
<li>
<p>The Volatility Penalty: For any system with compounding returns (like capital,
or operational uptime), the long-term growth rate is penalized by variance.
Higher volatility directly reduces your time-averaged growth, even if the
average return is the same.</p>
<p><strong>Time vs. average.</strong> For compounded outcomes, maximize
<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="double-struck">E</mi><mo stretchy="false">[</mo><mi>log</mi><mo>⁡</mo><mo stretchy="false">(</mo><mn>1</mn><mo>+</mo><mi>R</mi><mo stretchy="false">)</mo><mo stretchy="false">]</mo></mrow><annotation encoding="application/x-tex">\mathbb{E}[\log(1+R)]</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathbb">E</span><span class="mopen">[</span><span class="mop">lo<span style="margin-right:0.01389em">g</span></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="mclose">)]</span></span></span></span>:</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="double-struck">E</mi><mo stretchy="false">[</mo><mi>log</mi><mo>⁡</mo><mo stretchy="false">(</mo><mn>1</mn><mo>+</mo><mi>R</mi><mo stretchy="false">)</mo><mo stretchy="false">]</mo><mo>≈</mo><mi mathvariant="double-struck">E</mi><mo stretchy="false">[</mo><mi>R</mi><mo stretchy="false">]</mo><mo>−</mo><mstyle displaystyle="false" scriptlevel="0"><mfrac><mn>1</mn><mn>2</mn></mfrac></mstyle><mtext> </mtext><mrow><mi mathvariant="normal">V</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">r</mi></mrow><mo stretchy="false">(</mo><mi>R</mi><mo stretchy="false">)</mo><mo>−</mo><mstyle displaystyle="false" scriptlevel="0"><mfrac><mn>1</mn><mn>2</mn></mfrac></mstyle><mo stretchy="false">(</mo><mi mathvariant="double-struck">E</mi><mo stretchy="false">[</mo><mi>R</mi><mo stretchy="false">]</mo><msup><mo stretchy="false">)</mo><mn>2</mn></msup><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">\mathbb{E}[\log(1+R)] \approx \mathbb{E}[R] - \tfrac12\,\mathrm{Var}(R) - \tfrac12(\mathbb{E}[R])^2.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathbb">E</span><span class="mopen">[</span><span class="mop">lo<span style="margin-right:0.01389em">g</span></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="mclose">)]</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathbb">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.1901em;vertical-align:-0.345em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8451em"><span style="top:-2.655em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.394em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathrm">Var</span></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.2091em;vertical-align:-0.345em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8451em"><span style="top:-2.655em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.394em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mopen">(</span><span class="mord mathbb">E</span><span class="mopen">[</span><span class="mord mathnormal" style="margin-right:0.00773em">R</span><span class="mclose">]</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mord">.</span></span></span></span></span>
<p>Same mean, higher variance <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>⇒</mo></mrow><annotation encoding="application/x-tex">\Rightarrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.3669em"></span><span class="mrel">⇒</span></span></span></span> lower time-average growth.</p>
<p><strong>GBM exact:</strong> if <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><msub><mi>S</mi><mi>t</mi></msub></mrow><msub><mi>S</mi><mi>t</mi></msub></mfrac><mo>=</mo><mi>μ</mi><mtext> </mtext><mi>d</mi><mi>t</mi><mo>+</mo><mi>σ</mi><mtext> </mtext><mi>d</mi><msub><mi>W</mi><mi>t</mi></msub></mrow><annotation encoding="application/x-tex">\tfrac{dS_t}{S_t}=\mu\,dt+\sigma\,dW_t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.3413em;vertical-align:-0.4451em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8962em"><span style="top:-2.655em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05764em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2963em"><span style="top:-2.357em;margin-left:-0.0576em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em"><span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.4101em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05764em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2963em"><span style="top:-2.357em;margin-left:-0.0576em;margin-right:0.0714em"><span class="pstrut" style="height:2.5em"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em"><span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.4451em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">d</span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em"></span><span class="mord mathnormal" style="margin-right:0.03588em">σ</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord mathnormal">d</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span></span></span></span>, then</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="double-struck">E</mi><mo stretchy="false">[</mo><mi>log</mi><mo>⁡</mo><msub><mi>S</mi><mi>t</mi></msub><mo stretchy="false">]</mo><mo>=</mo><mi>log</mi><mo>⁡</mo><msub><mi>S</mi><mn>0</mn></msub><mo>+</mo><mo stretchy="false">(</mo><mi>μ</mi><mo>−</mo><mstyle displaystyle="false" scriptlevel="0"><mfrac><mn>1</mn><mn>2</mn></mfrac></mstyle><msup><mi>σ</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mi>t</mi><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">\mathbb{E}[\log S_t]=\log S_0+(\mu-\tfrac12\sigma^2)t.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathbb">E</span><span class="mopen">[</span><span class="mop">lo<span style="margin-right:0.01389em">g</span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mclose">]</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em"></span><span class="mop">lo<span style="margin-right:0.01389em">g</span></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.2091em;vertical-align:-0.345em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8451em"><span style="top:-2.655em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.394em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">σ</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord mathnormal">t</span><span class="mord">.</span></span></span></span></span>
</li>
<li>
<p>The Kelly Criterion: The optimal strategy for maximizing long-run growth in
the face of uncertainty is to never bet the whole farm. The more volatile the
system, the more margin you must hold in reserve.</p>
<p><strong>Kelly (binary odds <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>b</mi><mo lspace="0em" rspace="0em">:</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">b{:}1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em"></span><span class="mord mathnormal">b</span><span class="mord"><span class="mrel">:</span></span><span class="mord">1</span></span></span></span>):</strong></p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>g</mi><mo stretchy="false">(</mo><mi>f</mi><mo stretchy="false">)</mo><mo>=</mo><mi>p</mi><mi>log</mi><mo>⁡</mo><mo stretchy="false">(</mo><mn>1</mn><mo>+</mo><mi>f</mi><mi>b</mi><mo stretchy="false">)</mo><mo>+</mo><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>p</mi><mo stretchy="false">)</mo><mi>log</mi><mo>⁡</mo><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>f</mi><mo stretchy="false">)</mo><mo separator="true">,</mo><mspace width="1em"></mspace><msup><mi>f</mi><mstyle mathcolor="#cc0000"><mtext>\*</mtext></mstyle></msup><mo>=</mo><mfrac><mrow><mi>b</mi><mi>p</mi><mo>−</mo><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>p</mi><mo stretchy="false">)</mo></mrow><mi>b</mi></mfrac><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">g(f)=p\log(1+fb)+(1-p)\log(1-f),\quad
f^\*=\frac{bp-(1-p)}{b}.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.03588em">g</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.10764em">f</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop">lo<span style="margin-right:0.01389em">g</span></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.10764em">f</span><span class="mord mathnormal">b</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal">p</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.1667em"></span><span class="mop">lo<span style="margin-right:0.01389em">g</span></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.188em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.10764em">f</span><span class="mclose">)</span><span class="mpunct">,</span><span class="mspace" style="margin-right:1em"></span><span class="mspace" style="margin-right:0.1667em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord text mtight" style="color:#cc0000"><span class="mord mtight" style="color:#cc0000">\*</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:2.113em;vertical-align:-0.686em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em"><span style="top:-2.314em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord mathnormal">b</span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.677em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord mathnormal">b</span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord mathnormal">p</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord">.</span></span></span></span></span>
<p><strong>Merton (continuous log-utility):</strong></p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>f</mi><mstyle mathcolor="#cc0000"><mtext>\*</mtext></mstyle></msup><mo>=</mo><mfrac><mrow><mi>μ</mi><mo>−</mo><mi>r</mi></mrow><msup><mi>σ</mi><mn>2</mn></msup></mfrac><mspace width="1em"></mspace><mo stretchy="false">(</mo><mtext>or&nbsp;</mtext><mo stretchy="false">(</mo><mi>μ</mi><mo>−</mo><mi>r</mi><mo stretchy="false">)</mo><mi mathvariant="normal">/</mi><mo stretchy="false">(</mo><mi>γ</mi><msup><mi>σ</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mtext>&nbsp;for&nbsp;CRRA</mtext><mo stretchy="false">)</mo><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">f^\*=\frac{\mu-r}{\sigma^2}\quad(\text{or }(\mu-r)/(\gamma\sigma^2)\text{ for CRRA}).</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.1324em;vertical-align:-0.1944em"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord text mtight" style="color:#cc0000"><span class="mord mtight" style="color:#cc0000">\*</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.9463em;vertical-align:-0.686em"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2603em"><span style="top:-2.314em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">σ</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7401em"><span style="top:-2.989em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em"><span class="pstrut" style="height:3em"></span><span class="frac-line" style="border-bottom-width:0.04em"></span></span><span style="top:-3.677em"><span class="pstrut" style="height:3em"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mord mathnormal" style="margin-right:0.02778em">r</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:1em"></span><span class="mopen">(</span><span class="mord text"><span class="mord">or&nbsp;</span></span><span class="mopen">(</span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1.1141em;vertical-align:-0.25em"></span><span class="mord mathnormal" style="margin-right:0.02778em">r</span><span class="mclose">)</span><span class="mord">/</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05556em">γ</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em">σ</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord text"><span class="mord">&nbsp;for&nbsp;CRRA</span></span><span class="mclose">)</span><span class="mord">.</span></span></span></span></span>
</li>
<li>
<p>Ruin is an Absorbing State: A system optimized for efficiency with a non-zero
probability of catastrophic failure will, given enough time, eventually fail.
Resilience is the strategy of avoiding ruin first, and optimizing for
efficiency second.</p>
<p><strong>Ruin hazard:</strong> if per-period ruin prob is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ε</mi><mo>&gt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">\varepsilon&gt;0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em"></span><span class="mord mathnormal">ε</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">0</span></span></span></span>,</p>
<span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="double-struck">P</mi><mo stretchy="false">{</mo><mtext>no&nbsp;ruin&nbsp;ever</mtext><mo stretchy="false">}</mo><mo>=</mo><munder><mrow><mi>lim</mi><mo>⁡</mo></mrow><mrow><mi>n</mi><mo>→</mo><mi mathvariant="normal">∞</mi></mrow></munder><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>ε</mi><msup><mo stretchy="false">)</mo><mi>n</mi></msup><mo>=</mo><mn>0.</mn></mrow><annotation encoding="application/x-tex">\mathbb{P}\{\text{no ruin ever}\}=\lim_{n\to\infty}(1-\varepsilon)^n=0.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathbb">P</span><span class="mopen">{</span><span class="mord text"><span class="mord">no&nbsp;ruin&nbsp;ever</span></span><span class="mclose">}</span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:1.45em;vertical-align:-0.7em"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.6944em"><span style="top:-2.4em;margin-left:0em"><span class="pstrut" style="height:3em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mrel mtight">→</span><span class="mord mtight">∞</span></span></span></span><span style="top:-3em"><span class="pstrut" style="height:3em"></span><span><span class="mop">lim</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7em"><span></span></span></span></span></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222em"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em"></span><span class="mord mathnormal">ε</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7144em"><span style="top:-3.113em;margin-right:0.05em"><span class="pstrut" style="height:2.7em"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em"></span></span><span class="base"><span class="strut" style="height:0.6444em"></span><span class="mord">0.</span></span></span></span></span>
</li>
</ul></div></div>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="roadmap-towards-practical-resilience">Roadmap towards Practical Resilience<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#roadmap-towards-practical-resilience" class="hash-link" aria-label="Direct link to Roadmap towards Practical Resilience" title="Direct link to Roadmap towards Practical Resilience">​</a></h2>
<p>True resilience, therefore, is not about nostalgia or a return to a simpler
time. Resilience is capability density in the missing-middle. It is about
fundamentally re-architecting our systems for optionality and sovereignty. This
means shifting our design principles:</p>
<ul>
<li>From Platforms to Protocols: We must prioritize open interfaces, data
portability, and the right to substitute components without being locked into
a single vendor's ecosystem.</li>
<li>From Centralized Control to Edge Capability: We must build systems that can
operate autonomously, with graceful degradation, when disconnected from the
central cloud.</li>
<li>From Tenancy to Ownership: We must empower users and communities with control
over their own infrastructure, data, and devices.</li>
</ul>
<p>This isn't an abstract manifesto. It's a practical engineering roadmap. At
Matrix AI, our mission is to help build the tools and protocols that bridge the
gap between these principles and on-the-ground reality. The goal isn't to boil
the ocean or rebuild the entire industrial world; it's to enable the creation of
a "pop-up civilization stack", a ladder of modular, portable capabilities that a
community can deploy and own themselves.</p>
<p>This ladder has four essential rungs, built in sequence:</p>
<ul>
<li>Secure Local Energy: First, you establish energy sovereignty.</li>
<li>Establish Resilient Comms: Then, you light up communications.</li>
<li>Enable Local Making &amp; Sensing: Next, you gain the ability to build and
measure.</li>
<li>Build Sovereign Logistics: Finally, you move things on your own terms.</li>
</ul>
<p>We are starting with the first and most fundamental rung: Energy. Everything
else depends on power. If you want local agency, you begin by securing a local
energy source that can operate independently of the grid. Solar is the most
modular, rapidly deployable, and accessible technology to achieve this. It
scales from a single panel on a roof to a full microgrid, and its core
components are becoming increasingly commoditized.</p>
<p>For a place like Southeast Asia, this isn't a theoretical exercise. Frequent
brownouts, the high cost of diesel for off-grid communities, and an archipelagic
geography make distributed solar a necessity, not a luxury. The climate here is
both a blessing (ample sun-hours) and a curse (heat and humidity that punish
poorly-engineered systems). This makes it the perfect place to focus on what
actually works.</p>
<p>True energy sovereignty isn't just about deploying panels that someone else
manufactured in a hyper-centralized, distant factory. That's just a longer, more
fragile supply chain. True resilience comes from owning the means of production.
This is a deliberate shift away from a society of alienated consumers and
towards a society of capable producers. It reframes the debate: the goal of
decentralization is not to find a "cheaper" consumer product that can compete
with the hyper-efficient centralized economy. The goal is to make a producer
investment. You decentralize because you want to own a piece of your own
infrastructure, to have agency over the tools that power your life.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>Decentralization wins by reducing rent extraction and sharing value to
producers, by structurally prioritizing antifragility and local economies of
scope over monolithic efficiency. It does not win by undercutting hyperscale on
sticker price. Return on Investment (ROI) comes from use (stacked yields,
leveraging recombination and diverse outputs), not from the panel's ex-factory
<code>$/W</code>. Low module prices (or low commodity prices in general) are a tactical
input, not a strategy.</p></div></div>
<p>This is why we must focus on technologies that can be decentralized not just in
their use, but in their creation, their design, and their funding. This leads us
to the concept of the microfactory, a powerful tool for rewilding agency.
Instead of relying on a global supply chain for finished modules, a community or
a small enterprise can use a compact, containerized production line to fabricate
and repair their own solar panels on-site. This is a profound shift in
capability. It increases optionality by reducing dependency on shipping,
enabling faster repair and replacement cycles, and allowing for rapid iteration
on designs tailored to the local environment.</p>
<p>Most importantly, it builds a local ecosystem of skilled technicians, the very
"missing middle" our current system has hollowed out. It creates a context for
tech transfer, for skills to be learned and compounded locally. This is not just
about producing watts; it's about producing capability.</p>
<p>The question then becomes: which solar technologies are actually amenable to
this kind of decentralized, producer-centric model? This forces us to look
beyond just today's market leader and into the strange, new tech that offers a
different set of trade-offs, not just in efficiency, but in manufacturability
and accessibility.</p>
<p>This is why we need to compare the incumbent, crystalline silicon, with an
emerging alternative like perovskites.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-state-of-solar-silicon-vs-the-perovskite-wedge">The State of Solar: Silicon vs. The Perovskite Wedge<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-state-of-solar-silicon-vs-the-perovskite-wedge" class="hash-link" aria-label="Direct link to The State of Solar: Silicon vs. The Perovskite Wedge" title="Direct link to The State of Solar: Silicon vs. The Perovskite Wedge">​</a></h2>
<p>Today's solar landscape is dominated by crystalline silicon (c-Si). It's a
mature, bankable technology. The panels are rugged, the failure modes are
well-understood, and the global supply chain, while concentrated, is efficient.
For fixed, long-term installations where weight is not the primary constraint,
silicon is the undisputed workhorse.</p>
<p>However, silicon's manufacturing process from purifying silicon to growing
ingots and wafering is a high-capex, centralized affair. This is where a new
class of materials, perovskites, presents a compelling alternative, not as a
wholesale replacement, but as a strategic "resilience wedge."</p>
<table><thead><tr><th style="text-align:left"><strong>Factor</strong></th><th style="text-align:left"><strong>Crystalline Silicon (c-Si)</strong></th><th style="text-align:left"><strong>Perovskites (Printable Thin-Film)</strong></th><th style="text-align:left"><strong>The Resilience Implication</strong></th></tr></thead><tbody><tr><td style="text-align:left"><strong>Manufacturing</strong></td><td style="text-align:left">High-temperature, high-capex, centralized fabs.</td><td style="text-align:left">Low-temperature, solution-based "printing." Amenable to smaller, distributed microfactories.</td><td style="text-align:left">Perovskites offer a path to localizing the <em>manufacturing</em> of PV, not just the assembly.</td></tr><tr><td style="text-align:left"><strong>Form Factor</strong></td><td style="text-align:left">Rigid, heavy glass-sandwich modules.</td><td style="text-align:left">Can be printed on flexible, lightweight substrates (like plastics) or glass.</td><td style="text-align:left">High power-to-weight ratio. Enables rapid-deployment, portable, and weight-constrained applications (e.g., rooftops, drones, temporary shelters).</td></tr><tr><td style="text-align:left"><strong>Efficiency</strong></td><td style="text-align:left">High (20-23% commercial modules).</td><td style="text-align:left">Approaching silicon in labs. Perovskite-on-silicon tandems are already hitting &gt;25% commercially, boosting the output of existing silicon tech.</td><td style="text-align:left">Tandems offer an upgrade path; standalone perovskites are "good enough" for many off-grid loads.</td></tr><tr><td style="text-align:left"><strong>Supply Chain</strong></td><td style="text-align:left">Highly concentrated in a few regions, creating geopolitical risk.</td><td style="text-align:left">Precursor chemicals are more broadly available, but high-purity grades and specific halides (like iodine) have their own chokepoints.</td><td style="text-align:left">Diversifies the material dependency away from the silicon supply chain, but introduces new chemical sourcing considerations.</td></tr></tbody></table>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-hard-realities-for-perovskites-in-southeast-asia">The Hard Realities for Perovskites in Southeast Asia:<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-hard-realities-for-perovskites-in-southeast-asia" class="hash-link" aria-label="Direct link to The Hard Realities for Perovskites in Southeast Asia:" title="Direct link to The Hard Realities for Perovskites in Southeast Asia:">​</a></h3>
<p>The promise of perovskites is immense, but the engineering challenges in a
tropical environment are non-trivial. This is where the real work of the
"missing middle" comes in:</p>
<ol>
<li><strong>Encapsulation is the Product:</strong> Perovskites are notoriously sensitive to
moisture and oxygen. In the heat and humidity of Southeast Asia, a naive
encapsulation will fail in months, not years. The real innovation isn't just
the perovskite chemistry itself, but the development of robust, low-cost
barrier films, edge seals, and lamination processes that can survive years
of thermal cycling and UV exposure. Glass-glass encapsulation with a
UV-cured edge seal is a proven starting point.</li>
<li><strong>Lead Management is Non-Negotiable:</strong> Most high-performance perovskites
today contain a small amount of lead. While the quantity is minimal (grams
per square meter), a responsible deployment requires a full lifecycle plan,
including robust encapsulation to prevent leaching and a clear end-of-life
recycling or reclamation process. This is a solvable engineering and
logistics problem, not a fundamental showstopper.</li>
<li><strong>Stability over Peak Efficiency:</strong> For a resilience application, a 12%
efficient panel that lasts for ten years is infinitely more valuable than a
20% efficient panel that dies in two. The focus of a local microfactory
should be on process control, quality assurance, and developing a stable,
reproducible "recipe" that is optimized for the local climate, rather than
chasing record lab efficiencies.</li>
</ol>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="lets-make-a-perovskite-pv-panel">Let's make a Perovskite PV Panel<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#lets-make-a-perovskite-pv-panel" class="hash-link" aria-label="Direct link to Let's make a Perovskite PV Panel" title="Direct link to Let's make a Perovskite PV Panel">​</a></h2>
<p>Our goal is to build a hand-made, palm-sized <strong>glass mini-module</strong> that can
produce a few hundred milliwatts in the sun—enough to light LEDs or
trickle-charge a small battery through a DC-DC board. We are specifically using
a <strong>fully printable "carbon" perovskite solar cell</strong> architecture. This is the
simplest, most robust starting point that avoids the need for expensive,
specialized equipment like vacuum tools and metal evaporators. It's a technology
that is not just used at the edge, but can be <em>made</em> at the edge.</p>
<p>We fully acknowledge such a micro-factory is effectively an infant-industrial
lab. But this is where we have to start in-order to rebuild that missing-middle
and eventually decentralize all the things!</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-anatomy-of-our-panel-what-each-layer-does">The Anatomy of Our Panel: What Each Layer Does<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-anatomy-of-our-panel-what-each-layer-does" class="hash-link" aria-label="Direct link to The Anatomy of Our Panel: What Each Layer Does" title="Direct link to The Anatomy of Our Panel: What Each Layer Does">​</a></h3>
<p>Before we build, let's understand the components. A solar panel is a sandwich of
functional layers, and in our case, each one is critical:</p>
<ul>
<li><strong>FTO Glass (The Foundation):</strong> This is our substrate. It's a clear sheet of
glass with a thin, conductive coating of fluorine-doped tin oxide (FTO). It
serves two functions: it lets sunlight in, and it acts as the front electrical
contact for our solar cell. We choose FTO over its cousin, ITO (indium tin
oxide), because it is more robust and can handle the high-temperature baking
steps in our process. <img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/fto-glass-tec15-473593d5e159a1eedc08fb7d3ac1eb2d.png" width="549" height="475" class="img_ev3q"></li>
<li><strong>TiO₂ Layer (The Electron Superhighway):</strong> This is a layer of titanium
dioxide, the same benign material found in sunscreen and paint. We print it as
a porous, sponge-like ceramic. Its job is to efficiently collect the electrons
that are generated when sunlight hits the perovskite.
<img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/titanium-dioxide-and-zirconium-dioxide-paste-7897364ca4d87fa097e48201363c4bfe.png" width="280" height="279" class="img_ev3q"></li>
<li><strong>ZrO₂ Spacer (The Insulator):</strong> This is a layer of zirconium dioxide, another
common ceramic. It acts as an insulating spacer, preventing the front and back
electrodes from touching and short-circuiting the cell.</li>
<li><strong>Carbon Layer (The All-in-One Back Contact):</strong> This is a simple, printable
"paint" made of carbon (graphite and carbon black). It serves as the top
electrode, collecting the "holes" (positive charges) from the perovskite.
Crucially, it's also porous, allowing the perovskite solution to be wicked
into the stack from behind.</li>
<li><strong>Perovskite (The Engine):</strong> This is the light-absorbing layer. We introduce
it as a liquid salt solution that soaks into the ceramic sponge and then
crystallizes to form the active material that converts photons into
electricity.</li>
</ul>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/perovskite-layers-0737b2a9a9fcdc9930cf21fa52114aab.png" width="629" height="506" class="img_ev3q"></p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-minimum-viable-microfactory-your-bench-kit">The Minimum Viable Microfactory: Your Bench Kit<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-minimum-viable-microfactory-your-bench-kit" class="hash-link" aria-label="Direct link to The Minimum Viable Microfactory: Your Bench Kit" title="Direct link to The Minimum Viable Microfactory: Your Bench Kit">​</a></h3>
<p>You don't need a cleanroom or a multi-million dollar fabrication facility to
start. Here is the essential, no-frills kit:</p>
<ul>
<li><strong>Printing:</strong> A small, manual screen printer with a vacuum table, a steel
squeegee, and a set of stainless mesh screens. This is the same basic
technology used for printing t-shirts, adapted for high-precision electronics.
<img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/screen-printer-squeegee-f2017c6c8fd72bf852a2ae67c7a6d1a8.png" width="357" height="359" class="img_ev3q"></li>
<li><strong>Heat:</strong> A benchtop <strong>muffle furnace</strong> that can reach at least 500°C for
sintering the ceramic layers, and a standard lab hotplate for
lower-temperature steps. <img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/muffle-furnace-4d3598a996ecd51e9026b168a6889dca.png" width="506" height="506" class="img_ev3q"></li>
<li><strong>Wet Work:</strong> Standard laboratory glassware (beakers, pipettes), a precision
scale for weighing chemicals, and essential personal protective equipment
(PPE). A fume hood or a well-ventilated workspace is critical for safety.</li>
<li><strong>Testing:</strong> At a minimum, a multimeter to measure voltage and current. To
properly characterize your cells, a small LED-based solar simulator and a USB
buck/boost board are highly recommended.</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-shopping-list-sourcing-your-consumables">The Shopping List: Sourcing Your Consumables<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-shopping-list-sourcing-your-consumables" class="hash-link" aria-label="Direct link to The Shopping List: Sourcing Your Consumables" title="Direct link to The Shopping List: Sourcing Your Consumables">​</a></h3>
<p>The materials for this process are surprisingly accessible and are not subject
to the same strategic chokepoints as traditional silicon manufacturing.</p>
<ul>
<li><strong>FTO Glass:</strong> Available from various online scientific suppliers, get the
TEC15 variant.</li>
<li><strong>Pastes:</strong> You can purchase pre-mixed, screen-printable pastes for TiO₂,
ZrO₂, and Carbon from specialized vendors. This is the easiest way to start.</li>
<li><strong>Perovskite Solution:</strong> You can buy pre-mixed perovskite inks or the
individual precursor salts (e.g., lead iodide and organic salts like
formamidinium iodide) and mix them yourself following established recipes.
<em>(Note: Lead is a hazardous material and must be handled with appropriate
safety protocols.)</em></li>
<li><strong>Encapsulation:</strong> A roll of <strong>PIB (polyisobutylene) edge-seal tape</strong> and a
second sheet of plain glass for the back. A hydrophobic topcoat can be added
for extra moisture resistance.</li>
<li><strong>Contacts:</strong> Silver paint or conductive epoxy for making electrical
connections, along with standard copper tape and wires.</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-10-step-recipe-from-glass-to-power">The 10-Step Recipe: From Glass to Power<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-10-step-recipe-from-glass-to-power" class="hash-link" aria-label="Direct link to The 10-Step Recipe: From Glass to Power" title="Direct link to The 10-Step Recipe: From Glass to Power">​</a></h3>
<p>This is a simplified, step-by-step guide to fabricating a single 10x10 cm solar
cell.</p>
<ol>
<li><strong>Clean the Glass:</strong> Start with a thorough cleaning of the FTO glass
substrate. A sequence of detergent, deionized water, and isopropanol is
standard. From this point on, handle it only by the edges.</li>
<li><strong>Define the Active Area (Optional but Recommended):</strong> To improve
performance, you can score the FTO coating with a glass cutter or a laser to
define the precise area where you will print your cell. For your first
attempt, you can skip this and print a simple rectangle.</li>
<li><strong>Print the TiO₂ Layer:</strong> Using your screen printer, apply a thin, even layer
of the TiO₂ paste. Allow it to dry, and then <strong>sinter</strong> it in the muffle
furnace for 30-60 minutes at 450-500°C. This burns off the organic binders
and hardens the ceramic.</li>
<li><strong>Print the ZrO₂ Layer:</strong> Print the insulating spacer layer directly on top
of the TiO₂. Dry and sinter it at a similar temperature.</li>
<li><strong>Print the Carbon Layer:</strong> Print the carbon electrode on top of the ZrO₂.
This layer also needs to be dried and sintered, typically at around 400°C.</li>
<li><strong>Infiltrate the Perovskite:</strong> This is the magic step. Warm the printed stack
on a hotplate to around 60°C. Then, carefully drop-cast the liquid perovskite
solution onto the carbon side. The solution will be wicked into the porous
ceramic stack via capillary action. Continue until the area darkens
uniformly.</li>
<li><strong>Crystallize the Perovskite:</strong> Bake the cell on a hotplate at 80-100°C for
several minutes. This drives off the solvent and allows the perovskite to
form a high-quality crystal structure inside your scaffold.</li>
<li><strong>Make the Electrical Contacts:</strong>
<ul>
<li><strong>Front Contact:</strong> Carefully scrape a small area of the printed layers off
one edge of the FTO glass to expose the conductive coating. Apply a small
dab of silver paint or conductive epoxy and attach a piece of copper tape.</li>
<li><strong>Back Contact:</strong> Apply a small dot of silver paint onto the carbon layer
(away from the main active area) and attach a tinned wire.</li>
</ul>
</li>
<li><strong>Encapsulate the Cell:</strong> To protect your cell from the elements, run a strip
of PIB edge-seal tape around the perimeter. Place a clean sheet of cover
glass on top and apply gentle pressure and heat to create a seal.</li>
<li><strong>Test Your Creation:</strong> Take your finished module out into the sun! Measure
the open-circuit voltage (Voc) and short-circuit current (Isc) with your
multimeter. Connect it to a small load, like an LED, or use a boost
converter to charge a 5V USB device.</li>
</ol>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="what-to-expect-working-vs-world-record">What to Expect: "Working" vs. "World-Record"<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#what-to-expect-working-vs-world-record" class="hash-link" aria-label="Direct link to What to Expect: &quot;Working&quot; vs. &quot;World-Record&quot;" title="Direct link to What to Expect: &quot;Working&quot; vs. &quot;World-Record&quot;">​</a></h3>
<p>Don't expect your first hand-made cell to match the performance of a commercial
panel. The goal here is capability. A "working" first attempt will likely
produce an open-circuit voltage of around 0.8-0.95V and a few tens of milliamps
of current for a 10cm square cell. Achieving a practical efficiency of <strong>5-10%
is a fantastic first milestone</strong> with this architecture. While state-of-the-art
research devices with this carbon-based structure have exceeded 20% efficiency,
your benchtop result will be lower but incredibly valuable—it will be power that
you <em>made</em>.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="safety-and-sustainability-a-non-negotiable-part-of-the-process">Safety and Sustainability: A Non-Negotiable Part of the Process<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#safety-and-sustainability-a-non-negotiable-part-of-the-process" class="hash-link" aria-label="Direct link to Safety and Sustainability: A Non-Negotiable Part of the Process" title="Direct link to Safety and Sustainability: A Non-Negotiable Part of the Process">​</a></h3>
<p>This process involves hazardous materials, specifically lead salts and solvents.
A responsible microfactory operation must include:</p>
<ul>
<li><strong>Lead Safety:</strong> All work with lead compounds should be done over trays to
contain spills, and with appropriate PPE (gloves, eye protection).</li>
<li><strong>Waste Management:</strong> A dedicated, clearly labeled waste stream for all
lead-contaminated materials (wipes, gloves, rinses) must be established. Do
not pour these materials down the drain.</li>
<li><strong>End-of-Life Plan:</strong> From day one, have a plan for what to do with failed or
end-of-life cells. This could involve encapsulation in resin for safe disposal
or developing a protocol for recycling.</li>
</ul>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="from-a-single-cell-to-a-full-panel-the-path-to-scaling">From a Single Cell to a Full Panel: The Path to Scaling<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#from-a-single-cell-to-a-full-panel-the-path-to-scaling" class="hash-link" aria-label="Direct link to From a Single Cell to a Full Panel: The Path to Scaling" title="Direct link to From a Single Cell to a Full Panel: The Path to Scaling">​</a></h3>
<p>A single cell produces only about 1V. To create a useful panel, you need to
connect multiple cells in series to increase the voltage. There are two ways to
do this:</p>
<ol>
<li><strong>Tile-and-Tab:</strong> The simplest method. You create multiple individual cells,
as described above, and then wire them together externally with copper
ribbon, like connecting batteries in a series.</li>
<li><strong>Monolithic Module:</strong> A more advanced technique where you use a laser or
mechanical scriber to pattern the layers on a single, larger sheet of glass,
creating series interconnections directly on the substrate.</li>
</ol>
<p>Start with the tile-and-tab method. Once you have mastered the basic process,
you can invest in the equipment needed for monolithic integration.</p>
<p>This is the essence of the perovskite wedge. It's not about replacing the entire
global solar industry overnight. It's about providing a tangible, accessible,
and powerful tool for communities to start building their own energy
sovereignty, one printable panel at a time.</p>
<p>The point is to for the "decentralized community" to start getting into their
hands dirty in the physical world, and start contributing and investing into the
industrial commons. So that an adaptive ecosystem of physical world engineering
becomes possible once more, and so that civilisation is not stuck in TINA
mindset.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="yield-stacking-the-second-life-silicon-line">Yield Stacking the Second-Life Silicon Line<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#yield-stacking-the-second-life-silicon-line" class="hash-link" aria-label="Direct link to Yield Stacking the Second-Life Silicon Line" title="Direct link to Yield Stacking the Second-Life Silicon Line">​</a></h2>
<p>Silicon panels have a lifetime of 20 years. Within the next 20 years, there will
be numerous existing solar panels that need to be recycled. Imagine what would
be possible if these perovskite microfactories were combined with micro-
recycling refineries for second life PVs. And with that, I leave you the reader
with a combined diagram of the entire process flow above expanded with a
potential future upgrade of refining second life silicon panels.</p>
<!-- -->
<!-- -->
<section data-footnotes="true" class="footnotes"><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5 sr-only" id="footnote-label">Footnotes<a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#footnote-label" class="hash-link" aria-label="Direct link to Footnotes" title="Direct link to Footnotes">​</a></h2>
<ol>
<li id="user-content-fn-1-84387a">
<p><a href="https://programsandcourses.anu.edu.au/2014/course/vcug2002" target="_blank" rel="noopener noreferrer">The 2011 ANU VCUG2002 started off as an experimental course that later became public in 2014.</a> <a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#user-content-fnref-1-84387a" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-2-84387a">
<p>Archived at
<a href="https://web.archive.org/web/20250916051829/https://cmcdragonkai.wordpress.com/2011/10/25/efficiency-vs-redundancy-vs-vulnerability-vs-trust/" target="_blank" rel="noopener noreferrer">Wayback Machine</a> <a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#user-content-fnref-2-84387a" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#efficiency-vs-redundancy" class="table-of-contents__link toc-highlight">Efficiency vs Redundancy</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#roadmap-towards-practical-resilience" class="table-of-contents__link toc-highlight">Roadmap towards Practical Resilience</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-state-of-solar-silicon-vs-the-perovskite-wedge" class="table-of-contents__link toc-highlight">The State of Solar: Silicon vs. The Perovskite Wedge</a><ul><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-hard-realities-for-perovskites-in-southeast-asia" class="table-of-contents__link toc-highlight">The Hard Realities for Perovskites in Southeast Asia:</a></li></ul></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#lets-make-a-perovskite-pv-panel" class="table-of-contents__link toc-highlight">Let's make a Perovskite PV Panel</a><ul><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-anatomy-of-our-panel-what-each-layer-does" class="table-of-contents__link toc-highlight">The Anatomy of Our Panel: What Each Layer Does</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-minimum-viable-microfactory-your-bench-kit" class="table-of-contents__link toc-highlight">The Minimum Viable Microfactory: Your Bench Kit</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-shopping-list-sourcing-your-consumables" class="table-of-contents__link toc-highlight">The Shopping List: Sourcing Your Consumables</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#the-10-step-recipe-from-glass-to-power" class="table-of-contents__link toc-highlight">The 10-Step Recipe: From Glass to Power</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#what-to-expect-working-vs-world-record" class="table-of-contents__link toc-highlight">What to Expect: "Working" vs. "World-Record"</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#safety-and-sustainability-a-non-negotiable-part-of-the-process" class="table-of-contents__link toc-highlight">Safety and Sustainability: A Non-Negotiable Part of the Process</a></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#from-a-single-cell-to-a-full-panel-the-path-to-scaling" class="table-of-contents__link toc-highlight">From a Single Cell to a Full Panel: The Path to Scaling</a></li></ul></li><li><a href="https://matrix.ai/learn/blog/pop-up-civilization-protocols-resilience-tech-for-rewilding-agency#yield-stacking-the-second-life-silicon-line" class="table-of-contents__link toc-highlight">Yield Stacking the Second-Life Silicon Line</a></li></ul><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>resilience</category>
            <category>protocols</category>
            <category>southeast-asia</category>
            <category>operational-technology</category>
            <category>sovereignty</category>
        </item>
        <item>
            <title><![CDATA[Escaping the Builder's Trap: Build the Business System First]]></title>
            <link>https://matrix.ai/learn/blog/builders-trap-escape-loop</link>
            <guid>https://matrix.ai/learn/blog/builders-trap-escape-loop</guid>
            <pubDate>Fri, 15 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Infra founders love perfect code, but markets only care about outcomes. The real]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Infra founders love perfect code, but markets only care about outcomes. The real
system to be built is the business itself, not just the tech inside it. If
you're shipping feature after feature and watching adoption stay flat, you might
be in the builder's trap. Here's why it happens, and what to pay attention to
instead.</p>
<p>Technical founders often fall into a common pattern. They optimize the cleanest
part of the stack, the software itself, and treat everything essential for
distribution and adoption as "a problem to be solved later." This approach
misses a critical reality: the business is itself a system. It functions as an
engine of feedback loops, where only the outermost loop connecting to the market
truly sets the speed limit. Building a feature is easy; building one that moves
a business metric is a different game entirely.</p>
<p>The operational tug-of-war, then, is almost always between the "Market Loop"
(will anyone care?) and the "Build Loop" (can we ship it?). The trap is letting
the build loop's own gravity pull it away from the market's orbit. This is
particularly easy to fall into for a certain kind of founder.</p>
<p>If you're a systems founder, you know the pull. That's the archetype, right? You
build keystone primitives where the real value only shows up after multiple,
complex pieces are wired together. This naturally drags you into "builder mode."
It's not that you don't "get" markets; it's that the sheer complexity of your
vision can stretch the feedback loop so long that your contact with the market
decays to zero.</p>
<p>The journey feels intoxicating. Every problem you solve seems to uncover a
deeper, more fundamental one. You find yourself on a quest of technical,
conceptual, and user discovery all at once. This is the hard, meaningful work,
the intellectual puzzle. You might be architecting for
<a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing" target="_blank" rel="noopener noreferrer">decentralized value sharing</a>,
designing a
<a href="https://polykey.com/blog/global-public-acl-and-trust-federation" target="_blank" rel="noopener noreferrer">global public ACL</a>,
or wrestling with how to guarantee
<a href="https://polykey.com/blog/ai-detection-versus-cryptographic-provenance" target="_blank" rel="noopener noreferrer">cryptographic provenance</a>
in an era of bots. It all feels essential. And one day you realise you spent 10
years digging into that rabbit hole, and you also realise, it will never end.
There is no perfect solution, only trade-offs.</p>
<p>Real impact demands running both loops in parallel, so that solving the problem
can be done with work-in-progress capital-flywheel.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-concurrent-loops">The Concurrent Loops<a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#the-concurrent-loops" class="hash-link" aria-label="Direct link to The Concurrent Loops" title="Direct link to The Concurrent Loops">​</a></h2>
<p><strong>Impact = Build Loop x Market Loop</strong></p>
<ul>
<li><strong>The Build Loop</strong> - This is your comfort zone. It's about creating an
elegant, secure protocol. The metrics you track are technical:
time-to-provision an identity, mean-time-to-revoke a credential, signed-claim
throughput. The anti-pattern here is subtle but deadly: you keep adding
surfaces to the protocol faster than any single use-case can become
undeniable. You end up with a beautiful engine for a car nobody is ready to
drive yet.</li>
<li><strong>The Market Loop</strong> - This is the one that often feels foreign. Its only job
is to find a paying customer with a painful, first-order problem <em>today</em>. It's
not about selling the grand vision of trust federation; it's about solving
something mundane and expensive, like eliminating static secrets in CI/CD
pipelines or managing cross-organization vendor access. The metrics here are
about cash and customers: the number of active design partners, weekly jobs
run on your platform, and verified ROI stories.</li>
</ul>
<p>Mastering that second loop is where things get tricky. Every time you try to
solve a fundamental problem you uncover while working on a smaller one, your
complexity doesn't just grow, it multiplies with your uncertainty. Each new
component you add to the system introduces not only its own set of technical
unknowns but also an exponential number of unknown <em>interactions</em> with
everything else. That's the cost curve: the more foundational your project gets,
the more unknowns you accumulate, not just in tech but in how customers will
react, how a supporting ecosystem will be built, and whether you can even
explain what you've made. The smartest teams get tripped up by this paradox.
Sometimes being "dumber", artificially limiting scope, keeping things simpler
than your intelligence tempts you to, is what lets you make real progress.
Learning velocity beats speculative perfection every time.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="rabbit-hole-of-complexity">Rabbit Hole of Complexity<a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#rabbit-hole-of-complexity" class="hash-link" aria-label="Direct link to Rabbit Hole of Complexity" title="Direct link to Rabbit Hole of Complexity">​</a></h2>
<p><img decoding="async" loading="lazy" alt="S-curve of Adoption/Diffusion" src="https://matrix.ai/assets/images/s-curve-adoption-diffusion-5d9967d725e1fad7b20940ced9462581.webp" width="800" height="373" class="img_ev3q"></p>
<p>This feeds directly into the tyranny of complements. When you plug into existing
systems, you inherit a world of support: distribution channels, documentation,
common mental models, and all the complements are already baked in. But when you
build greenfield protocols, every missing piece: SDKs, admin panels, policy
languages, even basic "how-to" guides, is another steep hill to climb. Each
absent complement quietly blows the complexity budget and pushes the adoption
S-curve further to the right. The effort required to turn a mere "program" into
a robust "product" that people can use, and then into a "system" that can be
built upon, doesn't just add up, it multiplies. You see this pattern everywhere.
A system with immense potential dies because the surrounding ecosystem didn't
show up at the same time.</p>
<figure style="margin:10px 0px"><p><img decoding="async" loading="lazy" alt="A 2x2 grid showing the exponential effort increase from a Program to a Programming System Product" src="https://matrix.ai/assets/images/tar-pit-program-product-diagram-27c9ed267b88e85863dca59c292ae602.png" width="400" height="340" class="img_ev3q"></p><figcaption><em>The Tar Pit diagram, adapted from Fred Brooks' "The Mythical Man-Month", illustrating how the effort to turn a simple program into a robust, supported "Programming System Product" multiplies. Falling into the top-right quadrant is the classic builder's trap.</em></figcaption></figure>
<p>Staring into that top-right quadrant is terrifying. It's Fred Brooks' famous
"tar pit," where great engineering ambition goes to die, bogged down by a
nine-fold effort multiplier. Faced with this reality, it can feel like the only
rational response is a massive, non-consensus bet that sidesteps the problem
entirely. But there's a trap inside the trap: mistaking being non-consensus for
just being contrarian. The real edge isn't knee-jerk disagreement, it's reading
further out on the chain of consequences. It's seeing the second- and
third-order effects, the non-linear jumps that never show up on a burn-down
chart.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="cutting-the-gordion-knot">Cutting the Gordion Knot<a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#cutting-the-gordion-knot" class="hash-link" aria-label="Direct link to Cutting the Gordion Knot" title="Direct link to Cutting the Gordion Knot">​</a></h2>
<p>An operational improvement is a linear gain. The non-linear, paradigm-shifting
return comes from discovering how that improvement unlocks a new, composable
primitive that can ignite a network effect.</p>
<p>To make this concrete, consider an example from our work in
<a href="https://polykey.com/" target="_blank" rel="noopener noreferrer">decentralized security and verifiable outcomes</a>. The
first-order effect of replacing static secrets with dynamic, sigchain-based
capabilities is an operational improvement: a smaller attack surface and less
audit toil. That's the linear gain. But the true non-linear leap happens next.
With a system like this, each action, a code deployment, a data access, a
command to an AI agent, can now generate a cryptographic receipt: a discrete,
verifiable artifact of what happened, signed by the actors involved.</p>
<p>At first, these receipts are just better internal audit trails. But when they
become a common, interoperable language for trust, a network effect begins.
Suddenly, you're not just building a security tool. You're building the
foundation for a new utility for verifiable outcomes. Security policy becomes
programmable, composable and auditable across entire ecosystems. A "deployment
receipt" from your CI/CD system can be used as direct evidence for a
cyber-insurance policy. A vendor can prove compliance to a customer without
sharing proprietary logs. The focus shifts from managing keys to trading on
verifiable truths.</p>
<p>That is the leap. The question isn't "How do I outsmart the herd?" but "What is
about to become inevitable if these interactions compound for another six
months?" Consensus thinking usually means you're just optimizing for a local
minimum.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="principles-are-simple-and-ancient-execution-is-difficult">Principles are Simple and Ancient, Execution is Difficult<a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#principles-are-simple-and-ancient-execution-is-difficult" class="hash-link" aria-label="Direct link to Principles are Simple and Ancient, Execution is Difficult" title="Direct link to Principles are Simple and Ancient, Execution is Difficult">​</a></h2>
<p>This brings us to the real job of the founder. Entrepreneurship here is less
about having a "vision" and more about designing and owning feedback loops. It's
the agency to decide when to expand or contract the system boundary. Sometimes
"build tech" is the right call. But the decision to make repeatedly is when to
pull back and let the needs of the first-order "Market Loop" lead.</p>
<p>This is a delicate balancing act. The day-to-day operational reality is an
iterative, often mundane process of getting the first-order business right. It's
about cash flow, customer retention, and solving one real problem so well that
someone pays for it. But to attract capital and talent, you must also be able to
tell the nth-order story, the epic narrative of how your verifiable receipts and
network effects could change an entire industry. That's "narrative financing,"
and it's essential for selling the vision.</p>
<p>The entrepreneur's real edge is living in both timelines at once, using the
proof from the mundane first-order reality to make the epic nth-order story
credible. It's bet-sizing: knowing which small, iterative experiments will
resolve the most uncertainty for the least effort, and being okay with leaving
the rest to entropy until the time is right.</p>
<p>The signals that you're escaping the trap are tangible, because the loops start
to couple tightly. Market feedback shapes the roadmap in weeks, not quarters.
"Shipping" becomes less about pushing raw features and more about releasing
artifacts that generate real, external proof. A stable core emerges, one that
attracts the complements it needs without the team having to brute force
everything. The narrative shifts from "what does it do?" to "what does it let us
accomplish?" That's when adoption starts to compound.</p>
<p>These positive signals stand in stark contrast to the familiar warning signs of
the trap. Most are old news, just dressed in new clothes: premature generality
and protocol romanticism, driven by an obsession with the "Build Loop". You see
infinite proof-of-concept limbo, where the "Market Loop" never gets a chance to
close. Activity becomes a stand-in for evidence. Energy is spent making things
more elegant rather than more useful. The business system drifts while the
technical system gets ever more intricate.</p>
<p>Sun Tzu's The Art of War fits on a few dozen pages. Its principles are famously
simple: know your enemy, know yourself; avoid what is strong, attack what is
weak. Yet for 2,500 years, generals with this knowledge have still lost battles.</p>
<p>The gap between knowing the principle and executing it under fire is where
everything lives. It's where companies, armies, and careers are made or broken.</p>
<p>The real work of execution happens in the messy middle, in the constant,
difficult arguments over questions that have no easy answers:</p>
<ul>
<li>How much uncertainty should we carry at once?</li>
<li>When is it worth accepting dependency on an existing framework, even if it
cramps our technical ambitions? (Our experience is that external dependencies
sometimes don't do what they say in the README and can cause expensive
refactors later when integration is not an easily reversible decision, so
rather than trusting the label, use AI to do a deep due diligence...)</li>
<li>What's "enough" surface area for our platform to be viable right now, and when
do we stop adding more?</li>
</ul>
<p>This framework, then, isn't a map with a destination marked "X". It's a compass
and a shared language. It's a tool to help you have the right arguments and make
conscious trade-offs in real-time, rather than defaulting to what's comfortable.
It externalizes the psychological battle, turning a personal feeling of being
trapped into a systems-level problem that the team can diagnose and solve
together.</p>
<p>If there's a discipline to any of this, it's in using that compass relentlessly.
It's in drawing and redrawing the system boundary, managing feedback loops, and
owning the complexity you choose to take on. The business is the system, and the
code is just a means, not an end. Build the business system first; let the code
follow where it's needed.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#the-concurrent-loops" class="table-of-contents__link toc-highlight">The Concurrent Loops</a></li><li><a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#rabbit-hole-of-complexity" class="table-of-contents__link toc-highlight">Rabbit Hole of Complexity</a></li><li><a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#cutting-the-gordion-knot" class="table-of-contents__link toc-highlight">Cutting the Gordion Knot</a></li><li><a href="https://matrix.ai/learn/blog/builders-trap-escape-loop#principles-are-simple-and-ancient-execution-is-difficult" class="table-of-contents__link toc-highlight">Principles are Simple and Ancient, Execution is Difficult</a></li></ul><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>entrepreneurship</category>
            <category>systems-thinking</category>
            <category>product-market-fit</category>
            <category>complexity</category>
            <category>feedback-loops</category>
        </item>
        <item>
            <title><![CDATA[Strange Attractors and Systems Thinking in Southeast Asia]]></title>
            <link>https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia</link>
            <guid>https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia</guid>
            <pubDate>Sun, 13 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[There are few moments in one's life that reveal a step-inflection in one's]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>There are few moments in one's life that reveal a step-inflection in one's
goals, purpose, telos, actions, even your sense of history. Often these moments
start in strange ways, strange places, and through strange people: "strange
attractors" if you will. It's never immediately clear what impact they'll have
until after reflection, long after the event itself fades from memory.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-cmkl-entrance-640bf7775a38dd63175954fe60f03bf1.webp" width="1024" height="768" class="img_ev3q"></p>
<p>For me, the Khlongs and Subaks workshop in early 2025 was one such strange
attractor. Organized in Bangkok by
<a href="https://seapunkstudios.notion.site/southbeastasia" target="_blank" rel="noopener noreferrer">Seapunk Studios</a> alongside
the Summer of Protocols (an Ethereum Foundation think tank) and
<a href="https://cmkl.ac.th/" target="_blank" rel="noopener noreferrer">Carnegie Mellon’s CMKL University</a>, the event was
ostensibly about exploring real-world coherence and coordination problems
through Southeast Asian anthropology and ethnography. Specifically, we focused
on the Khlongs (canals) in Bangkok and the Subak rice farming cooperatives in
Bali. But beneath the surface, it was something deeper, richer, and more
profoundly strange. A deliberate effort to construct a new Southeast Asian
narrative that bridges blockchain and open distributed AI protocols with
deeply-rooted social and cultural wisdom.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-first-day-1-venkat-d36a2374e29def489ae97bc469d8e16e.webp" width="1024" height="768" class="img_ev3q"></p>
<p>In practice, the workshop became a fascinating collision of diverse disciplines.
Ethnographers chatted with crypto-economists, philosophers mingled with AI
researchers, artists exchanged insights with technologists, and everyone
collectively dove head-first into the complexity of real-world coordination
challenges. This produced a rare confluence with conversations looped between
blockchain consensus algorithms, the nature of Knightian uncertainty,
Wittgenstein's language games, Balinese irrigation rituals, game theory
mechanics, existential tail-risk, Buddhist awareness and cybernetic feedback
loops. It reaffirmed our experience that the world is composed of interconnected
protocols, and that systems thinking is a fundamental tool to understand how the
reality of our vast socio-technical systems actually works, beyond ideological
simplicities and superficial narratives.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-first-day-1-f49b454aa9225dc58115322bb66c9484.webp" width="1024" height="768" class="img_ev3q"></p>
<p>In a time when societies globally are building higher walls to protect
themselves from chaos, here was a group deliberately seeking out the edge of
chaos. Instead of running away, participants leaned in. Instead of holding onto
ideological purity, participants listened. And this is where genuine coherence
happens, not in perfect agreement, but in a mutual willingness to find
connection amidst differences.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-protocol-stories-015bef106edfd217ab0f826c84ee7e68.webp" width="768" height="1024" class="img_ev3q"></p>
<p>Reflecting on the experience, these are some key insights that deeply resonated
with me:</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1-policy-optimizes-legibility-for-simplicity-but-reality-is-often-highly-complex">1. Policy optimizes Legibility for Simplicity, But Reality is often Highly Complex<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#1-policy-optimizes-legibility-for-simplicity-but-reality-is-often-highly-complex" class="hash-link" aria-label="Direct link to 1. Policy optimizes Legibility for Simplicity, But Reality is often Highly Complex" title="Direct link to 1. Policy optimizes Legibility for Simplicity, But Reality is often Highly Complex">​</a></h2>
<p>Effective policy requires a clear understanding (legibility) of the system it
governs. Without it, symbols disconnect from reality. This is the world James C.
Scott describes in The Art of Not Being Governed, where states constantly try to
make complex, organic societies legible to better tax and control them. The
Balinese subak system is the perfect counterexample. For centuries, its
adaptive, self-organizing nature was inherently illegible to outsiders. When the
"Green Revolution" imposed a legible, top-down agricultural model, it shattered
this delicate balance, leading to "chaos in irrigation and devastating losses
from pests." The lesson is that true understanding requires embracing
complexity, not forcing simplicity upon it.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-lily-pads-2a8728918e3172e4a51fb02a2dc9daf7.webp" width="1024" height="768" class="img_ev3q"></p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2-coordination-without-full-coherence-is-the-only-way-to-scale">2. Coordination Without Full Coherence is the Only Way to Scale<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#2-coordination-without-full-coherence-is-the-only-way-to-scale" class="hash-link" aria-label="Direct link to 2. Coordination Without Full Coherence is the Only Way to Scale" title="Direct link to 2. Coordination Without Full Coherence is the Only Way to Scale">​</a></h2>
<p>The idea that everyone needs to be on the same page to cooperate is a fallacy.
The Subak system demonstrates clearly that effective coordination does not
require absolute agreement or perfect centralization. Instead, adaptive, local
rituals and distributed knowledge drive the entire network toward optimal
conditions. Coordination emerges naturally, not through forcing everyone onto a
single "global blockchain" of understanding, but through conscious, intentional
shards of understanding—much like validator nodes in a distributed network.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-khlong-management-28affdd59229a6ccf55437ede2e14a51.webp" width="1024" height="768" class="img_ev3q"></p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3-the-principal-agent-problem-is-the-original-alignment-problem">3. The Principal-Agent Problem is the Original Alignment Problem<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#3-the-principal-agent-problem-is-the-original-alignment-problem" class="hash-link" aria-label="Direct link to 3. The Principal-Agent Problem is the Original Alignment Problem" title="Direct link to 3. The Principal-Agent Problem is the Original Alignment Problem">​</a></h2>
<p>Aligning the incentives of individuals (agents) with the goals of a collective
(the principal) is the fundamental challenge of any organization, whether human
or artificial. The Subaks are a masterclass in solving this. Through a
combination of shared economic incentives (maximizing harvests), ritualistic
commitment, and social pressure, they align hundreds of farmers into a cohesive
unit. This provides a powerful historical analog for modern crypto-economic
design and the AI alignment problem.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="4-crypto-economic-experiments-enable-real-world-testing-of-economic-theories">4. Crypto-Economic Experiments enable Real-World Testing of Economic Theories<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#4-crypto-economic-experiments-enable-real-world-testing-of-economic-theories" class="hash-link" aria-label="Direct link to 4. Crypto-Economic Experiments enable Real-World Testing of Economic Theories" title="Direct link to 4. Crypto-Economic Experiments enable Real-World Testing of Economic Theories">​</a></h2>
<p>Economists have dreamed of field-testing theories for decades, and
crypto-economics now provides the lab. The workshop affirmed my belief that
crypto-economic experimentation is the frontier for innovation in governance and
economics. The next Nobel Prize in Economics might just come from the ecosystem
of decentralized autonomous organizations.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-khlong-solar-5d193e7160dd6365868ad9b027a57e09.webp" width="691" height="389" class="img_ev3q"></p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="5-narrative-and-meaning-engineering-is-societys-operating-system">5. Narrative and Meaning Engineering is Society's Operating System<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#5-narrative-and-meaning-engineering-is-societys-operating-system" class="hash-link" aria-label="Direct link to 5. Narrative and Meaning Engineering is Society's Operating System" title="Direct link to 5. Narrative and Meaning Engineering is Society's Operating System">​</a></h2>
<p>Contradictions within societal narratives signal latent incoherence that can
lead to rupture. Narrative engineering, like the kind we attempted at this
workshop, helps societies consciously resolve contradictions before rupture
occurs. It’s a proactive maintenance for the societal OS.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="6-rupture-is-where-agency-thrives">6. Rupture is Where Agency Thrives<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#6-rupture-is-where-agency-thrives" class="hash-link" aria-label="Direct link to 6. Rupture is Where Agency Thrives" title="Direct link to 6. Rupture is Where Agency Thrives">​</a></h2>
<p>Every rupture, every symmetry break, is an opportunity to build new meaning.
However, seizing this moment demands real agency and a deep understanding of the
dynamics that held the previous system together. Rupture without understanding
leads to chaos, but rupture with agency leads to renewal.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-digital-humanities-visualisation-68a691c70656d0b00a32e28ddb5346f1.webp" width="691" height="389" class="img_ev3q"></p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="7-our-meaning-architectures-are-inherited-but-malleable">7. Our Meaning Architectures are Inherited but Malleable<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#7-our-meaning-architectures-are-inherited-but-malleable" class="hash-link" aria-label="Direct link to 7. Our Meaning Architectures are Inherited but Malleable" title="Direct link to 7. Our Meaning Architectures are Inherited but Malleable">​</a></h2>
<p>Our social consensus mechanisms aren't fundamental, they're socially constructed
and adaptable, influenced by incentives and structures. Human behavior is more
flexible than we realize, yet agency remains our most resilient spark.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="8-history-holds-actionable-protocols-not-just-stories">8. History Holds Actionable Protocols, Not Just Stories<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#8-history-holds-actionable-protocols-not-just-stories" class="hash-link" aria-label="Direct link to 8. History Holds Actionable Protocols, Not Just Stories" title="Direct link to 8. History Holds Actionable Protocols, Not Just Stories">​</a></h2>
<p>Thai Khlongs and Balinese Subaks aren't just fascinating stories; they're living
examples of sociocultural and governance infrastructure. Their wisdom isn't in
the tale but in the practical protocol that has functioned for generations.
These are living blueprints for decentralized resource allocation and conflict
resolution.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="9-daoist-insight-the-low-lands-over-the-high-lands">9. Daoist Insight: "The Low Lands Over the High Lands."<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#9-daoist-insight-the-low-lands-over-the-high-lands" class="hash-link" aria-label="Direct link to 9. Daoist Insight: &quot;The Low Lands Over the High Lands.&quot;" title="Direct link to 9. Daoist Insight: &quot;The Low Lands Over the High Lands.&quot;">​</a></h2>
<p>Water flows to the lowest point, where life and nutrients gather. The workshop
felt like this Daoist principle made manifest: a conceptual "low-land," fertile
ground where different streams of thought and expertise flowed together. The
purpose wasn’t domination by one perspective but relational coherence for all
perspectives.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="10-narrative-consensus-is-slow-methodical-and-necessary">10. Narrative Consensus is Slow, Methodical, and Necessary<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#10-narrative-consensus-is-slow-methodical-and-necessary" class="hash-link" aria-label="Direct link to 10. Narrative Consensus is Slow, Methodical, and Necessary" title="Direct link to 10. Narrative Consensus is Slow, Methodical, and Necessary">​</a></h2>
<p>In a world enamored with speed, the deepest and most resilient shifts come
slowly. Building new narratives is painstaking and deliberate work. There are no
shortcuts, only patient, continuous engagement with complexity.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="11-ai-is-a-coherence-engine-hallucinations-are-features-not-bugs">11. AI is a Coherence Engine. Hallucinations are Features, not Bugs.<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#11-ai-is-a-coherence-engine-hallucinations-are-features-not-bugs" class="hash-link" aria-label="Direct link to 11. AI is a Coherence Engine. Hallucinations are Features, not Bugs." title="Direct link to 11. AI is a Coherence Engine. Hallucinations are Features, not Bugs.">​</a></h2>
<p>One unexpected insight was re-framing AI's hallucinations as necessary functions
rather than defects.
<a href="https://aibuddy.software/coherence-confirmed-llms-arent-thinking-theyre-coherent/" target="_blank" rel="noopener noreferrer">They reveal latent connections within concept-space, surfacing hidden coherence</a>.
AI's power as a coherence engine lies precisely in its ability to hypercut
through the n-dimensional space of meaning.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="airloom-a-protocol-for-intentionality">Airloom: A Protocol for Intentionality<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#airloom-a-protocol-for-intentionality" class="hash-link" aria-label="Direct link to Airloom: A Protocol for Intentionality" title="Direct link to Airloom: A Protocol for Intentionality">​</a></h2>
<p>The synthesis of these insights led not to a whitepaper, but to a new technical
and social artifact that we call the Airloom (AI + Heirloom). It addresses a
fundamental gap in our current technology stack: the inability to encode,
transmit, and steward intention over time.</p>
<p>Where an NFT provides verifiable proof-of-ownership and a digital twin models
state and performance, the Airloom provides verifiable proof-of-meaning. It is a
protocol designed to anchor the telos, the purpose, spirit, and narrative
intent, of a system into a non-fungible, real-world artifact or place.</p>
<p>Functionally, an Airloom is a cybernetic system that bridges the physical and
digital through three components:</p>
<ol>
<li>The Vessel: A unique physical object or demarcated geographical space. This
is the tangible anchor: a carved artifact, a specific tree in a forest, a
foundational stone in a building. Its non-fungibility is based in physical
reality.</li>
<li>The Sensorium: A suite of sensors and data oracles that capture relevant
information about the Vessel and its context. For a forest Airloom, this
could be IoT sensors monitoring soil health and biodiversity. For an
institutional Airloom, it could be oracles tracking on-chain governance
decisions and off-chain community sentiment.</li>
<li>The Anima: A specialized AI model that acts as the guardian of the Airloom's
meaning. The Anima's role is not just to process data, but to interpret it in
the context of the system's founding charter or stated intention. It performs
two key functions:<!-- -->
<ul>
<li>Conservation: It serves as a living archive, weaving sensor data, oral
histories, and documented events into a persistent, evolving narrative.
This memory extends beyond human lifetimes.</li>
<li>Adaptability: It monitors for "intentional drift", actions or environmental
changes that deviate from the Airloom's core purpose. By surfacing these
deviations, it acts as a Schelling point for stewardship, prompting the
community (the stewards) to either correct course or consciously evolve the
original intention.</li>
</ul>
</li>
</ol>
<p>The Airloom, therefore, gives a system presence and memory. It creates a
feedback loop between a community's actions and its stated purpose, making its
constitutional principles legible and actionable.</p>
<p>By anchoring this AI-powered intentionality in a physical object, the Airloom
protocol resists pure digital abstraction. It is a direct counter-proposal to
technology that alienates us from our environment. It is an infrastructure for
encoding the priceless, stewarding the sacred, and enabling conservation and
adaptation across generations. This is the pivot from crypto-economics to
meaning-tech: a stack for engineering our values directly into the world.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="a-protocol-for-generating-new-protocols">A Protocol for Generating New Protocols<a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#a-protocol-for-generating-new-protocols" class="hash-link" aria-label="Direct link to A Protocol for Generating New Protocols" title="Direct link to A Protocol for Generating New Protocols">​</a></h2>
<p>Looking back, workshops like the Khlongs and Subaks ended up being a protocol
for generating new protocols. A strange attractor, pulling disparate elements of
our world into a coherent shape. It reaffirmed what I’ve always sensed deeply:
the profound interconnectedness of everything, and how the subtle interactions
at the edge of chaos are where new worlds begin.</p>
<p>If you're wired to think this way: systems-thinking, recognizing fractal
patterns across diverse contexts, unafraid of complexity and contradiction, you
might just find your tribe here.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/khlong-subaks-reflection-2a6bab38c6b6bdb9def6a74add99606c.webp" width="1024" height="768" class="img_ev3q"></p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#1-policy-optimizes-legibility-for-simplicity-but-reality-is-often-highly-complex" class="table-of-contents__link toc-highlight">1. Policy optimizes Legibility for Simplicity, But Reality is often Highly Complex</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#2-coordination-without-full-coherence-is-the-only-way-to-scale" class="table-of-contents__link toc-highlight">2. Coordination Without Full Coherence is the Only Way to Scale</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#3-the-principal-agent-problem-is-the-original-alignment-problem" class="table-of-contents__link toc-highlight">3. The Principal-Agent Problem is the Original Alignment Problem</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#4-crypto-economic-experiments-enable-real-world-testing-of-economic-theories" class="table-of-contents__link toc-highlight">4. Crypto-Economic Experiments enable Real-World Testing of Economic Theories</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#5-narrative-and-meaning-engineering-is-societys-operating-system" class="table-of-contents__link toc-highlight">5. Narrative and Meaning Engineering is Society's Operating System</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#6-rupture-is-where-agency-thrives" class="table-of-contents__link toc-highlight">6. Rupture is Where Agency Thrives</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#7-our-meaning-architectures-are-inherited-but-malleable" class="table-of-contents__link toc-highlight">7. Our Meaning Architectures are Inherited but Malleable</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#8-history-holds-actionable-protocols-not-just-stories" class="table-of-contents__link toc-highlight">8. History Holds Actionable Protocols, Not Just Stories</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#9-daoist-insight-the-low-lands-over-the-high-lands" class="table-of-contents__link toc-highlight">9. Daoist Insight: "The Low Lands Over the High Lands."</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#10-narrative-consensus-is-slow-methodical-and-necessary" class="table-of-contents__link toc-highlight">10. Narrative Consensus is Slow, Methodical, and Necessary</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#11-ai-is-a-coherence-engine-hallucinations-are-features-not-bugs" class="table-of-contents__link toc-highlight">11. AI is a Coherence Engine. Hallucinations are Features, not Bugs.</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#airloom-a-protocol-for-intentionality" class="table-of-contents__link toc-highlight">Airloom: A Protocol for Intentionality</a></li><li><a href="https://matrix.ai/learn/blog/strange-attractors-systems-thinking-southeast-asia#a-protocol-for-generating-new-protocols" class="table-of-contents__link toc-highlight">A Protocol for Generating New Protocols</a></li></ul><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>systems-thinking</category>
            <category>protocols</category>
            <category>southeast-asia</category>
            <category>narrative-engineering</category>
            <category>crypto-economics</category>
        </item>
        <item>
            <title><![CDATA[Centralized Value Extraction vs Decentralized Value Sharing]]></title>
            <link>https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing</link>
            <guid>https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing</guid>
            <pubDate>Sun, 01 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[In a perfect free market, prices naturally gravitate toward their]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>In a perfect free market, prices naturally gravitate toward their
<a href="https://en.wikipedia.org/wiki/Marginal_cost" target="_blank" rel="noopener noreferrer">marginal cost of production</a>. This
principle ensures fairness in exchanges but poses a significant challenge for
businesses: how can they sustain profitability in a system where competition
drives pricing to the bare minimum? This question lies at the heart of the
tension between centralized and decentralized economic models. Centralization
often arises as a solution to overcome these challenges by creating defensible
moats and mechanisms for value extraction, but it also leads to power
consolidation and extractive economies. Decentralized systems, by contrast,
offer an alternative path, emphasizing shared value and equitable distribution
through innovative coordination mechanisms.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-economic-problem-defensible-moats-and-profit-extraction">The Economic Problem: Defensible Moats and Profit Extraction<a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#the-economic-problem-defensible-moats-and-profit-extraction" class="hash-link" aria-label="Direct link to The Economic Problem: Defensible Moats and Profit Extraction" title="Direct link to The Economic Problem: Defensible Moats and Profit Extraction">​</a></h2>
<p>In order to maintain long-term profitability, businesses develop a
<a href="https://www.investopedia.com/terms/e/economicmoat.asp" target="_blank" rel="noopener noreferrer">"defensible moat"</a>. This
strategic advantage allows businesses to extract value beyond marginal costs,
achieving what is known as economic profit. Centralized business models rely
heavily on this approach, where a central point of control orchestrates all
economic inputs and outputs to establish and maintain dominance.</p>
<p>Through mechanisms of control and the creation of scarcity (whether real or
artificial), centralized businesses generate
<a href="https://www.investopedia.com/terms/n/non-zero-sum-game.asp" target="_blank" rel="noopener noreferrer">non-zero-sum value</a>,
expanding the overall value pie. However, this structure inherently incentivizes
profit extraction from users rather than value sharing. Efficiency gains are
often redirected to owners, not customers, unless competitive forces compel
otherwise. A clear example of this can be seen in the airline industry, where
cost-cutting measures often lead to higher shareholder returns but negligible
improvements in customer pricing.</p>
<p>Consider this: centralized platforms prioritize fortifying their monopoly power.
For example, major e-commerce platforms use data-driven insights and economies
of scale to undercut smaller competitors, maximizing pricing control and
eliminating threats to their dominance. In the absence of robust competition or
viable substitutes, this approach invariably leads to
<a href="https://en.wikipedia.org/wiki/Capitalism,_Socialism_and_Democracy" target="_blank" rel="noopener noreferrer">extractive economies</a>.
Centralized systems, by design, tilt incentives toward consolidating control,
often at the expense of broader value distribution.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="centralization-in-software-economics">Centralization in Software Economics<a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#centralization-in-software-economics" class="hash-link" aria-label="Direct link to Centralization in Software Economics" title="Direct link to Centralization in Software Economics">​</a></h2>
<p>The software industry provides a stark example of centralization’s effects,
particularly in its approach to sustaining profitability through artificial
scarcity. Since 2018, companies such as MongoDB, Confluent, HashiCorp, and
Dgraph Labs have implemented changes to their open-source licenses to prevent
cloud providers like AWS from capturing most of the value their software
generates. These changes gave rise to the
<a href="https://spdx.org/licenses/BUSL-1.1.html" target="_blank" rel="noopener noreferrer">Business Source License (BSL)</a>, which
introduced restrictions aimed at preserving these companies’ ability to monetize
their software as a service.</p>
<p>Without these restrictions, open-source cores often become marketing tools for
proprietary services, eventually abandoned in favor of products that generate
direct revenue. For example, Nginx operates as an open-source web server, but
the company behind it also offers Nginx Plus, a proprietary version with
additional features and enterprise support. This model allows the open-source
version to drive adoption, while the proprietary version becomes the main
revenue source. Alternatively, businesses that rely on enterprise support as
their primary income face incentives to overcomplicate their software, making it
difficult for users to operate independently and effectively locking them into
expensive "solution engineer" services.</p>
<p>This underscores a broader issue: funding for significant open-source projects
is rarely decentralized. Donations, while laudable, fail to provide the
sustainable funding needed. As a result, centralized artificial scarcity becomes
a default mechanism for profit extraction. However, the research and development
process itself is inherently scarce—it requires labor, energy, and equipment,
all of which must be compensated. Once software is created, its marginal cost of
reproduction drops to zero, creating a unique economic challenge. Non-software
businesses, which charge per unit of output, avoid this dilemma entirely.</p>
<p><img decoding="async" loading="lazy" alt="Case in point, a comment how one funds an open-source LLM memory library" src="https://matrix.ai/assets/images/hacker_news_comment_about_opensource_commercialization-f4e9100b6b0cce93cc03f4c5c4353a1a.jpg" width="1080" height="897" class="img_ev3q"></p>
<p>There are parallels to industries such as pharmaceuticals, where high upfront
costs for research and development are offset by low production costs post-
discovery. Similarly, open-source businesses grapple with monetizing significant
investment without creating exploitative models. For instance, infrastructure
software like OpenSSL delivers immense value globally but struggles to capture
enough to fund its development adequately.</p>
<p><img decoding="async" loading="lazy" src="https://imgs.xkcd.com/comics/dependency.png" alt="OpenSSL holds up the internet, yet was maintained by 1 guy?" class="img_ev3q"></p>
<p>This dynamic raises a key question: Are open-source businesses a temporary
phenomenon - a stopgap until the socio-technological environment matures—or can
they evolve into models that sustainably balance decentralization and
innovation?</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="decentralized-alternatives">Decentralized Alternatives<a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#decentralized-alternatives" class="hash-link" aria-label="Direct link to Decentralized Alternatives" title="Direct link to Decentralized Alternatives">​</a></h2>
<p>The limitations of centralized systems in software development and beyond point
to the need for innovative approaches that prioritize fairness and shared value.
Decentralized systems offer a compelling alternative by aligning incentives
among all participants and enabling new governance models. These systems
challenge monopolistic tendencies by leveraging technologies like blockchain and
DAOs, which provide frameworks for large-scale coordination and equitable value
distribution.</p>
<p>Economics hinges on aligning incentives to coordinate resource use effectively.
Decentralized systems - particularly in the crypto space - are forging new paths
in economic governance, offering exciting opportunities for small-scale economic
experimentation and scaling. These systems challenge centralized monopolies,
which often rely on regulatory oversight - a system prone to
<a href="https://www.investopedia.com/terms/r/regulatory-capture.asp" target="_blank" rel="noopener noreferrer">regulatory capture</a>.
By design, decentralized alternatives align incentives more equitably among
participants, fostering innovation and fair resource distribution.</p>
<p>Decentralized Autonomous Organizations (DAOs), for example, demonstrate that
large-scale coordination and capital accumulation are achievable without
centralized authority. Meanwhile, emerging technologies like solar panels,
batteries, and blockchain protocols are transforming industries previously
constrained by traditional centralization. These decentralized innovations
provide models for alternative energy systems, finance, and digital services.</p>
<ol>
<li><strong>Cryptocurrencies vs Visa, Mastercard, and Government-Issued Currencies</strong>
Cryptocurrencies redefine value transfer by enabling decentralized,
peer-to-peer transactions without intermediaries. Unlike centralized systems
like Visa, Mastercard, or national currencies managed by central banks,
cryptocurrencies operate on networks immune to manipulation or control by a
single entity. This ensures transparency, neutrality, and resistance to
censorship, making them truly global and borderless. While critics argue that
cryptocurrencies lack intrinsic value because they aren't backed by
governments, this is precisely their strength. Their independence from
central authority protects them from inflation, sanctions, and political
interference, offering a neutral and fair alternative for transferring and
storing value. Networks like Bitcoin's Lightning or Ethereum’s Layer 2
solutions (e.g., Arbitrum, Optimism) enhance scalability and cost-efficiency,
enabling decentralized systems to compete directly with traditional payment
systems. By removing centralized control, cryptocurrencies empower
individuals and create a resilient financial ecosystem that prioritizes
accessibility and fairness over monopoly and control.</li>
<li><strong>Radicle vs GitHub</strong> Radicle enables peer-to-peer code collaboration without
central ownership, standing in stark contrast to Microsoft-owned GitHub. By
decentralizing repository hosting, Radicle resists censorship and unilateral
policy changes, empowering developers directly.</li>
<li><strong>Aave vs Banks</strong> Aave’s decentralized finance (DeFi) protocol facilitates
collateralized lending without the need for traditional banking
intermediaries. This model democratizes access to financial services,
reducing barriers and fees.</li>
<li><strong>DEXs vs Centralized Exchanges</strong> Decentralized exchanges (DEXs) such as
Uniswap allow users to trade directly with one another through smart
contracts, eliminating the risks associated with centralized authorities like
hacks and regulatory interference.</li>
<li><strong>IPFS/Filecoin vs AWS S3</strong> IPFS and Filecoin offer decentralized,
distributed data storage solutions that challenge the centralized dominance
of cloud providers like AWS. These protocols enhance resilience and
censorship resistance.</li>
<li><strong>Helium vs Telecom Networks</strong> Helium’s model incentivizes individuals to
deploy wireless hotspots, creating decentralized networks for IoT devices and
reducing infrastructure costs compared to traditional telecom networks.</li>
<li><strong>Rarible vs Centralized Marketplaces</strong> Rarible’s community-governed NFT
marketplace decentralizes power, allowing creators and users to shape its
development and decision-making processes. This contrasts with extractive
centralized platforms.</li>
<li><strong>Arcade City vs Uber</strong> Arcade City decentralizes ridesharing, enabling
drivers and riders to negotiate directly without the intermediation of a
corporate entity, thereby redistributing power and value.</li>
<li><strong>Akash Network vs AWS</strong> Akash offers a decentralized cloud computing
marketplace, allowing data centers to rent excess computing power. This
reduces costs and fosters a more competitive and censorship-resistant cloud
ecosystem.</li>
<li><strong>Arweave vs Cloudflare</strong> Arweave ensures permanent, tamper-proof data
storage via a decentralized network, directly challenging centralized
content delivery networks like Cloudflare.</li>
<li><strong>Ethereum Name Service (ENS) vs DNS</strong> The Ethereum Name Service (ENS)
offers a decentralized alternative to the traditional Domain Name System
(DNS). ENS uses blockchain technology to create a trustless system for
domain name registration, giving users complete ownership and control over
their domain names. This decentralization reduces the risks of censorship
and domain seizure, making ENS a more secure and resilient option for the
future of web infrastructure.</li>
<li><strong>Network State Coliving Spaces vs Traditional Rental Models</strong> Network State
coliving spaces present a potential new model for community governance and
capitalization. Unlike traditional rental arrangements, these spaces enable
users to hold a stake in their living environments, fostering better
liquidity, transparency, and automation. While similar to existing co-op
structures, Network State coliving leverages blockchain technology to align
incentives and streamline governance. This creates a more dynamic housing
model where value is not merely extracted as rent but reinvested to benefit
all participants, transforming housing from a commodity to a collaborative
ecosystem.</li>
<li><strong>Solar Panels, Batteries and Micro Grids vs Traditional Power Companies</strong>
Decentralized energy solutions, often categorized under DePin (Decentralized
Physical Infrastructure Networks), leverage solar panels, battery storage,
and <a href="https://en.wikipedia.org/wiki/Distributed_generation" target="_blank" rel="noopener noreferrer">microgrids</a> to
empower communities and individuals to generate, store, and trade energy
independently of traditional power companies. These systems enable localized
energy production, peer-to-peer trading, and grid resilience by isolating
from centralized systems during outages. DePin energy solutions use
blockchain technology for transparent transactions, dynamic pricing, and
equitable energy distribution. In contrast, traditional power companies
operate centralized infrastructures prone to inefficiencies, monopolistic
pricing, and large-scale outages. By democratizing energy access and
fostering innovation, decentralized energy networks promote sustainability
and empower communities to achieve energy independence.</li>
<li><strong>Public Goods Funding via Quadratic Funding vs Taxes/Donations</strong>
<a href="https://www.wtfisqf.com/" target="_blank" rel="noopener noreferrer">Quadratic funding (QF)</a> introduces a
decentralized, community-driven alternative to funding public goods,
contrasting with traditional models like taxes or donations. Platforms such
as <a href="https://explorer.gitcoin.co/#/round/42161/609/42" target="_blank" rel="noopener noreferrer">Gitcoin</a> and
<a href="https://www.drips.network/" target="_blank" rel="noopener noreferrer">Drips Network</a> allocates resources more
equitably by amplifying contributions from a broad base of smaller donors.
This ensures that funding decisions reflect the preferences of the many
rather than the influence of a few large contributors. Unlike taxes, which
rely on centralized government allocation, or donations, which can be
sporadic and opaque, QF maximizes impact through transparent and democratic
funding mechanisms. By incentivizing widespread participation, quadratic
funding aligns incentives to efficiently support shared resources and public
goods, demonstrating the power of decentralized solutions in fostering
collective well-being.</li>
</ol>
<p>Decentralized systems excel in turning centralized weaknesses into opportunities
for innovation. One of the most revolutionary aspects of decentralized systems
is their inherent openness. Unlike traditional centralized platforms that thrive
on competition and work to create defensible moats, decentralized systems
encourage cooperation. These systems are built on the idea of interoperability
and the ability to build value on top of existing platforms rather than tearing
them down.</p>
<p>In the traditional startup ecosystem, "creative destruction" or "disruption" is
often seen as a driving force—new technologies emerge, old ones are destroyed,
and market leaders are replaced. However, in decentralized ecosystems, the focus
shifts from destruction to cooperation.
<a href="https://ethereum.org/en/developers/docs/bridges/" target="_blank" rel="noopener noreferrer">Cross-chain technologies</a> are
a prime example of this. They enable different blockchain networks to
communicate and interact, allowing value to flow freely across different
systems. This means that instead of replacing older systems, new decentralized
platforms can build upon and enhance them, creating additional value without the
need for destructive competition.</p>
<p>As
<a href="https://www.lynalden.com/open-networks/" target="_blank" rel="noopener noreferrer">Lyn Alden discusses in her post about open networks</a>,
these systems operate on principles of openness and interoperability, allowing
multiple networks to coexist and complement each other rather than compete
destructively. This cooperative nature of decentralized systems may also mean
that decentralized monopolies, if they ever form, would look very different from
traditional monopolies. In a decentralized ecosystem, even if a platform becomes
dominant, its open nature means that other platforms can still interact and
build upon it, reducing the risk of extractive practices. The result is a system
where value is continuously created and shared, rather than concentrated and
extracted.</p>
<p>One of the most intriguing aspects of decentralized systems is their ability to
enable small-scale economic experiments that were previously impossible under
centralized frameworks. These experiments allow developers and entrepreneurs to
test new ideas, governance models, and economic incentives on a smaller scale
before scaling them up.</p>
<p>For instance, while Arcade City and Origin Protocol faced challenges and paused
their development, the experiments they initiated laid the groundwork for future
decentralized platforms. These trials contribute valuable insights and refine
the underlying concepts, which are likely to be reattempted with adjustments to
smart contract models and incentive structures. When these decentralized
alternatives succeed, they often have greater longevity than centralized
systems, which can be abruptly shut down or altered by their owners.</p>
<p>This potential for enduring success is rooted in the decentralized model itself,
where control is distributed, and the community plays an active role in
governance. As a result, decentralized platforms are more resilient to the whims
of single entities and more adaptable to the evolving needs of their users.
These systems, especially in the context of emerging blockchain
technologies—enable economic coordination without central authority. Unlike
centralized models, where value is often extracted from users, decentralized
alternatives focus on generating value through the enhancement and maintenance
of the protocol itself. Users, incentivized through ownership, have a vested
interest in the protocol’s success, aligning incentives across the ecosystem.
When done effectively, decentralized systems promote value creation and
equitable sharing rather than extractive practices.</p>
<p>Two-sided marketplaces like Airbnb, Uber, and eBay illustrate the centralization
problem vividly. These platforms thrive on network effects, where their value
grows as more users (buyers and sellers, drivers and riders, hosts and guests)
participate. However, they are centralized entities that extract value by
imposing fees and commissions. Decentralization offers a compelling alternative
by reducing dependence on extractive intermediaries, allowing for fairer value
distribution and governance by participants themselves.</p>
<p>Centralization, while advantageous for managing economies of scale, often leads
to power consolidation, which increases the risk of corruption and value
extraction. However, decentralization introduces its own set of challenges,
including scalability, user adoption, and governance complexities. These systems
require robust coordination mechanisms to avoid inefficiencies and ensure
equitable value flows. Yet, recent advancements in blockchain technologies,
smart contracts, and decentralized governance models demonstrate that these
challenges can be mitigated. When implemented effectively, decentralization not
only addresses power consolidation but also fosters innovation and resilience by
aligning incentives across a distributed network.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="crypto-economic-experiments">Crypto-Economic Experiments<a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#crypto-economic-experiments" class="hash-link" aria-label="Direct link to Crypto-Economic Experiments" title="Direct link to Crypto-Economic Experiments">​</a></h2>
<p>At Matrix AI, we are actively exploring crypto-economic experiments using
protocols like AAVE, Rocketpool, and Polykey as part of our broader
investigation into decentralized systems.</p>
<p><a href="https://polykey.com/" target="_blank" rel="noopener noreferrer">Polykey</a>, a decentralized secrets manager could evolve
into a robust decentralized trust infrastructure. This infrastructure would
incentivize not only the creation and maintenance of trust claims but also their
verification and reputation management. By leveraging open reputation systems,
Polykey could enable cross-border credit rails for world-wide peer-to-peer
undercollateralized micro-loans, fostering trust and enabling financial
inclusion at a global scale. Additionally, Polykey aligns with models like
Gitcoin for public goods funding, where decentralized reputation systems ensure
transparent allocation of resources. This vision extends to Polykey's
<a href="https://polykey.com/docs/theory/decentralized-trust-network" target="_blank" rel="noopener noreferrer">Decentralized Trust Network</a>,
designed to coordinate trust and claims across a global, decentralized network,
addressing enterprise needs while expanding into public authority applications
with scalable and transparent solutions.</p>
<p>Our <a href="https://zeta.house/" target="_blank" rel="noopener noreferrer">Zeta House</a> project exemplifies how Matrix AI applies
decentralized principles in the real world. In the future, Zeta House aims to
expand into broader decentralized governance models. By enabling residents to
hold stakes in their living spaces, Zeta House fosters community ownership,
enhances liquidity, and ensures transparent governance. This approach bridges
theoretical decentralized models with tangible outcomes, offering insights into
the challenges and opportunities of implementing decentralized systems in
everyday life. Future milestones include expanding its operational framework and
integrating blockchain-based governance tools to further align resident
incentives with shared goals.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#the-economic-problem-defensible-moats-and-profit-extraction" class="table-of-contents__link toc-highlight">The Economic Problem: Defensible Moats and Profit Extraction</a></li><li><a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#centralization-in-software-economics" class="table-of-contents__link toc-highlight">Centralization in Software Economics</a></li><li><a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#decentralized-alternatives" class="table-of-contents__link toc-highlight">Decentralized Alternatives</a></li><li><a href="https://matrix.ai/learn/blog/centralized-value-extraction-vs-decentralized-value-sharing#crypto-economic-experiments" class="table-of-contents__link toc-highlight">Crypto-Economic Experiments</a></li></ul><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>decentralization</category>
            <category>value-extraction</category>
            <category>crypto</category>
            <category>economics</category>
        </item>
        <item>
            <title><![CDATA[Content Commoditization and Trust in the Bot Era]]></title>
            <link>https://matrix.ai/learn/blog/content-commoditization-and-trust-in-the-bot-era</link>
            <guid>https://matrix.ai/learn/blog/content-commoditization-and-trust-in-the-bot-era</guid>
            <pubDate>Thu, 29 Aug 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Welcome to the era where AI isn't just augmenting our lives; it's beginning to]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Welcome to the era where AI isn't just augmenting our lives; it's beginning to
commoditize our very thoughts, creations, and even our conversations. In this
world, the bots don't just talk, they create, consume, and regurgitate content
with such efficiency that the lines between original and synthetic blur. And, as
this happens, something profound shifts in the digital landscape. Trust becomes
the new currency.</p>
<p>We've all witnessed it. The explosion of AI-driven content generators, from
GPT-4 and Claude to specialized coding bots like Aider, is transforming how
content is created. These tools can whip up an article, solve complex coding
problems, and even generate entire software modules, faster and cheaper than
ever. This isn't just a revolution in productivity; it's a fundamental shift
towards the commoditization of content itself.</p>
<p>For example, a colleague in clean energy consulting recently swapped original
research for ChatGPT, using it as the foundation of all his presentations. The
efficiency gains are undeniable, but so is the loss of originality. It's no
longer about uncovering new insights; it's about remixing existing ones to suit
the needs of the moment. And if we, as engineers, are honest with ourselves, how
many of us have shifted from Stack Overflow to ChatGPT for problem-solving? The
reliance on AI-generated content is becoming ubiquitous. It's just more specific
and more convenient.</p>
<p>With everyone relying on AI to generate and consume content, a new question
arises: what's the incentive to create human generated content if it's just
going to be absorbed into the AI ecosystem? Bots consuming bots, an idea once
relegated to dystopian fiction, is quickly becoming a reality. Content is
generated, spliced, repurposed, and consumed, often without credit, copyright,
or even a hint of authorship. It's content stripped down to its purest
form—knowledge, ready for consumption, free from the constraints of origin.</p>
<p>This leads us to the "Dead Internet Theory" a concept where much of the
Internet's content could soon be generated by AI, with humans playing a minimal
role. More than a decade ago, I joked about creating an AI called Singularity to
flood social networks with AI-generated noise until they collapsed. This is our
reality now.</p>
<p>It is a world where LLM Optimisation (LLMO) replaces Search Engine Optimisation
(SEO). Where website rankings are entirely irrelevant, because people aren't
going to visit the original source when all consumption and generation of
content will be mediated by AI.</p>
<p>The common retort to this, is that the majority of AI content will be garbage,
and AI garbage/noise will overwhelm the good stuff/the signal. However this is
only a problem when there's no discriminator of signal versus noise. Every
content distribution system is a form of discrimination, that separates the
noise from the signal. And the evidence shows that even before the advent of
LLMs, the majority of content was garbage anyway. The same algorithms that
bubbles up the good content will continue to work even in the world of LLM
generated content. The biggest losers here are those that rely on content alone
to make money. The question that must be asked is: where is the moat?</p>
<p>In a world where content is increasingly commoditized, the value of trust and
authenticity skyrockets. The next wave of technological evolution isn't just
about better AI; it's about creating systems that ensure the authenticity and
provenance of the content we consume. At Matrix AI, we envision tools like
Polykey becoming the decentralized trust infrastructure that democratizes access
to provenance tooling for everyone. Forget blue checkmarks; we’re talking about
a system where the very fabric of content is interwoven with verifiable trust.</p>
<p>We're moving towards an era where trust isn't just an add-on but a necessity.
Imagine a future where every piece of content, every line of code, and every
article is backed by an indelible record of its origin and modifications. That's
where we're headed, and it's going to redefine how we interact with the digital
world.</p>
<p>As we stand on the brink of this new era, it's essential to ask ourselves: How
will we adapt? How will we maintain the balance between innovation and
authenticity? The AI-driven commoditization of content is here to stay, but so
is the growing demand for trust and provenance. We believe that the
technological tools we're developing today, like Polykey, will play a pivotal
role in shaping this future.</p>
<p>The bots are taking over, but it’s up to us to ensure that trust remains a
fundamental part of the equation.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>ai</category>
            <category>content-creation</category>
            <category>commoditization</category>
            <category>trust</category>
            <category>provenance</category>
            <category>polykey</category>
        </item>
        <item>
            <title><![CDATA[Our Cybersecurity and Digital Trust Community]]></title>
            <link>https://matrix.ai/learn/blog/cybersecurity-and-digital-trust-meetups</link>
            <guid>https://matrix.ai/learn/blog/cybersecurity-and-digital-trust-meetups</guid>
            <pubDate>Mon, 23 Jan 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Apart from our professional endeavours, we're also committed to building a]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Apart from our professional endeavours, we're also committed to building a
friendly and inviting cybersecurity community here in the Sydney CBD region. We
do regular meetups and talks, where we aim to:</p>
<ul>
<li>Share ideas, best practices, and case studies</li>
<li>Present the latest risks and developments in cybersecurity</li>
<li>Practice cybersecurity problems and solutions</li>
<li>Support each other via networking opportunities and broadening our business
understanding of related topics</li>
</ul>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="diverse-community">Diverse Community<a href="https://matrix.ai/learn/blog/cybersecurity-and-digital-trust-meetups#diverse-community" class="hash-link" aria-label="Direct link to Diverse Community" title="Direct link to Diverse Community">​</a></h2>
<p>As a diverse community of cybersecurity professionals specialising in different
fields, we intend our meetups to be an intersection of our combined knowledge.
We encourage anyone to nominate topics of their fields of interest to discuss
with the rest of us, whether it be technical or business focused, no matter how
niche or mainstream. In all, we strive to create an accessible forum to learn,
share, and connect with like-minded individuals.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="overview">Overview<a href="https://matrix.ai/learn/blog/cybersecurity-and-digital-trust-meetups#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview">​</a></h2>
<p>As a brief overview on what we've covered so far:</p>
<ul>
<li>In our initial meetup we presented
<a href="https://www.slideshare.net/RogerQiu1/cybersecurity-future-risks-zero-trust-and-the-optus-data-leakpdf" target="_blank" rel="noopener noreferrer">Future Risks, Zero Trust, and the Optus Leak</a>.
Through it, we discussed the recent Optus Hack as a case study for the reasons
as to the modern pivot towards Zero Trust architectures in the cybersecurity
industry.</li>
<li>Following this, we discussed the workings of
<a href="https://www.slideshare.net/RogerQiu1/zero-trust-architecture-and-electric-vehicle-cyberrisks" target="_blank" rel="noopener noreferrer">Zero Trust Architecture and Electric Vehicle Cyberrisks</a>,
exploring the workings and possibilities of digital trust through a
foundational understanding of game theory.</li>
<li>To expand on our previous meetup, we discussed causes and risks of Secret
Sprawl, and the implementation of Principle of Least Privilege secrets
management workflows that mitigate this phenomenon.</li>
</ul>
<p>We invite you to join us at future events by signing up to our
<a href="https://www.meetup.com/cybersecurity-digital-trust/" target="_blank" rel="noopener noreferrer">Cybersecurity &amp; Digital Trust Meetup Group</a>.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="https://matrix.ai/learn/blog/cybersecurity-and-digital-trust-meetups#diverse-community" class="table-of-contents__link toc-highlight">Diverse Community</a></li><li><a href="https://matrix.ai/learn/blog/cybersecurity-and-digital-trust-meetups#overview" class="table-of-contents__link toc-highlight">Overview</a></li></ul><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>cybersecurity</category>
            <category>trust</category>
            <category>event</category>
            <category>presentation</category>
        </item>
        <item>
            <title><![CDATA[Matrix AI Deep Learning Training Course Pilot with NetScout (NASDAQ: NTCT)]]></title>
            <link>https://matrix.ai/learn/blog/matrix-ai-deep-learning-training-course-pilot-with-netscout-nasdaq-ntct</link>
            <guid>https://matrix.ai/learn/blog/matrix-ai-deep-learning-training-course-pilot-with-netscout-nasdaq-ntct</guid>
            <pubDate>Thu, 05 Dec 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Over the last several weeks, Matrix AI has been training the senior and]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Over the last several weeks, Matrix AI has been training the senior and
principal software engineers at NetScout (NASDAQ: NTCT) on machine learning with
a focus on deep neural networks.</p>
<div class="row"><div class="col col--6"><p>We piloted our first machine-learning training course in collaboration with NetScout. Over 2.5 weeks, we went through the basics of deep learning:</p><ul>
<li>Statistical Data Exploration</li>
<li>Linear &amp; Logistic Regression</li>
<li>Single Neurons</li>
<li>Multi Layer Neural Networks</li>
<li>Deep Neural Networks</li>
<li>Deep Convolutional Neural Networks</li>
</ul><p>Each topic encompassed practical exercises involving real-life datasets that
were used to demonstrate the concepts of predictive analytics: regression and
classification.</p><p>With the successful completion of this course, Matrix AI has launched a new
product called the Matrix AI Introduction to Deep Learning Course. For more
details see our Training page.</p></div><div class="col col--6"><p><img decoding="async" loading="lazy" alt="Something" src="https://matrix.ai/assets/images/deep_learning_course_gallery-91197932ba458fc3254579541cd4e157.jpg" width="1024" height="1024" class="img_ev3q"></p></div></div>
<p>It is a high-intensity course focused on bringing senior software engineers up
to speed with the latest developments in deep machine learning. This will allow
them to make practical use of machine learning techniques to solve big and small
business data problems.</p>
<blockquote>
<p>Roger's course was a great way to get up to speed on machine learning. The
mathematical concepts introduced really made the subject matter stick. Now, we
are capable of dissecting ML-based research papers, understanding what the
innovations are, and applying them to problems we want to solve. -- David
Turnbull - Principal Software Engineer</p>
</blockquote>
<p>If your company requires leveling up your existing senior software engineers to
be capable of understanding and making use of deep learning technology to solve
real-world business problems, see our course page for more information (link).</p>
<p>Matrix AI is a company that applies Artificial Intelligence to DevOps and Cloud
Infrastructure through the Matrix Operating System. We provide consulting
services in the domain of machine-learning. This mean we help companies develop
end-to-end machine learning infrastructure that encompasses data analysis,
distributed big-data processing pipelines, bespoke information-extraction tools,
deep neural network architectures focused on regression and classification, and
GPU compute orchestration. Our specialty is in computer vision which involves
image classification, object detection, segmentation and geographic information
systems.</p>
<p><img decoding="async" loading="lazy" src="https://matrix.ai/assets/images/deep_learning_class_gallery-87e49701d5f6107e8a7d89460e59e2b7.jpg" width="1456" height="932" class="img_ev3q"></p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>deep-learning</category>
            <category>course</category>
            <category>nasdaq</category>
            <category>netscout</category>
            <category>presentation</category>
        </item>
        <item>
            <title><![CDATA[Common Problems in Image Classification and Object Detection Training]]></title>
            <link>https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection</link>
            <guid>https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection</guid>
            <pubDate>Thu, 12 Sep 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Machine learning for image classification and object detection sounds]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Machine learning for image classification and object detection sounds
straightforward, until you're neck-deep in debugging misclassifications or
training stalls. In this post, we'll unpack some real-world problems we've faced
while working on the
<a href="https://matrix.ai/learn/blog/image-classification-of-solar-inverters-for-asset-compliance-auditing">image classification of solar inverters for asset compliance auditing</a>
and our strategies to tackle them.</p>
<p>Convolutional Neural Networks (CNNs) are an impressive tool, but they aren’t
magic. They’ve got quirks that can lead to subtle bugs or costly inefficiencies
if not accounted for during training. Here's a closer look at some of these
issues and how we dealt with them.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-rotation-invariance-problem">The Rotation Invariance Problem<a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#the-rotation-invariance-problem" class="hash-link" aria-label="Direct link to The Rotation Invariance Problem" title="Direct link to The Rotation Invariance Problem">​</a></h2>
<p>Rotating an image of a solar inverter slightly can throw a classifier off its
game. CNNs don’t natively handle rotations well, as they learn patterns specific
to the orientation seen during training. Our first solution was the obvious one:
augmentation. But adding all possible rotations was computationally expensive
and introduced diminishing returns.</p>
<p>Instead, we built an augmentation pipeline that rotated images to a canonical
orientation before passing them to the classifier. This way, the classifier
could focus on what it does best, detecting features, without being thrown off
by rotations.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-overlapping-class-problem">The Overlapping Class Problem<a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#the-overlapping-class-problem" class="hash-link" aria-label="Direct link to The Overlapping Class Problem" title="Direct link to The Overlapping Class Problem">​</a></h2>
<p>Are two visually identical inverters always the same model? Not when government
compliance regulations step in. This issue arises when classes overlap visually
to the point that even a human would struggle to distinguish them. Our
classifier often struggled with such ambiguity, leading to misclassifications
that were technically correct in appearance but incorrect by regulatory
standards.</p>
<p>To address this, we used a dual strategy of <strong>oversampling underrepresented
classes</strong> and <strong>undersampling overrepresented ones</strong>. For oversampling, we
augmented underrepresented classes with transformations such as rotations,
scaling, and brightness adjustments. This artificially increased the diversity
of these classes in the training dataset, improving the model's ability to
recognize rare variants.</p>
<p>For undersampling overrepresented classes, we turned to a combination of the
Goldberg image similarity metric and the FastPair algorithm. By applying these
tools, we could identify and eliminate redundant images within the same class,
effectively reducing the dominance of overrepresented classes in the dataset.
The Goldberg metric quantifies similarity between images, while FastPair
efficiently computes the dynamic closest pair problem, identifying which images
to remove without excessive computational overhead.</p>
<p>This balanced the class distribution and forced the classifier to learn finer
details that distinguish visually similar but semantically different classes.
The result was a more equitable training set and improved performance across all
classes, especially those prone to overlap.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="the-unary-classification-problem">The Unary Classification Problem<a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#the-unary-classification-problem" class="hash-link" aria-label="Direct link to The Unary Classification Problem" title="Direct link to The Unary Classification Problem">​</a></h2>
<p>Not every image fed into our pipeline contains a solar inverter, some might not
even contain anything useful. Early on, we manually labeled our training set to
include only relevant images. But let’s face it, humans make mistakes, and this
process doesn’t scale.</p>
<p>Our solution was to implement a unary classifier, trained specifically to detect
whether an image contained a solar inverter at all. We based this on the work of
Chalapathy et al. in their paper
<a href="https://arxiv.org/abs/1801.05365" target="_blank" rel="noopener noreferrer">"Learning Deep Features for One-Class Classification"</a>,
which uses a loss function designed around <strong>compactness</strong> and
<strong>descriptiveness</strong>.</p>
<p>These two principles, compactness and descriptiveness, are key to the unary
classification challenge. Compactness ensures that embeddings of "in-class"
samples, like solar inverters, are tightly grouped in the feature space, while
descriptiveness ensures these embeddings remain distinct from all "out-of-class"
samples, representing the vast and unpredictable variety of everything else.</p>
<p>This approach aligns conceptually with loss functions like center loss or
triplet loss. Center loss minimizes intra-class variance by pulling features
closer to their class center, and triplet loss separates embeddings based on
anchor, positive, and negative sample relationships. Similarly, compactness
penalizes embeddings that are too spread out, while descriptiveness works to
maximize separation between the target class and the infinite set of
"non-inverter" samples.</p>
<p>Unary classification is fundamentally different from binary classification.
Binary classifiers have the advantage of defined, balanced categories, allowing
clear decision boundaries to be learned. In unary classification, we deal with
an inherently asymmetrical scenario: one well-defined target class against an
undefined "everything else." This imbalance makes traditional binary loss
functions unsuitable, as they can't account for the boundless diversity of
irrelevant data in the background class.</p>
<p>Training such a model requires overcoming additional challenges. Noise in the
dataset, such as mislabeled examples or edge cases, can confuse the classifier.
Additionally, the dataset needs to be representative of the class's full
variation to ensure robustness. To address this, we augmented our training
dataset with diverse samples of solar inverters captured under varying
conditions, ensuring the model learned the distinguishing features that
generalized well.</p>
<p>By filtering irrelevant data early in the pipeline, the unary classifier acts as
a gatekeeper, passing only relevant images downstream. This saves computational
resources and enhances the efficiency of later tasks, such as fine-grained
classification and object detection. It’s an essential component of building
robust and scalable machine learning pipelines for real-world applications.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="file-systems-arent-just-a-storage-problem">File Systems Aren't Just a Storage Problem<a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#file-systems-arent-just-a-storage-problem" class="hash-link" aria-label="Direct link to File Systems Aren't Just a Storage Problem" title="Direct link to File Systems Aren't Just a Storage Problem">​</a></h2>
<p>Training large models on massive datasets is already a headache without slow
file systems or flaky VPN connections piling on. Early on, we wasted hours
restarting training jobs because of these bottlenecks. Enter Mothra: our
content-addressed filesystem designed for high-speed access and stability.</p>
<p>Mothra hashes all inputs using multihash and stores them on S3, with a local
disk cache to handle frequent reads. This improved stability and reduced
training time significantly. By cutting out our reliance on NFS or EFS and their
VPN dependencies, we streamlined our workflow and slashed costs.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="why-it-matters">Why It Matters<a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#why-it-matters" class="hash-link" aria-label="Direct link to Why It Matters" title="Direct link to Why It Matters">​</a></h2>
<p>These solutions aren't just clever hacks; they're investments in reliability.
When you're building a system for something as critical as asset compliance
auditing, every misclassification can lead to compliance violations or wasted
man-hours. And let's not forget: AI systems that fail in high-stakes scenarios
don’t just disappoint, they erode trust in the technology itself.</p>
<p>We'll continue exploring ways to improve model robustness and training
efficiency, including diving deeper into augmentation strategies, transfer
learning, and domain adaptation in future efforts.</p>
<p>For the full presentation, watch the YOW! Data 2019 talk:</p>
<div style="padding:56.25% 0 0 0;position:relative"><iframe src="https://player.vimeo.com/video/354650061?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write" style="position:absolute;top:0;left:0;width:100%;height:100%" title="YOW! Data 2019 - Roger Qiu - Image Classification in a Noisy Fraudulent World"></iframe></div></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#the-rotation-invariance-problem" class="table-of-contents__link toc-highlight">The Rotation Invariance Problem</a></li><li><a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#the-overlapping-class-problem" class="table-of-contents__link toc-highlight">The Overlapping Class Problem</a></li><li><a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#the-unary-classification-problem" class="table-of-contents__link toc-highlight">The Unary Classification Problem</a></li><li><a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#file-systems-arent-just-a-storage-problem" class="table-of-contents__link toc-highlight">File Systems Aren't Just a Storage Problem</a></li><li><a href="https://matrix.ai/learn/blog/common-problems-in-image-classification-and-object-detection#why-it-matters" class="table-of-contents__link toc-highlight">Why It Matters</a></li></ul><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>machine-learning</category>
            <category>image-classification</category>
            <category>object-detection</category>
        </item>
        <item>
            <title><![CDATA[Image Classification of Solar Inverter Models for Asset Compliance and Auditing]]></title>
            <link>https://matrix.ai/learn/blog/image-classification-of-solar-inverters-for-asset-compliance-auditing</link>
            <guid>https://matrix.ai/learn/blog/image-classification-of-solar-inverters-for-asset-compliance-auditing</guid>
            <pubDate>Sat, 17 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Solar technologies have long been a pillar of sustainable energy, accounting for]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Solar technologies have long been a pillar of sustainable energy, accounting for
almost 10% of Australia's total electrical energy production in 2019. One of the
incentives driving this adoption is the Small-scale Energy Certificate (STC)
program offered by the Australian government, which offers discounts for the
purchase of small-scale solar energy equipment such as solar panels and
inverters.</p>
<p>A compliance industry has emerged from the introduction of these incentives in
order to verify the eligibility of residential solar installations for STCs.
This is because only a certain set of solar equipment are approved for STCs.
When an application for STCs is incorrect either due to fraud or accident, the
compliance industry is fined by the government. Therefore, this process is
critical and involves reviewing a large amount of photographic evidence, which
is time-consuming and prone to errors. But what if this didn't have to be the
case?</p>
<p><img decoding="async" loading="lazy" alt="The focus of photographic evidence within the compliance workflow" src="https://matrix.ai/assets/images/compliance-workflow-diagram-4cbabfa4c93084332d70ce04253ae01f.svg" width="1383" height="546" class="img_ev3q"></p>
<p>Matrix AI has been consulting a client in this compliance industry to replace
the manual process of checking photographic evidence of solar inverters with a
computer-vision AI system.</p>
<p>Currently this process involves collecting photographic evidence along with the
claimed solar inverter model through a mobile application, which is then queued
up into a backend order processing system that is checked by human workers.</p>
<figure style="text-align:center;max-width:600px;padding-top:20px;padding-bottom:20px;margin-left:auto;margin-right:auto"><img class="w-full h-full" alt="A noisy dataset of manually classified solar inverters" src="https://matrix.ai/assets/images/inverter-dataset-72ba0865ff1f71a83d7e8fe3190351e3.png"><figcaption style="font-size:8pt"><p>Roger Qiu. YOW! Data 2019 - Image Classification in a Noisy Fraudulent World. 2019. <a href="https://vimeo.com/354650061"></a><a href="https://vimeo.com/354650061" target="_blank" rel="noopener noreferrer">https://vimeo.com/354650061</a></p></figcaption></figure>
<p>We designed a solution using a convolutional deep neural network to
automatically classify the photographs of inverters.</p>
<p><img decoding="async" loading="lazy" alt="The image classification process" src="https://matrix.ai/assets/images/inverter-image-classification-diagram-0ba45eb3be92c5e6cc52e1b5d4a07174.png" width="1146" height="256" class="img_ev3q"></p>
<figure class="block sm:float-left" style="max-width:600px;padding:30px;margin-left:auto;margin-right:auto"><img class="w-full h-full" alt="Abstract diagram on CNN with image classification" src="https://matrix.ai/assets/images/cnn-abstract-diagram-f84580191db4bcdb6aac0ebb96773fb5.png"><figcaption style="font-size:8pt"><p>Hoeser T, Kuenzer C. Object Detection and Image Segmentation with Deep Learning on Earth Observation Data: A Review-Part I: Evolution and Recent Trends. Remote Sensing. 2020; 12(10):1667. <a href="https://doi.org/10.3390/rs12101667"></a><a href="https://doi.org/10.3390/rs12101667" target="_blank" rel="noopener noreferrer">https://doi.org/10.3390/rs12101667</a></p></figcaption></figure>
<p>Convolutional Neural Networks (CNNs) are a type of deep learning neural networks
used for image classification that extract visual features from input images.
These features are then weighted and used to classify the most likely solar
inverter model.</p>
<p>In our case, the inverter classifier model is trained on a large dataset of
400,000 solar inverter images containing over 3000 solar inverter models
collected over the last 10 years. By comparing the inferred model of the solar
inverter to the claimed model submitted by the user, we are able to verify
whether the submitted application is potentially fraudulent or contains a
mistake.</p>
<p>As we started training the inverter classifier model, we encountered two
problems:</p>
<ul>
<li>There were many solar inverter models were visually indistinguishable from
each other.</li>
<li>Photographs taken by claimants did not have to be of inverters, they could be
photographs of anything.</li>
</ul>
<p>We solved the first problem by creating a labelling system that could coalesce
solar inverter models together, and the second problem by stacking a unary
classifier that separates all non-solar inverter images first. We will talk
about the unary classifier in a subsequent blog post.</p>
<p>Our computer vision AI system was presented to the client through a custom
classification interface, the photographic evidence is shown on the left, and
the inferred model is shown on the right. The potential models inferred from a
given image are ranked from highest to lowest probability, and allows the user
to reorder the ranking in case of false-positives, as well as coalesce models in
case of visual similarity. These corrections will be taken into account for a
subsequent retraining in order to improve the accuracy of the AI system.</p>
<figure style="text-align:center;max-width:600px;padding-top:20px;padding-bottom:20px;margin-left:auto;margin-right:auto"><img class="w-full h-full" alt="Screenshot of the Inverter Analysis User Interface" src="https://matrix.ai/assets/images/inverter-analysis-interface-1009f9c1fdd86bf35b00b28a9251e6ca.png"><figcaption style="font-size:8pt"><p>Roger Qiu. YOW! Data 2019 - Image Classification in a Noisy Fraudulent World. 2019. <a href="https://vimeo.com/354650061"></a><a href="https://vimeo.com/354650061" target="_blank" rel="noopener noreferrer">https://vimeo.com/354650061</a></p></figcaption></figure>
<p>With the deployment of the inverter analysis system, this is just one step
towards full automation of the compliance workflow process. Further data
integration is required for full automation as this system still requires a
human in the loop.</p>
<p>Further adoption of AI technologies in the compliance industry can reduce the
costs of adopting renewable energy, especially as government incentive programs
in renewable energy require complex asset auditing and compliance.</p>
<p>For the full presentation, watch the YOW! Data 2019 talk:</p>
<div style="padding:56.25% 0 0 0;position:relative"><iframe src="https://player.vimeo.com/video/354650061?title=0&amp;byline=0&amp;portrait=0&amp;badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write" style="position:absolute;top:0;left:0;width:100%;height:100%" title="YOW! Data 2019 - Roger Qiu - Image Classification in a Noisy Fraudulent World"></iframe></div></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>deep-learning</category>
            <category>image-classification</category>
            <category>clean-energy</category>
            <category>solar</category>
        </item>
        <item>
            <title><![CDATA[Service Abstraction and Communication Flows]]></title>
            <link>https://matrix.ai/learn/blog/service-abstraction-and-communication-flows</link>
            <guid>https://matrix.ai/learn/blog/service-abstraction-and-communication-flows</guid>
            <pubDate>Tue, 04 Sep 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Previously we had talked about]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Previously we had talked about
<a href="https://matrix.ai/learn/blog/service-centric-networking/">service-centric networking</a>. Since
then, we have now implemented a prototype experiment implementing the ideas from
Serval that demonstrates ICMP ping migration involving the Linux iptables and
Network Namespaces.</p>
<p>As a reminder of what we're dealing with, today's cloud infrastructure is
increasingly viewing a group of machines as a "service" rather than just hosts
connected to the internet.</p>
<p>Abstracting machines into services allows easier horizontal scaling as we can
load balance between instances of those services. Doing this sort of abstraction
requires a service name that is not associated to a particular machine. This
name can be a "virtual" IP address. However, just because you can remap a name
to point to a different concrete address, doesn't mean the endpoints on the 2
sides of the communication can continue the conversation transparently. Many
communication protocols are not stateless. Therefore, remapping a virtual
service name may involve complex state tracking and synchronisation.</p>
<p>Our experiment involves a network structure like below:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">+----------------------------------------------------------------+</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|                                                                |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">| +-----+     +-----+     +-----+   +-----+                      |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">| |a.com|     |b.com|     |a.com|   |c.com|                      |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">| +--+--+     +--+--+     +--+--+   +--+--+                      |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|    |           |           |         |                         |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|    |           |           |         |                         |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|    +-----------+-----+-----+---------+         Host            |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|                      |                                         |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|                      |                                         |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|            +---------+---------+                               |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|            |orchestrator bridge|                               |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|            +-------------------+                               |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">|                                                                |</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+----------------------------------------------------------------+</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Each domain listed above is just a human-readable name associated with an ICMP
ping service running in their own network namespace. They are all connected to
orchestrator via virtual ethernet. The orchestrator currently runs as a network
bridge. The entire experiment is only within a Linux host.</p>
<p>We enter one of the network namespaces and initiate a ping operation to another
service using an abstract service name ( represented as an IP address). Then
inside the orchestrator, we stopped the receiving service, and started another
service while preserving the same abstract service name. The servicing sending
ICMP ping continued to work without any interruptions.</p>
<p>This experiment does not address zero-downtime migrations, it was only an
exercise in using Linux OS tooling for preserving abstract service names between
different services.</p>
<p>The experiment also raised issues such as having a NAT engine which is able to
load balance as well (which iptables doesn't do) as well as further questions on
whether DNS resolution is a suitable mechanism for flow establishment, naming of
services and migration of communication state.</p>
<p>The experiment source can be found at:
<a href="https://github.com/MatrixAI/Relay/tree/master/experiments/stateless_container_ping_migrations" target="_blank" rel="noopener noreferrer">https://github.com/MatrixAI/Relay/tree/master/experiments/stateless_container_ping_migrations</a></p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>networking</category>
        </item>
        <item>
            <title><![CDATA[Session Types]]></title>
            <link>https://matrix.ai/learn/blog/session-types</link>
            <guid>https://matrix.ai/learn/blog/session-types</guid>
            <pubDate>Sat, 14 Jul 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Working with type systems and communications can be very difficult. In Haskell,]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Working with type systems and communications can be very difficult. In Haskell,
messages between threads are usually conveyed through channels that only accept
a single type, and as a result are not very versatile. In networked systems, a
stream of bytes is sent that hopefully conforms to one of many protocols
including TCP, UDP, and HTTP, and hopefully both parties agree on what is sent
and when. Session Types are a way to bridge the gap between these systems, as
they can capture complicated protocols, and be properly type checked.</p>
<p>There are
<a href="http://groups.inf.ed.ac.uk/abcd/session-implementations.html" target="_blank" rel="noopener noreferrer">many ways</a> that
Session Types are notated and implemented.
<a href="http://www.scribble.org/" target="_blank" rel="noopener noreferrer">Scribble's notation</a> looks more like an imperative
programming language, where others are more functional, using algebraic data
types and typeclasses. The notation in this post is inspired by a paper on
<a href="http://homepages.inf.ed.ac.uk/wadler/papers/gradsess/gradsess.pdf" target="_blank" rel="noopener noreferrer">Gradual Session Types</a>
and a paper on
<a href="http://mrg.doc.ic.ac.uk/publications/dynamic-multirole-session-types/dynamic-multirole-session-types.pdf" target="_blank" rel="noopener noreferrer">Multiparty Session Types</a>.</p>
<p>The most basic units of Session Types are for sending and receiving data; <code>!t</code>
represents sending a value of type <code>t</code>, and <code>?t</code> represents receiving a value of
type <code>t</code>. These can be concatenated by a semicolon, so a service that receives a
string and responds with its length could be represented by the session type
<code>?String; !Nat</code>, and any client using it would be represented by
<code>!String; ?Nat</code>.</p>
<p>To represent more complicated protocols we add the possiblity of branching,
though it is useful to include in the notation which party is responsible for
choosing the branch. For the party that is deciding on the branch we allocate
the session type <code>+{a:x,…,c:z}</code>, where <code>a</code> and <code>c</code> are labels for the Session
Types <code>x</code> and <code>z</code>. The party that is not responsible for choosing would have the
corresponding session type <code>&amp;{a:x,…,c:z}</code>. With this, we can encode a server
that offers the client of receiving a guest page or signing in as a user with
the following Session Type:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">&amp;{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  guest: !HTML,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  user: ?Username; ?Password; +{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    success: !HTML,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    fail: !Error</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The last feature of this version of session types is one that allows sessions to
loop. For this we use the mu fixed point operator, which is notated as
<code>μt.a(t)</code>, where <code>a(t)</code> is some session type that contains <code>t</code>, and can be
interpreted as the recursive definition <code>t = a(t)</code>. If we wanted a user to have
unlimited attempts at logging on to a system, our server could have the
following Session Type:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">μt. (</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  ?Username;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  ?Password;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  +{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    success: !HTML,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    fail: t</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>With all of these features, we can attempt to encode a HTTP 1.1 client, which
can send as many requests as it wants before receiving responses:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">µt. (</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  !HTTPRequest;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  +{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sendMore: t,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    wait: end</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  };</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  ?HTTPResponse;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  +{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sendMore: t,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    wait: end</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Session Types have a notion of duality, where two protocols are compatible when
they are duals. We define <code>?t</code> to be dual to <code>!t</code>, <code>&amp;{a:x,…,c:z}</code> to be dual to
<code>+{a:u,…,c:w}</code> when all the choices <code>x</code> and <code>u</code>, <code>z</code> and <code>w</code> etc. are duals, and
a series of concatenated session types <code>x;…;z</code> is dual to <code>u;…;w</code> when each pair
of session types <code>u</code> and <code>x</code>, <code>w</code> and <code>z</code> etc. are duals. The dual of a fixpoint
<code>μt.a(t)</code> is <code>μs.b(s)</code>, where assuming <code>t</code> and <code>s</code> are duals implies that <code>a(t)</code>
and <code>b(s)</code> are duals.</p>
<p>However, duality on its own does not define compatibility, since our earlier
server that offered services to either a guest or a user would be compatible
with a client that always chooses to be a guest, with the session type
<code>+{ guest: ?HTML }</code>. To formalise this we define what it means for two Session
Types <code>a</code> and <code>b</code> to be subtypes, notated <code>a &lt;: b</code>, where the key property we
want from subtypes is that if we have <code>a &lt;: b</code> and <code>c &lt;: d</code> and <code>a</code> and <code>c</code> are
compatible, then the more general Session Types <code>b</code> and <code>d</code> should be
compatible.</p>
<p>With this in mind, <code>&amp;{a:x,…,b:y}</code> is a subtype of <code>&amp;{a:x,…b:y,…,c:z}</code>, since
offering extra options does not break compatibility, <code>+{a:x,…b:y,…,c:z}</code> is a
subtype of <code>+{a:x,…,b:y}</code>, since choosing a subset of the available options does
not break compatibility. Thus offering fewer choices is a subtype of offering
more, and choosing between more choices is a subtype of choosing fewer.</p>
<p>To handle fixpoints, if assuming <code>t &lt;: s</code> implies <code>a(t) &lt;: b(s)</code>, then
<code>μt.a(t) &lt;: μs.b(s)</code>. Using this we can come up with a recursive definition of
subtypes. Finally, we can define two Session Types to be compatible if one is a
subtype of the other's dual.</p>
<p>An alternative syntax for the above operators is to replace <code>!</code> with <code>send</code>, <code>?</code>
with <code>recv</code>, <code>+</code> with <code>choose</code>, <code>&amp;</code> with <code>offer</code>, <code>;</code> with significant
whitespace, and <code>μ</code> with <code>rec</code>. Therefore the previous HTTP example would be
like:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">rec t (</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  send HTTPRequest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  choose {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sendMore: t,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    wait: end</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  recv HTTPResponse</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  choose {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sendMore: t,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    wait: end</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Most uses of Session Types are in allowing more complex communication within a
strongly typed language, however at Matrix AI we are hoping to apply them to
distributed systems. We will use Session Types to describe network protocols,
allowing us to check which parts of a distributed system can communicate, to
type check the construction of network combinators, and to analyse the behaviour
of networked systems.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>session</category>
        </item>
        <item>
            <title><![CDATA[Docker's V1 and V2 Image Specification]]></title>
            <link>https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2</link>
            <guid>https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2</guid>
            <pubDate>Sat, 05 May 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[In 2016, Docker has officially updated their image specification from V1 to V2,]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>In 2016, Docker has officially updated their image specification from V1 to V2,
adopting a more sophisticated scheme that is inline with
<a href="https://github.com/opencontainers/image-spec" target="_blank" rel="noopener noreferrer">OCI Container Image Specification</a>.</p>
<p>There are only a few minor differences between Docker's image spcification V2
and OCI image specification (See
<a href="https://github.com/opencontainers/image-spec/blob/main/media-types.md#compatibility-matrix" target="_blank" rel="noopener noreferrer">Compatibility Matrix</a>).
Here we will discuss some major changes from V1 and V2, and why Docker has moved
towards these changes.</p>
<p>Docker images contain the underlying changes in the root filesystem, and the
execution parameters of a container. When we write a Dockerfile, the FROM clause
bring in a base image from an external registry; each line of operation adds a
new layer or attribute to the base image. Eventually <code>docker build</code> will gives
us an image that we can deploy, share or run as a container.</p>
<p>It is important to distinguish that an image is different from a container. When
a container is ran, the image (which is a stack of tarballs with manifest JSON
files) is processed and transformed into the underlying filesystem, mounts,
environment variables and so on.
<a href="https://github.com/opencontainers/image-spec" target="_blank" rel="noopener noreferrer">OCI Container Image Specification</a>
and
<a href="https://github.com/opencontainers/runtime-spec" target="_blank" rel="noopener noreferrer">OCI Container Runtime Specification</a>
give a good modern understanding on what an image is.</p>
<h1>Content Addressability</h1>
<p>In Docker Image Specification V1.0, each image layer has a randomly generated
256-bit id that uniquely references the layer. The space of the id is sufficient
to ensure the uniqueness of all layers, but it does not guarantee that the image
you pull is always the image you expect. Imagine that you have an image
<code>pychat:1.0</code> that uses <code>python:3</code> as its base image. You uploaded your image to
an image registry, and over the years someone comes along and swaps out some
files in <code>python:3</code>. All in a sudden your code breaks and you might have to look
into a deep chain of dependencies to figure out why your container doesn't work
anymore. This is why having an unique id is not enough, we want a way to
efficiently address the <strong>content</strong> of a container.</p>
<p>Content addressing is achieved by using a
<a href="https://en.wikipedia.org/wiki/Cryptographic_hash_function" target="_blank" rel="noopener noreferrer">collision resistent hash function</a>.
In Docker Image Specification V2, each image layer is referenced with a unique
content address computed from the canonical representation of the layer
changeset. We can look at it like this:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">"""</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Note that this is an over-simplified version of how</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">image_ids are generated.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">"""</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">layer_ids = []</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">for layer_changeset in layers:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    layer_id = hash(repr(layer_changeset))</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    layer_ids.add(layer_id)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">image_manifest = layer_ids</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">image_id = hash(image_manifest)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Due to the nature of cryptographic hash functions, the hashes can be used to
distinguish whether two layers contain exactly the same content. We can use this
property to ensure that the image we download is the same image we used before,
i.e. tell Docker to fetch an image with the content address of a previously used
and tested image. This will ensure that the image we get hadn't been changed
since, as any changes to the image will result in a entirely different content
address.</p>
<p>A <code>manifest</code> is a JSON file that contains all necessary configuration for an
image. In Docker image spec V2, a <code>manifest</code> contains the content addresses of
all layers in an image. Since it contains the hash of all layers, we can simply
download this small JSON file and take the hash of it to verify that this image
has all the layers we wanted. This saves us a lot of time from downloading and
checking the content of the entire image.</p>
<p>An example V2 image manifest:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  "schemaVersion": 2,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  "mediaType": "application/vnd.docker.distribution.manifest.v2+json",</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  ...</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  "layers": [</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "size": 32654,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "digest": "sha256:e692418e4cbaf90ca...b51fab815ad7fc331f"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "size": 16724,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "digest": "sha256:3c3a4604a545cdc12...f4a9c1905b15da2eb4"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "size": 73109,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      "digest": "sha256:ec4b8955958665577...7f12184802ad867736"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Example Dockerfile utilizing the image described in the above manifest:</p>
<div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">FROM python@sha256:b22de77...f118cb</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">...</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">CMD ["python3", "pychat.py"]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This way <code>pychat:1.0</code> is guaranteed to pull the same base image everytime it is
ran, and the container will remain deterministic until our selected hash
algorithm is found to be broken, which hopefully is not in the near future.</p>
<h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="one-thing-to-look-out-for-when-pulling-images-by-content-address">One thing to look out for when pulling images by content address:<a href="https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2#one-thing-to-look-out-for-when-pulling-images-by-content-address" class="hash-link" aria-label="Direct link to One thing to look out for when pulling images by content address:" title="Direct link to One thing to look out for when pulling images by content address:">​</a></h3>
<p>There are some inconsistencies between the content of the image manifest in the
system and the content of the manifest that exists in the registry, i.e. The
image ID displayed in <code>docker image list --no-trunc</code> is different to the address
you use to fetch an image
(<a href="https://windsock.io/explaining-docker-image-ids/" target="_blank" rel="noopener noreferrer">relevant blog post</a> and
<a href="https://github.com/deitch/docker_registry2/issues/4" target="_blank" rel="noopener noreferrer">Github issue</a>).</p>
<h1>Image Specific Properties</h1>
<p>Another important change is the location of image specific properties. In V1,
each layer contains a JSON file that specifies what the image should do <em>up to
this layer</em>. The file contains information such as
<code>entrypoint, env, cmd, memory</code> and so on. However, these attributes should not
be layer specific. Each layer essentially represents a change in the image's
filesystem at a point in time, associating such component with runtime
properties such as environment variables, entrypoints and CPU usage is
completely unnecessary. Runtime properties should be related to an image as a
whole, not a single layer in the filesystem.</p>
<p>We can take a look at Docker V1's Image format by doing
<code>docker save &lt;image name&gt; | tar -x</code> in an empty directory. <code>docker save</code> and
<code>docker load</code> are the two docker commands that still uses the V1 standard for
legacy reasons.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ docker pull ubuntu@sha256:d2518289e66fd3892c2dae5003218117abeeed2edbb470cba544aef480fb6b3a</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ docker save ubuntu@sha256:d2518289e66fd3892c2dae5003218117abeeed2edbb470cba544aef480fb6b3a | tar -x</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ tree</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── 08ca6384a97957eac5a5a69cdc799434739655c88e69efb23d2bb963110dbf48</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── layer.tar</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── VERSION</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── 0fa211e5edebeb29d3e29cc2c8c87e9a6a8306901816c19b7f6fb6a7392c3cef</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── layer.tar</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── VERSION</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── 452a96d81c30a1e426bc250428263ac9ca3f47c9bf086f876d11cb39cf57aeec.json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── 614c02cb92ee20d3cd51770f07d67503f87a75602ddf032a0a6163527fcf97e0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── layer.tar</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── VERSION</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── cc8487ed6373e8b38c60ff8fc5bdfdd9576aa49226a6e4dcac522f61f5f19d31</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── layer.tar</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── VERSION</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">├── daf8616e33b20539309a114814ba9864367630ad8da63d4e96bea40dd22841ba</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   ├── layer.tar</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">│   └── VERSION</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">└── manifest.json</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We can see that the image has 5 underlying layers (represented by
sub-directories) and a top level layer (represented by the root directories).
The <code>manifest.json</code> tells us the ordering of the layers and which of them is the
top level directory. We can also see that there is a file json in each sub
directory, this is the configuration of each layer in V1 format as described
earlier. Read the json files and pay special attention to the <code>container_config</code>
attribute set, these attributes should be assoicated to the image as a whole,
however they exist at each layer instead. Having a hierarchy of inheritance on
these runtime attributes layer by layer often leads to unnecessary complexity.</p>
<p>In V2, the layer JSON is discarded and instead it was decided that the layer
changeset itself is enough to represent a layer in the image. Layer hierarchies
are specified in the <code>layers</code> attribute in the root level manifest, which
references the layers by its content addresses. The attributes of
<code>container_config</code> is now stored in another file inline with the
<a href="https://github.com/opencontainers/runtime-spec" target="_blank" rel="noopener noreferrer">OCI Runtime Specification</a>. The
new specification makes sure that the runtime configurations are associated with
the image as a whole, and inheritance happens at a image level rather than a
container level. Note that the content address of this runtime configuration is
also included in the V2 manifest.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="multi-architecture-images">Multi-Architecture Images<a href="https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2#multi-architecture-images" class="hash-link" aria-label="Direct link to Multi-Architecture Images" title="Direct link to Multi-Architecture Images">​</a></h2>
<p>V2 also introduces a new configuration component called a <strong>manifest list</strong>, or
an <strong>image index</strong> in OCI's terminology. Manifest list is essentially a list of
platform specific image manifests which contains similar contents, for example,
an Ubuntu:16.04 container for a macOS host and an Ubuntu:16.04 container for a
linux host. This allows multi-architecture containers to be coupled together and
treated as a whole, which is useful for packaging a set of similar images and
distributing them to an image registry.</p>
<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="conclusion">Conclusion<a href="https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Here's a summary of the differences mentioned in this article:</p>
<ul>
<li>Image Spec V1<!-- -->
<ul>
<li>Randomly generated image ID</li>
<li>Image specific properties are defined at layer level</li>
<li>No multi-architecture support</li>
</ul>
</li>
<li>Image Spec V2<!-- -->
<ul>
<li>Image IDs are content addresses</li>
<li>Image specific properties defined at image level</li>
<li>Multi-architecture support</li>
</ul>
</li>
</ul>
<p>There are other advantages, we'll examine in later posts.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2#one-thing-to-look-out-for-when-pulling-images-by-content-address" class="table-of-contents__link toc-highlight">One thing to look out for when pulling images by content address:</a></li><li><a href="https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2#multi-architecture-images" class="table-of-contents__link toc-highlight">Multi-Architecture Images</a></li><li><a href="https://matrix.ai/learn/blog/docker-image-specification-v1-vs-v2#conclusion" class="table-of-contents__link toc-highlight">Conclusion</a></li></ul><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>docker</category>
        </item>
        <item>
            <title><![CDATA[Polykey - Distributed Secret Sharing]]></title>
            <link>https://matrix.ai/learn/blog/polykey-distributed-secret-sharing</link>
            <guid>https://matrix.ai/learn/blog/polykey-distributed-secret-sharing</guid>
            <pubDate>Sun, 29 Apr 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[The Matrix AI team has been developing Polykey, a distributed peer-to-peer]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>The Matrix AI team has been developing Polykey, a distributed peer-to-peer
secret sharing system. It is intended to manage secrets, passwords, API keys for
both humans and machines.</p>
<p>Many secret management systems have been designed either only for humans, or
only for machines. We think this is unnecessary and intend Polykey to work in
both cases. However, for this article, we'll focus solely on what Polykey
provides to the Matrix infrastructure.</p>
<p>Matrix Automatons may require secrets in order to communicate to an external
API. There are several challenges to managing infrastructural secrets:</p>
<ul>
<li>How to automatically deploy software which relies on external API keys?</li>
<li>How to manage key updates while there are online applications using and
depending on those keys?</li>
<li>How to ensure the security of the keys at-rest or during transit?</li>
<li>How to revoke access keys?</li>
<li>How to only pass keys that are strictly relevant for the application?
(Principle of Least Privilege)</li>
<li>How to backup keys?</li>
<li>Polykey was created to solve these problems and more. It integrates Git,
public key cryptography and Keybase. It is designed to operate in a
distributed manner similar to Git repositories (and using Git gives us version
control for free). Here we will illustrate the abstract semantics of Polykey
and in later articles we will address how we are implementing it.</li>
</ul>
<p>A Polykey keynode is a single file. Keynodes can be stored anywhere. In this
way, it is similar to <a href="https://www.passwordstore.org/" target="_blank" rel="noopener noreferrer">pass</a>. A keynode stores a
set of secrets. Each secret is independently version controlled (this is where
<code>Git</code> comes in). Each secret or subset of secrets can be shared to another
keynode. You can create multiple keynodes and make some keynodes only store
subsets of other keynodes. Sharing can be either push-based or pull-based (just
like <code>Git</code>). For keynode A to push or pull secrets to or from keynode B, node A
must have the capability to do so. This is done via public key cryptography.</p>
<p>In this way, a network of keynodes can represent a delivery mechanism for
updating secrets. The computation required for dealing with secrets such as
crytographic calculations or network transmission is divorced from where the
secrets are stored. Furthermore, read-only computations only require read-only
access.</p>
<p>Because keynodes are just files, they are completely self-hosted and
self-contained, and you can be sure that your secrets are encrypted at-rest and
during transit. They are also constructed using standard Unix formats: tar
archives, <code>git</code> repositories, GnuPG encryption, Unix hardlinks, and just Plain
Text. You don't need to launch a service or bind to some network. Secrets can
just be acquired using a command line program, or directly accessed via a
standard libraries that understand Unix file formats. This makes the Polykey
keynode format very flexible and amenable to automation.</p>
<p>The exact design of Polykey is still under flux, but you can follow along here:
[<a href="https://github.com/MatrixAI/Polykey" target="_blank" rel="noopener noreferrer">https://github.com/MatrixAI/Polykey</a>]</p>
<p>We have been developing several libraries to support the development:</p>
<ul>
<li><a href="https://github.com/MatrixAI/js-resource-counter" target="_blank" rel="noopener noreferrer">js-resource-counter</a>:
Sequentially Allocatable and Deallocatable Resource Counter</li>
<li><a href="https://github.com/MatrixAI/js-permaproxy" target="_blank" rel="noopener noreferrer">js-permaproxy</a>: Proxy pattern for
proxying an object mediated through a container.</li>
<li><a href="https://github.com/MatrixAI/js-virtualfs" target="_blank" rel="noopener noreferrer">js-virtualfs</a>: Virtual posix-like
filesystem that runs completely in-memory.</li>
<li><a href="https://github.com/MatrixAI/js-reference-pointer" target="_blank" rel="noopener noreferrer">js-reference-pointer</a> -
Wrap a primitive value in a reference pointer, and pass by reference!</li>
<li><a href="https://github.com/MatrixAI/js-object-tagger" target="_blank" rel="noopener noreferrer">js-object-tagger</a>: Takes a POJO
and tags specified keys pointing to objects with unique numbers.</li>
<li><a href="https://github.com/MatrixAI/js-array-fixed" target="_blank" rel="noopener noreferrer">js-array-fixed</a>: Arrays with
Fixed Preallocated Length</li>
<li><a href="https://github.com/MatrixAI/js-tree-order-index" target="_blank" rel="noopener noreferrer">js-tree-order-index</a>: (not
yet working) - Indexing Trees for Efficient Queries and Updates</li>
<li><a href="https://github.com/MatrixAI/js-virtualgit" target="_blank" rel="noopener noreferrer">js-virtualgit</a> (not yet working) -
In-memory Git</li>
</ul>
<p>We expect Polykey to be usable on every platform (Linux, Windows, Mac, Android,
iOS, Browsers). Even platforms that don't use JavaScript can just use standard
Unix tools!</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>distributed-systems</category>
            <category>polykey</category>
            <category>presentation</category>
        </item>
        <item>
            <title><![CDATA[Service Centric Networking]]></title>
            <link>https://matrix.ai/learn/blog/service-centric-networking</link>
            <guid>https://matrix.ai/learn/blog/service-centric-networking</guid>
            <pubDate>Sat, 21 Apr 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[TCP/IP networking relies on IP addresses mapped to a machine to facilitate]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>TCP/IP networking relies on IP addresses mapped to a machine to facilitate
routing through the Border Gateway Protocol ( BGP). This mapping is usually done
through the DNS, which maps human-readable names ("cats.com") to IP addresses.
Service centric networks are an alternative/extension to DNS, where the host
maintains their own table of mappings from service names to tuples of IP address
and port number, but with additional capabilities to control the routing of
data. This additional flexibility is usually referenced in the literature as
separating the control plane and data plane. The key advantage provided by this
is additional flexibility in dynamically modifying the service table compared to
DNS. Our discussion of service centric networking is based on the Serval paper
<a href="https://sns.cs.princeton.edu/docs/serval-tr11.pdf" target="_blank" rel="noopener noreferrer">here</a>.</p>
<p>In service centric networks, the control plane is the mechanism used to
configure routes in the network, and also to configure the path that a payload
may take through the network. Once the route for a payload has been established
through the control plane, the payload is said to move through the data plane to
the target based on the established configuration. The reason for this
separation is that control and configuration of the network is itself
distributed, and requires communication channels of their own.</p>
<p>One way this control/data plane split is achieved is to use a host maintained
service table as an intermediary between the control plane and data plane:
routing decisions in the data plane are made using rules that are listed in the
service table, but the value of these routing rules is managed independently by
a local daemon running on each node in the network.</p>
<p>Something that we can do with this control/data plane split is called 'late
binding'. In DNS any peer that is looked up must already have a bound IP address
in the DNS table. This is called early binding, because the IP address of the
peer is explicitly written in the DNS table. With the service table, when a
connect is called, the IP address of the peer can actually be discovered
dynamically, by routing the initial packet of the connection through the
network, to find a peer that supports the service. After the peer is found, the
peer can open a connection directly to the host, and the connection is now
established. This approach, for example, allows us to implement a load balanced
network without a load balancer.</p>
<p>Payloads moving in the data plane have an additional layer of encapsulation
between the addressing headers used to facilitate network forwarding, and the
headers use to identify the protocol that is being communicated. This additional
information consists of a source and destination 'flow' identifier, the
transport protocol that is being used, a series of sequence and acknowledgement
numbers, and a service identifier for communication. We can distribute a payload
over multiple flows to and from the peer as necessary.</p>
<p>Our use case for service centric networks is to allow for finer control and
addressing in a microservice infrastructure (more so than in DNS), and being
able to change the location of such services on the fly. We would also like to
make use of features implicit in the transport protocol that is chosen for a
flow, that allow us to migrate live peers to a new location, and reattaching any
open flows in a way that is transparent to the end user.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>networking</category>
        </item>
        <item>
            <title><![CDATA[Linux Network Namespaces]]></title>
            <link>https://matrix.ai/learn/blog/linux-network-namespaces</link>
            <guid>https://matrix.ai/learn/blog/linux-network-namespaces</guid>
            <pubDate>Tue, 03 Apr 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[The fundamental isolation technology supporting containers on Linux are]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>The fundamental isolation technology supporting containers on Linux are
<a href="http://man7.org/linux/man-pages/man7/namespaces.7.html" target="_blank" rel="noopener noreferrer">Linux namespaces</a>.
Namespaces provide isolation of global resources in a way that is transparent to
the processes within the namespace. There are currently 7 different namespaces
that are supported: Cgroups, IPC, Network, Mount, PID, User, UTS. Today we will
be looking at the network namespace.</p>
<p>The network namespace can be thought of as a copy of the network stack. It
provides isolation in network interfaces, routes, and firewall rules. In this
article we will be using the tools from
<a href="https://wiki.linuxfoundation.org/networking/iproute2" target="_blank" rel="noopener noreferrer">iproute2</a> to demonstrate.</p>
<p>First let's create a new network namespace to play with:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Create a new net namespace ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns add ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Show all net namespaces</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns show</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">ns0</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Here we have created a new network namespace called <code>ns0</code>. Let's go into the
namespace and see what it looks like.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Execute `ip link` in the ns0 namespace</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link show</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">1: lo: &lt;LOOPBACK&gt; mtu 65536 qdisc noop state DOWN mode DEFAULT group default</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>As shown from this example, our newly created namespace <code>ns0</code> only has one
loopback interface. If you are familiar with network interfaces (those "labels"
you see in the well known <code>ifconfig</code> command), you can see that ns0 does not
inherit any of the interfaces such as <code>eth0, wlan0</code> from your main namespace.</p>
<p>This is what we mean by isolation of network device: whenever we create a new
network namespace, the network resources in that namespace is separated from
your main namespace. Processes that runs in this namespace (e.g. <code>ip link</code>) does
not have access to the interfaces in other namespaces and vice versa.</p>
<p>Linux namespaces allow processes within one computer to think that they actually
exists on different computers. In a network context, you can create a virtual
network consisting of different processes, rather than per computer.</p>
<p>Let's get into the fun stuff and create a network of processes! There are a few
ways to allow communication between containers, the most common way is to use a
device called <strong>veth pair</strong>
(<a href="http://man7.org/linux/man-pages/man4/veth.4.html" target="_blank" rel="noopener noreferrer">virtual ethernet pair</a>). In
simple terms, <strong>veth pair</strong> is always created in pairs, and whatever information
we passed into one end will come out from another. Let's start with a simple
example to demonstrate veth pair.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Let's create another namespace ns1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns add ns1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns show</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">ns1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">ns0</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now we create a veth pair in the main namespace:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Create a veth pair vth0 and vth1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip link add vth0 type veth peer name vth1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>And then we move the two end points into namespaces <code>ns0</code> and <code>ns1</code>. Remember to
check that our move operation was successful using the <code>ip link</code> command.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Move vth0 into ns0 and vth1 into ns1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip link set vth0 netns ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip link set vth1 netns ns1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Verify that vth0 is now in namespace ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link show vth0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">6: vth0: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    link/ether 9e:e4:e9:12:ad:42 brd ff:ff:ff:ff:ff:ff</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Verify that vth1 is now in namespace ns1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns1 ip link show vth1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">5: vth1: &lt;BROADCAST,MULTICAST&gt; mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    link/ether e2:da:f7:04:9e:e3 brd ff:ff:ff:ff:ff:ff</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We also want to give those devices addresses and subnet.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># assign a static address to specified device</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip addr add "10.0.0.1/24" dev vth0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns1 ip addr add "10.0.0.2/24" dev vth1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Let's bring the devices up and see if it works.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link set vth0 up</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns1 ip link set vth1 up</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ping -c 2 10.0.0.2</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.047 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.052 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- 10.0.0.2 ping statistics ---</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">2 packets transmitted, 2 received, 0% packet loss, time 999ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">rtt min/avg/max/mdev = 0.047/0.049/0.052/0.007 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns1 ping -c 2 10.0.0.2</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.043 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.055 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- 10.0.0.1 ping statistics ---</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">2 packets transmitted, 2 received, 0% packet loss, time 999ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">rtt min/avg/max/mdev = 0.043/0.049/0.055/0.006 ms</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>We have created a working virtual network between two network namespace. Veth
pairs are easy to implement, but what if you want to add in more namespaces? it
will eventually become a complete graph with a lots of links all over the place.
This is very inefficient and hard to maintain. To solve this problem, we can use
a bridge.</p>
<p>A bridge works like a virtual switch, it has the ability to connect multiple
ethernet segments together in a protocol independent way. In our case, we are
trying to connect multiple virtual ethernet segments together. Let's try putting
the veth pairs we created earlier into a bridge.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Create a bridge device in ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link add br0 type bridge</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Assign an IP to the bridge device</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip addr add "10.0.0.1/24" dev br0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Brings the bridge up</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link set br0 up</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Plug the veth end-point into the bridge</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link set vth0 master br0</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice here that we have set the bridge's address the same as <code>vth0</code>'s address.
This is because <code>vth0</code>'s address does not matter anymore as it is now connected
to br0, and br0 essentially serves as the entry of the network for <code>ns0</code> now.</p>
<p>We should now revoke the address that was given to vth0 so the traffic can be
routed properly.</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Revoke vth0's address</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip addr del "10.0.0.1/24" dev vth0</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Let's test that it all works:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Pinging 10.0.0.2 from ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ping -c 2 10.0.0.2</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.054 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.063 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- 10.0.0.2 ping statistics ---</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">2 packets transmitted, 2 received, 0% packet loss, time 999ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">rtt min/avg/max/mdev = 0.054/0.058/0.063/0.008 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Pinging 10.0.0.1 from ns1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns1 ping -c 2 10.0.0.1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.052 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.066 ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- 10.0.0.1 ping statistics ---</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">2 packets transmitted, 2 received, 0% packet loss, time 999ms</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">rtt min/avg/max/mdev = 0.052/0.059/0.066/0.007 ms</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now if we want to add a namespace into the network, we can simply do the
following:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Create a new namespace ns3 with a veth pair vth2 and vth3</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns add ns2</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns2 ip link add vth2 type veth peer name vth3</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns2 ip addr add "10.0.0.3/24" dev vth3</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns2 ip link set vth3 up</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Move vth2 into ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns2 ip link set vth2 netns ns0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link set vth2 up</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Plug vth2 into the bridge</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$ ip netns exec ns0 ip link set vth2 master br0</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Then you can test the connectivity using ping. <code>ns0, ns1</code> and <code>ns2</code> should be
able to ping each other successfully.</p>
<p>There are other ways to enable communication between network namespaces, such as
Vlan, Macvlan, IPvlan, tuntap, etc. These will be left for a later topic.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>networking</category>
            <category>linux</category>
        </item>
        <item>
            <title><![CDATA[Programming with Linear Temporal Logic Operators]]></title>
            <link>https://matrix.ai/learn/blog/programming-with-linear-temporal-logic-operators</link>
            <guid>https://matrix.ai/learn/blog/programming-with-linear-temporal-logic-operators</guid>
            <pubDate>Tue, 03 Apr 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[At Matrix AI our research into language constructs for formally describing]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>At Matrix AI our research into language constructs for formally describing
distributed systems has led us to a concept called Linear Temporal Logic. It is
a logic system that allows us to express logical statements about time. This
article will provide a brief introduction to this logic system.</p>
<p>Linear Temporal Logic takes the basic ideas of
<a href="https://en.wikipedia.org/wiki/Propositional_calculus" target="_blank" rel="noopener noreferrer">Propositional</a> and
<a href="https://en.wikipedia.org/wiki/First-order_logic" target="_blank" rel="noopener noreferrer">Predicate</a> logic and
introduces concepts about time.</p>
<p>Predicate logic is widely used for
<a href="https://en.wikipedia.org/wiki/Automated_proof_checking" target="_blank" rel="noopener noreferrer">automatically checking and proving theorems</a>,
verifying software correctness and security, and is the foundation of the
programming language <a href="https://en.wikipedia.org/wiki/Prolog" target="_blank" rel="noopener noreferrer">ProLog</a>.</p>
<p>In Linear Temporal Logic (LTL), we can express statements about things that are
true. Our expression will have both English word variants and also operator
variants. The simplest statement is simply <code>A</code>. This means that <code>A</code> is true
right now. We can also write that <code>A</code> will be true from now on and to the
future, and that can be expressed as <code>Forever A</code> or □A. If <code>A</code> will be true
eventually, we can write <code>Eventually A</code> or ◇A. Notice that <code>Not Forever Not A</code>
is the same as <code>Eventually A</code> or ¬□¬A≡◇A. This is because if <code>A</code> won't always be
false then <code>A</code> will eventually be true. If we model time as discrete moments, we
can say that <code>A</code> will be true in the next moment, and write it as <code>Next A</code> or
◯A.</p>
<p><img decoding="async" loading="lazy" alt="Diagrams of the basic modal operators" src="https://matrix.ai/assets/images/diagram_ltl_basic_modal_operators-d6bde7d18e264521eb157dca01c9bf13.png" width="533" height="549" class="img_ev3q"></p>
<p>There are more sophisticated operators too, such as <code>A Until B</code> or A U B, which
means <code>A</code> is true until <code>B</code> is true, and <code>Eventually B</code>. This can be written
recursively as A U B ≡ B∨(A∧◇B∧◯(A U B)). There is also a weaker version of
<code>Until</code>, denoted A W B, where <code>B</code> need not occur. We can write A W B ≡ □A ∨ (A U
B).</p>
<p><img decoding="async" loading="lazy" alt="Diagrams of the complex modal operators" src="https://matrix.ai/assets/images/diagram_ltl_complex_modal_operators-c269d66e6a407bd409fdcb2c5643d7d1.png" width="629" height="379" class="img_ev3q"></p>
<p>There is a strong parallel between Propositional Logic and Functional
Programming. Let's use Haskell as an example. If the formulas <code>A</code> and <code>B</code> are
types then A∧B can be written the pair <code>(A,B)</code>, A∨B can be written as
<code>Either A B</code>, and if <code>A</code> implies <code>B</code>, we use the function type <code>A -&gt; B</code>. Now
function application looks like Modus Ponens, the distributivity laws look like
alternative representations of the same types, and formal proofs look like
Haskell programs.</p>
<p>As for the modal operators of linear temporal logic, we have to look at
Functional Reactive Programming. <code>Forever A</code> is an unending stream of values of
type <code>A</code>, <code>Eventually A</code> is a container that will eventually yield a value of
type <code>A</code>, and <code>A Until B</code> is a stream of type <code>A</code> terminated with a value of
type <code>B</code>. Using these types, IO operations can have types like
<code>Forever (Int, Int)</code> for mouse position, <code>Eventually Bytestring</code> for receiving
network data, and <code>Char `Until` Nothing</code> for standard input.</p>
<p><a href="https://www.seas.harvard.edu/sites/default/files/files/archived/Czaplicki.pdf" target="_blank" rel="noopener noreferrer">Evan Czaplicki's Paper</a>
goes over the many attempts to implement Functional Reactive Programming.
However, for distributed systems, a complete functional reactive language is
unnecessary. Instead, we can learn from Arrowised FRP, and model processes as
Signal Functions. This model may help us describe the distributed services that
Matrix is orchestrating.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>temporal</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[Developing with Nix (C, JavaScript, Python, Haskell, Emscripten, PHP)]]></title>
            <link>https://matrix.ai/learn/blog/developing-with-nix</link>
            <guid>https://matrix.ai/learn/blog/developing-with-nix</guid>
            <pubDate>Sat, 24 Mar 2018 00:00:00 GMT</pubDate>
            <description><![CDATA[Nix, NixOS and NixPkgs allows us to create project-specific development]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Nix, NixOS and NixPkgs allows us to create project-specific development
environments with project-specific dependencies (this usually means things like
a C project, or a Python project... etc).</p>
<p>The way this is done is different for every language community within the Nix
ecosystem. The most well developed patterns would be the C/C++, Haskell and
Python community, other language communities tend to be smaller and has less
documentation. This article serves as an introduction to using Nix for
developing projects in different languages that we have worked with. This means
we will only focus on <code>shell.nix</code>.</p>
<p>Remember that Nix is a turing complete purely functional language, and so it has
real functions. Defining a project environment within Nix is done via functions.
The most common function utilised for this purpose is <code>stdenv.mkDerivation</code>.
However, various language communities within Nix has wrapped this function in
higher order functions to provide further automation to deal with the
environment configuration that different language toolchains expect.</p>
<p>First decide whether your project is an "application" or a "library". If it's an
application, you need a <code>default.nix</code> and a <code>shell.nix</code>. But if it's a library
you only need a <code>shell.nix</code>. The <code>default.nix</code> that is created may is generally
not the same as the <code>default.nix</code> that gets committed into the mainline
<code>nixpkgs</code> repository. Your project's <code>default.nix</code> should be a self-contained
expression that can be used to build and install your project. Whereas the
<code>default.nix</code> committed into the mainline <code>nixpkgs</code> needs to be compatible with
the rest of the <code>nixpkgs</code> package set in order to merge into a "harmonious"
package set. In practice this means the <code>default.nix</code> in your project will use a
pinned <code>nixpkgs</code> package set, whereas the <code>default.nix</code> in <code>nixpkgs</code> will expect
a <code>pkgs</code> parameter to be passed in.</p>
<p>The <code>default.nix</code> will be utilised when you run <code>nix-build</code>. The <code>shell.nix</code>
will be utilised when you run <code>nix-shell</code>.</p>
<p>The <code>shell.nix</code> defines a development environment, so it is usually simpler than
the <code>default.nix</code>. The <code>default.nix</code> needs to also define installation
locations.</p>
<p>When encountering dependencies not available under <code>nixpkgs</code>, you have 2
choices. Either write a nix expression for that package, or utilise a
language-specific package manager. In our examples below, we will utilise
language-specific package managers within our <code>shell.nix</code> in order to create
environments that work even under non-Nix environments. However, for
dependencies that rely on system libraries, we'll generally install them via
Nix, rather than doing compilation without or <code>nix-shell</code>. To make this work
elegantly, we want to make sure we are not specifying dependencies twice, and
some language-specific package managers are able to recognise dependencies
already installed by Nix.</p>
<p>Nix 2.0 has the ability to verify hashes when using the <code>builtins.fetchTarball</code>
function with the <code>sha256</code> property. To know what hash you want to use. Run
<code>nix-prefetch-url --unpack https://package-you-want-to-use</code>. In our examples, we
utilise this parameter. However, to make the expressions work under 1.x, remove
the <code>sha256</code> parameter.</p>
<p>Often language specific dependencies do not appear in the online package search
engine
<a href="https://nixos.org/nixos/packages.html" target="_blank" rel="noopener noreferrer">https://nixos.org/nixos/packages.html</a>.
To actually find available packages, you can either look at the <code>nixpkgs</code> source
code, or use <code>nix-repl</code> with <code>:l &lt;nixpkgs&gt;</code> and then accessing the package set
relevant to your language. The same package set may be aliased to multiple
names. Some names are more general than other names. While the names may seem
ambiguous, within a content-addressed package set, what these names map to is
deterministic. In subsequent <code>nixpkgs</code> versions, the names may point to new
package sets.</p>
<p>If you are making use of pinned nixpkgs following our previous tutorial:
<a href="https://matrix.ai/2017/03/13/intro-to-nix-channels-and-reproducible-nixos-environment/" target="_blank" rel="noopener noreferrer">https://matrix.ai/2017/03/13/intro-to-nix-channels-and-reproducible-nixos-environment/</a>
You can acquire the hash of your current pinning via:
<code>git -C /nix/nixpkgs rev-parse HEAD</code>.</p>
<p>The package set for C in <code>nixpkgs</code> is itself!</p>
<p>Here is an example <code>shell.nix</code> for a C project:</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs </span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    url </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token url">https://github.com/NixOS/nixpkgs-channels/archive/084445b8f38ff8196f4b3f16d0ad0e79aa88dcbc.tar.gz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0jqxx3csxbs32ijn8w6cbd9c3l9vvsjz57rqsyp44dgg37xxx00i"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> pkgs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  stdenv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">mkDerivation </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"c-project"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> autoreconfHook </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Out of all the language environments, C has the best support. The
<code>stdenv.mkDerivation</code> already brings in the standard C toolchain.</p>
<p>In this particular example, we've used <code>autoreconfHook</code> as a <code>buildInput</code>. You
only need this if your project uses Autotools. If you use CMake, you would
instead bring in <code>cmake</code>.</p>
<h1>JavaScript</h1>
<p>The package set for JavaScript in <code>nixpkgs</code> is: <code>nodePackages</code>.</p>
<p>Here is an example <code>shell.nix</code> for a JavaScript project:</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs </span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    url </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token url">https://github.com/NixOS/nixpkgs-channels/archive/00e56fbbee06088bf3bf82169032f5f5778588b7.tar.gz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"15pl5p3f14rw477qg316gjp9mqpvrr6501hqv3f50fzlcxn9d1b4"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> pkgs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  stdenv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">mkDerivation </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"javascript-project"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> nodejs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">8_x flow </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Note how we are utilising <code>nodejs-8_x</code>. This is just an alias. What the alias
means depends on the content addressed package set. We are also bringing in
<code>flow</code> which is a JavaScript type checker.</p>
<p>Within this project we can use <code>npm</code> freely just like normal. So that's where we
will put all our dependencies.</p>
<p>For most projects, this is enough. However, some projects require building C++
extensions. To do this we need to find the toolchain required to build the
extension. The 3 common choices are <code>node-gyp</code>, <code>node-gyp-build</code> and
<code>node-pre-gyp</code>. Look at the <code>package.json</code> of the package you're trying to
install to find out which one is being used. Once you know this, you can add the
relevant toolchain to the <code>buildInputs</code>.</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)"># you don't actually need all 3 gyp toolchains, this is just an example</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  nodejs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">8_x</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  flow</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  nodePackages_8_x</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">node</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">gyp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  nodePackages_8_x</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">node</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">gyp</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  nodePackages_8_x</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">node</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">pre</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">gyp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In some cases, you may also need <code>python</code>. It all depends on what kind of
package you are installing.</p>
<p>The resulting project works in a Nix environment, and also works outside of a
Nix environment.</p>
<h1>Python</h1>
<p>The package set for Python in <code>nixpkgs</code> is: <code>python2Packages</code>,
<code>python3Packages</code>.</p>
<p>Here is an example <code>shell.nix</code> for a Python project:</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs </span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    url </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token url">https://github.com/NixOS/nixpkgs-channels/archive/630dbfe672164eeaf4bc822226cbb3ad7c1b0805.tar.gz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0xvj0z928mzcs56hindxw608a6jm1fvsi2ap5r7m4a0plnrcwx90"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> pkgs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  python35Packages</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">buildPythonApplication </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"python-project"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> python35Packages</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      numpy</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      gdal</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      scikitimage</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      tensorflowWithCuda</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">matplotlib</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">override </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> enableQt </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    shellHook </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">''</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      echo 'Entering Python Project Environment'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      set -v</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      # extra packages can be installed here</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      unset SOURCE_DATE_EPOCH</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      export PIP_PREFIX="$(pwd)/pip_packages"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      python_path=(</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">        "$PIP_PREFIX/lib/python3.5/site-packages"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">        "$PYTHONPATH"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      )</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      # use double single quotes to escape bash quoting</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      IFS=: eval 'python_path="''${python_path[*]}"'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      export PYTHONPATH="$python_path"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      export MPLBACKEND='Qt4Agg'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      set +v</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    ''</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This one is more sophisticated because it shows how to get Tensorflow with CUDA,
and <code>matplotlib</code> rendering with Qt4.</p>
<p>Because <code>pip</code> by default installs into a global directory, we have to set
<code>PIP_PREFIX</code> to a Project local directory. This directory should then be ignored
by <code>.gitignore</code>.</p>
<p>When using <code>pip</code>, it actually is aware of dependencies installed via Nix. So in
this case, if you later try to install a package that depends on <code>numpy</code>, <code>pip</code>
will not reinstall <code>numpy</code>. Unless of course that dependency has a constraint
that is not met by the <code>numpy</code> that you installed. The point is you can still
write a normal <code>setup.py</code> and <code>requirements.txt</code>, and the project is still
usable by non-Nix developers.</p>
<h1>Haskell</h1>
<p>The package set for Haskell in <code>nixpkgs</code> is: <code>haskellPackages</code>.</p>
<p>Here is an example <code>shell.nix</code> for a Haskell project:</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs </span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    url </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token url">https://github.com/NixOS/nixpkgs-channels/archive/8b1cf100cd8badad6e1b6d4650b904b88aa870db.tar.gz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"1p0xxyz30bd2bg0wrfviqgsskz00w647h0l2vi33w90i42k8r3li"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> pkgs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  haskell</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">lib</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">buildStackProject </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"haskell-project"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    shellHook </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">''</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      echo 'Entering Haskell Project Environment'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      set -v</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      alias stack="\stack --nix"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      set +v</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    ''</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>This example is really simple. Because here we are relying on <code>stack</code> to bring
in all the Haskell dependencies similar to how we setup a <code>shell.nix</code> for
JavaScript.</p>
<p>The usage of <code>haskell.lib.buildStackProject</code> wraps <code>stdenv.mkDerivation</code> and
adds all these features:
<a href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/generic-stack-builder.nix" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/haskell-modules/generic-stack-builder.nix</a></p>
<p>When using <code>--nix</code> flag on <code>stack</code>, it just makes sure that <code>stack</code> will utilise
the GHC supplied by the <code>haskell.lib.buildStackProject</code>, instead of acquiring
its own GHC, which would be a waste of time. All other stack commands work
normally.</p>
<p>Becareful with the usage of the alias here. If you have scripts (like a
<code>Makefile</code>) inside that call <code>stack</code>, they may not have <code>--nix</code> applied. If so
something will go wrong. It would be better to have some sort of environment
variable instead, but I'm not aware of it.</p>
<p>An alternative to using the alias is to set:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  enable: true</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>In your Project's <code>stack.yaml</code> or in <code>~/.stack/config.yaml</code>. If you are
expecting that your projects will be used by people not using Nix, then it makes
sense not to put it in the Project's <code>stack.yaml</code>. However instead you can then
put it in <code>~/.stack/config.yaml</code>.</p>
<p>When using <code>stack</code> if a dependency doesn't build, that could be because it's
missing a C library. The most common is probably <code>zlib</code>. If so, just put it into
your <code>buildInputs</code>.</p>
<h1>Emscripten</h1>
<p>The package set for Emscripten in <code>nixpkgs</code> is: <code>emscriptenPackages</code>.</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs </span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    url </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token url">https://github.com/NixOS/nixpkgs-channels/archive/084445b8f38ff8196f4b3f16d0ad0e79aa88dcbc.tar.gz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0jqxx3csxbs32ijn8w6cbd9c3l9vvsjz57rqsyp44dgg37xxx00i"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> pkgs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  stdenv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">mkDerivation </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"emscripten-project"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      emscripten</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      cmakeCurses</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      pkgconfig</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      python2</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      nodejs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      flow</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    shellHook </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">''</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      EMSCRIPTEN_ROOT_PATH='</span><span class="token string interpolation antiquotation important" style="color:rgb(206, 145, 120)">$</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string interpolation" style="color:rgb(206, 145, 120)">emscripten</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/share/emscripten'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">      EMSCRIPTEN='</span><span class="token string interpolation antiquotation important" style="color:rgb(206, 145, 120)">$</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string interpolation" style="color:rgb(206, 145, 120)">emscripten</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/share/emscripten'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    ''</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>At this moment we are not aware of any function which wraps
<code>stdenv.mkDerivation</code> that deals with <code>emscripten</code> requirements. Preferably this
can either be stored in a package hook when you bring in <code>emscripten</code> or it can
be placed into a special function. This means at this point if you bring in an
<code>emscriptenPackages</code>, it isn't automatically registered. You have to find the
relevant environment variable to configure in your <code>shellHook</code>.</p>
<h1>PHP</h1>
<p>The package set for PHP in <code>nixpkgs</code> is: <code>phpPackages</code>.</p>
<p>Here is an example <code>shell.nix</code> for a PHP project:</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs </span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    url </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token url">https://github.com/NixOS/nixpkgs-channels/archive/084445b8f38ff8196f4b3f16d0ad0e79aa88dcbc.tar.gz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"0jqxx3csxbs32ijn8w6cbd9c3l9vvsjz57rqsyp44dgg37xxx00i"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> pkgs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  stdenv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">mkDerivation </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"php-project"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      php71</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">++</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> php71Packages</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      composer</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Here we rely on <code>composer</code> to bring in all the PHP dependencies. So it's just
like JavaScript.</p>
<h1>Database Services</h1>
<p>Application projects often might rely on a database service. You can use
<code>shell.nix</code> <code>shellHook</code> to help set this up, so that each project can have its
own database running within the shell. To make this work without adding in
container/network namespaces, we rely on unix domain sockets. This allows each
database process to only communicate with a project local unix domain socket.</p>
<p>Here is an example using MySQL and the Flyway migrations system:</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">shellHook </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">''</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  echo 'Entering MySQL Environment'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  . ./.env</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  set -v</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  alias mysql="\mysql --socket='$(pwd)/.mysql/mysql.sock' "$DB_DATABASE""</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  alias mysqladmin="\mysqladmin --socket='$(pwd)/.mysql/mysql.sock'"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  alias mysqld="\mysqld \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    --datadir="$(pwd)/.mysql" \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    --socket="$(pwd)/.mysql/mysql.sock" \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    --bind-address="$DB_HOST" \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    --port="$DB_PORT""</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  alias flyway="\flyway \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    -user="$DB_USERNAME" \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    -password="$DB_PASSWORD" \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    -url="jdbc:mysql://$DB_HOST:$DB_PORT/$DB_DATABASE" \</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">    -locations=filesystem:$(pwd)/migrations";</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">  set +v</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">''</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Notice the <code>.env</code> file which stores all the environment variables. So you can
use <code>shell.nix</code> as a <code>dotenv</code> replacement.</p>
<p>Remember to set up initialise your database before you start using it!</p>
<p>rm -rf .mysql &amp;&amp; mkdir .mysql
mysqld --datadir="$(pwd)/.mysql" --initialize-insecure</p>
<h1>launch your database without networking!</h1>
<p>mysqld --skip-networking &amp;</p>
<p>Again beware of using aliases, it is actually better to use environment
variables when possible as they will carry over to any scripts you run.</p>
<p>Here's a bonus using PostgreSQL and PostGIS:</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs </span><span class="token operator" style="color:rgb(212, 212, 212)">?</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token url">https://github.com/NixOS/nixpkgs-channels/archive/49a0ecc49b491c1f1a6f329d3d4fc9cf559b18aa.tar.gz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> pkgs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">let</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    pg </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">pg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      buildEnv </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"postgresql-and-plugins-</span><span class="token string interpolation antiquotation important" style="color:rgb(206, 145, 120)">$</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string interpolation keyword" style="color:rgb(86, 156, 214)">builtins</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string interpolation function" style="color:rgb(220, 220, 170)">parseDrvName</span><span class="token string interpolation" style="color:rgb(206, 145, 120)"> pg</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string interpolation" style="color:rgb(206, 145, 120)">name</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string interpolation" style="color:rgb(206, 145, 120)">version</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        paths </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> pg pg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">lib </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">postgis</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">override </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> postgresql </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> pg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> makeWrapper </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        postBuild </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">''</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">          mkdir -p $out/bin</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">          rm $out/bin/{pg_config,postgres,pg_ctl}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">          cp --target-directory=$out/bin </span><span class="token string interpolation antiquotation important" style="color:rgb(206, 145, 120)">$</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string interpolation" style="color:rgb(206, 145, 120)">pg</span><span class="token string interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string" style="color:rgb(206, 145, 120)">/bin/{postgres,pg_config,pg_ctl}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">          wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token string" style="color:rgb(206, 145, 120)">        ''</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">in</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    stdenv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">mkDerivation </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"project-with-postgres-postgis"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      buildInputs </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">pg postgresql</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>nix</category>
            <category>nixos</category>
            <category>programming</category>
        </item>
        <item>
            <title><![CDATA[Intro to Nix Channels and Reproducible NixOS Environment]]></title>
            <link>https://matrix.ai/learn/blog/intro-to-nix-channels-and-reproducible-nixos-environment</link>
            <guid>https://matrix.ai/learn/blog/intro-to-nix-channels-and-reproducible-nixos-environment</guid>
            <pubDate>Mon, 13 Mar 2017 00:00:00 GMT</pubDate>
            <description><![CDATA[This introduction assumes you have played with NixOS a bit, you know about]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>This introduction assumes you have played with NixOS a bit, you know about
content addressability and why it is important, and how Git repositories
represent a distributed content addressed storage system.</p>
<p>Git and Github is used as the source control for all of NixOS and NixPkgs. Both
NixOS and NixPkgs source code is located here:
<a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs</a>. This means
every package that is available via Nix is defined in that repository. This
includes OS services and general software. Nix, the language interpreter and the
package manager tool is however located here:
<a href="https://github.com/NixOS/nix" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nix</a>.</p>
<p>Channels is a rolling distribution endpoint that provides the latest builds of
NixOS and Nixpkgs, and the Nix expression set corresponding to those builds.
Because NixOS is just a particular build of NixPkgs that is geared towards
running a full OS, we'll be using NixOS channels and not NixPkgs channels. The
channels have names of the form:</p>
<ul>
<li><code>nixos-YY.MM</code></li>
<li><code>nixos-YY.MM-small</code></li>
<li><code>nixos-unstable</code></li>
<li><code>nixos-unstable-small</code></li>
<li><code>nixpkgs-unstable</code></li>
</ul>
<p>We will ignore NixPkgs channels (<code>nixpkgs-*</code>) and only focus on NixOS channels
(<code>nixos-*</code>) because the NixPkgs channels are intended to be used by non-NixOS
users like other Linux distributions or Macintosh users. The exact artifacts
that the channel points to will have their names detailed in this way:
<code>label-YY.MM.N.H-*</code>. The <code>label</code> is is name of the artifact such as <code>nixos</code>,
<code>nixos-graphical</code>, <code>nixos-minimal</code>. The <code>N</code> is the iteration number of the major
version <code>YY.MM</code>. The <code>H</code> is a 7 character truncated Git hash. The <code>*</code> is the
reamining metadata for the build artifact.</p>
<p>Channels are built from Git release branches on the official NixPkgs source
repository:
<a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs</a>. The
branches are notated as <code>release-YY-MM</code>. On every commit to these branches,
Hydra (the Nix build system) clones the source code and builds them while
running tests. If these tests succeed, the successful branch commit is then
propagated to a channels repository located at:
<a href="https://github.com/NixOS/nixpkgs-channels" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs-channels</a>.
Hydra will also "release" them to the official channel endpoint at:
<a href="https://nixos.org/channels/" target="_blank" rel="noopener noreferrer">https://nixos.org/channels/</a> . Once a commit is
available at <a href="https://nixos.org/channels" target="_blank" rel="noopener noreferrer">https://nixos.org/channels</a>, it is
guaranteed that the packages specified inside the corresponding Nix expressions
will be built, and cached in the binary cache.</p>
<p>Let's see if these things match up (here we use <code>httpie</code>, <code>pup</code> and <code>jq</code>):</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">http https://nixos.org/channels/ </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> pup </span><span class="token string" style="color:rgb(206, 145, 120)">'table tr:nth-child(n+4) td a attr{href}'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">http </span><span class="token string" style="color:rgb(206, 145, 120)">'https://api.github.com/repos/NixOS/nixpkgs/branches?per_page=100'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> jq </span><span class="token string" style="color:rgb(206, 145, 120)">'[.[] | select(.name | startswith("release"))]'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">http </span><span class="token string" style="color:rgb(206, 145, 120)">'https://api.github.com/repos/NixOS/nixpkgs-channels/branches?per_page=100'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The released channel hashes
(<a href="https://nixos.org/channels/" target="_blank" rel="noopener noreferrer">https://nixos.org/channels/</a>) exactly match the
channels repository branch hashes
(<a href="https://github.com/NixOS/nixpkgs-channels" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs-channels</a>).</p>
<p>However because Hydra takes time to build and verify release branches, the
release branches at
<a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs</a> will be
sometimes ahead of the released channel branches and released channels.</p>
<p>Some extra things to note:</p>
<ul>
<li>The <code>small</code> channel variants are updated before the entire package set is
built. This means the <code>small</code> channel variants will be up to date with the
latest security changes and bug fixes compared to the non-<code>small</code> variants.
This does mean that sometimes Nix will force a build from source rather than
downloading pre-built packages.</li>
<li>The <code>nixos-unstable</code> channel corresponds to the <code>master</code> branch at
<a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs</a>. The
master branch will sometimes be ahead of the channel, as the channel relies on
Hydra to finish evaluation.</li>
<li>There is no channel that corresponds to the <code>staging</code> branch.</li>
<li>The <code>staging</code> branch at
<a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs</a> is even
more unstable than <code>master</code>. The <code>staging</code> branch is intended for changes that
will cause mass-rebuilds of packages, and is supposed to be merged back into
<code>master</code> every couple weeks.</li>
</ul>
<p>So which source should we source our channels from? It depends:</p>
<ul>
<li>If you are developing on NixOS, you'll often need to make use of the latest
commits or pull requests, in that case, you have to use branches from
<a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs</a>.</li>
<li>If you're just using NixOS and want to have a stable experience, you should
use the official released channels endpoint at
<a href="https://nixos.org/channels/" target="_blank" rel="noopener noreferrer">https://nixos.org/channels/</a></li>
<li>If you're power user, but you still want a stable experience, you should use
the Git release branches at
<a href="https://github.com/NixOS/nixpkgs-channels" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nixpkgs-channels</a>.</li>
</ul>
<p>The great thing about Nix, is that you can mix-and-match. Your system can be
sourced from release branches, while cherry-picking changes directly from
official nixpkgs repository, and even picking up forks, random commits and
making use of them inside a Nix profile or a nix-shell.</p>
<p>However if you need to download the built ISOs for a given release, these should
be downloaded from <a href="https://nixos.org/channels/" target="_blank" rel="noopener noreferrer">https://nixos.org/channels/</a>,
because the repositories don't host these artifacts. Another source for built
artifacts is Hydra itself, but we'll not go into this yet.</p>
<p>It is at this point where we must differentiate the channels at
<a href="https://nixos.org/channels/" target="_blank" rel="noopener noreferrer">https://nixos.org/channels/</a> and the Git
repository sources from which those channels are built from. The minimal
definition of a "channel" is a directory with 2 files: <code>nixexprs.tar.xz</code> and
<code>binary-cache-url</code>. The <code>nixexprs.tar.xz</code> is the tarball that contains a
<code>default.nix</code> which is what is actually used to evaluate Nix expressions. The
<code>binary-cache-url</code> is just a text pointer to another location containing the
cache for the Nix expressions.</p>
<p>The main utility of using these official channels over the sources in the Git
repositories is so that you can know when the binary cache is ready to supply
all the packaeges in the channel's Nix expression. Nix provides a command called
<code>nix-channel</code> which allows you manage system and profile channels. The system
channel is also the root user's channel.</p>
<p>Ultimately you can think of using Nix channels for every day usage, but you
should be using the Git repository hashes as sources for your package sets when
you care about reproducibility, which basically whenever you're developing
software. On installation of a fresh NixOS system, there will be one channel the
system is already subscribed to.</p>
<p>Running <code>sudo nix-channel --list</code> will show something like:
<code>nixos https://nixos.org/channels/nixos-17.03</code>. The <code>nixos</code> name is just an
alias, it allows you refer to multiple channels during package installation.
(This is not as flexible as directly using the Git sources, because you need a
proper channel structure including the <code>binary-cache-url</code>, and we don't have a
valid binary cache for every single source commit hash.)</p>
<p>Having multiple channel aliases, allows you perform installations like
<code>nix-env --install --attr nixos.packagename</code> or
<code>nix-env --install --attr mycoolchannel.packagename</code>. This also means anybody
can publish a channel, they just need to provide a binary cache as well.</p>
<p>We had to use <code>sudo</code> because by default in order to see the channel of the root
user/system. But every user on a NixOS system can manage their own set of
channels, where the channel aliases can override the system channel aliases.</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)"># make sure you don't have `.` or `-` in the channel name!!!</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># this is a bug: https://github.com/NixOS/nix/issues/1457</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-channel </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--add</span><span class="token plain"> https://nixos.org/channels/nixos-17.03-small nixosSmall1703</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-channel </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--update</span><span class="token plain"> nixosSmall1703</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-iA</span><span class="token plain"> nixosSmall1703.xmlstarlet</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Adding a channel by itself does not download the channel expressions, you need
explicitly run the update command. The channels are stored in <code>/nix/store</code> but
referenced from <code>~/.nix-defexpr</code> (this exists for both normal users and the root
user). If you want to learn more about this, watch the contents of
<code>~/.nix-defexpr/channels/</code> and <code>~/.nix-defexpr/channels_root/</code> while running the
above commands.</p>
<p>The <code>nix-channel</code> command is quite limited, it does not tell you what channels
are out of date, so you would need to run the <code>--update</code> command often to get
the latest released iterations of each channel. You can find the exact version
of your channel by looking at
<code>cat ~/.nix-defexpr/channels/nixosSmall1703/svn-revision</code> or
<code>~/.nix-defexprs/channels_root/nixos/svn-revision</code>. But this is not an official
supported technique.</p>
<p>You can remove channels with <code>nix-channel --remove nixosSmall1703</code>, and you
don't need to run <code>nix-channel --update</code>.</p>
<p>Because of how channels work, we prefer to side-step this functionality and
instead pin our NixOS system a particular commit hash within a released channel.
This is what makes a NixOS system reproducible. We'll try to make sure that the
packages we want to install are all from a single commit hash. Note that this is
sometimes not possible when a package at a particular iteration or version is
only available at a different commit hash, and you don't want to move your
entire system to that commit hash. However with Nix, it's very easy to have
packages from multiple different commit hashes cohabiting on the same system,
and when you need isolation, this can be provided via Nix profiles or nix-shell.</p>
<p>While we could just import the desired Nix expression inside our
configuration.nix, certain tools like <code>nix-env</code> relies on the ambient channel
setup to install packages. The right way to solve this would be to make
<code>nix-channel</code> support specific commit hashes and local directories containing
Nix expressions, rather than only channel directories. This would make pinning a
NixOS system much easier, and would seamlessly work with the existing <code>nix-env</code>
expectations. There is however a workaround involving the utilisation of the Git
content-addressed system and <code>NIX_PATH</code>. This workaround was discovered here:
<a href="http://anderspapitto.com/posts/2015-11-01-nixos-with-local-nixpkgs-checkout.html" target="_blank" rel="noopener noreferrer">http://anderspapitto.com/posts/2015-11-01-nixos-with-local-nixpkgs-checkout.html</a>
( There is an error with this workaround that is discussed below.)</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)"># switch to super user</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">sudo</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--login</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># we're going to create /nix/nixpkgs as our pinned nix expressions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">rm</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--recursive</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--force</span><span class="token plain"> /nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> clone https://github.com/nixos/nixpkgs /nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> /nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> remote </span><span class="token function" style="color:rgb(220, 220, 170)">add</span><span class="token plain"> channels https://github.com/nixos/nixpkgs-channels</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> fetch </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--all</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> checkout </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">-B</span><span class="token plain"> channels-nixos-17.03 channels/nixos-17.03</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># /nix/nixpkgs will now be set to branch channels-nixos-17.03 and tracking channels/nixos-17.03</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now go into your configuration.nix, and set
<code>nix.nixPath = [ "nixpkgs=/nix/nixpkgs" "nixos-config=/etc/nixos/configuration.nix" ];</code>.</p>
<p>Since the current <code>NIX_PATH</code> hasn't updated yet, we need to force a rebuild with
the the new source for Nix expressions:
<code>nixos-rebuild -I nixpkgs=/nix/nixpkgs switch</code>.</p>
<p>When you want to update you can just perform a <code>git pull</code> on the directory.
These Git commands will also be helpful when you want to checkout a specific
commit hash, or when you want to switch to a different channel source.</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)"># show remote info</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> remote show channels</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># update all remotes</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> fetch </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--all</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># see all the branches that is available</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> branch </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--all</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--verbose</span><span class="token plain"> </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--verbose</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># see what the remote provides along with pull requests to that remote</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> ls-remote channels</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># if you have added changes to your local branch, you can rebase your changes on top of any updates</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> rebase channels/nixos-17.03 channels-nixos-17.03</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># if you want to reset to upstream channel and drop any local changes (resets the working tree as well)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> reset </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--hard</span><span class="token plain"> channels/nixos-17.03</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Now we can remove the system channel and any user-channels as they will no
longer be used:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-channel </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--remove</span><span class="token plain"> nixosSmall1703</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">sudo</span><span class="token plain"> nix-channel </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--remove</span><span class="token plain"> nixos</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>All nix commands except the <code>nix-env</code> command will work. The <code>nix-env</code> currently
only uses <code>~/.nix-defexpr</code>. This issue
(<a href="https://github.com/NixOS/nix/issues/993" target="_blank" rel="noopener noreferrer">https://github.com/NixOS/nix/issues/993</a>)
asked to make <code>nix-env</code> use <code>NIX_PATH</code> or <code>&lt;nixpkgs&gt;</code> as a fallback if there are
no channels installed. However this was only implemented in the new Nix UI
project, and is not available on the current <code>nix-env</code> (1.11.15). The only way
to make <code>nix-env</code> use <code>NIX_PATH</code> is to alias it with the option
<code>--file '&lt;nixpkgs&gt;'</code>. This is safe as you can override the <code>--file</code> option by
specifying it again. Once you do this, attribute path installation doesn't
require a channel name. For example:
<code>nix-env --file '&lt;nixpkgs&gt; --install --attr 'hello'</code>.</p>
<p>While this makes sense for general purpose use, for unattended NixOS servers
where it doesn't make sense to use <code>nix-env</code>, there is no need to do all of
this, and you can just directly import a content-addressed Nix expression set
inside your configuration.nix.</p>
<p>At this point we can see how to acquire packages from different sources
(including other commit hashes) and have them all coexist. There are 2 ways to
do this. Through the imperative <code>nix-env</code> command that mutates your profile
state, and through Nix expressions that you can inline into your
configuration.nix or your nix-shell configuration files.</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--file</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'&lt;nixpkgs&gt;'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--file</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'/package.nix'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--file</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'/directory/containing/default.nix/'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--file</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'/tarball/containing/default.nix/tarball.tar'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--file</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'https://github.com/NixOS/nixpkgs/archive/master.tar.gz'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--file</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'https://github.com/NixOS/nixpkgs/archive/74f22ff827d7c91fe26a62c69a53556a62ecc70c.tar.gz'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">nix-env </span><span class="token parameter variable" style="color:rgb(156, 220, 254)">--file</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'https://nixos.org/channels/nixos-unstable/nixexprs.tar.xz'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Because <code>/nix/nixpkgs</code> is owned by root, if you run Git operations via <code>sudo</code>,
you'll end up with permissions that don't allow usage by other users (due to the
default umask used by Git when creating new files). You'll need to run these
commands to reset to proper permissions. We need to make sure that all
directories are at least can be readable and executable by all users, and that
all files are at least readable by all users.</p>
<h1>they are just build support files</h1>
<p>sudo chmod --recursive u=rwX,g=,g=rX,o=,o=rX /nix/nixpkgs</p>
<p>There may be a way to avoid these permission problems in the future.</p>
<p>As you can see we rely on Github to expose specific commit hashes as tarballs
that our <code>nix-env</code> can consume. This makes it convenient to install packages
from different branches, forks and even pull requests.</p>
<p>The same thing can be done inside a Nix expression such as our
configuration.nix. The key primop is <code>import</code>. This command expects either a
directory containing <code>default.nix</code> or a Nix file. If we intend to acquire an
expression set remotely, we just need to use <code>fetchTarball</code> to expose the Nix
expression. Note that <code>nixpkgs</code> based expressions is exported as a function,
which means you can apply an empty attribute set to it before using it. The
attribute set argument is intended to provide various flags into the Nixpkgs
attribute set.</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">let</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">env </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain">nixpkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">my </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token url">./package.nix</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">dir </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token url">./packages/containing/default.nix/</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">unstable </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token function" style="color:rgb(220, 220, 170)">fetchTarball</span><span class="token plain"> </span><span class="token url">http://nixos.org/channels/nixos-unstable/nixexprs.tar.xz</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">in</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    environment</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">systemPackages </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">env</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">packageAttrName</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">my</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">packageAttrName</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">dir</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">packageAttrName</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      pkgs</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">unstable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">packageAttrName</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Any path specified with angle brackets such as <code>&lt;nixpkgs&gt;</code> utilises the
<code>NIX_PATH</code> environment variable to find files. We just set our <code>NIX_PATH</code> to
<code>nixpkgs=/nix/nixpkgs</code>, which means <code>&lt;nixpkgs&gt;</code> just resolves to <code>/nix/nixpkgs</code>.
However if we instead had <code>&lt;something/subthing&gt;</code>, this would try to look for
<code>something/subthing</code> in each of the paths listed in the <code>NIX_PATH</code>. This is how
it works:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">NIX_PATH = nixpkgs=/nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&lt;nixpkgs&gt; = /nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">NIX_PATH = nixpkgs=/nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&lt;nixpkgs/lib&gt; = /nix/nixpkgs/lib</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">NIX_PATH = nixpkgs=/nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&lt;nonexistent&gt; = Error</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">NIX_PATH = /somedir/containing/something/:nixpkgs=/nix/nixpkgs</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&lt;something&gt; = /somedir/containing/something/something</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>You can find out ahead of time whether Nix will find an angular path by using:
<code>nix-instantiate --eval --expr '&lt;something&gt;'</code>.</p>
<p>The same techniques can be further applied in your shell.nix when developing
inside an isolated Nix shell, you should make sure your software environment is
reproducible.</p>
<p>However if you are developing a package for the purpose of inclusion into
official Nixpkgs, after you've done with development, if you are dependent on
packages that is already available in one of the Nixpkgs iterations, you should
rely on the ambient Nixpkgs provided through the <code>pkgs</code> attribute. This ensures
that packages within a single Nixpkgs package set work in harmony with each
other, and reduce the number of unnecessary duplicated dependencies. We have
found that within the Nixpkgs source, there are times when multiple versions of
a particular package is required by different downstream packages, this is when
the particular iteration of Nixpkgs will often contain multiple versions of the
same package. However, as soon as these conflicts are fixed, either by the
upstream of the Nixpkgs maintainers, the older versions of the package will be
deprecated and removed from future iterations of NixPkgs.</p>
<p>One possible downside is that you won't get automatic security updates with this
approach. However this depends on your priorities. When in the act of developing
software, reproducibility matters more. When in the act of maintaining/operating
software, automatic security updates matter more. You can get the best of both
worlds by building a system to monitor security issues relevant to your software
dependency graph, and trigger updates then builds then tests before finally
deploying.</p>
<hr>
<p><strong>UPDATE</strong>: We have found a way to avoid needing to apply permission changes
after updating your <code>/nix/nixpkgs</code>. You do this by applying a temporary <code>umask</code>
change. The reason is that the permission problems applies to new files being
created by <code>git</code>.</p>
<h1>we use a subshell to make umask change temporary</h1>
<p>(umask 022 &amp;&amp; sudo git -C /nix/nixpkgs checkout channels-nixos-17.09)
(umask 022 &amp;&amp; sudo git -C /nix/nixpkgs pull)</p>
<p>The above can be automated by changing <code>sudo</code> umask options:
<a href="https://unix.stackexchange.com/a/278817/56970" target="_blank" rel="noopener noreferrer">https://unix.stackexchange.com/a/278817/56970</a></p>
<p>Also, when you are using <code>sudo</code> while doing <code>git</code> operations requiring
authentication. You may require <code>sudo -E</code> or <code>sudo --preserve-env</code> to preserve
your SSH or GPG environment.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
            <category>nix</category>
            <category>nixos</category>
        </item>
        <item>
            <title><![CDATA[Configuration Divergence]]></title>
            <link>https://matrix.ai/learn/blog/configuration-divergence</link>
            <guid>https://matrix.ai/learn/blog/configuration-divergence</guid>
            <pubDate>Sat, 01 Oct 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Configuration]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p><a href="https://en.wikipedia.org/wiki/Configuration_management" target="_blank" rel="noopener noreferrer">Configuration</a>
<a href="https://blog.flyingcircus.io/2016/05/06/thoughts-on-systems-management-methods/" target="_blank" rel="noopener noreferrer">divergence</a>
is a result of <a href="https://en.wikipedia.org/wiki/Software_entropy" target="_blank" rel="noopener noreferrer">change entropy</a>
in an environment that doesn't enforce
<a href="https://en.wikipedia.org/wiki/Referential_integrity" target="_blank" rel="noopener noreferrer">referential integrity</a>
between <a href="https://en.wikipedia.org/wiki/Loose_coupling" target="_blank" rel="noopener noreferrer">loosely-coupled</a> state or
"state-at-a-distance". Simultaneously this allows the anti-pattern of
<a href="https://en.wikipedia.org/wiki/Action_at_a_distance_(computer_programming)" target="_blank" rel="noopener noreferrer">action at a distance</a>.
This phenomenon is also called
"<a href="https://en.wikipedia.org/wiki/Connascence_(computer_programming)" target="_blank" rel="noopener noreferrer">Connascence</a>"
and I have also called this
"<a href="https://en.wikipedia.org/wiki/Coupling_(computer_programming)" target="_blank" rel="noopener noreferrer">meta-coupling</a>".</p>
<p>This process gives us a system that becomes more and more opaque as time
continues, and we lose
<a href="https://en.wikipedia.org/wiki/Referential_transparency" target="_blank" rel="noopener noreferrer">referential transparency</a>
on the entire system. The result of course is a repeated cycle of
<a href="http://c2.com/cgi/wiki?EntropyReduction" target="_blank" rel="noopener noreferrer">entropic reduction projects</a> (often
called " refactoring" or "rewriting") where consultants are hired to clean up
<a href="https://en.wikipedia.org/wiki/Technical_debt" target="_blank" rel="noopener noreferrer">technical debt</a>. Occasionally
these projects will suffer from the
<a href="https://en.wikipedia.org/wiki/Second-system_effect" target="_blank" rel="noopener noreferrer">second system effect</a>. All
of this resolves to increase the cost of changing/adapting software systems.</p>
<p>With this in mind, the significant difference between
<a href="http://c2.com/cgi/wiki?DataAndCodeAreTheSameThing" target="_blank" rel="noopener noreferrer">data and code</a> is that code
is usually considered to be
<a href="https://matrix.ai/2015/05/23/declarative-stateless-migrations-in-databases/" target="_blank" rel="noopener noreferrer">"stateless"</a>,
and data to be "stateful" , but this is not a difference in kind, but a
difference in degree. In time, both data and code will be changed, and will
exhibit all the properties of "stateful" systems. Therefore, this problem cannot
be solved with
<a href="http://gfxmonk.net/2015/01/03/nixos-and-stateless-deployment.html" target="_blank" rel="noopener noreferrer">tools</a> that
only enforce a consistent
<a href="https://en.wikipedia.org/wiki/Baseline_(configuration_management)" target="_blank" rel="noopener noreferrer">baseline</a>.
We either accept divergence and try to
<a href="https://en.wikipedia.org/wiki/CFEngine#Convergence" target="_blank" rel="noopener noreferrer">converge back to the fixed point</a>,
or we rebuild with tools that are
<a href="http://c2.com/cgi/wiki?CorrectByConstruction" target="_blank" rel="noopener noreferrer">correct by construction</a>. As a
software community, we'll get there eventually, but it's going to take time.</p>
<p>Here are examples of this problem:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Magic_string" target="_blank" rel="noopener noreferrer">Magic Strings</a> and
<a href="https://en.wikipedia.org/wiki/Magic_number_(programming)" target="_blank" rel="noopener noreferrer">Magic Numbers</a></li>
<li>Laravel's Route Tags</li>
</ul></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Reproducible Builds vs Semantic Versioning]]></title>
            <link>https://matrix.ai/learn/blog/content-addressed-dependencies-vs-semantic-versioning</link>
            <guid>https://matrix.ai/learn/blog/content-addressed-dependencies-vs-semantic-versioning</guid>
            <pubDate>Tue, 05 Apr 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Today, the most common way for developers to address a dependency is through the]]></description>
            <content:encoded><![CDATA[<div class="grid-cols-[repeat(2,minmax(65%,1fr))] space-x-40 text-balance md:grid"><div><p>Today, the most common way for developers to address a dependency is through the
use of <a href="http://semver.org/" target="_blank" rel="noopener noreferrer">semantic versioning</a>. This is where you create
project <code>A</code> that depends on <code>B</code> at <code>1.2.3</code>, where <code>1</code> is the major version, <code>2</code>
is the minor version and <code>3</code> is the patch version.</p>
<p>Accordingly, the rules of following semantic versioning means:</p>
<ol>
<li>Major versions change when you make incompatible API changes.</li>
<li>Minor versions change when you add functionality in a backwards-compatible
manner.</li>
<li>Patch versions change when you make backwards-compatible bug fixes.</li>
</ol>
<p>Theoretically you should be able to update patch and minor versions of
dependencies without any kind of problem. In fact many package managers
<a href="https://getcomposer.org/doc/articles/versions.md#tilde" target="_blank" rel="noopener noreferrer">recommend</a> that you
should use the "next significant release" dependency address notation of <code>~1.2</code>
which means <code>&gt;=1.2 &lt;2.0.0</code> or <code>~1.2.3</code> meaning <code>&gt;=1.2.3 &lt;1.3.0</code>.</p>
<p>In practice this often can lead to subtle bugs, and occasional flaky builds.
There's just nothing that guarantees that updating a patch version will not
break a build, and sometimes software is so complex, the runtime behaviour of a
minor version bump might cause problems in production or at scale. Over time
we've learned that dealing with these nightmares is not worth it, and that fixed
versions is the right way to go. If we want to update, we must verify the update
works. This idea of fixing versions is done by many package managers, such as
PHP's composer will create a <code>composed.lock</code> that will lock down all the
versions as long as you don't run another <code>composer update</code>.</p>
<p>However, there's still one more problem, there's no guarantee that what is
<code>1.2.3</code> today is what's <code>1.2.3</code> a month from now. This is because there's no
direct relationship between a semantic version tag and the actual contents of
the dependency. Instead, there's just a third party that you are trusting when
you are asking them for the package that is <code>1.2.3</code>. The only constraint that
<code>1.2.3</code> is enforcing, is that the package must say it's <code>1.2.3</code>. However the
package could have changed in the meantime, while spoofing the package version.</p>
<p>If only there was a way to refer to some package or dependency, not by some
arbitrary tag, but by an address that represented the contents of the package...</p>
<p>Well there is! Check out
<a href="https://en.wikipedia.org/wiki/Content-addressable_storage" target="_blank" rel="noopener noreferrer">Content Addressable Storage</a>.
The idea is simple, we need a crytographic hash function to generate a digest of
the package contents, store in into a location that is referencable by hashes.</p>
<p>While this is not a new idea, doing a short google search shows that there is
only 3 package management systems today that can be considered a content
addressable package system:</p>
<ul>
<li><a href="https://nixos.org/" target="_blank" rel="noopener noreferrer">Nix, Nixpkgs and NixOS</a> (and the related
<a href="https://www.gnu.org/software/guix/" target="_blank" rel="noopener noreferrer">Guix</a>)</li>
<li><a href="http://gugel.io/ied/" target="_blank" rel="noopener noreferrer">ied</a></li>
<li><a href="https://git-scm.com/" target="_blank" rel="noopener noreferrer">Git</a></li>
</ul>
<p>Having content addressable dependencies is the first of the necessary factors
for <a href="https://reproducible-builds.org/" target="_blank" rel="noopener noreferrer">reproducible builds</a>. The second
necessary factor is for mirrored dependency storage. You cannot rely on the
third party to maintain availability of the dependency (they may go down for a
myriad of reasons: downtime, ddos, network problems, lawsuits like the
<a href="http://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm" target="_blank" rel="noopener noreferrer">leftpad fiasco</a>).</p>
<p>Nix and Git are the 2 systems that I'm most familiar with in the above list. It
turns out both systems can satisfy both of the necessary factors, but not out of
the box.</p>
<p>For Nix, while we get content addressable dependencies. The official
<a href="https://github.com/NixOS/nixpkgs" target="_blank" rel="noopener noreferrer">nixpkgs</a> does not do any dependency or source
code mirroring (it does have a binary cache, but that's not what I'm talking
about). This means from time to time, you can get build failures because the
upstream source code has gone offline, in fact this happened to me a month ago
with the dependencies from <a href="https://www.freedesktop.org/wiki/" target="_blank" rel="noopener noreferrer">freedesktop.org</a>.
However you can work around this, by creating your own mirrors of the upstream
dependencies, and creating nix expressions for them. It is however not currently
a first class feature.</p>
<p>For Git, content address package management relies on the cutting edge
<a href="https://git-scm.com/docs/git-submodule" target="_blank" rel="noopener noreferrer">submodule</a> feature of Git. So cutting
edge, that you need the latest Git 2.8 to get everything to work. Submodules are
basically subproject Git repositories within a superproject Git repository. In
fact you can actually clone any Git repository, and you can do work on that
subproject and push from it to the upstream remote without affecting the
superproject other than updating the commit hash that the superproject tracks.
The key feature is that the superproject tracks the commit hash of the
subprojects, hence all dependencies here are identified by their content
address. So that when you later clone the superproject, you will get exactly the
dependencies that were specified by the content address, and nothing else. Git
currently uses a <a href="https://gist.github.com/masak/2415865" target="_blank" rel="noopener noreferrer">SHA1 hash</a> as their
commit hash.</p>
<p>Here we demonstrate a simple way of using Git submodules:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; cd /tmp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; mkdir --parents SuperProject</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; cd SuperProject</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git init</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Initialized empty Git repository in /tmp/SuperProject/.git/</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; echo 'Hello World' &gt; ./README.md</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git add --all</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git commit --message='Hello World'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">[master (root-commit) a60c612] Hello World</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> 1 file changed, 1 insertion(+)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> create mode 100644 README.md</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; mkdir --parents modules</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git ls-remote https://github.com/CMCDragonkai/bashpp.git</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">5e94d3c285f4424f3fa4c6ddf036f405688b1d51        HEAD</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">5e94d3c285f4424f3fa4c6ddf036f405688b1d51        refs/heads/master</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">5e94d3c285f4424f3fa4c6ddf036f405688b1d51        refs/tags/0.0.1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git submodule add https://github.com/CMCDragonkai/bashpp.git modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Cloning into 'modules/bashpp'...</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">remote: Counting objects: 344, done.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">remote: Compressing objects: 100% (5/5), done.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">remote: Total 344 (delta 0), reused 0 (delta 0), pack-reused 338</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Receiving objects: 100% (344/344), 66.20 KiB | 46.00 KiB/s, done.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Resolving deltas: 100% (170/170), done.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Checking connectivity... done.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git diff --staged</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">diff --git a/.gitmodules b/.gitmodules</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">new file mode 100644</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">index 0000000..10f797f</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- /dev/null</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+++ b/.gitmodules</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">@@ -0,0 +1,3 @@</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+[submodule "modules/bashpp"]</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+       path = modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+       url = https://github.com/CMCDragonkai/bashpp.git</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">diff --git a/modules/bashpp b/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">new file mode 160000</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">index 0000000..5e94d3c</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- /dev/null</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+++ b/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">@@ -0,0 +1 @@</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+Subproject commit 5e94d3c285f4424f3fa4c6ddf036f405688b1d51</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git add --all</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git commit --message='Added bashpp as a dependency.'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">[master fc545ee] Added bashpp as a dependency.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> 2 files changed, 4 insertions(+)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> create mode 100644 .gitmodules</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> create mode 160000 modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git submodule status modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> 5e94d3c285f4424f3fa4c6ddf036f405688b1d51 modules/bashpp (0.0.1)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git ls-tree master modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">160000 commit 5e94d3c285f4424f3fa4c6ddf036f405688b1d51  modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; cd modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git checkout cefe74b6d6006ee75897790ed2090b8bc7741ed9</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Note: checking out 'cefe74b6d6006ee75897790ed2090b8bc7741ed9'.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">You are in 'detached HEAD' state. You can look around, make experimental</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">changes and commit them, and you can discard any commits you make in this</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">state without impacting any branches by performing another checkout.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">If you want to create a new branch to retain commits you create, you may</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">do so (now or later) by using -b with the checkout command again. Example:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  git checkout -b &lt;new-branch-name&gt;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">HEAD is now at cefe74b... Changed shebang to be more generic</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; cd ../..</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git status --verbose --verbose</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">On branch master</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Changes not staged for commit:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  (use "git add &lt;file&gt;..." to update what will be committed)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  (use "git checkout -- &lt;file&gt;..." to discard changes in working directory)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        modified:   modules/bashpp (new commits)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--------------------------------------------------</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Changes not staged for commit:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">diff --git i/modules/bashpp w/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">index 5e94d3c..cefe74b 160000</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- i/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+++ w/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">@@ -1 +1 @@</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">-Subproject commit 5e94d3c285f4424f3fa4c6ddf036f405688b1d51</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+Subproject commit cefe74b6d6006ee75897790ed2090b8bc7741ed9</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">no changes added to commit (use "git add" and/or "git commit -a")</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git add --all</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git commit --message='Fixed bashpp dependency to cefe74b6d6006ee75897790ed2090b8bc7741ed9'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">[master dacb700] Fixed bashpp dependency to cefe74b6d6006ee75897790ed2090b8bc7741ed9</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git submodule status modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> cefe74b6d6006ee75897790ed2090b8bc7741ed9 modules/bashpp (0.0.1~2)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git submodule update --remote --merge modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Updating cefe74b..5e94d3c</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Fast-forward</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> bin/bashpp | 2 +-</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Submodule path 'modules/bashpp': merged in '5e94d3c285f4424f3fa4c6ddf036f405688b1d51'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git status --verbose --verbose</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">On branch master</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Changes not staged for commit:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  (use "git add &lt;file&gt;..." to update what will be committed)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  (use "git checkout -- &lt;file&gt;..." to discard changes in working directory)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        modified:   modules/bashpp (new commits)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--------------------------------------------------</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Changes not staged for commit:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">diff --git i/modules/bashpp w/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">index cefe74b..5e94d3c 160000</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">--- i/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+++ w/modules/bashpp</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">@@ -1 +1 @@</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">-Subproject commit cefe74b6d6006ee75897790ed2090b8bc7741ed9</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+Subproject commit 5e94d3c285f4424f3fa4c6ddf036f405688b1d51</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">no changes added to commit (use "git add" and/or "git commit -a")</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>What we did above was to create <code>SuperProject</code>, added a submodule called
<code>bashpp</code> which was put into <code>modules/bashpp</code>. We didn't specify any further
constraints when it was added, therefore it was cloned into the default branch
<code>master</code>. However, we could then go into the submodule, and checkout a specific
commit hash (for content addressing), branch (for rolling updates) or tag (for
semantic versioning), however for proper content addressable dependencies, you
should prefer the commit hash, and use <code>git ls-remote</code> to acquire the commit
hash for any particular tag or branch. Upon doing so, the superproject
recognised this, and realised that the submodule is now tracking that specific
version.</p>
<p>Subsequently, you can push this to Github, and clone it along with its
submodules at exact their associated commit hash that you previously commited to
the <code>SuperProject</code>. Here's a demo:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#9CDCFE;background-color:#1E1E1E"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git clone &lt;repo&gt;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; cd &lt;repo-path&gt;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">&gt; git submodule update --init --recursive --depth 1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The above should acquire the transitive closure of dependencies, and only at
depth 1, that is not acquiring all dependencies. Currently however it the
<code>--depth 1</code> is a bit flaky. So it may be just safer to do
<code>git clone --recursive &lt;repo&gt;</code> which will acquire the entire repository for all
the submodules.</p>
<p>However, there is a feature that is currently missing, which is that the ability
to acquire a clone/submodule of a Git repository at a specific commit and only
at that commit, meaning a commit depth of 1. Currently as you see above, we have
to acquire the entire development repository prior to fixing it at a particular
commit hash. There's a discussion regarding this feature (or lack there of)
here:
<a href="https://stackoverflow.com/questions/26135216/why-isnt-there-a-git-clone-specific-commit-option" target="_blank" rel="noopener noreferrer">http://stackoverflow.com/questions/26135216/why-isnt-there-a-git-clone-specific-commit-option</a>
. Ideally in the future, we can just do
<code>git submodule add --branch dadbf912508272c268c809f97955e182854f79be --depth 1 &lt;repository&gt; [path]</code>
in order to acquire a dependency at exactly that commit hash. It does preclude
us from being able to develop within that submodule, but you should do that
directly in a different clone.</p>
<p>Furthermore, the tooling for manipulating the hashes of the Git submodule called
"gitlink" is still not fleshed out, at the moment we can only read the gitlink
using <code>git ls-tree</code> or <code>git submodule status</code>, but not change the "gitlink"
directly. We have to instead indirectly change the gitlink via updating the
submodule repository HEAD reference ( using <code>git checkout</code> or <code>git reset</code>
commands).</p>
<p>More information:</p>
<ul>
<li><a href="https://stackoverflow.com/questions/27188899/shallow-clone-with-submodules-in-git-how-to-use-pointed-commits-and-not-latest" target="_blank" rel="noopener noreferrer">http://stackoverflow.com/questions/27188899/shallow-clone-with-submodules-in-git-how-to-use-pointed-commits-and-not-latest</a></li>
<li><a href="https://stackoverflow.com/questions/1777854/git-submodules-specify-a-branch-tag" target="_blank" rel="noopener noreferrer">http://stackoverflow.com/questions/1777854/git-submodules-specify-a-branch-tag</a></li>
<li><a href="https://matthew-brett.github.io/pydagogue/git_submodules.html" target="_blank" rel="noopener noreferrer">https://matthew-brett.github.io/pydagogue/git_submodules.html</a></li>
<li><a href="https://stackoverflow.com/questions/2155887/git-submodule-head-reference-is-not-a-tree-error" target="_blank" rel="noopener noreferrer">http://stackoverflow.com/questions/2155887/git-submodule-head-reference-is-not-a-tree-error</a>
( For dealing with the situation where the superproject refers to a subproject
commit that no longer exists.)</li>
<li><a href="https://git-scm.com/docs/git-submodule" target="_blank" rel="noopener noreferrer">https://git-scm.com/docs/git-submodule</a></li>
</ul>
<p>There's quite a few more features to submodules including recursive operations,
where submodules contain further submodules. Therefore, as a feature it's still
got quite a few rough edges, and the workflow isn't fully fleshed out.</p>
<p>In comparing the 2 workflows Nix and Git, if you have a NixOS environment to
deploy into, you should definitely prefer to use Nix style. However, if you want
your project distributable to people who aren't using NixOS, Git submodules is a
viable alternative to get started using content addressable dependencies.</p>
<p>For both of them, it's important to consider the second necessary factor to
reproducible builds. For Nix, make sure to mirror the source. For Git, you can
just fork the project, prior to adding them as a dependency. However I'm looking
forward to the integration of
<a href="https://github.com/ipfs/notes/issues/51" target="_blank" rel="noopener noreferrer">IPFS with Nixpkgs</a>.</p>
<p>Now does this mean semantic versioning is out, and
<code>dadbf912508272c268c809f97955e182854f79be</code> is in? No. Semantic versioning is
still very useful as a metatag of software releases. It communicates intent of
the developers, and that's very handy. But it's not something we should be
relying on when building production software.</p>
<p>In this post, I haven't addressed the "harmoniousness" of a package set (the
idea that packages in package set should work together out of the box with no
conflicts). But this is solved Nix and Nixpkgs as well. And it also solves the
problem with duplicate dependencies by flattening the hierarchy and hardlinking
dependencies with the same hash. Nonetheless, it still requires hardwork from a
community in making all the packages in a package set work without problems, so
it's an ongoing effort.</p></div><div class="max-w-fit"><div class="tableOfContents_jeP5 thin-scrollbar"><button class="button_e1J3 secondary_alWi mb-0 mt-2 w-[200px]" type="button"><p class="btn1_nelt mb-0">Share</p></button></div></div></div>]]></content:encoded>
        </item>
    </channel>
</rss>