<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://krismuniz.com</id>
    <title>Posts by Kristian Muñiz</title>
    <updated>2026-01-25T20:55:47.484Z</updated>
    <generator>none</generator>
    <author>
        <name>Kristian Muñiz</name>
        <email>contact@krismuniz.com</email>
        <uri>https://krismuniz.com</uri>
    </author>
    <link rel="alternate" href="https://krismuniz.com"/>
    <link rel="self" href="https://krismuniz.com/atom.xml"/>
    <subtitle>Thoughts about open source software, programming, the Web, and personal projects.</subtitle>
    <logo>https://krismuniz.com/og-image.png</logo>
    <icon>https://krismuniz.com/headshot.png</icon>
    <rights>© 2026 Kristian Muñiz</rights>
    <entry>
        <title type="html"><![CDATA[Soup]]></title>
        <id>https://krismuniz.com/posts/soup</id>
        <link href="https://krismuniz.com/posts/soup"/>
        <updated>2026-01-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A meditation on the stories we tell ourselves to feel safe.]]></summary>
        <content type="html"><![CDATA[<p>When you learn about someone else&#x27;s misfortune, you are reminded of your own vulnerability.</p>
<p>You try to find reasons to believe you are exempt from suffering.</p>
<p>You want to believe that you are in control, that the world is fundamentally fair, and that you get what you deserve.</p>
<p>Terrible things can happen to you, for reasons that you cannot possibly control.</p>
<p>There is no fate to deserve. There is no lesson to learn. There is no reason to anything.</p>
<p>You will eventually be disassembled and spread across the vast cosmos to be anything else that could be except you.</p>
<p>The Universe will pour you back into the soup of everything.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Semantically-Aware Constrained Decoding for Code Generation]]></title>
        <id>https://krismuniz.com/posts/constrained-decoding</id>
        <link href="https://krismuniz.com/posts/constrained-decoding"/>
        <updated>2024-03-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A speculative post on using semantically-aware constrained decoding for code generation.]]></summary>
        <content type="html"><![CDATA[<p>In my previous post, I shared <a href="https://krismuniz.com/posts/aici">Microsoft&#x27;s AICI</a> a very clever way of controlling the LLM inference process through portable, efficient, sandboxed WASM-based virtual machines.</p>
<p>Through a powerful abstraction like this, we could bring different stages of the generative pipeline of a Transformer-like architecture all the way up to the application layer.</p>
<p>Now that we are no longer limited by the static nature of prompts and hyperparameter configuration, we are able to apply advanced techniques for controlling the outputs of LLMs as a consumer.</p>
<h2 id="constrained-decoding"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#constrained-decoding"><span># </span></a>Constrained Decoding</h2>
<blockquote>
<p>My focus for this post is constrained decoding, specifically for text-based LLMs, but this could be applicable for any sequence-to-sequence generative model and may be extended beyond that.</p>
</blockquote>
<p>In simple terms, constrained decoding consists of reducing the number of possible next-token predictions to guide the model to produce a more desireable outcome. This is usually done by providing logit biases for specific tokens at each decoding step.</p>
<p>An example of this is OpenAI&#x27;s <a href="https://platform.openai.com/docs/guides/text-generation/json-mode">&quot;JSON Mode&quot;</a>, which, among other techniques, applies a grammar-based constraint in the decoding phase of GPT to reduce occurrences of invalid JSON syntax outputs. This methodology is likely also applied for OpenAI&#x27;s <a href="https://platform.openai.com/docs/guides/function-calling">function calling</a> feature, to ensure function calls are correct.</p>
<p>To illustrate the ideas of this post, I decided to use JavaScript, so I could express my ideas in a langage that is more accessible to a wider audience, but this could be implemented in any language.</p>
<p>In fact, the AICI project has a JavaScript interface <a href="https://github.com/microsoft/aici/tree/main/controllers/jsctrl">JsCtrl</a> which you can use to write these controllers.</p>
<p>This is how an AICI controller looks like:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">await</span> $<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">The answer to the ultimate question of life, the universe, and everything is </span><span class="token template-punctuation string">`</span></span>
    <span class="token keyword control-flow">await</span> <span class="token function">gen</span><span class="token punctuation">(</span><span class="token punctuation">{</span> regex<span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\d\d</span><span class="token regex-delimiter">/</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token function">start</span><span class="token punctuation">(</span>main<span class="token punctuation">)</span>
</code></pre>
<p>A likely output for this inference would be:</p>
<pre><code>The answer to the ultimate question of life, the universe, and everything is 42
</code></pre>
<p>For general-purpose code generation, however, I would lean towards a more precise approach for constraint decoding that explicitly presents the abstract syntax tree (AST). This will improve readability and maintainability of the code, and will also allow for more advanced features like context-awareness and type-safety.</p>
<p>In general, the idea is to use functions with tagged template literals to express the AST of the code that we want to generate <em>and</em> the constraints that we want to apply to the LLM.</p>
<p>For example, a function called <code>membersOf</code> would be used to express a <code>MemberExpression</code> tree in JavaScript, and a function called <code>property</code> would be used to express a <code>Property</code> tree that is a child of a <code>MemberExpression</code> tree.</p>
<pre class="language-ts"><code class="language-ts"><span class="token doc-comment comment">/**
 * 
 * <span class="token keyword">@example</span> Syntax Tree
 * MemberExpression(
 *   object: Identifier(&#x27;user&#x27;)
 *   property: Identifier(&#x27;name&#x27;)
 * )
 * <span class="token keyword">@example</span> Outputs
 * user
 * user.name
 * user.email
 */</span>
membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">user</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
    property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">name</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
    property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">email</span><span class="token template-punctuation string">`</span></span>
<span class="token punctuation">)</span>
</code></pre>
<p>Here&#x27;s a more practical example of how this could be used to express a constraint to match one of five possible JavaScript member expressions:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> oneOf<span class="token punctuation">,</span> membersOf<span class="token punctuation">,</span> property <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">&quot;?&quot;</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">await</span> <span class="token function">oneOf</span><span class="token punctuation">(</span>
        <span class="token doc-comment comment">/**
         * <span class="token keyword">@example</span> Output
         * meaningOfLife.answer
         * meaningOfLife.question
         */</span>
        membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">meaningOfLife</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">answer</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">question</span><span class="token template-punctuation string">`</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token doc-comment comment">/**
         * <span class="token keyword">@example</span> Output
         * meaningOfLife.author.name
         * meaningOfLife.author.born
         * meaningOfLife.author.died
         */</span>
        membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">meaningOfLife.author</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">name</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">born</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">died</span><span class="token template-punctuation string">`</span></span>
        <span class="token punctuation">)</span>
    <span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token function">start</span><span class="token punctuation">(</span>main<span class="token punctuation">)</span>
</code></pre>
<p>The content in the tagged template literals would work the same way as AICI&#x27;s <code>$</code> function, but with the added benefit of being able to mix the AST with the grammar constraints.</p>
<p>We could also express other syntactic features like function calls, computed properties, or even variable references.</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> oneOf<span class="token punctuation">,</span> membersOf<span class="token punctuation">,</span> callOf<span class="token punctuation">,</span> property<span class="token punctuation">,</span> arg<span class="token punctuation">,</span> computedProperty <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">&quot;?&quot;</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">await</span> <span class="token function">oneOf</span><span class="token punctuation">(</span>
        membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">meaningOfLife</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">answer</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">question</span><span class="token template-punctuation string">`</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">,</span>
        membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">meaningOfLife.author</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">name</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">born</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">died</span><span class="token template-punctuation string">`</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">,</span>
        membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">inventory.fruit</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            computedProperty<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">0</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            computedProperty<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">1</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
            computedProperty<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">2</span><span class="token template-punctuation string">`</span></span>
        <span class="token punctuation">)</span><span class="token punctuation">,</span>
        membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">userMap</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            computedProperty<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">userId</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
        <span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token doc-comment comment">/**
         * <span class="token keyword">@example</span>
         * window.localStorage.getItem(userMap[userId])
         */</span>
        callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">window.localStorage.getItem</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            memberOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">userMap</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
                computedProperty<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">userId</span><span class="token template-punctuation string">`</span></span>
            <span class="token punctuation">)</span>
        <span class="token punctuation">)</span>
    <span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token function">start</span><span class="token punctuation">(</span>main<span class="token punctuation">)</span>
</code></pre>
<p>At a surface level, these could be expressed as a grammar, in fact here&#x27;s how it would look like in EBNF:</p>
<pre class="language-ebnf"><code class="language-ebnf"><span class="token rule">RULE_0_A</span> :<span class="token operator">=</span> <span class="token string">&quot;name&quot;</span> <span class="token operator">|</span> <span class="token string">&quot;born&quot;</span> <span class="token operator">|</span> <span class="token string">&quot;died&quot;</span>
<span class="token rule">RULE_0</span>   :<span class="token operator">=</span> <span class="token string">&quot;meaningOfLife&quot;</span> <span class="token string">&quot;.&quot;</span> <span class="token punctuation">[</span> <span class="token string">&quot;answer&quot;</span> <span class="token string">&quot;question&quot;</span> <span class="token string">&quot;author&quot;</span> <span class="token punctuation">[</span> <span class="token string">&quot;.&quot;</span> <span class="token rule">RULE_0_1</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span>
<span class="token rule">RULE_1_A</span> :<span class="token operator">=</span> <span class="token string">&quot;0&quot;</span> <span class="token operator">|</span> <span class="token string">&quot;1&quot;</span> <span class="token operator">|</span> <span class="token string">&quot;2&quot;</span>
<span class="token rule">RULE_1</span>   :<span class="token operator">=</span> <span class="token string">&quot;inventory&quot;</span> <span class="token punctuation">[</span> <span class="token string">&quot;.&quot;</span> <span class="token string">&quot;fruit&quot;</span> <span class="token string">&quot;[&quot;</span> <span class="token rule">RULE_1_1</span> <span class="token string">&quot;]&quot;</span> <span class="token punctuation">]</span>
<span class="token rule">RULE_2</span>   :<span class="token operator">=</span> <span class="token string">&quot;userMap&quot;</span> <span class="token punctuation">[</span> <span class="token string">&quot;[userId]&quot;</span> <span class="token punctuation">]</span>
<span class="token rule">RULE_3</span>   :<span class="token operator">=</span> <span class="token string">&quot;window.localStorage.getItem&quot;</span> <span class="token punctuation">[</span> <span class="token string">&quot;(&quot;</span> <span class="token string">&quot;userMap&quot;</span> <span class="token punctuation">[</span> <span class="token string">&quot;[userId]&quot;</span> <span class="token punctuation">]</span> <span class="token string">&quot;)&quot;</span> <span class="token punctuation">]</span>
<span class="token rule">OUTPUT</span>   :<span class="token operator">=</span> <span class="token rule">RULE_0</span> <span class="token operator">|</span> <span class="token rule">RULE_1</span> <span class="token operator">|</span> <span class="token rule">RULE_2</span> <span class="token operator">|</span> <span class="token rule">RULE_3</span>
</code></pre>
<p>However, expressing the AST in our decoding process has the added benefit of being able to express constraints that are also semantically significant.</p>
<h2 id="semantically-aware-constrained-decoding"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#semantically-aware-constrained-decoding"><span># </span></a>Semantically-Aware Constrained Decoding</h2>
<p>So far, we&#x27;ve only been talking about static semantic constraints. But what if we could go further? Could we handle dynamic semantic constraints?</p>
<p>Consider this example, which constrains the LLM to pick between two different API calls <code>fetchUsersByEmail</code> and <code>postUser</code>. This illustrates how <code>str()</code> could be used to express the AST of the code that we want to generate while also providing the LLM opportunities to fill in the blanks.</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> oneOf<span class="token punctuation">,</span> callOf<span class="token punctuation">,</span> obj<span class="token punctuation">,</span> property<span class="token punctuation">,</span> str <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">&quot;?&quot;</span>

<span class="token keyword">const</span> name <span class="token operator">=</span> <span class="token function">str</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> email <span class="token operator">=</span> <span class="token function">str</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token doc-comment comment">/**
 * <span class="token keyword">@example</span> Output
 * fetch(&quot;https://api.example.com/users?email=john.doe@example.com&quot;)
 */</span>
<span class="token keyword">const</span> fetchUsersByEmail <span class="token operator">=</span> callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">fetch</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
    str<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.example.com/users?email=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>email<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
<span class="token punctuation">)</span>

<span class="token doc-comment comment">/**
 * <span class="token keyword">@example</span> Output
 * fetch(&quot;https://api.example.com/users&quot;, <span class="token punctuation">{</span>
 *   method: &quot;POST&quot;,
 *   body: <span class="token punctuation">{</span>
 *     name: &quot;John Doe&quot;,
 *     email: &quot;john.doe@example.com&quot;
 *   <span class="token punctuation">}</span>
 * <span class="token punctuation">}</span>)
 */</span>
<span class="token keyword">const</span> postUser <span class="token operator">=</span> callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">fetch</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
    str<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.example.com/users</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
    <span class="token function">obj</span><span class="token punctuation">(</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">method</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token string">&quot;POST&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">body</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            <span class="token function">obj</span><span class="token punctuation">(</span>
                property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">name</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">,</span>
                property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">email</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>email<span class="token punctuation">)</span>
            <span class="token punctuation">)</span>
        <span class="token punctuation">)</span>
    <span class="token punctuation">)</span>
<span class="token punctuation">)</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">await</span> <span class="token function">oneOf</span><span class="token punctuation">(</span>
        fetchUsersByEmail<span class="token punctuation">,</span>
        postUser
    <span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token function">start</span><span class="token punctuation">(</span>main<span class="token punctuation">)</span>
