<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ...</title>
    <description>The latest articles on DEV Community by ... (@terminalkitten).</description>
    <link>https://dev.to/terminalkitten</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F304816%2Fc86b2148-2371-4e92-94d7-b99ccc5eaf2c.jpeg</url>
      <title>DEV Community: ...</title>
      <link>https://dev.to/terminalkitten</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/terminalkitten"/>
    <language>en</language>
    <item>
      <title>pledge: a fast double-entry ledger inside PostgreSQL, ready for Django</title>
      <dc:creator>...</dc:creator>
      <pubDate>Thu, 12 Nov 2026 15:54:04 +0000</pubDate>
      <link>https://dev.to/terminalkitten/pledge-a-fast-double-entry-ledger-inside-postgresql-ready-for-django-3b9</link>
      <guid>https://dev.to/terminalkitten/pledge-a-fast-double-entry-ledger-inside-postgresql-ready-for-django-3b9</guid>
      <description>&lt;p&gt;pledge is a double-entry ledger that runs inside PostgreSQL, with a Django package on top. If your app moves money, credits or points, it keeps the books for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Balanced by design.&lt;/strong&gt; Every transfer writes two entries that sum to zero.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;History built in.&lt;/strong&gt; Each entry stores the running balance, so you can ask for any past balance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe retries.&lt;/strong&gt; Send your own transfer id; the same transfer twice is booked once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tamper-resistant.&lt;/strong&gt; Ledger rows can't be deleted or edited; accounts are closed, never removed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast.&lt;/strong&gt; Written in Rust, one SQL statement per transfer or batch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Django first
&lt;/h2&gt;

&lt;p&gt;With django-pledge the ledger looks like ordinary Django models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip install django-pledge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="no"&gt;INSTALLED_APPS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"django_pledge"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;decimal&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django_pledge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Transfer&lt;/span&gt;

&lt;span class="n"&gt;cash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;alice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allow_negative_balance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;cash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"10.00"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bulk_create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to_account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"2.50"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from_account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to_account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# one atomic batch, one statement&lt;/span&gt;

&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refresh_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt;          &lt;span class="c1"&gt;# Decimal('8.50')&lt;/span&gt;
&lt;span class="n"&gt;alice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;history&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;# every entry, with its running balance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Overdraw Alice's account and you get a typed exception, &lt;code&gt;NegativeBalanceNotAllowed&lt;/code&gt;, with the account id attached. Store a &lt;code&gt;TransferId&lt;/code&gt; with your own record before you call the ledger, and a retry books nothing twice. Link your own models with a normal &lt;code&gt;ForeignKey&lt;/code&gt; to &lt;code&gt;pledge.Account&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Or plain SQL
&lt;/h2&gt;

&lt;p&gt;Django is optional. Everything is a function in the &lt;code&gt;pledge&lt;/code&gt; schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="no"&gt;EXTENSION&lt;/span&gt; &lt;span class="n"&gt;pledge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pledge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bank'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'USD'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pledge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'alice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'USD'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allow_negative_balance&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pledge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pla_…bank'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'pla_…alice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;100.00&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pledge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accounts_view&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pledge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;-- every check should say ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fast, and checked
&lt;/h2&gt;

&lt;p&gt;pledge grew out of &lt;a href="https://github.com/pgr0ss/pgledger" rel="noopener noreferrer"&gt;pgledger&lt;/a&gt; by &lt;a href="https://github.com/pgr0ss" rel="noopener noreferrer"&gt;pgr0ss&lt;/a&gt;, and we still benchmark against it:&lt;/p&gt;

&lt;p&gt;pledge is about 1.5 times faster per transfer and about 2 times faster for batches. Speed only counts if the books stay straight, so pledge also passes a bank test where connections are killed mid-transfer, a model-based test, and a replay of a real bank's million transactions.&lt;/p&gt;

&lt;p&gt;It's a young project, so the API may still change before 1.0. It runs on PostgreSQL 17 and 18.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://pgpledge.github.io/pledge/" rel="noopener noreferrer"&gt;https://pgpledge.github.io/pledge/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Tutorial, build a small currency exchange in Django:
&lt;a href="https://pgpledge.github.io/pledge/django/exchange/" rel="noopener noreferrer"&gt;https://pgpledge.github.io/pledge/django/exchange/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repository: &lt;a href="https://github.com/pgpledge/pledge" rel="noopener noreferrer"&gt;https://github.com/pgpledge/pledge&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/django-pledge/" rel="noopener noreferrer"&gt;https://pypi.org/project/django-pledge/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clone the repo and run &lt;code&gt;just example&lt;/code&gt; to click through the exchange in your browser. Feedback and issues are very welcome.&lt;/p&gt;

