<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>release &amp;mdash; Nat Knight</title>
    <link>http://natknight.xyz/tag:release</link>
    <description>Reflections, diversions, and opinions from a progressive ex-physicist programmer dad with a sore back.</description>
    <pubDate>Sat, 23 May 2026 14:41:13 -0700</pubDate>
    <item>
      <title>todo-sqlite3 v0.1</title>
      <link>http://natknight.xyz/todo-sqlite3-v0-1</link>
      <description>&lt;![CDATA[#release #sqlite3&#xA;&#xA;I wrote a spec for a SQLite-based todo database and just release version 0.1.&#xA;&#xA;!--more--&#xA;&#xA;todo.txt is an obvious inspiration, but I wanted to put my data in SQLite for a couple of reasons:&#xA;&#xA;SQLite is very stable, nearly as stable as plain text.&#xA;Having your todos in a database opens up possibilities for querying, viewing, and extending that data much more easily than if it&#39;s in plain text.&#xA;Having the data in SQLite in particular means multiple apps can interact with the database simultaneously, so I can have a CLI, a web app, and automation scripts touching the same todo list without risking corruption or data loss.&#xA;&#xA;Now that the database schema is ready I just have to build the rest of the app...&#xA;&#xA;The schema (not counting a tagging extension) in full:&#xA;&#xA;-- todo-sqlite3&#xA;-- https://github.com/nathanielknight/todo-sqlite3&#xA;&#xA;-- Foreign Key constraints are required.&#xA;PRAGMA foreignkeys = ON;&#xA;&#xA;-- Core Items table&#xA;CREATE TABLE items (&#xA;    id INTEGER PRIMARY KEY,&#xA;    -- Every item has a title (not necessarily unique)&#xA;    title TEXT NOT NULL,&#xA;    -- Body can be markdown, plaintext, asciidoc, etc.&#xA;    body TEXT,&#xA;    -- Items can be archived to support soft-deletion&#xA;    isarchived BOOLEAN NOT NULL DEFAULT 0,&#xA;    archivedstatuschangedat TIMESTAMP,&#xA;    -- Items have automatically updating createdat and changedat timestamps&#xA;    createdat TIMESTAMP NOT NULL DEFAULT (unixepoch(&#39;now&#39;, &#39;subsec&#39;)),&#xA;    changedat TIMESTAMP NOT NULL DEFAULT (unixepoch(&#39;now&#39;, &#39;subsec&#39;))&#xA;);&#xA;&#xA;-- The changedat and archivedstatuschangedat fields are automatically updated.&#xA;CREATE TRIGGER updateitemschangedat &#xA;AFTER UPDATE ON items&#xA;BEGIN&#xA;    UPDATE items SET changedat = unixepoch(&#39;now&#39;, &#39;subsec&#39;)&#xA;    WHERE id = NEW.id;&#xA;END;&#xA;&#xA;CREATE TRIGGER updatearchivedstatustimestamp&#xA;AFTER UPDATE OF isarchived ON items&#xA;WHEN NEW.isarchived != OLD.isarchived&#xA;BEGIN&#xA;    UPDATE items &#xA;    SET archivedstatuschangedat = unixepoch(&#39;now&#39;, &#39;subsec&#39;)&#xA;    WHERE id = NEW.id;&#xA;END;&#xA;`]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:release" class="hashtag"><span>#</span><span class="p-category">release</span></a> <a href="http://natknight.xyz/tag:sqlite3" class="hashtag"><span>#</span><span class="p-category">sqlite3</span></a></p>

<p>I wrote a spec for a <a href="https://github.com/nathanielknight/todo-sqlite3">SQLite-based todo database</a> and just release <a href="https://github.com/nathanielknight/todo-sqlite3/releases/tag/v0.1">version 0.1</a>.</p>



<p><a href="http://todotxt.org/">todo.txt</a> is an obvious inspiration, but I wanted to put my data in SQLite for a couple of reasons:</p>
<ul><li>SQLite is <em>very</em> stable, nearly as stable as plain text.</li>
<li>Having your todos in a database opens up possibilities for querying, viewing, and extending that data much more easily than if it&#39;s in plain text.</li>
<li>Having the data in SQLite in particular means multiple apps can interact with the database simultaneously, so I can have a CLI, a web app, and automation scripts touching the same todo list without risking corruption or data loss.</li></ul>

<p>Now that the database schema is ready I just have to build the rest of the app...</p>

<p>The schema (not counting a tagging extension) in full:</p>

<pre><code class="language-sql">-- todo-sqlite3
-- https://github.com/nathanielknight/todo-sqlite3

-- Foreign Key constraints are required.
PRAGMA foreign_keys = ON;


-- Core Items table
CREATE TABLE items (
    id INTEGER PRIMARY KEY,
    -- Every item has a title (not necessarily unique)
    title TEXT NOT NULL,
    -- Body can be markdown, plaintext, asciidoc, etc.
    body TEXT,
    -- Items can be archived to support soft-deletion
    is_archived BOOLEAN NOT NULL DEFAULT 0,
    archived_status_changed_at TIMESTAMP,
    -- Items have automatically updating created_at and changed_at timestamps
    created_at TIMESTAMP NOT NULL DEFAULT (unixepoch(&#39;now&#39;, &#39;subsec&#39;)),
    changed_at TIMESTAMP NOT NULL DEFAULT (unixepoch(&#39;now&#39;, &#39;subsec&#39;))
);

-- The changed_at and archived_status_changed_at fields are automatically updated.
CREATE TRIGGER update_items_changed_at 
AFTER UPDATE ON items
BEGIN
    UPDATE items SET changed_at = unixepoch(&#39;now&#39;, &#39;subsec&#39;)
    WHERE id = NEW.id;
END;

CREATE TRIGGER update_archived_status_timestamp
AFTER UPDATE OF is_archived ON items
WHEN NEW.is_archived != OLD.is_archived
BEGIN
    UPDATE items 
    SET archived_status_changed_at = unixepoch(&#39;now&#39;, &#39;subsec&#39;)
    WHERE id = NEW.id;
END;
</code></pre>
]]></content:encoded>
      <guid>http://natknight.xyz/todo-sqlite3-v0-1</guid>
      <pubDate>Thu, 27 Feb 2025 05:57:45 +0000</pubDate>
    </item>
    <item>
      <title>Release: llm-questioncache</title>
      <link>http://natknight.xyz/release-llm-questioncache</link>
      <description>&lt;![CDATA[#python #llm #embeddings #release #simonwillison&#xA;&#xA;I just released version 0.1 of a plugin for Simon Willison&#39;s llm called llm-questioncache. It lets you send questions to your default LLM with a system prompt that elicits short, to-the-point answers. It also maintains a cache of answers locally so that you only have to hit the LLM once for each bit of esoteric knowledge.&#xA;&#xA;!--more--&#xA;&#xA;It uses embeddings of each question to find similar questions so that (for example) if you ask&#xA;&#xA;  How do you compare two branches in git&#xA;&#xA;and&#xA;&#xA;  How to compare different branches in git&#xA;&#xA;you&#39;ll get the same answer.&#xA;&#xA;If you&#39;ve already got LLM installed you can try it out with &#xA;&#xA;llm install llm-questioncache&#xA;&#xA;Here&#39;s the PyPI package:&#xA;https://pypi.org/project/llm-questioncache/&#xA;&#xA;And here&#39;s the source code:&#xA;https://github.com/nathanielknight/llm-questioncache&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:python" class="hashtag"><span>#</span><span class="p-category">python</span></a> <a href="http://natknight.xyz/tag:llm" class="hashtag"><span>#</span><span class="p-category">llm</span></a> <a href="http://natknight.xyz/tag:embeddings" class="hashtag"><span>#</span><span class="p-category">embeddings</span></a> <a href="http://natknight.xyz/tag:release" class="hashtag"><span>#</span><span class="p-category">release</span></a> <a href="http://natknight.xyz/tag:simonwillison" class="hashtag"><span>#</span><span class="p-category">simonwillison</span></a></p>

<p>I just released version 0.1 of a plugin for Simon Willison&#39;s <a href="https://github.com/simonw/llm"><code>llm</code></a> called <a href="https://github.com/nathanielknight/llm-questioncache"><code>llm-questioncache</code></a>. It lets you send questions to your default LLM with a system prompt that elicits short, to-the-point answers. It also maintains a cache of answers locally so that you only have to hit the LLM once for each bit of esoteric knowledge.</p>



<p>It uses <a href="https://vickiboykis.com/what_are_embeddings/">embeddings</a> of each question to find similar questions so that (for example) if you ask</p>

<blockquote><p>How do you compare two branches in git</p></blockquote>

<p>and</p>

<blockquote><p>How to compare different branches in git</p></blockquote>

<p>you&#39;ll get the same answer.</p>

<p>If you&#39;ve already got LLM installed you can try it out with</p>

<pre><code>llm install llm-questioncache
</code></pre>

<p>Here&#39;s the PyPI package:
<a href="https://pypi.org/project/llm-questioncache/">https://pypi.org/project/llm-questioncache/</a></p>

<p>And here&#39;s the source code:
<a href="https://github.com/nathanielknight/llm-questioncache">https://github.com/nathanielknight/llm-questioncache</a></p>
]]></content:encoded>
      <guid>http://natknight.xyz/release-llm-questioncache</guid>
      <pubDate>Sun, 09 Feb 2025 05:59:09 +0000</pubDate>
    </item>
    <item>
      <title>A TiddlyWiki Server in Rust</title>
      <link>http://natknight.xyz/a-tiddlywiki-server-in-rust</link>
      <description>&lt;![CDATA[#tiddlywiki #rust #selfhosting #release&#xA;&#xA;I just published the first (v0.1.0) release of tiddly-wiki-server, which implements the TiddlyWiki WebServer API in Rust using Axum, SerDe, and TiddlyWiki.&#xA;&#xA;!--more--&#xA;&#xA;Motivation&#xA;&#xA;One might ask why a new TiddlyWiki server is necessary, since&#xA;&#xA;TiddlyWiki5 includes a first-party NodeJS web server, and&#xA;one of TiddlyWiki&#39;s beautiful features is that it works as as static HTML file.&#xA;&#xA;These are valid points. I confess, this project fulfills quite a narrow use case: I like to self-host my tools on a small, cheap VPS, and the first-party NodeJS server consumes about 100MB of RAM. This isn&#39;t huge, but it&#39;s a decent chunk of my available resources. This server consumes much less (about 10MB, and that&#39;s before I&#39;ve done anything to optimize it).&#xA;&#xA;This was also a project that let me combine two technologies that I like an awful lot, so if it seems self-indulgent, well... maybe it is. &#xA;&#xA;Components&#xA;&#xA;The server makes use of some very nice Crates; I&#39;ll mention some of the big ones:&#xA;&#xA;dl&#xA;dt&#xA;  a href=&#34;https://crates.io/crates/axum&#34;axum/a, a web framework&#xA;/dt&#xA;dd&#xA;I&#39;ve tried a number of Rust web frameworks (Tide, Rocket, simple-http-server); this one&#39;s the first one I feel like I really understood and was productive with (though that might also just be that I&#39;m slowly getting better at Rust). Of particular note is that Axum is compatible with a href=&#34;https://crates.io/crates/tower-http&#34;tower-http/a , so many services and middlewares that you might want already exist.&#xA;/dd&#xA;&#xA;dt&#xA;  a href=&#34;https://crates.io/crates/rusqlite&#34;rusqlite/a, a SQLite binding/a&#xA;/dt&#xA;dd&#xA;I use SQLite for most of my tiny side projects; this one&#39;s no exception. The TiddlyWiki back end mostly treats tiddlers as opaque bags of objects, so the database is little more than a key-value store.&#xA;/dd&#xA;&#xA;dt&#xA;  a href=&#34;https://crates.io/crates/serdejson&#34;serdejson/a, a loosely-typed JSON interface&#xA;/dt&#xA;dd&#xA;If you&#39;re reading about Rust you&#39;re probably familiar with serde, but since I wanted to retain TiddlyWiki&#39;s fairly open schema I needed an ergonomic way to work with un-typed JSON objects.&#xA;/dd&#xA;&#xA;/dl&#xA;&#xA;Future Work&#xA;&#xA;There are lots of ways this project could be added or improved:&#xA;&#xA;More testing; I want this server to be feature-compatible with the first party server.&#xA;User authentication and access control&#xA;Streaming large responses to keep memory small&#xA;&#xA;If any of that sounds interesting to you, pull requests and bug reports are very much welcome!&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:tiddlywiki" class="hashtag"><span>#</span><span class="p-category">tiddlywiki</span></a> <a href="http://natknight.xyz/tag:rust" class="hashtag"><span>#</span><span class="p-category">rust</span></a> <a href="http://natknight.xyz/tag:selfhosting" class="hashtag"><span>#</span><span class="p-category">selfhosting</span></a> <a href="http://natknight.xyz/tag:release" class="hashtag"><span>#</span><span class="p-category">release</span></a></p>

<p>I just published the first (v0.1.0) release of <a href="https://github.com/nathanielknight/tiddly-wiki-server">tiddly-wiki-server</a>, which implements the <a href="https://tiddlywiki.com/#WebServer%20API">TiddlyWiki WebServer API</a> in Rust using Axum, SerDe, and TiddlyWiki.</p>



<h2 id="motivation" id="motivation">Motivation</h2>

<p>One might ask why a new TiddlyWiki server is necessary, since</p>
<ul><li>TiddlyWiki5 includes a first-party NodeJS web server, and</li>
<li>one of TiddlyWiki&#39;s beautiful features is that it works as as static HTML file.</li></ul>

<p>These are valid points. I confess, this project fulfills quite a narrow use case: I like to self-host my tools on a small, cheap VPS, and the first-party NodeJS server consumes about 100MB of RAM. This isn&#39;t huge, but it&#39;s a decent chunk of my available resources. This server consumes much less (about 10MB, and that&#39;s before I&#39;ve done anything to optimize it).</p>

<p>This was also a project that let me combine two technologies that I like an awful lot, so if it seems self-indulgent, well... maybe it is.</p>

<h2 id="components" id="components">Components</h2>

<p>The server makes use of some very nice Crates; I&#39;ll mention some of the big ones:</p>

<dl>
<dt>
  <a href="https://crates.io/crates/axum">axum</a>, a web framework
</dt>
<dd>
I&#39;ve tried a number of Rust web frameworks (Tide, Rocket, simple-http-server); this one&#39;s the first one I feel like I really understood and was productive with (though that might also just be that I&#39;m slowly getting better at Rust). Of particular note is that Axum is compatible with <a href="https://crates.io/crates/tower-http">tower-http</a> , so many services and middlewares that you might want already exist.
</dd>

<dt>
  <a href="https://crates.io/crates/rusqlite">rusqlite</a>, a SQLite binding</a>
</dt>
<dd>
I use SQLite for most of my tiny side projects; this one&#39;s no exception. The TiddlyWiki back end mostly treats tiddlers as opaque bags of objects, so the database is little more than a key-value store.
</dd>

<dt>
  <a href="https://crates.io/crates/serde_json">serde_json</a>, a loosely-typed JSON interface
</dt>
<dd>
If you&#39;re reading about Rust you&#39;re probably familiar with serde, but since I wanted to retain TiddlyWiki&#39;s fairly open schema I needed an ergonomic way to work with un-typed JSON objects.
</dd>

</dl>

<h2 id="future-work" id="future-work">Future Work</h2>

<p>There are lots of ways this project could be added or improved:</p>
<ul><li>More testing; I want this server to be feature-compatible with the first party server.</li>
<li>User authentication and access control</li>
<li>Streaming large responses to keep memory small</li></ul>

<p>If any of that sounds interesting to you, pull requests and bug reports are very much welcome!</p>
]]></content:encoded>
      <guid>http://natknight.xyz/a-tiddlywiki-server-in-rust</guid>
      <pubDate>Mon, 27 Jun 2022 07:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>