</code></pre>
<p>But generating literals is... well, too literal (and let&#x27;s be honest, table stakes).</p>
<p>Of course the model would generate values for <code>name</code> and <code>email</code>, but in the real world we may want to use values that are present in the context of the application like variables and other expressions.</p>
<p>What if we used a special <code>contextOf</code> function to express the context of the application in a way that can be referenced by the LLM in a semantically-accurate way?</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> contextOf<span class="token punctuation">,</span> callOf<span class="token punctuation">,</span> obj<span class="token punctuation">,</span> property<span class="token punctuation">,</span> str<span class="token punctuation">,</span> num<span class="token punctuation">,</span> bool <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">&quot;?&quot;</span>

<span class="token doc-comment comment">/**
 * <span class="token keyword">@example</span> Output
 * session.user.name
 * session.user.email
 * api.url
 */</span>
<span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token function">contextOf</span><span class="token punctuation">(</span>
    membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">session.user</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">name</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">,</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">email</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">,</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">age</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>num<span class="token punctuation">)</span>
    <span class="token punctuation">)</span><span class="token punctuation">,</span>
    membersOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">api</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">url</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>str<span class="token punctuation">)</span><span class="token punctuation">,</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">public</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>bool<span class="token punctuation">)</span>
    <span class="token punctuation">)</span>
<span class="token punctuation">)</span>

<span class="token keyword">const</span> postUser <span class="token operator">=</span> callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">fetch</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
    <span class="token function">str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token function">obj</span><span class="token punctuation">(</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">method</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token string">&quot;POST&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">body</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>
            <span class="token function">obj</span><span class="token punctuation">(</span>
                property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">name</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
                property<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">email</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">str</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token punctuation">)</span>
        <span class="token punctuation">)</span>
    <span class="token punctuation">)</span>
<span class="token punctuation">)</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">await</span> context<span class="token punctuation">;</span>
    <span class="token keyword control-flow">await</span> postUser<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">start</span><span class="token punctuation">(</span>main<span class="token punctuation">)</span>
</code></pre>
<p>This <code>contextOf</code> function is not a function that generates a context, but a function that <em>references</em> a context and makes it available to future generative steps.</p>
<p>We would implement our <code>str</code> handler to prompt the model to generate a string literal <em>or</em> reference a <code>string</code> from the context.</p>
<h4 id="speculative-implementation-details"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#speculative-implementation-details"><span># </span></a>Speculative Implementation Details</h4>
<p>Behind the scenes, a type mapping could be generated from the <code>contextOf</code> call, and the LLM would be guided to generate values that are semantically accurate and type safe.</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">string</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> session.user.name
    <span class="token punctuation">-</span> session.user.email