</description>
      <category>ledger</category>
      <category>django</category>
      <category>postgres</category>
    </item>
    <item>
      <title>tackline: Backseat driving for your coding agent.</title>
      <dc:creator>...</dc:creator>
      <pubDate>Mon, 26 Oct 2026 08:23:51 +0000</pubDate>
      <link>https://dev.to/terminalkitten/tackline-backseat-driving-for-your-coding-agent-3al9</link>
      <guid>https://dev.to/terminalkitten/tackline-backseat-driving-for-your-coding-agent-3al9</guid>
      <description>&lt;p&gt;Coding agents got good at writing code. Telling them exactly what to change is still clumsy, so I built a small tool for that part: &lt;a href="https://github.com/terminalkitten/tackline" rel="noopener noreferrer"&gt;tackline&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Most of my day with Claude Code isn't typing prompts from scratch. It's reading what the agent just did, spotting what's off, and sending it back for another pass. That loop is where the friction lives.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fry38n6nsvub8095y0uh8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fry38n6nsvub8095y0uh8.gif" alt="tackline in ten seconds: select code, add a note, review the session, copy the prompt" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: prompts full of paths and line numbers
&lt;/h2&gt;

&lt;p&gt;You review a diff and see five things. The loop in the matcher should be an iterator chain. That helper already exists, use it. Don't touch the public function signature. And so on.&lt;/p&gt;

&lt;p&gt;Then you turn those thoughts into a prompt. You copy a file path, look up the line numbers, paste a snippet so the agent knows which loop you mean, and write the instruction. Five times. By the third one, you're writing "also the thing in utils" and hoping the agent guesses right.&lt;/p&gt;

&lt;p&gt;The information you need is all on your screen while you're reading the code. The prompt is just a worse copy of it, assembled by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  What tackline does
&lt;/h2&gt;

&lt;p&gt;tackline is a terminal app that lets you point at code and write what the agent should do there. It turns all those notes into one prompt.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;tackline&lt;/code&gt; (or &lt;code&gt;tack&lt;/code&gt;) in a repository. It opens on the git diff if you have uncommitted changes, otherwise on a file browser.&lt;/li&gt;
&lt;li&gt;Select a line or a block of code with &lt;code&gt;V&lt;/code&gt;, &lt;code&gt;v&lt;/code&gt;, Shift+arrows or the mouse, and press &lt;code&gt;c&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Write the instruction and press Enter. Notes collect in a named session.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;3&lt;/code&gt; to see the session, then &lt;code&gt;y&lt;/code&gt; to copy it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F06o6gnkjunizhqcvw78m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F06o6gnkjunizhqcvw78m.png" alt="The note popup: the location, the selected code, and the instruction, with Tab to pick the session" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you paste into your agent looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Search speedup&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="sb"&gt;`src/matcher.rs:3-7`&lt;/span&gt;
   &lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;rs
&lt;/span&gt;       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="nf"&gt;.contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;```&lt;/span&gt;
   replace the loop with an iterator chain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every note carries its file, its lines and the code as it is right now. The agent doesn't have to guess which loop you meant, and you never typed a path.&lt;/p&gt;

&lt;p&gt;Before you copy, the Session view shows every note with its code in prompt order. You can reorder, edit or drop notes before the agent sees them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7bei3eyosnp0drczrs87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7bei3eyosnp0drczrs87.png" alt="The Session view: each note with its location, code and instruction, in prompt order" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes follow the code
&lt;/h2&gt;

&lt;p&gt;Steering an agent happens in rounds: you note things, the agent edits the files, you look again and note more. Line numbers break the moment the agent touches a file.&lt;/p&gt;

&lt;p&gt;So each note remembers the code it was attached to, not just its line numbers. When lines are inserted above it, or the code moves within the file, the note moves with it. If the code is gone entirely, the note is marked stale and left out of the prompt, with a warning so you know.&lt;/p&gt;

&lt;p&gt;Sessions are saved as you go, in readable JSON files in the repo. Close the app, come back tomorrow, and your notes are still there.&lt;/p&gt;

&lt;p&gt;In the editor, noted code is tinted, with a marker in the gutter. You can see at a glance what you've already flagged, and press Enter on a noted line to read the whole note.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxkjnjnx29lb74j5qwt3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxkjnjnx29lb74j5qwt3k.png" alt="The Files view: noted code tinted yellow, with gutter markers and the note under the cursor in the bottom border" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Works with any agent
&lt;/h2&gt;

&lt;p&gt;The output is plain Markdown, so tackline doesn't care which agent you use. Press &lt;code&gt;y&lt;/code&gt; to copy it, or hand it over from the shell:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Hand over the prompt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;`tackline export \&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex&lt;/td&gt;
&lt;td&gt;{% raw %}&lt;code&gt;codex exec "$(tackline export)"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;opencode&lt;/td&gt;
&lt;td&gt;&lt;code&gt;opencode run "$(tackline export)"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aider&lt;/td&gt;
&lt;td&gt;&lt;code&gt;aider --message "$(tackline export)"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cursor&lt;/td&gt;
&lt;td&gt;paste it into the chat, or &lt;code&gt;agent -p "$(tackline export)"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For Claude Code there's an extra: a small skill file turns your active session into a &lt;code&gt;/tackline&lt;/code&gt; slash command, so the agent reads your notes itself.&lt;/p&gt;

