<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Random Hacks</title>
    <description>Random code snippets, projects and musings about software from Eric Kidd, a developer and occasional entrepreneur.</description>
    <link>http://www.randomhacks.net/</link>
    <atom:link href="http://www.randomhacks.net/feed.xml" rel="self" type="application/rss+xml" />
    <language>en</language>
    
      <item>
        <title>Redoubtful: Linux agent sandbox progress</title>
        <description>
          &lt;p&gt;I’ve also been experimenting with agent sandboxes lately. &lt;a href=&quot;https://github.com/emk/redoubtful&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;redoubtful&lt;/code&gt;&lt;/a&gt; is a work-in-progress sandbox that supports:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;strong&gt;Linux-only sandboxes:&lt;/strong&gt; I’m focusing on what Linux supports, specifically, rather than trying to support the lowest-common-denominator features that work cross platform.&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;Modular configuration profiles:&lt;/strong&gt; See below.&lt;/li&gt;
  &lt;li&gt;Isolation using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pasta&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bwrap&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;A shadow filesystem that &lt;em&gt;looks&lt;/em&gt; like your home directory, so things like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt; actually work correctly. You can also selectively mount existing parts of your filesystem in read-only or read-write mode.&lt;/li&gt;
  &lt;li&gt;Network port forwarding and filtering proxy server.&lt;/li&gt;
  &lt;li&gt;
&lt;strong&gt;TODO:&lt;/strong&gt; Proxy credential support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But first, a warning: Nearly 100% of this code was written by coding agents, much of it by a local Qwen3.6 27B. I am, however, keeping a &lt;em&gt;very&lt;/em&gt; close eye on the output—one of my goals here is to see just what a small agent like this can do. This is maybe only 80% as good as my handwritten code would be a similar point in a project.&lt;/p&gt;

&lt;p&gt;And finally, &lt;strong&gt;this is an incomplete work-in-progress&lt;/strong&gt;, and it has not been packaged nicely for anyone besides me yet.&lt;/p&gt;

&lt;h3 id=&quot;modular-configuration-profiles&quot;&gt;Modular configuration “profiles”&lt;/h3&gt;

&lt;p&gt;One of the &lt;em&gt;slightly&lt;/em&gt; novel parts of all this is the ability to define modular configuration. This allows us to invoke a sandbox with a specific set of credentials:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;redoubtful run &lt;span class=&quot;nt&quot;&gt;--uses&lt;/span&gt; pi &lt;span class=&quot;nt&quot;&gt;--uses&lt;/span&gt; llama-server pi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, we’re running the &lt;a href=&quot;https://pi.dev/&quot;&gt;pi.dev&lt;/a&gt; coding agent with a locally-served Qwen3.6 27B via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llama-server&lt;/code&gt;. Qwen3.6 27B is a fantastic lightweight coding model, and it works very well with pi.dev’s minimalist prompt. And since we’re running in a sandbox, we don’t care that pi.dev provides no sandbox and no confirmation before acting.&lt;/p&gt;

&lt;p&gt;To set up these two profiles, we first define a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node&lt;/code&gt; profile:&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Standard Node setup. If you&apos;re using `nvm`, you&apos;ll need to fix the path_add&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# entry to point to the correct nvm version.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# We might want some kind of plugin system to handle messy things like nvm.&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[profile.node]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;mounts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.npm-global&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.local/share/nvm&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;access&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;rw&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;path_add&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/.npm-global/bin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.local/share/nvm/v24.15.0/bin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then let’s make Rust work:&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# A Rust setup, with optional rustup and advisory support.&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[profile.rust]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;mounts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.rustup&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.cargo&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Cargo audit/deny support, which needs to take a lock to update the&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# advisory database.&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.cargo/advisory-dbs/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;access&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;rw&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;path_add&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;[&quot;~/.cargo/bin&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; is easy—we just need enough config to read &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user.name&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user.email&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Things you will likely want for git.&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[profile.git]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;mounts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.gitconfig&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then finally, we can set up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pi&lt;/code&gt; itself:&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Profile for the pi coding agent. Run with:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#     redoubtful run -u pi pi&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[profile.pi]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;uses&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;rust&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;git&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;mounts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;~/.pi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;access&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;rw&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Pass through llama-server connections.&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;[profile.llama-server]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;forwards&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host_port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8080&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;proxies&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;whats-left&quot;&gt;What’s left?&lt;/h3&gt;

