<?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>markdown on S Anand</title>
    <link>https://www.s-anand.net/blog/tag/markdown/</link>
    <description>Recent content in markdown on S Anand</description>
    <generator>Hugo -- 0.156.0</generator>
    <language>en-us</language>
    <lastBuildDate>Sat, 16 May 2026 13:32:06 +0800</lastBuildDate>
    <atom:link href="https://www.s-anand.net/blog/tag/markdown/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Google Meet captions as a local transcript recorder</title>
      <link>https://www.s-anand.net/blog/google-meet-captions-local-transcript-recorder/</link>
      <pubDate>Sat, 16 May 2026 13:32:06 +0800</pubDate>
      <guid>https://www.s-anand.net/blog/google-meet-captions-local-transcript-recorder/</guid>
      <description>&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2026-05-15-google-meet-captions-tool.avif&#34;&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m a man of simple needs. All I want is: when I&amp;rsquo;m on &lt;a href=&#34;https://meet.google.com/&#34;&gt;Google Meet&lt;/a&gt;, I turn on captions. I wanted to click a bookmarklet and save those captions into a local Markdown file. (So that an AI agent can guide me from it.)&lt;/p&gt;
&lt;p&gt;Hence, &lt;a href=&#34;https://tools.s-anand.net/gmeetcaptions/&#34;&gt;Google Meet Captions&lt;/a&gt;. The code is in &lt;a href=&#34;https://github.com/sanand0/tools/tree/main/gmeetcaptions&#34;&gt;&lt;code&gt;gmeetcaptions/&lt;/code&gt;&lt;/a&gt;. Drag the button to your bookmarks bar. Join a Meet. Turn on captions. Click it.&lt;/p&gt;
&lt;p&gt;You get a tiny panel with two buttons: &lt;strong&gt;Copy&lt;/strong&gt; and &lt;strong&gt;Start Recording&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sanand0/tools/blob/main/gmeetcaptions/gmeetcaptions.js&#34;&gt;The bookmarklet&lt;/a&gt; writes this kind of Markdown:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gh&#34;&gt;# Meeting title
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; **Meeting code**: abc-defg-hij
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; **Started**: 5/15/2026, 8:00:00 AM
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; **Participants**: Alice, Bob, Carol
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Alice [0:12]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Good morning everyone.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;gu&#34;&gt;## Bob [0:18]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Let&amp;#39;s get started with the agenda.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. No server. No extension. No login. No API. Just a &lt;a href=&#34;https://github.com/sanand0/tools/blob/main/gmeetcaptions/index.html&#34;&gt;bookmarklet page&lt;/a&gt;, a &lt;a href=&#34;https://github.com/sanand0/tools/blob/main/gmeetcaptions/script.js&#34;&gt;script&lt;/a&gt;, and local browser APIs.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;BUT&lt;/strong&gt;: Google Meet captions are live and unstable.&lt;/p&gt;
&lt;p&gt;A sentence may appear as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mic, so,
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then a second later become:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mic, So that&amp;#39;s a new person. Okay.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then become:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mic, So that&amp;#39;s a new person. Okay. Hey. oh, but,
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If I simply append every change, the transcript becomes garbage. So the bookmarklet keeps updating the active speaker turn until it becomes stable. The implementation uses a &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver&#34;&gt;&lt;code&gt;MutationObserver&lt;/code&gt;&lt;/a&gt; plus a one-second polling fallback. After four unchanged polls, it treats the turn as final.&lt;/p&gt;
&lt;p&gt;The tests are in &lt;a href=&#34;https://github.com/sanand0/tools/blob/main/gmeetcaptions/gmeetcaptions.test.js&#34;&gt;&lt;code&gt;gmeetcaptions.test.js&lt;/code&gt;&lt;/a&gt;, using an anonymized fixture at &lt;a href=&#34;https://github.com/sanand0/tools/blob/main/gmeetcaptions/__fixtures__/captions-anonymized.html&#34;&gt;&lt;code&gt;__fixtures__/captions-anonymized.html&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;BUT #2&lt;/strong&gt;: Google Meet&amp;rsquo;s DOM is not a public API. Class names like &lt;code&gt;.nMcdL&lt;/code&gt;, &lt;code&gt;.NWpY1d&lt;/code&gt;, and &lt;code&gt;.ygicle&lt;/code&gt; can vanish overnight.&lt;/p&gt;
&lt;p&gt;So the scraper first tries semantic and structural selectors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[role=&amp;quot;region&amp;quot;][aria-label=&amp;quot;Captions&amp;quot;]&lt;/code&gt; for the captions region&lt;/li&gt;
&lt;li&gt;&lt;code&gt;img[data-iml]&lt;/code&gt; and &lt;code&gt;googleusercontent.com&lt;/code&gt; avatars to identify caption items&lt;/li&gt;
&lt;li&gt;the first &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; as the speaker&lt;/li&gt;
&lt;li&gt;the last non-image &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; as the caption text&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Only then does it fall back to obfuscated class names. That selector strategy is documented in the &lt;a href=&#34;https://github.com/sanand0/tools/blob/main/gmeetcaptions/README.md&#34;&gt;&lt;code&gt;README&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Boring, but also the difference between &amp;ldquo;worked once&amp;rdquo; and &amp;ldquo;might work tomorrow.&amp;rdquo;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The weirdest was Chrome writing to a &lt;code&gt;.md.crswap&lt;/code&gt; file while recording. The file appears unfinished until I click &lt;strong&gt;Stop Recording&lt;/strong&gt;. Then Chrome finalizes it.&lt;/p&gt;
&lt;p&gt;This is good, actually. It means the browser is safely streaming to a local file via the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/File_System_API&#34;&gt;File System Access API&lt;/a&gt;. But it also means: &lt;strong&gt;stop the recorder before trusting the file&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;I captured these bugs and prompts in &lt;a href=&#34;https://github.com/sanand0/tools/blob/main/gmeetcaptions/prompts.md&#34;&gt;&lt;code&gt;prompts.md&lt;/code&gt;&lt;/a&gt;, because future-me will forget. Future-agent, too.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Why bother? Because transcripts are not the output. They are raw material.&lt;/p&gt;
&lt;p&gt;Once a meeting is Markdown, I can ask agents to extract decisions, questions, follow-ups, contradictions, reusable prompts, and blog ideas. I can diff it. Search it. Commit it. Feed it to another workflow.&lt;/p&gt;
&lt;p&gt;Meetings now become the &amp;ldquo;context&amp;rdquo; in context engineering!&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Migrating my blog from WordPress to Hugo</title>
      <link>https://www.s-anand.net/blog/migrating-my-blog-from-wordpress-to-hugo/</link>
      <pubDate>Fri, 02 Jan 2026 12:30:00 +0800</pubDate>
      <guid>https://www.s-anand.net/blog/migrating-my-blog-from-wordpress-to-hugo/</guid>
      <description>&lt;p&gt;In 2009, I migrated from a self-made Perl static site generator to &lt;a href=&#34;https://www.wordpress.org/&#34;&gt;WordPress&lt;/a&gt; because it was slow, WordPress was dynamic and rapidly growing in features, and I wanted to write rather than code. (Also, I had &lt;em&gt;plenty&lt;/em&gt; of time in 2009 for such things!)&lt;/p&gt;