&lt;p&gt;And if you'd rather click than learn keys, &lt;code&gt;tackline serve&lt;/code&gt; opens the same tool in your browser, on localhost only, working on the same files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fttucjgjix03srbt6ea3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fttucjgjix03srbt6ea3u.png" alt="The web version: the same files, notes and session in the browser" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Steering, not reviewing
&lt;/h2&gt;

&lt;p&gt;I first tried code review tools for this, and they didn't fit. Review tools are built around verdicts: approve, request changes, resolve the thread. That's the wrong shape for working with an agent.&lt;/p&gt;

&lt;p&gt;A tackline note is an instruction. "Make this async." "Use this helper instead." "This is the pattern to follow." "Don't touch this signature." Some notes are about code the agent wrote, others point at existing code it should read first. Together they're a brief, not a review.&lt;/p&gt;

&lt;p&gt;That's also why it works before a task, not only after one. Browse a codebase, pin the places that matter, and give the agent a prompt that already knows where to look. If you work on a fork, &lt;code&gt;tackline --base upstream/main&lt;/code&gt; shows only your changes, so you can annotate exactly what differs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9xvshr3b6cgcawl9cvnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9xvshr3b6cgcawl9cvnp.png" alt="The Diff view: notes attach to the new side of the diff" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;tackline is free and MIT licensed, with prebuilt binaries for macOS, Linux and Windows. No Rust needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS and Linux&lt;/span&gt;
curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-LsSf&lt;/span&gt; https://github.com/terminalkitten/tackline/releases/latest/download/tackline-installer.sh | sh

&lt;span class="c"&gt;# Homebrew&lt;/span&gt;
brew tap terminalkitten/tackline https://github.com/terminalkitten/tackline
brew &lt;span class="nb"&gt;install &lt;/span&gt;terminalkitten/tackline/tackline

&lt;span class="c"&gt;# Windows (PowerShell)&lt;/span&gt;
powershell &lt;span class="nt"&gt;-ExecutionPolicy&lt;/span&gt; Bypass &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"irm https://github.com/terminalkitten/tackline/releases/latest/download/tackline-installer.ps1 | iex"&lt;/span&gt;

&lt;span class="c"&gt;# With Rust&lt;/span&gt;
cargo &lt;span class="nb"&gt;install &lt;/span&gt;tackline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;tack&lt;/code&gt; in any repository, select some code and press &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docs: &lt;a href="https://terminalkitten.github.io/tackline/" rel="noopener noreferrer"&gt;terminalkitten.github.io/tackline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/terminalkitten/tackline" rel="noopener noreferrer"&gt;github.com/terminalkitten/tackline&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Crate: &lt;a href="https://crates.io/crates/tackline" rel="noopener noreferrer"&gt;crates.io/crates/tackline&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a young project, so I'd love to hear how you steer your agents and what's missing. Open an issue, or tell me where it got in your way.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>coding</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <title>dokk: a tiny docs generator I built for my own Python libraries</title>
      <dc:creator>...</dc:creator>
      <pubDate>Mon, 19 Oct 2026 20:30:26 +0000</pubDate>
      <link>https://dev.to/terminalkitten/dokk-a-tiny-docs-generator-in-python-522g</link>
      <guid>https://dev.to/terminalkitten/dokk-a-tiny-docs-generator-in-python-522g</guid>
      <description>&lt;p&gt;I maintain a handful of small Python libraries. None of them is big, but every one of them needs documentation: how to install it, a quick start, a few guides, the options. And every time, setting up the docs took longer than it should.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;The tools I tried are good, but none of them fit a small library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sphinx&lt;/strong&gt; is powerful and made for large projects. For a library with ten pages, I spent more time on &lt;code&gt;conf.py&lt;/code&gt;, extensions and reStructuredText than on the docs themselves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MkDocs&lt;/strong&gt; comes closest, and most projects use it with Material for MkDocs. It is a great, complete theme, but this one is personal: the Material look never did it for me. I wanted something quieter and cleaner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docusaurus, Starlight and VitePress&lt;/strong&gt; produce beautiful sites, but they bring a JavaScript toolchain into a Python project, just for the docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I wanted was simple: &lt;code&gt;pip install&lt;/code&gt; one thing, write Markdown in a &lt;code&gt;docs/&lt;/code&gt; folder, push, and get a site that looks good and has search and dark mode, without assembling anything. I also wanted a tool small enough that I could read all of it.&lt;/p&gt;