&lt;p&gt;The biggest missing piece is teaching the proxy server how to inject real credentials into network connections. This isn’t a new idea. The goal is to provide access to things like GitHub without giving an agent actual credentials.&lt;/p&gt;

&lt;p&gt;After that, it’s just packaging everything up nicely and writing some docs, so that other people (or agents) can easily configure it for different purposes.&lt;/p&gt;

            
        </description>
        <pubDate>Sun, 17 May 2026 14:50:36 -0400</pubDate>
        <link>http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2026/05/17/redoubtful-agent-sandbox-progress/</guid>
      </item>
    
      <item>
        <title>Lab notebook: Edit completion #1</title>
        <description>
          &lt;p&gt;I &lt;a href=&quot;https://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/&quot;&gt;continue to be interested&lt;/a&gt; in late-2024-era edit completion, the “Fill in the Middle” (FIM) models. You know, what Copilot used to do, back before it started generating “mini diffs.” Why?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I like and use agentic workflows. But as many people are realizing, &lt;a href=&quot;https://blog.k10s.dev/im-going-back-to-writing-code-by-hand/&quot;&gt;it’s &lt;em&gt;super&lt;/em&gt; easy to lose track of what’s happening in your code, with terrible consequences&lt;/a&gt;. So I want to reinvest in human-in-the-loop tools, too. (And slightly weaker agentic models, but more on that later.)&lt;/li&gt;
  &lt;li&gt;The new-school edit completion offered by Copilot and &lt;a href=&quot;https://zed.dev/blog/zeta2&quot;&gt;Zed’s Zeta2&lt;/a&gt; actually slows me down. It overlays diffs on my buffer, which is visually disorienting at speed. And it proposes edits further from the current cursor, which take me longer to mentally process. Personally, the new style feels like hunt-and-peck. The older style felt like &lt;em&gt;really fast&lt;/em&gt; touch typing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mind you, I’m a very specific sort of user. I want to know how my code works. I want my code to be clean. And I can read a half-page code completion in moments, thanks to way too many years of reading PRs.&lt;/p&gt;

&lt;h3 id=&quot;initial-experiments&quot;&gt;Initial experiments&lt;/h3&gt;

&lt;p&gt;All experiments performed in Zed, which does less post-processing of the raw model output than some tools. All evaluations are purely subjective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;New-school models (generating diffs).&lt;/strong&gt; Zeta2 is honestly pretty underwhelming right now. The completions are very generic. And Zeta2 seems to be bad about taking the context into account. It will complete a function, sure. But I’d swap Zeta2 for late 2024 Copilot in a heartbeat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Old-school models (FIM, inserting at cursor).&lt;/strong&gt; Let’s go down the list so far:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ggml-org/Qwen2.5-Coder-7B-Q8_0-GGUF:Q8_0&lt;/code&gt;: The classic, default choice. This isn’t &lt;em&gt;terrible&lt;/em&gt;, and it gives more context-aware completions than Zeta2. But it’s generations old, and I want to know if anything is new and shiny.&lt;/li&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mradermacher/Seed-Coder-8B-Base-i1-GGUF:Q6_K&lt;/code&gt;. This is the raw base that went into Zeta2, I think? It doesn’t seem to be useful in Zed, because the inserted text feels pretty raw. This might work better in a smarter harness. But I’m dropping it for now.&lt;/li&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JetBrains/Mellum-4b-base-gguf:Q8_0&lt;/code&gt;. Downloaded, but not yet tested.&lt;/li&gt;
  &lt;li&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_XS&lt;/code&gt;. This is &lt;a href=&quot;https://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/&quot;&gt;unexpectedly good&lt;/a&gt;! Worth further experimentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;refining-qwen36-35b-a3b-changing-order-from-psm-to-spm&quot;&gt;Refining Qwen3.6 35B A3B: Changing order from PSM to SPM&lt;/h2&gt;

