<?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>flux blog</title>
        <link>https://codewandler.github.io/flux/blog</link>
        <description>Tutorials and release walkthroughs for flux — the deterministic agent platform.</description>
        <lastBuildDate>Sat, 01 Aug 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright © 2026 codewandler</copyright>
        <item>
            <title><![CDATA[flux 0.45.0 — verify before you parse]]></title>
            <link>https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse</link>
            <guid>https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse</guid>
            <pubDate>Sat, 01 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A webhook now authenticates before it decodes, over the exact bytes the sender signed. Four hand-rolled redaction walkers become one that cannot narrow. A redaction that fails no longer hands back the original. Plus the editor grammar finally parses the language flux ships.]]></description>
            <content:encoded><![CDATA[<p><strong>0.45.0 is a minor release</strong>, which pre-1.0 is how this project signals a breaking change. One of
them: a webhook that listens beyond your own machine must now state what it does about verification.
If that is you, read the <a class="" href="https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse#action-needed">action-needed
section</a> before upgrading — it is one line.</p>
<p>This post covers <strong>0.43.0 through 0.45.0</strong>. The theme running through all three is not a feature. It
is that several things which <em>looked</em> verified turned out not to be, and the interesting part is
consistently <strong>how they were found</strong> rather than what the patch was.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="verify-before-you-parse">Verify before you parse<a href="https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse#verify-before-you-parse" class="hash-link" aria-label="Direct link to Verify before you parse" title="Direct link to Verify before you parse" translate="no">​</a></h2>
<p>A <code>channel webhook</code> had no signature verification path at all. It now captures the raw body and
authenticates the caller <strong>before</strong> decoding anything.</p>
<p>The ordering is the whole point. A signature is over bytes. Anything that parses and re-serializes
first has verified a <em>normalisation</em> of the message, not the message. That distinction is easy to
assert and hard to prove, so the test fixture is a body deliberately built to be destroyed by a JSON
round trip:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ORIGINAL     = {"b": 1,\n  "a": 2,   "a": 3 }</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ROUNDTRIPPED = {"a":3,"b":1}</span><br></div></code></pre></div></div>
<p>Keys reorder, the duplicate key collapses, whitespace is erased. Feeding the verifier a
re-serialized body reds exactly one test out of sixty-four — which is also the measure of how little
a canonical-JSON fixture would have proved.</p>
<p>Nine guards ship with it, each verified by deleting it and watching a named test change colour. The
two refusal sites are deliberately independent: removing the load-time guard reds two integration
tests while all sixty-four unit tests stay green, and removing the request-time guard does the exact
reverse. Neither half silently carries the other — the same doctrine the connector and bearer-token
fixes established earlier.</p>
<p>The signature <em>schemes</em> themselves are not here yet. A declared-but-unperformable verification is a
<strong>load error before a port is bound</strong>, so nothing degrades quietly to unverified while you wait.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="one-walk-so-it-cannot-narrow-again">One walk, so it cannot narrow again<a href="https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse#one-walk-so-it-cannot-narrow-again" class="hash-link" aria-label="Direct link to One walk, so it cannot narrow again" title="Direct link to One walk, so it cannot narrow again" translate="no">​</a></h2>
<p>flux hides registered credentials from logs, from models, and from saved transcripts. An earlier
release closed a hole where the walker that scans saved JSON skipped plain <strong>numbers</strong> — which
matters because an all-digit credential is invisible to every heuristic flux has, making registration
its only protection.</p>
<p>Fixing it turned up three more copies of the same traversal. Two of them fed <strong>durable stores</strong>, and
those two also skipped object <em>keys</em>.</p>
<p>Four independent hand-rolled walks of one shape, each free to narrow on its own. That duplication was
not a tidiness problem — it was the mechanism by which the defect could exist at all, because there
was no single place where "total" was defined. There is now one walk, and its <code>match</code> is exhaustive
with no catch-all, so a new JSON node kind fails the <strong>build</strong> rather than being silently skipped.</p>
<p>A related fix in the same area is worth stating plainly because the direction was wrong rather than
the code: when text-level redaction corrupted a recorded request badly enough that it no longer
parsed, the fallback returned the <strong>unredacted</strong> original. It failed open, and silently. It now
refuses.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-editor-grammar-parses-the-language">The editor grammar parses the language<a href="https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse#the-editor-grammar-parses-the-language" class="hash-link" aria-label="Direct link to The editor grammar parses the language" title="Direct link to The editor grammar parses the language" translate="no">​</a></h2>
<p>flux ships a tree-sitter grammar that Helix, Neovim and Zed use. It could not parse <strong>7 of 15</strong> of
flux's own canonical examples — 166 error nodes across six constructs it never supported, including
bare-identifier binds, <code>ctx</code> blocks and <code>+=</code>.</p>
<p>Why nobody noticed is the useful part. The grammar repository had its own three-file example corpus,
and its CI parsed <em>that</em> one. At the identical revision that corpus was 100% clean while flux's was
47% broken. <strong>A second corpus did not merely permit the drift — it certified it.</strong></p>
<p>That is now closed at both ends: the grammar parses all fifteen, its CI parses <em>flux's</em> corpus with
no allowlist, and a check on this side verifies that the exact revision flux pins can parse the
canonical examples. Moving that pin, it turns out, was the step that had been quietly missing — two
earlier grammar improvements had landed and reached nobody because the pin never moved.</p>
<p>Editors also stopped rendering ordinary identifiers as punctuation, which in the language server was
worse than a colour problem: those tokens were emitted <strong>not at all</strong>, so an editor lost the
identifier entirely.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="also-in-this-release">Also in this release<a href="https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse#also-in-this-release" class="hash-link" aria-label="Direct link to Also in this release" title="Direct link to Also in this release" translate="no">​</a></h2>
<ul>
<li class=""><strong>Connector deliveries</strong> — point a channel at an installed connector and flux reads that
connector's own description of itself. Every rule in it is re-checked as a load error before a port
is bound, so a description edited after publication cannot start a channel that quietly does
nothing.</li>
<li class=""><strong><code>http.request</code> returns a record</strong> — <code>{status, headers, body}</code> instead of one flat string, so a
flow can select a field. Note the action-needed item from 0.43.0 if you consume it as text.</li>
<li class=""><strong>Panes actually appear.</strong> The <code>pane.*</code> vocabulary shipped inert in 0.42.0; the surface sink is now
installed, and both remaining links of the delivery chain are pinned by tests that fail
independently.</li>
<li class=""><strong>Plugin catalog refresh</strong> without a restart, where a refresh can only ever <em>narrow</em> what a plugin
may reach — a refreshed manifest asking for more is refused outright.</li>
<li class=""><strong>Configured <code>[limits]</code></strong> are now observed end to end on the app-journey path, proven by breaking
links in the middle of the chain rather than at its ends.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action-needed">Action needed<a href="https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse#action-needed" class="hash-link" aria-label="Direct link to Action needed" title="Direct link to Action needed" translate="no">​</a></h2>
<ul>
<li class=""><strong>A webhook that listens beyond your own machine must state its verification.</strong> If it has a token
and no verification, add <code>verify "none"</code> to keep today's behaviour. flux refuses to start
otherwise, names the channel, and prints the exact line to add — rather than opening a port whose
protection you might have assumed. Webhooks bound to loopback are unaffected.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-note-on-how-these-were-found">A note on how these were found<a href="https://codewandler.github.io/flux/blog/flux-0-45-0-verify-before-you-parse#a-note-on-how-these-were-found" class="hash-link" aria-label="Direct link to A note on how these were found" title="Direct link to A note on how these were found" translate="no">​</a></h2>
<p>Nearly every item above came from a review or an implementor's audit rather than from a roadmap —
and in several cases the <em>story describing the bug was itself wrong</em>. One claimed a truncation
mechanism that provably does not exist. One was blocked on a dependency constraint that had lifted
weeks earlier. One named the wrong root cause, the wrong fault model and the wrong colour.</p>
<p>Each was corrected by the person implementing it, with evidence, before the fix shipped. That is
worth more than any single entry on this list.</p>
<p>Full engineering detail, including the review findings behind each change, is in the
<a href="https://github.com/codewandler/flux/blob/main/CHANGELOG.md" target="_blank" rel="noopener noreferrer" class="">CHANGELOG</a>.</p>]]></content:encoded>
            <category>release</category>
            <category>security</category>
            <category>channels</category>
            <category>flux-lang</category>
        </item>
        <item>
            <title><![CDATA[flux 0.42.0 — rooms, and the history you already have]]></title>
            <link>https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history</link>
            <guid>https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history</guid>
            <pubDate>Fri, 31 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A Room port and a real XMPP backend let flux be one participant among several. Local harness transcripts become searchable, contained by construction. Plus per-child resource ceilings, and a memory-eating prune caught before it had a caller.]]></description>
            <content:encoded><![CDATA[<p><strong>0.42.0 is a minor release</strong>, which pre-1.0 is how this project signals a breaking change. Two of
them: <code>VoiceTurnHandler::turn</code> now carries a <code>Speaker</code>, and <code>SubAgents</code> gained a public field. If you
implement a voice handler or build <code>SubAgents</code> with a struct literal, read the <a class="" href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#action-needed">action-needed
section</a> before upgrading.</p>
<p>The headline is that flux can now sit in a room with several people. The subtler half is that three
of the nine stories in this cut are <strong>foundations whose consumers are not wired yet</strong> — and saying so
plainly is more useful than a feature list that implies otherwise.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rooms--one-participant-among-several">Rooms — one participant among several<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#rooms--one-participant-among-several" class="hash-link" aria-label="Direct link to Rooms — one participant among several" title="Direct link to Rooms — one participant among several" translate="no">​</a></h2>
<p>Every channel flux had was one-to-one or fire-and-forget. <code>schedule</code>, <code>webhook</code>, <code>slack</code> and <code>a2a</code>
wake a journey and return. The voice path was richer but assumed <strong>exactly one caller</strong>, because on a
phone line there is only one candidate.</p>
<p>A room breaks that assumption, and the break is not cosmetic: <strong>every inbound event now carries an
occupant id</strong>. Attribution is not a feature layered on top of a room, it is the precondition for one.
Without knowing who spoke, "answer only when addressed" cannot even be expressed.</p>
<p>Two stories landed together. The <strong><code>Room</code> port</strong> (<code>join</code> / <code>occupants</code> / <code>say</code> / <code>whisper</code> / <code>leave</code>,
plus a <code>Joined</code>/<code>Left</code>/<code>Message</code>/<code>Ended</code> event stream) arrives as an ordinary channel kind, so a room
reaches an agent through the same machinery every other channel uses — and a room-sourced turn
dispatches through the ordinary executor and approver, which is asserted by a test rather than
assumed.</p>
<p>The <strong>XMPP MUC backend</strong> then makes it real against any standards-compliant server — prosody,
ejabberd, or a hosted JaaS tenant — with <strong>no browser and no vendor SDK</strong>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-the-dependency-choice-was-a-safety-decision">Why the dependency choice was a safety decision<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#why-the-dependency-choice-was-a-safety-decision" class="hash-link" aria-label="Direct link to Why the dependency choice was a safety decision" title="Direct link to Why the dependency choice was a safety decision" translate="no">​</a></h3>
<p>The obvious move was an existing XMPP client crate. We rejected it, and the reason is worth stating
because it generalises: <code>tokio-xmpp</code> opens its own TCP socket and resolves its own DNS. That means its
egress <strong>cannot</strong> be routed through flux's network guard — every outbound request in flux passes one
guard that resolves hostnames and blocks private, loopback and link-local ranges unless the caller
holds a scoped grant. Using that crate would have meant either a bypass or a second guard, and the
invariant forbids both.</p>
<p>So we took <code>quick-xml</code> — a <em>parser</em>, not a client — and wrote the protocol here, about 200 lines of
element tree. It is the only new package in the lockfile, and no second TLS stack came with it.</p>
<p>Two details from a live spike are now regression tests, asserted against the raw frames the server
actually reads: every stanza is namespace-qualified (prosody answers <code>&lt;unsupported-stanza-type/&gt;</code> and
kills the stream otherwise), and the keepalive is an XMPP ping, never a whitespace frame — a bare
space gets the connection closed with <code>1007</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-deliberately-not-finished">What is deliberately not finished<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#what-is-deliberately-not-finished" class="hash-link" aria-label="Direct link to What is deliberately not finished" title="Direct link to What is deliberately not finished" translate="no">​</a></h3>
<p><strong>The agent replies to every line said in the room.</strong> The addressing rule is carried in settings and
not yet enforced; that is the next story. Under the in-process test double this was theoretical. With
a real backend it is a live cost, and you should treat a room as something you put flux into
deliberately, not something to leave running.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-history-you-already-have">The history you already have<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#the-history-you-already-have" class="hash-link" aria-label="Direct link to The history you already have" title="Direct link to The history you already have" translate="no">​</a></h2>
<p>If you use codex, claude-code or opencode, you have years of transcripts on disk. Their token-usage
parsers already walk right past the message text to reach the eight integers they came for.</p>
<p>This release extracts that text — normalising roles across three different vocabularies — and exposes
it as <code>search(query, harness)</code>.</p>
<p><strong>The containment is the story, not a caveat on it.</strong> Because this is the change that exposes the
data, it is the change that has to contain it, and each property is structural rather than
maintained:</p>
<ul>
<li class=""><strong>Off by default</strong>, by construction — the default tool pack <em>literally is</em> the history-enabled one
called with history disabled, so there are not two declarations that could drift apart.</li>
<li class=""><strong>Redacted and escaped at ingest</strong>, not at render. The test asserts on the record sitting in the
index, because redaction-at-render is the failure mode that looks identical from a passing test.</li>
<li class=""><strong>Per-harness permission</strong>, so granting search over one harness is not granting it over all.</li>
<li class="">The escaper is the one flux already uses for untrusted knowledge-base bodies, exported as a
one-line delegation so the two callers cannot drift into two schemes.</li>
</ul>
<p>Nothing in flux wires this up yet. That is deliberate: extraction shipped one release before this
one specifically so unredacted text could not reach a model-visible surface before redaction existed.</p>
<p>Two limits are documented rather than claimed solved: the over-fetch behind the harness filter is a
<strong>heuristic, not a bound</strong> — a harness holding many better-scoring hits can still cause a silent
under-return — and a host must pass <strong>one</strong> history handle to both ingest and registration, because
they take independent handles today.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="resource-ceilings-that-actually-reach-something">Resource ceilings that actually reach something<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#resource-ceilings-that-actually-reach-something" class="hash-link" aria-label="Direct link to Resource ceilings that actually reach something" title="Direct link to Resource ceilings that actually reach something" translate="no">​</a></h2>
<p>A configured <code>[limits]</code> table now binds for the <code>flux</code> binary and descends into sub-agents. It is
<strong>per-child</strong>: <code>max_concurrent_tool_calls = N</code> bounds <em>each</em> agent, so a process with k live children
may run up to N×(k+1).</p>
<p>That is weaker than it sounds and we are saying so rather than letting the name imply otherwise. A
shared ceiling was built first — and reproduced a real deadlock, where a parent holds a permit while
awaiting a child that queues on the same semaphore. Per-child is safe by construction: parent and
child hold different semaphores, so no ancestor can block a descendant.</p>
<p>Not covered: <code>flux app run</code> assembles its own environment and still ignores <code>[limits]</code> entirely.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-prune-that-would-have-eaten-your-memory">A prune that would have eaten your memory<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#a-prune-that-would-have-eaten-your-memory" class="hash-link" aria-label="Direct link to A prune that would have eaten your memory" title="Direct link to A prune that would have eaten your memory" translate="no">​</a></h2>
<p><code>memory:*</code> streams carry no registry row, which is exactly what the ad-hoc stream prune targets. An
aged memory was indistinguishable from an aged scratch stream and would have been swept.</p>
<p>It was caught before it could bite — the prune has no caller anywhere in the tree — so this closes a
trap rather than fixing an incident. Whether memory should <em>ever</em> be prunable by age is now answered
in writing rather than left implicit: it should not be, and <code>forget</code> remains the deliberate path.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="also-in-this-release">Also in this release<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#also-in-this-release" class="hash-link" aria-label="Direct link to Also in this release" title="Direct link to Also in this release" translate="no">​</a></h2>
<ul>
<li class=""><strong>Flux Glyph</strong>, a compact indented opcode projection of a Flux program, for agents. The round-trip
is proven as a property across every node kind in three nesting positions, plus hundreds of seeded
random programs. <code>.flux</code> and the runtime are untouched.</li>
<li class=""><strong><code>pane.open</code> / <code>update</code> / <code>close</code></strong> — an agent can open its own panes. Shipped <strong>partial</strong>: the ops
are surfaced only when a host has a surface sink, and nothing installs one yet, so the vocabulary is
currently inert.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action-needed">Action needed<a href="https://codewandler.github.io/flux/blog/flux-0-42-0-rooms-and-history#action-needed" class="hash-link" aria-label="Direct link to Action needed" title="Direct link to Action needed" translate="no">​</a></h2>
<ul>
<li class=""><strong>If you implement a voice handler</strong>, its <code>turn</code> method now takes a speaker alongside the text. If
you only use flux's built-in phone/voice support, the single caller on a line is simply named now
instead of anonymous, and nothing changes for you.</li>
<li class=""><strong>If you construct <code>SubAgents</code> with a struct literal</strong>, add the new field or switch to
<code>SubAgents::new</code>.</li>
</ul>
<p>Full engineering detail, including the review findings behind each change, is in the
<a href="https://github.com/codewandler/flux/blob/main/CHANGELOG.md" target="_blank" rel="noopener noreferrer" class="">CHANGELOG</a>.</p>]]></content:encoded>
            <category>release</category>
            <category>channels</category>
            <category>datasource</category>
            <category>runtime</category>
        </item>
        <item>
            <title><![CDATA[A workflow family in one file]]></title>
            <link>https://codewandler.github.io/flux/blog/a-workflow-family-in-one-file</link>
            <guid>https://codewandler.github.io/flux/blog/a-workflow-family-in-one-file</guid>
            <pubDate>Thu, 30 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A first tutorial for named entrypoints and the git ops — build a small family of deterministic workflows, land a branch with a real merge commit, and undo it without rewriting history.]]></description>
            <content:encoded><![CDATA[<p>Two features that landed recently pair better than either reads alone: <strong>named entrypoints</strong>
(<code>flux run &lt;file&gt; --entry &lt;name&gt;</code>, 0.38.0) let one <code>.flux</code> file hold a family of related workflows,
and the <strong>git family</strong> (<code>git_branch</code> / <code>git_merge</code> / <code>git_revert</code>, 0.37.0) lets a flow integrate work
end to end. Together they cover a real job: prepare a branch, land it with a proper merge commit, and
back it out if you were wrong — with the flow, not the model, deciding every step.</p>
<p>Nothing here needs an API key or a network call. Every command and every output below was run against
a throwaway git repository, and pasted verbatim.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="set-up-a-scratch-repository">Set up a scratch repository<a href="https://codewandler.github.io/flux/blog/a-workflow-family-in-one-file#set-up-a-scratch-repository" class="hash-link" aria-label="Direct link to Set up a scratch repository" title="Direct link to Set up a scratch repository" translate="no">​</a></h2>
<p>Do this somewhere disposable. The flows below make real commits.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">mkdir</span><span class="token plain"> /tmp/flux-tutorial </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token builtin class-name">cd</span><span class="token plain"> /tmp/flux-tutorial</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> init </span><span class="token parameter variable" style="color:#36acaa">-q</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> config user.email you@example.com</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> config user.name </span><span class="token string" style="color:#e3116c">"You"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token builtin class-name">echo</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"# demo"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> README.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> </span><span class="token builtin class-name">.</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> commit </span><span class="token parameter variable" style="color:#36acaa">-qm</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"initial commit"</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="one-file-several-workflows">One file, several workflows<a href="https://codewandler.github.io/flux/blog/a-workflow-family-in-one-file#one-file-several-workflows" class="hash-link" aria-label="Direct link to One file, several workflows" title="Direct link to One file, several workflows" translate="no">​</a></h2>
<p>Before named entrypoints, a file held one workflow and a family meant a file each. Now a module can
declare several top-level flows and the caller picks one by name.</p>
<p>Save this as <code>repo-notes.flux</code>:</p>
<div class="language-flux codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-flux codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">flow</span><span class="token plain"> status </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Any</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  state </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git_status</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  recent </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git_log</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">limit</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> state</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> recent </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">flow</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">branch</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Any</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  switched </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git_checkout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">branch</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">branch</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> create</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> switched </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">flow</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">save</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Any</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">git_stage</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">paths</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"."</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  committed </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git_commit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> committed </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">flow</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">land</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">onto</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">branch</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Any</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">git_checkout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">branch</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> onto</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  merged </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git_merge</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">branch</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">branch</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> no_ff</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> merged </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">flow</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undo</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">commit</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Any</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  reverted </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git_revert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">commit</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> commit</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> mainline</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> reverted </span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div><button class="openButton_ReAm">Edit · Check</button>
<p>Five workflows, one file. Two things in that source are worth naming, because both are newer than
most examples you will find:</p>
<ul>
<li class=""><strong>No <code>$</code> sigils.</strong> <code>state = git_status()</code> binds a result directly. The older <code>$state = …</code> spelling
still parses, but this is the canonical form the formatter now emits.</li>
<li class=""><strong>Named inputs look named.</strong> <code>git_merge(branch: branch, no_ff: true)</code> instead of wrapping arguments
in an object literal. <code>{ state, recent }</code> is shorthand for <code>{ state: state, recent: recent }</code> —
punning is allowed only where the names are identical, so it cannot quietly change meaning.</li>
</ul>
<p>Run the read-only one first:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">flux run repo-notes.flux </span><span class="token parameter variable" style="color:#36acaa">--entry</span><span class="token plain"> status </span><span class="token parameter variable" style="color:#36acaa">--yes</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">flow  low · mutating · 2 op(s)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">→ git_status</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ✓ ?? repo-notes.flux  · exec 6ms + approval 1µs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">→ git_log   limit=5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ✓ fa51d90 initial commit  · exec 6ms + approval 1µs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{"recent":"fa51d90 initial commit","state":"?? repo-notes.flux"}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">──────────────────────────────────────────────────────────────── 2 steps · 33ms</span><br></div></code></pre></div></div>
<p>Every operation is listed with its arguments before its result. That trace is not a log the flow
chose to print — it is the execution path itself, and the ops in it are exactly the ops the source
names. No model decided to call <code>git_log</code>; the flow did.</p>
<p><code>--entry</code> reuses the strict authored-flow input path, so a flow's declared parameters are checked.
Ask for a flow that does not exist, or omit a required input, and it fails before doing any work
rather than midway through.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="landing-a-branch">Landing a branch<a href="https://codewandler.github.io/flux/blog/a-workflow-family-in-one-file#landing-a-branch" class="hash-link" aria-label="Direct link to Landing a branch" title="Direct link to Landing a branch" translate="no">​</a></h2>
<p>Commit the module, then start a branch through the flow:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">git</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">add</span><span class="token plain"> repo-notes.flux </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">git</span><span class="token plain"> commit </span><span class="token parameter variable" style="color:#36acaa">-qm</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"add the workflow module"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">flux run repo-notes.flux </span><span class="token parameter variable" style="color:#36acaa">--entry</span><span class="token plain"> start </span><span class="token parameter variable" style="color:#36acaa">--arg</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">branch</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">feature/notes </span><span class="token parameter variable" style="color:#36acaa">--yes</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">→ git_checkout branch="feature/notes", create=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ✓ Switched to a new branch 'feature/notes'  · exec 6ms + approval 1µs</span><br></div></code></pre></div></div>
<p>Make a change and save it. <code>save</code> takes its message as an input, so the <em>commit text</em> is a caller
decision while the <em>sequence</em> — stage, then commit — is fixed by the flow:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token builtin class-name">echo</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"hello"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> note.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">flux run repo-notes.flux </span><span class="token parameter variable" style="color:#36acaa">--entry</span><span class="token plain"> save </span><span class="token parameter variable" style="color:#36acaa">--arg</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">message</span><span class="token operator" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"add a note"</span><span class="token plain"> </span><span class="token parameter variable" style="color:#36acaa">--yes</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">→ git_commit message="add a note"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ✓ [feature/notes 40c5b1f] add a note</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     1 file changed, 1 insertion(+)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     create mode 100644 note.txt  · exec 7ms + approval 1µs</span><br></div></code></pre></div></div>
<p>Now land it. <code>no_ff: true</code> forces a real merge commit even where a fast-forward was possible, so the
branch stays visible in the history:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">flux run repo-notes.flux </span><span class="token parameter variable" style="color:#36acaa">--entry</span><span class="token plain"> land </span><span class="token parameter variable" style="color:#36acaa">--arg</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">onto</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">main </span><span class="token parameter variable" style="color:#36acaa">--arg</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">branch</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">feature/notes </span><span class="token parameter variable" style="color:#36acaa">--yes</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">→ git_merge branch="feature/notes", no_ff=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ✓ Merge made by the 'ort' strategy.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     note.txt | 1 +</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     1 file changed, 1 insertion(+)</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">*   082036e Merge branch 'feature/notes'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">|\</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">| * 40c5b1f add a note</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">|/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">* 71fda9e add the workflow module</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">* fa51d90 initial commit</span><br></div></code></pre></div></div>
<p>A merge is <code>Risk::High</code> and a conflict is a <strong>recoverable</strong> error: it names the conflicting files,
aborts, and restores the tree. It is never left half-merged for something else to trip over. If a
merge is already in progress <code>git_merge</code> refuses outright and aborts nothing — that in-flight
resolution may be work someone has not saved.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="undoing-without-rewriting">Undoing without rewriting<a href="https://codewandler.github.io/flux/blog/a-workflow-family-in-one-file#undoing-without-rewriting" class="hash-link" aria-label="Direct link to Undoing without rewriting" title="Direct link to Undoing without rewriting" translate="no">​</a></h2>
<p>This is the part worth internalising. <code>git_revert</code> <strong>appends the inverse</strong> of a commit. It never
resets, and it never rewrites history.</p>
<p>For a merge commit you must say which parent to keep, which is what <code>mainline: 1</code> means — the branch
you merged <em>into</em>:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">flux run repo-notes.flux </span><span class="token parameter variable" style="color:#36acaa">--entry</span><span class="token plain"> undo </span><span class="token parameter variable" style="color:#36acaa">--arg</span><span class="token plain"> </span><span class="token assign-left variable" style="color:#36acaa">commit</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">082036e </span><span class="token parameter variable" style="color:#36acaa">--yes</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">→ git_revert commit="082036e...", mainline=1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  ✓ [main b6f5817] Revert "Merge branch 'feature/notes'"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     1 file changed, 1 deletion(-)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     delete mode 100644 note.txt</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    reverted 082036e — b6f5817 Revert "Merge branch 'feature/notes'"</span><br></div></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">* b6f5817 Revert "Merge branch 'feature/notes'"</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">*   082036e Merge branch 'feature/notes'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">|\</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">| * 40c5b1f add a note</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">|/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">* 71fda9e add the workflow module</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">* fa51d90 initial commit</span><br></div></code></pre></div></div>
<p><code>note.txt</code> is gone from the working tree, and <strong>both the merge and the original commit are still
reachable</strong>. The record of what happened survives the decision to undo it — which is what you want
when an agent, rather than a person, made the call.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>A rename you may need to act on</div><div class="admonitionContent_BuS1"><p>The step that discards changes and returns the checkout to a snapshot used to be called <code>git_revert</code>,
which described the wrong thing — it resets. It is now <strong><code>git_reset</code></strong>, and <code>git_revert</code> means the
appending, non-destructive operation above. <strong>There is no alias</strong>, so an old flow calling <code>git_revert</code>
expecting a reset will not silently do the wrong thing: the new <code>git_revert</code> refuses a snapshot
argument instead of resetting anything. If you have flows from before 0.37.0, rename those calls.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-to-go-next">Where to go next<a href="https://codewandler.github.io/flux/blog/a-workflow-family-in-one-file#where-to-go-next" class="hash-link" aria-label="Direct link to Where to go next" title="Direct link to Where to go next" translate="no">​</a></h2>
<p>Three more things landed in the same window that extend this shape:</p>
<ul>
<li class=""><strong>Work boards</strong> can be read as structured data, not just text — a flow can loop over items, filter
to what is ready <em>and</em> not blocked by unfinished dependencies in one call, and read back its own
notes. Since 0.38.0 a board can also hand an item to a different worker when its holder dies, and
attach evidence such as a commit or PR link to a finished item. See
<a class="" href="https://codewandler.github.io/flux/docs/agent/datasources">datasources</a>.</li>
<li class=""><strong>Delegated helpers are visible while they work.</strong> When flux hands work to helper agents, a status
line shows each one's role, how long since it last did anything, and whether it is working or
stuck. Their inputs and outputs are never shown — only that activity happened — so a helper
handling secrets cannot leak them onto your screen. Local helpers today; remote workers stay silent
for now.</li>
<li class=""><strong>A flux program can drive its own release</strong>, having a model draft the changelog prose while the
version number is derived from commit titles rather than from anything the model says. See
<a class="" href="https://codewandler.github.io/flux/docs/agent/improvement">improvement</a>.</li>
</ul>
<p>If you want the deterministic-execution model behind all of this, start with
<a class="" href="https://codewandler.github.io/flux/docs/language/overview">Flux-Lang overview</a>; for the operation catalogue, see
<a class="" href="https://codewandler.github.io/flux/docs/language/ops">operations</a>.</p>]]></content:encoded>
            <category>tutorial</category>
            <category>flux-lang</category>
            <category>git</category>
        </item>
    </channel>
</rss>