&lt;p&gt;That became &lt;a href="https://terminalkitten.github.io/dokk/" rel="noopener noreferrer"&gt;dokk&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is about 2,000 lines of Python code. You give it a folder of Markdown and it writes plain HTML: a sidebar from your folders, search, dark mode, code highlighting and a set of components, all at build time. There are no plugins to choose and nothing to configure before the first page works.&lt;/p&gt;

&lt;p&gt;It is deliberately not everything. dokk does not generate API docs from docstrings, and there is no plugin system. If you need those, Sphinx and MkDocs are still the right tools. If you want good-looking docs for a small project in ten minutes, read on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tutorial: docs for a small library
&lt;/h2&gt;

&lt;p&gt;We will add docs to a small, made-up library called &lt;strong&gt;slugkit&lt;/strong&gt;, which turns text into URL slugs. Use your own project instead: the steps are the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Install dokk
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"dokk[serve,search]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;serve&lt;/code&gt; adds the dev server with live reload, &lt;code&gt;search&lt;/code&gt; adds full-text search (&lt;a href="https://pagefind.app" rel="noopener noreferrer"&gt;Pagefind&lt;/a&gt;). Both are optional; plain &lt;code&gt;pip install dokk&lt;/code&gt; builds sites without them.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create the site
&lt;/h3&gt;

&lt;p&gt;In the root of your repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dokk init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates four things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dokk.toml                      title and settings
docs/index.md                  the home page
.gitignore                     .dokk/ added (the build output)
.github/workflows/docs.yml     publishes the site to GitHub Pages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;init&lt;/code&gt; never overwrites your files; an existing &lt;code&gt;.gitignore&lt;/code&gt; only gets the &lt;code&gt;.dokk/&lt;/code&gt; line added.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Start writing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dokk serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://127.0.0.1:8002/" rel="noopener noreferrer"&gt;http://127.0.0.1:8002/&lt;/a&gt; and edit &lt;code&gt;docs/index.md&lt;/code&gt;. The page reloads every time you save.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Add pages and folders
&lt;/h3&gt;

&lt;p&gt;Every &lt;code&gt;.md&lt;/code&gt; file is a page, and every folder becomes a group in the sidebar. For slugkit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs/
  index.md
  getting-started/
    index.md
  guides/
    unicode.md
  reference/
    api.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A page's title comes from its first &lt;code&gt;# Heading&lt;/code&gt;, or from front matter, where you can also set its place in the sidebar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Getting&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;started"&lt;/span&gt;
&lt;span class="na"&gt;sidebar&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Links between pages are plain relative Markdown links, such as &lt;code&gt;[the guides](../guides/unicode.md)&lt;/code&gt;. dokk turns them into the right URLs, and tells you when one is broken.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Use components
&lt;/h3&gt;

&lt;p&gt;Components are short Markdown blocks, so your docs stay readable on GitHub and in any editor. The getting-started page of slugkit uses three of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;::install[slugkit]

:::steps
&lt;span class="p"&gt;1.&lt;/span&gt; Install slugkit.
&lt;span class="p"&gt;2.&lt;/span&gt; Import it: &lt;span class="sb"&gt;`from slugkit import slugify`&lt;/span&gt;.
&lt;span class="p"&gt;3.&lt;/span&gt; Call &lt;span class="sb"&gt;`slugify("Hello World")`&lt;/span&gt;.
:::