&lt;p&gt;Qwen typically uses FIM, “Fill in the Middle” completion. This uses 3 magic tokens:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cd&quot;&gt;/// Qwen FIM prefix marker.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PRE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;|fim_prefix|&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cd&quot;&gt;/// Qwen FIM suffix marker.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SUF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;|fim_suffix|&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cd&quot;&gt;/// Qwen FIM middle marker (model generates after this).&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;|fim_middle|&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have two possible flavors. The original is “PSM” compeletion, “prefix, suffix, middle”:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;{PRE}{prefix}{SUF}{suffix}{MID}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But since the prefix grows with each keystroke, we can’t cache the entire message. We could get much better caching with “SPM” order:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;{SUF}{suffix}{PRE}{prefix}{MID}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we can cache everything up to the final {MID} character, and resume generation with a longer prefix. Whooo, speed!&lt;/p&gt;

&lt;p&gt;But Zed doesn’t support SPM completion, only PSM. So I fired up a copy of Claude Code (as one does), and asked, “Hey, write me a Rust proxy server (using my standard conventions) that intercepts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/completion&lt;/code&gt;, and translates PSM to SPM please.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt; Extremely disappointing. SPM format confuses Qwen3.6 35B A3B pretty badly. But then I thought, “Hey, even if we’re running in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/completion&lt;/code&gt; mode, this is still an instruction-tuned model. Can we prompt it?” One unscientific tweak later:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;You are a code-completion tool. You receive input in
fim_suffix+fim_prefix+fim_middle order, and your job
is to generate what the user would be likely to type
next. When in doubt, keep it short. Think of this like
generating a diff in agentic coding mode. You&apos;re trying
to insert the right text to make a working program that
does what the user wants. If there&apos;s no obvious next
step, generate nothing.

{SUF}{suffix}{PRE}{prefix}{MID}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is &lt;em&gt;still&lt;/em&gt; pretty bad, but it’s better. You can tell it’s &lt;em&gt;trying&lt;/em&gt; to be an SPM autocompleter, though it’s still the worst of the bunch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Possible next steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;What if we modify the proxy to transform &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/completion&lt;/code&gt; into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/chat/completions&lt;/code&gt; request, with a real prompt, real text inputs, and tool for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;insert_at_cursor(text)&lt;/code&gt;? Can we access more of the model’s intelligence?&lt;/li&gt;
  &lt;li&gt;Qwen3.6 35B A3B is small enough to fine-tune! We could look up file completion data sets, and try to create a LoRA adapter. We could even use something like &lt;a href=&quot;https://tree-sitter.github.io/tree-sitter/&quot;&gt;tree-sitter&lt;/a&gt; to generate custom completion examples. Would that give us something useful?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I also notice that FIM-style models are &lt;em&gt;notoriously&lt;/em&gt; bad at choosing a good stopping place. This can be fixed with a lot of regexes. But what if our fine-tuning data took care to demonstrate &lt;em&gt;good&lt;/em&gt; stopping places?&lt;/p&gt;

            
        </description>
        <pubDate>Sat, 16 May 2026 11:49:55 -0400</pubDate>
        <link>http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2026/05/16/lab-notebook-edit-completion-1/</guid>
      </item>
    
      <item>
        <title>I should blog more</title>
        <description>
          &lt;p&gt;This blog is ancient, in blog years. The first post was on June 30, 1998, and it featured a &lt;a href=&quot;https://www.randomhacks.net/1998/06/30/randomhacks-online-mathmap/&quot;&gt;randomized emboss for MathMap&lt;/a&gt;. Back in those days, it was a mix of neat little snippets like that and interesting links. The site was a single, hand-edited HTML file in reverse chronological order. It ran on a Linux mini-tower built from parts from &lt;a href=&quot;https://w1mx.mit.edu/flea-at-mit/&quot;&gt;the MIT Swapfest&lt;/a&gt;, and it lived under my desk.&lt;/p&gt;

&lt;p&gt;Google hadn’t been incoporated yet. The Internet bubble was still inflating.&lt;/p&gt;

&lt;p&gt;Over the years, the tech stack changed: for a while, this site used SGML-based rendering via a custom script (or was it XML?), then it was a nice interactive Typo site with comments, and then eventually it migrated to the current Jekyll architecture. Which seems to be about 12 years old. I’m pretty proud to have kept nearly all the inbound links working for decades now.&lt;/p&gt;

&lt;p&gt;Around 2007 or so, I did a fun series of high effort posts about &lt;a href=&quot;https://www.randomhacks.net/probability-monads/&quot;&gt;probability monads&lt;/a&gt;. But high-effort posts are a trap. Soon I started feeling like &lt;em&gt;every&lt;/em&gt; post ought to be high effort. And then I wrote less and less.&lt;/p&gt;

