···11<!DOCTYPE html>
22-<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="oppiliappan's μsings" /><meta name="author" content="Akshay Oppiliappan" /><meta name="color-scheme" content="light dark" /><meta name="twitter:card" content="summary" /><title>configuring jujutsu</title><link rel="stylesheet" href="/style.css?v=215baaaf" /><style>html { font-size-adjust: ex-height 0.53; }</style><meta property="og:type" content="website" /><meta property="og:site_name" content="oppi.li" /><meta property="og:title" content="configuring jujutsu" /><meta property="og:description" content="oppiliappan's μsings" /></head><body><div class="min-h-screen flex flex-col"><nav class="px-2"><a href="/">home</a><span> :: <a href="/posts">posts</a></span><span> :: <a href="#">configuring jujutsu</a></span></nav><main class="px-2"><div class="max-w-xl mx-auto text-pretty mb-12"><h1 class="text-center">configuring jujutsu</h1><div class="text-center space-x-2"><span>7 min</span><span>·</span><span>79 sentences</span><span>·</span><span>188.48 cm</span><span>·</span><span>24.05.2025</span></div><p>There are a lot of reasons to use
22+<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="oppiliappan's μsings" /><meta name="author" content="Akshay Oppiliappan" /><meta name="color-scheme" content="light dark" /><meta name="twitter:card" content="summary" /><title>configuring jujutsu</title><link rel="stylesheet" href="/style.css?v=215baaaf" /><style>html { font-size-adjust: ex-height 0.53; }</style><meta property="og:type" content="website" /><meta property="og:site_name" content="oppi.li" /><meta property="og:title" content="configuring jujutsu" /><meta property="og:description" content="oppiliappan's μsings" /></head><body><div class="min-h-screen flex flex-col max-w-xl mx-auto"><nav class="px-2"><a href="/">home</a><span> :: <a href="/posts">posts</a></span><span> :: <a href="#">configuring jujutsu</a></span></nav><main class="px-2"><div class="text-pretty mb-12"><h1 class="text-center">configuring jujutsu</h1><div class="text-center space-x-2"><span>7 min</span><span>·</span><span>79 sentences</span><span>·</span><span>188.48 cm</span><span>·</span><span>24.05.2025</span></div><p>There are a lot of reasons to use
33<a href="https://github.com/jj-vcs/jj">jujutsu</a>, but this post is
44not about that. I have this terrible habit of turning every
55knob on a tool before I even fully absorb how it works; and
+1-1
_site/posts/curing_a_case_of_git-UX/index.html
···11<!DOCTYPE html>
22-<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="oppiliappan's μsings" /><meta name="author" content="Akshay Oppiliappan" /><meta name="color-scheme" content="light dark" /><meta name="twitter:card" content="summary" /><title>curing a case of git-UX</title><link rel="stylesheet" href="/style.css?v=215baaaf" /><style>html { font-size-adjust: ex-height 0.53; }</style><meta property="og:type" content="website" /><meta property="og:site_name" content="oppi.li" /><meta property="og:title" content="curing a case of git-UX" /><meta property="og:description" content="oppiliappan's μsings" /></head><body><div class="min-h-screen flex flex-col"><nav class="px-2"><a href="/">home</a><span> :: <a href="/posts">posts</a></span><span> :: <a href="#">curing a case of git-UX</a></span></nav><main class="px-2"><div class="max-w-xl mx-auto text-pretty mb-12"><h1 class="text-center">curing a case of git-UX</h1><div class="text-center space-x-2"><span>7 min</span><span>·</span><span>143 sentences</span><span>·</span><span>167.65 cm</span><span>·</span><span>03.09.2022</span></div><p>Git worktrees are great, but they fall behind the venerable
22+<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="oppiliappan's μsings" /><meta name="author" content="Akshay Oppiliappan" /><meta name="color-scheme" content="light dark" /><meta name="twitter:card" content="summary" /><title>curing a case of git-UX</title><link rel="stylesheet" href="/style.css?v=215baaaf" /><style>html { font-size-adjust: ex-height 0.53; }</style><meta property="og:type" content="website" /><meta property="og:site_name" content="oppi.li" /><meta property="og:title" content="curing a case of git-UX" /><meta property="og:description" content="oppiliappan's μsings" /></head><body><div class="min-h-screen flex flex-col max-w-xl mx-auto"><nav class="px-2"><a href="/">home</a><span> :: <a href="/posts">posts</a></span><span> :: <a href="#">curing a case of git-UX</a></span></nav><main class="px-2"><div class="text-pretty mb-12"><h1 class="text-center">curing a case of git-UX</h1><div class="text-center space-x-2"><span>7 min</span><span>·</span><span>143 sentences</span><span>·</span><span>167.65 cm</span><span>·</span><span>03.09.2022</span></div><p>Git worktrees are great, but they fall behind the venerable
33<code>git checkout</code> sometimes. I attempted to fix that with
44<a href="https://github.com/junegunn/fzf">fzf</a> and
55a bit of bash.</p>
+1-1
_site/posts/font_size_fallacies/index.html
···11<!DOCTYPE html>
22-<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="oppiliappan's μsings" /><meta name="author" content="Akshay Oppiliappan" /><meta name="color-scheme" content="light dark" /><meta name="twitter:card" content="summary" /><title>font size fallacies</title><link rel="stylesheet" href="/style.css?v=215baaaf" /><style>html { font-size-adjust: ex-height 0.53; }</style><meta property="og:type" content="website" /><meta property="og:site_name" content="oppi.li" /><meta property="og:title" content="font size fallacies" /><meta property="og:description" content="oppiliappan's μsings" /></head><body><div class="min-h-screen flex flex-col"><nav class="px-2"><a href="/">home</a><span> :: <a href="/posts">posts</a></span><span> :: <a href="#">font size fallacies</a></span></nav><main class="px-2"><div class="max-w-xl mx-auto text-pretty mb-12"><h1 class="text-center">font size fallacies</h1><div class="text-center space-x-2"><span>2 min</span><span>·</span><span>44 sentences</span><span>·</span><span>41.15 cm</span><span>·</span><span>16.03.2020</span></div><p>I am not an expert with fonts, but I do have some
22+<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="oppiliappan's μsings" /><meta name="author" content="Akshay Oppiliappan" /><meta name="color-scheme" content="light dark" /><meta name="twitter:card" content="summary" /><title>font size fallacies</title><link rel="stylesheet" href="/style.css?v=215baaaf" /><style>html { font-size-adjust: ex-height 0.53; }</style><meta property="og:type" content="website" /><meta property="og:site_name" content="oppi.li" /><meta property="og:title" content="font size fallacies" /><meta property="og:description" content="oppiliappan's μsings" /></head><body><div class="min-h-screen flex flex-col max-w-xl mx-auto"><nav class="px-2"><a href="/">home</a><span> :: <a href="/posts">posts</a></span><span> :: <a href="#">font size fallacies</a></span></nav><main class="px-2"><div class="text-pretty mb-12"><h1 class="text-center">font size fallacies</h1><div class="text-center space-x-2"><span>2 min</span><span>·</span><span>44 sentences</span><span>·</span><span>41.15 cm</span><span>·</span><span>16.03.2020</span></div><p>I am not an expert with fonts, but I do have some
33experience <a href="https://github.com/nerdypepper/scientifica">^exp</a>, and common sense. This post aims to debunk some
44misconceptions about font sizes!</p>
55<p>11 px on your display is <em>probably not</em> 11 px on my display.
···88 <language>en-us</language>
99 <copyright>Creative Commons BY-NC-SA 4.0</copyright>
1010 <item>
1111+ <title>jjj</title>
1212+ <description><p>Several <a href="https://docs.jj-vcs.dev/latest/">jujutsu</a> commands
1313+require a revset. When I am hacking on a project, I tend to
1414+poke at <a href="https://blog.tangled.org/stacking/#interdiff-code-review-on-tangled">multiple
1515+stacks</a>
1616+simultaneously. Many of these stacks use a <a href="https://docs.jj-vcs.dev/latest/config/#generated-bookmark-names-on-push">generated
1717+bookmark
1818+name</a>.</p>
1919+<p>Identifying them becomes a bit tricky after a while, so I've
2020+created a little script with <code>fzf</code>, called <code>jjj</code> (jujutsu
2121+jump i suppose), to help me select revsets:</p>
2222+<pre><code class="language-bash">cmd=&quot;${1:-show}&quot;
2323+2424+selected=$(
2525+ jj log -r 'all()' --color=always \
2626+ | fzf \
2727+ --min-height=15 \
2828+ --cycle \
2929+ --ansi \
3030+ --prompt &quot;jj $cmd&gt; &quot;
3131+) || exit 0
3232+3333+rev=$(echo &quot;$selected&quot; | awk '{for(i=1;i&lt;=NF;i++) if(length($i)&gt;=7){print $i; exit}}')
3434+3535+jj &quot;$cmd&quot; -r &quot;$rev&quot; &quot;$@&quot;
3636+</code></pre>
3737+<p><code>jjj</code> is exactly like <code>jj</code>, except your revset selection
3838+happens inside <code>fzf</code>. Every other arg is just passed
3939+straight through.</p>
4040+<p>This opens up <code>jj log</code> in an fzf window:</p>
4141+<pre><code>$ jjj new
4242+jj new&gt;
4343+ 4774/4774
4444+ @ srppunpn (empty) (no description set) default@ 2h
4545+&gt; • qknsmttw knotserver: remove `--allow-empty` from `git am`..
4646+ • lqvzlslt knotserver: calculate old/new SHAs in merge 2h
4747+ │ · lqvzlslt knotserver: calculate old/new SHAs in merge op..
4848+ ├─╯
4949+ • xqwtwoxr appview,blog: add twitter link to footer 20h
5050+ • vsrmrrlt knotserver/xrpc: emit `refUpdate` event on `repo..
5151+ • orsknlnx knotserver/git: allow applying empty patches 20h
5252+ │ • xqwtwoxr appview,blog: add twitter link to footer icy/x..
5353+ ├─╯
5454+ • nrrqukxt ogre: center align footer items 21h
5555+ │ · llvrxstp appview/timeline: announce vouching in timelin..
5656+ │ · uztumlpw appview/pages: add vouch hats 20h
5757+ │ · urzpovyu appview/state: add vouch handlers 20h
5858+ │ · xwysqnul appview/ingester: ingest vouch records 23h
5959+ │ · vrpmqwpu appview/{db,models}: add table and models for ..
6060+ │ · oswtmkqr lexicons: add vouch lexicon 1d
6161+ ├─╯
6262+ │ · lxrslzty (empty) (no description set) 1d
6363+ │ · nzqqortv knotserver: limit request size op/nzqqortvpnzz..
6464+</code></pre>
6565+<p>You can filter by typing a keyword, say, &quot;vouch&quot; in my case:</p>
6666+<pre><code>$ jjj new
6767+jj new&gt; vouch
6868+ 515/4774
6969+&gt; │ · oswtmkqr lexicons: add vouch lexicon 1d
7070+ │ · uztumlpw appview/pages: add vouch hats 20h
7171+ │ · urzpovyu appview/state: add vouch handlers 20h
7272+ │ · xwysqnul appview/ingester: ingest vouch records 23h
7373+ ..u appview/{db,models}: add table and models for vouching 23h
7474+ │ · llvrxstp appview/timeline: announce vouching in timelin..
7575+ • vouqlrtz improve branch-pr ux branch-prs-2 1y
7676+ • vxozrylw deps: use fork of chroma 11mo
7777+ • vwknkkmt fix default value for resubmitCheck 1y
7878+ • vnxlozsk feature: ability to change default branch for a ..
7979+ ..ysx knotserver: have top level router use cors header func..
8080+</code></pre>
8181+<p>Hitting enter simply substitutes that rev into a <code>jj new</code>
8282+command:</p>
8383+<pre><code>$ jjj new
8484+# perform a selection in fzf
8585+8686+$ jj new -r oswtmkqr
8787+</code></pre>
8888+<p>You could use any <code>jj</code> command really:</p>
8989+<pre><code>$ jjj edit
9090+$ jjj show
9191+$ jjj evolog -p
9292+</code></pre>
9393+<p>This is because almost all <code>jj</code> commands accept a revset
9494+using the <code>-r</code> flag:</p>
9595+<pre><code>$ jj show --help
9696+ .
9797+ .
9898+ .
9999+Arguments:
100100+ [REVSET]
101101+ Show changes in this revision, compared to its parent(s) [default: @] [aliases: -r]
102102+</code></pre>
103103+<p>You can add a preview window, to view the patch for each
104104+change, with these flags:</p>
105105+<pre><code> --preview 'echo {} | awk &quot;{for(i=1;i&lt;=NF;i++) if(length(\$i)&gt;=7){print \$i; exit}}&quot; | xargs jj show --color=always ' \
106106+ --preview-window=right:60% \
107107+</code></pre>
108108+<p>Note that the <code>jjj</code> is tuned to my log template. It requires
109109+that your log output be one-line per change and that you
110110+print a full 7+ character change-id in the log. Mutate as
111111+required.</p>
112112+</description>
113113+ <link>https://oppi.li/posts/jjj/</link>
114114+ <pubDate>Thu, 31 Jul 2025 00:00:00 +0000</pubDate>
115115+ <guid>https://oppi.li/posts/jjj/</guid>
116116+ </item>
117117+ <item>
11118 <title>mounting the atmosphere</title>
12119 <description><p><a href="https://tangled.sh/@oppi.li/pdsfs">pdsfs</a> is a tool that
13120mounts <a href="https://atproto.com">atproto</a> PDS repositories as a
···11+<!DOCTYPE html>
22+<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><meta name="description" content="oppiliappan's μsings" /><meta name="author" content="Akshay Oppiliappan" /><meta name="color-scheme" content="light dark" /><meta name="twitter:card" content="summary" /><title>2026-17</title><link rel="stylesheet" href="/style.css?v=215baaaf" /><style>html { font-size-adjust: ex-height 0.53; }</style><meta property="og:type" content="website" /><meta property="og:site_name" content="oppi.li" /><meta property="og:title" content="2026-17" /><meta property="og:description" content="oppiliappan's μsings" /></head><body><div class="min-h-screen flex flex-col max-w-xl mx-auto"><nav class="px-2"><a href="/">home</a><span> :: <a href="/weeklies">weeklies</a></span><span> :: <a href="#">2026-17</a></span></nav><main class="px-2"><div class="text-pretty mb-12"><h1 class="text-center">2026-17</h1><div class="text-center space-x-2"><span>2 min</span><span>·</span><span>40 sentences</span><span>·</span><span>43.18 cm</span><span>·</span><span>28.04.2026</span></div><h2 id="joining-cambridge">Joining Cambridge</h2>
33+<p>I am thrilled to announce that I have joined Cambridge as a
44+Research Associate working under <a href="https://anil.recoil.org">Anil
55+Madhavapeddy</a>. I thank the EE group
66+for the <a href="https://anil.recoil.org/notes/2026w17#welcoming-akshay-to-cambridge">warm
77+welcome</a>
88+(or <a href="https://www.jacksgelato.com/">cold?</a>).</p>
99+<p>My immidiate areas of focus are to customize knots to make
1010+them more amenable to scientific workloads (LFS or
1111+<a href="https://git-scm.com/docs/large-object-promisors">LOPs</a>),
1212+and also towards building a subset-appview of the Tangled
1313+network, which first requires total appview independence.</p>
1414+<h2 id="towards-appview-independence">Towards appview independence</h2>
1515+<p>This week, I finally finished off my work on
1616+<a href="https://bsky.app/profile/oppi.li/post/3lnkhoyqlos2d">"atprotation"</a>
1717+of pull-requests on Tangled. It is now possible to open PRs
1818+(stacked or otherwise) on a Tangled repository using just
1919+atproto records. This brings us one step closer to a totally
2020+self-hostable Tangled.</p>
2121+<p>Presently, to use some parts of Tangled, you will need to
2222+log into the website. The parts of Tangled that are usable
2323+<em>without</em> the existing appview are:</p>
2424+<ul>
2525+<li>setting up knots, pushing/pulling from them
2626+</li>
2727+<li>setting up spindles, executing CI jobs
2828+</li>
2929+<li>opening issues, commenting on them
3030+</li>
3131+<li>(new) opening PRs, resubmitting them etc.
3232+</li>
3333+<li>social bits: follows, stars
3434+</li>
3535+</ul>
3636+<p>However repository operations are dependent, they have to go
3737+through the appview in order to be transacted safely, but
3838+there is <a href="https://tangled.org/tangled.org/core/pulls/1135/round/16">work in
3939+progress</a>
4040+to solve that as well.</p>
4141+<h2 id="vouching-on-tangled">Vouching on Tangled</h2>
4242+<p>I've also finalized my work on building a web-of-trust on
4343+Tangled using atproto this week. It largely builds on the
4444+<a href="https://github.com/mitchellh/vouch/">vouch</a> project. Some
4545+considerations:</p>
4646+<ul>
4747+<li>all ops are public, much like the original vouch project
4848+</li>
4949+<li>you can vouch/denounce anybody, along with a reason
5050+</li>
5151+<li>vouching/denouncing does not block interactions, it only
5252+serves as a marker on the interface, to inform descisions,
5353+this may change down the line
5454+</li>
5555+</ul>
5656+<p>Things I want to add to this:</p>
5757+<ul>
5858+<li>decay over time: vouch/denounce records could decay over
5959+time, and require re-attestation after a while, credits to
6060+Anil for this brilliant idea
6161+</li>
6262+<li>evidence based vouching: vouching for a user after merging
6363+their PR would automagically add a piece of evidence to
6464+their vouch record
6565+</li>
6666+</ul>
6767+<h2 id="ocaml-hacking">OCaml hacking</h2>
6868+<p>I have been poking at the
6969+<a href="https://tangled.org/oppi.li/site">site</a> a bit more.
7070+Surprisingly, more than one person reached out to me to tell
7171+me that my RSS feed was missing! The RSS feed has now been
7272+reinstated, there is one for the weeklies and another for my
7373+musings, and a secret third one for my art.</p>
7474+<p>I've also quickly <a href="https://tangled.org/oppi.li/modal/">whipped up an
7575+interpreter</a> for
7676+<a href="https://wryl.tech/projects/modal.html">Modal</a>, to showcase
7777+my <a href="https://tangled.org/patrick.sirref.org/bruit/">bruit</a>
7878+<a href="https://tangled.org/oppi.li/bruit">fork</a> that operates on
7979+the web. It does include a web-repl and a terminal-repl, but
8080+they do require some polish.</p>
8181+<h2 id="life">Life</h2>
8282+<p>I have started packing up my flat to move to a new place,
8383+leaving <a href="https://oppi.li/weeklies/2026-16/#travel">several
8484+houseplants</a>
8585+behind.</p>
8686+</div></main></div></body></html>
···88 <language>en-us</language>
99 <copyright>Creative Commons BY-NC-SA 4.0</copyright>
1010 <item>
1111+ <title>2026-17</title>
1212+ <description><h2 id="joining-cambridge">Joining Cambridge</h2>
1313+<p>I am thrilled to announce that I have joined Cambridge as a
1414+Research Associate working under <a href="https://anil.recoil.org">Anil
1515+Madhavapeddy</a>. I thank the EE group
1616+for the <a href="https://anil.recoil.org/notes/2026w17#welcoming-akshay-to-cambridge">warm
1717+welcome</a>
1818+(or <a href="https://www.jacksgelato.com/">cold?</a>).</p>
1919+<p>My immidiate areas of focus are to customize knots to make
2020+them more amenable to scientific workloads (LFS or
2121+<a href="https://git-scm.com/docs/large-object-promisors">LOPs</a>),
2222+and also towards building a subset-appview of the Tangled
2323+network, which first requires total appview independence.</p>
2424+<h2 id="towards-appview-independence">Towards appview independence</h2>
2525+<p>This week, I finally finished off my work on
2626+<a href="https://bsky.app/profile/oppi.li/post/3lnkhoyqlos2d">&quot;atprotation&quot;</a>
2727+of pull-requests on Tangled. It is now possible to open PRs
2828+(stacked or otherwise) on a Tangled repository using just
2929+atproto records. This brings us one step closer to a totally
3030+self-hostable Tangled.</p>
3131+<p>Presently, to use some parts of Tangled, you will need to
3232+log into the website. The parts of Tangled that are usable
3333+<em>without</em> the existing appview are:</p>
3434+<ul>
3535+<li>setting up knots, pushing/pulling from them
3636+</li>
3737+<li>setting up spindles, executing CI jobs
3838+</li>
3939+<li>opening issues, commenting on them
4040+</li>
4141+<li>(new) opening PRs, resubmitting them etc.
4242+</li>
4343+<li>social bits: follows, stars
4444+</li>
4545+</ul>
4646+<p>However repository operations are dependent, they have to go
4747+through the appview in order to be transacted safely, but
4848+there is <a href="https://tangled.org/tangled.org/core/pulls/1135/round/16">work in
4949+progress</a>
5050+to solve that as well.</p>
5151+<h2 id="vouching-on-tangled">Vouching on Tangled</h2>
5252+<p>I've also finalized my work on building a web-of-trust on
5353+Tangled using atproto this week. It largely builds on the
5454+<a href="https://github.com/mitchellh/vouch/">vouch</a> project. Some
5555+considerations:</p>
5656+<ul>
5757+<li>all ops are public, much like the original vouch project
5858+</li>
5959+<li>you can vouch/denounce anybody, along with a reason
6060+</li>
6161+<li>vouching/denouncing does not block interactions, it only
6262+serves as a marker on the interface, to inform descisions,
6363+this may change down the line
6464+</li>
6565+</ul>
6666+<p>Things I want to add to this:</p>
6767+<ul>
6868+<li>decay over time: vouch/denounce records could decay over
6969+time, and require re-attestation after a while, credits to
7070+Anil for this brilliant idea
7171+</li>
7272+<li>evidence based vouching: vouching for a user after merging
7373+their PR would automagically add a piece of evidence to
7474+their vouch record
7575+</li>
7676+</ul>
7777+<h2 id="ocaml-hacking">OCaml hacking</h2>
7878+<p>I have been poking at the
7979+<a href="https://tangled.org/oppi.li/site">site</a> a bit more.
8080+Surprisingly, more than one person reached out to me to tell
8181+me that my RSS feed was missing! The RSS feed has now been
8282+reinstated, there is one for the weeklies and another for my
8383+musings, and a secret third one for my art.</p>
8484+<p>I've also quickly <a href="https://tangled.org/oppi.li/modal/">whipped up an
8585+interpreter</a> for
8686+<a href="https://wryl.tech/projects/modal.html">Modal</a>, to showcase
8787+my <a href="https://tangled.org/patrick.sirref.org/bruit/">bruit</a>
8888+<a href="https://tangled.org/oppi.li/bruit">fork</a> that operates on
8989+the web. It does include a web-repl and a terminal-repl, but
9090+they do require some polish.</p>
9191+<h2 id="life">Life</h2>
9292+<p>I have started packing up my flat to move to a new place,
9393+leaving <a href="https://oppi.li/weeklies/2026-16/#travel">several
9494+houseplants</a>
9595+behind.</p>
9696+</description>
9797+ <link>https://oppi.li/weeklies/2026-17/</link>
9898+ <pubDate>Tue, 28 Apr 2026 00:00:00 +0000</pubDate>
9999+ <guid>https://oppi.li/weeklies/2026-17/</guid>
100100+ </item>
101101+ <item>
11102 <title>2026-16</title>
12103 <description><h2 id="fp-launchpad-at-iit-madras">FP Launchpad at IIT Madras</h2>
13104<p>I had the pleasure of attending the inaugration of <a href="https://fplaunchpad.org/">FP
+14-11
bin/art.ml
···1010 let card ?(base = "") post =
1111 Tw_html.(
1212 a
1313- ~at:At.[ href (img_url post) ]
1313+ ~at:At.[ href (img_url post); style "color:inherit" ]
1414 ~tw:Tw.[ no_underline ]
1515 [
1616- img ~at:At.[ src (img_url post); alt (P.title post); loading_lazy ] ();
1616+ img
1717+ ~tw:Tw.[ w_full ]
1818+ ~at:At.[ src (img_url post); alt (P.title post); loading_lazy ]
1919+ ();
1720 ])
18211919- let masonry_order ~cols xs =
2020- let buckets = Array.make cols [] in
2121- List.iteri (fun i x -> buckets.(i mod cols) <- x :: buckets.(i mod cols)) xs;
2222- Array.to_list buckets |> List.concat_map List.rev
2222+ let split_buckets ~cols xs =
2323+ List.init cols (fun c -> List.filteri (fun i _ -> i mod cols = c) xs)
23242425 let render posts =
2525- let items =
2626+ let buckets =
2627 List.sort compare_date posts
2727- |> masonry_order ~cols:2
2828- |> List.map (fun post -> Tw_html.(div ~tw:Tw.[ mb 4 ] [ card post ]))
2828+ |> split_buckets ~cols:2
2929+ |> List.map (fun bucket ->
3030+ Tw_html.(
3131+ div ~tw:Tw.[ flex; flex_col; flex_1; gap 4 ] (List.map card bucket)))
2932 in
3033 Tw_html.(
3134 div
···3336 [
3437 h1 ~tw:Tw.[ text_center ] [ txt "art" ];
3538 div
3636- ~tw:Tw.[ text_center; space_x 2. ]
3939+ ~tw:Tw.[ text_center; space_x 4. ]
3740 [ span [ txt (Printf.sprintf "%d pieces" (List.length posts)) ] ];
3838- div ~tw:Tw.([ mt 4; space_y 2. ] @ str "columns-2") items;
4141+ div ~tw:Tw.[ flex; mt 4; gap 4 ] buckets;
3942 ])
40434144 let preview ?(base = "") ~limit posts =
+127
content/posts/jjj.md
···11+---
22+date: 31-07-2025
33+---
44+Several [jujutsu](https://docs.jj-vcs.dev/latest/) commands
55+require a revset. When I am hacking on a project, I tend to
66+poke at [multiple
77+stacks](https://blog.tangled.org/stacking/#interdiff-code-review-on-tangled)
88+simultaneously. Many of these stacks use a [generated
99+bookmark
1010+name](https://docs.jj-vcs.dev/latest/config/#generated-bookmark-names-on-push).
1111+1212+Identifying them becomes a bit tricky after a while, so I've
1313+created a little script with `fzf`, called `jjj` (jujutsu
1414+jump i suppose), to help me select revsets:
1515+1616+```bash
1717+cmd="${1:-show}"
1818+1919+selected=$(
2020+ jj log -r 'all()' --color=always \
2121+ | fzf \
2222+ --min-height=15 \
2323+ --cycle \
2424+ --ansi \
2525+ --prompt "jj $cmd> "
2626+) || exit 0
2727+2828+rev=$(echo "$selected" | awk '{for(i=1;i<=NF;i++) if(length($i)>=7){print $i; exit}}')
2929+3030+jj "$cmd" -r "$rev" "$@"
3131+```
3232+3333+`jjj` is exactly like `jj`, except your revset selection
3434+happens inside `fzf`. Every other arg is just passed
3535+straight through.
3636+3737+This opens up `jj log` in an fzf window:
3838+3939+```
4040+$ jjj new
4141+jj new>
4242+ 4774/4774
4343+ @ srppunpn (empty) (no description set) default@ 2h
4444+> • qknsmttw knotserver: remove `--allow-empty` from `git am`..
4545+ • lqvzlslt knotserver: calculate old/new SHAs in merge 2h
4646+ │ · lqvzlslt knotserver: calculate old/new SHAs in merge op..
4747+ ├─╯
4848+ • xqwtwoxr appview,blog: add twitter link to footer 20h
4949+ • vsrmrrlt knotserver/xrpc: emit `refUpdate` event on `repo..
5050+ • orsknlnx knotserver/git: allow applying empty patches 20h
5151+ │ • xqwtwoxr appview,blog: add twitter link to footer icy/x..
5252+ ├─╯
5353+ • nrrqukxt ogre: center align footer items 21h
5454+ │ · llvrxstp appview/timeline: announce vouching in timelin..
5555+ │ · uztumlpw appview/pages: add vouch hats 20h
5656+ │ · urzpovyu appview/state: add vouch handlers 20h
5757+ │ · xwysqnul appview/ingester: ingest vouch records 23h
5858+ │ · vrpmqwpu appview/{db,models}: add table and models for ..
5959+ │ · oswtmkqr lexicons: add vouch lexicon 1d
6060+ ├─╯
6161+ │ · lxrslzty (empty) (no description set) 1d
6262+ │ · nzqqortv knotserver: limit request size op/nzqqortvpnzz..
6363+```
6464+6565+You can filter by typing a keyword, say, "vouch" in my case:
6666+6767+```
6868+$ jjj new
6969+jj new> vouch
7070+ 515/4774
7171+> │ · oswtmkqr lexicons: add vouch lexicon 1d
7272+ │ · uztumlpw appview/pages: add vouch hats 20h
7373+ │ · urzpovyu appview/state: add vouch handlers 20h
7474+ │ · xwysqnul appview/ingester: ingest vouch records 23h
7575+ ..u appview/{db,models}: add table and models for vouching 23h
7676+ │ · llvrxstp appview/timeline: announce vouching in timelin..
7777+ • vouqlrtz improve branch-pr ux branch-prs-2 1y
7878+ • vxozrylw deps: use fork of chroma 11mo
7979+ • vwknkkmt fix default value for resubmitCheck 1y
8080+ • vnxlozsk feature: ability to change default branch for a ..
8181+ ..ysx knotserver: have top level router use cors header func..
8282+```
8383+8484+Hitting enter simply substitutes that rev into a `jj new`
8585+command:
8686+8787+```
8888+$ jjj new
8989+# perform a selection in fzf
9090+9191+$ jj new -r oswtmkqr
9292+```
9393+9494+You could use any `jj` command really:
9595+9696+```
9797+$ jjj edit
9898+$ jjj show
9999+$ jjj evolog -p
100100+```
101101+102102+This is because almost all `jj` commands accept a revset
103103+using the `-r` flag:
104104+105105+```
106106+$ jj show --help
107107+ .
108108+ .
109109+ .
110110+Arguments:
111111+ [REVSET]
112112+ Show changes in this revision, compared to its parent(s) [default: @] [aliases: -r]
113113+```
114114+115115+You can add a preview window, to view the patch for each
116116+change, with these flags:
117117+118118+```
119119+ --preview 'echo {} | awk "{for(i=1;i<=NF;i++) if(length(\$i)>=7){print \$i; exit}}" | xargs jj show --color=always ' \
120120+ --preview-window=right:60% \
121121+```
122122+123123+Note that the `jjj` is tuned to my log template. It requires
124124+that your log output be one-line per change and that you
125125+print a full 7+ character change-id in the log. Mutate as
126126+required.
127127+
+88
content/weeklies/2026-17.md
···11+---
22+date: 28-04-2026
33+---
44+## Joining Cambridge
55+66+I am thrilled to announce that I have joined Cambridge as a
77+Research Associate working under [Anil
88+Madhavapeddy](https://anil.recoil.org). I thank the EE group
99+for the [warm
1010+welcome](https://anil.recoil.org/notes/2026w17#welcoming-akshay-to-cambridge)
1111+(or [cold?](https://www.jacksgelato.com/)).
1212+1313+My immidiate areas of focus are to customize knots to make
1414+them more amenable to scientific workloads (LFS or
1515+[LOPs](https://git-scm.com/docs/large-object-promisors)),
1616+and also towards building a subset-appview of the Tangled
1717+network, which first requires total appview independence.
1818+1919+## Towards appview independence
2020+2121+This week, I finally finished off my work on
2222+["atprotation"](https://bsky.app/profile/oppi.li/post/3lnkhoyqlos2d)
2323+of pull-requests on Tangled. It is now possible to open PRs
2424+(stacked or otherwise) on a Tangled repository using just
2525+atproto records. This brings us one step closer to a totally
2626+self-hostable Tangled.
2727+2828+Presently, to use some parts of Tangled, you will need to
2929+log into the website. The parts of Tangled that are usable
3030+*without* the existing appview are:
3131+3232+- setting up knots, pushing/pulling from them
3333+- setting up spindles, executing CI jobs
3434+- opening issues, commenting on them
3535+- (new) opening PRs, resubmitting them etc.
3636+- social bits: follows, stars
3737+3838+However repository operations are dependent, they have to go
3939+through the appview in order to be transacted safely, but
4040+there is [work in
4141+progress](https://tangled.org/tangled.org/core/pulls/1135/round/16)
4242+to solve that as well.
4343+4444+## Vouching on Tangled
4545+4646+I've also finalized my work on building a web-of-trust on
4747+Tangled using atproto this week. It largely builds on the
4848+[vouch](https://github.com/mitchellh/vouch/) project. Some
4949+considerations:
5050+5151+- all ops are public, much like the original vouch project
5252+- you can vouch/denounce anybody, along with a reason
5353+- vouching/denouncing does not block interactions, it only
5454+ serves as a marker on the interface, to inform descisions,
5555+ this may change down the line
5656+5757+Things I want to add to this:
5858+5959+- decay over time: vouch/denounce records could decay over
6060+ time, and require re-attestation after a while, credits to
6161+ Anil for this brilliant idea
6262+- evidence based vouching: vouching for a user after merging
6363+ their PR would automagically add a piece of evidence to
6464+ their vouch record
6565+6666+## OCaml hacking
6767+6868+I have been poking at the
6969+[site](https://tangled.org/oppi.li/site) a bit more.
7070+Surprisingly, more than one person reached out to me to tell
7171+me that my RSS feed was missing! The RSS feed has now been
7272+reinstated, there is one for the weeklies and another for my
7373+musings, and a secret third one for my art.
7474+7575+I've also quickly [whipped up an
7676+interpreter](https://tangled.org/oppi.li/modal/) for
7777+[Modal](https://wryl.tech/projects/modal.html), to showcase
7878+my [bruit](https://tangled.org/patrick.sirref.org/bruit/)
7979+[fork](https://tangled.org/oppi.li/bruit) that operates on
8080+the web. It does include a web-repl and a terminal-repl, but
8181+they do require some polish.
8282+8383+## Life
8484+8585+I have started packing up my flat to move to a new place,
8686+leaving [several
8787+houseplants](https://oppi.li/weeklies/2026-16/#travel)
8888+behind.
+9-7
lib/content.ml
···6767 | _ -> ([], lines)
68686969 let frontmatter t = t.frontmatter
7070- let title' fm path = Option.value (fm_string "title" fm) ~default:(title_of_path path)
7070+7171+ let title' fm path =
7272+ Option.value (fm_string "title" fm) ~default:(title_of_path path)
7373+7174 let title t = title' t.frontmatter t.path
7275 let date' fm = Option.bind (fm_string "date" fm) parse_date
7376 let date t = date' t.frontmatter
···131134 let html =
132135 Tw_html.(
133136 div
134134- ~tw:Tw.[ max_w_xl; mx_auto; text_pretty; mb 12 ]
137137+ ~tw:Tw.[ text_pretty; mb 12 ]
135138 [
136139 h1 ~tw:Tw.[ text_center ] [ txt title'' ];
137140 div
···196199 let content = In_channel.with_open_text path In_channel.input_all in
197200 let frontmatter = Yaml.of_string_exn content in
198201 let slug = path |> Filename.basename |> Filename.remove_extension in
199199- let title = Option.value (fm_string "title" frontmatter) ~default:(title_of_path path) in
202202+ let title =
203203+ Option.value (fm_string "title" frontmatter) ~default:(title_of_path path)
204204+ in
200205 let date = Option.bind (fm_string "date" frontmatter) parse_date in
201206 { slug; frontmatter; title; date }
202207···205210 let title t = t.title
206211 let date t = t.date
207212 let toc _ = []
208208-209213 let img_url slug = Layout.cdn_url ^ "/art/" ^ slug ^ ".png"
210210-211211- let html t =
212212- Tw_html.(img ~at:At.[ src (img_url t.slug); alt t.title ] ())
214214+ let html t = Tw_html.(img ~at:At.[ src (img_url t.slug); alt t.title ] ())
213215214216 let rss_item ~link t =
215217 let title = xml_escape t.title in