<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://upket.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://upket.com/" rel="alternate" type="text/html" /><updated>2026-10-29T15:13:27+00:00</updated><id>https://upket.com/feed.xml</id><title type="html">Upket</title><subtitle>Apps for phone, desktop and web.</subtitle><entry><title type="html">Why I build small apps</title><link href="https://upket.com/writing/why-small-apps/" rel="alternate" type="text/html" title="Why I build small apps" /><published>2026-10-20T00:00:00+00:00</published><updated>2026-10-20T00:00:00+00:00</updated><id>https://upket.com/writing/why-small-apps</id><content type="html" xml:base="https://upket.com/writing/why-small-apps/"><![CDATA[<p>Most of my side projects used to die at 70%. They grew a settings page, a sync engine, an account system — and then I lost interest.</p>

<h2 id="the-rule">The rule</h2>

<p>Now every Upket app starts with one sentence: <em>what does it do in under ten words?</em> If I can’t write that sentence, I don’t start.</p>

<ul>
  <li>One core action, reachable in one tap</li>
  <li>Works offline first, syncs later</li>
  <li>Ship a demo before polishing</li>
</ul>

<blockquote>
  <p>Small apps get finished. Finished apps get used.</p>
</blockquote>

<p>This is a sample post — replace it with your own writing.</p>]]></content><author><name></name></author><category term="thoughts" /><summary type="html"><![CDATA[One problem, one screen, ship it. Notes on keeping side projects small enough to finish.]]></summary></entry><entry><title type="html">How Tally stays fast offline</title><link href="https://upket.com/writing/tally-offline-sync/" rel="alternate" type="text/html" title="How Tally stays fast offline" /><published>2026-09-14T00:00:00+00:00</published><updated>2026-09-14T00:00:00+00:00</updated><id>https://upket.com/writing/tally-offline-sync</id><content type="html" xml:base="https://upket.com/writing/tally-offline-sync/"><![CDATA[<p>Tally writes every purchase to a local database first. The UI never waits for the network.</p>

<h2 id="the-sync-queue">The sync queue</h2>

<p>Each change becomes a small record in a queue. When the phone is online, the queue drains in order:</p>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">data class</span> <span class="nc">Change</span><span class="p">(</span><span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="kd">val</span> <span class="py">op</span><span class="p">:</span> <span class="nc">Op</span><span class="p">,</span> <span class="kd">val</span> <span class="py">at</span><span class="p">:</span> <span class="nc">Long</span><span class="p">)</span>

<span class="k">suspend</span> <span class="k">fun</span> <span class="nf">drain</span><span class="p">(</span><span class="n">queue</span><span class="p">:</span> <span class="nc">Queue</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="p">(</span><span class="k">true</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">val</span> <span class="py">next</span> <span class="p">=</span> <span class="n">queue</span><span class="p">.</span><span class="nf">peek</span><span class="p">()</span> <span class="o">?:</span> <span class="k">break</span>
        <span class="n">api</span><span class="p">.</span><span class="nf">push</span><span class="p">(</span><span class="n">next</span><span class="p">)</span>
        <span class="n">queue</span><span class="p">.</span><span class="nf">remove</span><span class="p">(</span><span class="n">next</span><span class="p">.</span><span class="n">id</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Sample post — replace with your own.</p>]]></content><author><name></name></author><category term="tally" /><category term="engineering" /><summary type="html"><![CDATA[A local-first data model, a tiny sync queue, and why I skipped a backend for the first year.]]></summary></entry><entry><title type="html">Shipping Clip 0.8 on macOS and Windows</title><link href="https://upket.com/writing/shipping-clip-v0-8/" rel="alternate" type="text/html" title="Shipping Clip 0.8 on macOS and Windows" /><published>2026-08-02T00:00:00+00:00</published><updated>2026-08-02T00:00:00+00:00</updated><id>https://upket.com/writing/shipping-clip-v0-8</id><content type="html" xml:base="https://upket.com/writing/shipping-clip-v0-8/"><![CDATA[<p>Clip 0.8 adds pinned items and a faster search index.</p>

<h2 id="lessons">Lessons</h2>

<ul>
  <li>Test the installer on a clean machine, every time</li>
  <li>Keyboard shortcuts differ more than you think between platforms</li>
</ul>

<p>Sample post — replace with your own.</p>]]></content><author><name></name></author><category term="clip" /><category term="release" /><summary type="html"><![CDATA[What changed in 0.8, and a few lessons from packaging one app for two desktops.]]></summary></entry></feed>