<span class="token key atrule">number</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> session.user.age
<span class="token key atrule">boolean</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> api.public
// <span class="token punctuation">...</span>
<span class="token key atrule">SomeType</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> some.path.to.value
</code></pre>
<p>Practically-speaking, the real context would be provided by the application at runtime, but it wouldn&#x27;t even be necessary to provide it at inference time.</p>
<h3 id="type-safe-generative-variables"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#type-safe-generative-variables"><span># </span></a>Type-Safe Generative Variables</h3>
<p>If we want to allow the LLM to output variable declarations, we could define a <code>variable</code> function.</p>
<p>Then, when generating arguments for function calls, we would constrain the LLM to use a variable that is already in the context or a literal value that satisfies the type of the argument.</p>
<p>Here&#x27;s a simple arithmetic calculator used by contraining the model to only output variable declarations of explicitly <code>number</code> type and function invocations of explicitly the <code>add</code>, <code>sub</code>, <code>mul</code>, and <code>div</code> functions.</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> manyOf<span class="token punctuation">,</span> callOf<span class="token punctuation">,</span> returnOf<span class="token punctuation">,</span> variable<span class="token punctuation">,</span> id<span class="token punctuation">,</span> num <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">&quot;?&quot;</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token doc-comment comment">/**
     * <span class="token keyword">@example</span> Prompt
     * I bought 3 apples (3.99 ea) and 4 oranges (4.39 ea).
     * 
     * How much did I spend?
     * <span class="token keyword">@example</span> Output
     * let apples = 3
     * let oranges = 4
     * let applePrice = 3.99
     * let orangePrice = 4.39
     * let appleTotal = mul(apples, applePrice)
     * let orangeTotal = mul(oranges, orangePrice)
     * let total = add(appleTotal, orangeTotal)
     * return total
     */</span>
    <span class="token keyword control-flow">await</span> <span class="token function">manyOf</span><span class="token punctuation">(</span>
        variable<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        variable<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">add</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        variable<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">sub</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        variable<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">mul</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
        variable<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">div</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span>
    <span class="token keyword control-flow">await</span> <span class="token function">returnOf</span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The LLM would still need to generate the variable declarations and function invocations, but it would be guided to generate semantically-accurate and type-safe code.</p>
<h4 id="bonus-refactoring"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#bonus-refactoring"><span># </span></a>Bonus: Refactoring</h4>
<p>We could express the same code in a more readable, less-verbose way by abstracting the <code>variable</code> function.</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword module">import</span> <span class="token imports"><span class="token punctuation">{</span> manyOf<span class="token punctuation">,</span> callOf<span class="token punctuation">,</span> returnOf<span class="token punctuation">,</span> variable<span class="token punctuation">,</span> id<span class="token punctuation">,</span> num <span class="token punctuation">}</span></span> <span class="token keyword module">from</span> <span class="token string">&quot;?&quot;</span>

<span class="token keyword">const</span> varFor <span class="token operator">=</span> variable<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">await</span> <span class="token function">manyOf</span><span class="token punctuation">(</span>
        <span class="token function">varFor</span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// e.g. let apples = 3</span>
        <span class="token function">varFor</span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">add</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// e.g. let totalFruit = add(apples, oranges)</span>
        <span class="token function">varFor</span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">sub</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// e.g. let oneMinusTwo = sub(1, 2)</span>
        <span class="token function">varFor</span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">mul</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// e.g. let applesTotal = mul(apples, applePrice)</span>
        <span class="token function">varFor</span><span class="token punctuation">(</span>callOf<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">div</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// e.g. let orangeToAppleRatio = div(oranges, apples)</span>
    <span class="token punctuation">)</span>
    <span class="token keyword control-flow">await</span> <span class="token function">returnOf</span><span class="token punctuation">(</span><span class="token function">num</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// e.g. return orangeTotal</span>
<span class="token punctuation">}</span>
</code></pre>
<h3 id="conclusion"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#conclusion"><span># </span></a>Conclusion</h3>
<p>I know that this is purely a theoretical idea at this point, but I think it&#x27;s a very interesting one that would allow us to get semantically-accurate and type-safe code generation from LLMs.</p>
<p>This works in theory, but there are many practical challenges to overcome. For example, how would we handle the context at runtime? How would we handle the type mapping? How would we know when to pause and resume the inference process to provide the context?</p>
<p>I deeply believe these are all solvable problems, and I&#x27;m excited to see where this goes.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Microsoft's AICI]]></title>
        <id>https://krismuniz.com/posts/aici</id>
        <link href="https://krismuniz.com/posts/aici"/>
        <updated>2024-03-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[AICI uses WebAssembly to constrain and direct the output of Large Language Models in real time.]]></summary>
        <content type="html"><![CDATA[<p>A team at Microsoft unveiled <a href="https://github.com/microsoft/aici">AICI</a>:</p>
<blockquote>
<p>The Artificial Intelligence Controller Interface (AICI) lets you build Controllers that constrain and direct output of a Large Language Model (LLM) in real time. Controllers are flexible programs capable of implementing constrained decoding, dynamic editing of prompts and generated text, and coordinating execution across multiple, parallel generations. Controllers incorporate custom logic during the token-by-token decoding and maintain state during an LLM request. This allows diverse Controller strategies, from programmatic or query-based decoding to multi-agent conversations to execute efficiently in tight integration with the LLM itself.</p>
</blockquote>
<p>This is such a clever idea. A couple months ago I talked about being able to <a href="https://krismuniz.com/posts/openai-devday-wishlist#output-templates">control the output of an LLM in real time</a>. This does exactly that, but better because you can write your own custom logic to control the output.</p>
<p>What is most interesting to me is not only the <em>what</em> but also the <em>how</em>:</p>
<blockquote>
<p>AICI is designed for both local and cloud execution, including (eventually) multi-tenant LLM deployments. Controllers are implemented as light-weight WebAssembly (Wasm) modules which run on the same machine as the LLM inference engine, utilizing the CPU while the GPU is busy with token generation. AICI is one layer in the inference stack, and is designed to allow control libraries such as Guidance, LMQL, and others to run on top of it and gain both efficiency and performance improvements, as well as portability across LLM inference and serving engines.</p>
</blockquote>
<p>WebAssembly is a perfect fit for this. It&#x27;s <a href="https://webassembly.github.io/spec/core/">standard</a>, fast, and embeddable. More importantly, it is relatively easy to run arbitrary code in a sandboxed, memory-safe execution environment, which is ideal for this type of use-case.</p>
<p>Once again, the Web Platform is the future of software. I&#x27;m glad to see Microsoft embracing it. I hope OpenAI and other LLM developers follow suit and implement something like this as well.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[My OpenAI DevDay 2023 Wishlist]]></title>
        <id>https://krismuniz.com/posts/openai-devday-wishlist</id>
        <link href="https://krismuniz.com/posts/openai-devday-wishlist"/>
        <updated>2023-10-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Things I'd like to see OpenAI announce at DevDay 2023.]]></summary>
        <content type="html"><![CDATA[<p>OpenAI&#x27;s DevDay is coming up on November 6, 2023 and I&#x27;m excited to see what they announce.</p>
<p>Apparently they are not announcing new foundation models (i.e. GPT-5), but are instead going to focus on new features and tools for their APIs.</p>
<p>This is my wishlist, categorized in three buckets: <strong>Likely Suspects</strong>, <strong>Big Moves</strong>, <strong>Moonshots</strong>.</p>
<h2 id="likely-suspects"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#likely-suspects"><span># </span></a>Likely Suspects</h2>
<h3 id="general-performance-improvements"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#general-performance-improvements"><span># </span></a>General Performance Improvements</h3>
<p>This one feels obvious to me, faster <code>gpt-4</code>, it&#x27;s a no-brainer. Faster time-to-first-token, faster inference times, faster everything. GPT-4 is very slow. It&#x27;s still usable with streaming, but it&#x27;s too slow.</p>
<p>I&#x27;m not sure if this will be in the form of a &quot;distilled&quot; version of existing models, a completely new model, or just general infrastructure improvements across the board. Will <code>gpt-4</code> just be faster or will we see a <code>gpt-4-turbo</code>?</p>
<p>Maybe they will also release an <em>even faster</em> <code>gpt-3.5-turbo</code>?</p>
<h3 id="gpt-4-fine-tuning-api"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#gpt-4-fine-tuning-api"><span># </span></a>GPT-4 Fine-Tuning API</h3>
<p>This one is also a no-brainer. We already have the fine-tuning API for <code>gpt-3.5-turbo</code>, so it&#x27;s only natural that we get one for <code>gpt-4</code>. Right? Right!?</p>
<p>I&#x27;m interested in how the economics are going to look like, but the general idea is that you can fine-tune <code>gpt-4</code> to your specific domain or use case and get better results using fewer tokens, which generally means it&#x27;s going to be cheaper for specific cases.</p>
<h3 id="public-dalle-3-api"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#public-dalle-3-api"><span># </span></a>Public DALL·E 3 API</h3>
<p>We already have an API for DALL·E 2, of course they&#x27;re working on making DALL·E 3 public! In fact, they already said it was going to be released late fall when they publicly announced it.</p>
<p>What I&#x27;m really wondering is the pricing, though. Will it be the same as DALL·E 2? Will it be more expensive? Will it be cheaper because they achieved some sort of economies-of-scale win? I&#x27;m not sure, but I&#x27;m excited to find out.</p>
<h3 id="multimodal-api"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#multimodal-api"><span># </span></a>Multimodal API</h3>
<p>GPT-V, as OpenAI has been marketing it, is already making its way into ChatGPT and Bing, so it is possible that they bring it to the API.</p>
<p>I&#x27;m not sure if it will be a completely new model or just a modification to the API that allows sending images and text together.</p>
<p>I&#x27;m curious about how the API would look like and how the pricing would work. Are images encoded as base64 strings? Are they sent as URLs? Are they sent as binary blobs? Are they sent as a combination of all of the above?</p>
<h3 id="playground-improvements"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#playground-improvements"><span># </span></a>Playground Improvements</h3>
<p>I&#x27;m hoping for some improvements to the playground, especially if multimodality comes through. I&#x27;d like to see a token counter, support for function calling, and maybe even templating?</p>
<h2 id="big-moves"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#big-moves"><span># </span></a>Big Moves</h2>
<h3 id="ability-to-pause-insert-into-and-resume-inferences"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#ability-to-pause-insert-into-and-resume-inferences"><span># </span></a>Ability to Pause, Insert Into, and Resume Inferences</h3>
<p>I don&#x27;t know of a clever way to call this. But I would like to have longer-lived inferences that can span multiple requests.</p>
<blockquote>
<p><strong>Edit</strong>
You might be thinking, &quot;oh so you want a stateful API?&quot;.
Short answer is yes, but that is an implementation detail. I just want the ability to have longer-lived inferences. I don&#x27;t care how this is achieved, I just want it to be possible.</p>
</blockquote>
<p>A general idea is that you could provide some sort of token to pause the inference, freeze the state of the infrerence in place, provide more context to bias the rest of the inference, and then resume it.</p>
<p>If possible, maybe even save in token costs along the way?</p>
<p><code>llama.cpp</code> has a similar feature, where you can pause the inference at any time, inject some text, and then resume the inference as if the model produced the text you injected.</p>
<p>This would open the door for one-shot reACT loops. Fewer tokens, but longer inference lifespan. I think it&#x27;d be worth it.</p>
<p>We&#x27;d be able to do things like:</p>
<pre><code>Sure, I&#x27;ll unsubscribe you from the
/unsubscribe(User)⏸️Successfully unsubscribed User⏩️Done!
</code></pre>
<p>The ability to pause, insert into, and resume the inference.</p>
<p>The ability to pause... <a href="https://archive.org/details/original-iphone-keynote">are you getting it?</a> These aren&#x27;t three separate inferences, it&#x27;s one single inference that can be paused, inserted into, and resumed.</p>
<h2 id="moonshots"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#moonshots"><span># </span></a>Moonshots</h2>
<h3 id="output-templates"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#output-templates"><span># </span></a>Output Templates</h3>
<p>It would be great to be able to provide a template to the API and have the LLMs exclusively sample tokens in a way that the full output conforms to it. This would be amazing for things like biasing the model to output code, JSON, HTML, etc.</p>
<p>A good medium to allow this feature would be through the usage of a grammar file. <code>llama.cpp</code>, for example, <a href="https://github.com/ggerganov/llama.cpp/blob/master/grammars/README.md">supports this feature</a>.</p>
<h3 id="regular-updates-to-training-data"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#regular-updates-to-training-data"><span># </span></a>Regular Updates to Training Data</h3>
<p>What if OpenAI had a regular cadence of releasing new models with updated information about the outside world (e.g. current events, new people, new places, new things, etc.)?</p>
<h3 id="more-deterministic-models"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#more-deterministic-models"><span># </span></a>More Deterministic Models</h3>
<p>I know, I know... LLMs are inherently stochastic, but hear me out. I have a more practical solution to this problem.</p>
<p>I am under the impression that OpenAI&#x27;s models are not frozen in time, that they are constantly being updated and retrained. This means that the same input prompt can produce different outputs over time.</p>
<p>OpenAI kinda, <a href="https://platform.openai.com/docs/models/gpt-4">sorta versions their models</a>, but it is widely understood that they are making changes under the hood all the time.</p>
<p>Here&#x27;s a comprehensive list of things that could be altering the output of the model:</p>
<ul>
<li>Adding new training data</li>
<li>Changing the model architecture</li>
<li>Modifying the hyperparameters</li>
<li>Altering the training process</li>
<li>Applying learnings from RLHF</li>
<li>Updating the tokenization process</li>
<li>Scaling the API depending on load</li>
<li>Changing how the API is deployed</li>
</ul>
<p>It <em>must</em> be happening, no?</p>
<p>I&#x27;d like to see them release frozen models that are guaranteed to produce similar output for the same input prompt (as much as its stochastic nature allows).</p>
<p>Or, if they already guarantee this inherently, I would like to see them make it more clear.</p>
<h3 id="built-in-code-interpreter-api"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#built-in-code-interpreter-api"><span># </span></a>Built-In Code Interpreter API</h3>
<p>What if the API had a built-in runtime to execute code for popular programming languages (Python, JavaScript, TypeScript)? It would be amazing to have the model run the code for you in a sandboxed environment and use the output.</p>
<p>Here&#x27;s an imaginary transcript of the prompt and response:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token property">&quot;role&quot;</span><span class="token operator">:</span> <span class="token string">&quot;user&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;content&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Give me a random number from 1 to 10&quot;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    <span class="token property">&quot;role&quot;</span><span class="token operator">:</span> <span class="token string">&quot;assistant&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;to&quot;</span><span class="token operator">:</span> <span class="token string">&quot;javascript&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;content&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Math.floor(Math.random() * 10) + 1&quot;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    <span class="token property">&quot;role&quot;</span><span class="token operator">:</span> <span class="token string">&quot;interpreter&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;name&quot;</span><span class="token operator">:</span> <span class="token string">&quot;javascript&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;content&quot;</span><span class="token operator">:</span> <span class="token string">&quot;3&quot;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">{</span>
    <span class="token property">&quot;role&quot;</span><span class="token operator">:</span> <span class="token string">&quot;assistant&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;content&quot;</span><span class="token operator">:</span> <span class="token string">&quot;How about 3?&quot;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">]</span>
</code></pre>
<p>How cool would that be?</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Bringing Language Models Closer to the Editor Through Modal Editing]]></title>
        <id>https://krismuniz.com/posts/qq-in-printloop</id>
        <link href="https://krismuniz.com/posts/qq-in-printloop"/>
        <updated>2023-08-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A blog post showcasing QQ on printloop.dev, my proposal for a new editing modality that allows the user to make quick consults with a language model within the editor.]]></summary>
        <content type="html"><![CDATA[<p>Recently, I introduced <a href="https://onivim.github.io/docs/getting-started/modal-editing-101">modal editing</a> to <a href="https://printloop.dev">printloop.dev</a> through a feature I call QQ – it stands for &quot;quick question&quot; and is pronounced &quot;cue-cue&quot;.</p>
<p>QQ is my proposal for a new editing modality that allows the user make quick consults with a language model that has been fine-tuned for chat within the editor. It offers a frictionless way to ask for explanations, examples, and documentation without interrupting the user&#x27;s workflow.</p>
<p>Here is a brief demo of QQ in action:</p>
<iframe src="https://www.youtube.com/embed/crfdt1YNXhs?controls=0&amp;mute=1&amp;playsinline=1&amp;rel=0&amp;loop=1&amp;autoplay=1&amp;showinfo=0" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" class="bg-white dark:bg-zinc-900 rounded-[9px] aspect-video w-full border dark:border-zinc-800 border-zinc-200"></iframe>
<h2 id="how-to-trigger-qq"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#how-to-trigger-qq"><span># </span></a>How to Trigger QQ</h2>
<p>When the user types <code>qq</code> at the beginning of a line or comment, the editor shows a floating tooltip below the cursor line. The text editor then functions like a text input where the user can type a question like &quot;what does this code do?&quot;.</p>
<p>When the user presses <code>enter</code> (or <code>return</code> on macOS), the question is sent to a language model – in the case of the demo above, OpenAI&#x27;s <code>gpt-3.5-turbo</code>, – which streams back a response to answer the user&#x27;s question. The response is directly displayed in the tooltip, so the user doesn&#x27;t have to leave the editor to see the answer.</p>
<p>The user can then choose to either close the conversation by pressing <code>esc</code> or continue sending replies to the model to iterate on the generated responses. When the user closes the tooltip, the edited line is cleared and the editor returns to its regular state.</p>
<h2 id="why-modal-editing"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#why-modal-editing"><span># </span></a>Why Modal Editing?</h2>
<p>Modal editing is a way to preserve flow by reducing the number of context switches. It&#x27;s a way to &quot;stay in the zone&quot; and keep your hands on the keyboard while you&#x27;re working. With modal editing there&#x27;s no need to reach for the mouse, or to switch to a different pane to look something up. You will be able to type stuff out, and then ask for help, all without leaving the editor or in many cases switching focus away from the text editor itself.</p>
<h2 id="presenting-the-conversation"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#presenting-the-conversation"><span># </span></a>Presenting the Conversation</h2>
<p>In screen readers, the tooltip is announced as a live region, and the user is informed that they are in a conversation with a language model. I still need to do some research on how to best present the conversation to screen readers, but live regions seem to work better than a modal dialog, for example.</p>
<p>The content of the conversation is presented as a list of message bubbles, analogous to a two-way chat conversation between the user and another individual. Like in an instant-messaging application, the user&#x27;s questions are shown as accent-colored message bubbles on the right, and the responses from the language model are shown as message grayscale bubbles on the left.</p>
<p>When the conversation is empty, the user is presented with an empty state that shows &quot;No messages&quot;.</p>
<p>As the user types their question, the dialog shows the user&#x27;s question as a message bubble, but is presented in an indeterminate state, communicating that the question still has not been sent to the language model.</p>
<p>When the user presses <code>enter</code>, the question is sent and the message bubble&#x27;s visual state is updated to indicate it. A live announcement is dispatched to the screen reader through <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions">ARIA live regions</a> as well, communicating that the message has been sent.</p>
<p>As the response from the language model is received, the response is shown as a message bubble in a similar indeterminate state. When the response is received, the message bubble is updated to show the response.</p>
<p>Responses from the language model are expected to be richer in content and format than the user&#x27;s questions, so the message bubbles are styled differently to communicate that. Responses from the LLM also support markdown formatting and syntax highlighting of code-blocks to make the content more digestable and reable for the user.</p>
<h3 id="managing-conversations"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#managing-conversations"><span># </span></a>Managing Conversations</h3>
<p>The user can close the conversation by pressing <code>esc</code> or <code>enter</code> on an empty line. When the conversation is closed, the tooltip is hidden and the editor returns to its regular state, but the conversation is still available in the editor&#x27;s state. The user can trigger <code>qq</code> again to reopen the conversation and continue where they left off, or to review the conversation again.</p>
<p>Conversations are grouped by line number, so that the user can have multiple conversations open at the same time. This is useful for when the user is working on multiple lines of code at the same time, and wants to ask questions at different parts of the code.</p>
<h3 id="prompting"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#prompting"><span># </span></a>Prompting</h3>
<p>The contents of the active document are sent alongside the user&#x27;s question to the language model. This is done to provide context to the language model, and to help it generate more relevant responses for the user.</p>
<p>Here is the prompt that is sent to the language model:</p>
<pre class="language-text"><code class="language-text">As &quot;Loop&quot;, you&#x27;re a programming assistant driven by a language model.
Respect user&#x27;s instructions strictly, but avoid discussing opinions, existence, sentience, or engage in arguments.
Provide accurate, logical, brief, and Markdown-formatted responses with named language in code blocks.
Respond to technical inquiries with code suggestions only within code blocks.
Account for the user&#x27;s language in code blocks when using the text editor, Printloop.
Limit responses to one per interaction turn.
---
location: {window.location.origin}{window.location.pathname}
editing document: printloop.md
contents:
# A Simple SQLite Database

Here is a simple SQLite database:

```sqlite!
CREATE TABLE messages (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  text TEXT
);

&lt;- user&#x27;s cursor is here

INSERT INTO messages (text) VALUES (&#x27;Hi!&#x27;), (&#x27;How are you?&#x27;);

UPDATE messages SET text = &#x27;Hi there!&#x27; WHERE id = 1;

SELECT * FROM messages;
```
</code></pre>
<p>I&#x27;ve been using this prompt for a while now, and it&#x27;s been working well. I&#x27;m sure there are ways to improve it. I&#x27;m also thinking of adding a way for the user to customize the prompt, or to add their own prompts.</p>
<h3 id="next-steps"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#next-steps"><span># </span></a>Next Steps</h3>
<p>I&#x27;m still working on improving the experience of using QQ, and I&#x27;m looking forward to hearing feedback from users. My main focus right now is on improving accessibility, and making sure that the conversation is presented in a way that is easy to follow and understand for screen reader users and users with other cognitive and physical disabilities.</p>
<p>I also want to improve the triggering mechanism. Right now, the user has to type <code>qq</code> at the beginning of a line or comment, but I want to make it easier to trigger the conversation. I&#x27;m thinking of adding a keyboard shortcut, or a way to trigger the conversation by listening to <code>qq</code> as a series of keystrokes instead of parsing it from the text buffer per se.</p>
<h2 id="try-it"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#try-it"><span># </span></a>Try It!</h2>
<p>Type <code>qq</code> in <a href="https://printloop.dev/?code=CoTwDgpgBABgjnGUCWA7KBDKqIHcoA2a0ALgPZQDOEpAFtBACbIloDmUAtmYxkSSBToMAY1ZlUAQigAoGTAUDIlEQCdkYEjIgAPMGVUkoAMwCuqMcglRGZAMolTx4wApKJVQC4qH9gEpvd3VUDgBvGSgoVQhHVXQggDpKMH4XACI0vwTogDcIVWoXLIArMjR0zIBuGQBfGQB6eqgEKggCCDEoElpkSkJiSXkFIA%3D">printloop.dev</a> to open the QQ modal. Then, type a question, like &quot;what is a monad?&quot;.</p>
<iframe class="bg-white dark:bg-zinc-900 rounded-[9px] aspect-square md:aspect-video w-full border dark:border-zinc-800 border-zinc-200" src="https://printloop.dev/?code=CoTwDgpgBABgjnGUCWA7KBDKqIHcoA2a0ALgPZQDOEpAFtBACbIloDmUAtmYxkSSBToMAY1ZlUAQigAoGTAUDIlEQCdkYEjIgAPMGVUkoAMwCuqMcglRGZAMolTx4wApKJVQC4qH9gEpvd3VUDgBvGSgoVQhHVXQggDpKMH4XACI0vwTogDcIVWoXLIArMjR0zIBuGQBfGQB6eqgEKggCCDEoElpkSkJiSXkFIA%3D"></iframe>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Projection]]></title>
        <id>https://krismuniz.com/posts/projection</id>
        <link href="https://krismuniz.com/posts/projection"/>
        <updated>2023-04-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A short poem, written in code, reflecting on projection. Beware of A ∝ B]]></summary>
        <content type="html"><![CDATA[<p>The amount of hate you have for a trait in yourself is proportional to the amount of hate you have for that same trait in other people.</p>
<pre><code>h(x, y): |hate| in {x} for {y}
t(x, y): |trait|{x} in {y}
a(x): |amount| of {x}

T: any
Y: |you|
O: |other people|

A: a(h(Y, t(T, Y)))
B: a(h(Y, t(T, O)))

A ∝ B
</code></pre>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Large Language Models]]></title>
        <id>https://krismuniz.com/posts/large-language-models</id>
        <link href="https://krismuniz.com/posts/large-language-models"/>
        <updated>2023-03-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A brief post on the current state of large language models and the potential of self-hosting them on consumer hardware!]]></summary>
        <content type="html"><![CDATA[<p>It is no secret that I&#x27;ve been very enthusiastic about <em>The Commercial NLP Renaissance</em> a.k.a. Large Language Models (yet <a href="https://twitter.com/KristianMuniz/status/1627921607120556032">a bit skeptical about the type of people its attracting</a>).</p>
<p>I&#x27;ve been building a lot of stuff with them, mainly <a href="https://printloop.dev">Printloop</a>, but also <a href="https://github.com/krismuniz/bori">BORI</a>.</p>
<p>This week is expected to be big for language models as GPT-4 is rumored to be announced, but also high-performance language models are very close to land in consumer hardware!</p>
<h2 id="language-computer"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#language-computer"><span># </span></a>Language Computer</h2>
<p>I&#x27;ve been looking for ways to build a &quot;Language Computer&quot; for my home; I want to run a service on my own hardware that I can use to build personal language tools, services, and home automation workflows.</p>
<p>I also want to host other AI services at home (like speech-recognition), but my focus is on language models first because I believe it&#x27;s the most useful.</p>
<p>Turns out, I am very close to making this a reality! We&#x27;ll soon be able to run a language model with performance comparable to OpenAI&#x27;s Davinci GPT models on our own hardware.</p>
<p>I highly recommend reading Simon Wilson&#x27;s <a href="https://simonwillison.net/2023/Mar/13/alpaca/">&quot;Stanford Alpaca&quot; post</a> discussed the acceleration of large language model development on-device, particularly talking about Stanford Alpaca and llama.cpp.</p>
<p>I already so many ideas for things I will be able to do with my own language service at home:</p>
<ul>
<li>Digitize, summarize, categorize, and sort my snail mail</li>
<li>Digest, summarize, and present the news to me</li>
<li>An army of mechanical historians that indefinitely browse the web, recording findings about topics that I am interested in, keeps track of trends, and writes me a report every day</li>
</ul>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Project UN1]]></title>
        <id>https://krismuniz.com/posts/project-un1</id>
        <link href="https://krismuniz.com/posts/project-un1"/>
        <updated>2022-03-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Talking about my new hobby project UN1. I feel really good about it!]]></summary>
        <content type="html"><![CDATA[<p>I&#x27;m developing a new, secret hobby project.</p>
<p>Well, not so secret, as I&#x27;ve been <a href="https://twitter.com/KristianMuniz/status/1509372399568896003">regularly posting my progress on Twitter</a>. I&#x27;ve been working on it since March 20 and I&#x27;m pretty happy with my progress so far.</p>
<h2 id="what-im-building"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#what-im-building"><span># </span></a>What I&#x27;m Building</h2>
<p>All I have is a faint idea of the type of product I want to build: a beautiful, low-code, statechart editor. Doesn&#x27;t have to be full-featured, but enough to be dangerous.</p>
<p>Of course, a statechart editor is not a new idea at all, many software products like these exist already. My favorite one so far is <a href="https://stately.ai">Stately</a>, founded by <a href="https://twitter.com/DavidKPiano">David K. Piano</a>, creator of <a href="https://xstate.js.org/">XState</a> and a popular advocate for state machines and statecharts.</p>
<p>But I&#x27;m not trying to build a <strong>power tool</strong> like Stately! I want this to be more of a delightful <strong>toy tool</strong>. Or at least I want that to be the driving idea.</p>
<h3 id="what-do-you-mean-by-beautiful"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#what-do-you-mean-by-beautiful"><span># </span></a>What Do You Mean by Beautiful?</h3>
<p>I want <code>UN1</code> to be nice to look at, even if it&#x27;s at the expense of some performance. I want it to be easy to use, visually-appealing, and interactive. I do not care if that complicates my project or I have to sacrifice some feature for it.</p>
<p>The good thing about having no commercial incentive for working on a project is that I can make decisions that don&#x27;t make economical sense. I&#x27;m just in it for the fun of building it.</p>
<p>I want to work on rendering the arrows between elements, to build the infinite-canvas layout with pinch-to-zoom and panning.</p>
<p>I want this to have eye-catching visuals, a great UX, and a playful tone.</p>
<h3 id="why-low-code"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#why-low-code"><span># </span></a>Why Low-Code?</h3>
<p>I am currently working on a very ambitious low-code product at <a href="https://airkit.com">Airkit</a>, so I think about problems like these all the time. Having side-projects like <code>UN1</code> help me explore ideas beyond the scope of my work while still exercising my creativity in a similar context to the problem I try to solve for a living. It does wonders for my easily-distracted brain.</p>
<p>I want the graphical user interface to allow me to build statecharts without having to even <em>think</em> about code – except for maybe side-effects and guards. And even then, try to reduce those to a GUI whenever possible.</p>
<h3 id="lets-see-how-it-goes"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#lets-see-how-it-goes"><span># </span></a>Let&#x27;s See How it Goes</h3>
<p>I am explicitly avoiding naming this project until I figure out the finer details of the design. The last time I was so excited about a project was back in 2018 when I was working on <code>M1N</code>, which turned into <a href="/posts/minimo">Minimo</a>.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Using :scope Is Pretty Cool]]></title>
        <id>https://krismuniz.com/posts/scope-pseudo</id>
        <link href="https://krismuniz.com/posts/scope-pseudo"/>
        <updated>2021-10-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I recently found out about the :scope pseudo-class. Here's a quick writeup on the things you can do with it!]]></summary>
        <content type="html"><![CDATA[<p>While trying to solve a problem at work, a coleague and I found out about the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:scope"><code>:scope</code></a> pseudo-class. In a nutshell, it allows you to refer to the current element&#x27;s scope in a CSS selector.</p>
<p>When writing a stylesheet, <code>:scope</code> is the same thing as <code>:root</code>, because there is no way to write scoped stylesheets. Scoped stylesheets was a feature that was proposed some time ago, and some browsers experimented with, but have since been <a href="https://www.chromestatus.com/feature/5374137958662144">removed from browsers</a> and <a href="https://github.com/whatwg/html/issues/552">removed from the spec</a>.</p>
<p>Even though we cannot do anything useful with <code>:scope</code> in our stylesheets, we can use the <code>:scope</code> pseudo-class with the DOM API!</p>
<p>When using DOM API methods that expect CSS selectors, you can use <code>:scope</code> to refer to the element from which you are calling it!</p>
<pre class="language-javascript"><code class="language-javascript">element<span class="token punctuation">.</span><span class="token method function property-access">matches</span><span class="token punctuation">(</span><span class="token string">&quot;:scope&quot;</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment">// element is itself, so true!</span>
</code></pre>
<h2 id="things-you-can-do-with-scope"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#things-you-can-do-with-scope"><span># </span></a>Things You Can Do with <code>:scope</code></h2>
<h3 id="selecting-direct-descendants"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#selecting-direct-descendants"><span># </span></a>Selecting Direct Descendants</h3>
<p><code>:scope</code> is particularly useful when selecting direct descendants of the current element that match some criteria!</p>
<pre class="language-javascript"><code class="language-javascript">element<span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;:scope &gt; input#username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>An alternative, would be to get all the children of <code>element</code> and match them against a selector.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token known-class-name class-name">Array</span><span class="token punctuation">.</span><span class="token keyword module">from</span><span class="token punctuation">(</span>element<span class="token punctuation">.</span><span class="token property-access">children</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">find</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">child</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> child<span class="token punctuation">.</span><span class="token method function property-access">matches</span><span class="token punctuation">(</span><span class="token string">&quot;input#username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>Another approach would be to refer to the current element using an ID or class:</p>
<pre class="language-javascript"><code class="language-javascript">element<span class="token punctuation">.</span><span class="token method function property-access">setAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;id&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;myid&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
element<span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;#myid &gt; input#username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre>
<p>But this would be a bit harder to maintain, as the selector and whatever attribute we are using to match the current element would need to be in sync.</p>
<h3 id="assertions-that-involve-hierarchy"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#assertions-that-involve-hierarchy"><span># </span></a>Assertions That Involve Hierarchy</h3>
<p>Another use case for <code>:scope</code> is to elegantly assert whether the current element matches a particular selector without needing to use an ID or class to refer to the current element.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// element is a direct child of `div#wepa`</span>
element<span class="token punctuation">.</span><span class="token method function property-access">matches</span><span class="token punctuation">(</span><span class="token string">&quot;div#wepa &gt; :scope&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; `boolean`</span>

<span class="token comment">// element is descendant of #content</span>
element<span class="token punctuation">.</span><span class="token method function property-access">matches</span><span class="token punctuation">(</span><span class="token string">&quot;#content :scope&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; `boolean`</span>

<span class="token comment">// element is the next sibling of a `label`</span>
element<span class="token punctuation">.</span><span class="token method function property-access">matches</span><span class="token punctuation">(</span><span class="token string">&quot;label + :scope&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; `boolean`</span>

<span class="token comment">// the next sibling of the element is a `label`</span>
element<span class="token punctuation">.</span><span class="token method function property-access">matches</span><span class="token punctuation">(</span><span class="token string">&quot;:scope + label&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; `boolean`</span>

<span class="token comment">// element is a descendant of a `form` element,</span>
<span class="token comment">// and has a `textarea` as a child</span>
element<span class="token punctuation">.</span><span class="token method function property-access">matches</span><span class="token punctuation">(</span><span class="token string">&quot;form :scope &gt; textarea&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; `boolean`</span>
</code></pre>
<p>Again, there are other ways to do this, but this way is probably more expressive, concise, and easier to maintain.</p>
<h2 id="limitations"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#limitations"><span># </span></a>Limitations</h2>
<p>A noteworthy limitation that I&#x27;ve noticed, however, is that using <code>Element.querySelector()</code> or <code>Element.querySelectorAll()</code> to match siblings of the current element does not work.</p>
<p>This likely due to the fact that <code>querySelector</code> and <code>querySelectorAll</code> only consider the descendants of the current element, so it makes sense.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">// try to get all siblings of the current element</span>
element<span class="token punctuation">.</span><span class="token method function property-access">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">&quot;:scope ~ *&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; Empty NodeList</span>

<span class="token comment">// try to get the next sibling of the current element</span>
element<span class="token punctuation">.</span><span class="token method function property-access">querySelectorAll</span><span class="token punctuation">(</span><span class="token string">&quot;:scope + *&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; Empty Nodelist</span>
</code></pre>
<p>In that case we still have to use the traditional methods, like getting all the children of the parent element, matching them against a selector, and filtering out our &quot;target element&quot;.</p>
<p>Likely for the same reason, <code>:scope</code> cannot be used to match the current element itself. Which would not be useful, but interesting to know about.</p>
<pre class="language-javascript"><code class="language-javascript">element<span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;:scope&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// =&gt; null</span>
</code></pre>
<h2 id="browser-support"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#browser-support"><span># </span></a>Browser Support</h2>
<p>I expected <code>:scope</code> to have limited browser support. Surprisingly, at the time of this writing <code>:scope</code> has <a href="https://caniuse.com/mdn-css_selectors_scope">very good browser support</a>.</p>
<p>The TL;DR is if you don&#x27;t have to support Internet Explorer, you can use <code>:scope</code>!</p>
<h2 id="whats-next"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#whats-next"><span># </span></a>What&#x27;s Next?</h2>
<p>I hope you enjoyed this quick writeup. I&#x27;m going to write a couple more about other interesting Web features that I&#x27;ve found myself using recently.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Publishing to My Blog with github.dev]]></title>
        <id>https://krismuniz.com/posts/github-dev</id>
        <link href="https://krismuniz.com/posts/github-dev"/>
        <updated>2021-08-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Testing a new workflow for publishing posts to my site using nothing but a browser.]]></summary>
        <content type="html"><![CDATA[<p>I&#x27;ve been looking for a lightweight workflow to post to my site for a while. My process for publishing new posts and making changes to my site is already pretty simple, but GitHub&#x27;s new <a href="https://docs.github.com/en/codespaces/developing-in-codespaces/web-based-editor">web-based editor</a> has dramatically reduced the necessary friction, particularly when publishing new posts.</p>
<p>My blog posts are simple <a href="https://mdxjs.com/">MDX</a> files, so all I really need is a decent text editor with MDX syntax highlighting. Unfortunately, I haven&#x27;t found many MDX editors out there, so I&#x27;ve had to use VSCode all this time.</p>
<p>But now I can just use VSCode in the browser!!! There&#x27;s a very nice <a href="https://marketplace.visualstudio.com/items?itemName=silvenon.mdx">MDX extension</a> for VSCode, which I can also install on <code>github.dev</code>. So now I just open my site&#x27;s GitHub repo page, press <code>.</code> and boom, I&#x27;m in VSCode in seconds.</p>
<p>From there, I can just create a new <code>.mdx</code> file, edit it, and commit the changes straight from my browser. Committing my changes immediately triggers a new release. Netlify builds my site, <a href="/posts/the-og">generates a new open graph image</a> for my post, and we&#x27;re done!</p>
<p>From now on, I&#x27;ll be publishing blog posts from my browser using <a href="https://github.dev">github.dev</a>. Pretty neat.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[New Profile Picture]]></title>
        <id>https://krismuniz.com/posts/new-profile-picture</id>
        <link href="https://krismuniz.com/posts/new-profile-picture"/>
        <updated>2021-06-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I finally changed my profile picture. It was time.]]></summary>
        <content type="html"><![CDATA[<p>I&#x27;ve been using the <a href="/archive/headshot-2016.png">same old profile</a> picture since 2016. I can&#x27;t even remember when I took it or how, but I remember it coincided with me traveling to Austin to begin working at Claimbot.</p>
<p>Needless to say, I no longer look like myself 5 years ago. I&#x27;ve put on a few pounds and my beard is a mess these days.</p>
<p>I don&#x27;t take many pictures of myself, at least not many that I would use as my avatar. But I joined a new job last fall with a bunch of people who I haven&#x27;t met in person so I figured that the honest thing to do would be to change it. You know, to put a face to my name.</p>
<p>I took it with my webcam, because why would I take it with my very good iPhone camera when I can take it with a terrible potato camera instead. It&#x27;s good enough, though. And it&#x27;s more honest, I look friendlier (I think), and I&#x27;m wearing my favorite hoodie.</p>
<div style="display:flex;justify-content:center;width:100%;padding:2rem;box-sizing:border-box"><img src="/archive/headshot-2020.png" width="64" height="64"/></div>
<p>I&#x27;ve been using it exclusively as my internal headshot at Airkit since I joined, but I think I&#x27;m finally ready to let go of my old one and update every social media profile I have.</p>
<p>Here is to the next 5 years.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Clever Ideas]]></title>
        <id>https://krismuniz.com/posts/clever-ideas</id>
        <link href="https://krismuniz.com/posts/clever-ideas"/>
        <updated>2021-06-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Short ramblings about pursuing interesting ideas.]]></summary>
        <content type="html"><![CDATA[<p>Every once in a while I am faced with a challenge that sparks my curiosity more than others. I become obsessed with it. I think about it every day. I drink it with my morning coffee, breathe it when I go outside, and I sleep on it at the end of the night with the promise that I will pick it back up the next morning.</p>
<p>I&#x27;m ashamed to admit that more often than not, I&#x27;m trying to find an elegant, yet grandiose solution that will change <em>everything</em>. An explanation so concise that it can be expressed with a simple sentence. An approach so fantastic that I <em>have</em> to share with everyone.</p>
<p>The problem with this kind of idea is that they are usually vague, immature, and almost always rooted in fantasy. You couldn&#x27;t pierce such an idea with an invisible needle, because it would evaporate right before your eyes.</p>
<p>But these ideas keep me alive, they provide me with enough incentive to keep me engaged. They take fascinating shapes and make interesting noises. They are invisible but always feel like I am three diagrams and two essays away from making them concrete.</p>
<p>At the beginning, I find myself lost in thought in the middle of my day <em>fantasizing</em> about the dream solution. But as time progresses, the problem becomes more concrete and the novelty of the idea slowly fizzles out. At the end of it I&#x27;m left with the final product. Not groundbreaking as I imagined it, but pretty solid.</p>
<p>For me, clever ideas are not the vehicle, they are the fuel.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Now with Dynamic Open Graph Images]]></title>
        <id>https://krismuniz.com/posts/the-og</id>
        <link href="https://krismuniz.com/posts/the-og"/>
        <updated>2021-06-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I added dynamically-generated Open Graph images to my posts. Because I can now!]]></summary>
        <content type="html"><![CDATA[<p>Inspired by GitHub&#x27;s pretty sweet <a href="https://github.blog/2021-06-22-framework-building-open-graph-images/">post about their Open Graph images framework</a>, I decided to try to build something similar for my site (at a smaller scale, obviously!). I wanted to build this for my blog ever since I saw the folks at <a href="https://github.com/vercel/og-image">Vercel</a> do it.</p>
<p>I used <a href="https://pptr.dev/">Puppeteer</a> to take a screenshot of a very simple HTML template, hooked it into my website&#x27;s deployment pipeline, and voilà: dynamic OG images!</p>
<p><img src="/og/the-og.jpeg" alt="Dynamically-generated image shows the title of this post, &quot;Now With Dynamic Open Graph Images&quot; in large bold font. Above the title is the date when it was published, Thursday, June 24th, 2021"/></p>
<p>There&#x27;s still some tweaks I wanna make to the template to make it nicer, but it&#x27;s looking clean!</p>
<p>I wrote generator code that gets executed as part of my <code>next export</code> process, this is the full script:</p>
<pre class="language-typescript"><code class="language-typescript"><span class="token keyword module">import</span> <span class="token imports">chromium</span> <span class="token keyword module">from</span> <span class="token string">&quot;chrome-aws-lambda&quot;</span><span class="token punctuation">;</span>
<span class="token keyword module">import</span> <span class="token imports">format</span> <span class="token keyword module">from</span> <span class="token string">&quot;date-fns/format&quot;</span><span class="token punctuation">;</span>
<span class="token keyword module">import</span> <span class="token imports">fs</span> <span class="token keyword module">from</span> <span class="token string">&quot;fs&quot;</span><span class="token punctuation">;</span>
<span class="token keyword module">import</span> <span class="token imports">path</span> <span class="token keyword module">from</span> <span class="token string">&quot;path&quot;</span><span class="token punctuation">;</span>
<span class="token keyword module">import</span> <span class="token imports">posts</span> <span class="token keyword module">from</span> <span class="token string">&quot;./posts&quot;</span><span class="token punctuation">;</span>

<span class="token keyword module">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">generate</span><span class="token punctuation">(</span><span class="token punctuation">{</span> outDir <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> browser <span class="token operator">=</span> <span class="token keyword control-flow">await</span> chromium<span class="token punctuation">.</span><span class="token property-access">puppeteer</span><span class="token punctuation">.</span><span class="token method function property-access">launch</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    args<span class="token operator">:</span> chromium<span class="token punctuation">.</span><span class="token property-access">args</span><span class="token punctuation">,</span>
    executablePath<span class="token operator">:</span> <span class="token keyword control-flow">await</span> chromium<span class="token punctuation">.</span><span class="token property-access">executablePath</span><span class="token punctuation">,</span>
    headless<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword control-flow">await</span> browser<span class="token punctuation">.</span><span class="token method function property-access">newPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Open the HTML template as a data URI</span>
  <span class="token keyword control-flow">await</span> page<span class="token punctuation">.</span><span class="token method function property-access">goto</span><span class="token punctuation">(</span>
    <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">data:text/html;charset=UTF-8,</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span><span class="token constant">TEMPLATE</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> waitUntil<span class="token operator">:</span> <span class="token string">&quot;networkidle0&quot;</span> <span class="token punctuation">}</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Wait until the document is fully rendered</span>
  <span class="token keyword control-flow">await</span> page<span class="token punctuation">.</span><span class="token method function property-access">evaluateHandle</span><span class="token punctuation">(</span><span class="token string">&quot;document.fonts.ready&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// Set the viewport size to match</span>
  <span class="token keyword control-flow">await</span> page<span class="token punctuation">.</span><span class="token method function property-access">setViewport</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    width<span class="token operator">:</span> <span class="token number">1200</span><span class="token punctuation">,</span>
    height<span class="token operator">:</span> <span class="token number">632</span><span class="token punctuation">,</span>
    <span class="token comment">// Netlify build machines do not have a</span>
    <span class="token comment">// retina display, apparently xD</span>
    deviceScaleFactor<span class="token operator">:</span> process<span class="token punctuation">.</span><span class="token property-access">env</span><span class="token punctuation">.</span><span class="token constant">NETLIFY</span> <span class="token operator">?</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> ogImagesDir <span class="token operator">=</span> path<span class="token punctuation">.</span><span class="token method function property-access">resolve</span><span class="token punctuation">(</span>outDir<span class="token punctuation">,</span> <span class="token constant">OG_IMAGES_PATH</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// iterate over each post</span>
  <span class="token keyword control-flow">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> post <span class="token keyword">of</span> posts<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> info <span class="token operator">=</span> <span class="token punctuation">{</span>
      title<span class="token operator">:</span> post<span class="token punctuation">.</span><span class="token property-access">title</span><span class="token punctuation">,</span>
      date<span class="token operator">:</span> <span class="token function">format</span><span class="token punctuation">(</span>post<span class="token punctuation">.</span><span class="token property-access">date</span><span class="token punctuation">,</span> <span class="token string">&quot;dddd, MMMM Do, YYYY&quot;</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">;</span>

    <span class="token keyword control-flow">await</span> page<span class="token punctuation">.</span><span class="token method function property-access">evaluate</span><span class="token punctuation">(</span><span class="token punctuation">(</span>info<span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> titleElement <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;#title&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">const</span> dateElement <span class="token operator">=</span> <span class="token dom variable">document</span><span class="token punctuation">.</span><span class="token method function property-access">querySelector</span><span class="token punctuation">(</span><span class="token string">&quot;#date&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      titleElement<span class="token punctuation">.</span><span class="token property-access">innerHTML</span> <span class="token operator">=</span> info<span class="token punctuation">.</span><span class="token property-access">title</span><span class="token punctuation">;</span>
      dateElement<span class="token punctuation">.</span><span class="token property-access">innerHTML</span> <span class="token operator">=</span> info<span class="token punctuation">.</span><span class="token property-access">date</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> info<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword control-flow">await</span> page<span class="token punctuation">.</span><span class="token method function property-access">screenshot</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      path<span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>ogImagesDir<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>post<span class="token punctuation">.</span><span class="token property-access">id</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.png</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
      type<span class="token operator">:</span> <span class="token string">&quot;png&quot;</span><span class="token punctuation">,</span>
      clip<span class="token operator">:</span> <span class="token punctuation">{</span> x<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> y<span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> width<span class="token operator">:</span> <span class="token number">1200</span><span class="token punctuation">,</span> height<span class="token operator">:</span> <span class="token number">632</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// Wrap it up</span>
  <span class="token keyword control-flow">await</span> browser<span class="token punctuation">.</span><span class="token method function property-access">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This code heavily inspired by <a href="https://github.com/vercel/og-image">vercel/og-image</a>&#x27;s code.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Outlook Desktop Switching to a Web App]]></title>
        <id>https://krismuniz.com/posts/outlook-web-app</id>
        <link href="https://krismuniz.com/posts/outlook-web-app"/>
        <updated>2021-01-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[It looks like Microsoft is working to replace native Outlook desktop clients with "web apps". This most likely means they'll be using Electron or something similar.]]></summary>
        <content type="html"><![CDATA[<p>From the <a href="https://www.windowscentral.com/project-monarch-outlook-web-universal-email-client-microsoft">Windows Central article</a>:</p>
<blockquote>
<p>Microsoft is building a universal Outlook client for Windows and Mac that will also replace the default Mail &amp; Calendar apps on Windows 10 when ready. [...] The project will deliver Outlook as a single product, with the same user experience and codebase whether that be on Windows or Mac.</p>
</blockquote>
<p>This most definitely means they&#x27;re going to be using something like <a href="https://electronjs.com">Electron</a>.</p>
<p>And who could blame them? For a software product that is expected to run everywhere, having only one desktop client codebase just makes sense.</p>
<p>Shipping features frequently and consistently across platforms is a really complex problem that takes a remarkable level of coordination and engineering discipline. Not everybody can pull it off, and even those who do, still have to deal with big tradeoffs.</p>
<p>For a market as competitive as email, having cross-platform desktop applications that work consistently for every platform can be a huge differentiator. For enterprise customers, this might even be <em>expected</em> of your product (see how many platforms <a href="https://slack.com/help/articles/115002037526-Minimum-requirements-for-using-Slack">Slack</a> supports).</p>
<p>People often criticize when a big company switches their native clients to Electron, and with good reason. Since the framework bundles apps with its own instance of <a href="https://www.chromium.org/Home">Chromium</a>, Electron apps are usually bloated, glitchy, and resource intensive.</p>
<p>But <em>even so</em>, Electron&#x27;s value proposition is too attractive.</p>
<p>This wouldn&#x27;t be the first time Microsoft moves a fully native app to Electron, and it certainly won&#x27;t be the last. They did it with Skype, and were quite successful at it.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Twenty Twenty Update]]></title>
        <id>https://krismuniz.com/posts/twenty-twenty</id>
        <link href="https://krismuniz.com/posts/twenty-twenty"/>
        <updated>2021-01-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I moved to San Jose, Claimbot was acquired by Mobile Tech Rx, and I am now a Full Stack Engineer at Airkit.]]></summary>
        <content type="html"><![CDATA[<p>Wow, what <a href="https://en.wikipedia.org/wiki/2020">a mess of a year</a>! And 2021 doesn&#x27;t promise much either. In fact, I wouldn&#x27;t be surprised if this whole decade turned out pretty bleak.</p>
<p>Last year, lots of things changed for me (as it did for many of us). This post is for those changes I do want to share.</p>
<h2 id="i-moved"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#i-moved"><span># </span></a>I Moved</h2>
<p>Small move. I moved from Oakland to San Jose. The weather is even nicer, rent is cheaper, etc. No particular reason why I moved from Oakland other than <em>it didn&#x27;t make sense for me to live up there</em>.</p>
<h2 id="claimbot-was-acquired"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#claimbot-was-acquired"><span># </span></a>Claimbot Was Acquired</h2>
<p>In a remarkable turn of events, last fall, Claimbot&#x27;s virtual chat engine was <a href="https://www.mobiletechrx.com/resources/mobile-tech-rx-acquires-claimbot/">acquired by Mobile Tech Rx</a>! This also means that I&#x27;m no longer working at Claimbot.</p>
<p>Closing this chapter of my life was a bitter-sweet moment. I feel very lucky for having the opportunity to build a great product alongside very talented teammates. I&#x27;ll miss it dearly.</p>
<p>I am happy that all the work that we&#x27;ve put on the platform for the past four years will live on and be useful in different ways for the very talented folks at Mobile Tech Rx. Our work is in good hands, and I can&#x27;t wait to see what they build on top of it.</p>
<p>Having worked on Claimbot is an experience I&#x27;ll cherish for the rest of my career. I have grown exponentially as a professional and as a person, and I owe much of it to my co-founder, partner, and mentor, <a href="https://twitter.com/fernandezcw">Miguel Fernandez</a>, who started and gracefully lead this whole endeavor.</p>
<p>Gracias, broder.</p>
<h2 id="i-got-a-new-job"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#i-got-a-new-job"><span># </span></a>I Got a New Job</h2>
<p>Finally, as a direct – yet somehow also parallel – consequence of Claimbot&#x27;s news, I started working at a new company, <a href="https://airkit.com">Airkit</a>. In fact, most of my teammates from Claimbot are now working at Airkit too!</p>
<p>Airkit is a platform that empowers teams to build customer experiences without having to write a lot of code.</p>
<p>I&#x27;ll be working as a Full Stack Engineer on Airkit&#x27;s core platform. Particularly with the Developer Experience team, which mainly focuses on the Studio portion of Airkit, the interactive tool that companies use to build these low-code customer experiences!</p>
<p>There are lots of places where Airkit and Claimbot intersect, from go-to-market strategies and target industries, to tech stack and architecture design. Customer experience automation, configurable software, and full stack JavaScript is proving to be a career theme for me, which is awesome too!</p>
<p>I have worked at Airkit for the past ~3 months. So far, my experience has been delightful. Airkit is a great company, with a great team and product, and lots of potential. I&#x27;ve learned a lot so far and I&#x27;m excited to see what I&#x27;ll learn next!</p>
<p>Also, <a href="https://www.airkit.com/careers">we&#x27;re hiring</a>!</p>
<h2 id="onwards"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#onwards"><span># </span></a>Onwards</h2>
<p>Anyways!</p>
<p>As I said earlier, 2020 was objectively bad for the world and my expectations for 2021 are not that high either. However, on a personal level, I am thankful for all the good things that did happen last year and I&#x27;m looking forward for the good parts of this one.</p>
<p>Take care, everyone.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Lots of Zoom, Little Focus]]></title>
        <id>https://krismuniz.com/posts/zoom-zoom-zoom</id>
        <link href="https://krismuniz.com/posts/zoom-zoom-zoom"/>
        <updated>2020-04-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Zoom announced a 90-day feature freeze to "address" privacy and security concerns. Probably too little, but maybe not too late.]]></summary>
        <content type="html"><![CDATA[<p>Zoom has screwed up <a href="https://9to5mac.com/2019/07/09/zoom-vulnerability-mac/">time</a> and <a href="https://arstechnica.com/information-technology/2020/04/unpatched-zoom-bug-lets-attackers-steal-windows-credentials-with-no-warning/">time</a> <a href="https://www.wired.com/story/zoom-security-encryption/">again</a>. It has screwed up <a href="https://www.washingtonpost.com/technology/2020/04/03/thousands-zoom-video-calls-left-exposed-open-web/">so many</a> times that the tech community is having trouble agreeing on whether these screw-ups were innocent incompetence or <a href="https://www.theguardian.com/technology/2020/apr/02/zoom-technology-security-coronavirus-video-conferencing">malicious behavior</a>.</p>
<p>Eric Yuan (Zoom&#x27;s CEO) published what looks like an apology reacting to the criticism they&#x27;ve been receiving lately and acknowledging most of Zoom&#x27;s mistakes. In the <a href="https://blog.zoom.us/wordpress/2020/04/01/a-message-to-our-users/">post</a>, he announced that Zoom will be stopping the development of any new features to focus on addressing current security and privacy concerns.</p>
<p>I found this post reassuring and sincere. Large companies rarely — if ever — admit that many mistakes in a single post. It gave me hope that they are trying to make a secure and private product — even if their incentive to do so comes from the market, and after the fact, rather than their proactive willingness to build a quality product. Today, market pressure seems to be the only way to hold corporations accountable.</p>
<p>The thing is, Zoom knows better than any of us what are the internal forces that are causing all these issues. They seem to be cutting corners that a lot of startups usually cut, but they are doing it at an unforgivable scale. Zoom has become too popular, too important to ignore these mistakes, and serious customers are starting to lose trust in the platform.</p>
<p>In Eric&#x27;s post, he also mentioned that they set themselves a <a href="https://blog.zoom.us/wordpress/2020/04/01/a-message-to-our-users/">90-day deadline</a> to figure it out. With the global demand for video conferencing software skyrocketing to unprecedented levels due to the global COVID-19 pandemic, Zoom needs more than ever to focus on two main things: anticipating scale and sacrificing user experience, all in favor of security and privacy.</p>
<h3 id="anticipating-scale"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#anticipating-scale"><span># </span></a>Anticipating Scale</h3>
<p>We all know that the scale they are dealing with is unprecedented. In the month of March 2020, Zoom was handling around 200 million meeting participants <em>a day</em>.</p>
<p>During a global pandemic that made most businesses and schools — at least those who can — switch to video conferencing as their main method of communication, their video conferencing product still works really well.</p>
<p>It would simply not be fair to say that Zoom has not handled scale correctly. Even before the global COVID-19 pandemic, their video conferencing software was among the most reliable consumer-grade video communication platforms out there.</p>
<p>That said, there are also catastrophically incorrect ways to handle scale that are not necessarily linked to audio/video performance, like <a href="https://research.checkpoint.com/2020/zoom-zoom-we-are-watching-you/">generating guessable meeting IDs</a>, or not enabling meeting passwords by default.</p>
<p>You&#x27;ve probably read of the consequences of these design decisions. Hundreds of stories of <a href="https://www.washingtonpost.com/technology/2020/04/02/everybody-seems-be-using-zoom-its-security-flaws-could-leave-people-risk/">&quot;Zoom-bombings&quot;</a>, a type of prank that consists of an unknown party joining a meeting they do not belong to and saying or presenting something obscene or disturbing to the participants of the call in an act of crude vandalism.</p>
<p>There have been multiple attacks of this nature in <a href="https://www.washingtonpost.com/education/2020/03/31/fbi-issues-warning-about-hijacking-online-classes-by-intruders-after-schools-report-serious-disruptions/">virtual classrooms</a> and remote <a href="https://twitter.com/ceri_weber/status/1243907605854068736">thesis defenses</a>, which led the <a href="https://www.fbi.gov/contact-us/field-offices/boston/news/press-releases/fbi-warns-of-teleconferencing-and-online-classroom-hijacking-during-covid-19-pandemic">FBI to issue a warning</a> about this new fenomenon.</p>
<p>Thankfully, this issue is easily fixed by manually password-protecting your Zoom meetings, but they could&#x27;ve made Zoom-bombing harder from the beginning. They could have enabled password protection by default on all meetings or at least used longer, harder-to-guess, alphanumeric keys as meeting IDs. At the very least they could have hired a security firm to audit their security and privacy practices; any internal team that was proactively looking for a vulnerability would have found this one.</p>
<p>Whether they anticipated this problem at scale or not, this kind of behavior was inevitable and Zoom should&#x27;ve made these decisions months or maybe years ago. When it comes to security and privacy, you should be able to anticipate scale, especially when designing something as crucial, yet easily-avoidable, as unique IDs.</p>
<h3 id="stop-obsessing-with-reducing-friction"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#stop-obsessing-with-reducing-friction"><span># </span></a>Stop Obsessing with Reducing Friction</h3>
<p>Not so long ago, a security researcher <a href="https://medium.com/bugbountywriteup/zoom-zero-day-4-million-webcams-maybe-an-rce-just-get-them-to-visit-your-website-ac75c83f4ef5">found a security flaw</a> that allowed any website to start a Zoom meeting without any interaction — or request for consent — from the user. It took advantage of a Zoom &quot;feature&quot; that exposed a local, ever-running web server that enabled the native Zoom client to open a Zoom window on demand. All of this to save Zoom users a single click.</p>
<p>I get it. The state of video conferencing these days is confusing and complicated; every click matters. There are many operating systems and platforms to support, hundreds of services to integrate with, millions of businesses to connect, and many more millions of people with different setups trying to figure out how to enter these damn meetings.</p>
<p>Services like Microsoft Teams or Slack require you to have a common communication platform with your co-participants (i.e. they must all be on Slack or Microsoft Teams) — which usually isn&#x27;t the case. Services like Skype require you to have a Microsoft account. And services that allow you to dial into a video conferencing meeting without signing-in or having a common platform sign-in could be rare, expensive, and/or unreliable — in some cases all three.</p>
<p>There is a <em>need</em> for affordable, easy-to-use, and reliable video conferencing software and that&#x27;s what Zoom&#x27;s competitive advantage is all about.</p>
<p>But practicality and ease of use usually comes at a great cost: security and privacy. Skipping passwords, settling for easy-to-spell meeting IDs, and even saving a single click could mean sacrificing our natural expectations of privacy and security.</p>
<p>Zoom needs to start adding more security controls in place, by default, even if it meant sacrificing the user experience by adding a little friction. This aggresiveness against user friction is no longer helping build Zoom&#x27;s case, it&#x27;s deteriorating their reputation.</p>
<p>At this point Zoom clearly has all the demand it needs to be successful for a while, so it&#x27;s absurd to believe that a couple clicks will sacrifice any significant part of your sales. And even if it did, they wouldn&#x27;t compare to the business they are missing right now because of their... <a href="https://techcrunch.com/2020/04/01/zoom-doom/">insecure</a> or at the very least <a href="https://twitter.com/zachwaugh/status/1246092063160049665">suspicious</a> practices.</p>
<h3 id="wrapping-up"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#wrapping-up"><span># </span></a>Wrapping Up</h3>
<p>I know that everything is clear in hindsight. It&#x27;s super easy for me to sit here and point <a href="https://www.google.com/search?q=%22zoom%22+(%22flaw%22+OR+%22vulnerability%22+OR+%22issue%22+OR+%22bug%22)">all the flaws that Zoom has</a>, but I believe that they could&#x27;ve done better. Zoom is an excellent product, with high demand right now, that also performs really well. If they fix all this mess, they have the opportunity to position themselves among the best consumer video-conferencing products out there.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Apple Acquires Dark Sky Weather App]]></title>
        <id>https://krismuniz.com/posts/apple-acquires-dark-sky</id>
        <link href="https://krismuniz.com/posts/apple-acquires-dark-sky"/>
        <updated>2020-03-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Apple acquired Dark Sky, is shutting down the Android app and sunsetting their API. Yikes.]]></summary>
        <content type="html"><![CDATA[<p>From Dark Sky&#x27;s Blog – <a href="https://blog.darksky.net/dark-sky-has-a-new-home/"><em>Dark Sky Has a New Home</em></a>:</p>
<blockquote>
<p>Today we have some important and exciting news to share: Dark Sky has joined Apple.</p>
<p>Our goal has always been to provide the world with the best weather information possible, to help as many people as we can stay dry and safe, and to do so in a way that respects your privacy.</p>
<p>There is no better place to accomplish these goals than at Apple. We’re thrilled to have the opportunity to reach far more people, with far more impact, than we ever could alone.</p>
</blockquote>
<p>There&#x27;s no need to speculate on why this is a sound acquisition for Apple. They will always need to improve their weather capabilities on their operating systems and Dark Sky is a premium product that is precise and offers reliable forecasts. It checks out.</p>
<blockquote>
<p>The [Android] app will no longer be available for download. Service to existing users and subscribers will continue until July 1, 2020, at which point the app will be shut down. Subscribers who are still active at that time will receive a refund.</p>
</blockquote>
<p>Yikes. It makes sense that they are doing this, but it&#x27;s a huge stab in the back for their long-time Android customers.</p>
<p>The optics are not great for small tech businesses / startups in general. As customers, what guarantees do we have that the products we rely on won&#x27;t be acquired and immediately shut down by Google, Amazon, Microsoft, or Apple?</p>
<p>Even small, profitable, award-winning products like Dark Sky are not immune to the ever-expanding reach of The Tech Giants.</p>
<blockquote>
<p>Our API service for existing customers is not changing today, but we will no longer accept new signups. The API will continue to function through the end of 2021.</p>
</blockquote>
<p>Speaking of reliability, what about all those businesses that rely on the Dark Sky API? What are they gonna do? They now have a couple months to figure it out.</p>
<p>There is a glimmer of hope, though. Although it&#x27;s clear that Apple is not particularly interested in Dark Sky&#x27;s API business, seeing recent <a href="https://developer.apple.com/maps/">Apple Maps API</a> developments leads me to believe that they could build their own branded version of Dark Sky&#x27;s weather API – an <em>Apple Weather API</em>. Same as with their Maps API, they could offer it at competitive prices with first-class support for their operating systems and the web.</p>
<p>I hope this is what they&#x27;re gonna do with it.</p>
<p>The thing I&#x27;m curious about is whether this means that Siri will finally warn me if it&#x27;s gonna rain in 7 minutes before I walk my dog.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Casual Open Source Contributions]]></title>
        <id>https://krismuniz.com/posts/casual-open-source</id>
        <link href="https://krismuniz.com/posts/casual-open-source"/>
        <updated>2019-03-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[How to contribute to open source projects when you don't have much free time on your hands.]]></summary>
        <content type="html"><![CDATA[<p>I am not a regular open source contributor. I have contributed to many projects and I maintain a couple of them, but it&#x27;s never been a consistent activity for me.</p>
<p>Sometimes I spend several weeknights or entire weekends contributing to open source. And sometimes months go by and I don&#x27;t contribute to any project. It all depends on my availability, interest, and energy. And it&#x27;s all okay.</p>
<p>You don&#x27;t have to give all your free time away to be a useful part of an open source community. You don&#x27;t even need a regular contribution schedule. In fact, it&#x27;s common to see developers who have only made a couple contributions in a project&#x27;s lifetime, and their contributions are still valuable!</p>
<p>If you&#x27;ve been thinking about contributing to open source, but you are not sure if you want to do it regularly, this post is for you. This is a simple guide on how to contribute to open source when you don&#x27;t have much free time on your hands or simply don&#x27;t want a long term commitment.</p>
<h2 id="finding-projects--problems-to-solve"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#finding-projects--problems-to-solve"><span># </span></a>Finding Projects &amp; Problems to Solve</h2>
<p>Finding a project to contribute to can be time-consuming and exhausting. If you don&#x27;t have a specific system, you&#x27;ll end up asking yourself questions ranging from, <em>&quot;Am I in a position to contribute to this project?&quot;</em> to <em>&quot;Is this a meaningful project?&quot;</em>, and it can become complicated!</p>
<p>What project should you contribute to? And even after you find the perfect project: which problem should you solve?</p>
<p>I&#x27;ve found three approaches to finding the right problem in the right project.</p>
<h3 id="the-active-approach"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#the-active-approach"><span># </span></a>The <strong><em>Active</em></strong> Approach</h3>
<p>The simplest way to start is to take a look at open source software you are already using and actively look for things you can help with. It can be an app you use daily, a dependency for one of your hobby projects or a build tool you use regularly.</p>
<p>Think about your favorite open source project, open the project&#x27;s page (GitHub, GitLab, BitBucket, etc.), and try to find out what&#x27;s the best contribution you can make! Keep in mind that it doesn&#x27;t have to be a code-related contribution, there are many ways to <a href="#how-to-contribute">contribute</a>!</p>
<h3 id="the-passive-approach"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#the-passive-approach"><span># </span></a>The <strong><em>Passive</em></strong> Approach</h3>
<p>Wait for the problem to come to you. I believe that most casual open source developers prefer this method. Report problems, fix issues or propose features that affect you directly.</p>
<ul>
<li>Is your build step failing because of one bug in an open source project you depend on?</li>
<li>Is there something missing in a project&#x27;s documentation?</li>
<li>Is there a feature you would like to see in your favorite open source app?</li>
</ul>
<p>As long as the problem is not too big, these are good reasons to <a href="#how-to-contribute">contribute</a>.</p>
<p>The best part of this approach is that you have a personal incentive towards solving a particular problem, making it a highly-rewarding activity.</p>
<p>The only downside is that this type of contributions are spontaneous by nature and don&#x27;t happen very often, which is troubling if your responsibilities don&#x27;t allow you to find the perfect time to solve the problem.</p>
<h3 id="the-vigilante-approach"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#the-vigilante-approach"><span># </span></a>The <strong><em>Vigilante</em></strong> Approach</h3>
<p>The final one is a variant of the Active approach. It consists of using apps, dashboards or feeds to <del>stalk</del> watch your favorite organizations, developers, and projects. See what problems they are facing, and when the opportunity arises, <a href="#how-to-contribute">contribute</a>!</p>
<p>In my case, I use <a href="https://devhubapp.com">DevHub</a> (basically <a href="https://tweetdeck.com">TweetDeck</a> for <a href="https://github.com">GitHub</a>). DevHub provides a horizontal dashboard with feeds from my favorite OSS organizations, developers, and/or projects. I usually watch out for issues that I can reproduce, bugs I can fix or docs I can write.</p>
<p><img src="https://i.imgur.com/XEIuVDD.jpg" alt="My DevHub Dashboard, displaying a list of issues and comments from my favorite developers, projects, and organizations on GitHub" title="My DevHub Dashboard"/></p>
<p>This is my favorite way of finding open source projects to contribute to and problems to solve, because it&#x27;s on-demand, rewarding, and easy to squeeze into my schedule from time to time.</p>
<p>Whenever I feel like dedicating some time to open source (i.e. an uneventful Sunday evening), I check my dashboard and see if there&#x27;s any small problem I can help with. It&#x27;s not guaranteed to work, but it frequently does.</p>
<h2 id="how-to-contribute"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#how-to-contribute"><span># </span></a>How to Contribute</h2>
<p>There are multiple ways to contribute to an open source project, but generally speaking you should focus on discrete problems rather than recurrent tasks such as maintenance or content moderation. Those tasks are much better suited for regular contributors and maintainers.</p>
<h3 id="code-contributions"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#code-contributions"><span># </span></a>Code Contributions</h3>
<ul>
<li><strong>Bug Reports</strong> – open new issues, file bug reports, reproduce issues</li>
<li><strong>Feature Requests</strong> – request new features, propose solutions, draft proposals or <a href="https://en.wikipedia.org/wiki/Request_for_Comments">RFCs</a></li>
<li><strong>Bug Fixes</strong> – fix known issues, patch minor bugs, solve performance issues</li>
<li><strong>Security</strong> – search for vulnerabilities, patch them, update dependencies</li>
<li><strong>Features</strong> – add requested features, enhance existing features</li>
<li><strong>Automated Testing</strong> – write tests, integrate with CI/CD, refactor tests</li>
<li><strong>Accessibility</strong> – fix accessibility issues, provide accessibility feedback, point to useful resources</li>
</ul>
<h3 id="non-code-contributions"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#non-code-contributions"><span># </span></a>Non-Code Contributions</h3>
<ul>
<li><strong>Manual Testing / QA</strong> – test usability, solve non-trivial testing issues, develop automation strategies</li>
<li><strong>Documentation</strong> – document features, write how-to guides/tutorials, write examples, write translations</li>
<li><strong>Mentoring &amp; Support</strong> – help in community forums or chat channels occasionally, provide learning resources, participate in community discussions</li>
<li><strong>Design</strong> – make logos/graphical assets, propose branding strategies, provide constructive design feedback</li>
<li><strong>Outreach</strong> – promote a project, write instuctional articles, showcase a projects&#x27; usage</li>
</ul>
<h3 id="financial-contributions"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#financial-contributions"><span># </span></a>Financial Contributions</h3>
<ul>
<li><strong>Project Donations</strong> – donate thorugh open source funding programs such as <a href="https://opencollective.com">Open Collective</a></li>
<li><strong>Developer Funding</strong> – sponsor individual developers through subscription-based platforms such as <a href="https://patreon.com">Patreon</a></li>
</ul>
<p>Learn more on how to contribute to open source <a href="https://opensource.guide/how-to-contribute/">here</a>.</p>
<h2 id="choosing-tasks--problems-to-solve"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#choosing-tasks--problems-to-solve"><span># </span></a>Choosing Tasks &amp; Problems to Solve</h2>
<p>Contributions for any open source project can be split into two main categories: general contributions and specific contributions. As a casual open source contributor, the type of problems you tackle and the tasks you complete for a project should be determined by your knowledge, skills, availability, and interests.</p>
<h3 id="general-contributions"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#general-contributions"><span># </span></a>General Contributions</h3>
<p>This type of contribution focuses on tasks that are general in nature (i.e. they apply to many projects of the same kind) and require little to no domain-specific knowledge.</p>
<p>General contributions are suitable for you if you are familiarized with the project, but only at the surface level. This type of contribution is usually non-critical which means that your contribution will probably only <em>enhance</em> the project.</p>
<p>This is my favorite way of contributing to a project because contributions of this type are generally easy to solve, don&#x27;t require a big time investment, and aren&#x27;t domain-specific.</p>
<p>I also like that this type of contribution is usually non-controversial. It&#x27;s likely that your contribution will be welcome without much push-back or debate, which saves you some precious time.</p>
<p>Examples for general contributions include but are not limited to:</p>
<ul>
<li>Fixing simple code errors</li>
<li>Writing reference or usage documentation</li>
<li>Translating content/docs to other languages</li>
<li>Authoring usage guides (&quot;How to do [...]&quot;)</li>
<li>Updating dependencies that bring no breaking changes</li>
<li>Adding surface-level features</li>
<li>Comprehensive bug reports</li>
<li>Reproducing and documenting simple issues</li>
<li>Fixing typos and errors in documentation</li>
<li>Adding supporting resources</li>
<li>Translations, formatting tools, etc.</li>
</ul>
<h3 id="project-specific-contributions"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#project-specific-contributions"><span># </span></a>Project-Specific Contributions</h3>
<p>Project-specific contributions are focused on the core functionality of the project. This type of contribution is suitable for you if you have domain-specific knowledge that could be leveraged for solving project-specific problems.</p>
<p>This one is the trickiest, but in my opinion it&#x27;s also the most rewarding type of task you could find. The biggest downside is that it requires more skill and time. If you are familiar with a project&#x27;s inner-workings and structure, you might be able to do this from time to time.</p>
<p>It&#x27;s also important to note that this type of contribution also means that complex debates and brainstorming sessions might be necessary. It could take weeks or sometimes even months for your contribution to be accepted. If you are limited on time or are not willing to commit temporarily to solving a specific problem, this might not be the best type of contribution you could make.</p>
<p>Examples for specific contributions include but are not limited to:</p>
<ul>
<li>Fixing a critical bug that affects a specific group of users</li>
<li>Writing feature requests</li>
<li>Drafting proposals or <a href="https://en.wikipedia.org/wiki/Request_for_Comments">RFCs</a></li>
<li>Refactoring a major part of the project</li>
<li>Updating core dependencies that bring breaking changes</li>
<li>Adding support for a particular platform/integration</li>
<li>Reproducing and documenting complex issues</li>
</ul>
<h2 id="conclusion"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#conclusion"><span># </span></a>Conclusion</h2>
<p>I&#x27;ve been a casual open source contributor for ~6 years and as time passes, I dedicate more time to it. I do it with confidence because I know that if at any point in my life I need to take a break, I can do it without letting anyone down.</p>
<p>You don&#x27;t have to be a 10x developer or a full-time contributor to be a useful part of an open source community. There are ways to contribute to open source without dedicating your life to it or being exceptionally good at it.</p>
<p>If you know anyone who is thinking about contributing to open source share this article with them! If you have any other tips or hints on how to make casual open source contributions let me know (<a href="https://twitter.com/kristianmuniz">@KristianMuniz</a> on Twitter) and I&#x27;ll add them here!</p>
<h2 id="supporting-resources"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#supporting-resources"><span># </span></a>Supporting Resources</h2>
<p>Although this post is mainly subjective, the following resources served me as a source of inspiration and references for its development:</p>
<ul>
<li><a href="https://opensource.guide/">Open Source Guides</a></li>
<li><a href="https://opensource.com/article/17/10/managing-casual-contributors">How to manage casual contributors to open source projects</a></li>
</ul>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Welcome to My Blog]]></title>
        <id>https://krismuniz.com/posts/welcome</id>
        <link href="https://krismuniz.com/posts/welcome"/>
        <updated>2019-03-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A place for me to share my ideas, thoughts, and projects. Built with Next.js and hosted on Netlify.]]></summary>
        <content type="html"><![CDATA[<p>Hello there! Welcome to my blog, a place for me to share my thoughts, projects, and half-baked ideas.</p>
<h2 id="why-have-a-blog"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#why-have-a-blog"><span># </span></a>Why Have a Blog?</h2>
<p>I want to have a place to share longform writing without the restrictions of a publishing platform (like <a href="https://medium.com">Medium</a>) or the hassle of maintaining a self-hosted blogging platform like <a href="https://wordpress.org">WordPress</a> or <a href="https://ghost.org">Ghost</a>.</p>
<p>I want to have <em>full control</em> over the reading experience.</p>
<h2 id="features"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#features"><span># </span></a>Features</h2>
<p>Here is a general list of feature requirements that all iterations of my personal site must adhere to:</p>
<ul>
<li><strong>Security</strong> - Follow strict security practices, stay current, and adapt to our threat landscape to protect visitors.</li>
<li><strong>Privacy</strong> - Never track visitors and do not collect visitor data unless explicitly asking for permission to do so (e.g. newsletter signup forms, contact forms, preferences, etc.).</li>
<li><strong>Accessibility</strong> - Be accessible to as many visitors as possible and follow the latest <a href="https://en.wikipedia.org/wiki/Web_Content_Accessibility_Guidelines">Web Content Accessibility Guidelines (WCAG)</a> as well as other generally-accepted accessibility practices, normative or otherwise.</li>
<li><strong>Syndication</strong> - Provide alternative means of consuming site contents via <a href="https://en.wikipedia.org/wiki/Web_syndication">Web syndication</a>.</li>
<li><strong>Durability</strong> - To the extent that it is possible, the contents of this site should be built to be archiveable and last until the end of the Internet.</li>
<li><strong>Compatibility</strong> - Web Platform features used by this site must be supported by at least 90% of the global browser market share, even if its by means of a <a href="https://en.wikipedia.org/wiki/Polyfill_(programming)">Polyfill</a>. The site should work well without JavaScript enabled.</li>
</ul>
<h2 id="anyways"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#anyways"><span># </span></a>Anyways!</h2>
<p>Welcome to my blog! Make yourself at home, read some of my <a href="https://krismuniz.com/posts">posts</a>, learn more <a href="https://krismuniz.com/about">about me</a>, and subscribe to my <a href="https://krismuniz.com/feeds">feed</a>. You can also follow me on <a href="https://twitter.com/kristianmuniz">Twitter</a> or see my open source projects on <a href="https://github.com/krismuniz">GitHub</a>.</p>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[A Simpler New Tab Page]]></title>
        <id>https://krismuniz.com/posts/minimo</id>
        <link href="https://krismuniz.com/posts/minimo"/>
        <updated>2018-11-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Introducing my latest hobby project, Minimo. An elegant, simplified new tab page for your web browser.]]></summary>
        <content type="html"><![CDATA[<p>Almost every weekend for the past couple of months I&#x27;ve been working on a new hobby project: <a href="https://projects.krismuniz.com/minimo">Minimo</a> – an elegant, simplified new tab page for your web browser.</p>
<p>Minimo is a humble project with one objective: making the new tab page unobstrusive yet beautiful. It&#x27;s also a fully <a href="https://github.com/krismuniz/minimo">open source</a> project that anyone can contribute to!</p>
<p>As its name suggests, Minimo was designed to be simple, intuitive, and straightforward. There are no widgets, no complicated layouts, no account integrations, and no complicated settings pages. It&#x27;s just a new tab, with a couple shortcuts, and basic information at a glance. No distractions.</p>
<h3 id="features"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#features"><span># </span></a>Features</h3>
<p><img src="https://projects.krismuniz.com/minimo/screenshot.png" alt="Minimo Screenshot"/></p>
<p>Minimo provides a simple interface to access your favorite websites and have useful information at a glance. It displays the current date &amp; time, connection status, estimated download speed (in Mbps), battery level, and even synced tabs from other devices.</p>
<p>Thanks to the Bookmarks APIs provided by modern browsers, shortcuts are synced across devices and automatically backed-up in a <code>Shortcuts</code> folder on your bookmarks bar. If you export/import bookmarks from other platforms, it will work as expected. Your shortcuts will survive even if you switch browser vendors!</p>
<center><p><img src="https://media.giphy.com/media/5b1Rvw7SeFIcLRCQ1N/giphy.gif" alt="Animated GIF sowcasing Minimo&#x27;s writing mode"/></p></center>
<p>Minimo also has a simple, yet powerful, rich-text scratchpad called &quot;writing mode&quot; that allows you to jot down notes for later (stored locally). You can open &quot;writing mode&quot; from a configurable keyboard shortcut to have quick access to your notes.</p>
<h3 id="results"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#results"><span># </span></a>Results</h3>
<p>The development of Minimo is far from finished. There are still major things left in the <a href="https://github.com/krismuniz/minimo/projects">roadmap</a>. I&#x27;m definitely biased, but I consider Minimo the simplest new tab alternative that does not compromise user experience or aesthetics.</p>
<p>It feels good to be able to ship something so tangible. I hadn&#x27;t shipped a product like this in years, so it&#x27;s a rather refreshing experience. There&#x27;s lots to learn from this space, and I believe Minimo is in the right spot.</p>
<p>The extension is available on the <a href="https://chrome.google.com/webstore/detail/minimo/fanglmholkgdapjcfohfhnofcacjiodl">Chrome Webstore</a> and supports Brave and Chrome browsers. Support for more platforms (like Firefox) is coming soon!</p>
<p>Minimo was featured on <a href="https://producthunt.com/posts/minimo">Product Hunt</a> as <em>Product of the Day</em> on November 4, 2018. It has positive reviews both in Product Hunt and in the <a href="https://chrome.google.com/webstore/detail/minimo/fanglmholkgdapjcfohfhnofcacjiodl">Chrome Webstore</a>.</p>
<center><a href="https://www.producthunt.com/posts/minimo?utm_source=badge-top-post-badge" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=138439&amp;theme=light&amp;period=daily" alt="Minimo - An elegant, simplified new tab page | Product Hunt Embed" style="width:250px;height:54px;margin:1em" width="250px" height="54px"/></a><a href="https://www.producthunt.com/posts/minimo?utm_source=badge-featured" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=138439&amp;theme=light" alt="Minimo - An elegant, simplified new tab page | Product Hunt Embed" style="width:250px;height:54px;margin:1em" width="250px" height="54px"/></a></center>]]></content>
    </entry>
    <entry>
        <title type="html"><![CDATA[Conversational Graphs]]></title>
        <id>https://krismuniz.com/posts/conversational-graphs</id>
        <link href="https://krismuniz.com/posts/conversational-graphs"/>
        <updated>2017-06-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A theoretical solution for modeling complex conversational flows as directional graphs in JSON.]]></summary>
        <content type="html"><![CDATA[<blockquote>
<p><strong>Note:</strong> This is an archived post I recovered from my old blog.</p>
</blockquote>
<p>This design is a theoretical solution for modeling complex conversational flows as directional graphs. Conversational graphs will be expressed in JSON using <a href="https://github.com/jsongraph/json-graph-specification">JSON Graph Format spec</a> as a reference.</p>
<p>As a rule of thumb, conversational graph declarations should be serializable to JSON, portable, and contain <em>absolutely no code</em>. This reduces platform and language dependency and facilitates extendability.</p>
<h2 id="high-configurability"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#high-configurability"><span># </span></a>High Configurability</h2>
<p>In theory, directed graphs can be arranged to satisfy virtually any conversational flow. Even parallel processes such as performing asynchronous requests while other flows are happening may be possible.</p>
<p>Even if in practice not all configurations were possible, graphs will be able to describe most conversational flows. These flows will not be limited to trees and can be arranged in a natural, non-linear fashion.</p>
<h2 id="graphs-as-modular-components"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#graphs-as-modular-components"><span># </span></a>Graphs as Modular Components</h2>
<p>Each graph can be connected to other graphs via <a href="#abstract-nodes">abstract nodes</a> (<code>entry_node</code> and <code>exit_node</code>) that can lead to other flows. This facilitates portability, modularity, and composability.</p>
<p>Graphs will be arranged as atomic, specialized flows that will be part of a greater graph that connects them together through their entry and exit nodes.</p>
<p>The following graph could be a possible declaration for a simplified, modular flow that specializes in getting a user&#x27;s email:</p>
<p><img src="https://i.imgur.com/DAnUBQl.png" alt="image" title="Conversation graph for obtaining a user&#x27;s email"/></p>
<p>Note that not all graphs will have only one edge to exit. Any edge can flow to/from the exit/entry node; the flow could be adapted to exit on an <code>I don&#x27;t have an email</code> response, for example. Additional metadata could be passed through the exit edge to serve the entry node and edge of the following flow.</p>
<h2 id="definitions"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#definitions"><span># </span></a>Definitions</h2>
<h3 id="graphs"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#graphs"><span># </span></a>Graphs</h3>
<p>A graph describes the relations between <a href="#nodes">nodes</a> through <a href="#edges">edges</a>. In the context of this model, all graphs are directional and describe a conversational flow.</p>
<p>Example of a simplified <code>graph</code> JSON object:</p>
<pre class="language-json"><code class="language-JSON"><span class="token punctuation">{</span>
  <span class="token property">&quot;graph&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;example_graph&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;An example graph.&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;nodes&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;node_a&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;example_node&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Example of a simple node A&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;node_b&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;example_node&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Example of a simple node B&quot;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">&quot;edges&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;entry_edge&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;entry_node&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;node_a&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;example_edge&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;node_a&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;node_b&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;exit_edge&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;node_b&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;exit_node&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<h3 id="nodes"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#nodes"><span># </span></a>Nodes</h3>
<p>A <code>node</code> (or vertex) represents a discrete, atomic, single-purpose piece of a flow, fundamentally an <a href="#nodes-as-actions">action</a>.</p>
<p>Example of a simplified <code>node</code> JSON object:</p>
<pre class="language-json"><code class="language-JSON"><span class="token punctuation">{</span>
  <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask_email&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;What is your email address?&quot;</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The JSON object above describes an <code>ask</code> action. Note that the <code>node</code> object itself does not describe the next or previous steps. That&#x27;s what <a href="#edges">edges</a> are for.</p>
<h4 id="nodes-as-actions"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#nodes-as-actions"><span># </span></a>Nodes as Actions</h4>
<p>For example, nodes might be treated as discrete actions; conversational actions that can include but may not be limited to:</p>
<ul>
<li>
<p><code>ask</code> – ask a question expecting a response that is sent to the next node.</p>
</li>
<li>
<p><code>say</code> – send a message, expecting no response.</p>
</li>
<li>
<p><code>store</code> – store a message, status response may be sent to next node.</p>
</li>
</ul>
<p>Naturally, custom actions might be added to the model. Such as actions specialized on performing asynchronous tasks like http requests, for example.</p>
<h4 id="abstract-nodes"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#abstract-nodes"><span># </span></a>Abstract Nodes</h4>
<p>In order to achieve modularity in conversational graphs, specialized flows should make no assumptions on the rest of the flow. However, while this might be true, graphs aren&#x27;t designed to solve the modularity problem.</p>
<p>The proposed solution: abstract nodes.</p>
<p>Abstract nodes are nodes that serve as placeholders for the preceding or following nodes in a higher-order graph (a graph of graphs, so to speak).</p>
<p>There are two types of abstract nodes:</p>
<ul>
<li>
<p><code>entry_node</code> – the first node of any flow. An abstract reference (a placeholder) that represents the last node of the previous graph.</p>
</li>
<li>
<p><code>exit_node</code> – an abstract reference to a node that follows the last node in a graph.</p>
</li>
</ul>
<h3 id="edges"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#edges"><span># </span></a>Edges</h3>
<p>An <code>edge</code> (or link) represents a directional control and/or data flow. Each edge must have a source node and a destination node and only one of them may be an <a href="#abstract-nodes">abstract node</a>. Edges represent a data or control flow from a source node to a target node; every edge is directed, the whole graph is directed.</p>
<p>Example of a simplified <code>edge</code> JSON object:</p>
<pre class="language-json"><code class="language-JSON"><span class="token punctuation">{</span>
  <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;action&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;valid_email&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;store_email&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
<span class="token punctuation">}</span>
</code></pre>
<h4 id="edges-for-flow-control"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#edges-for-flow-control"><span># </span></a>Edges for Flow Control</h4>
<p>Edges might serve as a way to control which nodes to execute. An edge of type <code>control</code> might use assertion metadata to determine whether to move to a node or not.</p>
<p>Example of an edge as a flow control mechanism:</p>
<pre class="language-json"><code class="language-JSON"><span class="token punctuation">{</span>
  <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;control&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask_email&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;valid_email&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span><span class="token punctuation">,</span>
  <span class="token property">&quot;metadata&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">&quot;assertion&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token property">&quot;==&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">&quot;var&quot;</span><span class="token operator">:</span> <span class="token string">&quot;response.is_email&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>The edge above directs the flow from <code>ask_email</code> to <code>valid_email</code> only if <code>response.is_email</code> is <code>true</code>.</p>
<p>In this example <a href="http://jsonlogic.com/">JsonLogic</a> is used as an assertion mechanism, but other mechanisms (such as an NLP text-classification layer) could be employed to control the flow of a conversation.</p>
<h4 id="entry-and-exit-edges"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#entry-and-exit-edges"><span># </span></a>Entry and Exit Edges</h4>
<p>Entry and exit edges are in charge of connecting an <a href="#abstract-nodes">abstract node</a> to a regular node and transferring data to and from a graph.</p>
<h2 id="example-example-json-conversational-graph"><a tabindex="-1" aria-hidden="true" data-headlink="true" href="#example-example-json-conversational-graph"><span># </span></a>Example: Example JSON Conversational Graph</h2>
<p>If we wanted the following flow to happen:</p>
<pre><code>bot: What&#x27;s your email address?
user: My email is wrong-email.com
bot: What is your email address?
user: My email is bob@gmail.com
bot: Great! I will store your email now.
</code></pre>
<p>We would declare the flow in a JSON as follows:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
  <span class="token property">&quot;graph&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property">&quot;directed&quot;</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Ask for email flow.&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;nodes&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;What is your email address?&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;invalid_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;say&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;The email you provided is invalid.&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;valid_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;say&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;Great! I will store your email now.&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;id&quot;</span><span class="token operator">:</span> <span class="token string">&quot;store_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;store&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;label&quot;</span><span class="token operator">:</span> <span class="token string">&quot;* saves email in db *&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;metadata&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">&quot;take&quot;</span><span class="token operator">:</span> <span class="token string">&quot;response.text&quot;</span><span class="token punctuation">,</span>
          <span class="token property">&quot;save_as&quot;</span><span class="token operator">:</span> <span class="token string">&quot;user.email&quot;</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token property">&quot;edges&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;entry_edge&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;entry_node&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;control&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;valid_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;metadata&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">&quot;assertion&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">&quot;==&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">&quot;var&quot;</span><span class="token operator">:</span> <span class="token string">&quot;response.is_email&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">]</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;control&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;invalid_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;metadata&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
          <span class="token property">&quot;assertion&quot;</span><span class="token operator">:</span> <span class="token punctuation">{</span>
            <span class="token property">&quot;==&quot;</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">&quot;var&quot;</span><span class="token operator">:</span> <span class="token string">&quot;response.is_email&quot;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">]</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;action&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;valid_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;store_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;action&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;invalid_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;ask_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token punctuation">{</span>
        <span class="token property">&quot;type&quot;</span><span class="token operator">:</span> <span class="token string">&quot;exit_edge&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;source&quot;</span><span class="token operator">:</span> <span class="token string">&quot;store_email&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;target&quot;</span><span class="token operator">:</span> <span class="token string">&quot;exit_node&quot;</span><span class="token punctuation">,</span>
        <span class="token property">&quot;relation&quot;</span><span class="token operator">:</span> <span class="token string">&quot;flow&quot;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>This flow could be conceptually visualized as follows:</p>
<p><img src="https://i.imgur.com/DAnUBQl.png" alt="image" title="Conversation graph for obtaining a user&#x27;s email"/></p>]]></content>
    </entry>
</feed>