:::tip
Next, read the &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;guides&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;../guides/unicode.md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;.
:::
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;::install&lt;/code&gt; shows the pip, uv and poetry commands as tabs, and remembers which one the reader picked across the whole site. There are also tabs, cards, callouts, file trees, badges, images, and components for AI projects such as model cards, chats and tool schemas. The &lt;a href="https://terminalkitten.github.io/dokk/guides/components/" rel="noopener noreferrer"&gt;components guide&lt;/a&gt; shows them all.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Check before you publish
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dokk check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This builds the site and reports broken links, missing anchors and pages without a title, each with the file it is in. It is also the first step of the GitHub workflow, so a broken link never reaches your live docs.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Configure the site
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dokk.toml&lt;/code&gt; needs only a title. A few more lines make it yours:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"slugkit"&lt;/span&gt;
&lt;span class="py"&gt;site_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://you.github.io/slugkit/"&lt;/span&gt;

&lt;span class="nn"&gt;[theme]&lt;/span&gt;
&lt;span class="py"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"blue"&lt;/span&gt;

&lt;span class="nn"&gt;[links]&lt;/span&gt;
&lt;span class="py"&gt;github&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/you/slugkit"&lt;/span&gt;
&lt;span class="py"&gt;edit_url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/you/slugkit/edit/main/docs/{path}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;site_url&lt;/code&gt; gives you a sitemap and correct links on GitHub Pages. &lt;code&gt;color&lt;/code&gt; picks one of the shadcn/ui accent colors; try them all on the &lt;a href="https://terminalkitten.github.io/dokk/guides/themes/showcase/" rel="noopener noreferrer"&gt;theme showcase&lt;/a&gt;. The links add a GitHub icon in the header and an "Edit this page" link under every page.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Publish
&lt;/h3&gt;

&lt;p&gt;Push to GitHub, then go to &lt;strong&gt;Settings → Pages&lt;/strong&gt; and set &lt;strong&gt;Source&lt;/strong&gt; to &lt;strong&gt;GitHub Actions&lt;/strong&gt;. The workflow from &lt;code&gt;dokk init&lt;/code&gt; builds the site on every push to &lt;code&gt;main&lt;/code&gt; and publishes it. That's it: your docs are live.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optional: keep your Markdown tidy
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dokk format&lt;/code&gt; formats every page, so lists, tables and spacing look the same everywhere. It knows dokk's Markdown, so your components, front matter and tables stay intact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"dokk[format]"&lt;/span&gt;
dokk format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dokk format --check&lt;/code&gt; changes nothing and fails when a page is not formatted, which makes it a good fit for CI or a pre-commit hook. Under the hood it is &lt;a href="https://github.com/hukkin/mdformat" rel="noopener noreferrer"&gt;mdformat&lt;/a&gt; with &lt;a href="https://pypi.org/project/mdformat-directives/" rel="noopener noreferrer"&gt;mdformat-directives&lt;/a&gt;, a plugin I wrote alongside dokk.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A sidebar from your folders, or arranged by hand in &lt;code&gt;dokk.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Search, dark mode and code highlighting, with no JavaScript framework.&lt;/li&gt;
&lt;li&gt;Plain HTML with every asset bundled: no CDN, no tracking. It works on any static host.&lt;/li&gt;
&lt;li&gt;A Markdown copy of every page and an optional &lt;code&gt;llms.txt&lt;/code&gt;, so AI tools can read your docs too.&lt;/li&gt;
&lt;li&gt;Fast builds: a thousand pages in about a second and a half.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://terminalkitten.github.io/dokk/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;, built with dokk itself&lt;/li&gt;
&lt;li&gt;&lt;a href="https://terminalkitten.github.io/dokk/getting-started/" rel="noopener noreferrer"&gt;Quick start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://terminalkitten.github.io/dokk/guides/components/" rel="noopener noreferrer"&gt;Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://terminalkitten.github.io/dokk/examples/" rel="noopener noreferrer"&gt;Example pages&lt;/a&gt;: a CLI tool, a library reference, a changelog, an FAQ and AI projects&lt;/li&gt;
&lt;li&gt;&lt;a href="https://terminalkitten.github.io/dokk/guides/themes/showcase/" rel="noopener noreferrer"&gt;Theme showcase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/terminalkitten/dokk" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and &lt;a href="https://pypi.org/project/dokk/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://basecoatui.com" rel="noopener noreferrer"&gt;Basecoat&lt;/a&gt;, the components and styles behind dokk's look&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pagefind.app" rel="noopener noreferrer"&gt;Pagefind&lt;/a&gt;, the static search engine dokk uses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;dokk is young, so I would love to hear how it works for your project. Open an issue on GitHub with what you miss or what got in your way, or send a pull request.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>documentation</category>
      <category>python</category>
    </item>
  </channel>
</rss>
