<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Magnus Opera – Blog</title><link>https://magnusopera.io/blog/</link><description>Recent content in Blog on Magnus Opera</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>contact@magnusopera.io (Magnus Opera)</managingEditor><webMaster>contact@magnusopera.io (Magnus Opera)</webMaster><atom:link href="https://magnusopera.io/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Introducing Starpac: desired-state database delivery</title><link>https://magnusopera.io/blog/introducing-starpac/</link><pubDate>Wed, 05 Aug 2026 00:00:00 +0200</pubDate><author>contact@magnusopera.io (Magnus Opera)</author><guid>https://magnusopera.io/blog/introducing-starpac/</guid><description>
&lt;p&gt;Database schemas are easier to reason about when the repository describes the state you want, rather than only the sequence of changes that happened along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Starpac&lt;/strong&gt; is the home of &lt;code&gt;*pac&lt;/code&gt; (pronounced “starpac”), a family of focused desired-state database tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;pgpac&lt;/strong&gt; for PostgreSQL;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;d1pac&lt;/strong&gt; for Cloudflare D1 and SQLite.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you know DACPAC, the mental model will feel familiar: package a declarative database model, compare it to a target, then publish the delta.&lt;/p&gt;
&lt;h2&gt;Keep the desired schema in Git&lt;span class="hx-absolute -hx-mt-20" id="keep-the-desired-schema-in-git"&gt;&lt;/span&gt;
&lt;a href="#keep-the-desired-schema-in-git" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;A Starpac project points to ordinary SQL files that describe tables, indexes, views, and other database objects as they should exist. The CLI builds those files into a portable package: &lt;code&gt;.pgpkg&lt;/code&gt; for pgpac or &lt;code&gt;.d1pkg&lt;/code&gt; for d1pac.&lt;/p&gt;
&lt;p&gt;The package can then be compared with a live database:&lt;/p&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pgpac plan &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --package out/Application.pgpkg &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --connection &lt;span class="s2"&gt;&amp;#34;postgres://user:pass@localhost:5432/appdb&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;d1pac plan &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --package out/Application.d1pkg &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --database application &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --script deployment.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Instead of maintaining a growing chain of migration scripts, you can read the schema that the application expects today. Starpac works out the operations required to bring the target database to that state.&lt;/p&gt;
&lt;h2&gt;Review before applying&lt;span class="hx-absolute -hx-mt-20" id="review-before-applying"&gt;&lt;/span&gt;
&lt;a href="#review-before-applying" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Planning and applying are separate steps. A plan can be rendered as text, JSON, or SQL, making it suitable for local review and CI automation.&lt;/p&gt;
&lt;p&gt;Destructive operations are explicit. If a deployment would remove schema or data, the apply command stops unless the caller deliberately opts in. This keeps the desired-state workflow convenient without hiding consequential changes.&lt;/p&gt;
&lt;p&gt;Although pgpac and d1pac share a workflow, each tool retains engine-native behavior. PostgreSQL and D1 are not forced through a generic database abstraction.&lt;/p&gt;
&lt;h2&gt;Install the tool you need&lt;span class="hx-absolute -hx-mt-20" id="install-the-tool-you-need"&gt;&lt;/span&gt;
&lt;a href="#install-the-tool-you-need" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Both CLIs are available from the Magnus Opera Homebrew tap:&lt;/p&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew tap magnusopera/tap
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install pgpac&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;or:&lt;/p&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew tap magnusopera/tap
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install d1pac&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Visit the &lt;a href="https://magnusopera.github.io/starpac/" target="_blank" rel="noopener"&gt;Starpac website&lt;/a&gt; for the pgpac and d1pac quickstarts, command references, and versioned documentation. The project is open source on &lt;a href="https://github.com/MagnusOpera/starpac" target="_blank" rel="noopener"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Introducing Forge</title><link>https://magnusopera.io/blog/introducing-forge/</link><pubDate>Sat, 18 Jul 2026 00:00:00 +0200</pubDate><author>contact@magnusopera.io (Magnus Opera)</author><guid>https://magnusopera.io/blog/introducing-forge/</guid><description>
&lt;p&gt;&lt;strong&gt;Forge&lt;/strong&gt; is a focused GitHub client for macOS.&lt;/p&gt;
&lt;p&gt;It keeps repositories, pull requests, issues, and workflows together in a fast, keyboard-friendly three-pane workspace—so you can move through the work without building a maze of browser tabs.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://magnusopera.io/images/forge-light.png" alt="Forge for macOS in light mode" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Forge is local-only and open source. Your GitHub token stays protected on your Mac, and GitHub remains the source of truth.&lt;/p&gt;
&lt;p&gt;Install the Apple Silicon build with Homebrew:&lt;/p&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew tap magnusopera/tap
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install forge&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/MagnusOpera/forge/releases/latest" target="_blank" rel="noopener"&gt;Download Forge&lt;/a&gt; or &lt;a href="https://github.com/MagnusOpera/forge" target="_blank" rel="noopener"&gt;view the source on GitHub&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>FScript: a strongly typed language designed to be embedded</title><link>https://magnusopera.io/blog/fscript-embeddable-typed-language/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><author>contact@magnusopera.io (Magnus Opera)</author><guid>https://magnusopera.io/blog/fscript-embeddable-typed-language/</guid><description>
&lt;p&gt;Terrabuild&amp;rsquo;s extensions are powered by &lt;strong&gt;FScript&lt;/strong&gt;, a small, open-source language built at Magnus Opera. We created it for a specific reason: applications sometimes need logic that can evolve independently, without giving up the guarantees and boundaries of the host system.&lt;/p&gt;
&lt;p&gt;FScript is not only a command-line scripting tool. It is an &lt;strong&gt;embeddable language runtime&lt;/strong&gt; for .NET and JavaScript applications. A host can load a script in-process, type-check it, inspect its exported functions, and invoke them by name. No sidecar service or RPC layer is required.&lt;/p&gt;
&lt;h2&gt;ML-style, with strong static typing&lt;span class="hx-absolute -hx-mt-20" id="ml-style-with-strong-static-typing"&gt;&lt;/span&gt;
&lt;a href="#ml-style-with-strong-static-typing" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;FScript belongs to the ML family of languages and will feel familiar to F# and OCaml developers. Its language model includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;immutable bindings and expression-oriented code;&lt;/li&gt;
&lt;li&gt;records and discriminated unions;&lt;/li&gt;
&lt;li&gt;options, lists, tuples, and maps;&lt;/li&gt;
&lt;li&gt;functions, pipelines, and pattern matching;&lt;/li&gt;
&lt;li&gt;Hindley–Milner type inference.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last point matters. FScript is &lt;strong&gt;strongly and statically typed&lt;/strong&gt;, but most types do not need to be written explicitly. The language infers them and checks the program before evaluation. Type annotations remain available wherever an interface should be made explicit.&lt;/p&gt;
&lt;p&gt;Here is the pricing example from the &lt;a href="https://magnusopera.github.io/FScript/" target="_blank" rel="noopener"&gt;FScript home page&lt;/a&gt;:&lt;/p&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fsharp" data-lang="fsharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Plan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Seats&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;int&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;]&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;basePrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plan&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;scale&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;29&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;team&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;19&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="o"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;basePrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seats&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Customer&lt;/code&gt; record defines the input contract. Pattern matching makes the pricing rule explicit, and the type checker infers that &lt;code&gt;quote&lt;/code&gt; returns an integer. The &lt;code&gt;[&amp;lt;export&amp;gt;]&lt;/code&gt; annotation makes the function visible to the embedding host; everything else stays internal to the script.&lt;/p&gt;
&lt;p&gt;This is the balance FScript aims for: concise enough for rules and automation, while retaining the structure expected from application code.&lt;/p&gt;
&lt;h2&gt;The host stays in control&lt;span class="hx-absolute -hx-mt-20" id="the-host-stays-in-control"&gt;&lt;/span&gt;
&lt;a href="#the-host-stays-in-control" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Embedding a language is also about deciding what scripts are allowed to do.&lt;/p&gt;
&lt;p&gt;FScript uses a capability-based model. The core language has no ambient access to the filesystem, network, database, or process environment. The host explicitly registers typed external functions, and scripts can use only the capabilities they receive.&lt;/p&gt;
&lt;p&gt;The boundary works in both directions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the host defines typed functions available to scripts;&lt;/li&gt;
&lt;li&gt;scripts expose only bindings marked with &lt;code&gt;[&amp;lt;export&amp;gt;]&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;scripts are parsed and type-checked before execution;&lt;/li&gt;
&lt;li&gt;the host controls source loading, imports, timeouts, and operational limits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes FScript suitable for product rules, workflows, build integrations, and other extension points where flexibility must remain reviewable and constrained.&lt;/p&gt;
&lt;h2&gt;Why Terrabuild uses FScript&lt;span class="hx-absolute -hx-mt-20" id="why-terrabuild-uses-fscript"&gt;&lt;/span&gt;
&lt;a href="#why-terrabuild-uses-fscript" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;A Terrabuild extension translates a target action such as &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, or &lt;code&gt;publish&lt;/code&gt; into the shell operations that Terrabuild schedules. Built-in extensions for .NET, npm, pnpm, Docker, Terraform, and other tools are FScript programs, and workspaces can provide their own &lt;code&gt;.fss&lt;/code&gt; extensions without recompiling Terrabuild.&lt;/p&gt;
&lt;p&gt;The language and the host protocol complement each other:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FScript provides typed records, unions, options, functions, and pattern matching.&lt;/li&gt;
&lt;li&gt;Terrabuild provides typed build contexts and extension contracts.&lt;/li&gt;
&lt;li&gt;The extension returns data describing commands instead of running arbitrary processes directly.&lt;/li&gt;
&lt;li&gt;Terrabuild remains responsible for scheduling, containers, caching, artifacts, and failure handling.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the protocol is strongly typed, an extension&amp;rsquo;s inputs and outputs are checked when the script is loaded. Because capabilities are host-controlled, Terrabuild can restrict filesystem access and omit functions that do not fit deterministic graph evaluation.&lt;/p&gt;
&lt;p&gt;The result is an extension system that is easier to read and change than compiled plugins, without falling back to unstructured shell scripting.&lt;/p&gt;
&lt;h2&gt;Explore FScript&lt;span class="hx-absolute -hx-mt-20" id="explore-fscript"&gt;&lt;/span&gt;
&lt;a href="#explore-fscript" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;FScript can be used as a standalone CLI, embedded through NuGet packages, or loaded in a JavaScript application through &lt;code&gt;@magnusopera/fscript&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can &lt;a href="https://magnusopera.github.io/FScript/sandbox" target="_blank" rel="noopener"&gt;try FScript in the browser&lt;/a&gt;, read the &lt;a href="https://magnusopera.github.io/FScript/manual/" target="_blank" rel="noopener"&gt;language manual&lt;/a&gt;, or explore the project on &lt;a href="https://github.com/MagnusOpera/FScript" target="_blank" rel="noopener"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Terrabuild release status: from RC1 to 0.195</title><link>https://magnusopera.io/blog/terrabuild-release-status-july-2026/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><author>contact@magnusopera.io (Magnus Opera)</author><guid>https://magnusopera.io/blog/terrabuild-release-status-july-2026/</guid><description>
&lt;p&gt;Terrabuild RC1 was announced on &lt;strong&gt;March 4, 2026&lt;/strong&gt; with version &lt;code&gt;0.189.22&lt;/code&gt;. Four months later, the latest stable release is &lt;strong&gt;&lt;code&gt;0.195.10&lt;/code&gt;&lt;/strong&gt;, published on July 16.&lt;/p&gt;
&lt;p&gt;That represents six minor release lines and a steady progression from a release candidate to a more mature build platform. The changes go well beyond maintenance: Terrabuild now has stronger cache correctness, richer build data, a simpler extension model, clearer execution semantics, and new tools for automation.&lt;/p&gt;
&lt;h2&gt;More reliable artifacts and caching&lt;span class="hx-absolute -hx-mt-20" id="more-reliable-artifacts-and-caching"&gt;&lt;/span&gt;
&lt;a href="#more-reliable-artifacts-and-caching" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Releases &lt;code&gt;0.190&lt;/code&gt; through &lt;code&gt;0.192&lt;/code&gt; focused heavily on correctness.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Batched restores now reuse existing artifacts instead of publishing them again.&lt;/li&gt;
&lt;li&gt;Cache summaries no longer advertise output archives that were never created.&lt;/li&gt;
&lt;li&gt;Repository identities are normalized across local checkouts, GitHub Actions, and Git worktrees, keeping project and graph hashes stable.&lt;/li&gt;
&lt;li&gt;Remote-cache integration tests now exercise a complete .NET build through Docker, including restoring a project reference on a clean worker.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These changes make shared caching more predictable and reduce unnecessary transfers and rebuilds.&lt;/p&gt;
&lt;h2&gt;Better visibility and machine-readable reports&lt;span class="hx-absolute -hx-mt-20" id="better-visibility-and-machine-readable-reports"&gt;&lt;/span&gt;
&lt;a href="#better-visibility-and-machine-readable-reports" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Terrabuild now sends richer build-graph and artifact metadata to Insights, including stable project identities, project and target hashes, and execution timestamps.&lt;/p&gt;
&lt;p&gt;Version &lt;code&gt;0.195&lt;/code&gt; also introduced JSON reports for both execution and impact analysis:&lt;/p&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;terrabuild run --out build-report.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;terrabuild impact --base &amp;lt;sha&amp;gt; --out impact-report.json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This makes Terrabuild easier to integrate with CI gates, reporting pipelines, and other engineering tools. Impact analysis was also refined to compare source graphs independently from the execution-specific graph used by &lt;code&gt;run&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;FScript becomes the extension model&lt;span class="hx-absolute -hx-mt-20" id="fscript-becomes-the-extension-model"&gt;&lt;/span&gt;
&lt;a href="#fscript-becomes-the-extension-model" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The transition announced with RC1 is now complete. Terrabuild extensions use FScript &lt;code&gt;.fss&lt;/code&gt; scripts, and the legacy compiled F# &lt;code&gt;.fsx&lt;/code&gt; compatibility layer has been removed.&lt;/p&gt;
&lt;p&gt;The built-in extensions now live alongside Terrabuild as scripts, the standalone &lt;code&gt;@fscript&lt;/code&gt; extension is available for custom automation, and dependency resolution can explicitly use workspace paths or extension scopes. The embedded FScript runtime has continued to evolve and reaches version &lt;code&gt;0.75.0&lt;/code&gt; in Terrabuild &lt;code&gt;0.195.10&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The result is a smaller, more consistent extension surface with clearer security boundaries.&lt;/p&gt;
&lt;h2&gt;A clearer execution model&lt;span class="hx-absolute -hx-mt-20" id="a-clearer-execution-model"&gt;&lt;/span&gt;
&lt;a href="#a-clearer-execution-model" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The runtime now treats Docker, Podman, and host execution as explicit engine choices. Workspace configuration is authoritative, while the console and expressions expose the selected engine consistently.&lt;/p&gt;
&lt;p&gt;The graph pipeline has also been separated more carefully into source analysis and execution resolution. This improves impact calculations, restores execution-specific batch clustering, and provides better diagnostics for dependency cycles and invalid cached summaries.&lt;/p&gt;
&lt;p&gt;For day-to-day maintenance, the new command below removes old entries from the local cache while active entries have their access time refreshed automatically:&lt;/p&gt;
&lt;div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code"&gt;
&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;terrabuild prune &amp;lt;days&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="hextra-code-copy-btn-container hx-opacity-0 hx-transition group-hover/code:hx-opacity-100 hx-flex hx-gap-1 hx-absolute hx-m-[11px] hx-right-0 hx-top-0"&gt;
&lt;button
class="hextra-code-copy-btn hx-group/copybtn hx-transition-all active:hx-opacity-50 hx-bg-primary-700/5 hx-border hx-border-black/5 hx-text-gray-600 hover:hx-text-gray-900 hx-rounded-md hx-p-1.5 dark:hx-bg-primary-300/10 dark:hx-border-white/10 dark:hx-text-gray-400 dark:hover:hx-text-gray-50"
title="Copy code"
&gt;
&lt;div class="copy-icon group-[.copied]/copybtn:hx-hidden hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;div class="success-icon hx-hidden group-[.copied]/copybtn:hx-block hx-pointer-events-none hx-h-4 hx-w-4"&gt;&lt;/div&gt;
&lt;/button&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Documentation and platform updates&lt;span class="hx-absolute -hx-mt-20" id="documentation-and-platform-updates"&gt;&lt;/span&gt;
&lt;a href="#documentation-and-platform-updates" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Terrabuild&amp;rsquo;s documentation now ships with the source repository and is versioned with stable releases. The website exposes both the current preview documentation and snapshots for stable versions.&lt;/p&gt;
&lt;p&gt;The recent releases also include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;hardened cache archive extraction;&lt;/li&gt;
&lt;li&gt;improved macOS signing and notarization;&lt;/li&gt;
&lt;li&gt;macOS arm64 as the supported Apple binary;&lt;/li&gt;
&lt;li&gt;security updates across the website and UI dependencies;&lt;/li&gt;
&lt;li&gt;clearer errors when Terrabuild is run outside a Git repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is next: build phases&lt;span class="hx-absolute -hx-mt-20" id="what-is-next-build-phases"&gt;&lt;/span&gt;
&lt;a href="#what-is-next-build-phases" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The current preview line, &lt;strong&gt;&lt;code&gt;0.196.3-next&lt;/code&gt;&lt;/strong&gt;, introduces workspace-declared build phases. Phases provide whole-phase success barriers, keep batches isolated by phase, and can be displayed as grouped blocks in the interactive graph console.&lt;/p&gt;
&lt;p&gt;This work is still on the &lt;code&gt;-next&lt;/code&gt; channel and is not part of the latest stable release. It points toward a clearer way to model broad delivery stages without replacing the target-level dependency graph.&lt;/p&gt;
&lt;h2&gt;Try the latest release&lt;span class="hx-absolute -hx-mt-20" id="try-the-latest-release"&gt;&lt;/span&gt;
&lt;a href="#try-the-latest-release" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The current stable version is &lt;strong&gt;&lt;code&gt;0.195.10&lt;/code&gt;&lt;/strong&gt;. Release notes and binaries are available on &lt;a href="https://github.com/MagnusOpera/Terrabuild/releases" target="_blank" rel="noopener"&gt;GitHub&lt;/a&gt;, and the latest documentation is available at &lt;a href="https://terrabuild.io/" target="_blank" rel="noopener"&gt;terrabuild.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Questions or feedback? Contact us at &lt;code&gt;contact@magnusopera.io&lt;/code&gt;.&lt;/p&gt;</description></item></channel></rss>