&lt;p&gt;But blogs are a bit of a retro endeavour these days. RSS readers still exist, but I imagine nearly all my subscribers have disappeared since the heady days of 2007. And apparently it’s trendy to &lt;a href=&quot;https://notes.andymatuschak.org/Work_with_the_garage_door_up&quot;&gt;work with the garage door up&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So maybe it’s time to get back this site’s roots. I don’t have any &lt;a href=&quot;https://www.complang.tuwien.ac.at/schani/mathmap/dist/&quot;&gt;MathMap&lt;/a&gt; snippets for you today, sadly, because the last release seems to have been in 2004. &lt;a href=&quot;http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/&quot;&gt;But here’s a cool trick!&lt;/a&gt;&lt;/p&gt;

            
        </description>
        <pubDate>Wed, 13 May 2026 01:04:52 -0400</pubDate>
        <link>http://www.randomhacks.net/2026/05/13/i-should-blog-more/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2026/05/13/i-should-blog-more/</guid>
      </item>
    
      <item>
        <title>Edit completion works with Qwen3.6 35B A3B!</title>
        <description>
          &lt;p&gt;Do you miss the old-style Copilot completions? The ones where it inserted grey text at the cursor? There’s an open version of this called &lt;a href=&quot;https://api-docs.deepseek.com/guides/fim_completion&quot;&gt;“FIM completion”&lt;/a&gt;. And the classic model for doing this is &lt;a href=&quot;https://huggingface.co/Qwen/Qwen2.5-Coder-7B&quot;&gt;Qwen2.5 Coder 7B&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But it turns out that Qwen3.6 35B A3B is can also do autocompletion! The fact that it has 3B active parameters means that it’s fast. And the 35B total parameters means it’s smarter than the smaller models.&lt;/p&gt;

&lt;p&gt;So let’s fire it up using &lt;a href=&quot;https://github.com/ggml-org/llama.cpp&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;llama-server&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;llama-server &lt;span class=&quot;nt&quot;&gt;-hf&lt;/span&gt; unsloth/Qwen3.6-35B-A3B-GGUF:UD-IQ4_XS &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--cache-type-k&lt;/span&gt; q8_0 &lt;span class=&quot;nt&quot;&gt;--cache-type-v&lt;/span&gt; q8_0 &lt;span class=&quot;nt&quot;&gt;--no-mmproj&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;--ctx-size&lt;/span&gt; 4000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--no-mmproj&lt;/code&gt; says to disable the vision mode. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--cache-type-k q8_0 --cache-type-v q8_0&lt;/code&gt; reduces the cache precision, since we’re not really using the cache. You might also need to &lt;a href=&quot;https://huggingface.co/unsloth/Qwen3.6-35B-A3B-GGUF&quot;&gt;grab a smaller quant&lt;/a&gt;, depending on your available VRAM.&lt;/p&gt;

&lt;p&gt;Then, we can configure it using &lt;a href=&quot;https://zed.dev/&quot;&gt;Zed&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;edit_predictions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;provider&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;open_ai_compatible_api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;open_ai_compatible_api&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;api_url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;http://localhost:8080/v1/completions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;unsloth/Qwen3.6-35B-A3B-GGUF:IQ4_XS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;prompt_format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;qwen&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;max_output_tokens&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So how good is this? Well, the completions aren’t too bad at all, but Zed doesn’t seem to do much post-processing. So the completions to be too long. At lot of this could likely be improved with a proxy that did some pre- and post-processing, and maybe a bit of fine tuning.&lt;/p&gt;

&lt;p&gt;But this is an actual, working, 100% local autocomplete. And it’s &lt;em&gt;close&lt;/em&gt; to being actually good.&lt;/p&gt;

            
        </description>
        <pubDate>Wed, 13 May 2026 01:04:52 -0400</pubDate>
        <link>http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2026/05/13/edit-completion-with-qwen36/</guid>
      </item>
    
      <item>
        <title>9½ years of Rust in production (and elsewhere)</title>
        <description>
          &lt;p&gt;The first stable release of Rust was on May 15, 2015, just about 9½ years ago. My first “production” Rust code was a Slack bot, which talked to GoCD to control the rollout of a web app. This was utterly reliable. And so new bits of Rust started popping up.&lt;/p&gt;