&lt;p&gt;Over the years, problems crept in. Hosting costs ($200/year) for a slow server. No local writing - &lt;a href=&#34;https://www.s-anand.net/blog/wordpress-themes-on-windows-live-writer/&#34;&gt;Windows Live Writer&lt;/a&gt; was dead. I wasn&amp;rsquo;t using most WordPress features. So it was time to migrate back to a static site generator. (Also, I now have &lt;em&gt;plenty&lt;/em&gt; of time for such things!)&lt;/p&gt;
&lt;p&gt;I tried in 2024. But the complexity of the migration was higher than my laziness. (I tried with LLMs. Didn&amp;rsquo;t work.)&lt;/p&gt;
&lt;p&gt;Finally, in Dec 2025, coding agents were good enough to get this done. Codex and Claude Code both doubled their limits for the holidays, and I had no meetings. So, over two days, I joyfully migrated to a static site.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Content is written in Markdown via VS Code and pushed to &lt;a href=&#34;https://github.com/sanand0/blog/&#34;&gt;https://github.com/sanand0/blog/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A GitHub Action &lt;a href=&#34;https://github.com/sanand0/blog/blob/main/.github/workflows/deploy.yml&#34;&gt;&lt;code&gt;deploy.yaml&lt;/code&gt;&lt;/a&gt; publishes to GitHub Pages&lt;/li&gt;
&lt;li&gt;It uses a &lt;a href=&#34;https://github.com/sanand0/blog/blob/main/hugo.toml&#34;&gt;&lt;code&gt;hugo.toml&lt;/code&gt;&lt;/a&gt; configuration with &lt;a href=&#34;https://github.com/sanand0/blog/tree/main/scripts&#34;&gt;supporting scripts&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;re the useful practices I distilled from my prompts.&lt;/p&gt;
&lt;h3 id=&#34;create-a-planmd-before-complex-tasks&#34;&gt;Create a &lt;code&gt;PLAN.md&lt;/code&gt; before complex tasks&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Create a plan in PLAN.md to convert my blog into Markdown-based content I can commit on GitHub and is published via a static site generator retaining the same URLs.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;My website https://s-anand.net/ hosts a WordPress blog at https://s-anand.net/blog/ and I have exported the content as an XML file using the WordPress export tool into sanand.WordPress.2025-12-28.xml. Read it to understand.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Each post and page must become a Markdown file with front-matter containing all metadata (title, date, tags, categories, slug, author, etc). The Markdown must be stored as
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; ./metadata.yml (for site-wide metadata)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; ./posts/yyyy/yyyy-mm-dd-slug.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; ./pages/slug.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;You can browse the site https://s-anand.net/blog/ to see the site structure and all the types of pages that are generated.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;You can also &amp;#34;ssh sanand&amp;#34; to access the server and &lt;span class=&#34;sb&#34;&gt;`cd www/blog/`&lt;/span&gt; to see the WordPress configuration.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Note that some posts / pages have complex content: tables, code, embedded media, shortcodes, JavaScript, etc. Identify all such cases and how to handle them. There may still be edge cases that you don&amp;#39;t know how to handle; list them out. This is a major part of the plan - ensuring that you cover all types of content -- either with a plan to handle it easily and elegantly, or explicitly identifying ALL edge cases and listing them.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Include how to handle images and other media. The WordPress export XML file may not contain the actual media files; identify how to get them. Suggest how to store them - I can store them in the Git repo, or in GitHub releases (needs to be fetched during CI process), or in R2 (direct access like a CDN). I would also like to compress media (e.g. to WebP) for better performance.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I plan to use either of these hosting options. Let me know what you prefer:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; GitHub CI to deploy to GitHub Pages (preferred: it&amp;#39;s free, easy, and reliable).
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; OR, convert locally to static HTML and upload to R2 / CloudFlare pages (priced, more effort, but reliable).
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Suggest a static site generator (SSG) to use. I prefer something FAST and simple. I prefer single-binary SSGs or installation-free SSGs (e.g. via npx, uvx) if possible.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Consider any other requirements I may have missed, e.g. plugin features, SEO, redirects, analytics, comments, search, RSS feeds, sitemaps, etc. Going through the site or the WordPress configuration may help identify these. Suggest how to handle them.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It analyzed my blog: blocks and shortcodes used, plugins, URL structure, etc. and came up with a pretty good plan. Here are some notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Record unresolved edge cases for manual review. (Wise!)&lt;/li&gt;
&lt;li&gt;Prefer raw HTML inside Markdown when conversion would lose fidelity. (Interesting! Also has detailed rules for tables, code, figures, iframes, forms, &amp;hellip;)&lt;/li&gt;
&lt;li&gt;Frontmatter: Required: title, date, lastmod, slug, author, categories, tags, status, draft, canonical, summary/excerpt, comment_status, ping_status. (Um&amp;hellip; too much?)&lt;/li&gt;
&lt;li&gt;Use Hugo (single binary, fast, built-in RSS/sitemap/taxonomies, supports raw HTML and shortcodes) and GitHub Pages via GitHub Actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;rsquo;s &lt;em&gt;no&lt;/em&gt; way I would have thought of all of these!&lt;/p&gt;
&lt;h3 id=&#34;analyze-data-while-planning&#34;&gt;Analyze data while planning&lt;/h3&gt;
&lt;p&gt;Even while it was planning, another thing struck me. I won&amp;rsquo;t use GitHub to serve assets. It bloats the repo. Plus, there&amp;rsquo;s an opportunity to compress better with WebP. So I asked it to analyze my media.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I&amp;#39;ve rsynced &lt;span class=&#34;sb&#34;&gt;`sanand:www/blog/wp-content/uploads/`&lt;/span&gt; to &lt;span class=&#34;sb&#34;&gt;`./uploads/`&lt;/span&gt; locally.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Which uploads are unused in my blog posts / pages. Tell me the number, total size, and save them all in unused-uploads.tsv with columns size, filename.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;If I convert all used images over 10KB to WebP, how much space will I save? (An estimate is fine; I don&amp;#39;t need exact numbers.)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It parsed the WordPress export against my local &lt;code&gt;uploads/&lt;/code&gt;, listed unused uploads (1.7K files of 87MB), and found 515 used files of 34MB. It estimated ~11MB savings from WebP conversion of used images &amp;gt;10KB.&lt;/p&gt;
&lt;h3 id=&#34;edit-planmd-using-the-agent-not-manually&#34;&gt;Edit &lt;code&gt;PLAN.md&lt;/code&gt; using the agent, not manually&lt;/h3&gt;
&lt;p&gt;Editing manually is prone to mistakes, e.g. introducing contradictions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I am fine with Hugo + GitHub Pages.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/blog must remain the subpath - the URL structure must NOT be disturbed. Prefer publishing into a /blog/ folder.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Import old comments (prefer YAML over JSON for easy reading). The new static site will not have dynamic comments; I may switch to Giscus or Utterances later.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;As for media, let&amp;#39;s convert and save WebP versions instead of the originals and commit them directly to the Git repo under uploads/. Only used media should be included.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Revise PLAN.md accordingly. Let me know what other information you need, if any.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Useful lesson: &lt;strong&gt;Let me know what other information you need, if any.&lt;/strong&gt; Life is full of unknown unknowns!&lt;/p&gt;
&lt;p&gt;It did ask if I was OK changing URLs from &lt;code&gt;.jpg|.png&lt;/code&gt; to &lt;code&gt;.webp&lt;/code&gt;, which I confirmed in the next prompt.&lt;/p&gt;
&lt;h3 id=&#34;implement-small-steps-run-and-commit-as-you-go&#34;&gt;Implement small steps, run and commit as you go&lt;/h3&gt;
&lt;p&gt;I know from experience that a single-shot implementation of this size would be too complex today. So I asked for image conversion first.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Now, implement the upload handling. Delete unused uploads (I have backups on the server). Compress JPEGs with 50% quality and PNGs losslessly with 256 colors. Let me know the revised size of assets.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;I am OK with image URLs breaking.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Implement this by writing a script (bash, Python, Node JS - anything is fine, whatever is easiest) that will create an &lt;span class=&#34;sb&#34;&gt;`assets/`&lt;/span&gt; folder with the converted images from the &lt;span class=&#34;sb&#34;&gt;`uploads/`&lt;/span&gt; folder. I will want to re-run this later with some tweaks.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Commit as you go.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having the agent &lt;strong&gt;run the script&lt;/strong&gt; is the most powerful idea in here. If it makes a mistake, it can figure it out and fix itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Commit as you go&lt;/strong&gt; is useful. I can undo changes later. I also efficiently get a sense of the progress and thinking.&lt;/p&gt;
&lt;p&gt;It took a &lt;em&gt;long&lt;/em&gt; time (on GPT 5.2 Codex - Extra High Thinking), wrote a &lt;code&gt;scripts/prepare_assets.py&lt;/code&gt;, switched from ImageMagick to Pillow for better control (strange!), trouble-shooted PNG transparency bugs, ran it, noted that 41 files in my blog that were missing, and committed everything.&lt;/p&gt;
&lt;h3 id=&#34;run-post-mortems-mid-way&#34;&gt;Run post-mortems mid-way&lt;/h3&gt;
&lt;p&gt;Strangely the JPEG files weren&amp;rsquo;t converted. So I asked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Why does the assets/ folder still have some .jpg files, e.g. temperature.jpg? I assumed they&amp;#39;d all be converted to webp.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Because the script follows your latest instruction: it compresses JPEGs and PNGs in-place and keeps their original formats.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OOPS! My mistake. Anyway, I also needed it to convert MP3 to Opus. So&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;ask-for-actionable-exception-reports&#34;&gt;Ask for actionable exception reports&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s have it do all the conversions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Convert all JPEG files to WebP, too, with 50% quality. Use cwebp to convert - it is faster and has better quality.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Let&amp;#39;s also compress audio files to OPUS with ffmpeg using &lt;span class=&#34;sb&#34;&gt;`-c:a libopus -b:a 12k -ac 1 -application voip -vbr on -compression_level 10`&lt;/span&gt;. Modify the script accordingly.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Also modify the script to list missing local uploads/ mentioning the URL on https://s-anand.net/blog/... post or page that references each. Each line should list the missing filename and URL, tab-separated.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But note the last line. It had already identified that some uploads were missing. To &lt;strong&gt;action&lt;/strong&gt; that, I would need a post -&amp;gt; file mapping, which I asked for.&lt;/p&gt;
&lt;h3 id=&#34;delegate-verification-to-the-agent&#34;&gt;Delegate verification to the agent&lt;/h3&gt;
&lt;p&gt;In the exception report, there was an &lt;code&gt;amazoncooliri&lt;/code&gt; file missing. I couldn&amp;rsquo;t find it in the blog XML. So I asked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Double-check the files mentioned in the missing-uploads.tsv. Do these files really exist in the XML? For example, it mentions &amp;#34;amazoncooliri&amp;#34;. But there is no such word in the XML, I think, and uploads/amazoncooliris.jpg (which is probably what it refers to) exists. There may be similar mistakes. Make sure nothing required is missing either.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At first, I checked the code to see why &lt;code&gt;amazoncooliris&lt;/code&gt; became &lt;code&gt;amazoncooliri&lt;/code&gt;. But months of practicing &lt;del&gt;laziness&lt;/del&gt; delegation took over and I had it debug itself.&lt;/p&gt;
&lt;p&gt;Turned out it wrote &lt;code&gt;\\s&lt;/code&gt; instead of &lt;code&gt;\s&lt;/code&gt; which fixed it.&lt;/p&gt;
&lt;h3 id=&#34;accept-that-you-will-make-mistakes&#34;&gt;Accept that you &lt;em&gt;will&lt;/em&gt; make mistakes&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Why are there PNG images in assets? I assumed there wouldn&amp;#39;t be any and all would be WebP files...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It replied:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Because the script only converts &lt;strong&gt;JPEG → WebP&lt;/strong&gt;. For PNGs, it follows your instruction to “compress PNGs losslessly with 256 colors,” so they stay PNG.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OOPS AGAIN! I forgot to ask it to convert PNGs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Convert all PNGs to WebP using cwebp maximal effort with 256 color palette, just like the jpegs. Update, re-run, commit.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;verification-reports-speed-up-reviews&#34;&gt;Verification reports speed up reviews&lt;/h3&gt;
&lt;p&gt;Now for the big one: converting the blog posts.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Now implement the plan in PLAN.md to convert the WordPress XML export to Markdown files with front-matter. Write a Python script with inline dependencies that &lt;span class=&#34;sb&#34;&gt;`uv run`&lt;/span&gt; can execute. Run it and generate all the Markdown files. Verify that everything looks good - especially edge cases.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Make a list of edge cases you could handle that I should verify.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Make a list of any edge cases you couldn&amp;#39;t handle.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Share these as links to https://s-anand.net/blog/.... as well as the local relative paths.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Apart from converting the posts, it generated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reports/edge-cases-unhandled.tsv&lt;/code&gt; &amp;ndash; an exception report&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reports/edge-cases-handled.tsv&lt;/code&gt; &amp;ndash; a verification report&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The verification report was handy. I could see the edge cases (e.g. upload URLs rewritten, iframes/tables/objects/scripts that were retained, WordPress comment blocks removed) and spot check quickly.&lt;/p&gt;
&lt;p&gt;Without this, I would have spent a lot more time reviewing. This gave me &lt;em&gt;confidence&lt;/em&gt; that it had handled edge cases well.&lt;/p&gt;
&lt;h3 id=&#34;generate-easy-to-review-to-review-content&#34;&gt;Generate easy-to-review to review content&lt;/h3&gt;
&lt;p&gt;I find it productive to have the agent generate content that is &lt;em&gt;easy&lt;/em&gt; to review. At this point, I had a bunch of Markdown files that were &lt;em&gt;very&lt;/em&gt; easy for me to scan. So I created an &lt;em&gt;extensive&lt;/em&gt; list of changes:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Drop redundant or unchanging frontmatter. For example:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Retain title, date, lastmod, slug, categories
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; author: sanand is always the same. Drop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; draft: false and status: publish are redundant. Drop both
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; url: is deriable from the slug. Drop. Same for wp_link
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; If tags, excerpt, aliases, etc. are missing, drop them
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Drop meta: entirely
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Drop menu_order, ping_status, comment_status
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Drop wip_guid in favor of wp_id (retain wip_id)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; If I missed any other frontmatter, use the same principles.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Insert the featured image as the first element in the post, instead of the featured_image frontmatter.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Rewrite all the upload links (http://www.s-anand.net/blog/wp-content/uploads/xxx) to relative links to uploads/ (e.g. ../../uploads/xxx).
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Rerun. Commit as you go.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Finally, write a script to detect all links to s-anand.net/ that are not covered by this approach. For example, I have a bunch of direct assets like https://files.s-anand.net/blog/a/mystic-light.mp3 or other non-WordPress pages on my website. Create a TSV report with the link and the source.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PS: I keep editing prompt.md with my prompts. Keep ignoring it.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The last line was because I was also saving my prompts and it kept getting confused why a file it didn&amp;rsquo;t create kept changing 🙂.&lt;/p&gt;
&lt;h3 id=&#34;give-it-all-your-tools&#34;&gt;Give it all your tools&lt;/h3&gt;
&lt;p&gt;I had it install Hugo and run it. (I could have set it up myself, but why bother?)&lt;/p&gt;
&lt;p&gt;I allowed it to &lt;code&gt;ssh&lt;/code&gt; to my server to check logs if needed.&lt;/p&gt;
&lt;p&gt;In both cases, these are tools I would need to build and test. It makes sense to let the agent use them directly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Corrections:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; The relative URLs should be ../../assets/ not ../../uploads/ (my mistake)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; No action required on the file URLs and swf links. I&amp;#39;ll handle those.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Now, use Hugo (install via &lt;span class=&#34;sb&#34;&gt;`mise use -g hugo`&lt;/span&gt;) and generate a static site from the Markdown files.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Ensure that ALL the URLs from https://s-anand.net/blog/... are retained exactly, including URLs posts, pages, categories, tags, author pages, year (or other time period), etc. You can &lt;span class=&#34;sb&#34;&gt;`ssh sanand`&lt;/span&gt; and scan logs if that&amp;#39;ll help.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This will be deployed via GitHub pages. Create the GitHub action workflow to build and deploy the site on every push to main.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Commit as you go.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that I had made a mistake mentioning &lt;code&gt;uploads/&lt;/code&gt; instead of &lt;code&gt;assets/&lt;/code&gt;. This keeps happening.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know &lt;em&gt;any&lt;/em&gt; Hugo, so this was a bold step. But the output would be easy to review (it&amp;rsquo;s a static site), so &lt;strong&gt;more reviewability = more confidence&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After a &lt;em&gt;long&lt;/em&gt; time, it generated the static site. It managed to self-correct a bunch of stuff. For example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;I removed &lt;code&gt;--minify&lt;/code&gt; because inline scripts with &lt;code&gt;&amp;lt;br /&amp;gt;&lt;/code&gt; in &lt;code&gt;posts/2011/2011-05-19-eating-more-for-less.md&lt;/code&gt; break JS minification; HTML builds cleanly without minify.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;prefer-ui-reviews-over-code-reviews-for-ease&#34;&gt;Prefer UI reviews over code reviews for ease&lt;/h3&gt;
&lt;p&gt;In fact, if required, have it &lt;em&gt;build&lt;/em&gt; a throw-away tool to help you review.&lt;/p&gt;
&lt;p&gt;In my case, the output was &lt;em&gt;functional&lt;/em&gt; but ugly. So ugly that I couldn&amp;rsquo;t review it properly. I suggested a few obvious fixes (like broken links) but the main ask was to pick a theme and make it look like my website.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;FYI: I removed mise.toml. Running &lt;span class=&#34;sb&#34;&gt;`mise x hugo -- hugo`&lt;/span&gt; should still work, but feel free to reinstall.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Ensure that ALL LINKS are relative. For example, public/blog/index.html links to https://s-anand.net/blog/tamil-ai/ but I&amp;#39;d like to link to tamil-ai/ instead.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Pick and implement a nice, popular, lightweight theme that&amp;#39;s suitable for blogs.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Include these features. Where possible, use modern, well-supported &amp;amp; popular plugins or themes rather than custom code.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Below the title, have a single line showing the date created (date updated shown only if different from date created), categories with links to category pages, tags with links to tag pages (if any) are present.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Code blocks should be syntax-highlighted.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; At the bottom, include a link to the next and the previous posts (with title).
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Add a footer to all pages that lists
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; All categories with links &amp;amp; post count
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; All year archives with links and post count
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; All pages with links
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Run and test.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;you-can-resume-if-it-hangs-dont-worry-about-context&#34;&gt;You can resume if it hangs. Don&amp;rsquo;t worry about context&lt;/h3&gt;
&lt;p&gt;This took forever and I think Codex crashed or hung or something. So I killed it, resumed, and asked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;It&amp;#39;s been a while... maybe you were stuck? Resume and complete.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It managed to resume. I&amp;rsquo;m not sure if there was some context loss or confusion, but I&amp;rsquo;m learning to worry less.&lt;/p&gt;
&lt;h3 id=&#34;allow-it-design-flexibility&#34;&gt;Allow it design flexibility&lt;/h3&gt;
&lt;p&gt;Internal links were still broken. I didn&amp;rsquo;t know why, nor enough to fix them. So, rather than make a design decision (e.g. always use full / absolute / relative URLs), I let it decide.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;There are several problems due to wrong relative paths. If it will be easier, feel free to switch back to absolute paths for /blog/ to fix them.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Featured image URLs seem wrong. blog/ai-can-be-held-to-account/ links to &amp;#34;/blog/../assets/pig-court.webp&amp;#34; instead of just &amp;#34;../assets/pig-court.webp&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; When I visit /blog/2003/ the CSS is fine but it breaks in /blog/2003/page/2/ -- and the relative links from that page also break.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; The links from the footers in /blog/2003/ point to /2016/ instead of /blog/2016/ for example
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Swap &amp;#34;Next&amp;#34; and &amp;#34;Prev&amp;#34;. &amp;#34;Prev&amp;#34; indicates older posts.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Syntax highlighting of code blocks doesn&amp;#39;t seem to be working. In blog/openai-tts-cost/ I see a single block like this.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;code lang=&amp;#34;bash&amp;#34; class=&amp;#34;language-bash&amp;#34;&amp;gt;curl &amp;#34;https://api.openai.com/v1/organization/usage/audio_speeches?start_time=$(date -d &amp;#39;1 day ago&amp;#39; +%s)&amp;amp;amp;project_ids=$PROJECT_ID&amp;amp;amp;group_by=model&amp;#34; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -H &amp;#34;Authorization: Bearer $OPENAI_ADMIN_KEY&amp;#34; \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -H &amp;#34;Content-Type: application/json&amp;#34;&amp;lt;/code&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It decided to use absolute paths.&lt;/p&gt;
&lt;h3 id=&#34;generate-documentation&#34;&gt;Generate documentation&lt;/h3&gt;
&lt;p&gt;Apart from adding a few more features / fixes, I had it generate a README.md documenting what I would need to run this in the future.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Add featured images as thumbnails to post listings (e.g. blog home, category pages, tag pages, archive pages). Ensure that there is a placeholder (an elegant blank image) if there is no featured image.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Left-align the footer links.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Now, clean-up and add a README.md that explains the structure of the repo, how to build and deploy, etc.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I also had it fix another design error I made. The placeholders I asked for didn&amp;rsquo;t look good.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Skip featured images in post listings, post pages, etc. if they don&amp;#39;t exist. No need for a placeholder.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;ask-for-effort-estimates&#34;&gt;Ask for effort estimates&lt;/h3&gt;
&lt;p&gt;At this point, things were fine. But I was curious if we could refactor a bit.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m concerned if it might mess it up, though. &lt;strong&gt;Effort is a good proxy for errors&lt;/strong&gt;. So I asked it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;How easy are these changes? Just tell me, don&amp;#39;t implement them.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Set it up so that the content/ directory is auto-generated from posts/ without needing to be committed.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Drop the slug: frontmatter and instead, derive it from the filename.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; Embed the comments in the posts as Markdown, clearly distinguished from the content, rather than keep them in comments/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s response:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto-generate &lt;code&gt;content/&lt;/code&gt; from &lt;code&gt;posts/&lt;/code&gt; is moderate effort&amp;hellip;&lt;/li&gt;
&lt;li&gt;Dropping &lt;code&gt;slug&lt;/code&gt; frontmatter is easy if you accept Hugo’s filename‑based slug rules&amp;hellip;&lt;/li&gt;
&lt;li&gt;Embedding comments into each post is moderate effort&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;probe-for-confidence&#34;&gt;Probe for confidence&lt;/h3&gt;
&lt;p&gt;I asked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;What&amp;#39;s Hugo&amp;#39;s filename-based slug rules?
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I didn&amp;rsquo;t read the output. My aim was not to learn. It was more to glance at it, see if (based on my considerable experience in this area) if it looked reasonable. In short, I was &lt;strong&gt;probing for confidence&lt;/strong&gt; &amp;ndash; its &lt;em&gt;and&lt;/em&gt; mine.&lt;/p&gt;
&lt;h3 id=&#34;continue-the-session-for-the-long-tail&#34;&gt;Continue the session for the long tail&lt;/h3&gt;
&lt;p&gt;Normally, I would have created a new session to implement changes and fixes.&lt;/p&gt;
&lt;p&gt;But the session was auto-compacting quite well. So rather than lose context, I had it create a build steps and run &lt;em&gt;several&lt;/em&gt; minor fixes over the next few days. I didn&amp;rsquo;t need to specify the context again and again.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Here&amp;rsquo;re the lessons I distilled from this migration, tagged by whether it&amp;rsquo;s new to me.&lt;/p&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th style=&#34;text-align: right&#34;&gt;#&lt;/th&gt;
          &lt;th&gt;Lesson&lt;/th&gt;
          &lt;th&gt;New?&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;1&lt;/td&gt;
          &lt;td&gt;Create a &lt;code&gt;PLAN.md&lt;/code&gt; before complex tasks&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;2&lt;/td&gt;
          &lt;td&gt;Analyze data while planning&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;3&lt;/td&gt;
          &lt;td&gt;Edit &lt;code&gt;PLAN.md&lt;/code&gt; using the agent, not manually&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;4&lt;/td&gt;
          &lt;td&gt;Implement small steps, run and commit as you go&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;5&lt;/td&gt;
          &lt;td&gt;Run post-mortems mid-way&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;6&lt;/td&gt;
          &lt;td&gt;Ask for actionable exception reports&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;7&lt;/td&gt;
          &lt;td&gt;Delegate verification to the agent&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;8&lt;/td&gt;
          &lt;td&gt;Accept that you &lt;em&gt;will&lt;/em&gt; make mistakes&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;9&lt;/td&gt;
          &lt;td&gt;Verification reports speed up reviews&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;10&lt;/td&gt;
          &lt;td&gt;Generate easy-to-review to review content&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;11&lt;/td&gt;
          &lt;td&gt;Give it all your tools&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;12&lt;/td&gt;
          &lt;td&gt;Prefer UI reviews over code reviews for ease&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;13&lt;/td&gt;
          &lt;td&gt;You can resume if it hangs. Don&amp;rsquo;t worry about context&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;14&lt;/td&gt;
          &lt;td&gt;Allow it design flexibility&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;15&lt;/td&gt;
          &lt;td&gt;Generate documentation&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;16&lt;/td&gt;
          &lt;td&gt;Ask for effort estimates&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;17&lt;/td&gt;
          &lt;td&gt;Probe for confidence&lt;/td&gt;
          &lt;td&gt;New&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td style=&#34;text-align: right&#34;&gt;18&lt;/td&gt;
          &lt;td&gt;Continue the session for the long tail&lt;/td&gt;
          &lt;td&gt;&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</description>
    </item>
    <item>
      <title>Things I Learned - 10 Aug 2025</title>
      <link>https://www.s-anand.net/blog/things-i-learned-10-aug-2025/</link>
      <pubDate>Sun, 10 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/things-i-learned-10-aug-2025/</guid>
      <description>&lt;p&gt;This week, I learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAI supports a tool &lt;code&gt;&amp;quot;type&amp;quot;: &amp;quot;custom&amp;quot;&lt;/code&gt; that lets it write code as an argument to a tool call. Great for code / SQL generation. Even more powerfully, you can generate output following specific grammars, e.g. STL files, PostgreSQL dialect, Mermaid/PlantUML diagrams, OpenAPI specs, Vega-Lite JSONs, Cron expressions, GraphQL SDLs, Dockerfiles, Terraform HCLs, or any DSL! &lt;a href=&#34;https://cookbook.openai.com/examples/gpt-5/gpt-5_new_params_and_tools&#34;&gt;#&lt;/a&gt; #ai-coding&lt;/li&gt;
&lt;li&gt;The OpenAI playground has a &lt;a href=&#34;https://platform.openai.com/chat/edit?models=gpt-5&amp;amp;optimize=true&#34;&gt;GPT-5 Prompt Optimizer&lt;/a&gt; that can migrate prompts to GPT-5.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.npmjs.com/package/docsify/v/4.13.1&#34;&gt;Docsify 4.13.1&lt;/a&gt; is 2 years old and &lt;a href=&#34;https://github.com/docsifyjs/docsify/blob/v4.13.1/package.json#L68&#34;&gt;uses&lt;/a&gt; &lt;a href=&#34;https://www.npmjs.com/package/marked/v/1.2.9&#34;&gt;marked@1.2.9&lt;/a&gt; which is 5 years old. Newer plugins like &lt;a href=&#34;https://www.npmjs.com/package/marked-directive&#34;&gt;marked-directive&lt;/a&gt; don&amp;rsquo;t work with it. Though &lt;a href=&#34;https://github.com/docsifyjs/docsify/tree/v5.0.0-rc.1&#34;&gt;docsify v5.0.0-rc1&lt;/a&gt; is in development, it may be the better option for modern Markdown plugins. &lt;a href=&#34;https://github.com/sanand0/smartart/blob/e4c5bb88eba3aa3cd92d6711a9e29935cc36e62f/script.js&#34;&gt;Here&amp;rsquo;s sample code&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;CommonMark has a &lt;em&gt;powerful&lt;/em&gt; &lt;a href=&#34;https://talk.commonmark.org/t/generic-directives-plugins-syntax/444&#34;&gt;directive syntax&lt;/a&gt; proposal that lets you add classes, attributes, and arbitrary plugins to Markdown. For example, &lt;code&gt;:abbr[MD]{#id .class title=&amp;quot;Markdown&amp;quot;}&lt;/code&gt; for inline directives. Plugins exist for &lt;a href=&#34;https://www.npmjs.com/package/marked-directive&#34;&gt;marked&lt;/a&gt;, &lt;a href=&#34;http://npmjs.com/package/markdown-it-directive&#34;&gt;markdown-it&lt;/a&gt; and &lt;a href=&#34;https://github.com/remarkjs/remark-directive&#34;&gt;remark&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://biomejs.dev/&#34;&gt;biomejs&lt;/a&gt; and &lt;a href=&#34;https://dprint.dev/&#34;&gt;dprint&lt;/a&gt; are gaining traction as &lt;a href=&#34;https://prettier.io/&#34;&gt;prettier&lt;/a&gt; alternatives. I&amp;rsquo;m yet to try them but keen to explore.
&lt;ul&gt;
&lt;li&gt;Skip biomejs for now. It uses tabs (not spaces) and does not respect .gitignore by default. Handling these is too much work.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;⭐ Code generation is more flexible than tool calling. LLMs can&amp;rsquo;t write a tool-call loop, for example, but they can write code to run an API in a loop. So, I like telling the LLM to &amp;ldquo;write code using these APIs&amp;rdquo; than giving it APIs to tool-call. #ai-coding&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npx -y ccusage&lt;/code&gt; is an easy way of summarizing your &lt;a href=&#34;https://docs.anthropic.com/en/docs/claude-code/overview&#34;&gt;Claude Code&lt;/a&gt; usage and cost. My cost so far (since 21 July) is about $10. The median session cost is ~50 cents. Most of it ($7) was from a single temporary coding chat that I kept continuing for way too long, building up the context window. &lt;a href=&#34;https://github.com/ryoppippi/ccusage&#34;&gt;#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kepano/defuddle&#34;&gt;defuddle&lt;/a&gt; can be used in the browser to get the main content from web pages. A replacement for Mozilla Readability. &lt;a href=&#34;https://stephango.com/defuddle&#34;&gt;#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kashw1n.com/blog/nodejs-2025/&#34;&gt;Modern Node.js Patterns for 2025&lt;/a&gt; include these 5 features I&amp;rsquo;m excited by:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single-executable bundling&lt;/strong&gt;. &lt;code&gt;node --experimental-sea-config sea-config.json&lt;/code&gt; builds standalone binaries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ES Modules&lt;/strong&gt;. Use &lt;code&gt;node:&lt;/code&gt; prefix for built-in imports. &lt;code&gt;import { createServer } from &#39;node:http&#39;;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Watch mode&lt;/strong&gt;. Use &lt;code&gt;node --watch file.js&lt;/code&gt; auto-reloads when &lt;code&gt;file.js&lt;/code&gt; or dependencies change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Env file&lt;/strong&gt;. Use &lt;code&gt;node --env-file=.env&lt;/code&gt; loads &lt;code&gt;.env&lt;/code&gt; as environment variables.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;node:test&lt;/code&gt;&lt;/strong&gt; is a full-featured test framework with &lt;code&gt;--watch&lt;/code&gt; and coverage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Concise explanations speed up decisions because they&amp;rsquo;re faster to read and understand (obvious). They&amp;rsquo;re also easier to combine with other ideas (less obvious). &lt;a href=&#34;https://stephango.com/concise&#34;&gt;#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;ve been uncertain about &lt;a href=&#34;https://htmx.org/&#34;&gt;htmx&lt;/a&gt; for some time now. This tutorial, &lt;a href=&#34;https://github.com/BookOfCooks/blog/blob/master/htmx-is-hard-so-lets-get-it-right.md&#34;&gt;HTMX is hard, so let&amp;rsquo;s get it right&lt;/a&gt;, convinced me that it&amp;rsquo;s too far from my mental model, so I&amp;rsquo;m unlikely to ever use it.&lt;/li&gt;
&lt;li&gt;⭐ Slow, effortful practice (spaced recall, interleaving topics, self-testing) builds lasting knowledge but looks inefficient and doesn&amp;rsquo;t help with exams. &lt;a href=&#34;https://chatgpt.com/share/689180c7-03a0-800c-a5d4-5a455429e97f&#34;&gt;#&lt;/a&gt; #beliefs&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=vsls-contrib.gitdoc&#34;&gt;GitDoc VS Code extension&lt;/a&gt; auto-commits and syncs notes. I dropped &lt;a href=&#34;https://github.com/gitwatch/gitwatch&#34;&gt;gitwatch&lt;/a&gt; in favor of this.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s interesting that Gemini Deep Research cannot access Google Drive while Gemini can. On the other hand, ChatGPT Deep Research can access Google Drive but ChatGPT cannot.&lt;/li&gt;
&lt;li&gt;A trend that AI coding will only accelerate: &amp;ldquo;It is now possible for tiny teams to make principled software that millions of people use, unburdened by investors. &amp;hellip; you need far less money and far fewer employees to reach far more customers. That wave is only just beginning.&amp;rdquo; &lt;a href=&#34;https://stephango.com/vcware&#34;&gt;#&lt;/a&gt; #ai-coding&lt;/li&gt;
&lt;li&gt;Typed languages are better suited for vibe coding. This will likely lead to the growth of typed languages (TypeScript, Rust, Go) but also of typing in untyped languages (e.g. Python) &lt;a href=&#34;https://solmaz.io/typed-languages-are-better-suited-for-vibecoding&#34;&gt;#&lt;/a&gt; #ai-coding&lt;/li&gt;
&lt;li&gt;Instead of Celery, Redis, Kafka, etc. as task queues, we could the file system as a message queue. For example, &lt;code&gt;pending/task-01.json&lt;/code&gt; moves to &lt;code&gt;wip/task-01.json&lt;/code&gt; to &lt;code&gt;done/task-01.json&lt;/code&gt;. Folders for state/tags, files for task details.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://foambubble.github.io/&#34;&gt;Foam&lt;/a&gt; is a note-taking VS Code extension. The &lt;a href=&#34;https://foambubble.github.io/foam/user/features/wikilinks&#34;&gt;WikiLinks&lt;/a&gt;, &lt;a href=&#34;https://foambubble.github.io/foam/user/features/tags&#34;&gt;tags&lt;/a&gt; and &lt;a href=&#34;https://foambubble.github.io/foam/user/features/backlinking&#34;&gt;backlinking&lt;/a&gt; features align &lt;em&gt;naturally&lt;/em&gt; with Markdown note-taking. Via &lt;a href=&#34;https://stephango.com/vault&#34;&gt;Steph Ango&lt;/a&gt; who uses Obsidian which nudged me to search for WikiLink-ing features in VS Code.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m an open data hawk. But here are things I should remind myself of. &lt;a href=&#34;https://chatgpt.com/c/68901fb2-38b0-8333-9853-7e6c2fdaf97c&#34;&gt;#&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Privacy incubates creativity&lt;/strong&gt;. People self-censor when watched. Privacy shields fragile ideas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Power assymetry&lt;/strong&gt;. Big players can leverage openness more, e.g. Cambridge Analytics + Facebook data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context matters&lt;/strong&gt;. What&amp;rsquo;s harmless in one setting can be toxic in another.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One-way door&lt;/strong&gt;. Data can&amp;rsquo;t be unshared. Don&amp;rsquo;t scrap brakes dreaming of perfect roads. Anticipate tyrannical regimes / cultures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not your call&lt;/strong&gt;. You don&amp;rsquo;t share your neighbour&amp;rsquo;s medical records.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/One-Punch_Man&#34;&gt;One Punch Man&lt;/a&gt; is available as &lt;a href=&#34;https://onepunchmanmangaa.com/&#34;&gt;manga&lt;/a&gt;. I watched the anime first and assumed that came first. Apparently not.&lt;/li&gt;
&lt;li&gt;⭐ In &amp;ldquo;kind&amp;rdquo; environments (stable rules, rapid and accurate feedback), specialize. In &amp;ldquo;wicked&amp;rdquo; environments (rules shift, feedback is noisy/late), generalize. &lt;a href=&#34;https://chatgpt.com/share/68902bbf-bf58-800c-b6b5-9ae787fa9c26&#34;&gt;ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Models&amp;rsquo; ability to orchestrate longer workflows will improve. Factor that into your application design. Claude Code can already handle over 70 tasks in a workflow&lt;/li&gt;
&lt;li&gt;What happens when LLMs play Chinese Whispers / the &lt;a href=&#34;https://en.wikipedia.org/wiki/Telephone_game&#34;&gt;Telephone Game&lt;/a&gt;? Here are learnings. &lt;a href=&#34;https://chatgpt.com/share/68904271-6d10-800c-9084-8ae28668df92&#34;&gt;ChatGPT&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Drift increases faster than linear with hops.&lt;/li&gt;
&lt;li&gt;Bigger models do better, but constrained prompts (“Copy the text exactly; change nothing.”) have a bigger impact.&lt;/li&gt;
&lt;li&gt;Low temperature improves copying fidelity.&lt;/li&gt;
&lt;li&gt;But even after &amp;ldquo;forgetting&amp;rdquo;, LLMs reproduce rare content if they&amp;rsquo;re trained on it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;ldquo;In fact, React Native looks set to become the most engine-agnostic JavaScript runtime around&amp;rdquo;. &lt;a href=&#34;https://buttondown.com/whatever_jamie/archive/the-many-many-many-javascript-runtimes-of-the-last-decade/&#34;&gt;The Many, Many, Many, JavaScript Runtimes of the Last Decade&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.omdbapi.com/&#34;&gt;OMDb&lt;/a&gt; (simple) and &lt;a href=&#34;https://www.themoviedb.org/&#34;&gt;TMDb&lt;/a&gt; (comprehensive) are API-friendly alternatives to the IMDb.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/9001/copyparty&#34;&gt;copyparty&lt;/a&gt; seems one of the most feature-rich file servers out there. Single Python file, runs on any OS, works with any client, and optimized for speed. &lt;a href=&#34;https://youtu.be/15_-hgsX2V0&#34;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Quotes I enjoyed from &lt;a href=&#34;https://youtu.be/o8NPllzkFhE&#34;&gt;Linus Torvalds&amp;rsquo; TED interview&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;I want to not have external stimulation. You can kind of see, on the walls are this light green. I&amp;rsquo;m told that at mental institutions they use that on the walls. It&amp;rsquo;s like a calming color. &amp;hellip; the main thing I worry about in my computer is &amp;ndash; it really has to be completely silent. If the cat comes up, it sits in my lap. And I want to hear the cat purring.&lt;/li&gt;
&lt;li&gt;I did not start Linux as a collaborative project. I started it as one in a series of many projects I had done at the time for myself, partly because I needed the end result, but even more because I just enjoyed programming.&lt;/li&gt;
&lt;li&gt;I&amp;rsquo;m actually not a people person. But I do love other people who comment and get involved in my project.&lt;/li&gt;
&lt;li&gt;The big point for me was not being alone and having 10, maybe 100 people being involved. Going from 100 people to a million people is not a big deal &amp;ndash; to me. Well, I mean, maybe it is if you want to sell your result then it&amp;rsquo;s a huge deal. But if you&amp;rsquo;re interested in the technology and you&amp;rsquo;re interested in the project, the big part was getting the community.&lt;/li&gt;
&lt;li&gt;So Git is my second big project, which was only created for me to maintain my first big project. And this is literally how I work.&lt;/li&gt;
&lt;li&gt;Well, I do code for fun &amp;ndash; but I want to code for something meaningful so every single project I&amp;rsquo;ve ever done has been something I needed.&lt;/li&gt;
&lt;li&gt;Apparently, my sister said that my biggest exceptional quality was that I would not let go.&lt;/li&gt;
&lt;li&gt;I can&amp;rsquo;t do UI to save my life.&lt;/li&gt;
&lt;li&gt;Good taste is about really seeing the big patterns and kind of instinctively knowing what&amp;rsquo;s the right way to do things.&lt;/li&gt;
&lt;li&gt;Companies like Google and many others have made, arguably, like, billions of dollars out of your software. Does that piss you off? No. No, it doesn&amp;rsquo;t piss me off for several reasons. And one of them is, I&amp;rsquo;m doing fine. But the other reason is &amp;ndash; I mean, without doing the whole open source and really letting go thing, Linux would never have been what it is.&lt;/li&gt;
&lt;li&gt;I think one reason open source works so well in code (is that &amp;hellip;) Code either works or it doesn&amp;rsquo;t.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;a href=&#34;https://usesthis.com/&#34;&gt;Uses This&lt;/a&gt; site has interviewed professionals for decades. From their &lt;a href=&#34;https://github.com/waferbaby/usesthis&#34;&gt;repo&lt;/a&gt; I scraped the top developer apps post 2020:&lt;/li&gt;
&lt;li&gt;CloudFlare has an Iceberg data catalog in &lt;a href=&#34;https://developers.cloudflare.com/r2/data-catalog/&#34;&gt;R2 Data Catalog&lt;/a&gt;. Iceberg is like Parquet but supports metadata, time-travel, and schema edits. But I&amp;rsquo;m yet to find a single publicly accessible Iceberg catalog. Its open-data adoption is not as high as Parquet&amp;rsquo;s. &lt;a href=&#34;https://chatgpt.com/share/688f0b61-f9d8-800c-a7c8-46410ab4f1ab&#34;&gt;Apache Iceberg vs Parquet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://observablehq.com/notebook-kit/&#34;&gt;Observable Notebook 2&lt;/a&gt; is the new notebook format from Mike Bostock. It is vanilla JS and embeddable into other pages. THis would have been a big deal 2 years ago, but with the LLM ecosystem today, I&amp;rsquo;m not sure if it matters as much.&lt;/li&gt;
&lt;li&gt;To add CORS support to CloudFlare pages protected by Zero Trust, add a &lt;a href=&#34;https://developers.cloudflare.com/pages/configuration/headers/&#34;&gt;&lt;code&gt;_headers&lt;/code&gt;&lt;/a&gt; file to your repo. (This is different from the &lt;a href=&#34;https://developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/cors/&#34;&gt;Zero Trust CORS&lt;/a&gt; which allows automated logins.) Sample &lt;code&gt;_headers&lt;/code&gt; that lets logged-in users fetch pages via &lt;code&gt;fetch(&amp;quot;...&amp;quot;, { credentials: &amp;quot;include&amp;quot; })&lt;/code&gt;:
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/*
  Access-Control-Allow-Credentials: true
  Access-Control-Allow-Origin: https://your-site.example.com
  Access-Control-Allow-Methods: GET, HEAD
  Access-Control-Allow-Methods: *
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;As corporates restrict the use of LLMs, I see employees purchasing personal laptops to use LLMs on. An interesting trend!&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/openai/openai-python&#34;&gt;&lt;code&gt;openai-python&lt;/code&gt;&lt;/a&gt; has a CLI. You can run &lt;code&gt;uvx openai api chat.completions.create --stream -m gpt-4.1-nano -g developer &#39;Translate to Chinese&#39; -g user &amp;quot;Hello&amp;quot;&lt;/code&gt; for example&lt;/li&gt;
&lt;li&gt;Anthropic has an &lt;a href=&#34;https://docs.anthropic.com/en/api/openai-sdk&#34;&gt;OpenAI compatible API&lt;/a&gt; at &lt;code&gt;https://api.anthropic.com/v1/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Claude Code tips from &lt;a href=&#34;https://lucumr.pocoo.org/2025/7/30/things-that-didnt-work/&#34;&gt;Things that didn&amp;rsquo;t work&lt;/a&gt; by Armin Rocher #ai-coding
&lt;ul&gt;
&lt;li&gt;Speech-to-text. Cannot stress this enough but talking to the machine means you’re more likely to share more about what you want it to do.&lt;/li&gt;
&lt;li&gt;I maintain some basic prompts and context for copy-pasting at the end or the beginning of what I entered.&lt;/li&gt;
&lt;li&gt;I ended up preloading executables on the PATH that override the default ones, steering Claude toward the right tools, e.g. running &lt;code&gt;python&lt;/code&gt; asks it to use &lt;code&gt;uv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I use the task tool frequently for basic parallelization and context isolation.&lt;/li&gt;
&lt;li&gt;Simply taking time to talk to the machine and give clear instructions outperforms elaborate pre-written prompts.&lt;/li&gt;
&lt;li&gt;Forcing myself to evaluate the automation has another benefit: I’m less likely to just blindly assume it helps me.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Research indicates that we don&amp;rsquo;t know in advance which prompts will help. Evals beat prompt engineering. &lt;a href=&#34;https://bsky.app/profile/emollick.bsky.social/post/3lvgwdwn7422w&#34;&gt;Ethan Mollick&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>How to publish an eBook in 60 minutes</title>
      <link>https://www.s-anand.net/blog/how-to-publish-an-ebook-in-60-minutes/</link>
      <pubDate>Mon, 31 Mar 2025 12:47:13 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/how-to-publish-an-ebook-in-60-minutes/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;How to publish an eBook in 60 minutes&#34; loading=&#34;lazy&#34; src=&#34;https://files.s-anand.net/images/2025-03-31-an-lbs-exchange-program-ebook-cover.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;I &lt;a href=&#34;https://www.amazon.in/dp/B0F3D55R2Z/&#34;&gt;published an eBook on Amazon&lt;/a&gt;. It takes an hour &lt;strong&gt;if you have the content ready&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 1&lt;/strong&gt; (10 min): &lt;a href=&#34;https://account.kdp.amazon.com/&#34;&gt;Set up a Kindle Direct Publishing account&lt;/a&gt; with your address, bank details, and tax info.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 2&lt;/strong&gt; (15 min): &lt;a href=&#34;https://wordpress.com/support/export/&#34;&gt;Export&lt;/a&gt; my &lt;a href=&#34;https://www.s-anand.net/blog/category/london-2000/&#34;&gt;London 2000&lt;/a&gt; blog archive and &lt;a href=&#34;https://github.com/lonekorean/wordpress-export-to-markdown&#34;&gt;convert to Markdown&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;STEP 3&lt;/strong&gt; (10 min): Reformat the Markdown by writing a script in &lt;a href=&#34;https://cursor.com/&#34;&gt;Cursor&lt;/a&gt;. Here&amp;rsquo;s the prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Write a Python script that reads &lt;code&gt;*.md&lt;/code&gt; including the YAML frontmatter, adds the YAML &lt;code&gt;title&lt;/code&gt; as H1, &lt;code&gt;date&lt;/code&gt; (yyyy-mm-dd) like &lt;strong&gt;Sun, 01 Jan 2000&lt;/strong&gt; in a new para after the frontmatter and before the content.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;STEP 4&lt;/strong&gt; (15 min): Convert it to an ePub using &lt;a href=&#34;https://pandoc.org/&#34;&gt;pandoc&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pandoc *.md -o book.epub --toc &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --metadata &lt;span class=&#34;nv&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;An LBS Exchange Program&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --metadata &lt;span class=&#34;nv&#34;&gt;author&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Anand S&amp;#34;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --metadata &lt;span class=&#34;nv&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;en &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --metadata &lt;span class=&#34;nv&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;31 Mar 2025&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;STEP 5&lt;/strong&gt; (10 min): Generated a cover page with &lt;a href=&#34;https://chatgpt.com/&#34;&gt;ChatGPT&lt;/a&gt; (5 min) and compressed it into JPEG via &lt;a href=&#34;https://squoosh.app/&#34;&gt;Squoosh&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Draw a comic-style book cover page that covers the experiences of an Indian exchange student (picture attached) from IIM Bangalore at London Business School and exploring London. The book title is &amp;ldquo;An LBS Exchange Program&amp;rdquo;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;STEP 6&lt;/strong&gt; (10 min): &lt;a href=&#34;https://kdp.amazon.com/&#34;&gt;Publish the book on KDP&lt;/a&gt;. It&amp;rsquo;s priced at $0.99 / ₹49 because Kindle doesn&amp;rsquo;t allow free downloads.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it. Here&amp;rsquo;s the book: &lt;a href=&#34;https://www.amazon.in/dp/B0F3D55R2Z/&#34;&gt;https://www.amazon.in/dp/B0F3D55R2Z/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The three things that made publishing in 1 hour possible are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Amazon&amp;rsquo;s publishing process is &lt;strong&gt;simple&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open-source tooling (&lt;a href=&#34;https://wordpress.org/&#34;&gt;WordPress&lt;/a&gt;, &lt;a href=&#34;https://en.wikipedia.org/wiki/Markdown&#34;&gt;Markdown&lt;/a&gt;, &lt;a href=&#34;https://en.wikipedia.org/wiki/EPUB&#34;&gt;ePub&lt;/a&gt;, &lt;a href=&#34;https://pandoc.org/&#34;&gt;pandoc&lt;/a&gt;) has built a big part of the infrastructure.&lt;/li&gt;
&lt;li&gt;LLMs make the rest (&lt;a href=&#34;https://chatgpt.com/share/67ea8da7-7f90-800c-a89c-6f087e893749&#34;&gt;figuring out the steps&lt;/a&gt;, generating the cover) very easy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(An eBook takes 72 hours of review before going live on the Kindle store.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.linkedin.com/feed/update/urn%3Ali%3Ashare%3A7314884520820854784&#34;&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Voice Chat to Slides: My New AI-Powered Workflow</title>
      <link>https://www.s-anand.net/blog/voice-chat-to-slides-my-new-ai-powered-workflow/</link>
      <pubDate>Thu, 27 Mar 2025 16:34:53 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/voice-chat-to-slides-my-new-ai-powered-workflow/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;Voice Chat to Slides: My New AI-Powered Workflow&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/calvin-2.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s my new workflow for creating slide decks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ChatGPT interviews me and creates Markdown slides.&lt;/li&gt;
&lt;li&gt;I use Marp to convert Markdown to slides.&lt;/li&gt;
&lt;li&gt;LLMs create supporting images.&lt;/li&gt;
&lt;li&gt;I deploy on GitHub Pages.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;… and here are 2 decks created this way.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://sanand0.github.io/llmhallucinations/&#34;&gt;Visualizing LLM Hallucinations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://sanand0.github.io/llms-in-education/&#34;&gt;LLMs in Education&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;rsquo;s look at how I built the second example, step by step.&lt;/p&gt;
&lt;h3 id=&#34;chatgpt-interviews-me-and-creates-markdown-slides&#34;&gt;ChatGPT interviews me and creates Markdown slides&lt;/h3&gt;
&lt;p&gt;While walking 75 minutes from home to IIT Madras to deliver &lt;a href=&#34;https://sanand0.github.io/llms-in-education/&#34;&gt;this talk&lt;/a&gt;, I had ChatGPT interview me in &lt;a href=&#34;https://help.openai.com/en/articles/8400625-voice-mode-faq&#34;&gt;standard voice mode&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why an interview?&lt;/strong&gt; It&amp;rsquo;s easier when someone asks questions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why voice?&lt;/strong&gt; It&amp;rsquo;s hard to type while walking. Otherwise, I prefer typing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why not advanced voice mode?&lt;/strong&gt; I want to use a reasoning model like &lt;a href=&#34;https://chatgpt.com/?model=o3-mini-high&#34;&gt;O3 Mini High&lt;/a&gt; for better responses, not the GPT-4o-realtime model that advanced voice mode uses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://chatgpt.com/share/67e36f57-01c4-800c-b4fc-5c8b302403f4&#34;&gt;Here&amp;rsquo;s the conversation I had with ChatGPT&lt;/a&gt;. I began by speaking (not typing):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I want to create an insightful deck in Markdown on how I have been using LLMs in education.The audience will be technologists and educators. The slide contents must have information that is useful and surprising to them.&lt;/p&gt;
&lt;p&gt;The slides are formatted in Markdown with each slide title being a level 2 Markdown header and the contents of the slides being crisp bullet points that support the title. The titles are McKinsey style action titles. Just by reading the titles, the audience will understand the message that I am trying to convey.&lt;/p&gt;
&lt;p&gt;In this conversation, I&amp;rsquo;d like you to interview me, asking me questions one by one, and taking my inputs to craft this presentation. I&amp;rsquo;d also like you to review the inputs and the slide content you create to make sure that it is insightful, useful, non-obvious, and very clear and simple for the audience. Interact with me to improve the deck.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s begin.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(Unsurprisingly, I talk a lot more than I type.)&lt;/p&gt;
&lt;p&gt;There were 3 kinds of interactions I had with ChatGPT:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Content&lt;/strong&gt;. I explained each slide. For example:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Yeah, let&amp;rsquo;s move on to the next topic, which is where we had the students learn prompt engineering as part of the course. One of the questions was convincing an LLM to say yes, even though …&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Correction&lt;/strong&gt;. After ChatGPT read aloud a slide, I corrected it. For example:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Content-wise, it&amp;rsquo;s spot-on. Style-wise, it&amp;rsquo;s almost spot-on. It&amp;rsquo;s far more verbose. Can you retain the exact same style, but shorten the number of words considerably?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;These feel generic. I&amp;rsquo;d like stuff that comes across as insightful, non-obvious, and specific.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Collation&lt;/strong&gt;. I had ChatGPT put slides in order. For example:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Put all the slides together in sequence. Make sure you don&amp;rsquo;t miss anything.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Move the opening questions as the second slide. Move the final takeaways, which is currently the last slide, to just before the final set of questions.&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of the interview, I had all the content for the slides.&lt;/p&gt;
&lt;h3 id=&#34;marp-converts-markdown-to-slides&#34;&gt;Marp converts Markdown to slides&lt;/h3&gt;
&lt;p&gt;I use &lt;a href=&#34;https://marp.app/&#34;&gt;Marp&lt;/a&gt;, a JavaScript tool that turns Markdown into slides&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why Markdown?&lt;/strong&gt; It&amp;rsquo;s natural for programmers &lt;strong&gt;and&lt;/strong&gt; LLMs. ChatGPT renders rich text in Markdown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why not RevealJS?&lt;/strong&gt; Despite a &lt;a href=&#34;https://revealjs.com/markdown/&#34;&gt;Markdown plugin&lt;/a&gt;, RevealJS is built for HTML. Marp is built for Markdown.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I created a &lt;a href=&#34;https://tools.s-anand.net/page2md/&#34;&gt;bookmarklet&lt;/a&gt; that copies text as Markdown. Using this, I converted the ChatGPT slide transcript to Markdown, saving it as &lt;a href=&#34;https://github.com/sanand0/llms-in-education/blob/main/README.md&#34;&gt;README.md&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode&#34;&gt;Marp for VS Code plugin&lt;/a&gt; makes it easy to preview the slides when you adding YAML frontmatter like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;marp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Visualizing LLM Hallucinations&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;https://sanand0.github.io/llmhallucinations/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;gaia&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;backgroundColor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;white&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;llms-create-supporting-images&#34;&gt;LLMs create supporting images&lt;/h3&gt;
&lt;p&gt;I use ChatGPT or Gemini to create images that support the slides. For example &lt;a href=&#34;https://sanand0.github.io/llmhallucinations/#2&#34;&gt;this slide&lt;/a&gt; includes an image of a robot psychologist generated by Gemini&amp;rsquo;s ImageGen 3:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;Robopsychologist&#34; loading=&#34;lazy&#34; src=&#34;https://raw.githubusercontent.com/sanand0/llmhallucinations/refs/heads/main/img/robo-psychologist.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Today, with native image generation in &lt;a href=&#34;https://developers.googleblog.com/en/experiment-with-gemini-20-flash-native-image-generation/&#34;&gt;Gemini 2.0 Flash&lt;/a&gt; and &lt;a href=&#34;https://openai.com/index/introducing-4o-image-generation/&#34;&gt;GPT 4o&lt;/a&gt;, I&amp;rsquo;d likely use those. They have much better character control.&lt;/p&gt;
&lt;h3 id=&#34;deploying-on-github-pages&#34;&gt;Deploying on GitHub Pages&lt;/h3&gt;
&lt;p&gt;I use &lt;a href=&#34;https://github.com/sanand0/llms-in-education/blob/main/.github/workflows/deploy.yml&#34;&gt;GitHub Actions&lt;/a&gt; to render the slides and deploy them on GitHub Pages. Here&amp;rsquo;s what the key steps look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;steps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Checkout repository&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;actions/checkout@v4&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Setup Node.js&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;actions/setup-node@v4&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;node-version&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;22&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Generate HTML with Marp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;run&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;npx -y @marp-team/marp-cli@latest README.md -o index.html&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Setup GitHub Pages&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;actions/configure-pages@v4&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Upload artifact&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;actions/upload-pages-artifact@v3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Deploy to GitHub Pages&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;deployment&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;uses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;actions/deploy-pages@v4&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;whats-next&#34;&gt;What&amp;rsquo;s next?&lt;/h3&gt;
&lt;p&gt;I plan to make 3 improvements to this workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Adding images directly with voice prompts.&lt;/li&gt;
&lt;li&gt;Adding diagrams (e.g., Mermaid).&lt;/li&gt;
&lt;li&gt;Creating a custom GPT that auto-deploys slides on GitHub when I say &amp;ldquo;Publish these slides.&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If both of these work, I&amp;rsquo;ll be able to create &lt;strong&gt;and publish&lt;/strong&gt; an entire slide deck just by rambling to ChatGPT for an hour.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>A challenge of blog questions</title>
      <link>https://www.s-anand.net/blog/a-challenge-of-blog-questions/</link>
      <pubDate>Tue, 04 Mar 2025 11:13:55 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/a-challenge-of-blog-questions/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://thejeshgn.com/2025/02/27/a-challenge-of-blog-questions/&#34;&gt;Thejesh&lt;/a&gt; tagged me with these questions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why did you start blogging in the first place?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I started my website in 1997 on Geocities at &lt;code&gt;https://www.geocities.com/root_node/&lt;/code&gt;, mostly talking about me. (A cousin once told me, &amp;ldquo;Anand&amp;rsquo;s site is like &lt;a href=&#34;https://en.wikipedia.org/wiki/T._N._Seshan&#34;&gt;TN Seshan&lt;/a&gt; - talking only about himself.&amp;rdquo; 🙂)&lt;/p&gt;
&lt;p&gt;(As an aside, I didn&amp;rsquo;t know that searching for &lt;a href=&#34;https://www.google.com/search?q=geocities&#34;&gt;Geocities on Google&lt;/a&gt; renders the results in &lt;a href=&#34;https://www.reddit.com/r/google/comments/1e6kbpp/googling_geocities_changes_your_search_result_font/&#34;&gt;Comic Sans&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;I wanted a place to share the interesting links I found. Robot Wisdom by &lt;a href=&#34;https://en.wikipedia.org/wiki/Jorn_Barger&#34;&gt;John Barger&lt;/a&gt; and &lt;a href=&#34;https://scripting.com/&#34;&gt;Scripting News&lt;/a&gt; by &lt;a href=&#34;https://en.wikipedia.org/wiki/Dave_Winer&#34;&gt;Dave Winer&lt;/a&gt; were great examples: collection of interesting links updated daily.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;https://www.s-anand.net/blog/1999/&#34;&gt;July 1999&lt;/a&gt;, as a student at IIMB, I decided to put that into action by creating a custom HTML page updated manually.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What platform are you using to manage your blog and why did you choose it? Have you blogged on other platforms before?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;WordPress. Because it was the most fully-featured, mature platform when I migrated to it around 2006.&lt;/p&gt;
&lt;p&gt;Before that, I used:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A custom HTML page on Geocities. But it was hard to update multiple links, create individual pages, categories, etc. So…&lt;/li&gt;
&lt;li&gt;A Perl-based static-site generator I wrote myself. But as my link count grew, each generation took too long. So …&lt;/li&gt;
&lt;li&gt;A CGI-Perl-based blogging engine I hosed on freestarthost.com, handling commenting, etc. But at BCG, I didn&amp;rsquo;t have time to add many features (linkback, RSS, etc.) So…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.blogger.com/&#34;&gt;Blogger&lt;/a&gt; as a parallel blog, briefly. But it didn&amp;rsquo;t have as many features as (nor the portability of) WordPress. So…&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wordpress.com/&#34;&gt;WordPress&lt;/a&gt; - moving across a bunch of hosting services, and currently on &lt;a href=&#34;https://www.hostgator.com/&#34;&gt;HostGator&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I also blogged in parallel on InfyBlog, Infosys&amp;rsquo; internal blogging platform on LiveJournal.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;How do you write your posts? For example, in a local editing tool, or in a panel/dashboard that&amp;rsquo;s part of your blog?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I started with custom HTML in Emacs (or whatever code editor I kept moving to).&lt;/p&gt;
&lt;p&gt;Briefly, I used &lt;a href=&#34;https://en.wikipedia.org/wiki/Windows_Live_Writer&#34;&gt;Windows Live Writer&lt;/a&gt;, which was quite a good blogging tool.&lt;/p&gt;
&lt;p&gt;Now, I write in Markdown on VS Code and paste it into WordPress&amp;rsquo; editor.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When do you feel most inspired to write?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When an idea that&amp;rsquo;s been bubbling for a while in my mind bursts out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you publish immediately after writing, or do you let it simmer a bit as a draft?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I publish immediately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What&amp;rsquo;s your favorite post on your blog?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.s-anand.net/blog/the-next-chapter-of-my-life/&#34;&gt;The next chapter of my life&lt;/a&gt;, which I wrote on a one-way flight back from the UK to India to start &lt;a href=&#34;https://www.gramener.com/&#34;&gt;Gramener&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Any future plans for your blog? Maybe a redesign, a move to another platform, or adding a new feature?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I plan to move it to GitHub Pages with Markdown content and a static site generator. I might write my own SSG again in Deno or use one of the faster ones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Who&amp;rsquo;s next?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d love to hear from&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mvark.blogspot.com/&#34;&gt;Anil Radhakrishna&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://karthiks.co/&#34;&gt;Karthik Sashidhar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://simonwillison.net/&#34;&gt;Simon Willison&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    <item>
      <title>My learnings as week notes</title>
      <link>https://www.s-anand.net/blog/my-learnings-as-week-notes/</link>
      <pubDate>Wed, 25 Dec 2024 14:27:11 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/my-learnings-as-week-notes/</guid>
      <description>&lt;p&gt;&lt;img alt=&#34;My learnings as week notes&#34; loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/things-i-learned.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;One of my &lt;a href=&#34;https://www.s-anand.net/blog/my-year-in-2023/&#34;&gt;goals for 2024&lt;/a&gt; is to &amp;ldquo;Compound long-term goals, daily.&amp;rdquo; Learning is one of those.&lt;/p&gt;
&lt;p&gt;Some people publish their learnings as weekly notes, like &lt;a href=&#34;https://simonwillison.net/tags/weeknotes/&#34;&gt;Simon Willison&lt;/a&gt;, &lt;a href=&#34;https://thejeshgn.com/category/weekly-notes/&#34;&gt;Thejesh GN&lt;/a&gt;, &lt;a href=&#34;https://mvark.blogspot.com/&#34;&gt;Anil Radhakrishna&lt;/a&gt;, and &lt;a href=&#34;https://jvns.ca/til/&#34;&gt;Julia Evans&lt;/a&gt;. I follow their notes.&lt;/p&gt;
&lt;p&gt;I started doing the same, quietly, to see if I could sustain it. It&amp;rsquo;s been a year and it &lt;strong&gt;has sustained&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m finally publishing them. &lt;a href=&#34;https://til.s-anand.net/&#34;&gt;My week notes are at &lt;strong&gt;til.s-anand.net&lt;/strong&gt;&lt;/a&gt;. Here&amp;rsquo;s the &lt;a href=&#34;https://github.com/sanand0/til&#34;&gt;source code&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;capturing-learnings-must-be-frictionless&#34;&gt;Capturing learnings must be frictionless&lt;/h3&gt;
&lt;p&gt;I learn things when I&amp;rsquo;m reading, listening to podcasts, listening to people, or thinking. In every case I&amp;rsquo;m close to my phone or laptop.&lt;/p&gt;
&lt;p&gt;If my laptop is open, I add my notes to a few (long) Markdown files like &lt;a href=&#34;https://github.com/sanand0/til/blob/main/til.md&#34;&gt;this &lt;code&gt;til.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If my phone is easier to access, I type or dictate my notes into &lt;a href=&#34;https://to-do.office.com/tasks/&#34;&gt;Microsoft To Do&lt;/a&gt;, which is currently my most convenient note-taking app. It syncs with my laptop. I transfer it (via OCR on &lt;a href=&#34;https://learn.microsoft.com/en-us/windows/powertoys/text-extractor&#34;&gt;Microsoft Power Toys&lt;/a&gt;) into the Markdown file.&lt;/p&gt;
&lt;p&gt;The Markdown files are synced across my devices using &lt;a href=&#34;https://www.dropbox.com/&#34;&gt;Dropbox&lt;/a&gt;, which I find the most convenient and fast way to sync.&lt;/p&gt;
&lt;p&gt;The notes have a &lt;strong&gt;simple&lt;/strong&gt; format. Here&amp;rsquo;s something I quickly wrote down in Microsoft To Do while speaking with &lt;a href=&#34;https://www.linkedin.com/in/krangana/&#34;&gt;a senior&lt;/a&gt; at a restaurant:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Government websites like the official press releases cannot be crawled from outside India. Hence the need for server farms in India!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then I copied that over to the Markdown file as a list item along with the date (which Microsoft To Do captures), like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;-&lt;/span&gt; 15 Dec 2024. Government websites like the official press releases cannot be crawled from outside India. Hence the need for server farms in India!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. Quick and simple. The most important thing is to capture learnings &lt;strong&gt;easily&lt;/strong&gt;. Even the slightest friction hurts this goal.&lt;/p&gt;
&lt;h3 id=&#34;publishing-learnings&#34;&gt;Publishing learnings&lt;/h3&gt;
&lt;p&gt;I run this &lt;a href=&#34;https://github.com/sanand0/til/blob/main/convert.js&#34;&gt;Deno script&lt;/a&gt; which parses the Markdown files, groups them by week, and generates a set of static HTML pages. These are published on &lt;a href=&#34;https://pages.github.com/&#34;&gt;GitHub Pages&lt;/a&gt;, which is currently my favorite way to publish static files.&lt;/p&gt;
&lt;p&gt;It generates an &lt;a href=&#34;https://til.s-anand.net/feed.xml&#34;&gt;RSS feed&lt;/a&gt; as well. I&amp;rsquo;ve started reading more content using RSS feeds via &lt;a href=&#34;https://feedly.com/&#34;&gt;Feedly&lt;/a&gt;, including my own notes. I find browsing through them a useful refresher.&lt;/p&gt;
&lt;p&gt;This format is different from my &lt;a href=&#34;https://www.s-anand.net/blog/&#34;&gt;blog&lt;/a&gt;. In the 1990s and early 2000s, I published individual links as posts. Then I moved to long form posts. This consolidates multiple links into a single weekly post. But rather than publish via WordPress (which is what my blog is currently based on), I prefer a Markdown-based static site. So it&amp;rsquo;s separate for the moment.&lt;/p&gt;
&lt;p&gt;I intend to continue with these notes (and the format) for the foreseeable future.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;!-- wp-comments-start --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://www.s-anand.net/blog/my-year-in-2024/&#34;&gt;My Year in 2024 - S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;30 Dec 2024 10:01 pm&lt;/em&gt; &lt;em&gt;(pingback)&lt;/em&gt;:
[…] Learning. I took weekly notes of things I learned. […]&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- wp-comments-end --&gt;
</description>
    </item>
    <item>
      <title>How to extend Markdown with custom blocks</title>
      <link>https://www.s-anand.net/blog/how-to-extend-markdown-with-custom-blocks/</link>
      <pubDate>Fri, 08 Jan 2021 09:37:48 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/how-to-extend-markdown-with-custom-blocks/</guid>
      <description>&lt;p&gt;One problem I&amp;rsquo;ve had in Markdown is rendering a content in columns.&lt;/p&gt;
&lt;p&gt;On Bootstrap, the markup would look like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-markup&#34; data-lang=&#34;markup&#34;&gt;&amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;...&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;...&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;How do we get that into Markdown without writing HTML?&lt;/p&gt;
&lt;p&gt;On Python, the &lt;a href=&#34;https://python-markdown.github.io/extensions/attr_list/&#34;&gt;attribute lists extension&lt;/a&gt; lets you add a class. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This is some content
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{: .row}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; renders &lt;code&gt;&amp;lt;p class=&amp;quot;row&amp;quot;&amp;gt;This is some content&amp;lt;/p&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But I can&amp;rsquo;t do that to multiple paragraphs. Nor can I next content, i.e. add a &lt;code&gt;.col&lt;/code&gt; inside the &lt;code&gt;.row&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&#34;https://pypi.org/project/markdown-customblocks/&#34;&gt;markdown-customblocks&lt;/a&gt;. It&amp;rsquo;s a Python module that extends &lt;a href=&#34;https://python-markdown.github.io/&#34;&gt;Python Markdown&lt;/a&gt;. This lets me write:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: row
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: row
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;::: col
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content in column 2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This translates to:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-markup&#34; data-lang=&#34;markup&#34;&gt;&amp;lt;div class=&amp;#34;row&amp;#34;&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;Content in column 1&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;#34;col&amp;#34;&amp;gt;Content in column 2&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Better yet, we can create our own custom HTML block types. For example, this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;markdown&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Markdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;customblocks&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CustomBlocksExtension&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;audio&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;audio/mp3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&amp;#39;&amp;lt;audio src=&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#34; type=&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;    &amp;lt;/audio&amp;gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;md&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Markdown&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extensions&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;CustomBlocksExtension&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;generators&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s1&#34;&gt;&amp;#39;audio&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;audio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; lets you convert this piece of Markdown:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;md&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;::: audio src=&amp;#34;mymusic.ogg&amp;#34; type=&amp;#34;audio/ogg&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;    Your browser does not support `audio`.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; into this HTML:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-markup&#34; data-lang=&#34;markup&#34;&gt;&amp;lt;audio src=&amp;#34;mymusic.ogg&amp;#34; type=&amp;#34;audio/ogg&amp;#34;&amp;gt;
  Your browser does not support &amp;lt;code&amp;gt;audio&amp;lt;/code&amp;gt;.
&amp;lt;/audio&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;https://pypi.org/project/markdown-customblocks/&#34;&gt;markdown-customblocks&lt;/a&gt; is easily the most useful Python module I discovered last quarter.&lt;/p&gt;
</description>
    </item>
    <item>
      <title>Micro-notes</title>
      <link>https://www.s-anand.net/blog/micro-notes/</link>
      <pubDate>Sun, 29 Nov 2020 03:46:33 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/micro-notes/</guid>
      <description>&lt;p&gt;I maintain my (extensive) notes in text files. I&amp;rsquo;ve explored Evernote, Onenote, Google Keep, Apple Notes, and many other platforms. But text files work. I store them as Markdown and sync them on DropBox.&lt;/p&gt;
&lt;p&gt;They used to be relatively large files (50-100KB) each, on broad topics. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;todo.txt&lt;/strong&gt; was a consolidated list of things I had to do&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;people.txt&lt;/strong&gt; was a list of everything I knew about people (addresses, birthdays, etc)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;towrite.txt&lt;/strong&gt; was a list of everything I wanted to write about&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;notes.txt&lt;/strong&gt; was where I tracked notes about any topics&lt;/li&gt;
&lt;li&gt;&amp;hellip; and more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This led to a couple of problems.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Searching across files was hard&lt;/strong&gt;. I wouldn&amp;rsquo;t remember if I wrote ideas for my next talk in todo.txt or towrite.txt, or if my meeting minutes where in notes.txt todo.txt. I had to open each file and search.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Files were getting too big&lt;/strong&gt;. Editing them on mobile was harder. Scanning them was harder.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So I changed this system a few years ago into &lt;strong&gt;micro-notes&lt;/strong&gt;. These files became a folder. For example, my &lt;strong&gt;notes/&lt;/strong&gt; folder looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;time-management.txt&lt;/strong&gt; has my time management notes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;book-never-split-the-difference.txt&lt;/strong&gt; has book notes on &lt;a href=&#34;https://www.goodreads.com/book/show/26156469-never-split-the-difference&#34;&gt;Never Split the Difference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;eat-food-sleep-exercise-live-healthy.txt&lt;/strong&gt; has notes on fitness&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The folder has nearly 300 files. Here&amp;rsquo;s a glimpse of the latest files.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-png-1.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;Similarly, my &lt;strong&gt;people/&lt;/strong&gt; folder has details of my discussions with various people I interact with &amp;ndash; friends, colleagues &amp;amp; clients.&lt;/p&gt;
&lt;p&gt;What made this change possible is &lt;a href=&#34;https://www.voidtools.com/&#34;&gt;Everything&lt;/a&gt;, a fast file search tool on Windows that lets me find files as I type. For example, if I&amp;rsquo;m looking for my notes on &lt;a href=&#34;https://slidesense.ai/&#34;&gt;SlideSense&lt;/a&gt;, I just type &amp;ldquo;notes s&amp;rdquo; and it appears on the list.&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://www.s-anand.net/blog/assets/image-png-3.webp&#34;&gt;&lt;/p&gt;
&lt;p&gt;I usually sort the files by run count (how often I opened them). That makes it easy to re-open the most used files.&lt;/p&gt;
&lt;p&gt;It also makes it easier to edit these notes on mobile. I sync the folder on Dropbox, and use &lt;a href=&#34;https://ia.net/writer&#34;&gt;IAWriter&lt;/a&gt; to edit them while on walks. &lt;a href=&#34;https://support.apple.com/en-in/HT208343&#34;&gt;Dictation&lt;/a&gt; is pretty good, so I&amp;rsquo;ve been using that to take notes too.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;!-- wp-comments-start --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Saurabh Mittal&lt;/strong&gt; &lt;em&gt;3 Dec 2020 1:20 pm&lt;/em&gt;:
Hey Anand, great to see you back! After a loonngggg hiatus!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;4 Dec 2020 10:37 am&lt;/em&gt;:
Thanks, Saurabh!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ananth&lt;/strong&gt; &lt;em&gt;26 Dec 2020 2:32 am&lt;/em&gt;:
Welcome back Anand. I have been following your &amp;ldquo;blog&amp;rdquo; (hope the term is still relevant!) for more than a decade. Your matter-of-fact writing is something that I enjoy and your experiences using various tools/approaches have always been interesting. Hope we can see more of your writing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ramamurthy&lt;/strong&gt; &lt;em&gt;27 Dec 2020 7:03 pm&lt;/em&gt;:
Hi Anand,
I stumbled into your page accidentally while looking for something about Ilayaraja.I am your chittappa,Lalitha chitti&amp;rsquo;s husband.We attended your wedding too. Much water has flown under the bridge and I have lost contact with our relatives.Ramnath and Shekar are in touch.How is your Sriram uncle and your dad.I hope you remember me!&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- wp-comments-end --&gt;
</description>
    </item>
    <item>
      <title>Markdress</title>
      <link>https://www.s-anand.net/blog/markdress/</link>
      <pubDate>Sat, 03 Dec 2011 18:05:26 +0000</pubDate>
      <guid>https://www.s-anand.net/blog/markdress/</guid>
      <description>&lt;p&gt;This year, I’ve converted the bulk of my content into &lt;a href=&#34;http://daringfireball.net/projects/markdown/&#34;&gt;Markdown&lt;/a&gt; – a simple way of formatting text files in a way that can be rendered into HTML.&lt;/p&gt;
&lt;p&gt;Not out of choice, really. It was the only solution if I wanted to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Edit files on my iPad / iPhone (I’ve started doing that a lot more recently)&lt;/li&gt;
&lt;li&gt;Allow the contents to be viewable as HTML as well as text, &lt;strong&gt;and&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Allow non techies to edit the file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As a bonus, it’s already the format &lt;a href=&#34;https://github.com/&#34;&gt;Github&lt;/a&gt; and &lt;a href=&#34;https://bitbucket.org/&#34;&gt;Bitbucket&lt;/a&gt; use for markup.&lt;/p&gt;
&lt;p&gt;If you toss &lt;a href=&#34;http://www.dropbox.com/&#34;&gt;Dropbox&lt;/a&gt; into the mix, there’s a powerful solution there. You can share files via Dropbox as Markdown, and publish them as web pages. There are already a number of solutions that let you do this. &lt;a href=&#34;http://droppages.com/&#34;&gt;DropPages.com&lt;/a&gt; and &lt;a href=&#34;http://pancake.io/&#34;&gt;Pancake.io&lt;/a&gt; let you share Dropbox files as web pages. &lt;a href=&#34;http://calepin.co/&#34;&gt;Calepin.co&lt;/a&gt; lets you blog using Dropbox.&lt;/p&gt;
&lt;p&gt;My needs were a bit simpler, however. I sometimes publish Markdown files on Dropbox that I want to see in a formatted way – without having to create an account. Just to test things, or share temporarily.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&#34;http://markdress.org/&#34;&gt;Markdress.org&lt;/a&gt;. My project for this morning.&lt;/p&gt;
&lt;p&gt;Just add any URL after markdress.org to render it as Markdown. For example, to render the file at &lt;a href=&#34;http://goo.gl/zTG1q&#34;&gt;http://goo.gl/zTG1q&lt;/a&gt;, visit &lt;a href=&#34;http://markdress.org/goo.gl/zTG1q&#34;&gt;http://markdress.org/goo.gl/zTG1q&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To test it out, create any text file in your Dropbox public folder, get the public link and append it to &lt;a href=&#34;http://markdress.org/&#34;&gt;http://markdress.org/&lt;/a&gt; without the http:// prefix.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;comments&#34;&gt;Comments&lt;/h2&gt;
&lt;!-- wp-comments-start --&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gee&lt;/strong&gt; &lt;em&gt;14 Jan 2012 12:38 am&lt;/em&gt;:
Great news. And all the best in your new ventures. Meanwhile, I made a simple bookmarklet for you: &lt;a href=&#34;https://gist.github.com/1609547&#34;&gt;https://gist.github.com/1609547&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://thejeshgn.com&#34;&gt;Thejesh GN&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;5 Dec 2011 6:47 am&lt;/em&gt;:
Check this
&lt;a href=&#34;http://markdoc.org&#34;&gt;http://markdoc.org&lt;/a&gt;
I have been using it locally for sometime. Its cool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;4 Dec 2011 12:18 pm&lt;/em&gt;:
James, your suggestion on following URLs is spot-on! I&amp;rsquo;ll put this in (one of these days, when I get back to this&amp;hellip;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;6 Dec 2011 10:10 pm&lt;/em&gt;:
You need to have an empty line before a list. For example:
&lt;h1 id=&#34;test&#34;&gt;Test&lt;/h1&gt;
This is a list:
* one
* two
* three&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://osweb.dk&#34;&gt;Michael Lajlev&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;5 Dec 2011 2:12 pm&lt;/em&gt;:
I seem to struggle getting list items to work &lt;a href=&#34;http://markdress.org/dl.dropbox.com/u/623576/test.md&#34;&gt;http://markdress.org/dl.dropbox.com/u/623576/test.md&lt;/a&gt;
Any idea?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gee&lt;/strong&gt; &lt;em&gt;12 Jan 2012 9:14 pm&lt;/em&gt;:
Markdress is great. I have it running on my server. I would like to render files in a directory adjacent to, or inside the app folder, instead of entering a URL path each time. I would like to enter just &lt;code&gt;filename.txt&lt;/code&gt; and it would default back to (effectively) &lt;code&gt;/markdress/filename.txt&lt;/code&gt;
I looked over index.php and tried a few things but I can&amp;rsquo;t get relative files to render. Is this an enhancement you&amp;rsquo;ve considered? Thanks for the great tool.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;13 Jan 2012 12:51 am&lt;/em&gt;:
I personally use this sort of a variant, but havent gotten around to making the same changes on markdress. I will do that over the next few days, once I settle down.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://bootcamp.jfdi.asia/2011/12/03/the-bootcamp-blog-begins/&#34;&gt;The Bootcamp Blog Begins | JFDI–Innov8 2012 Bootcamp&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;3 Dec 2011 8:16 pm&lt;/em&gt; &lt;em&gt;(pingback)&lt;/em&gt;:
[&amp;hellip;] kind of people who can whip up something like Markdress in a [&amp;hellip;]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://blog.sublogic.com/&#34;&gt;James Manning&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;4 Dec 2011 9:08 am&lt;/em&gt;:
Awesome! Nicely done!
Not sure if it&amp;rsquo;s by design or not, but FWIW the example given seems to show that relative url&amp;rsquo;s aren&amp;rsquo;t handled correctly - the bottom of this page:
&lt;a href=&#34;http://daringfireball.net/projects/markdown/index.text&#34;&gt;http://daringfireball.net/projects/markdown/index.text&lt;/a&gt;
has this relative url:
[tfmenu]: /graphics/markdown/mt_textformat_menu.png
which gets faithfully rendered into:
That fails, of course, with the attempted get operation returning:
&lt;a href=&#34;http://markdress.org/graphics/markdown/mt&#34;&gt;http://markdress.org/graphics/markdown/mt&lt;/a&gt;_textformat_menu.png
Could not fetch http://graphics/markdown/mt_textformat_menu.png
FWIW, inserting a base tag in the head seems to work fine, like:
However, it would have to be the &amp;lsquo;real&amp;rsquo; url in the base - IOW, this doesn&amp;rsquo;t work:
On a related note, IMHO it seems like markdress should handle redirects and &amp;lsquo;pass through&amp;rsquo; as a redirect to the markdress version.
IOW, looking at this example request from the post:
&lt;a href=&#34;http://markdress.org/goo.gl/zTG1q&#34;&gt;http://markdress.org/goo.gl/zTG1q&lt;/a&gt;
When markdress requested the page and got back a redirect, instead of following it, it should have instead passed back a redirect to:
&lt;a href=&#34;http://markdress.org/daringfireball.net/projects/markdown/index.text&#34;&gt;http://markdress.org/daringfireball.net/projects/markdown/index.text&lt;/a&gt;
IMHO, that&amp;rsquo;s a better user experience as it&amp;rsquo;s more clear what&amp;rsquo;s getting served up (and it would reflect in the title as well). If/when caching was added (assuming it&amp;rsquo;s not there now), then you&amp;rsquo;d want to have the canonical url for targets anyway. :)
That behavior isn&amp;rsquo;t required to fix the relative-url issue, but since you&amp;rsquo;ll have to know what requests redirect to (the call may be implicitly following it now, so you don&amp;rsquo;t currently know?), then you&amp;rsquo;ll have the necessary info to do this piece as well. :)
Thanks again for marking markdress! It&amp;rsquo;s definitely going to be incredibly useful!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://jeffbyrn.es/&#34;&gt;Jeff Byrnes&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;6 Dec 2012 3:14 pm&lt;/em&gt;:
Markdress appears to have expired, any chance of its return?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;http://www.s-anand.net/&#34;&gt;S Anand&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;7 Dec 2012 3:53 am&lt;/em&gt;:
I didn&amp;rsquo;t think anyone was using it &amp;ndash; so I just let the domain expire.
Alternatives are at &lt;a href=&#34;https://github.com/sanand0/markdress#alternatives&#34;&gt;https://github.com/sanand0/markdress#alternatives&lt;/a&gt;. You could also host the code yourself.&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- wp-comments-end --&gt;
</description>
    </item>
  </channel>
</rss>
