<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Brenner Cruvinel - vector db</title>
    <subtitle>AI researcher and product designer building at the edge of computer science and mental health.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://brennercruvinel.blog/en/tags/vector-db/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://brennercruvinel.blog"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-03T00:00:00+00:00</updated>
    <id>https://brennercruvinel.blog/en/tags/vector-db/atom.xml</id>
    <entry xml:lang="en">
        <title>At the end of the day it&#39;s the same thing, 1.3 GB</title>
        <published>2026-09-03T00:00:00+00:00</published>
        <updated>2026-09-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            Brenner Cruvinel
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://brennercruvinel.blog/en/blog/no-final-do-dia-ta-a-mesma-coisa-1-3-gb/"/>
        <id>https://brennercruvinel.blog/en/blog/no-final-do-dia-ta-a-mesma-coisa-1-3-gb/</id>
        
        <content type="html" xml:base="https://brennercruvinel.blog/en/blog/no-final-do-dia-ta-a-mesma-coisa-1-3-gb/">&lt;p&gt;I was sure. Sorting the cards by similarity before encoding would multiply the compression, because similar neighboring frames are exactly what video codecs love. I had written it in the bets, I had repeated it to the agent, and the &lt;a href=&quot;https://brennercruvinel.blog/en/blog/encoder-ignorou-o-tune-still-desde-o-primeiro-build/&quot;&gt;benchmark&lt;/a&gt; had handed me back a strange row: the variant with inter came out bigger than the one without. The configuration was wrong, scene cut detection was on, and different card after different card is one scene cut per frame. The encoder was burning cycles looking for a scene that didn&#39;t exist. I turned it off and put together a second corpus, almost three thousand real reprints of the same art, grouped together.&lt;/p&gt;