&lt;p&gt;I’m only going to talk about open source stuff here. This will be mostly production projects, with a couple of weekend projects thrown in. Each project will ideally get its own post over the next couple of months.&lt;/p&gt;

&lt;h2 id=&quot;posts-i-really-ought-to-write-someday&quot;&gt;Posts I really ought to write someday&lt;/h2&gt;

&lt;p&gt;Here are some of the tools I’d like to talk about someday:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Moving tables easily between many databases (&lt;a href=&quot;https://www.dbcrossbar.org/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dbcrossbar&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;700-CPU batch jobs&lt;/li&gt;
  &lt;li&gt;Geocoding 60,000 addresses per second&lt;/li&gt;
  &lt;li&gt;Interlude: Neural nets from scratch in Rust&lt;/li&gt;
  &lt;li&gt;Lots of CSV munging&lt;/li&gt;
  &lt;li&gt;Interlude: Language learning using subtitles, Anki, Whisper and ChatGPT&lt;/li&gt;
  &lt;li&gt;Transpiling BigQuery SQL for Trino (a work in progress)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;maintaining-rust--training-developers&quot;&gt;Maintaining Rust &amp;amp; training developers&lt;/h2&gt;

&lt;p&gt;One of the delightful things about Rust is the &lt;strong&gt;low rate of “bit rot”.&lt;/strong&gt; If something worked 5 years ago—and if it wasn’t linked against the C OpenSSL libraries—then it probably works unchanged today. And if it doesn’t, you can usually fix it in 20 minutes. This is largely thanks to Rust’s &lt;a href=&quot;https://blog.rust-lang.org/2014/10/30/Stability.html&quot;&gt;“stability without stagnation”&lt;/a&gt; policy, the &lt;a href=&quot;https://doc.rust-lang.org/edition-guide/editions/&quot;&gt;Edition system&lt;/a&gt;, and the &lt;a href=&quot;https://github.com/rust-lang/crater&quot;&gt;Crater&lt;/a&gt; tool which is used to nest new Rust releases against the entire ecosystem.&lt;/p&gt;

&lt;p&gt;The more interesting questions are (1) when should you use Rust, and (2) how do you make sure your team can use it?&lt;/p&gt;


            
              &lt;p&gt;
                &lt;a href="http://www.randomhacks.net/2024/11/17/9-years-of-rust-in-production-and-elsewhere/"&gt;Read more…&lt;/a&gt;
              &lt;/p&gt;
            
        </description>
        <pubDate>Sun, 17 Nov 2024 11:08:00 -0500</pubDate>
        <link>http://www.randomhacks.net/2024/11/17/9-years-of-rust-in-production-and-elsewhere/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2024/11/17/9-years-of-rust-in-production-and-elsewhere/</guid>
      </item>
    
      <item>
        <title>Pair programming with ChatGPT: A simple dice roller</title>
        <description>
          &lt;p&gt;[This was a fun early attempt to get ChatGPT to write software way back in 2022, before coding agents were a thing.]&lt;/p&gt;

&lt;p&gt;Like many folks, I spent too much of the last couple days playing with the new release of &lt;a href=&quot;https://openai.com/blog/chatgpt/&quot;&gt;ChatGPT&lt;/a&gt;. I’ve been trying discover what it’s good at, and how it breaks. At its best, it’s remarkable—I think it would actually pass many common “hiring screens” for programmers. And it has &lt;a href=&quot;https://github.com/max-sixty/aoc-gpt&quot;&gt;taken first place on an Advent of Code problem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But there are various tricks which will break it. Programs with randomized output occasionally fool it, as do programs with multiple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; branches. So I set down this morning for a short pair programming session, and wrote a classic dice roller with ChatGPT. The experience was &lt;em&gt;fascinating&lt;/em&gt;. Things started out very frustrating, but they wound up pretty mind-blowing by the end.&lt;/p&gt;


            
              &lt;p&gt;
                &lt;a href="http://www.randomhacks.net/2022/12/04/pair-programming-with-chatgpt/"&gt;Read more…&lt;/a&gt;
              &lt;/p&gt;
            
        </description>
        <pubDate>Sun, 04 Dec 2022 10:09:20 -0500</pubDate>
        <link>http://www.randomhacks.net/2022/12/04/pair-programming-with-chatgpt/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2022/12/04/pair-programming-with-chatgpt/</guid>
      </item>
    
      <item>
        <title>In nightly Rust, &apos;await!&apos; may never return (dropping futures)</title>
        <description>
          &lt;p&gt;I’ve been using the &lt;a href=&quot;https://areweasyncyet.rs/&quot;&gt;proposed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await!&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; features in nightly Rust&lt;/a&gt;, and overall, I really like the design. But I did run into one surprise: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await!&lt;/code&gt; may never return, and this has consequences I didn’t fully understand. Let’s take a look.&lt;/p&gt;

&lt;p&gt;We’re going to use Rust &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nightly-2019-02-08&lt;/code&gt;, and &lt;a href=&quot;https://tokio.rs/blog/2018-08-async-await/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio-async-await&lt;/code&gt;&lt;/a&gt;. This is highly experimental code, and it will require us to convert back and forth between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio::Future&lt;/code&gt; and the proposed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::future::Future&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can find &lt;a href=&quot;https://github.com/emk/drop-async-examples&quot;&gt;the full code&lt;/a&gt; on GitHub. We’ll start by enabling the experimental features we’ll need:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;#![feature(await_macro,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;async_await,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;futures_api)]&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;#[macro_use]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;crate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tokio_async_await&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we’ll import some libraries, and declare two helper functions &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio_fut&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boxed_fut&lt;/code&gt;, that make it easy to convert from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std::future::Future&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio::Future&lt;/code&gt; and into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Box&amp;lt;tokio::Future&amp;lt;..&amp;gt;&amp;gt;&lt;/code&gt;, respectively. You can look that code up &lt;a href=&quot;https://github.com/emk/drop-async-examples&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, we define a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delay&lt;/code&gt;, which returns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt; that waits for the specified number of milliseconds:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;millis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Delay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;nn&quot;&gt;Instant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_millis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;millis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;canceling-a-future&quot;&gt;Canceling a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Future&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now, we can define two tasks:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cd&quot;&gt;/// An asynchronous function that completes quickly.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;quick_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&apos;static&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;START quick_task&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;delay failed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;END quick_task&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;quick_task result&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cd&quot;&gt;/// An asynchronous function that completes very slowly.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;slow_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&apos;static&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;START slow_task&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10_000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;delay failed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;END slow_task&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;slow_task result&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quick_task&lt;/code&gt; waits for 10 milliseconds, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slow_task&lt;/code&gt; waits for 10,000 milliseconds. We can combine them using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;select_all&lt;/code&gt;:&lt;/p&gt;


            
              &lt;p&gt;
                &lt;a href="http://www.randomhacks.net/2019/03/09/in-nightly-rust-await-may-never-return/"&gt;Read more…&lt;/a&gt;
              &lt;/p&gt;
            
        </description>
        <pubDate>Sat, 09 Mar 2019 15:11:20 -0500</pubDate>
        <link>http://www.randomhacks.net/2019/03/09/in-nightly-rust-await-may-never-return/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2019/03/09/in-nightly-rust-await-may-never-return/</guid>
      </item>
    
      <item>
        <title>Should Rust channels panic on send if nobody&apos;s listening?</title>
        <description>
          &lt;p&gt;Lately, I’ve been working on several real-world systems using Rust’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tokio&lt;/code&gt;. As you can see on the &lt;a href=&quot;https://areweasyncyet.rs/&quot;&gt;areweasyncyet.rs&lt;/a&gt; site, this requires using nightly Rust and the experimental &lt;a href=&quot;https://tokio.rs/blog/2018-08-async-await/&quot;&gt;tokio-async-await&lt;/a&gt; library. I hope to talk more about these experiences soon!&lt;/p&gt;

&lt;p&gt;But today, I want to talk about channel APIs in Rust. A question was &lt;a href=&quot;https://github.com/crossbeam-rs/crossbeam/issues/314&quot;&gt;raised by @matklad on GitHub&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’ve migrated rust-analyzer to crossbeam-channel 0.3, and the thing I’ve noticed is that every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.send&lt;/code&gt; is followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.unwrap&lt;/code&gt;. Perhaps we should make this unwrapping behavior the default, and introduce a separate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checked_send&lt;/code&gt; which returns a Result?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;BurntSushi &lt;a href=&quot;https://www.reddit.com/r/rust/comments/awh751/proposal_new_channels_for_rusts_standard_library/ehmk3lz/&quot;&gt;followed up on Reddit&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Because the vast majority of uses of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send&lt;/code&gt; are like this: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ch.send(foo).unwrap()&lt;/code&gt;. That is, you panic because you generally regard it as a bug if you’re still sending values when all receivers have been dropped. Why? Because this is generally a property of the program’s organization.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hesitate to disagree with two such excellent developers, but my experiences with this issue are almost the exact opposite of matklad’s and BurntSushi’s.&lt;/p&gt;


            
              &lt;p&gt;
                &lt;a href="http://www.randomhacks.net/2019/03/08/should-rust-channels-panic-on-send/"&gt;Read more…&lt;/a&gt;
              &lt;/p&gt;
            
        </description>
        <pubDate>Fri, 08 Mar 2019 16:42:27 -0500</pubDate>
        <link>http://www.randomhacks.net/2019/03/08/should-rust-channels-panic-on-send/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2019/03/08/should-rust-channels-panic-on-send/</guid>
      </item>
    
      <item>
        <title>Bare Metal Rust 3: Configure your PIC to handle interrupts correctly</title>
        <description>
          &lt;p&gt;&lt;em&gt;Want to build your own kernel in Rust?  See &lt;a href=&quot;http://www.randomhacks.net/bare-metal-rust/&quot;&gt;Bare Metal Rust&lt;/a&gt; to get
started.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We’re almost ready to write a keyboard driver in Rust!  But first, we need
to deal with two obstacles: setting up the PIC, and handling interrupts
without crashing.  This is one of the most frustrating steps, as Julia
Evans explains in her hilarious and very helpful post
&lt;a href=&quot;http://jvns.ca/blog/2013/12/04/day-37-how-a-keyboard-works/&quot;&gt;After 5 days, my OS doesn’t crash when I press a key&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;Turn interrupts on (&lt;code&gt;sti&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The OS AGAIN crashes every time i press a key. Read “I Can’t Get
Interrupts Working” again. This is called “I’m receiving EXC9 instead
of IRQ1 when striking a key?!” Feel on top of this.&lt;/li&gt;
&lt;li&gt;Remap the PIC so that interrupt &lt;code&gt;i&lt;/code&gt; gets mapped to &lt;code&gt;i + 32&lt;/code&gt;,
because of an Intel design bug. This &lt;i&gt;basically&lt;/i&gt; looks like just
typing in a bunch of random numbers, but it works.&lt;/li&gt;
&lt;li&gt;12. THE OS IS STILL CRASHING WHEN I PRESS A KEY. This continues for 2
days.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’re going to follow Julia Evans’ roadmap. (She saved me several days of
suffering.)  And once we’re past these next few obstacles, things will get
easier.  Let’s talk to the PIC first.&lt;/p&gt;

&lt;h2 id=&quot;the-82958295a-programmable-interrupt-controller&quot;&gt;The 8295/8295A Programmable Interrupt Controller&lt;/h2&gt;

&lt;p&gt;We’re going to with the retro approach here, and handle interrupts using
the 8295 PIC.  You can &lt;a href=&quot;http://wiki.osdev.org/8259_PIC&quot;&gt;read all about it&lt;/a&gt; on the OSDev wiki, as
usual.  The PIC works fine in 64-bit mode, but someday, if we want to
support multiple processors and I/O, we’ll eventually need to support the
newer &lt;a href=&quot;http://wiki.osdev.org/APIC&quot;&gt;APIC&lt;/a&gt; and &lt;a href=&quot;http://wiki.osdev.org/IOAPIC&quot;&gt;IOAPIC&lt;/a&gt;.  But for now, let’s keep it simple.&lt;/p&gt;

&lt;p&gt;Technically, the x86 architecture has two PIC chips, usually known as PIC1
and PIC2.  PIC1 handles external interrupts 0–7, and PIC2 handles 8–15.
PIC2 is actually chained into interrupt 2 on PIC1, which means that we’ll
frequently need to talk to them as a pair.&lt;/p&gt;

&lt;p&gt;Unfortunately, the modern x86 architecture reserves CPU interrupts 0-31 for
processor exceptions.  This means that when we press a key, the CPU will
think it just received the “EXC9” mentioned by Julia Evans, which the Intel
manual tells me is “Coprocessor-Segment-Overrun Exception.”  So we need to
tell our PIC that, no, &lt;em&gt;McGyver&lt;/em&gt; and &lt;em&gt;Miami Vice&lt;/em&gt; are no longer
cutting-edge television, that there’s this new-fangled thing called 386
Protected Mode, and that it needs to start mapping interrupts at offset 32.&lt;/p&gt;


            
              &lt;p&gt;
                &lt;a href="http://www.randomhacks.net/2015/11/16/bare-metal-rust-configure-your-pic-interrupts/"&gt;Read more…&lt;/a&gt;
              &lt;/p&gt;
            
        </description>
        <pubDate>Mon, 16 Nov 2015 06:16:40 -0500</pubDate>
        <link>http://www.randomhacks.net/2015/11/16/bare-metal-rust-configure-your-pic-interrupts/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2015/11/16/bare-metal-rust-configure-your-pic-interrupts/</guid>
      </item>
    
      <item>
        <title>Bare Metal Rust 2: Retarget your compiler so interrupts are not evil</title>
        <description>
          &lt;p&gt;&lt;em&gt;Want to build your own kernel in Rust?  See the &lt;a href=&quot;http://www.randomhacks.net/bare-metal-rust/&quot;&gt;Bare Metal Rust&lt;/a&gt;
page for more resources and more posts in this series.  There’s just a few
more posts to go until we have keyboard I/O!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hacking on kernels in Rust is a lot of fun, but it can also result in
massive frustration when QEMU starts rebooting continuously because of a
&lt;a href=&quot;http://wiki.osdev.org/Triple_Fault&quot;&gt;triple fault&lt;/a&gt;.  One good way to minimize frustration is to wander on
over to the ever-helpful &lt;a href=&quot;http://wiki.osdev.org/Main_Page&quot;&gt;OSDev wiki&lt;/a&gt;.  It’s sort of like having an
experienced kernel developer on hand to give grouchy but sanity-saving
advice.&lt;/p&gt;

&lt;p&gt;The OSDev &lt;a href=&quot;http://wiki.osdev.org/Beginner_Mistakes&quot;&gt;Beginner Mistakes&lt;/a&gt; page, in particular, has saved me a couple
times already.  But there’s one bit of advice that I want to focus on
today, which I’ve marked in boldface below:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Beginners often ask “What is the &lt;em&gt;easiest&lt;/em&gt; way to do X?” rather than
“What is the best, proper, correct way to do X?”. This is dangerous as
the newcomer doesn’t invest time into understanding the superior way to
implement something, but instead picks a conceptually simpler method
copied from a tutorial. Indeed, the simpler route is often &lt;em&gt;too simple&lt;/em&gt;
and ends up causing more problems in the long run, because the beginner
is ignorant of the superior alternative and doesn’t know when it is
better to switch. What’s so bad about taking the hard route instead?&lt;/p&gt;

  &lt;p&gt;Common examples include &lt;strong&gt;being too lazy to use a Cross-Compiler,&lt;/strong&gt;
developing in Real Mode instead of Protected Mode or Long Mode, relying
on BIOS calls rather than writing real hardware drivers, using flat
binaries instead of ELF, and so on. Experienced developers use the
superior alternatives for a reason…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So what does that mean, “being too lazy to use a cross-compiler”?  It means
cheating, and using our regular &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustc&lt;/code&gt; setup to build ordinary user-space
code, and then trying to run it in kernel space.  This will actually work,
at least for a while.  But eventually, we may find ourselves engaged in
multiweek debugging nightmares.&lt;/p&gt;

&lt;p&gt;So today, I’m going to talk about the sanity-saving difference between
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--target x86_64-unknown-linux-gnu&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--target x86_64-unknown-none-gnu&lt;/code&gt;,
and how to get your Rust compiler ready for the kernel world.&lt;/p&gt;


            
              &lt;p&gt;
                &lt;a href="http://www.randomhacks.net/2015/11/11/bare-metal-rust-custom-target-kernel-space/"&gt;Read more…&lt;/a&gt;
              &lt;/p&gt;
            
        </description>
        <pubDate>Wed, 11 Nov 2015 05:43:30 -0500</pubDate>
        <link>http://www.randomhacks.net/2015/11/11/bare-metal-rust-custom-target-kernel-space/</link>
        <guid isPermaLink="true">http://www.randomhacks.net/2015/11/11/bare-metal-rust-custom-target-kernel-space/</guid>
      </item>
    
  </channel>
</rss>
