<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Salami dev blog]]></title><description><![CDATA[Salami is a runtime, and a little language, for safely and prudently running AI-generated code.


First prototype coming soon at: https://github.com/salamilang/salami]]></description><link>https://salamilang.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!IgJu!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facdb2e68-b61c-4080-92bd-dfb7fa1f261f_512x512.png</url><title>Salami dev blog</title><link>https://salamilang.substack.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 14 Sep 2026 04:57:28 GMT</lastBuildDate><atom:link href="https://salamilang.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Valentin Golev]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[salamilang@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[salamilang@substack.com]]></itunes:email><itunes:name><![CDATA[Valentin Golev]]></itunes:name></itunes:owner><itunes:author><![CDATA[Valentin Golev]]></itunes:author><googleplay:owner><![CDATA[salamilang@substack.com]]></googleplay:owner><googleplay:email><![CDATA[salamilang@substack.com]]></googleplay:email><googleplay:author><![CDATA[Valentin Golev]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The game of semantic promises (Or, why you are not using Siri)]]></title><description><![CDATA[Natural language interfaces must go all the way]]></description><link>https://salamilang.substack.com/p/the-game-of-semantic-promises-or</link><guid isPermaLink="false">https://salamilang.substack.com/p/the-game-of-semantic-promises-or</guid><dc:creator><![CDATA[Valentin Golev]]></dc:creator><pubDate>Tue, 09 Apr 2024 19:42:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Fnlh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Fnlh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Fnlh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Fnlh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Fnlh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Fnlh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Fnlh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg" width="640" height="459" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:459,&quot;width&quot;:640,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72011,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Fnlh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Fnlh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Fnlh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Fnlh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6ff9a8fb-b7dd-43d8-9617-4f87e8cc8e20_640x459.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>One can distinguish between the content of a message and the implications of the language used for such a message. If I say: &#8220;Good morning&#8221;, content-wise I communicate my intention to greet, but speech-act-wise I promise that I speak English. If I say &#8220;PK&#9829;&#9830;&#8221;, I state the fact that I can be understood in the formal language of a zip file.</p><p>And when I say "Ein Milchkaffee, bitte" here in Berlin, I imply that I will be able to handle a follow-up question in German. If my bluff is called and I can&#8217;t deliver, it&#8217;s a disappointing day for all the involved parties; disappointing enough that any hint of an accent or awkwardness of delivery is enough for many a local barista to switch immediately to English. Language learners hate this, but we also try to be conscious of the fact that no one wants to be an unpaid language tutor.</p><p>Let&#8217;s unpack this a little. An exchange of such messages is not completely free, and the transaction costs are high enough to make failed communication frustrating. The proposed language of communication is a promise to handle whatever semantics the language can express; it&#8217;s a bad situation when it&#8217;s a bluff that was called.</p><p>Now if I craft a complex sentence for you to handle, and you completely fail at understanding it, it&#8217;s annoying. If you know you don&#8217;t understand it, at least it&#8217;s something to work with. But if you grossly simplify it, misunderstand it stupidly, and still pretend that you completely understood it, that&#8217;s a communication disaster that sometimes takes a lot of patience to untangle.</p><p>We could distinguish between the German language proper, and the&nbsp;<em>Tourist</em>&nbsp;one (actually, it&#8217;s maybe more often expats, but &#8220;tourist&#8221; is the derogatory of choice for us anyway).&nbsp;<em>Tourist</em>&nbsp;is a subset of the German language that the particular tourist/expat understands; those subsets are quite similar among tourists (and expats) with a lot of memes enumerating the precise sets of phrases.</p><p>So there&#8217;s a choice for both parties between trying (and perhaps bluffing) to use German, or &#8220;simply&#8221; using English or some kind of German-like baby-talk. This game has two equilibria: either the expats aspire to speak real German (and painfully fail at that for many years), or everyone immediately switches to some kind of a terrible common denominator German-English for interactions with people they don&#8217;t know. Now, in many cases the second outcome seems unpalatable: I read a story once about Quebec(?) trying to avoid it by fiat (I can&#8217;t find the eloquent source). In Berlin, I think it&#8217;s more of a question of etiquette, enforced by the locals being both very reluctant to speak English and quite demanding of one&#8217;s German.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HKqn!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HKqn!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 424w, https://substackcdn.com/image/fetch/$s_!HKqn!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 848w, https://substackcdn.com/image/fetch/$s_!HKqn!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 1272w, https://substackcdn.com/image/fetch/$s_!HKqn!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HKqn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png" width="1456" height="1460" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/eaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1460,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2545719,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HKqn!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 424w, https://substackcdn.com/image/fetch/$s_!HKqn!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 848w, https://substackcdn.com/image/fetch/$s_!HKqn!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 1272w, https://substackcdn.com/image/fetch/$s_!HKqn!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Feaaafd35-f1a6-4d84-8ac1-e75a144a4eb0_1536x1540.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>This might be the better equilibrium (thanks @berlinauslandermemes)</em></p><div><hr></div><p>Let&#8217;s talk now about the natural language interfaces. Remember when you tried Siri, and you almost immediately realized it doesn&#8217;t&nbsp;<em>really</em>&nbsp;understand English? It guesses things with a recognizable predefined grammar, but can&#8217;t handle much more. Siri&#8217;s is not so much a &#8220;Natural Language&#8221; interface, but a &#8220;Small Subset of English&#8221; one. If one&#8217;s patient enough to learn this sub-language, one adapts to this small subset, learns the few sentences that Siri can understand, and avoids the rest. The visceral aversion to further communication failures makes any incremental improvements of Siri much harder to adopt.</p><p>ChatGPT, of course, is a different beast. It does seem to understand the language quite well, as long as you&#8217;re simply chatting with it. The problem, however, is when it is integrated as an interface to another system. We see a lot of systems being built with a chat interface, that is supposed to be fluent and comfortable. But those systems can&#8217;t actually handle everything ChatGPT can figure out for them. ChatGPT parses the requests alright, but there are simply not enough APIs, or a massive mismatch of the execution model, to express this formally in the system&#8217;s language.</p><p>Natural Language Interface is a huge promise to understand, and handle, whatever can be expressed in natural language. It&#8217;s often not more than a bluff. And if the user calls it, he knows that there&#8217;s no &#8220;natural language&#8221; at play here, and he would have to learn the actual sub-language of the system to be able to use it productively.</p><p>It is quite often not worth it for the user to learn this sub-language. Not only it&#8217;s inferior and a bit annoying to learn, but it&#8217;s also most of the time very badly defined. It&#8217;s undefined because the developers (or rather, the product people who order them around) are often in denial about even the existence of this sub-language. And because of that, the sub-language changes a lot without any advance warning<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> or, in some cases, even any control from the developers themselves.</p><p>And the worst of it is that an AI interface often can&#8217;t even recognize, or is programmed to not recognize, the situation when it can&#8217;t actually fully and completely &#8220;understand&#8221;, or effectively execute, a complex request. Such situations make those interfaces inherently untrustworthy and hard to steer, because often you&#8217;re not completely aware of the gross simplification that is happening, or have no clear means to fix it. Avoiding a situation like this is the reason, I believe, many people reach for a normal, traditional UI when they have an important and non-trivial task.</p><p><a href="https://salamilang.substack.com/p/slalom-designing-a-runtime-for-ai">Salami&#8217;s bet</a> is that Natural Language Interfaces are all-or-nothing, and it&#8217;s not enough to simply throw badly done &#8220;function-calling&#8221; at an LLM to match the expected semantics. We want to go against the dystopia of weak pseudo-natural sub-languages and make sure the largest possible expressible space is available to the users.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://salamilang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://salamilang.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Once I learned to shut up Alexa&#8217;s timer using &#8220;Thank you&#8221; and used the timer a lot. It was an interesting example of performativity of language. Then they changed the thank-you handler to respond politely and keep the timer screaming. I figured out I could just say &#8220;Alexa, shut up&#8221;, but I don&#8217;t really want to, so I ended up not using it at all anymore</p></div></div>]]></content:encoded></item><item><title><![CDATA[Salami: Designing a runtime for AI-generated code]]></title><description><![CDATA[The vision for the next step in running AI-generated code, integrated with our apps, for our users' commands.]]></description><link>https://salamilang.substack.com/p/slalom-designing-a-runtime-for-ai</link><guid isPermaLink="false">https://salamilang.substack.com/p/slalom-designing-a-runtime-for-ai</guid><dc:creator><![CDATA[Valentin Golev]]></dc:creator><pubDate>Sat, 10 Feb 2024 12:13:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!IgJu!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facdb2e68-b61c-4080-92bd-dfb7fa1f261f_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>NB: Salami is the new name for the project (changed from &#8220;Slalom&#8221; as it was taken). Salami: &#8220;Safe LLM-driven Interpreter&#8221;.</strong></p><p>Here&#8217;s a vision. We&#8217;re bound to have chatbots in every little app, and the users might want to ask to do something easy like this:</p><blockquote><p>Send the wedding invitations, wait a week for the responses. Use GPT to read them: allow extensions, and make sure everyone specifies both the +1 and the meal responses. Contact me immediately if I have anything to worry about.</p></blockquote><blockquote><p>If I get a message from the landlord, forward it to my lawyer. Wait a week. If the lawyer says nothing, notify me. Otherwise, thank him and contact me directly for further instructions.</p></blockquote><p>Complex triggers, awaiting indefinitely and far into the future, retained state, continuations from the user&#8230; Can LLM write code that does this kind of stuff? Can you? Will it use <code>setTimeout(..., 7*24*60*60*1000)</code>? (GPT-4&nbsp;<a href="https://chat.openai.com/share/f6b53b0b-1661-4178-bd5d-b8be92751340">did use</a>&nbsp;<code>time.sleep(604800)</code> for those examples). Will it have <code>eval(code_for_next_steps)</code>?<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> Would you run any of that? How?</p><p>To give this power to our users, we want to be able to run this kind of code cheaply, easily, safely, and reliably at scale, and using a solution that works with the architecture of the app, and doesn&#8217;t impose its own. This problem is greatly simplified by the fact that none of those little scripts need to be performant, and they don't demand state synchronization at a large scale.</p><p>The true power of LLMs for this kind of task is not that they can write Python code that looks like it&#8217;s written by a human. It&#8217;s that they wouldn&#8217;t be against writing much more boring, explicit code in a much more boring, syntactically poor, foolproof language. And given enough guardrails, that&#8217;s the kind of code we might consider running blindly<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><p>I am developing a custom runtime, supporting the kind of features the users would reasonably request, the kind of language that LLMs can reasonably write, the kind of architecture that engineers can easily integrate, and the kind of foolproof APIs that won&#8217;t be dangerous to expose. Below is the feature set I consider unusual, yet essential.</p><p><em>I&#8217;m working on&nbsp;<strong>Salami:</strong> a runtime, and a little language, for safely and prudently running AI-generated code. I am trying to approach it thoughtfully, and I started this blog to collect my thoughts and get feedback. Please subscribe</em><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a><em>, if you&#8217;re interested in the topic: today I&#8217;m talking about the runtime, and I&#8217;ll go deeper into the specifics of its internal language next week. I&#8217;m also planning to release the first batch of code on GitHub in a couple weeks, under the MIT license: do&nbsp;<a href="https://github.com/salamilang/salami">mark it with your star</a>.</em></p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://salamilang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://salamilang.substack.com/subscribe?"><span>Subscribe now</span></a></p><p>&nbsp;</p><p><strong>Foolproof APIs</strong></p><p>At its core, Salami would be a simple VM, deterministic and Turing-complete. But some things need to be supported on the runtime level, to enable the API integration designers to give something safe and useful to the users and to let the LLM write simplistic code without worrying about careful prompt-engineering-level safety checks. So let&#8217;s talk for a second about what we want from the API, and then we go more technical about the kinds of things we can do on the runtime level to enable this.</p><p>How do we make an API to be called from the LLM-written code that doesn&#8217;t lead to many regrets? I spent last year as an LLM-integration consultant (as a self-punishment for curiosity), to learn how people even go about it. My biggest gripe is that this essentially probabilistic industry is dominated by happy-path thinking. If one sends something to GPT4, and it kinda works from the third try, sure it might feel &#8220;magical&#8221;, but it&#8217;s still the opposite of a feature. The real work in LLM integration is the work of covering the&nbsp;<em>sad</em>&nbsp;paths, the ugly paths, the boring paths.</p><p>Running LLM-generated little workflows, there&#8217;s a trust issue with that. The notion of&nbsp;<em>trust</em>&nbsp;in this case is a bit different from the security experts&#8217; idea of it. Obviously, as an app developer, all the code that comes from your users is untrusted in the security sense, whether it&#8217;s written by an LLM or not. But even for the users it&#8217;s not trusted &#8211; because LLMs might be stupid. Because users might be confused about what they want. They don't have enough experience to avoid all the problems, nobody does. It can&#8217;t be their responsibility not to ask the LLM to produce&nbsp;<a href="https://en.wikipedia.org/wiki/Universal_Paperclips">too many paperclips</a>, because they will.</p><p>How do we design an API to prevent the LLMs from shooting the users in the foot? There&#8217;s no absolute solution. But we have some tools that can help. Ideally, all the exposed actions should be undoable. If it&#8217;s impossible, we can ask the user for permission for every particular action. We can ask them for a sanity check about a plan. We can slow things down when a lot of them happen. We can try and find ways for all of this to not be too annoying. We should do all of this without the users asking for it in the first place.</p><p>We should design something that makes it much easier to ask for permission than forgiveness. When the user asks to delete a file, put it in a &#8220;Bin&#8221;. When she asks to clear the &#8220;Bin&#8221;, put its contents into an even deeper &#8220;Bin&#8221;. And when the user says &#8220;send an email to my lawyer&#8221;, and LLM says &#8220;send_email&#8221;, what should actually happen is: create a draft of the letter, show it to the user, let her edit it, require that it is her who hits &#8220;Send&#8221;. This can&#8217;t be solved using a safety-oriented prompt, as you can never trust an LLM to always add the right checks. No, API should sound bold and clear to the LLM, and be actually careful and permission-seeking in its implementation.</p><p>The runtime must have everything to help the developers do the right thing (instead of simply dumping an OpenAPI spec into the &#8220;function calling&#8221; interface). That&#8217;s why the following features are important. They help give the user much more control over what happens, without complicating the code behind it. Giving the user more control is something that always makes writing business logic much more convoluted and hard; runtime has the power to make it much easier.</p><p>So, here are some of the features I think are essential, and a bit unusual for a VM:</p><ol><li><p>One can pause, serialize, and restore any running (or waiting) process&nbsp;</p></li><li><p>Green threads&#8230; with backtracking</p></li><li><p>Foreign functions can return a syntactic continuation</p></li><li><p>Resource management by slowing down</p></li></ol><h3>Storable runtime</h3><p>First unusual feature for the Salami VM is that you can pause it (or let it pause itself waiting for something), serialize it into a binary blob to store in some kind of a database, and then restore and continue running it when it's time to do so. The reason we need it is that it'd be very hard to integrate and run this kind of code safely if you have to keep the actual processes around.</p><p>The performance problem of Salami is not about making running one thread fast. Make your API fast, the Salami code should be high-level and can take its time. No, the performance problem is about running, say, a million of those threads<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>. Threads written by LLMs under unclear commands from users, that don&#8217;t care, or know anything, about your architecture or whatever you consider good async practices. Threads that mostly wait for events, or do something small. Making them independently storable (in any database you like), and easy to move from one machine to another &#8212; this is the key to the scalability approach that can adapt to whatever your app&#8217;s architecture is based on. You can run it on your server, on edge, or as a WASM module in the user&#8217;s browser.</p><p>This ability is an innocent-looking, but actually quite a serious complication. It prevents a lot of easy ways out of the burden of making a VM, such as a meta-circular interpretation, or using most of the existing VMs. It puts some burden on the API interface designers. E.g. it's still unclear if it's worth to differentiate between &#8220;fast async&#8221; calls and the calls that support pausing and shelving in progress (and which thus would often require some kind of state management).</p><p>But such a feature also makes a lot of patterns easy, even ones that don't require killing a process. Say you're writing a script for a video game: a character needs to go to the castle, then visit the bathroom, get out, and look at the stars. There might be a couple of conditions along the way. How do you code this up? Yield every destination from a coroutine? Typical coroutines in scripting languages are not storable and often require advanced cooperation from the runtime. One ends up reaching for an explicit state machine. Salami is designed from the ground up to enable this kind of implicit-state-machine coding without the typical limitations.</p><h3>Green threads, implicit process state</h3><p>Oh, coroutines. I am getting ahead of myself.</p><p>The green threads requirement was born directly from my experiments trying to get LLMs to write event-driven code for the workflows described above<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>. I was trying to be prudent and not implement an async runtime, so I wanted to see how well would LLMs manage callback hell and state synchronization. Well, I&#8217;m not impressed. They can do it, but they don&#8217;t want to. If something should happen after something else, they just want to call the functions, one after another.</p><p>Green threads can be thought of as a great way to implicitly define the stack machine behind an asynchronous process. But the state machines you are defining that way are kinda limited, they are basically linear, or looping. So I am experimenting with some kind of a &#8220;backtracking&#8221; technique for coroutines, where you can &#8220;undo&#8221; a little bit. Given that &#8220;undoability&#8221; is also a great thing to demand from the foreign APIs (see above), and we can likely be able to statically encode and deduce the undoability of some parts of code, this might enable something interesting. But it&#8217;s still more of an experiment, so no promises here.</p><p>Green threads are not a performance feature. Much more important here, in my opinion, might be determinism. So the threads have priorities, and they will actually wait for other threads before emitting their own effects. This is also an area of ongoing research and experimentation.</p><p>Any of the threads can yield itself to wait for an event. The event-matching values are defined by the foreign API so that it&#8217;s easy for the external executor to see what kinds of events are being awaited, and perform the needed effects accordingly. If ten threads are awaiting a value to be supplied from the database, you might be able to pack them into one SQL call. The events being awaited are also stored and serialized separately from the thread itself, so it&#8217;s easier to query your database of threads only for the ones that might need waking up.</p><p>When I talk about Salami to people, they sometimes mention BEAM (Erlang VM), its actor model, massive parallelism, and let-it-crash philosophy. BEAM is a great inspiration, but I think that none of the three is useful in this context. If there&#8217;s an error in a process like the one we want to support, it shouldn&#8217;t simply crash: it should notify the user, ask for a way out. The massive parallelism that Salami should enable is very different from Erlang&#8217;s one, its processes don&#8217;t need to stay in memory, their sleep is cold sleep in storage. As for the actor model, none of my experiments with the potential use cases made this model seem very essential, or nicer to use (we&#8217;ll talk about the language approach for the state synchronization in the next post)<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a>.</p><h3>Syntactic continuations</h3><p>Sometimes you&#8217;re giving some instructions, but you are not in the mood to cover all the cases. We&#8217;ll get there when we get there, and we&#8217;ll see. In Rust, you put a <code>todo!()</code> in that place, and the process will happily panic. But can we actually make these deferred instructions work, without a crash and restart?</p><p>Every step into a foreign function in Salami can currently return one of those things: a return value, a reference to a closure to call, an event to wait for (see above), or a &#8220;syntactic continuation&#8221;. Basically, it&#8217;s a piece of code that will execute as if it were written after that function call. This piece of code has access to all variables binding from all the parent environments. It's just a fancy name for "eval", I suppose; except this code will go through the compile-time type-checks, that I don&#8217;t think are typical: do strongly-typed languages ever have eval?</p><p>Syntactic continuations enable one to make it up as he goes along. One can go and ask users for directions, or even go directly to an LLM to propose a good next step. When doing so, the users will see the exact context and values that their continuation will be executed in, and that should make it much easier for them to make good decisions.</p><h3>Fair resource management</h3><p>Explicit and fair resource management is not only about making sure no user will hog all the computing space-time to themselves. It will also help to make it likely that if any shooting-in-the-foot happens, it might just be slow enough to notice and prevent much damage.</p><p>The language facilities I described already make it quite easy to implement all kinds of limits by, first of all, slowing down the code. By saying that e.g. one can&#8217;t remove more than one email per minute, we don&#8217;t introduce much inconvenience<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-7" href="#footnote-7" target="_self">7</a>, as our threads can easily run without any supervision. And then we can also prevent a catastrophe: if, in ten minutes, the user finds that the emails should&#8217;ve been kept, they only lost ten of them.</p><div><hr></div><p>That&#8217;s what I have on my mind, and to some extent, in code as well. What do you think? Would you want to try it? Is it at least interesting? Misguided? Is it an affront to all the good VM writing? Will this never ever work? Am I missing something obvious? Is there already a language or a runtime that does all of this? Am I misusing an important concept? Should I read a nice little paper? Is there a neat bimonoidal *-autonomous category that is perfect for what I&#8217;m building? Do tell me!</p><p><em>Next week, I&#8217;ll be talking about the internal language: will it have braces or tabs? Should it maybe be visual? How strong are its types, how shared is its state, how delimited continuations? Subscribe to find out.</em></p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://salamilang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://salamilang.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Will it be a callback hell with a custom trigger API for every case you can foresee? Will it rely on a random cron-style SaaS that would be gone in 2025? Will it be a truly massive YAML? Will it spend dollars/hour on GPT API to ask it directly for the next steps every minute?</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>If we don't, someone will end up blindly running LLM-generated JS. Avoiding that is the ethical imperative behind my work.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Substack has&nbsp;<a href="https://slalomlang.substack.com/feed">rss</a>&nbsp;btw. I do promise that this blog will never have AI-generated covers.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>It&#8217;s not my ambition, it&#8217;s your ambition!</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>I use quantized deepseek-coder, quantized StableCode, and calls to the cloud to gpt3.5-turbo-instruct and codellama. Salami is aimed at the commodity LLMs.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>Anthropomorphizing two different things is bound to make them interesting to equalize, so &#8220;LLM Actors&#8221; seems to be a thing people like to say, but I&#8217;m personally not sold on this stuff.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-7" href="#footnote-anchor-7" class="footnote-number" contenteditable="false" target="_self">7</a><div class="footnote-content"><p>Except, like, maybe in a shred-all-evidence situation&#8230;</p></div></div>]]></content:encoded></item><item><title><![CDATA[Coming soon]]></title><description><![CDATA[This is Salami dev blog.]]></description><link>https://salamilang.substack.com/p/coming-soon</link><guid isPermaLink="false">https://salamilang.substack.com/p/coming-soon</guid><dc:creator><![CDATA[Valentin Golev]]></dc:creator><pubDate>Thu, 08 Feb 2024 21:10:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!IgJu!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facdb2e68-b61c-4080-92bd-dfb7fa1f261f_512x512.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is Salami dev blog.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://salamilang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://salamilang.substack.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item></channel></rss>