&lt;p&gt;That did it. With prediction in groups of sixteen frames, the file came out 29% smaller than without prediction. Groups of sixteen beat a single keyframe for the whole stream, which surprised me, and they still keep any card reachable by decoding at most sixteen frames. And a detail I didn&#39;t expect: shuffling the reprints instead of grouping them cost only two points. Part of the gain comes from the frame every card shares, not from the repeated art. The codec was exploiting the chrome, as I had suspected on day one, and that held for any order.&lt;/p&gt;
&lt;h2 id=&quot;building-the-whole-corpus-at-night&quot;&gt;Building the whole corpus at night&lt;/h2&gt;
&lt;p&gt;With 29% in hand, I built the full corpus with similarity sorting and prediction on, and next to it the same corpus with none of that, to compare. And I built it with the media inside the file, because by then I no longer accepted MP4s sitting next to the database. Before getting there I opened the folder of an intermediate build and found &lt;code&gt;.build&lt;/code&gt;, &lt;code&gt;.cache&lt;/code&gt;, &lt;code&gt;.forge-state&lt;/code&gt;, &lt;code&gt;.tmp&lt;/code&gt;, a lock, a manifest, all next to a &lt;code&gt;.nest&lt;/code&gt; of a few megabytes. What is all this for? I asked, and the honest answer was that every piece had a reason and none of them needed to be there once the build finished. Media inside the file was half the answer, the other half was cleaning up the output.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;.nest&lt;/code&gt; is a container of sections, each with its own hash. The new section is the simplest of all: a table of offsets and the raw bytes of the videos, glued one after another. An MP4 stays an MP4, nothing is re-encoded to fit. Opening the file doesn&#39;t touch the media, the system only maps the slice when someone asks for a card, and you can export the original MP4 back out with the hash checked before writing.&lt;/p&gt;
&lt;p&gt;That section doesn&#39;t count toward Nest&#39;s content hash, and this matters more than it seems. The content hash is computed over what&#39;s inside the file, not over the packaging, and it&#39;s what makes a Nest citation point to a piece of knowledge instead of a place on disk. The same corpus built with the media inside and with the media outside gives the same hash. It cost three percent: the indexes, the card text and the vectors add up to about forty megabytes on top of 1.3 GB of video.&lt;/p&gt;
&lt;p&gt;The builds ran overnight, and the night was rough. Two died with a full disk, because macOS was taking system snapshots in waves, eating and releasing gigabytes without warning, and at one point I was down to a hundred and thirty megabytes free. And in the middle of that I read a summary from the agent saying the corpus had 200 cards. I had a client meeting in a few hours.&lt;/p&gt;
&lt;p&gt;&quot;Seriously, you used 200 demo cards? I have a client meeting and I still don&#39;t have the dataset.&quot; I had it run validation on the 1.3 GB file. All 38 thousand blobs checked out, one by one. The corpus was complete, the summary was describing the pilot, and I had read the summary instead of the disk. After the encoder that wasn&#39;t using the tune the manifest claimed, it was the second time that week that what I read wasn&#39;t what was actually there.&lt;/p&gt;
&lt;h2 id=&quot;at-the-end-of-the-day&quot;&gt;At the end of the day&lt;/h2&gt;
&lt;p&gt;The sorted build sat next to the plain build. 1.3 GB both, no difference at all. I sent it to the agent at four in the morning: at the end of the day it&#39;s the same thing, right, 1.3 GB.&lt;/p&gt;
&lt;p&gt;The reason was in the manifest, correct this time. Nest decides per segment whether to use prediction, encoding a sample both ways. On the real corpus, made of unique cards, the probe vetoed prediction in every segment. There&#39;s nothing to predict: the next card is another card, with other art, and the shared chrome doesn&#39;t pay for the cost. The 29% gain only exists on the reprint corpus, and I haven&#39;t built that one in full yet.&lt;/p&gt;
&lt;p&gt;There was a worse part, which I only understood later. In an earlier version of the probe, it decided on bytes alone, and in a build of the sample it picked prediction for every segment because it tied on size. Median quality dropped sixteen points. The encoder compresses predicted frames with coarser quantization, and with unique cards a predicted frame is just a worse keyframe in disguise. Equal bytes aren&#39;t equal quality. The probe now measures both sides, accepts losing at most two points, and records the reason when it vetoes. The 29% matrix also compares bytes only, so the number is real but it isn&#39;t equivalent quality. I&#39;m putting that down here because I forgot it myself for a whole day.&lt;/p&gt;
&lt;h2 id=&quot;what-if-the-file-doesn-t-need-to-be-pretty&quot;&gt;What if the file doesn&#39;t need to be pretty&lt;/h2&gt;
&lt;p&gt;What I take from that night isn&#39;t the 1.3 GB. It&#39;s that my intuition about codecs was wrong twice, and that I read summaries when I should read files. Now I only turn sorting on when the corpus has near-duplicates, and no build goes in without validation of the real file running alongside it.&lt;/p&gt;
&lt;p&gt;And one question was left over that seemed more promising than any sorting. Nest&#39;s quality gate locks the codec at a conservative level because the visual metrics never pass on small cards with tiny print. But Felipe&#39;s app keeps every card&#39;s JPEG cached for display. The &lt;code&gt;.nest&lt;/code&gt; only needs to answer which card it is. If the file doesn&#39;t need to be pretty, how far can you push the setting before search starts complaining?&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Nest: a sovereign, content-addressable, offline-first vector DB</title>
        <published>2026-01-15T00:00:00+00:00</published>
        <updated>2026-01-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            Brenner Cruvinel
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://brennercruvinel.blog/en/blog/nest-vector-db-soberano/"/>
        <id>https://brennercruvinel.blog/en/blog/nest-vector-db-soberano/</id>
        
        <content type="html" xml:base="https://brennercruvinel.blog/en/blog/nest-vector-db-soberano/">&lt;p&gt;Sharing the concept of something I am working on, tired of hacking around vector DBs with no stability. In an ordinary database, a chunk&#39;s ID can change when the index is rebuilt, and a saved citation starts pointing somewhere else without telling anyone.&lt;/p&gt;
