<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>hi, it&#39;s mike</title>
    <link>https://mike.puddingtime.org/tags/cli/</link>
    <description>Recent content on hi, it&#39;s mike</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>mike@puddingtime.org (mike)</managingEditor>
    <webMaster>mike@puddingtime.org (mike)</webMaster>
    <copyright>© 2026, mike</copyright>
    <lastBuildDate>Sun, 28 Jan 2024 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://mike.puddingtime.org/tags/cli/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Keeping secrets with 1Password&#39;s CLI tool</title>
      <link>https://mike.puddingtime.org/posts/2024-01-28-keeping-secrets-with-1password-s-cli-tool/</link>
      <pubDate>Sun, 28 Jan 2024 00:00:00 +0000</pubDate><author>mike@puddingtime.org (mike)</author>
      <guid>https://mike.puddingtime.org/posts/2024-01-28-keeping-secrets-with-1password-s-cli-tool/</guid>
      <description>A couple of ways to securely reference your secrets in scripts and apps using 1Password&amp;rsquo;s CLI tool (and a detour into gpg-based approaches.)</description>
      <content:encoded><![CDATA[<p>I wrote the initial version of my <a href="/posts/2024-01-26-daily-notes/">linkding plugin for Newsboat</a> using <a href="https://github.com/bkeepers/dotenv">dotenv</a> to provide my Linkding API key. You just have a <kbd>.env</kbd> file in your home directory with a simple &ldquo;<kbd>KEY=VALUE</kbd>&rdquo; setup. Works fine for not hardcoding your secrets into scripts and reducing the chance you&rsquo;ll end up adding a credential to version control, but the secrets are sitting around unencrypted.</p>
<p>Now that I have it working at about the same level of reliability as the other plugins in the Newsboat repo I&rsquo;ll pull out the dependency on <kbd>dotenv</kbd> and just tell the would-be consumer &ldquo;get this credential into an environment variable, hardcode it, or do something else that feels safe to you.&rdquo;</p>
<p>For myself, I&rsquo;m weighing a couple of options because I&rsquo;d like to do a little better than having a bunch of credentials sitting around in the plain.</p>
<p>Over the years I&rsquo;ve handled this with mutt by combining gpg with mutt&rsquo;s <kbd>source</kbd> config command:</p>
<ol>
<li>
<p>Make a very minimal rc file in mutt&rsquo;s config syntax that sets your user and password:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">       set imap_user=you@example.com
</span></span><span class="line"><span class="cl">       set imap_pass=yourimappassword1234</span></span></code></pre></div>
</li>
<li>
<p>Encrypt that file with gpg:</p>
<p><kbd>gpg -r <a href="mailto:yourkey@example.com">yourkey@example.com</a> &ndash;encrypt passwordfile</kbd></p>
</li>
<li>
<p>Use mutt&rsquo;s <kbd>source</kbd> directive in your <kbd>muttrc</kbd> to decrypt the file on the fly and read in those two directives:</p>
<p><kbd>source &ldquo;gpg -d ~/.mutt/passwords.gpg |&quot;</kbd></p>
</li>
</ol>
<p>If you have gpg set up correctly, you&rsquo;ll get a key authentication prompt when you run mutt. The credentials are never stored in the plain on disk, and you&rsquo;ll get a gpg password prompt every now and then if you have other stuff going on, such as multiple accounts that each need to periodically source that config when you change between them. mutt&rsquo;s <kbd>source</kbd> is just &ldquo;do whatever is in this file,&rdquo; same as <kbd>zsh</kbd>&rsquo;s, so I eventually landed on a way to do the same thing in a shell environment:</p>
<p><kbd>$(gpg &ndash;decrypt ./setenv.sh.gpg)</kbd></p>
<p>That just decrypts <kbd>setenv.sh.gpg</kbd> and runs the commands inside, which can be just setting a bunch of environment variables in the current shell environment. The data is never decrypted to disk.</p>
<p>That seems like a good general solution that covers a lot of drive-by security scenarios.</p>
<p>In the process of working that out, I wondered about 1Password&rsquo;s CLI tool. The few times I saw it mentioned the demos were for secrets management, not retrieval, but I took another look at the docs and it does have some interesting provisions for getting your secrets out of 1Password from the CLI.</p>
<p>Basically, when you use the <kbd>op</kbd> command&rsquo;s <kbd>run</kbd> argument you can tell it to source in some environment variables from a <kbd>.env</kbd> file that uses <kbd>op</kbd>&rsquo;s internal URI scheme to pull credentials out of your vault. An example resource reference looks like this:</p>
<p><kbd>op://Personal/Linkding/password</kbd></p>
<p>If you put that in an <kbd>env</kbd> file with a variable assignment, the <kbd>op</kbd> command can source it and pass it along to a shell command. So:</p>
<p><kbd>op run &ndash;env-file=&quot;$HOME/.env&rdquo;  &ndash; ~/bin/linkding.rb</kbd></p>
<p>&hellip; reads from a file that looks something like this:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nv">LINKDING_USER</span><span class="o">=</span><span class="s2">&#34;op://Personal/Linkding/username&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">LINKDING_TOKEN</span><span class="o">=</span><span class="s2">&#34;op://Personal/Linkding/credential&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">FRESHRSS_USER</span><span class="o">=</span><span class="s2">&#34;op://Personal/FreshRSS/username&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">FRESHRSS_PASS</span><span class="o">=</span><span class="s2">&#34;op://Personal/FreshRSS/credential&#34;</span></span></span></code></pre></div>
<p>&hellip; and supplies the <kbd>linkding</kbd> script with a value for this line:</p>
<p><kbd>token = ENV[&lsquo;LINKDING_TOKEN&rsquo;]</kbd></p>
<p>If you&rsquo;re already auth&rsquo;d into 1Password and you&rsquo;ve enabled integration between the CLI tool and the desktop app, then you don&rsquo;t have to do anything. If you need to re-auth your 1Password instance, you&rsquo;ll get a biometric prompt. If you&rsquo;re ssh&rsquo;d into a remote host where you wouldn&rsquo;t get the biometric prompt, you can bypass that by setting <kbd>OP_BIOMETRIC_UNLOCK_ENABLED=false</kbd> but you&rsquo;ll need to explicitly auth the 1Password CLI tool from the command line. It doesn&rsquo;t seem to just fail over to a CLI auth.</p>
<p>So, handled the 1Password way, your <kbd>.env</kbd> file could remain unencrypted, but you&rsquo;d probably be best off aliasing any scripts or commands you run where you want the <kbd>op</kbd> tool to interpolate your <kbd>.env</kbd> file.</p>
<p>It&rsquo;s a little more cumbersome but maybe there&rsquo;s benefit over the long haul from knowing that you just have to keep credentials in 1Password and can reference them elsewhere instead of maintaining an encrypted <kbd>.env</kbd> file. It&rsquo;s also nice to have a biometric prompt or system auth vs. using gpg keys, which require you to have another password on hand (at least until 1Password quits punting on a gpg agent to pair with the ssh one).</p>
<p>For now I&rsquo;ve only got enough stuff connected this way to use 1Password with FreshRSS and my Linkding plugin. Newsboat allows you to set your RSS service&rsquo;s password with output from a shell command, so I&rsquo;ve got that set to:</p>
<p><kbd>freshrss-passwordeval &ldquo;op read op://Personal/FreshRSS/credential&rdquo;</kbd></p>
<p>If I&rsquo;m auth&rsquo;d into 1Password, great: It just runs and sets the credential for NewsBoat. If I&rsquo;m not, great as well: It just runs and tosses up a biometric prompt before proceeding.</p>
<p>I&rsquo;m also using the env file pattern for Newsboat, for my bookmarking command:</p>
<p><kbd>bookmark-cmd &ldquo;op run &ndash;env-file=&quot;$HOME/.env&quot;  &ndash; ~/bin/linkding.rb&rdquo;</kbd></p>
<p>That&rsquo;s because I don&rsquo;t want to write my Linkding plugin to require any particular infrastructure. It just wants an environment variable, which is supplied by wrapping the script in the <kbd>op run</kbd> command with an <kbd>&ndash;env-file</kbd> switch. If someone wants to take the script and use another way to get the variable into their environment, or just decide to take their chances and hard-code it because they&rsquo;re comfortable with that risk, they can. If I ever stop using 1Password I can similarly just figure out a new secrets backend and may be able to avoid rewriting a bunch of utility scripts if I keep using this approach. If I want to use one of my scripts on a host where I don&rsquo;t have 1Password, well, there are other ways.</p>
<p><span class="underline"><span class="underline">Update:</span></span> I wondered about that mutt setup I have and ended up seeing what would happen if I replaced the whole &ldquo;load mutt, source a gpg-encrypted file&rdquo; thing with simple 1Password resource references. It works pretty well. If you&rsquo;re signed into 1Password, it just works. If you&rsquo;re not, you get a biometric prompt:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">imap_user</span><span class="o">=</span><span class="sb">`</span>op <span class="nb">read</span> op://Personal/MuttFastmail/imap_user<span class="sb">`</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">smtp_pass</span><span class="o">=</span><span class="sb">`</span>op <span class="nb">read</span> op://Personal/MuttFastmail/smtp_pass<span class="sb">`</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">imap_pass</span><span class="o">=</span><span class="sb">`</span>op <span class="nb">read</span> op://Personal/MuttFastmail/imap_pass<span class="sb">`</span></span></span></code></pre></div>
<p>Same caveats as with everything: If I ever end up wanting to use my mutt config on a machine I can&rsquo;t put 1Password on, I&rsquo;d need to go back to my old gpg file pattern.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Daily Notes for 2024-01-26</title>
      <link>https://mike.puddingtime.org/posts/2024-01-26-daily-notes/</link>
      <pubDate>Fri, 26 Jan 2024 00:00:00 +0000</pubDate><author>mike@puddingtime.org (mike)</author>
      <guid>https://mike.puddingtime.org/posts/2024-01-26-daily-notes/</guid>
      <description>Sorta the mutt of RSS readers. Scripting the Linkding API.</description>
      <content:encoded><![CDATA[<h2 id="sorta-the-mutt-of-rss-readers">Sorta the mutt of RSS readers</h2>
<p><a href="https://newsboat.org/">Newsboat</a> is pretty cool! It&rsquo;s a plaintext RSS reader that has strong affinities for mutt in look and configuration.</p>
<p>Like mutt, it might not crowd out everything else in the toolbox but it can help you burn through the subscription list and triage even if you have more comfortable ways of reading the content you process.</p>
<p>It also has built-in filtering. If you&rsquo;re using an RSS provider that already does that, e.g. FreshRSS or Feedly, that might not be super valuable, but it&rsquo;s easy to make a killfile either way:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">ignore-mode display
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/ducks/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/advice/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/nfl/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/beavers/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/blazers/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/highschoolsports/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/entertainment/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/realestate-news/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/food/\&#34;&#34;
</span></span><span class="line"><span class="cl">ignore-article &#34;*&#34; &#34;link =~ \&#34;/hawks/\&#34;&#34;</span></span></code></pre></div>
<h2 id="scripting-the-linkding-api-to-make-a-bookmark-function-for-newsboat">Scripting the Linkding API to make a bookmark function for Newsboat</h2>
<p>If you like reading longform plaintext maybe Newsboat is all you need. I tend to treat RSS as a two-step process: See an interesting thing, send it to some sort of RIL or bookmarking service. Newsboat has a bookmarking function you can customize with your own scripts. It just passes the article URL, title, description, and website description to your script, which has to talk to whatever API. There are a bunch of <a href="https://github.com/newsboat/newsboat/tree/master/contrib">examples in the Newsboat contrib directory</a> for things like Pocket, Pinboard, and Evernote. No Linkding, but <a href="https://github.com/sissbruecker/linkding/blob/master/docs/API.md">the Linkding API</a> is simple enough.</p>
<p>Could be simpler but I bounced off of <kbd>net:http</kbd> in my formative years:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/env ruby</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;httparty&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;json&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">linkding_uri</span> <span class="o">=</span> <span class="s2">&#34;https://links.puddingtime.net/api/bookmarks/&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Get your Linkding API key from Settings &gt; Integrations</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">token</span> <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;LINKDING&#39;</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">link_url</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">link_title</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">description</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">[</span><span class="mi">2</span><span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="n">website_title</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">[</span><span class="mi">3</span><span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">params</span> <span class="o">=</span> <span class="p">{</span><span class="ss">url</span><span class="p">:</span> <span class="no">URI</span><span class="p">(</span><span class="n">link_url</span><span class="p">),</span> <span class="ss">title</span><span class="p">:</span> <span class="n">link_title</span><span class="p">,</span> <span class="ss">website_title</span><span class="p">:</span> <span class="n">website_title</span><span class="p">,</span> <span class="ss">unread</span><span class="p">:</span> <span class="kp">true</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;Content-Type&#39;</span> <span class="o">=&gt;</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span> <span class="s1">&#39;Authorization&#39;</span> <span class="o">=&gt;</span> <span class="s2">&#34;Token </span><span class="si">#{</span><span class="n">token</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">resp</span> <span class="o">=</span> <span class="no">HTTParty</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">linkding_uri</span><span class="p">,</span> <span class="ss">body</span><span class="p">:</span> <span class="n">params</span><span class="o">.</span><span class="n">to_json</span><span class="p">,</span> <span class="ss">headers</span><span class="p">:</span> <span class="n">headers</span><span class="p">)</span></span></span></code></pre></div>
]]></content:encoded>
    </item>
    <item>
      <title>Daily notes for 2024-01-09 (mutt noodling edition)</title>
      <link>https://mike.puddingtime.org/posts/2024-01-09-daily-notes/</link>
      <pubDate>Tue, 09 Jan 2024 10:41:05 -0800</pubDate><author>mike@puddingtime.org (mike)</author>
      <guid>https://mike.puddingtime.org/posts/2024-01-09-daily-notes/</guid>
      <description>Multi-account, GPG-secure mutt configs. Mutt message scoring with Ruby, and score color-coding.</description>
      <content:encoded><![CDATA[<h2 id="multi-account-gpg-secured-mutt-config">Multi-account, GPG-secured mutt config</h2>
<p>I keep having to reinvent this every few years, and I always stitch it together from assorted sources, mostly because Google sort of shifts around now and then. So:</p>
<ul>
<li>Given a Gmail account with IMAP access turned on</li>
<li>Given a Fastmail account using IMAP</li>
<li>Given mutt, with your configuration in <code>~/.mutt</code> and with <code>muttrc</code> and <code>macros</code> files.</li>
<li>Given a working gpg config you can use to encrypt/decrypt</li>
</ul>
<p>There are all sorts of ways to handle mutt config for assorted providers. The examples here are working right now, in early 2024. They probably have bits of cruft and lint because my config has been a work in progress since some time in the late 20th century.</p>
<h3 id="overview">Overview</h3>
<p>You&rsquo;re making profiles to do this: One for each of your accounts that will hold account specific config information. If you currently have a monolith config in mutt, you can lift a lot of stuff out of it and move it into a profile, then source the profile in your main <code>muttrc</code>.</p>
<p>You&rsquo;re also going to make and encrypt a credential file for each account. Some people do this all in one file and use account hooks to make sure <code>imap_user</code>, <code>imap_password</code> and <code>smtp_password</code> are set correcctly depending on the account you&rsquo;re operating in. I chose to make a file for each account.</p>
<p>You&rsquo;re going to make macros that source the profiles when you want to switch between them.</p>
<h3 id="0-pre-config-with-gmail-and-fastmail">0. Pre-config with Gmail and Fastmail</h3>
<p>I&rsquo;m not going to go into a ton of detail here:</p>
<ul>
<li>Gmail needs to have less secure app access turned on. Find it in your account settings. If you&rsquo;re doing this for a work account, it may be your admin hasn&rsquo;t enabled this. Have fun fighting city hall, in that case.</li>
<li>If you have a GSuite admin, they need to have enabled all IMAP clients, not just OAuth ones.</li>
<li>If you have 2FA turned on with Google, you will need to enable an application password.</li>
</ul>
<p>For Fastmail:</p>
<ul>
<li>You need to have an app password set up for mutt. <code>Settings -&gt; Privacy and Security -&gt; Integrations -&gt; App passwords</code></li>
</ul>
<h3 id="1-the-profile-files">1. The profile files</h3>
<p>Make profile files for each of your accounts. I name them <code>workplace.profile</code>, <code>fastmail.profile</code>, etc. It doesn&rsquo;t matter there&rsquo;s no required convention. It&rsquo;s a good idea to use the first one as the template for the second one.</p>
<p>This is an example of my Fastmail profile. Note line 6:</p>
<p><code>source &quot;gpg -d ~/.mutt/passwords.gpg |&quot;</code></p>
<p>That&rsquo;s where your credentials will come from. I&rsquo;ll show that file next.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># -*- muttrc -*-</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Mutt sender profile : personal/default</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">unset</span> folder
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">smtp_authenticators</span> <span class="o">=</span> <span class="s1">&#39;gssapi:login&#39;</span> <span class="c1"># fastmail needs this</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">imap_authenticators</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">source</span> <span class="s2">&#34;gpg -d ~/.mutt/passwords.gpg |&#34;</span> 
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">spoolfile</span> <span class="o">=</span> <span class="s2">&#34;imaps://imap.fastmail.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">folder</span> <span class="o">=</span> <span class="s2">&#34;imaps://imap.fastmail.com/INBOX&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">postponed</span><span class="o">=</span><span class="s2">&#34;+Drafts&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">hostname</span><span class="o">=</span><span class="s2">&#34;yourdomain.com&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">signature</span><span class="o">=</span> <span class="s2">&#34;~/.mutt/personal.sig&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">from</span><span class="o">=</span> <span class="s2">&#34;Bob Jones &lt;bob@yourdomain.com&gt;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">realname</span> <span class="o">=</span> <span class="s2">&#34;Bob Jones&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">smtp_url</span> <span class="o">=</span> <span class="s2">&#34;smtps://bobjones@fastmail.com@smtp.fastmail.com:465&#34;</span> <span class="c1"># use your fastmail username, not your email address</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">imap_user</span> <span class="o">=</span> <span class="s2">&#34;bobjones@fastmail.com&#34;</span> <span class="c1"># use your fastmail username here, too</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># set the status to show which profile I&#39;m using</span>
</span></span><span class="line"><span class="cl"><span class="nb">set</span> <span class="nv">status_format</span><span class="o">=</span> <span class="s2">&#34;-%r-Fastmail: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%&gt;-(%P)---\n&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">unmy_hdr *
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">my_hdr From: Bob Jones &lt;bob@yourdomain.com&gt;
</span></span><span class="line"><span class="cl">my_hdr Organization: yourdomain.com
</span></span><span class="line"><span class="cl">my_hdr Sender: Bob Jones &lt;bob@yourdomain.com&gt;
</span></span><span class="line"><span class="cl">my_hdr Return-Path: &lt;bob@yourdomain.com&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># clear the existing mailboxes list</span>
</span></span><span class="line"><span class="cl">unmailboxes *
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># load up mailboxes appropriate to this profile</span>
</span></span><span class="line"><span class="cl">mailboxes + <span class="s2">&#34;=Spam&#34;</span>
</span></span><span class="line"><span class="cl">mailboxes + <span class="s2">&#34;=disposable&#34;</span>
</span></span><span class="line"><span class="cl">mailboxes + <span class="s2">&#34;=Newsletters&#34;</span>
</span></span><span class="line"><span class="cl">mailboxes + <span class="s2">&#34;=Sent&#34;</span>
</span></span><span class="line"><span class="cl">mailboxes + <span class="s2">&#34;=Archive&#34;</span></span></span></code></pre></div>
<h3 id="2-make-credentials-files">2. Make credentials files</h3>
<p>For each account, you need to make a file for your credentials.</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">set imap_user=bob@bobjones.com
</span></span><span class="line"><span class="cl">set imap_pass=&#34;klatu barada nikto&#34;
</span></span><span class="line"><span class="cl">set smtp_pass=&#34;klatu barada nikto&#34;</span></span></code></pre></div>
<p>Name it whatever. <code>passwords-accountname</code> works.</p>
<p>Once you&rsquo;ve created the file, encrypt it with gpg:</p>
<p><code>gpg -r your-gpg-key@yourdomain.com -e passwords-fastmail</code></p>
<p>Test it:</p>
<p><code>gpg -d passwords-fastmail.gpg</code></p>
<p>Then shred the plaintext original:</p>
<p><code>shred -u passwords-fastmail</code></p>
<p>Make sure that your profile (from the previous step) is sourcing the gpg file in line 6 of my example, e.g.</p>
<p><code>source &quot;gpg -d ~/.mutt/passwords-fastmail.gpg |&quot;</code></p>
<h3 id="3-do-a-quick-mid-config-check">3. Do a quick mid-config check</h3>
<p>Might as well test it now.  You can do that by sourcing one of your profiles in your <code>muttrc</code>:</p>
<p><code>source ~/.mutt/fastmail.profile</code></p>
<p>When you run mutt the first time in this login session, you should get a gpg prompt for your credentials so mutt can decrypt your password file and use it to log in.</p>
<p>If it&rsquo;s working, now&rsquo;s the time to make your second profile and credentials files using the above steps since it&rsquo;ll be good to know what they&rsquo;re all called for the next step, which is making macros.</p>
<h3 id="4-make-macros">4. Make macros</h3>
<p>I keep my macros in their own file under <code>~/.mutt</code> just to keep things modular. You can put these in your main <code>muttrc</code>. Whatever you prefer. If you have a separate file, make sure to source it in <code>muttrc</code>:</p>
<p><code>source ~/.mutt/macros</code></p>
<p>Now add something like this for each account:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">macro index .cf &#39;&lt;sync-mailbox&gt;&lt;enter-command&gt;source ~/.mutt/fastmail.profile&lt;enter&gt;&lt;change-folder&gt;!&lt;enter&gt;&#39;
</span></span><span class="line"><span class="cl">macro index .cg &#39;&lt;sync-mailbox&gt;&lt;enter-command&gt;source ~/.mutt/google.profile&lt;enter&gt;&lt;change-folder&gt;!&lt;enter&gt;&#39;</span></span></code></pre></div>
<p>That just does one last sync, then sources your profile, then changes folders to the inbox of that profile.</p>
<p>Restart mutt. From the index, if all is working correctly, the macro <code>.cf</code> will source your <code>fastmail.profile</code> and the macro <code>.cg</code> will source your <code>google.profile</code> file (both of which also source/decrypt their respective credential files).</p>
<h3 id="5-in-conclusion">5. In conclusion</h3>
<p>Once it&rsquo;s all wired up and running, you should be able to switch back and forth between accounts with just a few seconds of latency as the inbox syncs on exit and the new inbox syncs on login.</p>
<h2 id="the-pleasures-of-mutt">The pleasures of mutt</h2>
<p>I went on a mutt revival kick early last year. It remains a land of contrasts. I never end up sticking to it 100 percent of the time but instead prefer to use it as a quick triage tool: It&rsquo;s easy to make macros and keybindings that speed up inbox processing. Sometimes it&rsquo;s easier to just bail out to the web mail interface, but during the day it&rsquo;s helpful to just burn through the inbox never taking my hands off the keyboard.</p>
<h2 id="mutt-scoring-and-color-treatments">mutt scoring and color treatments</h2>
<p>One last thing, I guess, since I&rsquo;m documenting stuff.  One of the reasons I like mutt for triage so much is my ability to add a little visual treatment to messages based on their scores. That makes it easy to see what in my inbox has more priority.</p>
<p>I&rsquo;ve got this little script in my <code>~/.mutt</code>:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/env ruby</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;mail&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">require</span> <span class="s1">&#39;tempfile&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Wants a +/- integer, e.g. +20</span>
</span></span><span class="line"><span class="cl"><span class="n">score</span> <span class="o">=</span> <span class="no">ARGV</span><span class="o">.</span><span class="n">first</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">score_file</span> <span class="o">=</span> <span class="s2">&#34;</span><span class="si">#{</span><span class="no">Dir</span><span class="o">.</span><span class="n">home</span><span class="si">}</span><span class="s2">/.mutt/scored&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">msg</span> <span class="o">=</span> <span class="no">Tempfile</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">&#39;msg&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">msg</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="vg">$stdin</span><span class="o">.</span><span class="n">read</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">mail</span> <span class="o">=</span> <span class="no">Mail</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">from</span> <span class="o">=</span> <span class="n">mail</span><span class="o">.</span><span class="n">from</span><span class="o">.</span><span class="n">first</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">score_file</span><span class="p">,</span> <span class="s2">&#34;a&#34;</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="s2">&#34;score ~f</span><span class="si">#{</span><span class="n">from</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">score</span><span class="si">}</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">msg</span><span class="o">.</span><span class="n">close</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">msg</span><span class="o">.</span><span class="n">unlink</span></span></span></code></pre></div>
<p>And I&rsquo;ve got these macros in my <code>~/.mutt/macros</code> file:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># Score messages</span>
</span></span><span class="line"><span class="cl">macro index,browser .sp <span class="s2">&#34;&lt;pipe-entry&gt;~/.mutt/mailscore.rb +5\n&lt;enter-command&gt;source ~/.mutt/scored&lt;enter&gt;&#34;</span> <span class="c1"># score sender +5</span>
</span></span><span class="line"><span class="cl">macro index,browser .sP <span class="s2">&#34;&lt;pipe-entry&gt;~/.mutt/mailscore.rb +20\n&lt;enter-command&gt;source ~/.mutt/scored&lt;enter&gt;&#34;</span> <span class="c1"># score sender +20</span>
</span></span><span class="line"><span class="cl">macro index,browser .sm <span class="s2">&#34;&lt;pipe-entry&gt;~/.mutt/mailscore.rb -5\n&lt;enter-command&gt;source ~/.mutt/scored&lt;enter&gt;&#34;</span> <span class="c1"># score sender -5</span>
</span></span><span class="line"><span class="cl">macro index,browser .sM <span class="s2">&#34;&lt;pipe-entry&gt;~/.mutt/mailscore.rb -20\n&lt;enter-command&gt;source ~/.mutt/scored&lt;enter&gt;&#34;</span> <span class="c1"># score sender -20</span></span></span></code></pre></div>
<p>And I&rsquo;ve got a few lines in my <code>~/.mutt/colors</code> file:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">color index cyan default <span class="s2">&#34;~n 0-2 !~p&#34;</span>
</span></span><span class="line"><span class="cl">color index magenta default <span class="s2">&#34;~n &lt;5&#34;</span>
</span></span><span class="line"><span class="cl">color index brightyellow default <span class="s2">&#34;~n &gt;15&#34;</span>
</span></span><span class="line"><span class="cl">color index brightred default <span class="s2">&#34;~n &gt;19&#34;</span>
</span></span><span class="line"><span class="cl"><span class="c1">#</span></span></span></code></pre></div>
<p>The macros pipe a given message into the script, the script extracts the sender, and the script writes a line into my <code>~/.mutt/scored</code> file. Then the <code>~/.mutt/colors</code> file (which you need to source in <code>muttrc</code>) assigns colors to certain scores. I have a few other rules in <code>~/.mutt/scores</code>, as well:</p>






<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="c1"># Date-based scoring penalties -- older things fall down</span>
</span></span><span class="line"><span class="cl">score ~d&gt;3d -1
</span></span><span class="line"><span class="cl">score ~d&gt;7d -3
</span></span><span class="line"><span class="cl">score ~d&gt;14d -10
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">score <span class="s2">&#34;~O&#34;</span> +10 <span class="c1"># old = +10 so I don&#39;t miss it</span>
</span></span><span class="line"><span class="cl">score <span class="s2">&#34;~F&#34;</span> +20 <span class="c1"># flagged = +20 so it stays in the interesting view for a while, even if old</span>
</span></span><span class="line"><span class="cl">score <span class="s2">&#34;!~p ~d&gt;7d&#34;</span> -10 <span class="c1"># not for me directly, getting old, let it fade away</span>
</span></span><span class="line"><span class="cl">score <span class="s2">&#34;!~l&#34;</span> +2 <span class="c1"># to a known list, give it a bump</span></span></span></code></pre></div>
]]></content:encoded>
    </item>
    <item>
      <title>Daily notes for 2024-01-03</title>
      <link>https://mike.puddingtime.org/posts/2024-01-03-daily-notes/</link>
      <pubDate>Wed, 03 Jan 2024 16:04:07 -0800</pubDate><author>mike@puddingtime.org (mike)</author>
      <guid>https://mike.puddingtime.org/posts/2024-01-03-daily-notes/</guid>
      <description>More a/v messing around. Zellij: A tmux alternative.</description>
      <content:encoded><![CDATA[<h2 id="more-av-messing-around">More a/v messing around</h2>
<p>I got a boom for my USB shotgun mic (a Rode VideoMic GO). It mounts on the back of my desk and swings in and out of place between calls. It sits about eight inches away from my face, but just off camera (yay relatively tight 23mm crop) and the sound quality is sooo much better than when I had it mounted in my X-T2&rsquo;s hot shoe. Much more presence and bass, much less reverb.  Okay. Time to start a podcast. I can feel it.</p>
<h2 id="tmux-alternative">tmux alternative</h2>
<p><a href="https://zellij.dev/">Zellij</a> is a terminal multiplexer <em>ala</em> screen or tmux, but it&rsquo;s got a nicer onboarding ramp than either thanks to a decent menu that exposes most of what you need and out-of-the-box UX touches.</p>
<p><img src="https://photos.smugmug.com/photos/i-vcsZGfh/0/5ae23ff4/XL/i-vcsZGfh-XL.jpg" alt="Screenshot of Zellij, a terminal multiplexer showing multiple panes and a helpful menu"></p>
<h2 id="through-the-holidays">Through the holidays</h2>
<p>We had a pretty good holiday season this year. Ben was home from his first term at UofO, and we had a quiet couple of weeks with few obligations. Work was pretty quiet, too: We had a major system change slated for the interim week, then the vendor backed out, so there was a little bit of &ldquo;shrug, I guess there&rsquo;s this paperwork to catch up on,&rdquo; which is a fine way to spend that week.</p>
<p>It&rsquo;s good to be almost on the other side: We have a balance day off this Friday, so this will be a three-day week, then back to normal next week.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Daily notes for 2023-12-28</title>
      <link>https://mike.puddingtime.org/posts/2023-12-28-daily-notes/</link>
      <pubDate>Thu, 28 Dec 2023 11:30:38 -0800</pubDate><author>mike@puddingtime.org (mike)</author>
      <guid>https://mike.puddingtime.org/posts/2023-12-28-daily-notes/</guid>
      <description>A CLI for Remember the Milk. Vampire Survivors. A little on Substack.</description>
      <content:encoded><![CDATA[<h2 id="a-cli-for-rtm">A CLI for rtm</h2>
<p>Just as good as Todoist for my purposes, and with a little more personal affection toward it, is definitely <a href="https://www.rememberthemilk.com/app/">Remember the Milk</a>. It also <a href="https://github.com/dwaring87/rtm-cli">has a CLI</a> that allows for task manipulation, etc. It also uses RTM&rsquo;s advanced search syntax, so you don&rsquo;t have to have a preexisting filter, as you would in Todoist, to query upcoming todos with due dates only:</p>
<p><code>rtm lsd -d 4 NOT due:never</code></p>
<p>(<em>List due items no more than 4 days out, exclude things without due dates</em>)</p>
<p>Its output also includes index numbers, so once I invoke my near-term todos, I can act on them from the command line, e.g.</p>
<p><code>rtm due 07 tomorrow</code></p>
<p>&hellip; which changes the due date of item 7 from the list to tomorrow.</p>
<p>I think this may have put to bed my interest in exploring <a href="https://xwmx.github.io/nb/">nb</a>. I spent some time poking at it, but the question, as always, comes down to &ldquo;how does this thing handle mobile use cases?&rdquo; For todos, I need a little more than the sort of <a href="https://gist.github.com/pdxmph/1d17833f910dbfd86068d94cfac585f9">web publishing lashup I made for my Denote notes</a>.</p>
<h2 id="vampire-survivors">Vampire Survivors</h2>
<p>I am not sure what compelled me besides maybe the sale price, but I gave Vampire Survivors a go and I&rsquo;m hooked. It&rsquo;s a rogue-like bullet hell thing where you&rsquo;re running around being chased by hordes of undead, slowly acquiring weapons and powerups that eventually turn you into a killing machine.</p>
<p>It was disorienting at first, because you don&rsquo;t do anything besides move around. All your weapons fire or deploy themselves, and your only real input into the process is the direction you face the character. Live long enough and you&rsquo;re eventually emitting magical energies or deploying roaming weapons of mass destruction, killing the oncoming demonic hordes by the score. Sometimes there&rsquo;s a turkey you can eat to get life back.</p>
<p>It&rsquo;s an intense game, but it&rsquo;s not really fast. I think that&rsquo;s what I like about it. Your character doesn&rsquo;t move at a very high speed. You just sort of walk around, trying not to be touched by the monsters. If you&rsquo;re lucky you happen across one of the aura weapons that just passively kill anything that gets close. When you die, you can spend your gold on incremental improvements to your character that allow you move a little faster, regenerate health, widen the radius of your weapons, do more damage, etc.</p>
<p>It&rsquo;s very simple to play and very easy to put down and pick back up.</p>
<h2 id="substack">Substack</h2>
<p>I wish people that I appreciate and who are not Nazis, or interested in helping Nazis, and who are also on Substack, would get off of it. The company did itself a favor paying the advances it did at its founding, because I know of a few writers who have been very transparent about how much space that gave them to branch out on their own, establish or rebuild writing careers, and find an audience.</p>
<p>I always wondered how long it would take for attention to turn to it, and what it would take. Honestly, I think it is a refutation of the Woke Apocalypse Doomsaying Community that it took this long and such an odious provocation to finally generate that kind of awareness. There has always been complaining, because left libs were never going to be okay with a platform that provided a home for the likes of Bari Weiss, Matt Taibi, and assorted other &ldquo;heterodox&rdquo; types, but it took honest-to-God Nazis &ndash; and the fact that Substack has decided their money spends just fine &ndash; to draw prolonged attention.</p>
<p>A while back, fresh out of years and years doing online content, I gave a thought to providing something Substack-like: I had the technical know-how for a lot of it, had done some time putting together newsletters and turnkey premium content, and had a good idea of what would work for content types. I didn&rsquo;t have any idea how to scale it all, or how to draw the line between &ldquo;good enough&rdquo; and &ldquo;feature rich&rdquo; in a way that would make much money. I&rsquo;m just noting that because the quandary facing people who signed up and are now making a living from their work on Substack is real. There are parts and pieces laying around that they could pick up and use to cobble together a similar suite of blog, newsletter, and podcast tools; but the discovery part &ndash; the marketing problem, especially given the current realignment going on with social media &ndash; is going to be fraught even if one does have the wherewithal to rummage around in the parts bin of publishing platforms, payment processing, etc.</p>
<p>This is a tougher situation than, I dunno, a well-off tech worker who just can&rsquo;t kick their X habit. It is hard to make a go of it as a writer. It would be hard to pull up stakes and move on.</p>
<p>I wouldn&rsquo;t mind being a little more current and capable than I am today, because there would be some social utility and satisfaction in helping people get out of this situation.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
