<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-08-09T09:32:22+00:00</updated><id>/feed.xml</id><title type="html">Claes Adamsson</title><subtitle>A personal site for projects, documentation, and thoughts on software development and delivery.
</subtitle><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><entry><title type="html">hica analyse: Measuring Functional Debt</title><link href="/2026/08/05/hica-analyse/" rel="alternate" type="text/html" title="hica analyse: Measuring Functional Debt" /><published>2026-08-05T00:00:00+00:00</published><updated>2026-08-05T00:00:00+00:00</updated><id>/2026/08/05/hica-analyse</id><content type="html" xml:base="/2026/08/05/hica-analyse/"><![CDATA[<p>I ran <code class="language-plaintext highlighter-rouge">hica analyse</code> across my codebase last week. The report flagged twelve functions, including four I would have sworn were clean.</p>

<p>Then came the overall score:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Total FP Quality Index: 77/100
</code></pre></div></div>

<p>A score of 77 is good, but it is not 100. Seeing that number made me think: where did the missing 23 points go?</p>

<p>Standard linters operate on source text or surface syntax. A quick <code class="language-plaintext highlighter-rouge">grep</code> can spot a stray <code class="language-plaintext highlighter-rouge">for</code> loop, but it cannot tell you that a function returns <code class="language-plaintext highlighter-rouge">maybe&lt;maybe&lt;T&gt;&gt;</code>. That double wrapper forces callers to unwrap twice, turning <code class="language-plaintext highlighter-rouge">None</code> and <code class="language-plaintext highlighter-rouge">Some(None)</code> into two distinct states that callers are forced to distinguish.</p>

<p>Because <code class="language-plaintext highlighter-rouge">hica</code> runs right after the type checker, it operates on a fully-typed AST. It catches architectural design traps rather than cosmetic formatting:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">find_first</span><span class="p">(</span><span class="n">pred</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="kt">bool</span><span class="p">,</span><span class="w"> </span><span class="n">xs</span><span class="p">:</span><span class="w"> </span><span class="kt">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="kt">maybe</span><span class="o">&lt;</span><span class="kt">maybe</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nb">Some</span><span class="p">(</span><span class="nf">filter</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span><span class="w"> </span><span class="n">pred</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span><span class="w"> </span><span class="n">head</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Here, <code class="language-plaintext highlighter-rouge">head</code> already returns <code class="language-plaintext highlighter-rouge">maybe&lt;int&gt;</code>. Wrapping it in <code class="language-plaintext highlighter-rouge">Some(...)</code> is redundant and turns the function signature into a trap. The fix is a single line:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">find_first</span><span class="p">(</span><span class="n">pred</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="o">-&gt;</span><span class="w"> </span><span class="kt">bool</span><span class="p">,</span><span class="w"> </span><span class="n">xs</span><span class="p">:</span><span class="w"> </span><span class="kt">list</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="kt">maybe</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=&gt;</span><span class="w">
  </span><span class="nf">filter</span><span class="p">(</span><span class="n">xs</span><span class="p">,</span><span class="w"> </span><span class="n">pred</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span><span class="w"> </span><span class="n">head</span><span class="w">
</span></code></pre></div></div>

<p>The typed AST also unlocks deeper analysis through Koka’s effect system. The analyser knows when a function looks pure on the surface but is not. A <code class="language-plaintext highlighter-rouge">calculate_total</code> function hiding a <code class="language-plaintext highlighter-rouge">print</code> statement inside an order-summing loop is detectable not from the source text, but directly from the effect row in the type tree. The guidance remains consistent: push I/O to the boundaries and keep core logic pure.</p>

<p>When tackling a larger codebase, filtering for the worst offenders yields the best return:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hica analyse my_program.hc <span class="nt">--format</span> markdown <span class="nt">--top</span> 3
</code></pre></div></div>

<p>This dumps a structured payload for the three lowest-scoring functions: signature, location, debt score, flagged anti-patterns, and the original snippet.</p>

<p>This format works well as a prompt payload for an LLM. Providing a report that specifies line numbers, scores, and flagged anti-patterns gives the model explicit constraints. You get targeted rewrites instead of vague suggestions.</p>

<p>In practice, the score alone is usually enough. Seeing <code class="language-plaintext highlighter-rouge">[CRITICAL] my_program.hc:12 (score: 18)</code> next to code written yesterday provides immediate clarity. Once a tool pinpoints the exact line and underlying flaw, fixing it directly is often faster than delegating it.</p>

<p>A score simply highlights where friction exists in your codebase. Whether you fix accidental debt or accept intentional trade-offs is still up to you.</p>

<h2 id="quick-reference">Quick reference</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hica analyse &lt;file&gt;                           <span class="c"># text report (terminal colours)</span>
hica analyse &lt;file&gt; <span class="nt">--format</span> markdown         <span class="c"># markdown payload</span>
hica analyse &lt;file&gt; <span class="nt">--format</span> markdown <span class="nt">--top</span> 5 <span class="c"># top 5 issues only</span>
hica analyse <span class="nb">.</span>      <span class="nt">--document</span>                <span class="c"># generate project docs</span>
hica analyse <span class="nb">.</span>      <span class="nt">--document</span> <span class="nt">--check-docs</span>   <span class="c"># verify docs are in sync</span>
</code></pre></div></div>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="hica" /><category term="static-analysis" /><category term="functional-programming" /><summary type="html"><![CDATA[I ran hica analyse across my codebase last week. The report flagged twelve functions, including four I would have sworn were clean.]]></summary></entry><entry><title type="html">The Double Trap</title><link href="/2026/07/29/the-double-trap/" rel="alternate" type="text/html" title="The Double Trap" /><published>2026-07-29T00:00:00+00:00</published><updated>2026-07-29T00:00:00+00:00</updated><id>/2026/07/29/the-double-trap</id><content type="html" xml:base="/2026/07/29/the-double-trap/"><![CDATA[<p>In <em><a href="/2026/02/22/the-comprehension-crisis/">The Comprehension Crisis</a></em>, I argued that AI can quietly erode one of our most valuable engineering assets: deep technical understanding. In <em><a href="/2026/02/19/the-pull-request-trap/">The Pull Request Trap</a></em>, I looked at how traditional delivery workflows create queues that slow down learning and feedback.</p>

<p>These two ideas are closely related. Generative AI amplifies both problems simultaneously.</p>

<p>I call this <strong>the double trap</strong>.</p>

<p>AI has dramatically reduced the cost of producing software. Individual developers can now generate code, tests, documentation, and even architectural proposals in minutes. Production has accelerated, yet our ability to validate and understand those changes has not. Learning is becoming the new bottleneck.</p>

<p>The result is a dangerous imbalance. We produce software faster than we can validate it, and we rely heavily on AI while understanding our systems less.</p>

<h2 id="the-two-traps">The two traps</h2>

<p>The double trap emerges when two reinforcing forces feed into each other.</p>

<p><a href="/assets/images/the-double-trap.png" target="_blank">
  <img src="/assets/images/the-double-trap.png" alt="The Double Trap diagram" style="max-width: 75%; display: block; margin: 20px auto; border-radius: 4px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);" />
</a></p>

<h3 id="trap-1-faster-output-slower-feedback">Trap 1: Faster output, slower feedback</h3>

<p>DevOps has always been about shortening feedback loops. AI changes the economics of production while leaving the downstream constraints completely intact. Customer validation, testing, operational feedback, and organisational learning all still take the same amount of time.</p>

<p>Using AI to generate more code within the same delivery model only moves the bottleneck. More code creates larger queues that delay feedback. Ultimately, the system becomes much busier without actually becoming more effective.</p>

<p>This is the exact pattern behind the Pull Request Trap. When every developer can generate dramatically more code, asynchronous review queues become completely overwhelmed. The bottleneck shifts downstream, where changes sit waiting to be reviewed, integrated, tested, or understood. AI compresses production time, while feedback remains constrained by human speed.</p>

<p>AI optimises the productivity of individual developers. Organisations succeed by optimising the performance of the entire delivery system. Those are not the same thing.</p>

<h3 id="trap-2-less-thinking-less-understanding">Trap 2: Less thinking, less understanding</h3>

<p>At the same time, AI fundamentally alters how we solve problems. When developers repeatedly outsource reasoning to an assistant, they make fewer architectural decisions themselves. They find themselves evaluating more than they create, and over time, their internal mental models weaken.</p>

<p>True comprehension is built through decision-making. We understand systems by exploring trade-offs, debugging failures, and explaining <em>why</em> one solution is better than another. If AI performs the bulk of that cognitive work for us, we gradually lose the intuition that makes experienced engineers valuable.</p>

<p>The real risk is perfectly correct-looking code that nobody in the team truly understands.</p>

<h2 id="why-these-traps-reinforce-each-other">Why these traps reinforce each other</h2>

<p>These two problems create a vicious reinforcing loop. Faster code generation increases the sheer volume of work entering the system, leading to longer queues and delayed feedback. As feedback slows down, so does learning.</p>

<p>This reduced understanding makes teams depend even more heavily on AI to explain, generate, and modify the codebase, which in turn generates even more output. The entire system accelerates while the underlying organisational capability slowly declines. Teams become busier while learning less.</p>

<h2 id="escaping-the-double-trap">Escaping the double trap</h2>

<p>To escape this loop, we have to improve the systems we work in.</p>

<h3 id="build-to-learn-before-you-build-to-earn">Build to learn before you build to earn</h3>

<p>Use AI aggressively during product discovery. Prototype quickly, challenge assumptions, explore alternatives, and validate customer problems before investing heavily in production-quality software. Speed is most valuable when you are in the phase of learning.</p>

<h3 id="optimise-feedback-not-output">Optimise feedback, not output</h3>

<p>Practices like small batches, continuous integration, automated verification, and rapid deployment reduce the time between making a change and learning whether it was the right one. AI makes these practices even more essential.</p>

<h3 id="keep-humans-responsible-for-understanding">Keep humans responsible for understanding</h3>

<p>Use AI to generate options, not ownership. Every significant design decision must still be understood, challenged, and explained by the team responsible for operating the system. If you cannot explain why a solution works, you do not really own it.</p>

<h3 id="measure-learning">Measure learning</h3>

<p>Counting lines of code or completed tickets was never a good measure of progress. In an AI-assisted world, it is completely meaningless. Instead, optimise for customer feedback, deployment frequency, lead time, recovery time, and validated outcomes. These are the true signals that the organisation is learning.</p>

<h2 id="velocity-isnt-the-goal">Velocity isn’t the goal</h2>

<p>AI dramatically accelerates software production, yet organisations still improve in the same fundamental ways. High-performing teams have always won by learning faster than everyone else. DevOps, Lean, and Trunk-Based Development all exist to shorten the feedback loops that make learning possible.</p>

<p>Velocity has never been the goal, learning has. Organisations that pair AI with fast feedback, small batches, continuous integration, and deep technical ownership will increase both their delivery speed and their overall capability. Those that optimise for output alone will fall straight into the double trap: producing more, while understanding less.</p>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="AI" /><category term="DevOps" /><category term="productivity" /><category term="TBD" /><category term="comprehension" /><summary type="html"><![CDATA[In The Comprehension Crisis, I argued that AI can quietly erode one of our most valuable engineering assets: deep technical understanding. In The Pull Request Trap, I looked at how traditional delivery workflows create queues that slow down learning and feedback.]]></summary></entry><entry><title type="html">hicurl: a modern HTTP CLI built with hica</title><link href="/2026/07/26/hicurl/" rel="alternate" type="text/html" title="hicurl: a modern HTTP CLI built with hica" /><published>2026-07-26T00:00:00+00:00</published><updated>2026-07-26T00:00:00+00:00</updated><id>/2026/07/26/hicurl</id><content type="html" xml:base="/2026/07/26/hicurl/"><![CDATA[<p>I spend a lot of time testing HTTP endpoints, inspecting JSON responses, and composing API calls, whether writing automated BDD specs in <a href="https://cladam.github.io/choreo/">choreo</a> or probing APIs interactively in the terminal.</p>

<p>Tools like <a href="https://curl.se">cURL</a> are indispensable, but making routine JSON requests requires verbose flag ceremony (<code class="language-plaintext highlighter-rouge">-H "Content-Type: application/json" -d '...'</code>). HTTPie solved this years ago with intuitive syntax sugar, but running a Python interpreter on every invocation introduces noticeable startup latency. Curlie wrapped <code class="language-plaintext highlighter-rouge">curl</code> in Go to improve performance, but still requires external tools like <code class="language-plaintext highlighter-rouge">jq</code> to parse basic response payloads.</p>

<p>I wanted a single, fast native binary that combined the ergonomics of HTTPie, the rock-solid networking of <code class="language-plaintext highlighter-rouge">libcurl</code>, and native response filtering without needing <code class="language-plaintext highlighter-rouge">jq</code>.</p>

<p>The result is <a href="https://github.com/cladam/hicurl">hicurl</a>: a modern HTTP CLI built in <a href="https://www.hica.dev">hica</a>.</p>

<h3 id="what-it-does">What it does</h3>

<p><code class="language-plaintext highlighter-rouge">hicurl</code> handles the common HTTP operations without you having to fight shell quote escaping or pipe output to secondary tools.</p>

<h4 id="intuitive-syntax-sugar">Intuitive Syntax Sugar</h4>
<p>Positional arguments are dynamically parsed into headers, query parameters, or JSON fields based on their operator:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Implicit GET with query params</span>
hicurl /search <span class="nv">query</span><span class="o">==</span><span class="s2">"hica lang"</span> <span class="nv">limit</span><span class="o">==</span>10

<span class="c"># Explicit POST with typed JSON body and custom headers</span>
hicurl post /users <span class="nv">name</span><span class="o">=</span><span class="s2">"Alicia"</span> age:<span class="o">=</span>28 X-Client-ID:12345

<span class="c"># Localhost shorthand (expands to http://localhost:8000/v1/health)</span>
hicurl :8000/v1/health :status

<span class="c"># Form data toggle (-f)</span>
hicurl post /oauth/token <span class="nv">name</span><span class="o">=</span><span class="s2">"Alicia"</span> age:<span class="o">=</span>15 <span class="nt">-f</span>
</code></pre></div></div>

<p>It also supports embedding files directly into request payloads: <code class="language-plaintext highlighter-rouge">bio=@text.txt</code> embeds file contents as a string, while <code class="language-plaintext highlighter-rouge">data:=@payload.json</code> parses and embeds the JSON structure directly.</p>

<h4 id="native-response-filtering">Native Response Filtering</h4>

<p>Instead of piping responses to <code class="language-plaintext highlighter-rouge">jq</code>, <code class="language-plaintext highlighter-rouge">awk</code>, or <code class="language-plaintext highlighter-rouge">cut</code>, response selectors can be appended directly to the query:</p>

<ul>
  <li><strong>JSON Dot-Paths:</strong> Extract nested fields or array elements directly (<code class="language-plaintext highlighter-rouge">.data.users0.id</code>).</li>
  <li><strong>HTTP Metadata:</strong> Extract status codes (<code class="language-plaintext highlighter-rouge">:status</code>), raw headers (<code class="language-plaintext highlighter-rouge">:headers</code>), or specific case-insensitive header values (<code class="language-plaintext highlighter-rouge">:header.Content-Type</code>).</li>
  <li><strong>Cookies &amp; Diagnostics:</strong> Extract session tokens (<code class="language-plaintext highlighter-rouge">:cookie.session_id</code>) or query latency metrics directly from <code class="language-plaintext highlighter-rouge">libcurl</code> (<code class="language-plaintext highlighter-rouge">:time</code>, <code class="language-plaintext highlighter-rouge">:time.ttfb</code>, <code class="language-plaintext highlighter-rouge">:time.dns</code>).</li>
</ul>

<h4 id="environment-contexts--safety">Environment Contexts &amp; Safety</h4>

<p>When given a relative path like <code class="language-plaintext highlighter-rouge">hicurl /v1/users -e staging</code>, <code class="language-plaintext highlighter-rouge">hicurl</code> locates <code class="language-plaintext highlighter-rouge">.hicurl.env</code> by walking up parent directories (matching <code class="language-plaintext highlighter-rouge">git</code> directory resolution) and prepends the configured base URL.</p>

<p>It also includes an offline dry-run mode (<code class="language-plaintext highlighter-rouge">--dry-run</code> or <code class="language-plaintext highlighter-rouge">-E http</code>), which formats and prints the exact HTTP/1.1 request stream without firing bytes across the network. Safe inspection of request payloads is a core safety feature, reflecting the same philosophy behind <a href="https://cladam.github.io/2025/08/23/dry-run/">tbdflow’s –dry-run feature</a>.</p>

<h3 id="tty-awareness">TTY Awareness</h3>

<p>One design rule <code class="language-plaintext highlighter-rouge">hicurl</code> follows is <strong>stdout TTY awareness</strong>.</p>

<p>When you run <code class="language-plaintext highlighter-rouge">hicurl</code> in an interactive terminal, JSON responses are pretty-printed and colourised with ANSI terminal colours for visual readability.</p>

<p>However, when <code class="language-plaintext highlighter-rouge">stdout</code> is redirected, piped to another command, or used in subshells, <code class="language-plaintext highlighter-rouge">hicurl</code> automatically suppresses all ANSI colour codes and formatting. If you query a dot-path like <code class="language-plaintext highlighter-rouge">.token</code>, it outputs the raw, unquoted string.</p>

<p>This makes command composition very clean:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Query the GitHub API, pass the URL into a second hicurl query, and extract the bio</span>
hicurl <span class="si">$(</span>hicurl <span class="o">[</span>api.github.com/search/users]<span class="o">(</span>https://api.github.com/search/users<span class="o">)</span> <span class="nv">q</span><span class="o">==</span>cladam <span class="nv">per_page</span><span class="o">==</span>3 .items.0.url<span class="si">)</span> .bio
</code></pre></div></div>

<h3 id="what-this-means-for-hica">What this means for hica</h3>

<p>Building <code class="language-plaintext highlighter-rouge">hicurl</code> provided a practical testbed for <code class="language-plaintext highlighter-rouge">std/cli</code>, parent directory file operations, and C FFI bindings to <code class="language-plaintext highlighter-rouge">libcurl</code>.</p>

<p>Building CLI tools continues to be one of the best way to validate hica’s standard library and language mechanics. The C FFI story works, linking against system <code class="language-plaintext highlighter-rouge">libcurl</code> works cleanly, and the resulting binary runs without runtime overhead.</p>

<h3 id="try-it">Try it</h3>

<p>Using <code class="language-plaintext highlighter-rouge">curl</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-fsSL</span> https://github.com/cladam/hicurl/releases/latest/download/install.sh | sh
</code></pre></div></div>

<p>Or using <code class="language-plaintext highlighter-rouge">hicurl</code> (leveraging implicit GET, redirect following, and TTY detection to stream raw text to <code class="language-plaintext highlighter-rouge">sh</code>):</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hicurl https://github.com/cladam/hicurl/releases/latest/download/install.sh | sh
</code></pre></div></div>

<p>Pre-built binaries are available for macOS (ARM64), Linux (ARM64, x86_64) and Windows (x86_64).</p>

<ul>
  <li><strong><a href="https://github.com/cladam/hicurl">hicurl source</a></strong> - MIT licensed</li>
  <li><strong><a href="https://www.hica.dev">hica</a></strong> - the language it’s written in</li>
</ul>

<blockquote>
  <p><em>Instant feedback loops are a safety feature!</em></p>
</blockquote>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="hicurl" /><category term="hica" /><category term="cli" /><category term="curl" /><category term="http" /><summary type="html"><![CDATA[I spend a lot of time testing HTTP endpoints, inspecting JSON responses, and composing API calls, whether writing automated BDD specs in choreo or probing APIs interactively in the terminal.]]></summary></entry><entry><title type="html">Exploratory Learning: Discovering hica via the REPL</title><link href="/2026/07/21/exploratory-learning/" rel="alternate" type="text/html" title="Exploratory Learning: Discovering hica via the REPL" /><published>2026-07-21T00:00:00+00:00</published><updated>2026-07-21T00:00:00+00:00</updated><id>/2026/07/21/exploratory-learning</id><content type="html" xml:base="/2026/07/21/exploratory-learning/"><![CDATA[<p>The best way to learn a new programming language is to play with it. Reading documentation or scanning source files is fine, but you don’t really get a feel for the syntax and semantics until you start typing code and seeing what happens.</p>

<p>This is where the REPL shines.</p>

<p>Instead of just running the files in the <code class="language-plaintext highlighter-rouge">examples/</code> directory as static binaries, you can load them directly into hica’s REPL. This lets you inspect their types, call functions with different arguments, and even write new helpers on top of them interactively.</p>

<p>This post walks through how to explore hica examples in the REPL and how Hindley-Milner type inference makes interactive learning a lot faster.</p>

<h3 id="querying-types-on-the-fly">Querying types on the fly</h3>

<p>Because hica uses Hindley-Milner type inference, the compiler always knows the types even if you didn’t write them down. When you load an example into the REPL, you don’t need to guess what arguments a function takes or go digging through the source code. You can just ask the compiler.</p>

<p>With the <code class="language-plaintext highlighter-rouge">:t</code> command, you can query any function or expression:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="p">:</span><span class="n">t</span><span class="w"> </span><span class="nf">fizzbuzz</span><span class="p">
  (</span><span class="n">n</span><span class="p">:</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="w">
</span></code></pre></div></div>

<p>This tells you the exact signature of <code class="language-plaintext highlighter-rouge">fizzbuzz</code>. You get instant feedback without having to run the code or look at the files.</p>

<h3 id="a-typical-session">A typical session</h3>

<p>To start exploring, run the REPL from the root of the project:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hica repl
</code></pre></div></div>

<p>You can load any example using <code class="language-plaintext highlighter-rouge">:load</code>. The REPL will parse and type-check the file:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="p">:</span><span class="n">load</span><span class="w"> </span><span class="n">examples</span><span class="o">/</span><span class="n">fizzbuzz</span><span class="p">.</span><span class="n">hc</span><span class="w">
  </span><span class="n">loading</span><span class="w"> </span><span class="n">examples</span><span class="o">/</span><span class="n">fizzbuzz</span><span class="p">.</span><span class="n">hc</span><span class="w">
  </span><span class="n">loaded</span><span class="p">:</span><span class="w"> </span><span class="n">fizzbuzz</span><span class="w">
</span></code></pre></div></div>

<p>If you want to see what functions were loaded, use <code class="language-plaintext highlighter-rouge">:defs</code>:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="p">:</span><span class="n">defs</span><span class="w">
  </span><span class="kd">fun</span><span class="w"> </span><span class="nf">fizzbuzz</span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<p>Now check the type of <code class="language-plaintext highlighter-rouge">fizzbuzz</code>:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="p">:</span><span class="n">t</span><span class="w"> </span><span class="nf">fizzbuzz</span><span class="p">
  (</span><span class="n">n</span><span class="p">:</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="w">
</span></code></pre></div></div>

<p>Once loaded, you can evaluate expressions directly:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="nf">fizzbuzz</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span><span class="w">
</span><span class="s2">"FizzBuzz"</span><span class="w">
</span><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="nf">fizzbuzz</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="w">
</span><span class="s2">"7"</span><span class="w">
</span></code></pre></div></div>

<p>You can also define new functions on top of what is already loaded. For example, we can write a helper to run <code class="language-plaintext highlighter-rouge">fizzbuzz</code> over a range of numbers:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="kd">fun</span><span class="w"> </span><span class="nf">fizz_range</span><span class="p">(</span><span class="n">lo</span><span class="p">,</span><span class="w"> </span><span class="n">hi</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">[</span><span class="n">lo</span><span class="o">..=</span><span class="n">hi</span><span class="p">]</span><span class="w"> </span><span class="o">|&gt;</span><span class="w"> </span><span class="nf">map</span><span class="p">(</span><span class="n">fizzbuzz</span><span class="p">)</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="n">defined</span><span class="p">:</span><span class="w"> </span><span class="n">fizz_range</span><span class="w">
</span></code></pre></div></div>

<p>And run it:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="nf">fizz_range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">15</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="s2">"1"</span><span class="p">,</span><span class="w"> </span><span class="s2">"2"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Fizz"</span><span class="p">,</span><span class="w"> </span><span class="s2">"4"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Buzz"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Fizz"</span><span class="p">,</span><span class="w"> </span><span class="s2">"7"</span><span class="p">,</span><span class="w"> </span><span class="s2">"8"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Fizz"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Buzz"</span><span class="p">,</span><span class="w"> </span><span class="s2">"11"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Fizz"</span><span class="p">,</span><span class="w"> </span><span class="s2">"13"</span><span class="p">,</span><span class="w"> </span><span class="s2">"14"</span><span class="p">,</span><span class="w"> </span><span class="s2">"FizzBuzz"</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>If you want to switch to a different example, there is no need to restart the REPL. Just reset the state and load another file:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="p">:</span><span class="n">reset</span><span class="w">
  </span><span class="n">state</span><span class="w"> </span><span class="n">cleared</span><span class="w">
</span><span class="n">hica</span><span class="o">=&gt;</span><span class="w"> </span><span class="p">:</span><span class="n">load</span><span class="w"> </span><span class="n">examples</span><span class="o">/</span><span class="n">word_count</span><span class="p">.</span><span class="n">hc</span><span class="w">
  </span><span class="n">loading</span><span class="w"> </span><span class="n">examples</span><span class="o">/</span><span class="n">word_count</span><span class="p">.</span><span class="n">hc</span><span class="w">
  </span><span class="n">loaded</span><span class="p">:</span><span class="w"> </span><span class="n">count_words</span><span class="p">,</span><span class="w"> </span><span class="n">show_entry</span><span class="w">
</span></code></pre></div></div>

<h3 id="useful-commands">Useful commands</h3>

<p>Here is a quick reference of the available commands:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:load &lt;file&gt;     <span class="c"># Load a hica source file</span>
:defs            <span class="c"># List all active functions, structs, and enums</span>
:t &lt;<span class="nb">expr</span><span class="o">&gt;</span>        <span class="c"># Show the inferred type of an expression</span>
:reset           <span class="c"># Clear the active environment</span>
:help            <span class="c"># Show all commands</span>
:quit            <span class="c"># Exit the REPL</span>
</code></pre></div></div>

<h3 id="suggested-progression">Suggested progression</h3>

<p>If you want to explore the examples, this is a good order to go through:</p>

<ol>
  <li><code class="language-plaintext highlighter-rouge">examples/fizzbuzz.hc</code>: Basic control flow, conditionals, and integers.</li>
  <li><code class="language-plaintext highlighter-rouge">examples/word_count.hc</code>: List pattern matching, recursion, and string manipulation.</li>
  <li><code class="language-plaintext highlighter-rouge">examples/json_parser.hc</code>: Custom enums (ADTs), tuple usage, and parser states.</li>
</ol>

<p>Have fun exploring!</p>

<blockquote>
  <p><em>Feedback loops are the ultimate learning accelerant.</em></p>
</blockquote>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="hica" /><category term="REPL" /><category term="learning" /><summary type="html"><![CDATA[The best way to learn a new programming language is to play with it. Reading documentation or scanning source files is fine, but you don’t really get a feel for the syntax and semantics until you start typing code and seeing what happens.]]></summary></entry><entry><title type="html">tbdflow-ui: a desktop dashboard built with hica</title><link href="/2026/06/30/tbdflow-ui/" rel="alternate" type="text/html" title="tbdflow-ui: a desktop dashboard built with hica" /><published>2026-06-30T00:00:00+00:00</published><updated>2026-06-30T00:00:00+00:00</updated><id>/2026/06/30/tbdflow-ui</id><content type="html" xml:base="/2026/06/30/tbdflow-ui/"><![CDATA[<p><a href="https://www.hica.dev">hica</a> recently got initial package management, and I wanted to build something meaningful to put it to practise. I’ve added examples and working programs to the <a href="https://github.com/cladam/hica">repo</a>, but I wanted a real showcase using the <code class="language-plaintext highlighter-rouge">imgui</code> library. <a href="https://github.com/cladam/tbdflow">tbdflow</a> was the obvious candidate.</p>

<p><code class="language-plaintext highlighter-rouge">tbdflow</code> needed structured JSON output first, otherwise IPC would have meant brittle string parsing. Adding <code class="language-plaintext highlighter-rouge">--json</code> also improved the overall developer experience: if you use tbdflow in scripts or have a Genie committing code through it, you get machine-readable output instead of human-readable text. Supported by <code class="language-plaintext highlighter-rouge">info</code>, <code class="language-plaintext highlighter-rouge">status</code>, <code class="language-plaintext highlighter-rouge">radar</code>, <code class="language-plaintext highlighter-rouge">sync</code>, <code class="language-plaintext highlighter-rouge">recover --list</code>, <code class="language-plaintext highlighter-rouge">task show</code>, and <code class="language-plaintext highlighter-rouge">note --show</code>.</p>

<p>The commands work great in the terminal. But sometimes you just want to glance at a repository’s health without switching context, a quick ambient read. That peripheral awareness is important for comprehension, especially across multiple repos (teams should really be on a monorepo, but that’s a separate post).</p>

<p>The result is <code class="language-plaintext highlighter-rouge">tbdflow-ui</code>: a persistent three-panel desktop window that sits alongside your editor and keeps the workflow visible.</p>

<div align="center">
  <img src="/assets/images/tbdflow-ui-screenshot.png" alt="tbdflow-ui screenshot" width="700" />
</div>

<h3 id="what-it-does">What it does</h3>

<p>The window is organised into three panels.</p>

<p>The <strong>left panel</strong> is your context: which repo you’re in, which branch, whether CI is enabled, whether radar is active. A quick glance tells you where you are and whether the trunk is healthy.</p>

<p>The <strong>centre panel</strong> is where the work happens. Sync with one click. The Intent Log is right in front: type a note, press Add Note, it calls <code class="language-plaintext highlighter-rouge">tbdflow note "&lt;text&gt;"</code> and the log refreshes immediately. The breadcrumb is the point: reasoning is sharpest at the moment you write the code, and a field sitting in front of you captures it before the next context switch. Rules that rely on documenting something later don’t have the same pull. I wrote about the underlying risk in <a href="/2026/02/22/the-comprehension-crisis/">The Comprehension Crisis</a>. Below that is the commit form: a type dropdown populated from your repo’s <code class="language-plaintext highlighter-rouge">tbdflow --json info</code> config and a message. There is an <em>Advanced</em> toggle for the rest of the supported options.</p>

<p>The <strong>right panel</strong> provides Awareness: trunk status with a colour-coded signal (green, pending, red), churn hotspots from the last three days highlighted on a red-to-yellow scale, and an overlap count across active branches.</p>

<p>It also supports <strong>multiple repos</strong>. Click Browse, pick a directory, all panels reload. Handy if you’re switching between a few repos throughout the day.</p>

<h3 id="the-design-rule">The design rule</h3>

<p>There’s one rule the UI follows strictly: <strong>the CLI is the source of truth.</strong></p>

<p><code class="language-plaintext highlighter-rouge">tbdflow-ui</code> never touches Git directly. Every piece of data comes from <code class="language-plaintext highlighter-rouge">tbdflow --json &lt;command&gt;</code>. The commit button constructs a full <code class="language-plaintext highlighter-rouge">tbdflow commit -t &lt;type&gt; -m "&lt;message&gt;"</code> command string and executes it. The intent log reads from <code class="language-plaintext highlighter-rouge">tbdflow --json notes</code>. Radar reads from <code class="language-plaintext highlighter-rouge">tbdflow --json radar</code>.</p>

<p>This matters because it means the UI can never drift out of sync with the CLI’s logic. If <code class="language-plaintext highlighter-rouge">tbdflow</code> adds a new commit flag tomorrow, the UI gets it by passing through the JSON output, not by reimplementing the logic.</p>

<h3 id="why-a-desktop-app">Why a desktop app?</h3>

<p>A terminal is perfect when you’re actively working. A desktop window serves a different purpose. It provides ambient awareness: trunk health, overlaps, hotspots, and your current intent are visible without interrupting your flow. The goal wasn’t to replace the CLI, but to complement it.</p>

<h3 id="built-with-hica">Built with hica</h3>

<p>This is the part that interests me most, because <code class="language-plaintext highlighter-rouge">tbdflow-ui</code> is written in <a href="https://www.hica.dev">hica</a>, my own functional, expression-based language.</p>

<p>hica transpiles to Koka, and Koka compiles to C. So the pipeline for <code class="language-plaintext highlighter-rouge">tbdflow-ui</code> is:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.hc → hica → .kk → Koka → C → native binary
</code></pre></div></div>

<p>For a CLI tool, that pipeline is fairly unremarkable. For a GUI app with Dear ImGui, it gets more interesting. ImGui is a C++ immediate-mode GUI library. Getting hica to talk to it meant building a thin C FFI layer that exposes ImGui’s widgets as plain C functions, then wrapping those in a hica <code class="language-plaintext highlighter-rouge">imgui</code> library.</p>

<p>The result is that the hica source looks like this:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">render_sidebar_context</span><span class="p">(</span><span class="n">c</span><span class="p">:</span><span class="w"> </span><span class="nc">Config</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">:</span><span class="w"> </span><span class="nc">Status</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">label</span><span class="p">(</span><span class="s2">"Branch"</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_text</span><span class="p">(</span><span class="n">s</span><span class="p">.</span><span class="n">current_branch</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_spacing</span><span class="p">()</span><span class="w">

  </span><span class="nf">label</span><span class="p">(</span><span class="s2">"Mode"</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_text</span><span class="p">(</span><span class="n">c</span><span class="p">.</span><span class="n">mode</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_spacing</span><span class="p">()</span><span class="w">

  </span><span class="nf">label</span><span class="p">(</span><span class="s2">"CI Status:"</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_same_line</span><span class="p">()</span><span class="w">
  </span><span class="k">if</span><span class="w"> </span><span class="n">c</span><span class="p">.</span><span class="n">ci_check_enabled</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nf">gui_text_colored</span><span class="p">(</span><span class="s2">"- Enabled"</span><span class="p">,</span><span class="w"> </span><span class="mf">0.06</span><span class="p">,</span><span class="w"> </span><span class="mf">0.71</span><span class="p">,</span><span class="w"> </span><span class="mf">0.65</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nf">gui_text_colored</span><span class="p">(</span><span class="s2">"o Disabled"</span><span class="p">,</span><span class="w"> </span><span class="mf">0.94</span><span class="p">,</span><span class="w"> </span><span class="mf">0.33</span><span class="p">,</span><span class="w"> </span><span class="mf">0.31</span><span class="p">,</span><span class="w"> </span><span class="mf">1.0</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>No FFI boilerplate in application code. <strong>No pointer management, no widget IDs, no frame-begin/frame-end ceremony</strong>. hica’s effect system means the rendering context flows implicitly; IO effects are tracked at the type level without being specified on every function.</p>

<p>The commit command builder is a good example of how hica code reads. It’s purely functional: a chain of string conditionals that assembles the final shell command:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">pub</span><span class="w"> </span><span class="kd">fun</span><span class="w"> </span><span class="nf">build_commit_cmd</span><span class="p">(</span><span class="n">ctype</span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">msg</span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">scope</span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">body</span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> 
                         </span><span class="n">tag</span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">issue</span><span class="p">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="n">breaking</span><span class="p">:</span><span class="w"> </span><span class="kt">bool</span><span class="p">,</span><span class="w"> </span><span class="n">no_verify</span><span class="p">:</span><span class="w"> </span><span class="kt">bool</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">base</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"tbdflow commit -t "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">ctype</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">" -m </span><span class="se">\"</span><span class="s2">"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">msg</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"</span><span class="se">\"</span><span class="s2">"</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">s1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">scope</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s2">""</span><span class="w">   </span><span class="p">{</span><span class="w"> </span><span class="n">base</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">" -s "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">scope</span><span class="w"> </span><span class="p">}</span><span class="w">             </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">base</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">s2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">body</span><span class="w">  </span><span class="o">!=</span><span class="w"> </span><span class="s2">""</span><span class="w">   </span><span class="p">{</span><span class="w"> </span><span class="n">s1</span><span class="w">   </span><span class="o">+</span><span class="w"> </span><span class="s2">" --body </span><span class="se">\"</span><span class="s2">"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">body</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">"</span><span class="se">\"</span><span class="s2">"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">s1</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">s3</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">tag</span><span class="w">   </span><span class="o">!=</span><span class="w"> </span><span class="s2">""</span><span class="w">   </span><span class="p">{</span><span class="w"> </span><span class="n">s2</span><span class="w">   </span><span class="o">+</span><span class="w"> </span><span class="s2">" --tag "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">tag</span><span class="w"> </span><span class="p">}</span><span class="w">            </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">s2</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">s4</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">issue</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s2">""</span><span class="w">   </span><span class="p">{</span><span class="w"> </span><span class="n">s3</span><span class="w">   </span><span class="o">+</span><span class="w"> </span><span class="s2">" --issue "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">issue</span><span class="w"> </span><span class="p">}</span><span class="w">        </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">s3</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">s5</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">breaking</span><span class="w">      </span><span class="p">{</span><span class="w"> </span><span class="n">s4</span><span class="w">   </span><span class="o">+</span><span class="w"> </span><span class="s2">" --breaking"</span><span class="w"> </span><span class="p">}</span><span class="w">              </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">s4</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">s6</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">no_verify</span><span class="w">     </span><span class="p">{</span><span class="w"> </span><span class="n">s5</span><span class="w">   </span><span class="o">+</span><span class="w"> </span><span class="s2">" --no-verify"</span><span class="w"> </span><span class="p">}</span><span class="w">             </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">s5</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="n">s6</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Pure functions with clear data flow and no side effects until <code class="language-plaintext highlighter-rouge">exec()</code> is called.</p>

<h3 id="the-hica-imgui-library">The hica imgui library</h3>

<p>One thing I really like is the theming. Since the entire rendering surface is a hica module, I can write themes as plain hica files:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">pub</span><span class="w"> </span><span class="kd">fun</span><span class="w"> </span><span class="nf">apply_theme</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">gui_set_color_text</span><span class="p">(</span><span class="mf">0.9333</span><span class="p">,</span><span class="w"> </span><span class="mf">0.9411</span><span class="p">,</span><span class="w"> </span><span class="mf">0.9529</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_set_color_bg</span><span class="p">(</span><span class="mf">0.0941</span><span class="p">,</span><span class="w"> </span><span class="mf">0.1098</span><span class="p">,</span><span class="w"> </span><span class="mf">0.1451</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_set_color_accent</span><span class="p">(</span><span class="mf">0.2314</span><span class="p">,</span><span class="w"> </span><span class="mf">0.5098</span><span class="p">,</span><span class="w"> </span><span class="mf">0.9647</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_set_color_plot</span><span class="p">(</span><span class="mf">0.0588</span><span class="p">,</span><span class="w"> </span><span class="mf">0.7098</span><span class="p">,</span><span class="w"> </span><span class="mf">0.6549</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_set_style_rounding</span><span class="p">(</span><span class="mf">4.0</span><span class="p">,</span><span class="w"> </span><span class="mf">4.0</span><span class="p">,</span><span class="w"> </span><span class="mf">4.0</span><span class="p">)</span><span class="w">
  </span><span class="nf">gui_set_style_spacing</span><span class="p">(</span><span class="mf">8.0</span><span class="p">,</span><span class="w"> </span><span class="mf">6.0</span><span class="p">,</span><span class="w"> </span><span class="mf">16.0</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Drop a different theme file in, call a different function. The app ships with a “Stillness Dark / Nordic Blue” theme and a One Dark Pro theme. Switching is one function call. The <code class="language-plaintext highlighter-rouge">imgui</code> library has a <a href="https://github.com/cladam/imgui/tree/main/examples/theme-editor">theme-editor</a> if you want to create your own themes.</p>

<h3 id="what-this-means-for-hica">What this means for hica</h3>

<p><code class="language-plaintext highlighter-rouge">tbdflow-ui</code> is the most complete application I’ve built with hica so far, and hica itself didn’t require any language changes to build it. The language was already capable. What did evolve was the <code class="language-plaintext highlighter-rouge">imgui</code> FFI library: tbdflow-ui had requirements the earlier layer didn’t cover, so those gaps got filled as the application needed them.</p>

<p>That’s a healthy feedback loop. A real program with real requirements is a better driver for a library than designing the API in the abstract.</p>

<p>The takeaway is that hica can build real desktop GUI applications. A tool with multiple data sources, reactive panels, live CLI integration, clipboard access, hyperlinks, and two polished themes. The C FFI story works. The linking story works (Koka link flags for C++ static libs with <code class="language-plaintext highlighter-rouge">--cclinkopts=-lc++</code>). It compiles to a single native binary.</p>

<h3 id="try-it">Try it</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-fsSL</span> https://github.com/cladam/tbdflow-ui/releases/latest/download/install.sh | sh
</code></pre></div></div>

<p>Pre-built for macOS ARM64 and Linux x86_64. Requires <code class="language-plaintext highlighter-rouge">tbdflow</code> v0.33.0+ and SDL2 on your system.</p>

<p>If you want to build from source, install <a href="https://www.hica.dev">hica</a> and run <code class="language-plaintext highlighter-rouge">hica run</code> in the repo root.</p>

<ul>
  <li><a href="https://github.com/cladam/tbdflow-ui"><strong>tbdflow-ui source</strong></a> - MIT licensed</li>
  <li><a href="https://github.com/cladam/tbdflow"><strong>tbdflow</strong></a> - the CLI this wraps</li>
  <li><a href="https://www.hica.dev"><strong>hica</strong></a> - the language it’s written in</li>
</ul>

<p>This is an early release. tbdflow-ui will be improved continuously.</p>

<blockquote>
  <p><em>Throughput is a safety feature!</em></p>
</blockquote>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="tbdflow" /><category term="hica" /><category term="gui" /><category term="tbd" /><summary type="html"><![CDATA[hica recently got initial package management, and I wanted to build something meaningful to put it to practise. I’ve added examples and working programs to the repo, but I wanted a real showcase using the imgui library. tbdflow was the obvious candidate.]]></summary></entry><entry><title type="html">Spec-Driven Development and the Return of Big Batch Thinking</title><link href="/2026/06/22/spec-driven-development/" rel="alternate" type="text/html" title="Spec-Driven Development and the Return of Big Batch Thinking" /><published>2026-06-22T00:00:00+00:00</published><updated>2026-06-22T00:00:00+00:00</updated><id>/2026/06/22/spec-driven-development</id><content type="html" xml:base="/2026/06/22/spec-driven-development/"><![CDATA[<p>Some are calling it <strong>“Spec-Driven Development.”</strong> Write a detailed specification for a large chunk of system functionality, hand it to an AI agent, and let it generate a working codebase. The argument is that shipping small, vertical slices (define a tiny piece, build it, get feedback, repeat) is too slow for the AI era.</p>

<p>I find myself sceptical, and not because of the AI part.</p>

<h3 id="a-pattern-that-feels-familiar">A pattern that feels familiar</h3>

<p>The workflow looks like this:</p>

<ol>
  <li><strong>Design</strong> a large batch of features upfront.</li>
  <li><strong>Generate</strong> a large body of code from that design.</li>
  <li><strong>Review, test, and debug</strong> the output.</li>
  <li><strong>Ship</strong> it in a single release.</li>
</ol>

<p>In DevOps, this is Big Batch Delivery. We have decades of evidence for why it struggles. Large batches amplify risk at every stage. A single flawed assumption early in the design doesn’t just invalidate one feature; it invalidates everything built on top of it.</p>

<blockquote>
  <p>Software requirements aren’t facts. They are a network of unverified hypotheses.</p>
</blockquote>

<p>The entire purpose of iterative delivery is to test those hypotheses as cheaply and as early as possible, long before you have built an ecosystem on top of them.</p>

<p>AI doesn’t change this. <strong>The bottleneck was never how fast code gets written. It is the feedback loop.</strong></p>

<h3 id="the-review-problem">The review problem</h3>

<p>When an AI agent produces a large, multi-thousand-line output from a single specification, that code still has to be integrated, understood, and maintained by a human team. In practice, it lands in a review gate.</p>

<p>I explored this in <a href="https://cladam.github.io/2026/02/19/the-pull-request-trap/">The Pull Request Trap</a>. Human comprehension doesn’t scale with line count. A team reviewing a two-thousand-line AI-generated diff faces the same cognitive limits as a team reviewing a two-thousand-line human-generated one. Under time pressure, reviews go superficial. The gate exists, but the signal is weak.</p>

<p>Slower integration is the obvious problem. The less obvious one is structural debt introduced without anyone understanding it well enough to manage it.</p>

<h3 id="the-comprehension-dimension">The comprehension dimension</h3>

<p>There is also a subtler problem. When you optimise purely for generation speed, delivery and understanding come apart.</p>

<p>I wrote about this in <a href="https://cladam.github.io/2026/02/22/the-comprehension-crisis/">The Comprehension Crisis</a>. If a model generates the spec, the code, and the explanation, it is easy to ship without ever owning the reasoning behind it. The system looks faster but the team’s capability quietly degrades.</p>

<blockquote>
  <p>Human comprehension must scale with delivery, or ownership evaporates.</p>
</blockquote>

<p>With large, spec-driven outputs, the team inherits a codebase they didn’t reason through. When something breaks, and it will, debugging starts from a much weaker position.</p>

<h3 id="what-elephant-carpaccio-teaches-us">What Elephant Carpaccio teaches us</h3>

<p>The practice of slicing work into the smallest provable unit has a name: <a href="https://alistaircockburn.com/Elephant-Carpaccio">Elephant Carpaccio</a>. The goal isn’t smaller work for its own sake. It is to shorten the distance between a decision and its validation.</p>

<p>This doesn’t change when an AI is doing the coding. Fast generation only helps if you can confirm assumptions just as fast. That speed advantage disappears the moment you batch everything back up into a slow, uncertain release.</p>

<p>Some things stay true regardless of who writes the code:</p>

<ul>
  <li><strong>Feed the smallest useful slice to the agent.</strong> A tightly scoped prompt produces output that is easier to review, test, and validate in production.</li>
  <li><strong>Prefer continuous integration over gates.</strong> Trunk-based development with non-blocking reviews keeps changes flowing and keeps comprehension distributed across the team.</li>
  <li><strong>Treat telemetry as the ground truth.</strong> Real user behaviour, not the initial spec, is where value is confirmed or refuted.</li>
  <li><strong>Throughput and comprehension are not in tension.</strong> High throughput with deep understanding lets you isolate variables and adapt quickly. High throughput without understanding is how you accumulate hidden debt.</li>
</ul>

<h3 id="the-underlying-question">The underlying question</h3>

<p>Spec-Driven Development probably has a place: where requirements are stable, well-understood, and easy to verify in bulk. Most product work isn’t like that.</p>

<p>Writing a complete spec and getting a complete codebase back feels productive. <strong>Feeling productive and being productive are different things.</strong> If a core assumption in the spec is wrong, the cost scales with how much was built before anyone found out.</p>

<p>Micro-sized batches and tight feedback loops aren’t a constraint on what AI can do. They’re how you find out if what the agent produced was worth building.</p>

<blockquote>
  <p><em>Throughput is a safety feature!</em></p>
</blockquote>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="DevOps" /><category term="AI" /><category term="comprehension" /><category term="TBD" /><summary type="html"><![CDATA[Some are calling it “Spec-Driven Development.” Write a detailed specification for a large chunk of system functionality, hand it to an AI agent, and let it generate a working codebase. The argument is that shipping small, vertical slices (define a tiny piece, build it, get feedback, repeat) is too slow for the AI era.]]></summary></entry><entry><title type="html">Don’t trust, instruct and verify</title><link href="/2026/06/10/hica-assistant/" rel="alternate" type="text/html" title="Don’t trust, instruct and verify" /><published>2026-06-10T00:00:00+00:00</published><updated>2026-06-10T00:00:00+00:00</updated><id>/2026/06/10/hica-assistant</id><content type="html" xml:base="/2026/06/10/hica-assistant/"><![CDATA[<p>Generic LLMs are bad at niche programming languages. Ask one to write hica code and it invents syntax, uses functions that aren’t in the prelude, or produces Koka with the wrong variable names. It’s never seen hica, so it guesses from whatever looks closest.</p>

<p>A better-informed model beats a smarter one.</p>

<h3 id="the-idea">The idea</h3>

<p>Ollama lets you create custom models with a <code class="language-plaintext highlighter-rouge">Modelfile</code>: base LLM, parameters, and a system prompt. That prompt is permanent context the model reads before every message.</p>

<p><code class="language-plaintext highlighter-rouge">hica-assistant</code> is built on <code class="language-plaintext highlighter-rouge">qwen3.6:35b-a3b</code> (a mixture-of-experts model, fast on a Mac) with a system prompt covering the compiler pipeline, syntax rules, the prelude API with types, the stdlib, and a table of pitfalls from real bugs I’ve encountered during development.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ollama create hica-assistant <span class="nt">-f</span> Modelfile
ollama run hica-assistant
</code></pre></div></div>

<p>No API key needed, no data leaving the machine (works offline) and no rate limits.</p>

<h3 id="the-verify-part">The verify part</h3>

<p>Every snippet the model generates gets checked with the hica compiler:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hica check generated.hc
hica run generated.hc
hica <span class="nb">test </span>generated.hc
</code></pre></div></div>

<p>When it fails, I find the gap in the Modelfile, add the rule, and rebuild. The system prompt is the ground truth and very updateable. My chat history is throwaway.</p>

<p>Let’s look at a concrete example: the model kept writing <code class="language-plaintext highlighter-rouge">is_empty(list)</code> to check whether a list is empty, that’s wrong as <code class="language-plaintext highlighter-rouge">is_empty</code> takes a <code class="language-plaintext highlighter-rouge">string</code>. I added a row to the pitfalls table, ran <code class="language-plaintext highlighter-rouge">ollama create hica-assistant -f Modelfile</code>, and the next response used <code class="language-plaintext highlighter-rouge">match xs { [] =&gt; ... }</code> correctly.</p>

<p>The loop: prompt, generate, compile, fix Modelfile, rebuild.</p>
<h3 id="it-works-for-real-code">It works for real code</h3>

<p>I asked it to write a filter-map-fold pipeline. First try, both styles:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="c1">// pipe style</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">]</span><span class="w">
    </span><span class="o">|&gt;</span><span class="w"> </span><span class="nf">filter</span><span class="p">((</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
    </span><span class="o">|&gt;</span><span class="w"> </span><span class="nf">map</span><span class="p">((</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span><span class="w">
    </span><span class="o">|&gt;</span><span class="w"> </span><span class="nf">fold</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">acc</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">acc</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w">
  </span><span class="nf">println</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="w">   </span><span class="c1">// 60</span><span class="w">

  </span><span class="c1">// dot-call style, same result</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">]</span><span class="w">
    </span><span class="p">.</span><span class="nf">filter</span><span class="p">((</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
    </span><span class="p">.</span><span class="nf">map</span><span class="p">((</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span><span class="w">
    </span><span class="p">.</span><span class="nf">fold</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">acc</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">acc</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w">
  </span><span class="nf">println</span><span class="p">(</span><span class="n">b</span><span class="p">)</span><span class="w">   </span><span class="c1">// 60</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Both compile. Both produce 60. <code class="language-plaintext highlighter-rouge">a |&gt; f</code> and <code class="language-plaintext highlighter-rouge">a.f()</code> are the same thing and the model knows when to reach for each.</p>

<h3 id="bounded-knowledge-is-a-feature">Bounded knowledge is a feature</h3>

<p>The model only knows what’s in the Modelfile. Ask it about <code class="language-plaintext highlighter-rouge">get_cwd()</code>, which doesn’t exist in hica yet, and it says so and gives the real workaround (<code class="language-plaintext highlighter-rouge">get_env("PWD")</code>). A generic model would invent <code class="language-plaintext highlighter-rouge">get_cwd()</code> confidently and leave you debugging a compile error.</p>

<p>When something is missing from the Modelfile, I add it. Right now it covers the prelude, <code class="language-plaintext highlighter-rouge">std/io</code>, <code class="language-plaintext highlighter-rouge">std/list</code>, <code class="language-plaintext highlighter-rouge">std/datetime</code>, and the main pitfall patterns. The file grows with the language.</p>

<h3 id="the-modelfile-is-in-the-repo">The Modelfile is in the repo</h3>

<p>The <a href="https://github.com/cladam/hica/blob/main/Modelfile">Modelfile</a> is in the hica repo, Apache 2.0 licensed.</p>

<p>The approach works for any language, framework, or internal API a generic model hasn’t seen. Write down what it needs to know, verify with real tooling, iterate.</p>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="hica" /><category term="ollama" /><category term="LLM" /><category term="AI" /><summary type="html"><![CDATA[Generic LLMs are bad at niche programming languages. Ask one to write hica code and it invents syntax, uses functions that aren’t in the prelude, or produces Koka with the wrong variable names. It’s never seen hica, so it guesses from whatever looks closest.]]></summary></entry><entry><title type="html">Building a Lisp in hica</title><link href="/2026/05/25/hilisp/" rel="alternate" type="text/html" title="Building a Lisp in hica" /><published>2026-05-25T00:00:00+00:00</published><updated>2026-05-25T00:00:00+00:00</updated><id>/2026/05/25/hilisp</id><content type="html" xml:base="/2026/05/25/hilisp/"><![CDATA[<p>Version 0.29.3 of <strong>hica</strong> is out and the core is getting pretty stable. I wanted to explore whether hica could be used to write a small Lisp, as a way to stress-test the hica compiler: closures, recursive data structures, lexical scoping, higher-order functions.</p>

<p><strong>HiLisp</strong> is now live and ready for tinkering.</p>

<h3 id="why-a-lisp">Why a Lisp?</h3>

<p>Many developers write a Lisp at some point. Same thing here really.</p>

<p>The useful part is that maintaining HiLisp <em>is</em> hica development. Every script and example exercises the compiler and provides feedback. I ended up fixing several bugs in hica while building HiLisp.</p>

<p>The main inspiration was <a href="https://carp-lang.github.io/Carp/LanguageGuide.html">Carp</a>, a Lisp with ML/Rust-like semantics. HiLisp borrows its vocabulary of special forms: <code class="language-plaintext highlighter-rouge">defn</code>, <code class="language-plaintext highlighter-rouge">def</code>, <code class="language-plaintext highlighter-rouge">fn</code>, <code class="language-plaintext highlighter-rouge">let</code>, <code class="language-plaintext highlighter-rouge">do</code>, <code class="language-plaintext highlighter-rouge">cond</code>, <code class="language-plaintext highlighter-rouge">quote</code>.</p>

<p>Also, there is objective beauty in parentheses.</p>

<h3 id="what-it-looks-like">What it looks like</h3>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">defn</span> <span class="nv">factorial</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">&lt;=</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)</span> <span class="mi">1</span> <span class="p">(</span><span class="nb">*</span> <span class="nv">n</span> <span class="p">(</span><span class="nv">factorial</span> <span class="p">(</span><span class="nb">-</span> <span class="nv">n</span> <span class="mi">1</span><span class="p">)))))</span>

<span class="p">(</span><span class="nv">println</span> <span class="p">(</span><span class="nv">factorial</span> <span class="mi">10</span><span class="p">))</span>   <span class="c1">; 3628800</span>
</code></pre></div></div>

<p>Closures work:</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">defn</span> <span class="nv">make_adder</span> <span class="p">(</span><span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nv">fn</span> <span class="p">(</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nb">+</span> <span class="nv">x</span> <span class="nv">n</span><span class="p">)))</span>
<span class="p">(</span><span class="nv">def</span> <span class="nv">add10</span> <span class="p">(</span><span class="nv">make_adder</span> <span class="mi">10</span><span class="p">))</span>
<span class="p">(</span><span class="nv">println</span> <span class="p">(</span><span class="nv">add10</span> <span class="mi">32</span><span class="p">))</span>   <span class="c1">; 42</span>
</code></pre></div></div>

<p>And higher-order functions:</p>

<div class="language-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nv">defn</span> <span class="nb">map</span> <span class="p">(</span><span class="nv">f</span> <span class="nv">lst</span><span class="p">)</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">=</span> <span class="nv">lst</span> <span class="o">'</span><span class="p">())</span> <span class="o">'</span><span class="p">()</span>
    <span class="p">(</span><span class="nb">cons</span> <span class="p">(</span><span class="nv">f</span> <span class="p">(</span><span class="nb">car</span> <span class="nv">lst</span><span class="p">))</span> <span class="p">(</span><span class="nb">map</span> <span class="nv">f</span> <span class="p">(</span><span class="nb">cdr</span> <span class="nv">lst</span><span class="p">)))))</span>

<span class="p">(</span><span class="nv">println</span> <span class="p">(</span><span class="nb">map</span> <span class="p">(</span><span class="nv">fn</span> <span class="p">(</span><span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nb">*</span> <span class="nv">x</span> <span class="nv">x</span><span class="p">))</span> <span class="o">'</span><span class="p">(</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span> <span class="mi">5</span><span class="p">)))</span>
<span class="c1">; (1 4 9 16 25)</span>
</code></pre></div></div>

<h3 id="the-pipeline">The pipeline</h3>

<p>HiLisp is a classic tree-walker interpreter:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>source text → tokenise → parse → eval
</code></pre></div></div>

<p>Each phase lives in its own hica module: <code class="language-plaintext highlighter-rouge">tokeniser.hc</code>, <code class="language-plaintext highlighter-rouge">parser.hc</code>, <code class="language-plaintext highlighter-rouge">eval.hc</code>. The AST is a recursive <code class="language-plaintext highlighter-rouge">LVal</code> enum representing numbers, booleans, strings, symbols, lists, lambdas, and nil. Pattern matching over that enum drives the evaluator.</p>

<p>The interesting bit was environments. Each lambda captures a reference to its defining environment for proper lexical scoping. I expected that to need some gymnastics, but structs and recursive types in hica made it pretty straightforward.</p>

<h3 id="try-it">Try it</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./hilisp                         <span class="c"># REPL</span>
./hilisp examples/recursion.hl   <span class="c"># run a file</span>

<span class="c"># Build from source (needs hica ≥ 0.29.3 and Koka 3.2.3)</span>
hica build <span class="nt">-o</span> hilisp
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">examples/</code> folder contains runnable <code class="language-plaintext highlighter-rouge">.hl</code> files covering arithmetic, closures, recursion, lists, and sorting. There’s also a <code class="language-plaintext highlighter-rouge">lib/prelude.hl</code> with helpers like <code class="language-plaintext highlighter-rouge">map</code>, <code class="language-plaintext highlighter-rouge">filter</code>, and <code class="language-plaintext highlighter-rouge">fold</code>.</p>

<ul>
  <li><a href="https://github.com/cladam/hica-lisp"><strong>Source</strong></a>, MIT license.</li>
  <li><a href="https://github.com/cladam/hica-lisp/blob/main/docs/lisp-primer.md"><strong>Lisp primer</strong></a>,  start here if you’ve never worked with a Lisp.</li>
</ul>

<p>Going forward, I’ll definitely be using HiLisp as part of hica development itself, both as a playground and as a way to continuously exercise the compiler with real code.</p>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="hica" /><category term="lisp" /><category term="languages" /><category term="learning" /><summary type="html"><![CDATA[Version 0.29.3 of hica is out and the core is getting pretty stable. I wanted to explore whether hica could be used to write a small Lisp, as a way to stress-test the hica compiler: closures, recursive data structures, lexical scoping, higher-order functions.]]></summary></entry><entry><title type="html">Test-Driven Development with hica</title><link href="/2026/05/20/tdd-hica/" rel="alternate" type="text/html" title="Test-Driven Development with hica" /><published>2026-05-20T00:00:00+00:00</published><updated>2026-05-20T00:00:00+00:00</updated><id>/2026/05/20/tdd-hica</id><content type="html" xml:base="/2026/05/20/tdd-hica/"><![CDATA[<p>hica has inline <code class="language-plaintext highlighter-rouge">test</code> blocks. They sit right next to your functions: no extra test files, no additional imports and no framework.
Run <code class="language-plaintext highlighter-rouge">hica test</code> and you’re done, that’s it!</p>

<p>Early on in hica’s design I wanted the simplest possible testing workflow, and I think I succeeded (IMHO)</p>

<p>This post walks through how TDD works in hica and why the compiler changes what you need to test.</p>

<h3 id="tdd-isnt-new">TDD isn’t new</h3>

<p>TDD has a reputation as a methodology someone invented. It’s most definitely not. Kent Beck has said he “rediscovered” it by studying older literature and watching what good programmers already did. 
Dijkstra argued in 1972 that correctness proof and programs should “grow hand in hand.”</p>

<p>Andrea Laforgia captures this well in his <a href="https://a4al6a.substack.com/p/td">T*D piece</a>. 
TDD, trunk-based development, and collaborative programming are patterns that keep emerging when teams care about quality and fast delivery. 
When you remove friction from testing, people test first. That’s what happened with hica.</p>

<h3 id="the-compiler-does-half-the-work">The compiler does half the work</h3>

<p>hica has Hindley-Milner inference and exhaustive pattern matching. A lot of the defensive tests I’d write in other languages aren’t needed:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">type</span><span class="w"> </span><span class="nc">Direction</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nc">North</span><span class="p">,</span><span class="w"> </span><span class="nc">South</span><span class="p">,</span><span class="w"> </span><span class="nc">East</span><span class="p">,</span><span class="w"> </span><span class="nc">West</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="kd">fun</span><span class="w"> </span><span class="nf">move</span><span class="p">(</span><span class="n">pos</span><span class="p">,</span><span class="w"> </span><span class="n">dir</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="k">match</span><span class="w"> </span><span class="n">dir</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nc">North</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">pos</span><span class="p">.</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">pos</span><span class="p">.</span><span class="mi">1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">),</span><span class="w">
    </span><span class="nc">South</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">pos</span><span class="p">.</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">pos</span><span class="p">.</span><span class="mi">1</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">),</span><span class="w">
    </span><span class="nc">East</span><span class="w">  </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">pos</span><span class="p">.</span><span class="mi">0</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">pos</span><span class="p">.</span><span class="mi">1</span><span class="p">),</span><span class="w">
    </span><span class="nc">West</span><span class="w">  </span><span class="o">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">pos</span><span class="p">.</span><span class="mi">0</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="n">pos</span><span class="p">.</span><span class="mi">1</span><span class="p">)</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Forget the null case (there’s no null). Pass a string where a <code class="language-plaintext highlighter-rouge">Direction</code> is expected? It won’t compile. Leave out <code class="language-plaintext highlighter-rouge">West</code>? Compile error. 
The type checker handles structural correctness. What’s left for tests is whether the function <em>does the right thing</em>.</p>

<p>Rule of thumb: if the compiler can’t distinguish a correct implementation from an incorrect one, write a test.</p>

<h3 id="red-green-refactor">Red-green-refactor</h3>

<p>Let’s build a simple password validator from scratch.</p>

<p><strong>Red.</strong> Stub the interface, assert what you want:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">validate</span><span class="p">(</span><span class="n">password</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="kc">false</span><span class="w">

</span><span class="k">test</span><span class="w"> </span><span class="s2">"valid password has 6+ characters"</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">assert</span><span class="p">(</span><span class="nf">validate</span><span class="p">(</span><span class="s2">"secret123"</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">hica test password.hc</code> fails. Good, that’s expected.</p>

<p><strong>Green.</strong> Minimum code to pass:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">validate</span><span class="p">(</span><span class="n">password</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nf">str_length</span><span class="p">(</span><span class="n">password</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">6</span><span class="w">
</span></code></pre></div></div>

<p>Passes.</p>

<p><strong>Red again.</strong> New requirement: passwords need at least one digit. Add a test for it. It should fail against the current <code class="language-plaintext highlighter-rouge">validate</code> implementation:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">test</span><span class="w"> </span><span class="s2">"rejects password without digit"</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">assert_false</span><span class="p">(</span><span class="nf">validate</span><span class="p">(</span><span class="s2">"noNumbersHere"</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><strong>Green.</strong> Update the implementation to pass all tests:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">has_digit</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nf">any</span><span class="p">(</span><span class="nf">chars</span><span class="p">(</span><span class="n">s</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="nf">is_digit</span><span class="p">(</span><span class="n">c</span><span class="p">))</span><span class="w">

</span><span class="kd">fun</span><span class="w"> </span><span class="nf">validate</span><span class="p">(</span><span class="n">password</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="kd">let</span><span class="w"> </span><span class="n">long_enough</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">str_length</span><span class="p">(</span><span class="n">password</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">6</span><span class="w">
  </span><span class="n">long_enough</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nf">has_digit</span><span class="p">(</span><span class="n">password</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="k">test</span><span class="w"> </span><span class="s2">"valid password has 6+ characters"</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">assert</span><span class="p">(</span><span class="nf">validate</span><span class="p">(</span><span class="s2">"secret123"</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="k">test</span><span class="w"> </span><span class="s2">"rejects password without digit"</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">assert_false</span><span class="p">(</span><span class="nf">validate</span><span class="p">(</span><span class="s2">"noNumbersHere"</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">

</span><span class="k">test</span><span class="w"> </span><span class="s2">"rejects short password"</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">assert_false</span><span class="p">(</span><span class="nf">validate</span><span class="p">(</span><span class="s2">"ab1"</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>All three pass. Refactor whenever, the tests catch regressions.</p>

<h3 id="no-context-switch">No context switch</h3>

<p>Tests live next to the code:</p>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">double</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="w">

</span><span class="k">test</span><span class="w"> </span><span class="s2">"double works"</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nf">assert_eq</span><span class="p">(</span><span class="nf">double</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span><span class="w"> </span><span class="mi">6</span><span class="p">)</span><span class="w">
  </span><span class="nf">assert_eq</span><span class="p">(</span><span class="nf">double</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>running 1 test(s)...

  ✓ double works

1 test(s) passed
</code></pre></div></div>

<p>When something breaks:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  ✗ double works
    assertion failed: assert_eq(double(3), 5)
      expected: 5
      actually: 6
</code></pre></div></div>

<p>Use <code class="language-plaintext highlighter-rouge">assert_eq</code> over <code class="language-plaintext highlighter-rouge">assert</code>. “expected 5, got 6” tells you what happened, <code class="language-plaintext highlighter-rouge">assert</code> just says “false”.</p>

<h3 id="a-typical-session">A typical session</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hica repl                <span class="c"># explore an API before writing tests</span>
nvim password.hc         <span class="c"># write a failing test</span>
hica <span class="nb">test </span>password.hc    <span class="c"># see it fail</span>
nvim password.hc         <span class="c"># make it pass</span>
hica <span class="nb">test </span>password.hc    <span class="c"># see it pass</span>
hica check password.hc   <span class="c"># fast type-check between edits</span>
tbdflow commit <span class="nt">-t</span> feat <span class="nt">-m</span> <span class="s2">"add password validation"</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">hica check</code> only type-checks, no compilation and near instant. I run it between almost every edit, like a spellchecker for logic 🙂
<code class="language-plaintext highlighter-rouge">hica repl</code> is useful when you’re not sure what a function returns. Try it interactively first, then write the test.</p>

<h3 id="one-test-per-behaviour">One test per behaviour</h3>

<p>“Validates length” and “requires digit” are separate tests. If a test name needs “and” in it, split it.</p>

<p>Happy testing!</p>

<blockquote>
  <p><em>Throughput is a safety feature!</em> (now with tests)</p>
</blockquote>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="hica" /><category term="TDD" /><category term="testing" /><category term="DevOps" /><summary type="html"><![CDATA[hica has inline test blocks. They sit right next to your functions: no extra test files, no additional imports and no framework. Run hica test and you’re done, that’s it!]]></summary></entry><entry><title type="html">Introducing hica: a language that transpiles to Koka</title><link href="/2026/05/13/introducing-hica/" rel="alternate" type="text/html" title="Introducing hica: a language that transpiles to Koka" /><published>2026-05-13T00:00:00+00:00</published><updated>2026-05-13T00:00:00+00:00</updated><id>/2026/05/13/introducing-hica</id><content type="html" xml:base="/2026/05/13/introducing-hica/"><![CDATA[<p>In my post about cloning <a href="https://cladam.github.io/2026/05/06/koka-ls-clone/">ls in Koka</a> I mentioned wanting to build a small language that transpiles to Koka. That idea has become <strong>hica</strong>!</p>

<h3 id="the-itch">The itch</h3>

<p>hica is a statically typed, expression-oriented language. It compiles <code class="language-plaintext highlighter-rouge">.hc</code> source files through a Pratt parser and Hindley-Milner type checker, emits Koka <code class="language-plaintext highlighter-rouge">.kk</code> source, and lets Koka handle the rest.</p>

<p>I’ve wanted to design my own language for years. Every attempt fizzled out in the same place: the plumbing… Lexers, type systems, backends, memory management – the mountain of infrastructure you need before you can even think about syntax. It felt like building a house by first inventing concrete in a way…</p>

<p>But then it occurred to me, if I target Koka, I skip all those parts. Koka already has Perceus for memory, C/JS/WASM backends, a standard library, optimisation passes, and the effect runtime. I just need to build the front half: syntax, type checker, diagnostics, and an emitter that spits out <code class="language-plaintext highlighter-rouge">.kk</code> files. Koka handles the rest.</p>

<p>The constraint is that hica can only express what Koka can express, but given that hica’s design pillars (algebraic effects, Perceus memory, expression-oriented, strong inference) are exactly what Koka already provides, that costs almost nothing.</p>

<h3 id="what-it-looks-like">What it looks like</h3>

<div class="language-hica highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">fun</span><span class="w"> </span><span class="nf">fizzbuzz</span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="o">=&gt;</span><span class="w">
  </span><span class="k">if</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">15</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"fizzbuzz"</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"fizz"</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"buzz"</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"</span><span class="si">{n}</span><span class="s2">"</span><span class="w"> </span><span class="p">}</span><span class="w">

</span><span class="kd">fun</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">1</span><span class="o">..</span><span class="mi">100</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nf">println</span><span class="p">(</span><span class="nf">fizzbuzz</span><span class="p">(</span><span class="n">i</span><span class="p">))</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>Everything is an expression: <code class="language-plaintext highlighter-rouge">if</code>, <code class="language-plaintext highlighter-rouge">match</code>, blocks all return values. No <code class="language-plaintext highlighter-rouge">return</code> keyword. <code class="language-plaintext highlighter-rouge">"{n}"</code> is string interpolation. The name stands for <strong>H</strong>indley-milner <strong>I</strong>nference <strong>C</strong>ompiler with <strong>A</strong>lgebraic effects.</p>

<p>The pipeline is straightforward:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.hc source → Lex → Parse → Desugar → Type Check → Emit Koka (.kk) → Koka Compiler → C/JS/WASM
</code></pre></div></div>

<p>Each compiler phase uses algebraic effects for its state: diagnostics, type variables and symbol scopes are all effect-tracked. Compilers in Koka are surprisingly natural. The type checker runs Hindley-Milner unification and the emitter annotates the Koka output with the inferred types.</p>

<h3 id="the-tooling">The tooling</h3>

<p>I really enjoy building CLI tools, hica comes with <code class="language-plaintext highlighter-rouge">hica run</code>, <code class="language-plaintext highlighter-rouge">hica build</code>, <code class="language-plaintext highlighter-rouge">hica check</code> (which reports effects!), <code class="language-plaintext highlighter-rouge">hica test</code>, <code class="language-plaintext highlighter-rouge">hica fmt</code>, <code class="language-plaintext highlighter-rouge">hica new</code>, <code class="language-plaintext highlighter-rouge">hica clean</code>. 
The CLI is using my Clap inspired <a href="https://github.com/cladam/klap">klap library</a>, which handles flags, subcommands, and help generation.</p>

<p>I needed to test hica properly and have reused <a href="https://github.com/cladam/kunit">kunit</a> to validate and verify its functionality, hundreds of tests across lexer, parser, checker, codegen, and CLI.</p>

<h3 id="built-with-help-of-a-genie">Built with help of a Genie</h3>

<p>I used a Genie (what I call my GenAI model – thanks <a href="https://tidyfirst.substack.com/">Kent Beck</a> for the term) as a pair-programming partner throughout. I maintain <a href="https://github.com/cladam/hica/blob/main/documentation/backlog.md">the backlog</a> and iterate until it’s right. 
It lets me focus on the design decisions; the Genie handles the mechanical parts. It’s been superfun, and a breath of fresh air compared to grinding through boilerplate alone.</p>

<h3 id="try-it">Try it</h3>

<p>The language is fun to use, and really usable with structs, enums, full pattern matching, modules, closures, UFCS, built-in testing.</p>

<p>I have tried to document along the way, and to be honest, I think I did a good job with it, take a look:</p>

<ul>
  <li><a href="https://www.hica.dev/playground/"><strong>Playground</strong></a>: try hica in the browser, no installation needed.</li>
  <li><a href="https://www.hica.dev/docs/"><strong>Docs</strong></a>: language reference, quick start, and style guide.</li>
  <li><a href="https://github.com/cladam/hica"><strong>Source</strong></a>: Apache-2.0 licensed.</li>
</ul>

<h3 id="thank-you-koka">Thank you, Koka</h3>

<p>hica wouldn’t exist without Koka. The effect system, Perceus, the C backend is all inherited. Huge thanks to everyone working on Koka for making it possible for someone like me to build a real language.</p>]]></content><author><name>Claes Adamsson</name><email>claes.adamsson@gmail.com</email></author><category term="koka" /><category term="languages" /><category term="hica" /><category term="learning" /><summary type="html"><![CDATA[In my post about cloning ls in Koka I mentioned wanting to build a small language that transpiles to Koka. That idea has become hica!]]></summary></entry></feed>