&lt;p&gt;Nest is my answer to that. It is a single-file vector DB, content-addressable, offline-first and hash-verified. Python builds the file, Rust serves the file. The address of any piece is:&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#657B83, #839496); background-color: light-dark(#FDF6E3, #002B36);&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nest://content_hash/chunk_id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You cite by content, not by location. If the content changes, the hash changes, and it is impossible to receive something other than what you asked for.&lt;/p&gt;
&lt;h2 id=&quot;the-hash-as-the-address&quot;&gt;The hash as the address&lt;/h2&gt;
&lt;p&gt;The central idea is just one: the hash of the content becomes the address of the content. Instead of &quot;give me the file in such-and-such folder&quot;, which could have been swapped without you knowing, you say &quot;give me the file whose content has this hash&quot;. If something else came back, it would have a different hash. Verification is not an extra step; it is the very way you ask.&lt;/p&gt;
&lt;p&gt;In Nest, the two parts of the address play different roles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;content_hash&lt;/code&gt; identifies the whole file by the hash of what it contains&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chunk_id&lt;/code&gt; points to the piece inside that file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The practical consequence is the one I wanted: a citation does not break when the file moves to another folder, disk or machine. It is only valid for that content. If the content changed, the hash changed, and you know right away you are talking about something else.&lt;/p&gt;
&lt;h2 id=&quot;the-family&quot;&gt;The family&lt;/h2&gt;
&lt;p&gt;This is not my invention. It is content-addressable storage, and it has famous relatives.&lt;/p&gt;
&lt;p&gt;The most everyday one is Git. Each commit is identified by a hash of its content, and a &lt;code&gt;git commit&lt;/code&gt; is a sealed snapshot of the code at that moment. If someone rewrites history, the hashes do not match and Git flags it. IPFS does the same thing at scale, on a distributed network of many machines.&lt;/p&gt;
&lt;p&gt;Nest sits between the two:&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;What it seals&lt;/th&gt;&lt;th&gt;What it is for&lt;/th&gt;&lt;th&gt;Scale&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Git&lt;/td&gt;&lt;td&gt;Code&lt;/td&gt;&lt;td&gt;Navigating versions&lt;/td&gt;&lt;td&gt;Repository&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;IPFS&lt;/td&gt;&lt;td&gt;Any file&lt;/td&gt;&lt;td&gt;Distribution&lt;/td&gt;&lt;td&gt;Network of machines&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Nest&lt;/td&gt;&lt;td&gt;Vectorized knowledge&lt;/td&gt;&lt;td&gt;Search&lt;/td&gt;&lt;td&gt;One local file&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Same mechanism, different purpose. Of the analogies I collected, this is the only one that describes Nest without a metaphor: content addressing for the same reason, so that asking for the data and verifying the data are the same operation.&lt;/p&gt;
&lt;h2 id=&quot;shipping-versions-without-downloading-everything-again&quot;&gt;Shipping versions without downloading everything again&lt;/h2&gt;
&lt;p&gt;A file that never changes is great for citing and bad for updating. If every new version forces you to download the whole file, nobody updates.&lt;/p&gt;
&lt;p&gt;The most technical option is binary diffing. Tools like &lt;code&gt;bsdiff&lt;/code&gt;, &lt;code&gt;xdelta&lt;/code&gt; and the &lt;code&gt;--patch-from&lt;/code&gt; mode of &lt;code&gt;zstd&lt;/code&gt; compute the difference between yesterday&#39;s file and today&#39;s and produce a small patch. Whoever already has yesterday&#39;s version downloads only the patch and rebuilds today&#39;s locally, the same way an operating system updates without downloading everything again.&lt;/p&gt;
&lt;p&gt;The problem is that this only works if the format is append-friendly, meaning that adding content at the end does not mess up what was already there. A deterministic build that reorders things internally, and compressed, indexed formats tend to reorganize a lot, can produce a huge diff for a small change: you change one chunk, the whole index moves, and the patch is no longer small. That is why I think this route is more fragile than splitting the file into shards and shipping only the new shard. And you only find out by testing.&lt;/p&gt;
&lt;h2 id=&quot;beyond-the-hash&quot;&gt;Beyond the hash&lt;/h2&gt;
&lt;p&gt;The hash proves that something did not change. It does not prove who vouched for it or when the content existed. There are three known layers for that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Digital signatures and certificates, the same idea behind &lt;code&gt;https&lt;/code&gt; and signed software, which adds the &quot;who&quot;&lt;/li&gt;
&lt;li&gt;Trusted timestamping, such as the &lt;a rel=&quot;external&quot; href=&quot;https://www.rfc-editor.org/rfc/rfc3161&quot;&gt;RFC 3161&lt;/a&gt; protocol or &lt;a rel=&quot;external&quot; href=&quot;https://opentimestamps.org/&quot;&gt;OpenTimestamps&lt;/a&gt;, which anchors the hash in Bitcoin and proves the content existed on a date without revealing the content&lt;/li&gt;
&lt;li&gt;Blockchain, which solves immutability with no central party to trust&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of the three, timestamping fits Nest best. Blockchain, for storing papers and citing passages, would be a sledgehammer to crack a nut: Nest wants content addressing and local verification, not consensus among machines that do not trust each other.&lt;/p&gt;
&lt;p&gt;In August, Nest started storing images too, and that became the &lt;a href=&quot;https://brennercruvinel.blog/en/blog/nest-archiver-de-cartas-de-magic/&quot;&gt;Magic card series&lt;/a&gt;. More soon.&lt;/p&gt;
</content>
        
    </entry>
</feed>
