<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <!-- Source: https://www.dolthub.com/blog/rss.xml -->
  <channel>
    <title>DoltHub Blog - Latest Posts</title>
    <description>Blog for DoltHub, a website hosting databases made with Dolt, an open-source version-controlled SQL database with Git-like semantics.</description>
    <link>https://siftrss.com/f/Kkmm5PG8lw</link>
    <language>en-us</language>
    <lastBuildDate>Fri, 07 Aug 2026 17:51:53 GMT</lastBuildDate>
    <atom:link href="https://siftrss.com/f/Kkmm5PG8lw" rel="self" type="application/rss+xml"/>
    <item>
      <title>Doltgres 1.0</title>
      <link>https://dolthub.com/blog/2026-08-06-doltgres-1-0/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-08-06-doltgres-1-0/</guid>
      <description>Doltgres, the Postgres-flavored version of Dolt, is now 1.0 and ready for production.</description>
      <pubDate>Thu, 06 Aug 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;At DoltHub, we’ve been in the version-controlled database business for eight years now. We made
&lt;a href="https://doltdb.com"&gt;Dolt&lt;/a&gt;, the world’s first version-controlled SQL database, and after a few years
in beta it hit 1.0 in 2023. It’s now running on thousands of machines around the world every
day, powering as many interesting version-controlled applications.&lt;/p&gt;
&lt;p&gt;Since we first announced Dolt, we’ve gotten one question more than any other:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What about a Postgres version?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dolt speaks the MySQL dialect and wire protocol, so it’s compatible with any tool or library that
can connect to MySQL. At the time we started writing the database, MySQL was far and away the most
popular free SQL database, but that was already starting to change. Postgres was gaining ground and
continues to do so. Today, few companies are building new products on top of MySQL. Nearly everyone
chooses Postgres for new work. This means that most of the new generation of database application
engineers are familiar with Postgres’s SQL dialect, toolchain, and ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://doltgres.com/"&gt;Doltgres&lt;/a&gt; is our way of meeting those customers where they live. Doltgres
combines the performant Git-style version control that makes Dolt unique with full Postgres
compatibility. Your favorite Postgres workbench or connection library can connect to Doltgres just
like a normal Postgres database, but with extra &lt;a href="https://www.doltgres.com/docs/reference/version-control/dolt-system-tables/"&gt;system
tables&lt;/a&gt; and
&lt;a href="https://www.doltgres.com/docs/reference/version-control/dolt-sql-functions/"&gt;functions&lt;/a&gt; for full
version control of all schema and data.&lt;/p&gt;
&lt;p&gt;It’s been almost three years since we announced &lt;a href="https://www.dolthub.com/blog/2023-11-01-announcing-doltgresql/"&gt;Doltgres’s alpha
release&lt;/a&gt; and about 18 months since
we announced &lt;a href="https://www.dolthub.com/blog/2025-04-16-doltgres-goes-beta/"&gt;Doltgres Beta&lt;/a&gt;. Today is
the 8th anniversary of DoltHub Inc., and we’re excited to announce that Doltgres has finally achieved
its 1.0 release.&lt;/p&gt;
&lt;h1 id="what-does-10-mean"&gt;What does 1.0 mean?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-does-10-mean"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Doltgres 1.0 means four things.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Forward Storage Compatibility&lt;/li&gt;
&lt;li&gt;Production Performance&lt;/li&gt;
&lt;li&gt;Postgres Compatibility&lt;/li&gt;
&lt;li&gt;Stable Version Control Interface&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="forward-storage-compatibility"&gt;Forward Storage Compatibility&lt;a class="anchor-link" aria-label="Link to heading" href="#forward-storage-compatibility"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;All future 1.x versions of Doltgres will be backwards compatible with 1.0.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dolt’s storage engine has gone through a couple of backwards-incompatible changes since its
original beta, including one that required existing customers to migrate their data. Doltgres has
likewise explored different ways of storing and versioning its data leading up to the 1.0 release,
but managed to do so in a way that didn’t require any customer data migration.&lt;/p&gt;
&lt;p&gt;With Doltgres 1.0 we are committing to the current storage format used for all data. There will be
no backwards-incompatible storage changes in any 1.x release of Doltgres.&lt;/p&gt;
&lt;h2 id="production-performance"&gt;Production Performance&lt;a class="anchor-link" aria-label="Link to heading" href="#production-performance"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Doltgres 1.0 has production level query performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://www.dolthub.com/blog/2025-12-04-dolt-is-as-fast-as-mysql/"&gt;Dolt is faster than MySQL&lt;/a&gt; on
the standard sysbench performance suite. Doltgres uses Dolt’s underlying storage and query engine,
so that same performance applies to Doltgres as well.&lt;/p&gt;
&lt;p&gt;However, MySQL itself is roughly 2-3 times slower than Postgres. This means that &lt;a href="https://www.doltgres.com/docs/reference/benchmarks/latency/"&gt;Doltgres is about
2.7 times slower than Postgres&lt;/a&gt; as of
this launch. But there are two pieces of good news here. First, databases are very fast. We’re
talking about the difference between 0.2 milliseconds for a query versus 0.5 milliseconds. In
practice, any difference in performance for typical OLTP queries in a database-backed application is
dominated by network latency, with the database itself being a relatively small part of overall
measured latency. Second, we’re continuing to make improvements to Dolt’s performance over time. We
started out 5x slower than MySQL and have now passed it in performance.&lt;/p&gt;
&lt;p&gt;Doltgres is slower than Postgres but still more than fast enough to handle your production
workload. And it will only get faster in future releases.&lt;/p&gt;
&lt;h2 id="postgres-compatibility"&gt;Postgres Compatibility&lt;a class="anchor-link" aria-label="Link to heading" href="#postgres-compatibility"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Doltgres 1.0 is 99% Postgres compatible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Doltgres measures Postgres compatibility in two primary ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A test suite of 5.6 million SQL queries that are verified against real Postgres for
correctness. These originally come from the
&lt;a href="https://sqlite.org/sqllogictest/doc/trunk/about.wiki"&gt;sqllogictest&lt;/a&gt; project, which was developed
for SQLite3. Doltgres currently scores over 99% on this suite.&lt;/li&gt;
&lt;li&gt;Comprehensive integration tests of different client libraries in different languages. Currently
&lt;a href="https://www.doltgres.com/docs/reference/supported-clients/clients/#supported-clients"&gt;over 20 have official
support&lt;/a&gt;,
with more being added all the time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compatibility has been our highest priority for the last year of development. We have imported many
hundreds of real-world Postgres dumps and written tests for dozens of client libraries. This means
we’re very confident your Postgres schema and queries will work in Doltgres. If you find that they
don’t, we promise to &lt;a href="https://www.dolthub.com/blog/2024-05-15-24-hour-bug-fixes/"&gt;fix the problem in 24
hours&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="stable-version-control-interface"&gt;Stable Version Control Interface&lt;a class="anchor-link" aria-label="Link to heading" href="#stable-version-control-interface"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Doltgres 1.0 version control interfaces will not change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href="https://www.doltgres.com/docs/reference/version-control/dolt-system-tables/"&gt;system tables&lt;/a&gt; and
&lt;a href="https://www.doltgres.com/docs/reference/version-control/dolt-sql-functions/"&gt;functions&lt;/a&gt; that
implement the version control features of Doltgres have been battle-hardened by years of production
use in Dolt. You can write applications that use them and be assured they will not change in any 1.x
release of Doltgres.&lt;/p&gt;
&lt;p&gt;We’ll of course continue innovating by adding new version control features and making the existing
ones work better and faster. But the code and queries you write today will continue working for
every 1.x release.&lt;/p&gt;
&lt;h1 id="whats-next"&gt;What’s next?&lt;a class="anchor-link" aria-label="Link to heading" href="#whats-next"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Doltgres 1.0 is just the beginning. You can read &lt;a href="https://www.dolthub.com/docs/other/roadmap/"&gt;our
roadmap&lt;/a&gt; for details, but here are some highlights.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for common extensions including PostGIS&lt;/li&gt;
&lt;li&gt;Vector indexes&lt;/li&gt;
&lt;li&gt;Row-level security&lt;/li&gt;
&lt;li&gt;Collation support&lt;/li&gt;
&lt;li&gt;Better DDL support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Paying customers get write access to the roadmap.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you’ve been interested in a version-controlled SQL database but have been waiting for the
Postgres version, this is your signal to &lt;a href="https://github.com/dolthub/doltgresql/releases/latest"&gt;try it out
now&lt;/a&gt;. The current version has been years in
the making and represents a lot of hard work and innovation by the team. We’re very excited for you
to try it and to tell us what you think.&lt;/p&gt;
&lt;p&gt;Questions about using the 1.0 release? Find a bug you want fixed? Come by our
&lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt; to talk to our engineering team and meet other Doltgres
users.&lt;/p&gt;</content:encoded>
      <dc:creator>Zach Musgrave</dc:creator>
      <category>doltgres</category>
      <category>feature release</category>
    </item>
    <item>
      <title>No Index GroupBy Optimization</title>
      <link>https://dolthub.com/blog/2026-08-03-no-index-groupby/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-08-03-no-index-groupby/</guid>
      <description>Sneak peek at one of the optimizations applied to Dolt and Doltgres</description>
      <pubDate>Mon, 03 Aug 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;You may have heard that we’re launching &lt;a href="https://www.dolthub.com/blog/2026-06-26-doltgres-1-0-coming-this-fall/"&gt;Doltgres 1.0&lt;/a&gt; on August 6th.
As part of the launch, we’ve been improving Doltgres’s performance on &lt;a href="https://www.doltgres.com/docs/reference/benchmarks/latency/"&gt;Sysbench Latency&lt;/a&gt;.
This blog focuses on one of the optimizations we made, specifically focusing on &lt;code&gt;groupby_scan&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id="discovering-the-optimization"&gt;Discovering the Optimization&lt;a class="anchor-link" aria-label="Link to heading" href="#discovering-the-optimization"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Doltgres reuses large portions of Dolt and GMS, so it’s not unreasonable to assume that Doltgres should perform similarly to Dolt.
Comparing latencies across the different platforms helps us highlight where we are underperforming and where we should focus our attention.&lt;/p&gt;










































































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;benchmark&lt;/th&gt;&lt;th&gt;dolt&lt;/th&gt;&lt;th&gt;doltgres&lt;/th&gt;&lt;th&gt;mysql&lt;/th&gt;&lt;th&gt;postgres&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;covering_index_scan&lt;/td&gt;&lt;td&gt;2.35&lt;/td&gt;&lt;td&gt;2.48&lt;/td&gt;&lt;td&gt;17.01&lt;/td&gt;&lt;td&gt;17.95&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;groupby_scan&lt;/td&gt;&lt;td&gt;144.96&lt;/td&gt;&lt;td&gt;147.61&lt;/td&gt;&lt;td&gt;144.97&lt;/td&gt;&lt;td&gt;40.37&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join&lt;/td&gt;&lt;td&gt;1.93&lt;/td&gt;&lt;td&gt;2.30&lt;/td&gt;&lt;td&gt;3.43&lt;/td&gt;&lt;td&gt;1.82&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join_scan&lt;/td&gt;&lt;td&gt;1.32&lt;/td&gt;&lt;td&gt;1.70&lt;/td&gt;&lt;td&gt;4.18&lt;/td&gt;&lt;td&gt;0.67&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_scan&lt;/td&gt;&lt;td&gt;219.36&lt;/td&gt;&lt;td&gt;493.24&lt;/td&gt;&lt;td&gt;350.33&lt;/td&gt;&lt;td&gt;179.94&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_point_select&lt;/td&gt;&lt;td&gt;0.25&lt;/td&gt;&lt;td&gt;0.39&lt;/td&gt;&lt;td&gt;0.19&lt;/td&gt;&lt;td&gt;0.15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_only&lt;/td&gt;&lt;td&gt;5.00&lt;/td&gt;&lt;td&gt;6.79&lt;/td&gt;&lt;td&gt;3.68&lt;/td&gt;&lt;td&gt;2.66&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_points&lt;/td&gt;&lt;td&gt;0.52&lt;/td&gt;&lt;td&gt;0.80&lt;/td&gt;&lt;td&gt;0.36&lt;/td&gt;&lt;td&gt;0.22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_ranges&lt;/td&gt;&lt;td&gt;0.65&lt;/td&gt;&lt;td&gt;1.21&lt;/td&gt;&lt;td&gt;0.39&lt;/td&gt;&lt;td&gt;0.42&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;table_scan&lt;/td&gt;&lt;td&gt;207.82&lt;/td&gt;&lt;td&gt;475.79&lt;/td&gt;&lt;td&gt;350.33&lt;/td&gt;&lt;td&gt;179.94&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_table_scan&lt;/td&gt;&lt;td&gt;458.96&lt;/td&gt;&lt;td&gt;1213.57&lt;/td&gt;&lt;td&gt;759.88&lt;/td&gt;&lt;td&gt;427.07&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_delete_insert&lt;/td&gt;&lt;td&gt;6.21&lt;/td&gt;&lt;td&gt;6.91&lt;/td&gt;&lt;td&gt;7.70&lt;/td&gt;&lt;td&gt;2.22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_insert&lt;/td&gt;&lt;td&gt;3.19&lt;/td&gt;&lt;td&gt;3.89&lt;/td&gt;&lt;td&gt;4.10&lt;/td&gt;&lt;td&gt;1.10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_write&lt;/td&gt;&lt;td&gt;11.24&lt;/td&gt;&lt;td&gt;14.46&lt;/td&gt;&lt;td&gt;8.90&lt;/td&gt;&lt;td&gt;4.33&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_index&lt;/td&gt;&lt;td&gt;3.30&lt;/td&gt;&lt;td&gt;3.82&lt;/td&gt;&lt;td&gt;4.41&lt;/td&gt;&lt;td&gt;1.14&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_non_index&lt;/td&gt;&lt;td&gt;3.02&lt;/td&gt;&lt;td&gt;3.55&lt;/td&gt;&lt;td&gt;4.18&lt;/td&gt;&lt;td&gt;1.12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_write_only&lt;/td&gt;&lt;td&gt;6.32&lt;/td&gt;&lt;td&gt;7.43&lt;/td&gt;&lt;td&gt;5.18&lt;/td&gt;&lt;td&gt;1.79&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_delete_insert&lt;/td&gt;&lt;td&gt;6.79&lt;/td&gt;&lt;td&gt;7.56&lt;/td&gt;&lt;td&gt;8.43&lt;/td&gt;&lt;td&gt;2.30&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Focusing on &lt;code&gt;groupby_scan&lt;/code&gt;, we see that Postgres is somehow outperforming Dolt, Doltgres, and even MySQL by a significant margin; it’s over &lt;code&gt;3x&lt;/code&gt; faster.
To see what they were doing, I ran &lt;code&gt;EXPLAIN&lt;/code&gt; on each of the databases.&lt;/p&gt;
&lt;p&gt;Dolt:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;sbtest&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;*&gt;&lt;/span&gt;&lt;span&gt; explain plan &lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; year_col, &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;(year_col), &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;(big_int_col), &lt;/span&gt;&lt;span&gt;avg&lt;/span&gt;&lt;span&gt;(small_int_col) &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; sbtest1 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; big_int_col &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; GROUP BY&lt;/span&gt;&lt;span&gt; year_col, set_col &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; year_col;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;---------------------------------------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| plan                                                                                                                |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;---------------------------------------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| Project                                                                                                             |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  ├─ columns: [sbtest1.year_col, count(sbtest1.year_col), max(sbtest1.big_int_col), avg(sbtest1.small_int_col)]      |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|  └─ Sort(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt; ASC&lt;/span&gt;&lt;span&gt;)                                                                                      |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|      └─ GroupBy                                                                                                     |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          ├─ &lt;/span&gt;&lt;span&gt;select&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;AVG&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;small_int_col&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span&gt;COUNT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span&gt;MAX&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;big_int_col&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          ├─ group: &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set_col&lt;/span&gt;&lt;span&gt;                                                                |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|          └─ IndexedTableAccess(sbtest1)                                                                             |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|              ├─ &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;: [sbtest1.big_int_col]                                                                        |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|              ├─ filters: [{(0, ∞)}]                                                                                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|              └─ columns: [small_int_col big_int_col set_col year_col]                                               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;---------------------------------------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt; sec) &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doltgres:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;postgres&lt;/span&gt;&lt;span&gt;=&gt;&lt;/span&gt;&lt;span&gt; explain &lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; year_col, &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;(year_col), &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;(big_int_col), &lt;/span&gt;&lt;span&gt;avg&lt;/span&gt;&lt;span&gt;(small_int_col) &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; sbtest1 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; big_int_col &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; GROUP BY&lt;/span&gt;&lt;span&gt; year_col, set_col &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; year_col;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                                                                 plan                                                                  &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;---------------------------------------------------------------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; Project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ├─ columns: [sbtest1.year_col, count(sbtest1.year_col) as count, max(sbtest1.big_int_col) as max, avg(sbtest1.small_int_col) as avg]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  └─ Sort(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt; ASC&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      └─ GroupBy&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          ├─ &lt;/span&gt;&lt;span&gt;select&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;COUNT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span&gt;MAX&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;big_int_col&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span&gt;avg&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;small_int_col&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          ├─ group: &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set_col&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;          └─ IndexedTableAccess(sbtest1)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;              ├─ &lt;/span&gt;&lt;span&gt;index&lt;/span&gt;&lt;span&gt;: [sbtest1.big_int_col]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;              ├─ filters: [{(NULL, 0)}]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;              └─ columns: [small_int_col big_int_col set_col year_col]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MySQL:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; explain analyze &lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; year_col, &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;(year_col), &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;(big_int_col), &lt;/span&gt;&lt;span&gt;avg&lt;/span&gt;&lt;span&gt;(small_int_col) &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; sbtest1 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; big_int_col &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; GROUP BY&lt;/span&gt;&lt;span&gt; year_col, set_col &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; year_col;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| EXPLAIN                                                                                                                                                                    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Sort: &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year_col&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set_col&lt;/span&gt;&lt;span&gt;  (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;765&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    -&gt;&lt;/span&gt;&lt;span&gt; Table&lt;/span&gt;&lt;span&gt; scan &lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;temporary&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;  (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;765&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        -&gt;&lt;/span&gt;&lt;span&gt; Aggregate&lt;/span&gt;&lt;span&gt; using&lt;/span&gt;&lt;span&gt; temporary &lt;/span&gt;&lt;span&gt;table&lt;/span&gt;&lt;span&gt;  (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;765&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            -&gt;&lt;/span&gt;&lt;span&gt; Filter&lt;/span&gt;&lt;span&gt;: (&lt;/span&gt;&lt;span&gt;sbtest1&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;big_int_col&lt;/span&gt;&lt;span&gt; &gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;)  (cost&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;995&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;4896&lt;/span&gt;&lt;span&gt;) (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;222&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;37&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;4896&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                -&gt;&lt;/span&gt;&lt;span&gt; Table&lt;/span&gt;&lt;span&gt; scan &lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt; sbtest1  (cost&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;995&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;9707&lt;/span&gt;&lt;span&gt;) (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;219&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;36&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;10000&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; row&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;02&lt;/span&gt;&lt;span&gt; sec)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Postgres:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;postgres&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;# explain analyze &lt;/span&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; year_col, &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;(year_col), &lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;(big_int_col), &lt;/span&gt;&lt;span&gt;avg&lt;/span&gt;&lt;span&gt;(small_int_col) &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; sbtest1 &lt;/span&gt;&lt;span&gt;WHERE&lt;/span&gt;&lt;span&gt; big_int_col &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; GROUP BY&lt;/span&gt;&lt;span&gt; year_col, set_col &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; year_col;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;                                                      QUERY PLAN                                                      &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;----------------------------------------------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; Sort  (cost&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;427&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;98&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;429&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;89&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;765&lt;/span&gt;&lt;span&gt; width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;55&lt;/span&gt;&lt;span&gt;) (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;003&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;057&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;765&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;   Sort &lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;: year_col&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;   Sort Method: quicksort  Memory: 84kB&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;   -&gt;&lt;/span&gt;&lt;span&gt;  HashAggregate  (cost&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;381&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;77&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;391&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;34&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;765&lt;/span&gt;&lt;span&gt; width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;55&lt;/span&gt;&lt;span&gt;) (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;183&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;672&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;765&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;         Group &lt;/span&gt;&lt;span&gt;Key&lt;/span&gt;&lt;span&gt;: year_col, set_col&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;         Batches&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;  Memory Usage: 297kB&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;         -&gt;&lt;/span&gt;&lt;span&gt;  Seq Scan &lt;/span&gt;&lt;span&gt;on&lt;/span&gt;&lt;span&gt; sbtest1  (cost&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;318&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;00&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;5102&lt;/span&gt;&lt;span&gt; width&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;17&lt;/span&gt;&lt;span&gt;) (actual &lt;/span&gt;&lt;span&gt;time=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;005&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;315&lt;/span&gt;&lt;span&gt; rows=&lt;/span&gt;&lt;span&gt;5104&lt;/span&gt;&lt;span&gt; loops&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;               Filter&lt;/span&gt;&lt;span&gt;: (big_int_col &lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;               Rows&lt;/span&gt;&lt;span&gt; Removed &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; Filter&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;4896&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; Planning &lt;/span&gt;&lt;span&gt;Time&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;711&lt;/span&gt;&lt;span&gt; ms&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; Execution &lt;/span&gt;&lt;span&gt;Time&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;327&lt;/span&gt;&lt;span&gt; ms&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;11&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interesting, Dolt and Doltgres are using the secondary index defined over &lt;code&gt;big_int_col&lt;/code&gt;, while MySQL and Postgres just perform a full table scan.
Since the values in &lt;code&gt;big_int_col&lt;/code&gt; are uniformly distributed around 0, the filter &lt;code&gt;where big_int_col &gt; 0&lt;/code&gt; excludes roughly half the columns.
It appears the MySQL and Postgres analyzer is smart enough to recognize that the additional lookup is suboptimal.&lt;/p&gt;
&lt;p&gt;The flame graph supports this conclusion.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/secondary_key_flame_graph.png/92035b7c96f6eca9e5d49c2d5d5da1fc2b4059f0aa45196f3bd4c46d8d0cc18e.webp" alt="flame graph"&gt;&lt;/p&gt;
&lt;p&gt;Here, we see that a large portion of the CPU is spent in &lt;code&gt;prolly.Map.Get&lt;/code&gt;, which is the secondary key lookup.&lt;/p&gt;
&lt;h1 id="optimization"&gt;Optimization&lt;a class="anchor-link" aria-label="Link to heading" href="#optimization"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Currently, our analyzer will always pick an index when applicable because we assume that will always be better.
Evidently, we have discovered that isn’t always the case.
We need to modify the existing coster to consider full table scans depending on how well the index filters the results.
Fortunately, we implemented statistics a while ago, and we can use the histograms there to get a good estimate of how selective the filter is.&lt;/p&gt;
&lt;p&gt;We added these new heuristics to the coster:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A primary key is always better than no index&lt;/li&gt;
&lt;li&gt;A secondary index should only be used over a full table scan if it selects fewer than 25% of rows&lt;/li&gt;
&lt;li&gt;A covering index is always better than no index&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rest of the coster remains the same.
In the future, we should take into consideration things like the complexity of the filter, if the table can fit into memory, size of output row, etc., but this is good enough for now.
If you’d like to read the implementation in greater detail, you can check out these PRs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dolthub/go-mysql-server/pull/3639"&gt;dolthub/go-mysql-server#3659&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dolthub/go-mysql-server/pull/3657"&gt;dolthub/go-mysql-server#3657&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, it took some extra work to carry these performance benefits over to Doltgres.
While Doltgres does use the same costing logic, statistics weren’t even enabled.
After enabling statistics, fixing some bugs, and adding some logic to get histograms working, these are the results:&lt;/p&gt;










































































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;benchmark&lt;/th&gt;&lt;th&gt;dolt&lt;/th&gt;&lt;th&gt;doltgres&lt;/th&gt;&lt;th&gt;mysql&lt;/th&gt;&lt;th&gt;postgres&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;covering_index_scan&lt;/td&gt;&lt;td&gt;2.35&lt;/td&gt;&lt;td&gt;2.43&lt;/td&gt;&lt;td&gt;17.01&lt;/td&gt;&lt;td&gt;17.95&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;groupby_scan&lt;/td&gt;&lt;td&gt;62.19&lt;/td&gt;&lt;td&gt;82.96&lt;/td&gt;&lt;td&gt;144.97&lt;/td&gt;&lt;td&gt;40.37&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join&lt;/td&gt;&lt;td&gt;1.93&lt;/td&gt;&lt;td&gt;2.30&lt;/td&gt;&lt;td&gt;3.43&lt;/td&gt;&lt;td&gt;1.82&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join_scan&lt;/td&gt;&lt;td&gt;1.32&lt;/td&gt;&lt;td&gt;1.67&lt;/td&gt;&lt;td&gt;4.18&lt;/td&gt;&lt;td&gt;0.67&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_scan&lt;/td&gt;&lt;td&gt;204.11&lt;/td&gt;&lt;td&gt;484.44&lt;/td&gt;&lt;td&gt;350.33&lt;/td&gt;&lt;td&gt;179.94&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_point_select&lt;/td&gt;&lt;td&gt;0.25&lt;/td&gt;&lt;td&gt;0.40&lt;/td&gt;&lt;td&gt;0.19&lt;/td&gt;&lt;td&gt;0.15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_only&lt;/td&gt;&lt;td&gt;4.91&lt;/td&gt;&lt;td&gt;6.55&lt;/td&gt;&lt;td&gt;3.68&lt;/td&gt;&lt;td&gt;2.66&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_points&lt;/td&gt;&lt;td&gt;0.52&lt;/td&gt;&lt;td&gt;0.74&lt;/td&gt;&lt;td&gt;0.36&lt;/td&gt;&lt;td&gt;0.22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_ranges&lt;/td&gt;&lt;td&gt;0.65&lt;/td&gt;&lt;td&gt;1.04&lt;/td&gt;&lt;td&gt;0.39&lt;/td&gt;&lt;td&gt;0.42&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;table_scan&lt;/td&gt;&lt;td&gt;204.47&lt;/td&gt;&lt;td&gt;475.79&lt;/td&gt;&lt;td&gt;350.33&lt;/td&gt;&lt;td&gt;179.94&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_table_scan&lt;/td&gt;&lt;td&gt;458.96&lt;/td&gt;&lt;td&gt;1213.57&lt;/td&gt;&lt;td&gt;759.88&lt;/td&gt;&lt;td&gt;427.07&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_delete_insert&lt;/td&gt;&lt;td&gt;6.21&lt;/td&gt;&lt;td&gt;6.79&lt;/td&gt;&lt;td&gt;7.70&lt;/td&gt;&lt;td&gt;2.22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_insert&lt;/td&gt;&lt;td&gt;3.19&lt;/td&gt;&lt;td&gt;3.89&lt;/td&gt;&lt;td&gt;4.10&lt;/td&gt;&lt;td&gt;1.10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_write&lt;/td&gt;&lt;td&gt;11.24&lt;/td&gt;&lt;td&gt;14.21&lt;/td&gt;&lt;td&gt;8.90&lt;/td&gt;&lt;td&gt;4.33&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_index&lt;/td&gt;&lt;td&gt;3.30&lt;/td&gt;&lt;td&gt;3.82&lt;/td&gt;&lt;td&gt;4.41&lt;/td&gt;&lt;td&gt;1.14&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_non_index&lt;/td&gt;&lt;td&gt;3.02&lt;/td&gt;&lt;td&gt;3.49&lt;/td&gt;&lt;td&gt;4.18&lt;/td&gt;&lt;td&gt;1.12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_write_only&lt;/td&gt;&lt;td&gt;6.32&lt;/td&gt;&lt;td&gt;7.30&lt;/td&gt;&lt;td&gt;5.18&lt;/td&gt;&lt;td&gt;1.79&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_delete_insert&lt;/td&gt;&lt;td&gt;6.79&lt;/td&gt;&lt;td&gt;7.43&lt;/td&gt;&lt;td&gt;8.43&lt;/td&gt;&lt;td&gt;2.30&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;On Dolt, this brought down the latency for &lt;code&gt;groupby_scan&lt;/code&gt; from &lt;code&gt;144.96ms&lt;/code&gt; to &lt;code&gt;62.19ms&lt;/code&gt;; this is a &lt;code&gt;57.1%&lt;/code&gt; improvement!
On Doltgres, &lt;code&gt;groupby_scan&lt;/code&gt; latency decreased from &lt;code&gt;147.61ms&lt;/code&gt; to &lt;code&gt;82.96ms&lt;/code&gt;, which is a &lt;code&gt;43.80%&lt;/code&gt; improvement.
With these optimizations, Dolt’s latency for &lt;code&gt;groupby_scan&lt;/code&gt; is less than half of MySQL’s.
Unfortunately, Postgres still pulls way ahead with their latency being less than half that of Doltgres’s.&lt;/p&gt;
&lt;p&gt;While we were focused on &lt;code&gt;groupby_scan&lt;/code&gt;, there were also some improvements to &lt;code&gt;index_scan&lt;/code&gt;.
Dolt went from &lt;code&gt;219.36ms&lt;/code&gt; down to &lt;code&gt;204.11ms&lt;/code&gt;, which is a &lt;code&gt;6.95%&lt;/code&gt; improvement.
Doltgres went from &lt;code&gt;493.24ms&lt;/code&gt; down to &lt;code&gt;484.44ms&lt;/code&gt;, which is a &lt;code&gt;1.78%&lt;/code&gt; improvement.
Interestingly, a byproduct of this optimization is that the &lt;code&gt;index_scan&lt;/code&gt; and &lt;code&gt;table_scan&lt;/code&gt; benchmarks are essentially the same now.
The resulting plans from both these queries avoid the secondary index, making them both full table scans with a filter.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We continue to bring performance improvements to both Dolt and Doltgres.
Making our coster just a little bit smarter has resulted in our &lt;code&gt;groupby_scan&lt;/code&gt; benchmarks running two times faster.
Stay tuned to hear more about the performance improvements included in the upcoming Doltgres 1.0 release!
Feel free to chat with us on &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt; or file a &lt;a href="https://github.com/dolthub/dolt/issues"&gt;Github issue&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <dc:creator>James Cor</dc:creator>
      <category>technical</category>
      <category>performance</category>
    </item>
    <item>
      <title>Running Ito, a Runtime Analysis Code Review Tool, on Doltgres</title>
      <link>https://dolthub.com/blog/2026-07-20-ito-ai-qa-for-doltgresql/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-07-20-ito-ai-qa-for-doltgresql/</guid>
      <description>For the past six weeks, we've been running Ito, a runtime analysis code review tool that works off of GitHub PRs and builds and runs your application instead of just reading the diff. We've had success using this on our Doltgresql repo and in this blog post we'll show what it's caught, how it works, and where it's let us down.</description>
      <pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;We ship a lot of code at DoltHub, and coding agents, like Claude and Cursor, help us produce code even faster. However, we still need a human to review all of that code and sign off on it before it goes into our products. About six weeks ago, we started using &lt;a href="https://www.ito.ai/"&gt;Ito&lt;/a&gt; on the repository for our Postgres-compatible version-controlled database, &lt;a href="https://github.com/dolthub/doltgresql"&gt;doltgresql&lt;/a&gt;. Ito is &lt;del&gt;an AI QA agent&lt;/del&gt; a runtime analysis code review tool that works off of GitHub PRs and takes a different approach than other AI tools that analyze PRs: instead of just reading your PR diff and commenting on it, Ito actually builds your application from the PR branch, runs it in a real environment, and exercises it like a user would. On Doltgres that means standing up a real &lt;code&gt;doltgres&lt;/code&gt; server and running SQL queries against it. Ito can handle other types of applications, too, for example, running your web application and capturing a screen recording of the UI testing. This post is our review of Ito. We’ll cover what Ito is, how to enable it, dig into a couple of concrete examples of bugs it’s helped us find, and close out with the numbers on how effective it’s actually been over the six weeks we’ve been running it, including our estimated signal-to-noise ratio on the findings it’s raised. Ito doesn’t replace a human reviewer, but it aguments our review process and has been successful at helping us find bugs and broken edge cases.&lt;/p&gt;
&lt;h1 id="what-is-ito"&gt;What is Ito?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-ito"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;AI tools that analyze GitHub PRs tend to work off the diff of your changes: they feed the changed lines (and &lt;em&gt;maybe&lt;/em&gt; some surrounding context) to an LLM and ask it to spot problems. That’s useful for catching sloppy code and some obvious bugs, but it can’t tell you how your product actually runs with these changes, and it can’t test if your product is behaving as expected. A good code reviewer understands the codebase and the product experience and reviews the changes in that larger context.&lt;/p&gt;
&lt;p&gt;Ito is different. Ito builds a containerized version of your application from the PR branch and actually runs it. It reads the diff and the PR description to figure out what area of your app is affected, generates a set of test scenarios targeting that area, and then executes them against the running application. For a web app, that means an agent driving a real browser session against your frontend and backend together. For Doltgres, it means opening a Postgres connection to a running &lt;code&gt;doltgres&lt;/code&gt; server and issuing SQL statements. Either way, the approach is the same: it’s checking how your code actually behaves, not just what the diff looks like.&lt;/p&gt;
&lt;p&gt;Every PR gets a comment from Ito summarizing what it ran, what passed, what failed, and a severity rating for anything it flagged, plus a top-line verdict on whether Ito thinks the PR is safe to merge. Failures come with reproduction instructions that make it easy to repro the failure yourself. For web-based applications, you even get a screen recording you can view that shows you exactly what Ito tested and how your application responded. The Ito website provides a more detailed view of the testing Ito performed. &lt;a href="https://app.ito.ai/share/61ad6bd4-2df1-4110-a2e8-e02915a5f39a?tab=details&amp;#x26;_gl=1*7w1ugk*_gcl_au*MTAzNjIwNDM2OS4xNzgxNTY1Mzgw*_ga*MTgwMTA2NzQyNC4xNzg0MTQ4MzUx*_ga_BRWMBEWN9V*czE3ODQxNDgzNTEkbzEkZzEkdDE3ODQxNDkxNzgkajU2JGwwJGgw"&gt;Here’s an example of a detailed report from the Ito website&lt;/a&gt; for changes it tested against the open-source chatwoot project.&lt;/p&gt;
&lt;p&gt;Below, you can see an example of what an Ito summary comment looks like on one of our PRs. It shows us that it ran 15 tests and two of them failed. It gives a summary of the findings and a recommendation that this PR is not safe to merge yet.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/ito-summary-comment.png/836b6e236713080eccaa00ad90c3de15d8ba44a12906917cf19c5ebd8b9ff522.webp" alt="Ito summary comment"&gt;&lt;/p&gt;
&lt;p&gt;In that same comment, you can drill into the “Tests run by Ito” section to see more detail. We’ll revisit these same findings below, when we talk about what kinds of bugs Ito has found for us.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/ito-summary-comment-tests-run.png/88550959d66c128a3d70a797c445bd69b8b08fabceb9e238cdea1697db9dd4f0.webp" alt="Ito summary comment tests run"&gt;&lt;/p&gt;
&lt;h1 id="turning-ito-on"&gt;Turning Ito On&lt;a class="anchor-link" aria-label="Link to heading" href="#turning-ito-on"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Setting up Ito is very easy. You create an account at &lt;a href="https://app.ito.ai"&gt;app.ito.ai&lt;/a&gt;, install the &lt;a href="https://github.com/apps/itoqa"&gt;Ito GitHub App&lt;/a&gt; on your organization (or a personal account), and select which repositories you want it watching. There’s no YAML to write and no config to tune before your first run. Ito maps out your codebase from what’s already there, and from that point on, it automatically picks up new and updated pull requests on the repos you selected. As PRs are reviewed, a bot account, &lt;code&gt;itoqa&lt;/code&gt;, comments with results as they come in.&lt;/p&gt;
&lt;p&gt;You can add custom variables, seed data, or secrets later if you want to point it at specific fixtures, but we haven’t needed to yet. It’s been running against our repo with the defaults.&lt;/p&gt;
&lt;p&gt;Ito provides &lt;a href="https://www.ito.ai/pricing"&gt;a free trial&lt;/a&gt; for startups and small teams, which makes it easy to test out Ito with your app and see how it can help your team.&lt;/p&gt;
&lt;h1 id="ito-in-action"&gt;Ito in Action&lt;a class="anchor-link" aria-label="Link to heading" href="#ito-in-action"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Let’s take a closer look at some real examples of how Ito has helped us catch some pretty tricky bugs. One of the things we’ve noticed is that Ito does a realy good job of testing edge cases in SQL behavior. SQL is a well-documented spec, so it makes sense that a generative AI tool like Ito could use that information to effectively test edge cases and find bugs. This is where we’ve seen Ito be most helpful so far in our experience testing our product.&lt;/p&gt;
&lt;p&gt;Two particularly good examples come out of &lt;a href="https://github.com/dolthub/doltgresql/pull/2913"&gt;PR #2913&lt;/a&gt;, which added native &lt;a href="https://www.postgresql.org/docs/current/tutorial-window.html"&gt;window function support&lt;/a&gt; to DoltgreSQL so that we could match PostgreSQL behavior exactly. Previously, Doltgres was relying on go-mysql-server’s implementation, which is implemented to match MySQL behavior, and doesn’t always match PostgreSQL’s behavior, particularly for return types. When I thought I was done with the work, I looked at the PR and noticed that Ito had added comments for two interesting issues it had found.&lt;/p&gt;
&lt;h2 id="bug-named-window-reference-over-w-produces-a-full-partition-sum-instead-of-a-running-sum-within-each-partition"&gt;Bug: Named window reference &lt;code&gt;OVER w&lt;/code&gt; produces a full-partition SUM instead of a running SUM within each partition&lt;a class="anchor-link" aria-label="Link to heading" href="#bug-named-window-reference-over-w-produces-a-full-partition-sum-instead-of-a-running-sum-within-each-partition"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SQL window function syntax allows you to define a “window” of result rows over which aggregate functions will operate. These window definitions can be inline (e.g. &lt;code&gt;SELECT sum(y) OVER (ORDER BY z)&lt;/code&gt;) or they be defined as a named window (e.g. &lt;code&gt;SELECT sum(y) over (w1) FROM a WINDOW w1 AS (order by z);&lt;/code&gt;). In either syntax form, if the &lt;code&gt;ORDER BY&lt;/code&gt; clause is not specified for a window, then the window function operates over the full partition. In other words, there is a single partition containing all rows that the window function operates on. However, there was a bug hiding deep in our database engine where the correct window framing was applied only if the &lt;code&gt;ORDER BY&lt;/code&gt; clause was defined inline. If the &lt;code&gt;ORDER BY&lt;/code&gt; clause was defined in a named window, our code saw that there wasn’t an &lt;code&gt;ORDER BY&lt;/code&gt; clause specified inline, and incorrectly defaulted to framing the window over the full result set. To execute this query correctly, our engine needed to recognize that a named window was being used and examine it to see if it declared an &lt;code&gt;ORDER BY&lt;/code&gt; clause. Only when no inline window definition &lt;strong&gt;and&lt;/strong&gt; no named window definition contained an &lt;code&gt;ORDER BY&lt;/code&gt; clause should the engine default the window framing to a single window over the entire result set.&lt;/p&gt;
&lt;p&gt;To make this more concrete, check out these statements that repro the issue:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; (x &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt; PRIMARY KEY&lt;/span&gt;&lt;span&gt;, y &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;, z &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;);                                                                                                          &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- the inline version worked correctly&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; sum&lt;/span&gt;&lt;span&gt;(y) &lt;/span&gt;&lt;span&gt;over&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; z) &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- correct:         0, 1, 3, 3, 4, 7   (running/cumulative sum)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- referencing a named window did NOT work correctly&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; sum&lt;/span&gt;&lt;span&gt;(y) &lt;/span&gt;&lt;span&gt;over&lt;/span&gt;&lt;span&gt; (w1) &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;WINDOW&lt;/span&gt;&lt;span&gt; w1 &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;order by&lt;/span&gt;&lt;span&gt; z) &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- buggy (pre-fix): 7, 7, 7, 7, 7, 7   (full-partition sum on every row)                                                                                   &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- correct:         0, 1, 3, 3, 4, 7   (running/cumulative sum)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that when the window definition was defined inline (i.e. &lt;code&gt;SELECT sum(y) over (order by z) FROM a ORDER BY x;&lt;/code&gt;), this query produced the correct results. This bug was specific to referencing a named window definition.&lt;/p&gt;
&lt;p&gt;Here’s the comment Ito added for this issue:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/ito-issue-comment-named-window-reference-via-over.png/f622fcebebdf274072f2d9028a4cc096bb41bcfb8d229936eae7a2cda85566c9.webp" alt="Ito issue comment named window reference via OVER"&gt;&lt;/p&gt;
&lt;p&gt;Inside that comment, there is a lot of detail, including a summary of the finding, evidence for repro’ing the problem, and even a sample prompt you can pass to a coding agent to start debugging the issue. I was particularly interested in the repro instructions. I find that’s usually the fastest way for me to understand an issue. When testing a UI application, Ito will actually provide evidence as a screen recording of the testing with your UI, so you can see exactly how it was triggered and how your app responded. Since DoltgreSQL is a server process and not a UI, the evidence Ito provided for us is a repro script and some analysis. You can see the full evidence Ito provided below.&lt;/p&gt;
&lt;details&gt;                                                                                                                                                  
&lt;summary&gt;Click to see Ito's evidence for this bug&lt;/summary&gt;                                                                                                       
&lt;h3 id="setup-context"&gt;setup context&lt;a class="anchor-link" aria-label="Link to heading" href="#setup-context"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h1 id="setup_keys-default-superuser"&gt;setup_keys: default-superuser&lt;a class="anchor-link" aria-label="Link to heading" href="#setup_keys-default-superuser"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h1 id="timestamp-2026-07-13t201156578z-test-execution-for-named-window-over-w"&gt;timestamp: 2026-07-13T20:11:56.578Z test execution for named window OVER w&lt;a class="anchor-link" aria-label="Link to heading" href="#timestamp-2026-07-13t201156578z-test-execution-for-named-window-over-w"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h3 id="reproduction-script"&gt;reproduction script&lt;a class="anchor-link" aria-label="Link to heading" href="#reproduction-script"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;DROP&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; IF&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; t_named;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; t_named&lt;/span&gt;&lt;span&gt;(id &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, grp &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, amt &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; t_named &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; id, &lt;/span&gt;&lt;span&gt;SUM&lt;/span&gt;&lt;span&gt;(amt) &lt;/span&gt;&lt;span&gt;OVER&lt;/span&gt;&lt;span&gt; w &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; t_named&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;WINDOW&lt;/span&gt;&lt;span&gt; w &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;PARTITION&lt;/span&gt;&lt;span&gt; BY&lt;/span&gt;&lt;span&gt; grp &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; id, &lt;/span&gt;&lt;span&gt;SUM&lt;/span&gt;&lt;span&gt;(amt) &lt;/span&gt;&lt;span&gt;OVER&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;PARTITION&lt;/span&gt;&lt;span&gt; BY&lt;/span&gt;&lt;span&gt; grp &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id) &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; s&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; t_named&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="observed-output"&gt;observed output&lt;a class="anchor-link" aria-label="Link to heading" href="#observed-output"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;DROP TABLE
CREATE TABLE
INSERT 0 3
id | s
----+----
1 | 30
2 | 30
3 |  5
(3 rows)&lt;/p&gt;
&lt;h3 id="inline-baseline-output"&gt;inline baseline output&lt;a class="anchor-link" aria-label="Link to heading" href="#inline-baseline-output"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;id | s
----+----
1 | 10
2 | 30
3 |  5
(3 rows)&lt;/p&gt;
&lt;h3 id="tabreadback-evidence"&gt;tab/readback evidence&lt;a class="anchor-link" aria-label="Link to heading" href="#tabreadback-evidence"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h1 id="test_start-executed-named-window-over-w-query-against-t_named"&gt;test_start: Executed named window OVER w query against t_named&lt;a class="anchor-link" aria-label="Link to heading" href="#test_start-executed-named-window-over-w-query-against-t_named"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h1 id="test_start-result-returned-id1-s30-id2-s30-id3-s5---partition-by-grp-works-but-order-by-id-is-ignored"&gt;test_start result: Returned id=1 s=30, id=2 s=30, id=3 s=5 - PARTITION BY grp works but ORDER BY id is ignored&lt;a class="anchor-link" aria-label="Link to heading" href="#test_start-result-returned-id1-s30-id2-s30-id3-s5---partition-by-grp-works-but-order-by-id-is-ignored"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h1 id="test_end-result-failed---named-window-order-by-id-is-not-applied"&gt;test_end result: Failed - named window ORDER BY id is not applied&lt;a class="anchor-link" aria-label="Link to heading" href="#test_end-result-failed---named-window-order-by-id-is-not-applied"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;h3 id="final-result"&gt;final result&lt;a class="anchor-link" aria-label="Link to heading" href="#final-result"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h1 id="final-result-parsing-1-failed---named-window-reference-over-w-returns-full-partition-sum-for-grp1-row-id1-30-instead-of-running-value-10"&gt;final result: PARSING-1 failed - named window reference OVER w returns full-partition SUM for grp=1 row id=1 (30) instead of running value (10).&lt;a class="anchor-link" aria-label="Link to heading" href="#final-result-parsing-1-failed---named-window-reference-over-w-returns-full-partition-sum-for-grp1-row-id1-30-instead-of-running-value-10"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;/details&gt;
&lt;p&gt;This issue was interesting for several reasons. First off, it’s a legitimate bug deep in our query processor, so it affected multiple products, including Dolt and Doltgres. It’s also syntax that we &lt;strong&gt;did&lt;/strong&gt; have test coverage for in our query processor. Unfortunately, the test coverage we had was asserting incorrect results! This is a great example of a latent bug where it &lt;em&gt;looked&lt;/em&gt; like we had good coverage, and we were indeed executing this syntax in tests, but we were asserting the wrong results. Ito provided great value here to help us catch this before a customer had to report it to us.&lt;/p&gt;
&lt;p&gt;This also illustrates a powerful aspect of Ito. Nothing in the code diff in the PR that Ito reviewed had &lt;strong&gt;any&lt;/strong&gt; direct sign of this bug. If Ito had only been looking at the diff lines from the PR, then it wouldn’t have caught this. Instead, Ito analyzed what was changing, used knowledge of window function syntax in SQL, and tested edge cases to see if it could find any problems, and sure enough, it did.&lt;/p&gt;
&lt;h2 id="bug-inheriting-or-overriding-a-named-windows-order-by-drops-it"&gt;Bug: Inheriting or overriding a named window’s &lt;code&gt;ORDER BY&lt;/code&gt; drops it&lt;a class="anchor-link" aria-label="Link to heading" href="#bug-inheriting-or-overriding-a-named-windows-order-by-drops-it"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The next issue that Ito found is a similar, but separate bug. Just like the previous issue, this one is a bug in how a named window definition is merged into a statement, specifically when an &lt;code&gt;ORDER BY&lt;/code&gt; clause is provided in the statement to override the ordering in the named window definition. In this case, the overridden &lt;code&gt;ORDER BY&lt;/code&gt; clause wasn’t getting applied correctly, and resulted in the aggregate function being incorrectly applied over a window covering &lt;strong&gt;all&lt;/strong&gt; result rows, instead of using the correct window framing required by the &lt;code&gt;ORDER BY&lt;/code&gt; clause.&lt;/p&gt;
&lt;p&gt;Here’s a concrete example of this bug and how it affects the returned results:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;span&gt;(id &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, grp &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, amt &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; t &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; id, &lt;/span&gt;&lt;span&gt;SUM&lt;/span&gt;&lt;span&gt;(amt) &lt;/span&gt;&lt;span&gt;OVER&lt;/span&gt;&lt;span&gt; (w1 &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id) &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; s &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    WINDOW&lt;/span&gt;&lt;span&gt; w1 &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;PARTITION&lt;/span&gt;&lt;span&gt; BY&lt;/span&gt;&lt;span&gt; grp) &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- buggy:   60, 60, 60, 20, 20   (full-partition sum, w1's frame leaking through)                                                                          &lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- correct: 10, 30, 60,  5, 20   (running sum, from the inline baseline SUM(amt) OVER (PARTITION BY grp ORDER BY id))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s the comment Ito added for this issue:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/ito-issue-comment-named-window-inheritance-drops-order-by.png/60d609d34f9578a247cbee9b21ae41c1e00ad79fb3b7f9e65389329a710e159a.webp" alt="Ito issue comment named window inheritancedrops ORDER BY"&gt;&lt;/p&gt;
&lt;p&gt;As with the previous bug, Ito provided clear steps to reproduce this bug, which made it very easy to get started debugging it.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Click to see Ito's evidence for this bug&lt;/summary&gt;
&lt;h3 id="setup-and-reproduction-sql"&gt;setup and reproduction SQL&lt;a class="anchor-link" aria-label="Link to heading" href="#setup-and-reproduction-sql"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;DROP&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; IF&lt;/span&gt;&lt;span&gt; EXISTS&lt;/span&gt;&lt;span&gt; t_inherit;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; t_inherit&lt;/span&gt;&lt;span&gt;(id &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, grp &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;, amt &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; t_inherit &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;30&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- Inheritance chain&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; id, &lt;/span&gt;&lt;span&gt;SUM&lt;/span&gt;&lt;span&gt;(amt) &lt;/span&gt;&lt;span&gt;OVER&lt;/span&gt;&lt;span&gt; w2 &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; s &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; t_inherit&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  WINDOW&lt;/span&gt;&lt;span&gt; w1 &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;PARTITION&lt;/span&gt;&lt;span&gt; BY&lt;/span&gt;&lt;span&gt; grp), w2 &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; (w1 &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id) &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- Explicit named-window override&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; id, &lt;/span&gt;&lt;span&gt;SUM&lt;/span&gt;&lt;span&gt;(amt) &lt;/span&gt;&lt;span&gt;OVER&lt;/span&gt;&lt;span&gt; (w1 &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id) &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; s &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; t_inherit&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  WINDOW&lt;/span&gt;&lt;span&gt; w1 &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;PARTITION&lt;/span&gt;&lt;span&gt; BY&lt;/span&gt;&lt;span&gt; grp) &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- Inline baseline (control)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; id, &lt;/span&gt;&lt;span&gt;SUM&lt;/span&gt;&lt;span&gt;(amt) &lt;/span&gt;&lt;span&gt;OVER&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;PARTITION&lt;/span&gt;&lt;span&gt; BY&lt;/span&gt;&lt;span&gt; grp &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id) &lt;/span&gt;&lt;span&gt;AS&lt;/span&gt;&lt;span&gt; s &lt;/span&gt;&lt;span&gt;FROM&lt;/span&gt;&lt;span&gt; t_inherit &lt;/span&gt;&lt;span&gt;ORDER BY&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="observed-output-1"&gt;observed output&lt;a class="anchor-link" aria-label="Link to heading" href="#observed-output-1"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h1 id="test-1-named-window-inheritance-chain-w1---w2"&gt;Test 1: Named window inheritance chain w1 -&gt; w2&lt;a class="anchor-link" aria-label="Link to heading" href="#test-1-named-window-inheritance-chain-w1---w2"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;id | s
----+----
1 | 60
2 | 60
3 | 60
4 | 20
5 | 20
(5 rows)&lt;/p&gt;
&lt;h1 id="test-2-named-window-with-override-clause"&gt;Test 2: Named window with override clause&lt;a class="anchor-link" aria-label="Link to heading" href="#test-2-named-window-with-override-clause"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;id | s
----+----
1 | 60
2 | 60
3 | 60
4 | 20
5 | 20
(5 rows)&lt;/p&gt;
&lt;h1 id="test-3-inline-window-baseline-correct-expected-behavior"&gt;Test 3: Inline window baseline (correct expected behavior)&lt;a class="anchor-link" aria-label="Link to heading" href="#test-3-inline-window-baseline-correct-expected-behavior"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;id | s
----+----
1 | 10
2 | 30
3 | 60
4 |  5
5 | 20
(5 rows)&lt;/p&gt;
&lt;h3 id="additional-mixed-form-readback-from-run"&gt;additional mixed-form readback from run&lt;a class="anchor-link" aria-label="Link to heading" href="#additional-mixed-form-readback-from-run"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;id | s1 | s2 | s3
----+----+----+----
1 | 38 | 38 | 38
2 | 38 | 38 | 38
3 | 20 | 20 | 20
4 | 20 | 20 | 20
5 | 38 | 38 | 38
(5 rows)&lt;/p&gt;
&lt;h1 id="final-result-parsing-3-failed---named-window-inheritancereference-forms-return-full-partition-sums-while-equivalent-inline-over-partition-by-grp-order-by-id-returns-running-sums"&gt;final result: PARSING-3 failed - named-window inheritance/reference forms return full-partition sums while equivalent inline OVER (PARTITION BY grp ORDER BY id) returns running sums.&lt;a class="anchor-link" aria-label="Link to heading" href="#final-result-parsing-3-failed---named-window-inheritancereference-forms-return-full-partition-sums-while-equivalent-inline-over-partition-by-grp-order-by-id-returns-running-sums"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;/details&gt;
&lt;p&gt;Like the previous bug, this bug was deep in our query processor, in the shared go-mysql-server module, so it affected all of our database products built on our query processor. Unlike the previous bug, this one was a gap in our test coverage. Thanks to Ito, we found this gap and added new tests for this case, ensuring that same tests will run for each of our database products and prevent a regression.&lt;/p&gt;
&lt;h1 id="not-just-for-sql"&gt;Not Just for SQL&lt;a class="anchor-link" aria-label="Link to heading" href="#not-just-for-sql"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It’s worth noting that DoltgreSQL is not the typical product Ito can handle testing. Ito’s initial target was web applications: an agent drives a real browser against your app, clicks around like a user, and hands back a video replay of anything that broke, alongside the usual severity rating and repro steps. DoltgreSQL has no UI to click through. It’s a database engine that other programs talk to over the Postgres wire protocol. On our repo, Ito’s “user” is a SQL client instead of a browser, and its test scenarios are queries instead of clicks.&lt;/p&gt;
&lt;h1 id="ito-improvements"&gt;Ito Improvements&lt;a class="anchor-link" aria-label="Link to heading" href="#ito-improvements"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We’ve only been using Ito for a little over a month, but even in that short amount of time, we’ve seen improvements in how well Ito is able to test our product. Like we mentioned earlier, the majority of Ito users are using it to test web-based applications. Because of that, Ito defaulted to taking screen recordings of the testing and showing that as the evidence for each bug report. As you can imagine… these screen recordings weren’t super interesting or helpful for a database server. The Ito team was receptive to this feedback and quickly rolled out changes so that non-UI products, like Doltgres, don’t include screen recordings, and instead, get a text file containing the evidence Ito used to determine each bug.&lt;/p&gt;
&lt;p&gt;We had another issue where Ito was reporting false alarms about SQL syntax that didn’t work. This was initially confusing because the PR where we saw this was successfully running tests that showed the new syntax working. When we reported this to the Ito team, they were responsive and quickly identified that Ito hit a problem building the Doltgres binary on our PR branch and instead used an older binary, which didn’t have support for the new syntax added in the PR. The Ito team quickly rolled out a change to prevent Ito from falling back to an older binary. Now if the binary couldn’t be successfully built from the PR branch, Ito would fail with a clear error message. We were happy with the quick response from the Ito team and haven’t seen this issue again.&lt;/p&gt;
&lt;p&gt;For the Doltgres database server, we’ve noticed that Ito does &lt;strong&gt;really&lt;/strong&gt; well finding issues with some PRs, but on other PRs, there are sometimes comments or reported issues that aren’t as helpful and can add noise to your PRs. How effectively Ito can find bugs in your PRs seems to depend on what type of application you’re building and what type of changes you have in your PR. For example, in our experience, we’ve noticed that Ito does &lt;strong&gt;really&lt;/strong&gt; well at finding bugs and broken edge cases when we’re implementing something well-documented, like features from the SQL spec. In the examples above, we were implementing well-defined syntax for SQL window functions, and Ito was able to identify a couple of broken edge cases. We’ve seen similarly helpful comments from Ito in other PRs where we implemented SQL functions, like &lt;code&gt;COALESCE()&lt;/code&gt;. In PRs where we were making internal performance optimizations that didn’t directly affect SQL features, Ito wasn’t as helpful or sometimes even added comments that didn’t warrant any action.&lt;/p&gt;
&lt;h1 id="by-the-numbers"&gt;By the Numbers&lt;a class="anchor-link" aria-label="Link to heading" href="#by-the-numbers"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The examples above are illustrative of the kinds of issues Ito has found for us. In addition to that, I also want to share some stats on the overall effectivness of Ito with our product so far. In the six weeks we’ve been using Ito, it has commented on 92 pull requests in the doltgresql repo. A little under half of those are dependabot-style PRs (e.g. automated dependency bumps, post-release metadata updates) with no real logic for Ito to exercise, so we’ll exclude those from our analysis. That leaves 43 substantive PRs where Ito actually had something to test.&lt;/p&gt;
&lt;p&gt;Of the 38 of those 43 PRs that have since merged or closed: 20 came back clean on every run, and on the 18 remaining PRs, Ito reported at least one issue. So, Ito is reporting issues for about half of our PRs. 8 of those 18 show a fix-and-re-verify cycle directly in Ito’s comment history before merge. That shows that for about half of the PRs where Ito is reporting issues, the PR author is seeing those issues and addressing them before merging the PR. This is still undercounting by a bit, since some Ito reported issues get fixed in a follow-up PR or moved to be tracked in our GitHub backlog. Based on that data, and rounding up a bit for issues that are addressed in follow-up PRs or added to the backlog, roughly 33% of our PRs are benefiting from the findings Ito is reporting.&lt;/p&gt;
&lt;p&gt;It’s also worth noting how often Ito finds bugs that have nothing to do with the PR it’s reviewing. In 26 of those 43 PRs (~60%), Ito surfaced at least one issue explicitly flagged as pre-existing and unrelated to the PR specific changes. Ito found those by understanding the functionality changing and testing edge cases around it, not because the PR touched that code path. That’s a different kind of value than catching a regression in the PR: it’s deeply testing parts of the product and finding existing issues that we didn’t know about yet.&lt;/p&gt;
&lt;p&gt;As one final angle, we went back through every review thread looking for cases where someone on the team weighed in directly on a specific Ito finding, calling it either legitimate or a false alarm. Across those judgment calls, we confirmed more than twice as many findings as we dismissed. A more than 2:1 ratio of confirmed-to-dismissed, on a tool that’s finding real bugs, is a worthwhile trade.&lt;/p&gt;
&lt;h1 id="summary"&gt;Summary&lt;a class="anchor-link" aria-label="Link to heading" href="#summary"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We’ve been using the Ito automated review tool on PRs in the Doltgres repository for about six weeks now. After a few initial bumps getting our product working with Ito, which were all quickly resolved by the Ito team, we’ve been getting real value from the comments Ito leaves on our PRs. The numbers above bear that out, including a more than 2:1 signal-to-noise ratio on the findings we’ve actually sat down and judged. It’s been particularly helpful at catching broken edge cases in PRs related to SQL features. In this blog, we showed examples of Ito finding two bugs with SQL window framing, that both existed deep in our query processor dependency.&lt;/p&gt;
&lt;p&gt;We’re still experimenting with Ito and seeing where it is most helpful. When we’ve hit an occassional issue using the tool, the Ito team has been responsive and quick to roll out a solution to improve our experience, including making their product work well for non-web-UI products, like Doltgres.&lt;/p&gt;
&lt;p&gt;If you’re curious about Ito, you should try it out! It’s easy to &lt;a href="https://app.ito.ai/auth/signup?_gl=1*1hx2fzk*_gcl_au*MTAzNjIwNDM2OS4xNzgxNTY1Mzgw*_ga*MTgwMTA2NzQyNC4xNzg0MTQ4MzUx*_ga_BRWMBEWN9V*czE3ODQxNDgzNTEkbzEkZzEkdDE3ODQxNDgzNzUkajM2JGwwJGgw"&gt;create an account with Ito&lt;/a&gt; and hook up the ItoQA GitHub action to your GitHub repository. If you are hesitant to change your repository settings, you can also &lt;a href="https://www.ito.ai/review"&gt;try out Ito by analyzing a single PR&lt;/a&gt;. This gives you a really lightweight way to see the Ito experience on your own PR. You can find more details on &lt;a href="https://www.ito.ai/pricing"&gt;Ito’s pricing online&lt;/a&gt;, which includes options for a free trial, as well as free use for approved open-source projects.&lt;/p&gt;
&lt;p&gt;Last, but not least, if you want to talk about version-controlled databases, or AI tooling, please come by the &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;DoltHub Discord&lt;/a&gt;. We’re always around Discord and happy to talk about the benefits of version-controlled databases and how AI tooling is changing the software development experience.&lt;/p&gt;</content:encoded>
      <dc:creator>Jason Fulghum</dc:creator>
      <category>ai</category>
      <category>doltgres</category>
    </item>
    <item>
      <title>Dolt in Four Flavors</title>
      <link>https://dolthub.com/blog/2026-07-16-dolt-in-4-flavors/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-07-16-dolt-in-4-flavors/</guid>
      <description>We now have the Dolt database that is right for you, whether that is classic Dolt, Doltgres, DoltLite, or Dumbo. Soon, all these databases will work with DoltHub, DoltLab, Hosted Dolt, and Dolt Workbench.</description>
      <pubDate>Thu, 16 Jul 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;We’ve been building Dolt for almost eight years now. The first seven of those years produced two Dolt flavors: classic &lt;a href="https://www.doltdb.com"&gt;MySQL-flavored Dolt&lt;/a&gt; and the much anticipated &lt;a href="https://www.doltgres.com"&gt;Postgres-flavored Doltgres&lt;/a&gt;. The past year has produced two additional flavors: the &lt;a href="https://www.doltlite.com"&gt;SQLite-flavored DoltLite&lt;/a&gt; and the &lt;a href="https://github.com/dolthub/dumbodb"&gt;MongoDB-flavored Dumbo&lt;/a&gt;. Coding agents rapidly accelerated our company’s ability to build new products. DoltLite and Dumbo are entirely agent-made.&lt;/p&gt;
&lt;p&gt;Why all the flavors? Which flavor should you choose for your use case? Which flavors work with other services like Hosted Dolt or DoltHub? This article explains.&lt;/p&gt;
&lt;h1 id="why-all-the-flavors"&gt;Why All the Flavors?&lt;a class="anchor-link" aria-label="Link to heading" href="#why-all-the-flavors"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Version control is useful, and &lt;a href="https://www.dolthub.com/blog/2026-03-13-multi-agent-persistence/"&gt;essential if agents are involved&lt;/a&gt;, in every database format, and our product catalog now reflects that. Moreover, over the eight years we’ve been building Dolt, users have asked for almost every database flavor. There is demand for all manner of version-controlled databases.&lt;/p&gt;
&lt;p&gt;Of the four Dolt flavors, only Dolt and Doltgres are redundant. MySQL and Postgres are mostly interchangeable as Online Transaction Processing (OLTP) SQL databases. DoltLite and Dumbo have completely different form factors. DoltLite is an embedded database, not an OLTP database. Dumbo is an OLTP database but not a SQL database.&lt;/p&gt;
&lt;p&gt;So why Dolt and Doltgres? Database formats are very sticky. You are either a MySQL shop or a Postgres shop. Convincing people to switch database formats is harder than providing both options. Postgres has definitely become the default OLTP SQL format. This was not the case in 2018 when we started building Dolt. MySQL was still very popular. Today, not so much. A Postgres flavor is required in 2026. &lt;a href="https://www.dolthub.com/blog/2026-06-26-doltgres-1-0-coming-this-fall/"&gt;Doltgres goes 1.0&lt;/a&gt; in August, signaling it is ready for production use.&lt;/p&gt;
&lt;h1 id="which-flavor-is-right-for-you"&gt;Which Flavor Is Right for You?&lt;a class="anchor-link" aria-label="Link to heading" href="#which-flavor-is-right-for-you"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Now that Dolt has four flavors, how do you pick the flavor that is right for you? This really comes down to what type of database you need.&lt;/p&gt;
&lt;p&gt;Do you want an OLTP database like MySQL or Postgres? Most OLTP databases are used to power the backends of websites or mobile applications. The database is run as a server that hosts one or many clients. If the answer to that question is yes, you have narrowed your choice down to Dolt, Doltgres, or Dumbo. If the answer is no, you probably want an embedded database and DoltLite is for you.&lt;/p&gt;
&lt;p&gt;Do you want your data structured as tables and accessed using SQL? If yes, then you can choose between Dolt and Doltgres. If no, Dumbo’s document format is for you.&lt;/p&gt;
&lt;p&gt;Choosing between Dolt and Doltgres comes down to your preference. Dolt is older and more stable. If you don’t care about SQL format, we always recommend choosing Dolt over Doltgres. If you are migrating from Postgres or wedded to Postgres as a company, choose Doltgres.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dolt-flavor-flowchart.png/41295272a6d941c3a6b1091f22a45b073fda54c1e07b272d511eca2dc8d04cca.webp" alt="Flavor Decision"&gt;&lt;/p&gt;
&lt;h1 id="the-dolt-ecosystem"&gt;The Dolt Ecosystem&lt;a class="anchor-link" aria-label="Link to heading" href="#the-dolt-ecosystem"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;What about DoltHub, DoltLab, Hosted Dolt, and the Dolt Workbench? If I want to share my data on DoltHub, can I use Doltgres?&lt;/p&gt;
&lt;p&gt;The goal is for all four flavors of Dolt to work with DoltHub, DoltLab, Hosted Dolt, and the Dolt Workbench with one exception: DoltLite will not be hosted. However, we’re probably 6-12 months away from reaching that goal.&lt;/p&gt;
&lt;p&gt;With DoltHub and DoltLab, there are two components. Can you push to them as a remote? Can you view your database contents using the user interface? Supporting the first is pretty easy while supporting the second is more involved. User interface features are things like pull requests and SQL queries. Here’s a compatibility matrix with estimated dates for the unsupported cells.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dolt-services-table.png/0f8d27091b117d12eeef39cf085cb198144f1e42863ade2c76698c37f0f78b53.webp" alt="Dolt Services Compatibility"&gt;&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We now have the Dolt that is right for you! Be that classic Dolt, Doltgres, DoltLite, or Dumbo. Soon, all these databases will work with DoltHub, DoltLab, Hosted Dolt, and Dolt Workbench. Want something prioritized? Come by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt; and let us know. We’re always willing to shift the schedule based on user feedback.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>dolt</category>
      <category>doltgres</category>
      <category>doltlite</category>
      <category>dumbo</category>
    </item>
    <item>
      <title>Dolt + TeamCity: Data Commits Now Trigger Builds</title>
      <link>https://dolthub.com/blog/2026-07-13-dolt-teamcity-vcs-plugin/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-07-13-dolt-teamcity-vcs-plugin/</guid>
      <description>A community plugin teaches TeamCity to treat a Dolt database as version control: data commits trigger builds, data tests, and binary packages.</description>
      <pubDate>Mon, 13 Jul 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Here are two builds of the same tiny game, one database commit apart:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="text"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;=== Battle report: 3 units in the roster (config hnak4bdfk10s) ===&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Footman vs Archer: draw at 6 hits each&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;=== Battle report: 3 units in the roster (config lravfogrck8d) ===&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Footman vs Archer: Footman wins in 5 hits&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No source code changed between these builds. A designer ran one SQL
&lt;code&gt;UPDATE&lt;/code&gt;, committed it, and a CI server was alerted to test and
ship a new binary with the commit hash stamped inside. The database is
&lt;a href="https://www.doltdb.com"&gt;Dolt&lt;/a&gt;, the world’s first version-controlled SQL
database. The CI server is
&lt;a href="https://www.jetbrains.com/teamcity/"&gt;TeamCity&lt;/a&gt;, which as of this year can
treat a Dolt database as a first-class version control system.&lt;/p&gt;
&lt;p&gt;It’s a collaborative sequel. Two years ago we wrote about
&lt;a href="https://www.dolthub.com/blog/2024-05-20-dolt-scorewarrior/"&gt;how Scorewarrior manages their game configuration with Dolt&lt;/a&gt;:
designers tune stats on branches, changes merge through pull requests,
and shipping means cutting a tag and building binary artifacts. That post
ended right where the config leaves Dolt and enters the build system.
Now the engineer who ran that build system just fixed its one missing piece.&lt;/p&gt;
&lt;h1 id="what-is-teamcity"&gt;What Is TeamCity?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-teamcity"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;TeamCity is JetBrains’ continuous integration (CI) server for developers and
build engineers. If CI is new to
you: it’s the practice of committing changes to a shared repository many
times a day, with every commit followed by an automated build and test
run, so integration problems surface in minutes instead of at release
time. TeamCity is a veteran of the field, available on-premises or as a
managed cloud service, and the free
&lt;a href="https://www.jetbrains.com/teamcity/buy/?edition=on-premises"&gt;Professional license&lt;/a&gt; is
generous: 100 build configurations, 3 build agents, no restrictions on
users or runtime, and the full feature set for commercial, open-source,
and personal projects alike.&lt;/p&gt;
&lt;p&gt;The architecture has two primary components: the TeamCity server, which
provides the web UI for managing configuration and results, and build
agents, the workers that execute your builds. You configure everything
through the UI, through the
&lt;a href="https://www.jetbrains.com/help/teamcity/kotlin-dsl.html"&gt;Kotlin DSL&lt;/a&gt;, or
a hybrid of both, with UI changes committed back to your repository as
code.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-gameconfig-project-overview.png/1000f25bd4fda31f9919494f52548b7ab0abe6feb736f85281a3d9ce3ff0ed3a.webp" alt="TeamCity&amp;#x27;s overview page for our GameConfig project, with its build configuration and recent runs"&gt;&lt;/p&gt;
&lt;p&gt;Notice the word “repository”. TeamCity is built around version control:
it polls your VCS for commits, lists them in a Changes tab, triggers
builds when they land, and pins every build to the revision that caused
it. That raises our favorite kind of question: what if the thing under
version control is a database?&lt;/p&gt;
&lt;h1 id="teamcity-and-dolt-before"&gt;TeamCity and Dolt, Before&lt;a class="anchor-link" aria-label="Link to heading" href="#teamcity-and-dolt-before"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.linkedin.com/in/prodoelmit/"&gt;Yury Dynnikov&lt;/a&gt;, formerly of
Scorewarrior and now at JetBrains, spent years building game configs from
Dolt into binary packages with TeamCity. However, TeamCity did not
understand Dolt’s version control: commits, branches, and tags were all
invisible. Still, a pipeline could work with a separate replica server
just to have something stable to build from, branch names passed around
as build parameters instead of TeamCity’s native branch handling, and
some other not-so-cool tricks.&lt;/p&gt;
&lt;h1 id="look-a-cool-new-plugin"&gt;Look, a Cool New Plugin!&lt;a class="anchor-link" aria-label="Link to heading" href="#look-a-cool-new-plugin"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Yury’s fix is a
&lt;a href="https://plugins.jetbrains.com/plugin/31918-vcs-support-dolt"&gt;Dolt plugin for TeamCity&lt;/a&gt;
(&lt;a href="https://github.com/prodoelmit/teamcity-dolt"&gt;source on GitHub&lt;/a&gt;, MIT
licensed). He is clear it’s a personal project rather than a JetBrains
product, but it does what his old pipeline always wanted: install it and
“Dolt” appears in TeamCity’s Type of VCS dropdown, right next to Git,
Subversion, and Perforce.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-type-of-vcs-dropdown-showing-dolt.png/15678f621b7132c00daca0d6db608db30a18fff1f31fc97cd8a6f413611e8785.webp" alt="TeamCity&amp;#x27;s Type of VCS dropdown listing Dolt alongside Git, Subversion, and Perforce"&gt;&lt;/p&gt;
&lt;p&gt;Commits show up in the Changes tab with hash, author, and message. Branch
specifications work, so a commit to &lt;code&gt;staging&lt;/code&gt; builds apart from &lt;code&gt;main&lt;/code&gt;,
each branch with its own build history:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-build-config-overview-with-branch-builds.png/6932c417bfabff845ffc0452252d985fcc4370f1e5837769edd4e0be475ec461.webp" alt="The build overview showing runs from the main and staging branches side by side"&gt;&lt;/p&gt;
&lt;p&gt;There are two connection modes: Remote JDBC
points at a &lt;code&gt;dolt sql-server&lt;/code&gt; you already run, while Local mode clones
from &lt;a href="https://www.dolthub.com"&gt;DoltHub&lt;/a&gt; or &lt;a href="https://www.doltlab.com"&gt;DoltLab&lt;/a&gt;
and manages its own SQL server, with private repos handled through an
Ed25519 keypair flow, the same
&lt;a href="https://www.dolthub.com/blog/2025-08-26-debugging-dolt-login/"&gt;credential mechanism &lt;code&gt;dolt login&lt;/code&gt; uses&lt;/a&gt;,
except TeamCity generates the keypair and you register its public half on
DoltHub.&lt;/p&gt;
&lt;p&gt;Yury also runs a public
&lt;a href="https://teamcity-dolt-demo.prodoelmit.me/project/EndlessSky"&gt;demo server&lt;/a&gt;
(guest login) where the plugin builds the
&lt;a href="https://endless-sky.github.io/"&gt;Endless Sky&lt;/a&gt; game data through a real
pipeline: export, data-quality tests, release bundles, all configured in
Kotlin DSL.&lt;/p&gt;
&lt;h1 id="the-query-behind-the-changes-tab"&gt;The Query Behind the Changes Tab&lt;a class="anchor-link" aria-label="Link to heading" href="#the-query-behind-the-changes-tab"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The plugin renders data changes and schema changes as different entries,
and you can see how via a common Dolt SQL function:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;SELECT&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; FROM&lt;/span&gt;&lt;span&gt; DOLT_DIFF_SUMMARY(&lt;/span&gt;&lt;span&gt;'hnak4bdfk10s...'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'lravfogrck8d...'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;-----------------+---------------+-----------+-------------+---------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| from_table_name | to_table_name | diff_type | data_change | schema_change |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;-----------------+---------------+-----------+-------------+---------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;| units           | units         | modified  | &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;           | &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;             |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;-----------------+---------------+-----------+-------------+---------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;data_change&lt;/code&gt; without &lt;code&gt;schema_change&lt;/code&gt; makes the Changes tab show
&lt;code&gt;tables/units&lt;/code&gt;. But run the same function against our branch that adds an
&lt;code&gt;armor&lt;/code&gt; column and both flags flip on, so the tab renders
&lt;code&gt;tables/units (schema)&lt;/code&gt; as its own entry.&lt;/p&gt;
&lt;p&gt;Why bring this up? Risk. The Footman buff changes a
number the game already knows how to read, so CI can test it and ship it
to live servers right away. The &lt;code&gt;armor&lt;/code&gt; column changes the shape of the
data, and every program that reads the config now has to be updated to
match, so that commit should get extra checks.&lt;/p&gt;
&lt;p&gt;Since the plugin writes the two as different paths, TeamCity
&lt;a href="https://www.jetbrains.com/help/teamcity/configuring-vcs-triggers.html"&gt;trigger rules&lt;/a&gt;
can route each kind to the right build automatically.&lt;/p&gt;
&lt;h1 id="setup"&gt;Setup&lt;a class="anchor-link" aria-label="Link to heading" href="#setup"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.jetbrains.com/teamcity/download/"&gt;Installers are available for Linux, macOS, and Windows&lt;/a&gt;,
but we used
&lt;a href="https://hub.docker.com/r/jetbrains/teamcity-server/"&gt;JetBrains’ own recommended Docker distribution&lt;/a&gt;.
After all, this is an inherently multi-service system: the TeamCity
server needs the
&lt;a href="https://hub.docker.com/r/jetbrains/teamcity-agent/"&gt;TeamCity agent image&lt;/a&gt;
to spawn build processes, plus a
&lt;a href="https://hub.docker.com/r/dolthub/dolt-sql-server"&gt;Dolt SQL server&lt;/a&gt; to be
the repository. (New to Dolt in Docker? We have a
&lt;a href="https://www.dolthub.com/blog/2023-10-25-dolt-docker/"&gt;getting started post&lt;/a&gt;.)
Three containers, wired like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-docker-compose-architecture-mermaid-flowchart.png/02730e527918c4a4b5adabdf03ee3267a55a30a16b98563cce78043f1264ce70.webp" alt="Diagram of the three-container stack: browser to TeamCity server, server polling Dolt over JDBC, agent registering and querying"&gt;&lt;/p&gt;
&lt;p&gt;This Compose file is everything you need to follow along:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="yaml"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  dolt&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;dolthub/dolt-sql-server:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      DOLT_ROOT_PASSWORD&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      DOLT_ROOT_HOST&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;"%"&lt;/span&gt;&lt;span&gt;    # let other containers connect as root&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    ports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      - &lt;/span&gt;&lt;span&gt;"3306:3306"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  server&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;jetbrains/teamcity-server:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    ports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      - &lt;/span&gt;&lt;span&gt;"8111:8111"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      - &lt;/span&gt;&lt;span&gt;tc_data:/data/teamcity_server/datadir&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      - &lt;/span&gt;&lt;span&gt;tc_logs:/opt/teamcity/logs&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  agent&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;jetbrains/teamcity-agent:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    environment&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;      SERVER_URL&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;http://server:8111&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;volumes&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  tc_data&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  tc_logs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;docker compose up -d&lt;/code&gt;, give TeamCity a couple of minutes to boot,
then open &lt;code&gt;http://localhost:8111&lt;/code&gt; and click through the one-time wizard:
accept the defaults (the internal database is fine for evaluation),
create your admin user, and authorize the agent under Agents,
Unauthorized. Next, install the plugin: download the zip from the
&lt;a href="https://plugins.jetbrains.com/plugin/31918-vcs-support-dolt"&gt;Marketplace page&lt;/a&gt;,
upload it on the Plugins page behind the Admin gear in the left-hand
navigation bar, and restart the server. You need TeamCity 2025.11.3 or
newer.&lt;/p&gt;
&lt;p&gt;While that restarts, give Dolt something worth building. Connect with
any MySQL client (&lt;code&gt;mysql -h127.0.0.1 -uroot -pdolt&lt;/code&gt;) and seed a tiny
game config:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; DATABASE&lt;/span&gt;&lt;span&gt; gameconfig&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;USE&lt;/span&gt;&lt;span&gt; gameconfig;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;CREATE&lt;/span&gt;&lt;span&gt; TABLE&lt;/span&gt;&lt;span&gt; units&lt;/span&gt;&lt;span&gt; (id &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt; PRIMARY KEY&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt; VARCHAR&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;64&lt;/span&gt;&lt;span&gt;), hp &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;, attack &lt;/span&gt;&lt;span&gt;INT&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;INSERT INTO&lt;/span&gt;&lt;span&gt; units &lt;/span&gt;&lt;span&gt;VALUES&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'Footman'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;12&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'Archer'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;70&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;),(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'Knight'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;180&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;25&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;CALL&lt;/span&gt;&lt;span&gt; DOLT_COMMIT(&lt;/span&gt;&lt;span&gt;'-Am'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'Initial game config'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, connect the two. Create a project (TeamCity’s onboarding will
offer to connect VCS hosting accounts and set up pipelines along the way;
skip all of it, because your version control is the database), add a VCS root of
type “Dolt”, and fill in the form: connection mode Remote JDBC, host
&lt;code&gt;dolt&lt;/code&gt; (the Compose service name), port &lt;code&gt;3306&lt;/code&gt;, database &lt;code&gt;gameconfig&lt;/code&gt;,
user &lt;code&gt;root&lt;/code&gt;, password &lt;code&gt;dolt&lt;/code&gt;, and branch specification &lt;code&gt;+:*&lt;/code&gt; to watch
every branch. Test connection, green.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-new-vcs-root-page-all-filled-values.png/c75d8ea7619b4b168ac3c9cc45eb5b7ae9c0aeccbcccc5b5439752075201e279.webp" alt="The Dolt VCS root form filled in with Remote JDBC mode, host dolt, database gameconfig, and branch specification watching all branches"&gt;&lt;/p&gt;
&lt;p&gt;One last piece of plumbing: a build configuration, so those commits have
something to trigger. Click “Create build configuration”, and on the “Set
up your build” page keep the plain “Build configuration” option and pick
your &lt;code&gt;gameconfig-dolt&lt;/code&gt; root under “From an existing VCS root”:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-set-up-new-build.png/b97511486a1865bf2fb41f9f1b2cc2cf570b0e5f06511ce849db7be196dd4fd7.webp" alt="The Set up your build page with the Build configuration option and the gameconfig-dolt root selected"&gt;&lt;/p&gt;
&lt;p&gt;Give it a Command Line build step; even &lt;code&gt;dolt version&lt;/code&gt; works as a
placeholder while you wire things up. Then add a
&lt;a href="https://www.jetbrains.com/help/teamcity/configuring-vcs-triggers.html"&gt;VCS trigger&lt;/a&gt;
under Triggers so new commits start builds on their own:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-build-config-triggers.png/b2f2c50b7a64fc0b1c5200d5ec5cb0fd27a4b2b2979476221ceb35be91b86ff7.webp" alt="The Triggers page with a VCS trigger added to the build configuration"&gt;&lt;/p&gt;
&lt;p&gt;The steps our demo build runs are more specific (i.e., data-quality probes
and compilation) which will come up in later sections.&lt;/p&gt;
&lt;h1 id="a-data-commit-walks-into-a-build"&gt;A Data Commit Walks Into a Build&lt;a class="anchor-link" aria-label="Link to heading" href="#a-data-commit-walks-into-a-build"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Here is the whole chain, end to end:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-data-commit-mermaid-sequence-diagram.png/f2d3360253be005131c2a90e05fddde9af5303ea486a125701b5147761b55082.webp" alt="Sequence diagram: a data commit, TeamCity&amp;#x27;s poll finding it, the VCS trigger firing, and the build querying data at that commit"&gt;&lt;/p&gt;
&lt;p&gt;Let’s say a designer is buffing a stat, expressed as SQL against the running
server:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;CALL&lt;/span&gt;&lt;span&gt; DOLT_CHECKOUT(&lt;/span&gt;&lt;span&gt;'main'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;UPDATE&lt;/span&gt;&lt;span&gt; units &lt;/span&gt;&lt;span&gt;SET&lt;/span&gt;&lt;span&gt; attack &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 14&lt;/span&gt;&lt;span&gt; WHERE&lt;/span&gt;&lt;span&gt; name&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 'Footman'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;CALL&lt;/span&gt;&lt;span&gt; DOLT_COMMIT(&lt;/span&gt;&lt;span&gt;'-Am'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'Balance pass: buff Footman attack 12 -&gt; 14'&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;About a minute later the commit is in the Changes tab and the VCS trigger
has started a build. A row update just triggered continuous integration.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-build-config-changes-tab-success.png/fbecb0d09855ddfcd0bfee32e00e84baa92957f836f5c0c7c6dfec4933e9844d.webp" alt="The build&amp;#x27;s Changes tab showing the Dolt commit with its hash, author, and message, rendered like any Git commit"&gt;&lt;/p&gt;
&lt;p&gt;TeamCity hands every build the commit that triggered it as
&lt;code&gt;%build.vcs.number%&lt;/code&gt;, and Dolt can
&lt;a href="https://www.dolthub.com/docs/sql-reference/version-control/querying-history/"&gt;query any table as of any commit&lt;/a&gt;.
Build steps therefore read the data exactly as it was at the triggering
revision, even if someone commits again while the build waits in the
queue:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "SELECT * FROM units AS OF '%build.vcs.number%'"&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="watch-a-test-turn-red"&gt;Watch a Test Turn Red&lt;a class="anchor-link" aria-label="Link to heading" href="#watch-a-test-turn-red"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our build step runs data-quality probes before anything ships, each
reported through TeamCity
&lt;a href="https://www.jetbrains.com/help/teamcity/service-messages.html"&gt;service messages&lt;/a&gt;
so a bad commit fails the build as a named red test instead of a wall of
log text, and the step halts on a red probe so bad config never reaches
the compiler. Here is the entire mechanism, two probes and a gate:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;PROBES_FAILED&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;probe&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  echo&lt;/span&gt;&lt;span&gt; "##teamcity[testStarted name='&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;']"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  bad&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; --host&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; --port&lt;/span&gt;&lt;span&gt; 3306&lt;/span&gt;&lt;span&gt; -u&lt;/span&gt;&lt;span&gt; root&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; --use-db&lt;/span&gt;&lt;span&gt; gameconfig&lt;/span&gt;&lt;span&gt; --no-tls&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "&lt;/span&gt;&lt;span&gt;$2&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; -r&lt;/span&gt;&lt;span&gt; csv&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;span&gt; tail&lt;/span&gt;&lt;span&gt; -1&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;span&gt; tr&lt;/span&gt;&lt;span&gt; -d&lt;/span&gt;&lt;span&gt; '\r'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;"${&lt;/span&gt;&lt;span&gt;bad&lt;/span&gt;&lt;span&gt;:-&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;}"&lt;/span&gt;&lt;span&gt; !=&lt;/span&gt;&lt;span&gt; "0"&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    echo&lt;/span&gt;&lt;span&gt; "##teamcity[testFailed name='&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;' message='${&lt;/span&gt;&lt;span&gt;bad&lt;/span&gt;&lt;span&gt;:-&lt;/span&gt;&lt;span&gt;probe&lt;/span&gt;&lt;span&gt; query&lt;/span&gt;&lt;span&gt; failed&lt;/span&gt;&lt;span&gt;} offending rows']"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    PROBES_FAILED&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  fi&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  echo&lt;/span&gt;&lt;span&gt; "##teamcity[testFinished name='&lt;/span&gt;&lt;span&gt;$1&lt;/span&gt;&lt;span&gt;']"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;probe&lt;/span&gt;&lt;span&gt; "data.units.positive_stats"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  "SELECT COUNT(*) FROM units AS OF '%build.vcs.number%' WHERE hp &amp;#x3C;= 0 OR attack &amp;#x3C;= 0"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;probe&lt;/span&gt;&lt;span&gt; "data.units.unique_names"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  "SELECT COUNT(*) - COUNT(DISTINCT name) FROM units AS OF '%build.vcs.number%'"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;$PROBES_FAILED&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; !=&lt;/span&gt;&lt;span&gt; "0"&lt;/span&gt;&lt;span&gt; ]; &lt;/span&gt;&lt;span&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  echo&lt;/span&gt;&lt;span&gt; "Data-quality probes failed; skipping compile and package."&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  exit&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A probe is a &lt;code&gt;COUNT(*)&lt;/code&gt; of rows that should not exist, and any nonzero answer becomes a
failed test. We committed a unit with attack zero to showcase:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="text"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;##teamcity[testStarted name='data.units.positive_stats']&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;##teamcity[testFailed name='data.units.positive_stats' message='1 offending rows']&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;##teamcity[testFinished name='data.units.positive_stats']&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The build goes red in the overview:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-build-config-overview-with-fail-build.png/e311dc3d07b7e741a381fdbf7eb875e6cf5fbc69cee3731af2fb183b69688712.webp" alt="The build overview with the Bugbear commit&amp;#x27;s build failed and marked red"&gt;&lt;/p&gt;
&lt;p&gt;Opening the failed build shows the step halted by the gate:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-build-config-failing-build-instance-overview.png/4ae0c994fa0c5fa95a69969638f62b25314c6d9eccdc325bd45921c3d1d00cd7.webp" alt="The failed build&amp;#x27;s page, its command line step stopped after the probes reported bad data"&gt;&lt;/p&gt;
&lt;p&gt;The Tests tab names the exact check that caught it, and nothing gets
packaged:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-data-units-positive-stats-failed-test.png/c1a72d1469a027f4595f8ea495cc9ecf911b76b6f0825fed644f708333d514e9.webp" alt="The Tests tab showing the data.units.positive_stats probe failed with one offending row"&gt;&lt;/p&gt;
&lt;p&gt;Revert the commit (&lt;code&gt;CALL DOLT_REVERT('HEAD')&lt;/code&gt;) and the revert, being
itself a commit, triggers one more build. That one is green.&lt;/p&gt;
&lt;h1 id="two-builds-two-games-one-commit-apart"&gt;Two Builds, Two Games, One Commit Apart&lt;a class="anchor-link" aria-label="Link to heading" href="#two-builds-two-games-one-commit-apart"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our build step generates Go source from the config at the pinned revision,
compiles an actual game binary with the Dolt commit stamped inside via
ldflags, and cross-compiles it for Linux, Windows, and Mac from one Linux
agent. The binaries self-identify: the &lt;code&gt;config hnak4bdfk10s&lt;/code&gt; in that
first line of output is the real Dolt commit hash the artifact carries.&lt;/p&gt;
&lt;p&gt;They are also reproducible. Building the same commit twice yields
byte-identical output:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="text"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;build1 sha256: a1d97cf4d47502e5...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;build2 sha256: a1d97cf4d47502e5...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dolt pins the data, the build pins everything else, and any artifact in
the wild traces back to the exact data commit that produced it. The
build’s Artifacts tab lists the binaries, each named after its revision:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/teamcity-build-config-success-artifacts.png/9c4e7bb8181a52afa54a813425bf31e0b37571a5bc5744d3dd3dcf12a14cfbc7.webp" alt="The build&amp;#x27;s Artifacts tab listing game binaries for Linux, Windows, and Mac, each named with the Dolt commit hash"&gt;&lt;/p&gt;
&lt;h1 id="the-fine-print"&gt;The Fine Print&lt;a class="anchor-link" aria-label="Link to heading" href="#the-fine-print"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The plugin is young, and its documentation is upfront about the edges:
data changes currently show row
counts rather than row-level diffs, the Changes tab is a linear list
without a commit graph, and there is no write-back yet, so no merges or
pre-tested commits driven from TeamCity. That last item is on the
&lt;a href="https://github.com/prodoelmit/teamcity-dolt/blob/master/docs/limitations-and-roadmap.md"&gt;roadmap&lt;/a&gt;,
and it’s the one to watch: CI gating merges to your data the way it
gates merges to your code.&lt;/p&gt;
&lt;p&gt;If that idea appeals, and you would rather not run your own CI server, we
have been building it from the hosted side for a while: DoltHub supports
&lt;a href="https://www.dolthub.com/blog/2024-11-14-continuous-integration-on-data/"&gt;CI testing on data&lt;/a&gt;
and &lt;a href="https://www.dolthub.com/blog/2024-12-12-pull-request-ci-on-dolthub/"&gt;pull request CI&lt;/a&gt;,
and we were wiring
&lt;a href="https://www.dolthub.com/blog/2020-04-08-data-ci-with-dolthub-webhooks/"&gt;data CI out of webhooks&lt;/a&gt;
back in 2020. Yury’s plugin brings the same conviction to your own
TeamCity, where your builds may already live.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The Scorewarrior post asked what you would use a version-controlled SQL
database for. This plugin answers one layer up the stack: you build from
it, test against it, and ship artifacts traceable to it, with your CI
server treating data commits as what they are, commits. Give the
&lt;a href="https://plugins.jetbrains.com/plugin/31918-vcs-support-dolt"&gt;plugin&lt;/a&gt; a
spin, poke at the
&lt;a href="https://teamcity-dolt-demo.prodoelmit.me/project/EndlessSky"&gt;demo server&lt;/a&gt;,
and tell Yury what you think. He asked for ideas on showcasing it, and
when we checked, the download counter read five. Let’s fix that.&lt;/p&gt;
&lt;!-- Check the Marketplace download count:
     https://plugins.jetbrains.com/api/plugins/31918/updates --&gt;
&lt;p&gt;Curious about version-controlled databases, or want to talk CI on data?
Stop by the &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;DoltHub Discord&lt;/a&gt; and say
hello. Our engineering team hangs out there all day.&lt;/p&gt;</content:encoded>
      <dc:creator>Elian Deogracia-Brito</dc:creator>
      <category>integration</category>
      <category>use case</category>
      <category>dolt</category>
    </item>
    <item>
      <title>Doltgres Reaches 99% Compliance on SQL Logic Tests</title>
      <link>https://dolthub.com/blog/2026-07-10-doltgres-99-percent-sql-logic-tests/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-07-10-doltgres-99-percent-sql-logic-tests/</guid>
      <description>Doltgres now passes 99% of our SQL Logic Test suite, hitting one of our key correctness targets for the Doltgres 1.0 launch on August 6th.</description>
      <pubDate>Fri, 10 Jul 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Two weeks ago, we &lt;a href="https://www.dolthub.com/blog/2026-06-26-doltgres-1-0-coming-this-fall/"&gt;announced that Doltgres 1.0 is coming August 6th&lt;/a&gt;. In that post, we laid out the four things we’re focused on to get there: correctness, storage format stability, performance, and compatibility. Correctness was measured by one very concrete number: &lt;strong&gt;99% compliance on our SQL Logic Test suite&lt;/strong&gt;. At the time we were sitting at a little over 96%. Today, we’ve hit our target: Doltgres passes 99% of the suite. That’s one more box checked on the road to 1.0. 🎉&lt;/p&gt;
&lt;h2 id="sql-logic-test"&gt;SQL Logic Test&lt;a class="anchor-link" aria-label="Link to heading" href="#sql-logic-test"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://sqlite.org/sqllogictest/doc/trunk/about.wiki"&gt;SQL Logic Test&lt;/a&gt; is a test suite originally built for SQLite, containing millions of statements and queries that exercise SQL expressions, joins, aggregates, and type coercion rules. We forked it &lt;a href="https://www.dolthub.com/blog/2023-11-27-doltgres-sqllogic-test/"&gt;years ago&lt;/a&gt; and extended it with more tests to measure how correctly Dolt (and now Doltgres) execute SQL statements. The test suite in SQL Logic Test specifically stress tests the expression support in each engine. 99% represents millions of individual queries whose results have to match PostgreSQL exactly, down to the type and formatting of every returned value. This gives us a high confidence that Doltgres can correctly execute a wide range of statements and expressions.&lt;/p&gt;
&lt;h2 id="establishing-a-baseline-against-postgresql"&gt;Establishing a Baseline Against PostgreSQL&lt;a class="anchor-link" aria-label="Link to heading" href="#establishing-a-baseline-against-postgresql"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before we could chase down our own bugs, we needed to answer a more basic question: how many of these tests are even valid against PostgreSQL? The suite was originally written for SQLite, and over the years it’s been adapted and extended for MySQL as we’ve used it to test Dolt. Postgres has never been the primary target, so we couldn’t assume the entire test suite would execute cleanly against Postgres.&lt;/p&gt;
&lt;p&gt;We pointed our test runner at a real PostgreSQL server and ran the full suite against stock PostgreSQL first, to establish a baseline of how compatible the tests actually were with Postgres. That baseline surfaced a number of places where the tests themselves (or in many cases, the runner’s expectations about results) were still encoding SQLite or MySQL behavior and not compatible with slightly different behavior in Postgres. Fixing those was a prerequisite before we could start figuring out what changes were needed in Doltgres.&lt;/p&gt;
&lt;p&gt;A few examples of what we found and fixed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Integer vs. float schema types.&lt;/strong&gt; The test format encodes an expected type for each result column (&lt;code&gt;I&lt;/code&gt; for integer, &lt;code&gt;R&lt;/code&gt; for float/real), based on &lt;a href="https://www.sqlite.org/datatype3.html#type_affinity"&gt;SQLite’s type affinity rules&lt;/a&gt;. Postgres is stricter about numeric types than SQLite, so expressions SQLite treats as integers may legitimately come back as floats from Postgres, and vice versa. We updated the runner’s schema comparison to treat &lt;code&gt;I&lt;/code&gt; and &lt;code&gt;R&lt;/code&gt; as compatible in both directions, and to normalize whole-number floats (like &lt;code&gt;3.000&lt;/code&gt;) to integer formatting (&lt;code&gt;3&lt;/code&gt;) so the value comparison succeeds when the underlying values genuinely match. Limiting this to whole-number floats only means we still detect correctness errors if the values don’t logically match, but we’re more flexible on the returned result type so that we can use the same tests to match against Postgres.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Empty result sets.&lt;/strong&gt; SQLite reports &lt;code&gt;SQLITE_NULL&lt;/code&gt; as the type for every column when a query returns zero rows, which doesn’t correspond to anything meaningful in Postgres. We updated the runner to skip schema-type verification entirely when both the expected and actual result sets are empty, since there’s nothing to compare.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postgres-specific type names in the harness.&lt;/strong&gt; Our test harness inspects the driver’s reported column types to decide how to parse and compare each value. It was written with MySQL’s type names in mind (&lt;code&gt;INT&lt;/code&gt;, &lt;code&gt;BIGINT&lt;/code&gt;, &lt;code&gt;DECIMAL&lt;/code&gt;, and so on), so it didn’t know what to do with Postgres-specific names like &lt;code&gt;BOOL&lt;/code&gt;, &lt;code&gt;INT2&lt;/code&gt;, or &lt;code&gt;FLOAT4&lt;/code&gt;. We filled in the missing cases so those types get parsed and compared correctly instead of falling through and failing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MySQL-only statements.&lt;/strong&gt; Some tests exercise MySQL-specific syntax or behavior that has no Postgres equivalent at all. Rather than force those through, we added skip directives so they’re excluded when running against Doltgres, the same way we already skip SQLite-specific tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to those improvements, we also invested in running the suite in parallel, spinning up a single shared Doltgres server and fanning test files out across concurrent workers, each against its own isolated database. At the scale of millions of test queries, that’s the difference between a test run that takes minutes and one that takes hours, which matters a lot when you’re iterating on fixes.&lt;/p&gt;
&lt;h2 id="bugs-the-tests-found-in-doltgres"&gt;Bugs the Tests Found in Doltgres&lt;a class="anchor-link" aria-label="Link to heading" href="#bugs-the-tests-found-in-doltgres"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With those changes in place, we could now run the SQL Logic Tests against a real PostgreSQL server and get over 99% correctness. There are still some issues for the test suite to run 100% against PostgreSQL, and we’ll keep chipping away at those in future passes. After these improvements, the remaining test failures with Doltgres were much more likely to be real Doltgres bugs that we needed to dig into. The most interesting was in our &lt;code&gt;COALESCE()&lt;/code&gt; implementation: when called with mixed numeric types (say, an &lt;code&gt;int4&lt;/code&gt; and an &lt;code&gt;int8&lt;/code&gt;, or an &lt;code&gt;int4&lt;/code&gt; and a &lt;code&gt;float8&lt;/code&gt;), it was using a generic type conversion instead of &lt;a href="https://www.postgresql.org/docs/current/typeconv-union-case.html"&gt;Postgres’ assignment cast rules to compute the common type&lt;/a&gt;. That’s an important distinction. Assignment casts are what Postgres itself uses to widen mixed-type arguments to a common type, and using the wrong conversion path meant we could return incorrectly typed or incorrectly rounded results for a fairly common pattern in real SQL.&lt;/p&gt;
&lt;h2 id="on-track-for-august-6th"&gt;On Track for August 6th&lt;a class="anchor-link" aria-label="Link to heading" href="#on-track-for-august-6th"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Correctly executing 99% of the SQL Logic Test suite was our target for Doltgres’ 1.0 release. It gives us high confidence that a wide range of statements and SQL expressions are executing correctly in Doltgres. By baselining the test suite against PostgreSQL, we discovered that we were closer to this milestone than we initially expected. We thought we still had many remaining gaps to fill to reach that milestone, but it turned out that how the results were being processed by the test runner accounted for most of the gap.&lt;/p&gt;
&lt;p&gt;Executing queries correctly, and returning identical results as PostgreSQL, is the foundation for our 1.0 launch. Without correct query execution, the other goals, like fast execution of queries and tool compatibility, just don’t matter. Overall, we’re making great progress on our 1.0 punch list and remain on track for &lt;strong&gt;August 6th&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you’re running Doltgres and you hit a query that returns the wrong result, an error you don’t expect, or behavior that just doesn’t match Postgres, please &lt;a href="https://github.com/dolthub/doltgresql/issues/new"&gt;send us a GitHub issue&lt;/a&gt; and let us know. We want to find and fix as many of these as possible before 1.0 ships, and customer-reported issues go straight to the top of our queue.&lt;/p&gt;
&lt;p&gt;If you haven’t started using Doltgres yet, give it a shot! You can install Doltgres by running &lt;code&gt;brew intall doltgres&lt;/code&gt; on a Mac with Homebrew, or you download a binary from our &lt;a href="https://github.com/dolthub/doltgresql/releases"&gt;GitHub releases&lt;/a&gt;. Our dev team hangs out on the DoltHub Discord server every day, so feel free to &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;come by and tell us how it’s going&lt;/a&gt;. We’re closing in on 1.0 and every bit of feedback helps us get there!&lt;/p&gt;</content:encoded>
      <dc:creator>Jason Fulghum</dc:creator>
      <category>doltgres</category>
    </item>
    <item>
      <title>Doltgres 1.0 Coming August 6th</title>
      <link>https://dolthub.com/blog/2026-06-26-doltgres-1-0-coming-this-fall/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-26-doltgres-1-0-coming-this-fall/</guid>
      <description>Doltgres 1.0 is coming August 6th. Here's what we've been working on and what we're focused on to get there.</description>
      <pubDate>Fri, 26 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;a href="https://www.doltgres.com/"&gt;Doltgres&lt;/a&gt; is a PostgreSQL-compatible database with Git-style version control built in. It gives you all the power of SQL with the ability to branch, merge, diff, clone, and push your data, using the same model you already know from managing your source code with Git. Doltgres implements the PostgreSQL wire protocol, syntax, and type system so that you can use it just like you use PostgreSQL.&lt;/p&gt;
&lt;p&gt;We first &lt;a href="https://www.dolthub.com/blog/2023-11-01-announcing-doltgresql/"&gt;announced Doltgres in November 2023&lt;/a&gt; as an Alpha, then &lt;a href="https://www.dolthub.com/blog/2025-04-16-doltgres-goes-beta/"&gt;launched the Beta in April 2025&lt;/a&gt;, and now we’re announcing our next major milestone: &lt;strong&gt;Doltgres 1.0, coming August 6th&lt;/strong&gt;. This date is pretty special for us here… it’s the eight-year anniversary of DoltHub! Eight years of hard work leading up to a production-ready, PostgreSQL-compatible versioned database! Not too shabby.&lt;/p&gt;
&lt;p&gt;In this post, we’ll explain what 1.0 means for Doltgres, share what we’re focused on in the next few months, and let you know how you can help.&lt;/p&gt;
&lt;h2 id="what-does-10-mean"&gt;What Does 1.0 Mean?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-does-10-mean"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Doltgres reaching 1.0 is our signal that Doltgres is ready for production use. That means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Correctness&lt;/strong&gt; Your queries reliably return the correct results, matching what PostgreSQL returns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage Stability&lt;/strong&gt; The storage format is locked in, and we won’t make breaking storage serialization changes in the 1.x releases that require migrating your data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt; Query latency is within an acceptable range of PostgreSQL’s performance. We’re shooting to be within 3x PostgreSQL’s latency for key sysbench measurements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility&lt;/strong&gt; The tools, libraries, ORMs, and frameworks your team already uses work correctly with Doltgres, too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Six months ago, we gave an update on Doltgres’ progress in the &lt;a href="https://www.dolthub.com/blog/2025-10-16-state-of-doltgres/"&gt;State of Doltgres&lt;/a&gt;. Since then, we’ve made significant progress towards a 1.0 milestone. Here’s what we’re focused on in the home stretch towards 1.0.&lt;/p&gt;
&lt;h2 id="correctness"&gt;Correctness&lt;a class="anchor-link" aria-label="Link to heading" href="#correctness"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of our key tools for testing SQL correctness is the &lt;a href="https://sqlite.org/sqllogictest/doc/trunk/about.wiki"&gt;SQLite SQL Logic Test suite&lt;/a&gt;. This is a large, open-source test suite originally developed by SQLite containing over seven million test queries covering a wide range of SQL expressions and statements. We’ve forked this module and added many more tests, and we run these against Dolt and Doltgres to measure compatibility and ensure that we’re returning correct results.&lt;/p&gt;
&lt;p&gt;We’ve been tracking our progress on this suite &lt;a href="https://www.dolthub.com/blog/2023-11-27-doltgres-sqllogic-test/"&gt;since the early days of the project&lt;/a&gt; when we were only able to execute 70% of the statements correctly. Today, we’re passing a little over 96% of the tests correctly, and we’re digging into the failing tests to categorize them and tackle the discrepancies.&lt;/p&gt;
&lt;p&gt;Our goal for 1.0 is to reach &lt;strong&gt;99% SQL Logic Test compliance&lt;/strong&gt;. Every percentage point matters here. At this scale of testing, 99% represents millions of individual queries and results that must match PostgreSQL exactly.&lt;/p&gt;
&lt;h2 id="storage-stability"&gt;Storage Stability&lt;a class="anchor-link" aria-label="Link to heading" href="#storage-stability"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One thing that makes our major version releases meaningful is the storage format guarantee they carry. For Doltgres 1.0, we’re committing to a stable on-disk serialization format, just like we did for the Dolt 1.0 launch back in 2023. This means &lt;strong&gt;no data migrations will be required&lt;/strong&gt; for any new features we add in the 1.x line of releases. Changing the storage serialization format requires data to be migrated from the old format to the new format, which is disruptive and inconvenient to customers, so we give this guarantee that the storage serialization format won’t change in the 1.x line. When we start to think about a 2.0 release for Doltgres, there may be compelling features or optimizations that require a serialization format change, but we don’t make those changes lightly. There’s a very high bar for backwards incompatible storage serialization changes once we’ve given our customers the green light to use a storage format in production.&lt;/p&gt;
&lt;h2 id="performance"&gt;Performance&lt;a class="anchor-link" aria-label="Link to heading" href="#performance"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ve been benchmarking Doltgres performance from &lt;a href="https://www.dolthub.com/blog/2023-12-15-benchmarking-postgres-mysql-dolt/"&gt;the beginning&lt;/a&gt;, and we continue to chase down performance bottlenecks as we find them. Because Doltgres uses the same query engine as Dolt (our MySQL-compatible database product), it has access to all the performance improvements we’ve done for Dolt. However, PostgreSQL raises the performance bar from where MySQL set it. In our testing, &lt;a href="https://www.dolthub.com/blog/2024-07-16-mysql-postgres-sysbench-latency/"&gt;we found that PostgreSQL is more than twice as fast as MySQL&lt;/a&gt;, so we’ve been working hard to find more optimizations, do more performance testing, and keep inching closer to PostgreSQL’s performance.&lt;/p&gt;
&lt;p&gt;Our performance goal for 1.0 is to get &lt;a href="https://github.com/akopytov/sysbench"&gt;sysbench&lt;/a&gt; results for Doltgres to within &lt;strong&gt;3x of PostgreSQL&lt;/strong&gt;. We’re currently right on the cusp of achieving this, with a current performance multiplier of 3.3x.&lt;/p&gt;
&lt;p&gt;We continue to find and fix performance issues as they come up. If you encounter a query that is unexpectedly slow, please &lt;a href="https://github.com/dolthub/doltgresql/issues/new"&gt;file an issue&lt;/a&gt; and we’ll dig in and find a way to make it fast for you.&lt;/p&gt;
&lt;h2 id="compatibility"&gt;Compatibility&lt;a class="anchor-link" aria-label="Link to heading" href="#compatibility"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PostgreSQL’s ecosystem is vast. Different clients, libraries, ORMs, and tools all speak the PostgreSQL wire protocol in subtly different ways. They use different combinations of the simple and extended query protocols, rely on different parts of &lt;code&gt;pg_catalog&lt;/code&gt;, and have different expectations about types, encodings, and error messages.&lt;/p&gt;
&lt;p&gt;For 1.0, we want to ensure broad compatibility across the PostgreSQL tools most teams are using. This means testing and fixing issues with popular clients and libraries including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Client libraries&lt;/strong&gt;: psycopg2, asyncpg, pgx, pg (node-postgres), and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ORMs&lt;/strong&gt;: Prisma, SQLAlchemy, ActiveRecord, Django ORM, Hibernate, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tools&lt;/strong&gt;: psql, TablePlus, pgAdmin, Dolt Workbench, and more&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these tools, especially the ORMs and higher-level tools make extensive use of the system information tables in &lt;code&gt;pg_catalog&lt;/code&gt; to introspect your schema and display it in a UI, generate migrations, or validate configurations, so this work also includes filling in gaps and fixing incorrect data in those tables so that tools can access the information they need to work correctly with Doltgres.&lt;/p&gt;
&lt;p&gt;We’ve already done a lot of work in this area. We’ve previously written about supporting &lt;a href="https://www.dolthub.com/blog/2026-04-06-doltgresql-prisma/"&gt;Prisma&lt;/a&gt;, &lt;a href="https://www.dolthub.com/blog/2025-06-03-doltgres-laravel/"&gt;Laravel&lt;/a&gt;, &lt;a href="https://www.dolthub.com/blog/2025-04-24-doltgres-django/"&gt;Django&lt;/a&gt;, &lt;a href="https://www.dolthub.com/blog/2025-07-18-sql-alchemy-getting-started-doltgres/"&gt;SQLAlchemy&lt;/a&gt;, and &lt;a href="https://www.dolthub.com/blog/2025-04-21-doltgres-and-knexjs/"&gt;KnexJS&lt;/a&gt;, but there’s more to do. We want to find the issues with popular tools before our customers do. This is another place where your real-world usage can help us find gaps. If you hit any issues with Doltgres and a SQL client library, ORM, or other SQL tool, please &lt;a href="https://github.com/dolthub/doltgresql/issues/new"&gt;report it to us&lt;/a&gt; so we can dig in and fix it.&lt;/p&gt;
&lt;h2 id="other-features"&gt;Other Features&lt;a class="anchor-link" aria-label="Link to heading" href="#other-features"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Beyond the core themes of correctness, storage stability, performance, and compatibility, there are several features we’re actively developing and vetting for Doltgres’ 1.0 launch:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remotes and Push/Pull&lt;/strong&gt; &lt;a href="https://www.doltgres.com/docs/concepts/git/remotes/"&gt;Remotes&lt;/a&gt; are a powerful feature that allow you to work in a distributed mode, by pushing data to remotes and pulling data from remotes, just like Git remotes. We’re working to ensure these features are fully supported in Doltgres, enabling the same kinds of remote collaboration and decentralized workflows that Dolt and Git users are familiar with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dolt Replication Protocol&lt;/strong&gt; &lt;a href="https://www.doltgres.com/docs/concepts/rdbms/replication/"&gt;Doltgres supports two types of replication&lt;/a&gt;: the PostgreSQL replication protocol and a Dolt-specific replication protocol. The PostgreSQl replication protocol allows you to run DoltgreSQL as a replica of a PostgreSQL server. The Dolt-specific replication protocol allows you to set up more advanced primary/replica configurations and includes features for high-availability and hot-swappable replicas. We’re working to finish testing this support and make sure it’s ready for production.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Garbage Collection Improvements&lt;/strong&gt; As databases accumulate history, they can grow large. Garbage collection helps keeps that growth manageable by cleaning up unreachable data that is no longer needed. Doltgres already supports the standard manually invoking garbage collection with the &lt;code&gt;dolt_gc()&lt;/code&gt; stored procedure, but we don’t want to launch 1.0 without the latest garbage collection improvements: &lt;a href="https://www.dolthub.com/blog/2026-04-28-introducing-incremental-garbage-collection/"&gt;incremental garbage collection&lt;/a&gt; and &lt;a href="https://www.dolthub.com/blog/2025-02-28-announcing-automatic-gc-in-sql-server/"&gt;automatic garbage collection&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="try-doltgres-and-send-us-issues"&gt;Try Doltgres and Send Us Issues&lt;a class="anchor-link" aria-label="Link to heading" href="#try-doltgres-and-send-us-issues"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The best way you can help us get to 1.0 is to &lt;strong&gt;use Doltgres on real workloads and tell us what breaks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Install Doltgres and try it with your existing PostgreSQL application. Point your ORM at it. Run your migrations. See what works and what doesn’t. Every issue you report makes the product better, and we love to move fast on customer-reported issues.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Install&lt;/strong&gt;: &lt;code&gt;brew install doltgres&lt;/code&gt; or download from our &lt;a href="https://github.com/dolthub/doltgresql/releases"&gt;GitHub releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Report issues&lt;/strong&gt;: &lt;a href="https://github.com/dolthub/doltgresql/issues/new"&gt;Create an issue in the Doltgres repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re very excited to get Doltgres to 1.0 and announce that it’s ready for production workloads. If you want to be part of getting us there, now is a great time to try out Doltgres! Come by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt; and let us know how your experience goes.&lt;/p&gt;</content:encoded>
      <dc:creator>Jason Fulghum</dc:creator>
      <category>doltgres</category>
    </item>
    <item>
      <title>What People Are Saying: LWN Edition</title>
      <link>https://dolthub.com/blog/2026-06-17-what-people-are-saying-lwn/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-17-what-people-are-saying-lwn/</guid>
      <description>More and more people are talking about us. Here's what LWN is saying.</description>
      <pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;In 2019, we released &lt;a href="https://www.github.com/dolthub/dolt"&gt;Dolt, the world’s first version-controlled SQL database.&lt;/a&gt; In the seven years since, we’ve seen a gradual but steady influx of attention as people become aware we exist.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dolt-stars.png/7e357eabb65fb93bd1e2a00b575811b3b6d0a30eaf912545097b99d318ffbd8d.webp" alt="Dolt&amp;#x27;s stars on GitHub"&gt;&lt;/p&gt;
&lt;p&gt;You can clearly see the first time we got mentioned on HackerNews in 2021.&lt;/p&gt;
&lt;p&gt;More and more, this attention is taking the form of people not just noticing us, but talking about us to others. We love that. We think that word-of-mouth buzz is a strong signal for the genuine usefulness of a tool.&lt;/p&gt;
&lt;p&gt;Last month, &lt;a href="https://lwn.net/Articles/1068864/"&gt;Daroc Alden over at LWN wrote about us.&lt;/a&gt;&lt;sup&gt;&lt;a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="" aria-describedby="footnote-label"&gt;1&lt;/a&gt;&lt;/sup&gt; It was really cool to see an outside perspective. I think they did a great job of explaining what Dolt is and how it can be used. They also have a great explanation of Prolly Trees, the B-tree inspired data structure that makes Dolt possible. &lt;a href="https://www.dolthub.com/blog/2024-03-03-prolly-trees/"&gt;We’re kind of obsessed with Prolly Trees&lt;/a&gt;, so it’s cool to see someone else understand them and even see them talk about some of the improvements that we made to Prolly Trees to improve node size distribution.&lt;/p&gt;
&lt;p&gt;Overall, I think the LWN article did a great job introducing Dolt to a new audience and I’m happy to see it. But there were a couple of misconceptions in the article, so for the sake of completeness I wanted to clear them up.&lt;/p&gt;
&lt;h2 id="project-architecture"&gt;Project Architecture&lt;a class="anchor-link" aria-label="Link to heading" href="#project-architecture"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Two related misconceptions we see pop up on occasion is the claim that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dolt and its siblings (Doltgres and DoltLite) are plugins/forks of common SQL engines.&lt;/li&gt;
&lt;li&gt;Each project is a different wrapper around an otherwise identical storage layer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combined, these two ideas paint the picture that Dolt / Doltgres / DoltLite each take the same underlying storage format and bridge it to MySQL / PostgreSQL / SQLite, respectively.&lt;/p&gt;
&lt;p&gt;LWN repeats both of these ideas in their article. To quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[Dolt, Doltgres, and Doltlite] have separate frontends for the different SQL dialects, but the projects share a common storage backend that supports version-control operations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;That competitive performance is possible because Dolt only changes the storage layer of the database. The query planner, index maintenance, and so on all reuse MySQL, PostgreSQL, or SQLite’s existing implementations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The reality is slightly more nuanced. We maintain our own SQL engine, &lt;a href="https://github.com/dolthub/go-mysql-server/"&gt;go-mysql-server&lt;/a&gt;. Like the name suggests, it was originally made for the MySQL dialect, but recently we’ve also been adding support for Postgres.&lt;/p&gt;
&lt;p&gt;We also have a common storage backend, designed for use with &lt;code&gt;go-mysql-server&lt;/code&gt;. Both Dolt and Doltgres use this backend. They aren’t plugins, and they don’t depend on the MySQL or Postgres code bases at all.&lt;/p&gt;
&lt;p&gt;On the other hand, DoltLite &lt;em&gt;is&lt;/em&gt; a custom storage backend for SQLite, and as such, it doesn’t use the common storage backend, but rather its own format and implementation. It’s based on the same design as the original, but the formats are not compatible.&lt;/p&gt;
&lt;h2 id="the-power-of-git"&gt;The Power of Git&lt;a class="anchor-link" aria-label="Link to heading" href="#the-power-of-git"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s a lot of reasons why applying the Git model to databases makes sense. The LWN article points out the biggest one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The real utility of Dolt comes from the ability to restore old commits, fork historical states of the database, and merge in changes after review.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is 100% true, and it’s the most common way we see users take advantage of Git-style version control. But there’s another big benefit to Git-style version control too: remotes.&lt;/p&gt;
&lt;p&gt;Just like Git, Dolt allows you to clone a database from a remote and then sync incrementally. When you &lt;code&gt;dolt pull&lt;/code&gt; or &lt;code&gt;dolt push&lt;/code&gt;, only the new changes get sent. This lets you get a local, up-to-date copy by only downloading the parts that actually changed. That turns out to be a pretty powerful feature for replicas.&lt;/p&gt;
&lt;h2 id="how-git-and-dolt-store-snapshots"&gt;How Git and Dolt Store Snapshots&lt;a class="anchor-link" aria-label="Link to heading" href="#how-git-and-dolt-store-snapshots"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Git and Dolt take a “snapshot” approach to version control, where each commit represents is an independent snapshot of the data at a specific point in time.&lt;sup&gt;&lt;a href="#user-content-fn-2" id="user-content-fnref-2" data-footnote-ref="" aria-describedby="footnote-label"&gt;2&lt;/a&gt;&lt;/sup&gt; But in the event that not much has changed between commits, what stops all the different snapshots from taking up lots of extra storage space?&lt;/p&gt;
&lt;p&gt;A common Git misconception is that Git reduces storage by storing commits internally as deltas. The article repeats that misconception and suggests that this is the main reason why Git (and by extension Dolt) require data structures that can be diffed efficiently. To quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Each commit is logically independent, and could in theory just be stored as-is. In practice, most Git repositories do not completely change between commits, and it’s more efficient to store the differences between subsequent snapshots, rather than the snapshots themselves.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Git, which works with entire directory trees, relies on being able to quickly check whether a particular sub-tree has changed in order to produce compact diffs that include only the actual changes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There’s some truth to this: Git does have the ability to produce compact diffs (such as with the &lt;code&gt;git diff&lt;/code&gt; command). And Git’s storage format does have the ability to store deltas on individual files. But it doesn’t store the whole commit as a delta, and deltas aren’t the primary method for achieving efficient storage.&lt;/p&gt;
&lt;p&gt;The actual method by which Git and Dolt achieve compact storage is much simpler: when two commits trees contain identical sub-trees, Git and Dolt simply only store that identical tree once. And indeed further down, the LWN article explains exactly that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Content-addressed storage is a scheme that many version-control systems use to deduplicate data: a particular diff or other object is stored in a location based on the hash of its contents. This ensures that duplicate items will reuse the same storage space.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This trick of reusing the unchanged parts of the tree is called &lt;strong&gt;structural sharing.&lt;/strong&gt; In order to make this possible, the data being stored requires that two trees containing the same items are exactly identical, regardless of how those items were inserted. This property is called &lt;strong&gt;history independence&lt;/strong&gt;, and its the property that Prolly Trees provide that B-trees don’t. History independence is also how both Git and Dolt can produce efficient diffs.&lt;/p&gt;
&lt;p&gt;So Git and Dolt’s efficient storage isn’t because of their diffing capabilities, but rather the same property (history independence) allows for both fast diffs &lt;em&gt;and&lt;/em&gt; compact storage.&lt;/p&gt;
&lt;h2 id="dolts-dynamic-node-size-thresholds"&gt;Dolt’s Dynamic Node Size Thresholds&lt;a class="anchor-link" aria-label="Link to heading" href="#dolts-dynamic-node-size-thresholds"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It was really cool to see this get a shout-out.&lt;/p&gt;
&lt;p&gt;A known shortcoming of the original prolly tree design is that it produces trees where the number of elements per node follows a &lt;a href="https://en.wikipedia.org/wiki/Geometric_distribution"&gt;geometric distribution&lt;/a&gt;. This is a pretty big problem, because it both means that there’s no theoretical upper bound on node sizes, and it leads to imbalanced trees with worse performance.&lt;/p&gt;
&lt;p&gt;Think about it this way: if a small number of nodes in your tree are much larger than others, then those nodes are not only going to take longer to process, but they’re also going to get visited more frequently because they have more children. This makes tree operations more likely to hit slow paths.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.dolthub.com/blog/2022-06-27-prolly-chunker/#chunk-size-variance"&gt;Dolt has a pretty clever solution to this problem,&lt;/a&gt; and not only did the article talk about it, it spawned some good discussion in the comments. Basically, Dolt uses a dynamic threshold to decide how to draw boundaries between tree nodes: as a tree node fills up, the probability of the next element causing a split increases.&lt;/p&gt;
&lt;p&gt;One small correction though: the dynamic threshold isn’t based on the number of node elements like the example suggests, but rather the number of bytes written. This matters when the elements are variable-length, and gives us better control over the exact distribution of node sizes.&lt;/p&gt;
&lt;h1 id="thats-all-folks"&gt;That’s All, Folks&lt;a class="anchor-link" aria-label="Link to heading" href="#thats-all-folks"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This was a great read. It was really cool to see an outsider’s perspective on Dolt. The readers of LWT are lively and did a lot of engaging in the comments of the original article.&lt;/p&gt;
&lt;p&gt;If you’d like to engage with us more, consider joining our &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt;. We’re always down to chat and answer questions.&lt;/p&gt;
&lt;section data-footnotes="" class="footnotes"&gt;&lt;h2 class="sr-only" id="footnote-label"&gt;Footnotes&lt;a class="anchor-link" aria-label="Link to heading" href="#footnote-label"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li id="user-content-fn-1"&gt;
&lt;p&gt;What does LWN stand for? &lt;a href="https://lwn.net/op/FAQ.lwn#:~:text=%5BWhat%20does%20LWN%20stand%20for%5D"&gt;Apparently nothing anymore, but it used to stand for Linux Weekly News.&lt;/a&gt; &lt;a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="user-content-fn-2"&gt;
&lt;p&gt;This is in comparison to delta-based version control systems, where each commit represents a diff on the previous commit. &lt;a href="https://www.dolthub.com/blog/2026-01-07-how-to-version-control-a-database/#version-control-approaches"&gt;We’ve written in the past about the different types of version control schemes.&lt;/a&gt; &lt;a href="#user-content-fnref-2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded>
      <dc:creator>Nick Tobey</dc:creator>
      <category>dolt</category>
    </item>
    <item>
      <title>Git For Context</title>
      <link>https://dolthub.com/blog/2026-06-15-git-for-context/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-15-git-for-context/</guid>
      <description>We built a version of Open Code with version-controlled context. Check it out.</description>
      <pubDate>Mon, 15 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Here at DoltHub we tend to view everything through the lens of version control. We built &lt;a href="https://www.doltdb.com"&gt;Dolt&lt;/a&gt;, the world’s first version-controlled SQL database after all. Would this new tool be better with branches? Diffs? Merges? Clones? Inevitably, we see some opportunities.&lt;/p&gt;
&lt;p&gt;Databases? Check.&lt;br&gt;
Spreadsheets? Eventually.&lt;br&gt;
Coding agents? Hmmm. I wonder…&lt;/p&gt;
&lt;p&gt;With the rise of &lt;a href="https://www.dolthub.com/blog/2026-03-26-vibe-code-vs-trad-code/"&gt;vibe coding&lt;/a&gt; and agents in general, we’re &lt;a href="https://www.dolthub.com/blog/2026-01-22-agentic-memory/"&gt;looking at context&lt;/a&gt; with a lustful, content-addressed eye. What if there was “Git for Context”? What would it look like? What features would developers love? This article won’t just answer those questions — it will answer them with a demo.&lt;/p&gt;
&lt;h1 id="context"&gt;Context&lt;a class="anchor-link" aria-label="Link to heading" href="#context"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I’m sure most people already know this but let’s start with a quick definition of context. Context is the prompt and additional metadata that is sent to a large language model to produce a response. One of the key innovations with agents was the ability to iterate on a context/response action loop, combined with tool use to allow agents to do useful work like writing code. Agents generally have an append-only context with a compaction step when it gets too big.&lt;/p&gt;
&lt;p&gt;For most agents, full context is hidden from the user, but you can dig into files in your &lt;code&gt;.claude&lt;/code&gt; or &lt;code&gt;.codex&lt;/code&gt;. It started as raw text files, but recently, most agents are discovering the need for &lt;a href="https://www.dolthub.com/blog/2026-03-13-multi-agent-persistence/"&gt;structured data in context&lt;/a&gt; for more targeted retrieval, quality control, and concurrency management. So now you’ll see a lot of JSON format files and even, for the more cutting edge agents, SQLite files.&lt;/p&gt;
&lt;h1 id="open-code"&gt;Open Code&lt;a class="anchor-link" aria-label="Link to heading" href="#open-code"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Enter &lt;a href="https://github.com/anomalyco/opencode"&gt;Open Code&lt;/a&gt;, the most popular open source coding agent. An open source coding harness? Yes please.&lt;/p&gt;
&lt;p&gt;Obviously, as an open source company ourselves, we love and support open source. One of the benefits of open source is that you can show, not tell. We saw Open Code &lt;a href="https://github.com/anomalyco/opencode/issues/7840"&gt;migrated their persistence to SQLite&lt;/a&gt; and thought “How hard would it be to add version control for context using Dolt or DoltLite? It’s already SQL.”&lt;/p&gt;
&lt;p&gt;Even the maintainers were goading us into it. This quote is ripped from one of their issues.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is not very big or complex data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds like a perfect place to add version control.&lt;/p&gt;
&lt;h1 id="why-version-control-context"&gt;Why Version Control Context?&lt;a class="anchor-link" aria-label="Link to heading" href="#why-version-control-context"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I wrote a whole article about &lt;a href="https://www.dolthub.com/blog/2026-03-13-multi-agent-persistence/"&gt;agentic memory&lt;/a&gt; that makes a deeper case for version-controlled context: Git for Context.&lt;/p&gt;
&lt;p&gt;But for Open Code in particular, we think Git for Context starts first and foremost as a development tool for Open Code contributors. What specifically happens to context after compaction? What if I compact 10 times on 10 different branches? How consistent is compaction? What if I manually &lt;a href="https://www.dolthub.com/blog/2026-05-13-delete-comments/"&gt;strip out code comments&lt;/a&gt; from context on one branch and leave them on another? I’ll compare the context and code after 5 turns. Branches and diffs are powerful development tools for testing and comparing different strategies in the probabilistic environment agents live in. Could Git for Context make Open Code better, faster?&lt;/p&gt;
&lt;p&gt;If Open Code contributors find Git for Context useful, maybe the most useful features could become user facing features? Having ten sub-agents work from the same context base on branches, comparing outputs, and merging good outcomes seems like a workflow that could work for some tasks. My only hesitation is the user experience. Adding version control to anything is a UX challenge.&lt;/p&gt;
&lt;p&gt;But I think the most important user-facing feature would probably be context preservation. It seems weird to me already that we don’t push the context of our coding agents up to an immutable repository and link to it in our pull requests. Stored context is the agent stack trace. When something goes wrong, surely we will want humans or even other agents to dig through the context to figure out what happened. This can be closely linked to multiplayer mode. Pull an agent’s context locally and have an agentic engineering expert resume the session where it went off the rails as a teaching moment for other engineers. This is more GitHub for Context than Git for Context, but you can’t have one without the other.&lt;/p&gt;
&lt;h1 id="why-talk-when-you-can-show"&gt;Why Talk When You Can Show?&lt;a class="anchor-link" aria-label="Link to heading" href="#why-talk-when-you-can-show"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We built it! You can check out &lt;a href="https://github.com/dolthub/opencode"&gt;version-controlled Open Code on GitHub&lt;/a&gt;, also free and open source.&lt;/p&gt;
&lt;h2 id="clone-and-build-our-open-code-fork"&gt;Clone and Build our Open Code Fork&lt;a class="anchor-link" aria-label="Link to heading" href="#clone-and-build-our-open-code-fork"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First, you need to clone and build &lt;a href="https://github.com/dolthub/opencode"&gt;our Open Code fork&lt;/a&gt;. Before you get started, make sure you have &lt;code&gt;bun&lt;/code&gt; installed. The example assumes you are running OSX with an ARM64 chip. If your architecture is different, the commands below will be similar but for your architecture.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ~/opencode-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; git@github.com:dolthub/opencode.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; opencode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;bun&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; opencode/packages/opencode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;bun&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt; --single&lt;/span&gt;&lt;span&gt; --skip-install&lt;/span&gt;&lt;span&gt; --skip-embed-web-ui&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; dist/opencode-darwin-arm64/bin/opencode&lt;/span&gt;&lt;span&gt; ~/bin/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you have an &lt;code&gt;opencode&lt;/code&gt; binary in &lt;code&gt;~/bin&lt;/code&gt;. If &lt;code&gt;~/bin&lt;/code&gt; is at the front f your &lt;code&gt;PATH&lt;/code&gt; your &lt;code&gt;PATH&lt;/code&gt;, you can just run &lt;code&gt;opencode&lt;/code&gt; or you can run it directly with a full path.&lt;/p&gt;
&lt;p&gt;But first, let’s create and start a Dolt server to house your version-controlled context. I would do this in a new shell so you can watch the query logs.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ~/opencode-demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; db&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; db&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "CREATE USER 'dolt'@'%' IDENTIFIED BY 'pass1234';"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "GRANT ALL PRIVILEGES ON *.* TO 'dolt'@'%';'"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql&lt;/span&gt;&lt;span&gt; -q&lt;/span&gt;&lt;span&gt; "CREATE DATABASE opencode;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; sql-server&lt;/span&gt;&lt;span&gt; -H127.0.0.1&lt;/span&gt;&lt;span&gt; --loglevel&lt;/span&gt;&lt;span&gt; DEBUG&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="try-it"&gt;Try It&lt;a class="anchor-link" aria-label="Link to heading" href="#try-it"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now, you’re ready to try &lt;a href="https://github.com/dolthub/opencode"&gt;version-controlled OpenCode&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;OPENCODE_MYSQL_URL&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;mysql://dolt:pass1234@127.0.0.1:3306/opencode&lt;/span&gt;&lt;span&gt; ~/bin/opencode&lt;/span&gt;&lt;span&gt; ~/myproject/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Version-controlled Open Code exposes the following new version control commands. If you’re familiar with Git, these will look familiar.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;/commit &amp;#x3C;message&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/log&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/branch [-v]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/branch &amp;#x3C;name&gt; &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/branch &amp;#x3C;name&gt; &amp;#x3C;[prompt_index]&gt; -m &amp;#x3C;message&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/checkout &amp;#x3C;branch_name&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/checkout -b &amp;#x3C;branch_name&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/reset&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/reset &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/reset &amp;#x3C;[prompt_index]&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/context [--show]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/context &amp;#x3C;ref&gt; [--show]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-stat&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-stat &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-stat &amp;#x3C;ref1&gt; &amp;#x3C;ref2&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-context&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-context &amp;#x3C;ref&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/diff-context &amp;#x3C;ref1&gt; &amp;#x3C;ref2&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/history [-v]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/history &amp;#x3C;ref&gt; [-v]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;/sql &amp;#x3C;SQL STATEMENT&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="demo"&gt;Demo&lt;a class="anchor-link" aria-label="Link to heading" href="#demo"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As many of you know, my pet project is &lt;a href="https://github.com/dolthub/doltlite"&gt;DoltLite&lt;/a&gt;, a fork of SQLite with Dolt-inspired version control. I asked Open Code to clone a copy and give it a code review, making commits along the way. I’m just going to show the &lt;code&gt;diff&lt;/code&gt; functionality today and come up with a more complex demo for another blog article.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;ok. we're going to be working on doltlite. can you give it a code review for duplicate code?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There was a lot of output. But how did the context change? I can use &lt;code&gt;/diff-stat&lt;/code&gt; for a raw view of what’s changed in my context.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;[/diff-stat]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Diff stat HEAD → WORKING&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;message:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  rows:   3 → 35 (+32)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  added:    +32 rows, +160 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  deleted:  -0 rows, -0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modified: ~0 rows, ~0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  data:   0 B → 13.5 KB (+13.5 KB)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    added rows:    +13.5 KB&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    deleted rows:  -0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    modified rows: 0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;part:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  rows:   9 → 142 (+133)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  added:    +133 rows, +798 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  deleted:  -0 rows, -0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modified: ~0 rows, ~0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  data:   0 B → 248.5 KB (+248.5 KB)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    added rows:    +248.5 KB&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    deleted rows:  -0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    modified rows: 0 B&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;todo:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  rows:   0 → 5 (+5)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  added:    +5 rows, +35 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  deleted:  -0 rows, -0 cells&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  modified: ~0 rows, ~0 cells&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, I’ll make another &lt;code&gt;/commit&lt;/code&gt; and ask Open Code to fix the first item in the review.&lt;/p&gt;
&lt;p&gt;After a few minutes, I’ll use &lt;code&gt;/diff-context&lt;/code&gt; this time to see a more human readable diff.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;[/diff-context]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Context diff HEAD → WORKING&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Model:           opencode/big-pickle (unchanged)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Messages:        64 → 124 (+60)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  assistant    32 → 62 (+30)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  tool         29 → 58 (+29)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  user         3 → 4 (+1)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Tool calls:      41 → 75 (+34)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total chars:     168023 → 275974 (+107951)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Approx tokens:   42006 → 68994 (+26988)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Changes by position:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [0..63]  identical (64 msgs)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [64]      added    user (+57 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [65]      added    assistant (+20832 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [66]      added    tool (+803 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [67]      added    assistant (+919 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [68]      added    tool (+3971 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [69]      added    assistant (+710 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [70]      added    tool (+1663 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [71]      added    assistant (+8361 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [72]      added    tool (+790 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [73]      added    assistant (+625 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [74]      added    tool (+4655 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [75]      added    assistant (+391 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [76]      added    tool (+1364 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [77]      added    assistant (+4381 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [78]      added    tool (+149 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [79]      added    assistant (+953 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [80]      added    tool (+805 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [81]      added    assistant (+306 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [82]      added    tool (+9912 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [83]      added    assistant (+8428 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [84]      added    tool (+149 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [85]      added    assistant (+3446 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [86]      added    tool (+150 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [87]      added    assistant (+715 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [88]      added    tool (+150 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [89]      added    assistant (+681 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [90]      added    tool (+807 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [91]      added    assistant (+662 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [92]      added    tool (+17608 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [93]      added    assistant (+18140 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [94]      added    tool (+149 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [95]      added    assistant (+720 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [96]      added    tool (+809 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [97]      added    assistant (+298 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [98]      added    tool (+141 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [99]      added    assistant (+294 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [100]      added    tool (+1141 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [101]      added    assistant (+1398 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [102]      added    tool (+135 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [103]      added    assistant (+1117 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [104]      added    tool (+135 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [105]      added    assistant (+506 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [106]      added    tool (+8433 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [107]      added    assistant (+421 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [108]      added    tool (+4157 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [109]      added    assistant (+1946 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [110]      added    tool (+542 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [111]      added    assistant (+525 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [112]      added    tool (+624 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [113]      added    assistant (+1340 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [114]      added    tool (+274 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [115]      added    assistant (+811 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [116]      added    tool (+263 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [117]      added    assistant (+507 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [118]      added    tool (+417 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [119]      added    assistant (+2730 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [120]      added    tool (+291 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [121]      added    assistant (+847 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [122]      added    tool (+809 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [123]      added    assistant (+1562 chars)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare this to my next &lt;code&gt;make a pr&lt;/code&gt; prompt. Much lighter weight.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="plaintext"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;  [/diff-context]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Context diff HEAD → WORKING&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Model:           opencode/big-pickle (unchanged)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Messages:        124 → 136 (+12)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  assistant    62 → 68 (+6)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  tool         58 → 63 (+5)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  user         4 → 5 (+1)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Tool calls:      75 → 82 (+7)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total chars:     275974 → 298799 (+22825)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Approx tokens:   68994 → 74700 (+5706)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Changes by position:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [0..123]  identical (124 msgs)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [124]      added    user (+34 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [125]      added    assistant (+971 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [126]      added    tool (+20477 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [127]      added    assistant (+449 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [128]      added    tool (+418 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [129]      added    assistant (+1098 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [130]      added    tool (+382 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [131]      added    assistant (+342 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [132]      added    tool (+327 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [133]      added    assistant (+1061 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [134]      added    tool (+174 chars)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  [135]      added    assistant (+215 chars)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The agent created &lt;a href="https://github.com/dolthub/doltlite/pull/1426"&gt;this PR&lt;/a&gt; which failed CI with a build error on the &lt;code&gt;sqllogictest&lt;/code&gt; job. I made another commit and then asked the agent to fix its build. At this point, the agent was ready for compaction and I hit a bug in our prototype. I have it trying to fix itself now.&lt;/p&gt;
&lt;p&gt;As you can see, this &lt;code&gt;diff&lt;/code&gt; functionality would be very useful for Open Code developers to track the evolution of context, especially under code changes to Open Code.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We’re definitely looking for feedback here. Please try out this harness and tell us what you think. Were the Git features useful? Do you want to see others? As always, you can come chat with us on &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt; or &lt;a href="https://github.com/dolthub/opencode/issues"&gt;create a GitHub issue&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>dolt</category>
      <category>ai</category>
    </item>
    <item>
      <title>How Fast Is DoltLite?</title>
      <link>https://dolthub.com/blog/2026-06-08-how-fast-is-doltlite/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-08-how-fast-is-doltlite/</guid>
      <description>DoltLite replaces SQLite's B-tree interface with a Prolly tree, so we can finally have a fair B-tree vs Prolly Tree race. How do the two data structures compare on sysbench using SQLite's SQL engine?</description>
      <pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;A couple months ago, we released &lt;a href="https://github.com/dolthub/doltlite"&gt;DoltLite&lt;/a&gt;, a free open-source drop-in replacement for &lt;a href="https://sqlite.org"&gt;SQLite&lt;/a&gt; with &lt;a href="https://github.com/dolthub/dolt"&gt;Dolt&lt;/a&gt;-style version control features. DoltLite works by ripping out SQLite’s B-Tree storage engine and replacing it with a content-addressed &lt;a href="https://docs.dolthub.com/architecture/storage-engine/prolly-tree"&gt;Prolly Tree&lt;/a&gt;, the same data structure that powers Dolt.&lt;/p&gt;
&lt;p&gt;We’ve been benchmarking Dolt against MySQL &lt;a href="https://www.dolthub.com/blog/2020-10-11-benchmarking-dolt-with-sysbench/"&gt;for years using &lt;code&gt;sysbench&lt;/code&gt;&lt;/a&gt;. Recently, &lt;a href="https://www.dolthub.com/blog/2026-01-06-more-read-performance-wins/"&gt;Dolt got faster than MySQL&lt;/a&gt; on &lt;code&gt;sysbench&lt;/code&gt;. But, Dolt and MySQL are completely separate SQL engines. Most of the performance difference comes from the SQL engine, not the B-tree vs Prolly Tree difference. “How much?”, you ask. It was hard to tell.&lt;/p&gt;
&lt;p&gt;Until now. DoltLite is SQLite from the B-tree interface up, in other words, the same SQL engine. The only difference between DoltLite and SQLite is B-tree versus Prolly Tree, a true performance bake off. We can finally answer the question “What’s the Prolly Tree performance tax?” This article does just that.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dolthub/doltlite"&gt;&lt;img src="https://static.dolthub.com/blogimages/doltlite-logo.png/187cf16f99ea27a3199258d56892a3869221f9c9af529beeaffba3990bfc3f47.webp" alt="DoltLite Logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="the-prolly-tree-tax"&gt;The Prolly Tree Tax&lt;a class="anchor-link" aria-label="Link to heading" href="#the-prolly-tree-tax"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Here’s the whole article in one table. Same SQL engine on both sides, so every number below is purely the Prolly Tree versus SQLite’s B-tree, nothing else. We run in memory to keep it a clean race, with no disk or page cache to muddy the result. The one exception is autocommit writes, which only mean anything on disk, since committing is a durability cost. Lower is better for DoltLite:&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Workload&lt;/th&gt;&lt;th&gt;Prolly Tree tax&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Reads&lt;/td&gt;&lt;td&gt;1.20x — a 20% tax&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Batched writes&lt;/td&gt;&lt;td&gt;1.67x — a 67% tax&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Autocommit writes&lt;/td&gt;&lt;td&gt;4.00x — the real tax lives here&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The Prolly Tree tax is modest on reads, noticeable on batched writes, and only really bites when you commit every single write. And on that last one you usually have an out: batch your writes in a transaction.&lt;/p&gt;
&lt;h1 id="a-true-bake-off"&gt;A True Bake-Off&lt;a class="anchor-link" aria-label="Link to heading" href="#a-true-bake-off"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;DoltLite is a drop-in replacement for SQLite, and that’s exactly what makes this measurement clean. Everything from the B-tree interface up — the parser, the planner, the whole SQL engine — is line-for-line SQLite. The only thing we
changed is the storage engine underneath. So when we run the identical SQL through both and compare, the difference is the Prolly Tree tax, isolated. No SQL-engine variable muddying the result the way there is when we benchmark Dolt against MySQL.&lt;/p&gt;
&lt;p&gt;To isolate the data structure even further, the numbers in this article are from in-memory databases. That strips out the disk and the page cache, leaving the raw cost of walking and updating a Prolly Tree instead of a B-tree.&lt;/p&gt;
&lt;p&gt;We build stock SQLite straight out of the same source tree (&lt;code&gt;make DOLTLITE_PROLLY=0 sqlite3&lt;/code&gt;) and run a &lt;a href="https://github.com/dolthub/doltlite/blob/main/test/sysbench_compare.sh"&gt;sysbench-style OLTP suite&lt;/a&gt; against both on every PR: 100,000-row tables, the median of 5 invocations per test (9 for autocommit writes), workload-only timing off a monotonic clock. CI enforces a hard ceiling: 2.5x on any individual test, 2x on a section average. The build goes red if we regress performance. We run the whole thing four times with different key types: integer, text, blob, and composite.&lt;/p&gt;
&lt;p&gt;The full table gets posted as a comment on &lt;a href="https://github.com/dolthub/doltlite/pull/1270"&gt;every PR&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="reads"&gt;Reads&lt;a class="anchor-link" aria-label="Link to heading" href="#reads"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In memory, reads cost about 20% more than SQLite:&lt;/p&gt;











































































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Test&lt;/th&gt;&lt;th align="right"&gt;SQLite (us)&lt;/th&gt;&lt;th align="right"&gt;DoltLite (us)&lt;/th&gt;&lt;th align="right"&gt;Multiplier&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;oltp_point_select&lt;/td&gt;&lt;td align="right"&gt;23,710&lt;/td&gt;&lt;td align="right"&gt;29,457&lt;/td&gt;&lt;td align="right"&gt;1.24&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_range_select&lt;/td&gt;&lt;td align="right"&gt;10,124&lt;/td&gt;&lt;td align="right"&gt;11,930&lt;/td&gt;&lt;td align="right"&gt;1.18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_sum_range&lt;/td&gt;&lt;td align="right"&gt;9,490&lt;/td&gt;&lt;td align="right"&gt;11,938&lt;/td&gt;&lt;td align="right"&gt;1.26&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_order_range&lt;/td&gt;&lt;td align="right"&gt;2,572&lt;/td&gt;&lt;td align="right"&gt;2,953&lt;/td&gt;&lt;td align="right"&gt;1.15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_distinct_range&lt;/td&gt;&lt;td align="right"&gt;3,628&lt;/td&gt;&lt;td align="right"&gt;4,013&lt;/td&gt;&lt;td align="right"&gt;1.11&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_index_scan&lt;/td&gt;&lt;td align="right"&gt;3,951&lt;/td&gt;&lt;td align="right"&gt;5,275&lt;/td&gt;&lt;td align="right"&gt;1.34&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_points&lt;/td&gt;&lt;td align="right"&gt;10,245&lt;/td&gt;&lt;td align="right"&gt;11,268&lt;/td&gt;&lt;td align="right"&gt;1.10&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;select_random_ranges&lt;/td&gt;&lt;td align="right"&gt;2,979&lt;/td&gt;&lt;td align="right"&gt;4,117&lt;/td&gt;&lt;td align="right"&gt;1.38&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;covering_index_scan&lt;/td&gt;&lt;td align="right"&gt;4,124&lt;/td&gt;&lt;td align="right"&gt;4,380&lt;/td&gt;&lt;td align="right"&gt;1.06&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;groupby_scan&lt;/td&gt;&lt;td align="right"&gt;30,945&lt;/td&gt;&lt;td align="right"&gt;33,884&lt;/td&gt;&lt;td align="right"&gt;1.09&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join&lt;/td&gt;&lt;td align="right"&gt;6,005&lt;/td&gt;&lt;td align="right"&gt;8,159&lt;/td&gt;&lt;td align="right"&gt;1.36&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;index_join_scan&lt;/td&gt;&lt;td align="right"&gt;3,396&lt;/td&gt;&lt;td align="right"&gt;4,597&lt;/td&gt;&lt;td align="right"&gt;1.35&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_table_scan&lt;/td&gt;&lt;td align="right"&gt;1,057,625&lt;/td&gt;&lt;td align="right"&gt;1,218,914&lt;/td&gt;&lt;td align="right"&gt;1.15&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;table_scan&lt;/td&gt;&lt;td align="right"&gt;1,233,810&lt;/td&gt;&lt;td align="right"&gt;1,304,540&lt;/td&gt;&lt;td align="right"&gt;1.06&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_only&lt;/td&gt;&lt;td align="right"&gt;102,177&lt;/td&gt;&lt;td align="right"&gt;120,120&lt;/td&gt;&lt;td align="right"&gt;1.18&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Average&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;1.20&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Why 20%? A Prolly Tree node is content-addressed, so every step down the tree is a hash lookup in the chunk cache plus a decode of the node’s packed key/value layout, where SQLite’s B-tree just follows a page pointer. That extra indirection is the tax.&lt;/p&gt;
&lt;h1 id="batched-writes"&gt;Batched Writes&lt;a class="anchor-link" aria-label="Link to heading" href="#batched-writes"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Batched into a transaction, writes cost about 67% more in memory:&lt;/p&gt;

































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Test&lt;/th&gt;&lt;th align="right"&gt;SQLite (us)&lt;/th&gt;&lt;th align="right"&gt;DoltLite (us)&lt;/th&gt;&lt;th align="right"&gt;Multiplier&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;oltp_bulk_insert&lt;/td&gt;&lt;td align="right"&gt;181,919&lt;/td&gt;&lt;td align="right"&gt;253,557&lt;/td&gt;&lt;td align="right"&gt;1.39&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_insert&lt;/td&gt;&lt;td align="right"&gt;15,472&lt;/td&gt;&lt;td align="right"&gt;27,785&lt;/td&gt;&lt;td align="right"&gt;1.80&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_index&lt;/td&gt;&lt;td align="right"&gt;51,887&lt;/td&gt;&lt;td align="right"&gt;89,758&lt;/td&gt;&lt;td align="right"&gt;1.73&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_non_index&lt;/td&gt;&lt;td align="right"&gt;34,388&lt;/td&gt;&lt;td align="right"&gt;59,641&lt;/td&gt;&lt;td align="right"&gt;1.73&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_delete_insert&lt;/td&gt;&lt;td align="right"&gt;46,005&lt;/td&gt;&lt;td align="right"&gt;71,917&lt;/td&gt;&lt;td align="right"&gt;1.56&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_write_only&lt;/td&gt;&lt;td align="right"&gt;22,530&lt;/td&gt;&lt;td align="right"&gt;44,628&lt;/td&gt;&lt;td align="right"&gt;1.98&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_delete_insert&lt;/td&gt;&lt;td align="right"&gt;24,611&lt;/td&gt;&lt;td align="right"&gt;40,401&lt;/td&gt;&lt;td align="right"&gt;1.64&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_write&lt;/td&gt;&lt;td align="right"&gt;72,397&lt;/td&gt;&lt;td align="right"&gt;108,598&lt;/td&gt;&lt;td align="right"&gt;1.50&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Average&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;1.67&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A 67% tax to get full history, branching, diff, and merge on your data. Sounds like a good trade to me.&lt;/p&gt;
&lt;p&gt;Writes cost more than reads because a Prolly Tree is immutable. Changing one row can’t overwrite a node in place the way a B-tree does. It re-hashes that node and every node above it up to the root, allocating new content-addressed chunks along the way. That’s more work per write, even inside a single transaction. The flip side is that the very same immutability is what buys you cheap branching and content-addressed diffs.&lt;/p&gt;
&lt;h1 id="autocommit-writes"&gt;Autocommit Writes&lt;a class="anchor-link" aria-label="Link to heading" href="#autocommit-writes"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It was going so well. Committing every write is where the Prolly Tree performance story gets a little gnarly. This is the one section measured on disk: a commit is a durable write, so it only means anything with a real file behind it.&lt;/p&gt;

































































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Test&lt;/th&gt;&lt;th align="right"&gt;SQLite (us)&lt;/th&gt;&lt;th align="right"&gt;DoltLite (us)&lt;/th&gt;&lt;th align="right"&gt;Multiplier&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;oltp_bulk_insert_ac&lt;/td&gt;&lt;td align="right"&gt;20,541&lt;/td&gt;&lt;td align="right"&gt;75,772&lt;/td&gt;&lt;td align="right"&gt;3.69&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_insert_ac&lt;/td&gt;&lt;td align="right"&gt;23,297&lt;/td&gt;&lt;td align="right"&gt;91,726&lt;/td&gt;&lt;td align="right"&gt;3.94&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_index_ac&lt;/td&gt;&lt;td align="right"&gt;26,183&lt;/td&gt;&lt;td align="right"&gt;104,527&lt;/td&gt;&lt;td align="right"&gt;3.99&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_update_non_index_ac&lt;/td&gt;&lt;td align="right"&gt;21,466&lt;/td&gt;&lt;td align="right"&gt;86,763&lt;/td&gt;&lt;td align="right"&gt;4.04&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_delete_insert_ac&lt;/td&gt;&lt;td align="right"&gt;22,961&lt;/td&gt;&lt;td align="right"&gt;96,960&lt;/td&gt;&lt;td align="right"&gt;4.22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_write_only_ac&lt;/td&gt;&lt;td align="right"&gt;23,384&lt;/td&gt;&lt;td align="right"&gt;95,285&lt;/td&gt;&lt;td align="right"&gt;4.07&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;types_delete_insert_ac&lt;/td&gt;&lt;td align="right"&gt;20,889&lt;/td&gt;&lt;td align="right"&gt;93,985&lt;/td&gt;&lt;td align="right"&gt;4.50&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;oltp_read_write_ac&lt;/td&gt;&lt;td align="right"&gt;29,065&lt;/td&gt;&lt;td align="right"&gt;103,041&lt;/td&gt;&lt;td align="right"&gt;3.55&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Average&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;&lt;/td&gt;&lt;td align="right"&gt;4.00&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;About 4x. This is structural, not a bug. Every commit in a Prolly Tree re-hashes the path from the changed leaf up to the root and writes new immutable, content-addressed chunks. That cost is O(log n) in the tree’s depth, but with a bigger constant than SQLite, so it grows as tables get bigger. Back when &lt;a href="https://github.com/dolthub/doltlite/pull/1000"&gt;we ran the suite at 10,000-row tables&lt;/a&gt;, autocommit writes were comfortably under 2x, versus the 4x you see here at 100,000 rows. SQLite just mutates a page in place and shifts the index if necessary.&lt;/p&gt;
&lt;p&gt;Moreover, DoltLite’s content-addressed store must update more physical locations on disk as well as the manifest and the branch HEADs. This just adds to the performance overhead.&lt;/p&gt;
&lt;h1 id="keep-doltlite-fast"&gt;Keep DoltLite Fast&lt;a class="anchor-link" aria-label="Link to heading" href="#keep-doltlite-fast"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;sysbench&lt;/code&gt; metrics suggest two pieces of DoltLite performance advice.&lt;/p&gt;
&lt;h2 id="batch-writes"&gt;Batch Writes&lt;a class="anchor-link" aria-label="Link to heading" href="#batch-writes"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The autocommit write fix is the same advice you’d get for stock SQLite: batch your writes.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sql"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;BEGIN&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;-- thousands of inserts here&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;COMMIT&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those same operations get much cheaper the moment you wrap them. Batching amortizes the per-commit re-hashing across thousands of rows, which is exactly why the batched-writes tax (1.67x) is so much smaller than the autocommit one (4x).&lt;/p&gt;
&lt;p&gt;Let’s keep the 4x in perspective. That autocommit test is 200 separate committed inserts, ~25ms total in SQLite versus ~100ms in DoltLite. Per write, that’s about 0.125ms versus 0.5ms, both faster than a single frame of video. Unless you’re committing one row at a time in a loop, you will never feel it. So go ahead and use &lt;code&gt;autocommit&lt;/code&gt; if it’s easier. For most applications the tax simply won’t matter.&lt;/p&gt;
&lt;h1 id="use-integer-keys"&gt;Use Integer Keys&lt;a class="anchor-link" aria-label="Link to heading" href="#use-integer-keys"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We run everything with a few different primary key types to see what, say, UUID-shaped keys cost. In memory, text keys push reads to about 1.5x and batched writes to about 1.9x, with range scans climbing toward 2.3x. The takeaway: if you care about speed, integer primary keys are the fast path. UUIDs work, they just cost more.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;So what’s the Prolly Tree tax? For years we could only guess. Dolt is faster than MySQL, but they’re different
SQL engines, so the storage layer’s contribution was buried. DoltLite finally lets us measure it in isolation. The Prolly Tree tax is about 20% on reads, 67% on batched writes, and 4x on single-row autocommit writes. Just like my beloved California, the taxes are worth it. In California, you get the weather. With DoltLite, you get the version control.&lt;/p&gt;
&lt;p&gt;Packing your bags and joining the DoltLite gold rush? Come by &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt;, and we’ll give you a warm welcome in the #doltlite🪶 channel.&lt;/p&gt;</content:encoded>
      <dc:creator>Tim Sehn</dc:creator>
      <category>doltlite</category>
      <category>performance</category>
    </item>
    <item>
      <title>Announcing Dumbo Garbage Collection</title>
      <link>https://dolthub.com/blog/2026-06-02-dumbodb-gc/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-06-02-dumbodb-gc/</guid>
      <description>MongoDB and Git had a baby, and it's named Dumbo. The latest release has garbage collection!</description>
      <pubDate>Tue, 02 Jun 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/dumbo-logo.png/c02da7b39168585c4dc1adf3ebf6ffe77404dd9b8fc5a35f6dc765bb9dea9e16.webp" alt="DumboDB Logo"&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/dolthub/dumbodb"&gt;DumboDB&lt;/a&gt; is a document database inspired by &lt;a href="https://github.com/mongodb/mongo"&gt;MongoDB&lt;/a&gt;, built on top of &lt;a href="https://github.com/dolthub/dolt"&gt;Dolt’s storage&lt;/a&gt;. DumboDB combines the flexibility of a document database with the power of Git-like version control, allowing you to track changes, branch, and merge your data with ease.&lt;/p&gt;
&lt;p&gt;It’s early days for DumboDB, but thanks to leveraging Dolt’s underlying architecture, we’re able to rapidly iterate and add new features. In &lt;a href="https://github.com/dolthub/dumbodb/releases/tag/v0.1.3"&gt;release 0.1.3&lt;/a&gt;, we’re excited to announce the addition of garbage collection (GC) to DumboDB!&lt;/p&gt;
&lt;h2 id="what-is-garbage-collection"&gt;What is Garbage Collection?&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-garbage-collection"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In many databases, as you update your data on disk, old versions of your data will accumulate over time. Cleaning up this data goes by many names. In PostgreSQL, it’s called &lt;a href="https://www.postgresql.org/docs/current/sql-vacuum.html"&gt;VACUUM&lt;/a&gt;. In MySQL, it’s called &lt;a href="https://dev.mysql.com/doc/refman/9.7/en/innodb-purge-configuration.html"&gt;purging&lt;/a&gt;. In Dolt, it’s called &lt;a href="https://www.dolthub.com/docs/sql-reference/server/garbage-collection/"&gt;garbage collection&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In traditional databases, it makes sense that garbage would exist. When you update a row in a table, the old version of that row is still on disk until the database decides to clean it up.&lt;/p&gt;
&lt;p&gt;Dolt and Dumbo are version-controlled databases, so it’s reasonable to assume we store every version of the data forever. Unfortunately, it’s not that simple. Dolt and Dumbo keep track of all &lt;em&gt;committed&lt;/em&gt; data, specifically data that has been committed to the database and is part of the commit history.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/how-garbage-is-created.png/c719463f830464444cce6a285c5a4125cc88710480ad62d28a3108f60a25739b.webp" alt="how garbage is created"&gt;&lt;/p&gt;
&lt;p&gt;In scenarios where you insert or update many documents, there are intermediate versions of the data that are not committed to the commit history. These intermediate versions take up disk space and may not be necessary to keep around indefinitely. This is where garbage collection comes in.&lt;/p&gt;
&lt;h2 id="how-does-dumbos-garbage-collection-work"&gt;How Does Dumbo’s Garbage Collection Work?&lt;a class="anchor-link" aria-label="Link to heading" href="#how-does-dumbos-garbage-collection-work"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The short answer is that it’s just like &lt;a href="https://www.dolthub.com/blog/2025-03-21-session-aware-gc-technical-details/"&gt;Dolt’s Session Aware GC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I won’t go into that level of detail here, but at a high level, every chunk of data in a Dolt (and Dumbo) database must be reachable from the commit history of all branches. We build a list of all chunks in the database, then walk the commit history to find all chunks that are reachable from commits. Any chunks that are not reachable from the commit history are considered garbage and can be safely deleted.&lt;/p&gt;
&lt;p&gt;This becomes more complicated when you consider that there may be active sessions in the database that are still using some of the intermediate versions of the data. We don’t want to delete any chunks that are still being used by active sessions, so we need to keep track of those as well.&lt;/p&gt;
&lt;p&gt;Dolt’s GC process takes this into account by keeping track of the active sessions and ensuring that any chunks that are still being used by those sessions are not deleted during the GC process. This allows us to safely clean up any garbage data without affecting any active operations in the database.&lt;/p&gt;
&lt;p&gt;DumboDB uses the same storage engine as Dolt, so we were able to leverage the existing GC implementation in Dolt to add GC support to DumboDB. This means that DumboDB can now automatically clean up any garbage data that may be taking up space on disk, without affecting any active sessions or operations in the database.&lt;/p&gt;
&lt;h2 id="using-garbage-collection-in-dumbodb"&gt;Using Garbage Collection in DumboDB&lt;a class="anchor-link" aria-label="Link to heading" href="#using-garbage-collection-in-dumbodb"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Garbage collection has been added in the &lt;a href="https://github.com/dolthub/dumbodb/releases/tag/v0.1.3"&gt;latest release&lt;/a&gt; of DumboDB.&lt;/p&gt;
&lt;p&gt;Be sure that the &lt;code&gt;mongo&lt;/code&gt; driver is installed for Python:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;pip&lt;/span&gt;&lt;span&gt; install&lt;/span&gt;&lt;span&gt; pymongo&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then create a script that creates a bunch of garbage chunks. Put this text in a file called &lt;code&gt;make_garbage.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="python"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; random&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; secrets&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; pymongo &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; MongoClient&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; MongoClient(&lt;/span&gt;&lt;span&gt;"mongodb://127.0.0.1:27017"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;db &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; client[&lt;/span&gt;&lt;span&gt;"gcdemo"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;coll &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; db[&lt;/span&gt;&lt;span&gt;"items"&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;for&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    docs &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        docs.append({&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "_id"&lt;/span&gt;&lt;span&gt;:   &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"b&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;secrets.token_hex(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "name"&lt;/span&gt;&lt;span&gt;:  &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"user-&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;secrets.token_hex(&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "email"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;secrets.token_hex(&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;@example.com"&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "age"&lt;/span&gt;&lt;span&gt;:   random.randint(&lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;80&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;            "score"&lt;/span&gt;&lt;span&gt;: random.random() &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; 100&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;        })&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    coll.insert_many(docs)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    db.command({&lt;/span&gt;&lt;span&gt;"dumboCommit"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;"message"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"batch &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;"author"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;"gcdemo &amp;#x3C;gcdemo@example.com&gt;"&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;"batch &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;b &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 1}&lt;/span&gt;&lt;span&gt;/50 committed"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This script creates 50 commits, each with 100 new random documents. As a result, it creates a lot of intermediate data versions that are not committed to the commit history and are therefore considered garbage. Run the script:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; python&lt;/span&gt;&lt;span&gt; make_garbage.py&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 1/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 2/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;[... snip ...]&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 49/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;batch&lt;/span&gt;&lt;span&gt; 50/50&lt;/span&gt;&lt;span&gt; committed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In another file, &lt;code&gt;run_gc.py&lt;/code&gt;, add the following code to trigger the GC process:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="python"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; pprint &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; pprint&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; pymongo &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; MongoClient&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; MongoClient(&lt;/span&gt;&lt;span&gt;"mongodb://127.0.0.1:27017"&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;res &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; client[&lt;/span&gt;&lt;span&gt;"gcdemo"&lt;/span&gt;&lt;span&gt;].command({&lt;/span&gt;&lt;span&gt;"dumboGC"&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;pprint(&lt;/span&gt;&lt;span&gt;dict&lt;/span&gt;&lt;span&gt;(res))&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;client.close()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you run this script, it will trigger the GC process in DumboDB and print out the results:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="sh"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; python&lt;/span&gt;&lt;span&gt; run_gc.py&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;'chunksAfter'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 6608.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'chunksBefore'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 7119.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'db'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 'gcdemo',&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'durationMs'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 163.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'mode'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 'default',&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'ok'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 1.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'sizeAfter'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 5929327.0,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 'sizeBefore'&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 7452156.0&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command returns statistics about the number of chunks before and after the GC process, the database size before and after, and how long the GC process took to run.&lt;/p&gt;
&lt;h2 id="comparison-to-dolt"&gt;Comparison to Dolt&lt;a class="anchor-link" aria-label="Link to heading" href="#comparison-to-dolt"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the reasons I wanted to add GC to DumboDB is to see how Dumbo’s storage usage compares to Dolt’s. I added &lt;a href="https://github.com/dolthub/dumbodb-parity-testing/pull/14"&gt;parity tests&lt;/a&gt; to generate equivalent data in both Dolt and Dumbo, then ran GC on both databases to see how much space was used for each.&lt;/p&gt;
&lt;p&gt;The results aren’t fantastic, I’m not gonna lie. There is clearly something amiss. When storing about 1M documents, Dumbo is using about 6x the amount of space after GC compared to Dolt.&lt;/p&gt;
&lt;p&gt;It’s not clear yet if this is the result of a bug in how Dumbo stores data or if we are being too conservative when we garbage collect. As we &lt;a href="https://www.dolthub.com/blog/2026-05-19-dumbodb-01-performance/"&gt;discussed in a previous post&lt;/a&gt;, this kind of side-by-side comparison is one of the main ways we can verify that a vibe-coded product such as Dumbo is working correctly. My gut says that we should have collected more data in our example and we are being too conservative. We will be investigating this issue in the coming weeks and will share our findings in a future blog post.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What’s Next?&lt;a class="anchor-link" aria-label="Link to heading" href="#whats-next"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sorting out the storage discrepancy just mentioned is the top priority. After we sort that out, automatic garbage collection is the next step. Similar to Dolt, when the server determines that there is a reasonable amount of garbage data that can be cleaned up, it will automatically trigger the GC process. This will help ensure that your DumboDB instance stays clean and efficient without requiring manual intervention.&lt;/p&gt;
&lt;p&gt;Want to learn more about Dolt and Dumbo? Hop on our &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Discord&lt;/a&gt; to ask questions and nerd out about version-controlled databases!&lt;/p&gt;</content:encoded>
      <dc:creator>Neil Macneale</dc:creator>
      <category>dumbo</category>
      <category>feature release</category>
    </item>
    <item>
      <title>Evolving with Beads</title>
      <link>https://dolthub.com/blog/2026-05-29-evolving-with-beads/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-29-evolving-with-beads/</guid>
      <description>A guide to evolving your Beads setup from classic single-agent mode to server and shared-server modes for multi-agent workflows, with a bonus look at the global Beads database.</description>
      <pubDate>Fri, 29 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;&lt;a href="https://github.com/gastownhall/beads"&gt;Beads&lt;/a&gt; is a tool for extending the memory of coding agents, such as &lt;a href="https://claude.com/product/claude-code"&gt;Claude Code&lt;/a&gt;, allowing them to manage tasks (i.e. beads) themselves. It was originally built by &lt;a href="https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a"&gt;Steve Yegge&lt;/a&gt; and is now part of &lt;a href="https://gastownhall.ai/"&gt;Gaslandia&lt;/a&gt;, which comprises of Beads, Gastown, Gas City, and Wasteland. Beads is backed by Dolt, and version &lt;a href="https://github.com/gastownhall/beads/releases/tag/v1.0.5"&gt;v1.0.5&lt;/a&gt; is available now.&lt;/p&gt;
&lt;p&gt;In today’s blog, I’ll cover a common question we’ve seen from Beads users about how to evolve with the tool: “I’ve been using Beads classic and want to know how to move to server mode, when should I do that, and how do I do that?” I’ll answer this by migrating from the most simple, “classic”, single-agent mode to the server and shared-server modes that better support multi-agent workflows.&lt;/p&gt;
&lt;h1 id="beads-classic"&gt;Beads Classic&lt;a class="anchor-link" aria-label="Link to heading" href="#beads-classic"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Most Beads users use the “classic” mode of Beads, which provides a coding-agent persistent memory and an interface for self-managing it. In this example, I have the latest Dolt installed, &lt;a href="https://github.com/dolthub/dolt/releases/tag/v2.0.8"&gt;v2.0.8&lt;/a&gt;, and will make a new Git project where my coding agent will work.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;dolt&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;span&gt; 2.0.8&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; mkdir&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; cd&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; echo&lt;/span&gt;&lt;span&gt; "# evolving_demo"&lt;/span&gt;&lt;span&gt; &gt;&gt;&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Initialized&lt;/span&gt;&lt;span&gt; empty&lt;/span&gt;&lt;span&gt; Git&lt;/span&gt;&lt;span&gt; repository&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.git/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; commit&lt;/span&gt;&lt;span&gt; -m&lt;/span&gt;&lt;span&gt; 'README.md'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;[main (root&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;commit) 9dffb6e] README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span&gt; changed,&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; insertion&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; 100644&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; remote&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enumerating&lt;/span&gt;&lt;span&gt; objects:&lt;/span&gt;&lt;span&gt; 3,&lt;/span&gt;&lt;span&gt; done.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Counting&lt;/span&gt;&lt;span&gt; objects:&lt;/span&gt;&lt;span&gt; 100%&lt;/span&gt;&lt;span&gt; (3/3), done.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Writing&lt;/span&gt;&lt;span&gt; objects:&lt;/span&gt;&lt;span&gt; 100%&lt;/span&gt;&lt;span&gt; (3/3), 250 bytes &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; 250.00&lt;/span&gt;&lt;span&gt; KiB/s,&lt;/span&gt;&lt;span&gt; done.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt; (delta &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;), reused 0 (&lt;/span&gt;&lt;span&gt;delta&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;), pack-reused 0 (&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;To&lt;/span&gt;&lt;span&gt; https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; [new &lt;/span&gt;&lt;span&gt;branch]&lt;/span&gt;&lt;span&gt;      main&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’ve initialized my git project and pushed it to GitHub as well. Next, I also have the latest version of Beads installed, and I can run &lt;code&gt;bd init&lt;/code&gt; to initialize the project with everything my agent will need to use Beads successfully.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; version&lt;/span&gt;&lt;span&gt; 1.0.5&lt;/span&gt;&lt;span&gt; (dev: &lt;/span&gt;&lt;span&gt;801fb95d1767&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Configured&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; →&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 76062c1e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 642acc6d98a2785e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; AGENTS.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Registered&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;span&gt; hook&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;⚠&lt;/span&gt;&lt;span&gt; Git&lt;/span&gt;&lt;span&gt; upstream&lt;/span&gt;&lt;span&gt; not&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  For&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; workflows,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; upstream&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  git&lt;/span&gt;&lt;span&gt; remote&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; upstream&lt;/span&gt;&lt;span&gt; &amp;#x3C;&lt;/span&gt;&lt;span&gt;repo-ur&lt;/span&gt;&lt;span&gt;l&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; successfully!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; embedded&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; evolving_demo-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;evolving_demo-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importantly, always choose the role ‘maintainer’ and choose ‘no’ for auto-export.&lt;/p&gt;
&lt;p&gt;Contributor mode is outside the scope of this blog, and auto-export is a legacy feature.&lt;/p&gt;
&lt;p&gt;After Beads is initialized in my repo, I can create a sample bead to test it out before my agent takes over.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "my first bead"&lt;/span&gt;&lt;span&gt; -t&lt;/span&gt;&lt;span&gt; task&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;💡&lt;/span&gt;&lt;span&gt; Tip:&lt;/span&gt;&lt;span&gt; Install&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; plugin&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; automatic&lt;/span&gt;&lt;span&gt; workflow&lt;/span&gt;&lt;span&gt; context,&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; 'bd setup claude'&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; CLI-only&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I’ll delete this sample issue and turn things over to Claude to start working.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; delete&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Deleted&lt;/span&gt;&lt;span&gt; evolving_demo-0v4&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Removed&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; dependency&lt;/span&gt;&lt;span&gt; link&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Updated&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span&gt; references&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; issue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Starting my agent in the repo brings it up with all the context it needs to use Beads on its own, so I can just talk to the agent normally, and it will get to work.&lt;/p&gt;
&lt;p&gt;In this example I’ve asked it to write me a news fetching application, and when Claude starts working, I can see what it’s doing in the &lt;code&gt;bd list&lt;/code&gt; output.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-2wo&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Unit&lt;/span&gt;&lt;span&gt; test&lt;/span&gt;&lt;span&gt; RSS&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; httptest&lt;/span&gt;&lt;span&gt; fixture&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-gby&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Implement&lt;/span&gt;&lt;span&gt; output&lt;/span&gt;&lt;span&gt; formatters&lt;/span&gt;&lt;span&gt; (text &lt;/span&gt;&lt;span&gt;and&lt;/span&gt;&lt;span&gt; JSON&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;◐&lt;/span&gt;&lt;span&gt; evolving_demo-mlq&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Scaffold&lt;/span&gt;&lt;span&gt; Go&lt;/span&gt;&lt;span&gt; module&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; CLI&lt;/span&gt;&lt;span&gt; entry&lt;/span&gt;&lt;span&gt; point&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-p5d&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Implement&lt;/span&gt;&lt;span&gt; Google&lt;/span&gt;&lt;span&gt; News&lt;/span&gt;&lt;span&gt; RSS&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-y7r&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; Wire&lt;/span&gt;&lt;span&gt; main.go:&lt;/span&gt;&lt;span&gt; client&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; formatter&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; error&lt;/span&gt;&lt;span&gt; handling&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-6ed&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P3&lt;/span&gt;&lt;span&gt; Write&lt;/span&gt;&lt;span&gt; README&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; build&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; usage&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 6&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (5 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When Claude is done, it closes the beads it worked on, and my app is ready to use. But Claude did not know that it can push the beads of this repo up to GitHub too, just like it pushes code, so I let Claude know.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;●&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; as&lt;/span&gt;&lt;span&gt; 9ed3470.&lt;/span&gt;&lt;span&gt; Working&lt;/span&gt;&lt;span&gt; tree&lt;/span&gt;&lt;span&gt; clean,&lt;/span&gt;&lt;span&gt; only&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; gitignored&lt;/span&gt;&lt;span&gt; usnews&lt;/span&gt;&lt;span&gt; binary&lt;/span&gt;&lt;span&gt; remains&lt;/span&gt;&lt;span&gt; untracked.&lt;/span&gt;&lt;span&gt; All&lt;/span&gt;&lt;span&gt; 6&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; closed.&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  remote&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; to.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✻&lt;/span&gt;&lt;span&gt; Baked&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; 25s&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;❯&lt;/span&gt;&lt;span&gt; there&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; try&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;●&lt;/span&gt;&lt;span&gt; Bash&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⎿&lt;/span&gt;&lt;span&gt;  Pushing&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;     Push&lt;/span&gt;&lt;span&gt; complete.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;●&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; pushed.&lt;/span&gt;&lt;span&gt; Now&lt;/span&gt;&lt;span&gt; checking&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; remote.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It actually used to be the case that there was &lt;a href="https://www.dolthub.com/blog/2026-02-19-supporting-git-remotes-as-dolt-remotes/"&gt;nothing visible on GitHub&lt;/a&gt; when using it as a Dolt remote, but we recently added some visual cues to more easily tell that your Git repo has Dolt data.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/git-dolt-remotes-github-visual-1.png/6e8bb4e95424055d1453ec4afb9ada0430b69f499ee4e77f13756ff3ac47f5d4.webp" alt="GitHub Dolt Remote Visualization 1"&gt;&lt;/p&gt;
&lt;p&gt;Git Dolt remotes now also create and push to a branch &lt;code&gt;__dolt_remote_info__&lt;/code&gt;, and this branch will have a file updated on each &lt;code&gt;dolt push&lt;/code&gt; that tells you the ref Dolt is using and its &lt;code&gt;HEAD&lt;/code&gt; sha.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.dolthub.com/blogimages/git-dolt-remotes-github-visual-2.png/1c3874b2ff3c533caf3b5320ee647cd3a1b638ed0f3e49a382bcfe1d8669a418.webp" alt="GitHub Dolt Remote Visualization 2"&gt;&lt;/p&gt;
&lt;p&gt;This is the standard Beads Classic usage pattern and app development style. And the application Claude wrote works great.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;go&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 1.&lt;/span&gt;&lt;span&gt; U.S.,&lt;/span&gt;&lt;span&gt; Iran&lt;/span&gt;&lt;span&gt; nearing&lt;/span&gt;&lt;span&gt; deal&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span&gt; war&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; reopen&lt;/span&gt;&lt;span&gt; Strait&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; Hormuz&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; Washington&lt;/span&gt;&lt;span&gt; Post&lt;/span&gt;&lt;span&gt; (1h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 2.&lt;/span&gt;&lt;span&gt; Judge&lt;/span&gt;&lt;span&gt; halts&lt;/span&gt;&lt;span&gt; Trump&lt;/span&gt;&lt;span&gt; ‘anti-weaponization’&lt;/span&gt;&lt;span&gt; fund&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; Jan.&lt;/span&gt;&lt;span&gt; 6&lt;/span&gt;&lt;span&gt; prosecutor&lt;/span&gt;&lt;span&gt; sues&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; NBC&lt;/span&gt;&lt;span&gt; News&lt;/span&gt;&lt;span&gt; (1h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 3.&lt;/span&gt;&lt;span&gt; Former&lt;/span&gt;&lt;span&gt; AG&lt;/span&gt;&lt;span&gt; Pam&lt;/span&gt;&lt;span&gt; Bondi&lt;/span&gt;&lt;span&gt; testifies&lt;/span&gt;&lt;span&gt; before&lt;/span&gt;&lt;span&gt; Congress&lt;/span&gt;&lt;span&gt; over&lt;/span&gt;&lt;span&gt; handling&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; Epstein&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; NPR&lt;/span&gt;&lt;span&gt; (23m &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 4.&lt;/span&gt;&lt;span&gt; Romania&lt;/span&gt;&lt;span&gt; Says&lt;/span&gt;&lt;span&gt; It&lt;/span&gt;&lt;span&gt; Could&lt;/span&gt;&lt;span&gt; Invoke&lt;/span&gt;&lt;span&gt; NATO’s&lt;/span&gt;&lt;span&gt; Article&lt;/span&gt;&lt;span&gt; 4.&lt;/span&gt;&lt;span&gt; What&lt;/span&gt;&lt;span&gt; Would&lt;/span&gt;&lt;span&gt; That&lt;/span&gt;&lt;span&gt; Do?&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; New&lt;/span&gt;&lt;span&gt; York&lt;/span&gt;&lt;span&gt; Times&lt;/span&gt;&lt;span&gt; (4h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 5.&lt;/span&gt;&lt;span&gt; Kenyan&lt;/span&gt;&lt;span&gt; court&lt;/span&gt;&lt;span&gt; halts&lt;/span&gt;&lt;span&gt; US&lt;/span&gt;&lt;span&gt; plans&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Ebola&lt;/span&gt;&lt;span&gt; quarantine&lt;/span&gt;&lt;span&gt; facility&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; Americans&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; politico.eu&lt;/span&gt;&lt;span&gt; (5h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 6.&lt;/span&gt;&lt;span&gt; Trump&lt;/span&gt;&lt;span&gt; Loses&lt;/span&gt;&lt;span&gt; It&lt;/span&gt;&lt;span&gt; at&lt;/span&gt;&lt;span&gt; Jill&lt;/span&gt;&lt;span&gt; Biden&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; Morning&lt;/span&gt;&lt;span&gt; Rage&lt;/span&gt;&lt;span&gt; Post&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; Daily&lt;/span&gt;&lt;span&gt; Beast&lt;/span&gt;&lt;span&gt; (4h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 7.&lt;/span&gt;&lt;span&gt; Bus&lt;/span&gt;&lt;span&gt; hits&lt;/span&gt;&lt;span&gt; cars&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; Virginia,&lt;/span&gt;&lt;span&gt; killing&lt;/span&gt;&lt;span&gt; 5&lt;/span&gt;&lt;span&gt; people&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; injuring&lt;/span&gt;&lt;span&gt; 34,&lt;/span&gt;&lt;span&gt; state&lt;/span&gt;&lt;span&gt; police&lt;/span&gt;&lt;span&gt; say&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; AP&lt;/span&gt;&lt;span&gt; News&lt;/span&gt;&lt;span&gt; (3h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 8.&lt;/span&gt;&lt;span&gt; California&lt;/span&gt;&lt;span&gt; House&lt;/span&gt;&lt;span&gt; Primary&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; Sacramento&lt;/span&gt;&lt;span&gt; Displays&lt;/span&gt;&lt;span&gt; Democrats’&lt;/span&gt;&lt;span&gt; Fierce&lt;/span&gt;&lt;span&gt; Generational&lt;/span&gt;&lt;span&gt; Battle&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; New&lt;/span&gt;&lt;span&gt; York&lt;/span&gt;&lt;span&gt; Times&lt;/span&gt;&lt;span&gt; (7h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 9.&lt;/span&gt;&lt;span&gt; Mullin&lt;/span&gt;&lt;span&gt; plan&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; punish&lt;/span&gt;&lt;span&gt; sanctuary&lt;/span&gt;&lt;span&gt; jurisdictions&lt;/span&gt;&lt;span&gt; by&lt;/span&gt;&lt;span&gt; targeting&lt;/span&gt;&lt;span&gt; their&lt;/span&gt;&lt;span&gt; airports&lt;/span&gt;&lt;span&gt; faces&lt;/span&gt;&lt;span&gt; fierce&lt;/span&gt;&lt;span&gt; headwinds&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; CNN&lt;/span&gt;&lt;span&gt; (7h &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;10.&lt;/span&gt;&lt;span&gt; In&lt;/span&gt;&lt;span&gt; Carroll&lt;/span&gt;&lt;span&gt; Lawsuits&lt;/span&gt;&lt;span&gt; Inquiry,&lt;/span&gt;&lt;span&gt; Scrutiny&lt;/span&gt;&lt;span&gt; Turns&lt;/span&gt;&lt;span&gt; Toward&lt;/span&gt;&lt;span&gt; Private&lt;/span&gt;&lt;span&gt; Citizens&lt;/span&gt;&lt;span&gt; Who&lt;/span&gt;&lt;span&gt; Antagonized&lt;/span&gt;&lt;span&gt; Trump&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; The&lt;/span&gt;&lt;span&gt; New&lt;/span&gt;&lt;span&gt; York&lt;/span&gt;&lt;span&gt; Times&lt;/span&gt;&lt;span&gt; (51m &lt;/span&gt;&lt;span&gt;ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="server-mode"&gt;Server Mode&lt;a class="anchor-link" aria-label="Link to heading" href="#server-mode"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The next phase of evolving with Beads is transitioning from classic to server mode. Server mode here means Beads will run a local Dolt server on your host, instead of using the non-server embedded Dolt mode, which is the default.&lt;/p&gt;
&lt;p&gt;But why use server mode in the first place?&lt;/p&gt;
&lt;p&gt;The reason users may want to consider running Beads in server mode is because it allows you to run many coding agent sessions against the same Git repo, since server mode is designed for multi-process concurrent use. This is a limitation of Beads classic, which is single-writer.&lt;/p&gt;
&lt;p&gt;To migrate from classic mode to server mode, let’s first make a new bead that we can easily track across the migration from classic to server mode.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "from classic to server mode"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; classic&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, to perform the migration we actually want to take a backup of our Beads database in classic mode, then after we initialize Beads in server mode, we’ll restore from the backup, which will give us our database back.&lt;/p&gt;
&lt;p&gt;To do this I first make a new directory to use as my database backup, then initialize it with the &lt;code&gt;bd backup init&lt;/code&gt; command. After initialization I can run &lt;code&gt;bd backup sync&lt;/code&gt; to sync my database to the backup destination.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; mkdir&lt;/span&gt;&lt;span&gt; ../ed_backup_1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; ../ed_backup_1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; destination&lt;/span&gt;&lt;span&gt; configured:&lt;/span&gt;&lt;span&gt; file:///home/dustin/cursor_src/repros/ed_backup_1&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; 'bd backup sync'&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; data.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; synced&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 20ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the backup synced, I can then remove the &lt;code&gt;.beads&lt;/code&gt; directory in my Git repo, which will delete the classic mode database (or just &lt;code&gt;mv&lt;/code&gt; it to not be named &lt;code&gt;.beads&lt;/code&gt; just in case), and then re-initialize Beads using the &lt;code&gt;--server&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; rm&lt;/span&gt;&lt;span&gt; -rf&lt;/span&gt;&lt;span&gt; .beads&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; --server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Bootstrapped&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Synced&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Bootstrapped&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 76062c1e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 642acc6d98a2785e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Adopted&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; identity&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; existing&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Updated&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; AGENTS.md&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; latest&lt;/span&gt;&lt;span&gt; format&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Hook&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; registered:&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Updated&lt;/span&gt;&lt;span&gt; existing&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; remote!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Server:&lt;/span&gt;&lt;span&gt; root@127.0.0.1:46091&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⚠&lt;/span&gt;&lt;span&gt; Server&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; defaulted&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; 127.0.0.1.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    If&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; BEADS_DOLT_SERVER_HOST&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; pass&lt;/span&gt;&lt;span&gt; --server-host.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; evolving_demo-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;evolving_demo-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As before, I keep my role as ‘maintainer’ and decline auto-export. This time though Beads is using a local server running on port &lt;code&gt;46091&lt;/code&gt;, as shown in the output above.&lt;/p&gt;
&lt;p&gt;Now I can restore from the backup I made earlier to get all my beads back.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; restore&lt;/span&gt;&lt;span&gt; ../ed_backup_1&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Restore&lt;/span&gt;&lt;span&gt; complete&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; classic&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you can see that the bead I made is available and ready. I can also see the “status” of my Beads server by running &lt;code&gt;bd dolt status&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Dolt&lt;/span&gt;&lt;span&gt; server:&lt;/span&gt;&lt;span&gt; running&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  PID:&lt;/span&gt;&lt;span&gt;  778645&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Port:&lt;/span&gt;&lt;span&gt; 46091&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Data:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.beads/dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Logs:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.beads/dolt-server.log&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I wanted to actually poke around in the state of my Beads database, I could do so with a standard MySQL client. As of this blog, Beads servers always run with &lt;code&gt;root&lt;/code&gt; and no password.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; docker&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; --rm&lt;/span&gt;&lt;span&gt; -it&lt;/span&gt;&lt;span&gt; --network&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; mysql:8&lt;/span&gt;&lt;span&gt; mysql&lt;/span&gt;&lt;span&gt; -h&lt;/span&gt;&lt;span&gt; 127.0.0.1&lt;/span&gt;&lt;span&gt; -P&lt;/span&gt;&lt;span&gt; 46091&lt;/span&gt;&lt;span&gt; -u&lt;/span&gt;&lt;span&gt; root&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Welcome&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; MySQL&lt;/span&gt;&lt;span&gt; monitor.&lt;/span&gt;&lt;span&gt;  Commands&lt;/span&gt;&lt;span&gt; end&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; ; &lt;/span&gt;&lt;span&gt;or&lt;/span&gt;&lt;span&gt; \g&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Your&lt;/span&gt;&lt;span&gt; MySQL&lt;/span&gt;&lt;span&gt; connection&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; 27&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Server&lt;/span&gt;&lt;span&gt; version:&lt;/span&gt;&lt;span&gt; 8.0.33&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Copyright&lt;/span&gt;&lt;span&gt; (c) 2000, 2026, Oracle and/or its affiliates.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Oracle&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; registered&lt;/span&gt;&lt;span&gt; trademark&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; Oracle&lt;/span&gt;&lt;span&gt; Corporation&lt;/span&gt;&lt;span&gt; and/or&lt;/span&gt;&lt;span&gt; its&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;affiliates.&lt;/span&gt;&lt;span&gt; Other&lt;/span&gt;&lt;span&gt; names&lt;/span&gt;&lt;span&gt; may&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; trademarks&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; their&lt;/span&gt;&lt;span&gt; respective&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;owners.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Type&lt;/span&gt;&lt;span&gt; 'help;'&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; '\h'&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; help.&lt;/span&gt;&lt;span&gt; Type&lt;/span&gt;&lt;span&gt; '\c'&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; clear&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span&gt; input&lt;/span&gt;&lt;span&gt; statement.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt; databases&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+--------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; Database&lt;/span&gt;&lt;span&gt;           |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+--------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt;               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;span&gt;      |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; information_schema&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; mysql&lt;/span&gt;&lt;span&gt;              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+--------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt; rows&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (0.00 &lt;/span&gt;&lt;span&gt;sec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;use&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Reading&lt;/span&gt;&lt;span&gt; table&lt;/span&gt;&lt;span&gt; information&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; completion&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; table&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; column&lt;/span&gt;&lt;span&gt; names&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;You&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; turn&lt;/span&gt;&lt;span&gt; off&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; feature&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; quicker&lt;/span&gt;&lt;span&gt; startup&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; -A&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Database&lt;/span&gt;&lt;span&gt; changed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;select&lt;/span&gt;&lt;span&gt; count&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; count(*&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;        7&lt;/span&gt;&lt;span&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;+----------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; row&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; (0.00 &lt;/span&gt;&lt;span&gt;sec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;mysql&lt;/span&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;span&gt;exit&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Bye&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our issue count in our restored database has our bead that we tracked across the classic to server migration and the six now closed issues used to build the news application.&lt;/p&gt;
&lt;p&gt;From this point forward, we could continue to use Beads in single-player mode as we did with classic mode, or we could open multiple terminal sessions against this repo and dispatch agents in each in parallel (non-overlapping) feature work.&lt;/p&gt;
&lt;h1 id="shared-server-mode"&gt;Shared-server Mode&lt;a class="anchor-link" aria-label="Link to heading" href="#shared-server-mode"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Lastly, let’s say I’ve been enjoying using Beads on many projects on my host, both in classic mode and server mode, but have noticed that each server mode project spins up a new Dolt sql-server process. Instead of doing this, can Beads run just a single Dolt sql-server for all my projects?&lt;/p&gt;
&lt;p&gt;Why yes it can, and this is the motivation behind shared-server mode. In this mode, Beads will manage a single global Dolt server that can house all Beads for your Git projects on the host, and these Beads will be isolated, so Beads will not leak between projects.&lt;/p&gt;
&lt;p&gt;To migrate from normal &lt;code&gt;--server&lt;/code&gt; mode to &lt;code&gt;--shared-server&lt;/code&gt; mode, we simply need to go through our backup and restore flow we did above, making sure to stop the running &lt;code&gt;--server&lt;/code&gt; mode process before starting the new &lt;code&gt;--shared-server&lt;/code&gt; process. If you have many &lt;code&gt;--server&lt;/code&gt; mode Beads projects on your host, you’ll want to do this for each one.&lt;/p&gt;
&lt;p&gt;To start, let’s remove the old bead we made and make a new one to watch across the migration.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; classic&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; delete&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Deleted&lt;/span&gt;&lt;span&gt; evolving_demo-w1g&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Removed&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; dependency&lt;/span&gt;&lt;span&gt; link&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Updated&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span&gt; references&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; issue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "from server to shared-server"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will need a new backup directory for our existing &lt;code&gt;--server&lt;/code&gt; mode Beads database.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; ../ed_backup_2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; ../ed_backup_2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; destination&lt;/span&gt;&lt;span&gt; configured:&lt;/span&gt;&lt;span&gt; file:///home/dustin/cursor_src/repros/ed_backup_2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; 'bd backup sync'&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; data.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Backup&lt;/span&gt;&lt;span&gt; synced&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 50ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the backup is synced I can stop the &lt;code&gt;--server&lt;/code&gt; mode server with &lt;code&gt;bd dolt stop&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; stop&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Flushed&lt;/span&gt;&lt;span&gt; working&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;before&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; stop&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; stopped.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, like before, I can remove the existing &lt;code&gt;.beads&lt;/code&gt; directory in my Git project and reinitialize Beads with the &lt;code&gt;--shared-server&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; rm&lt;/span&gt;&lt;span&gt; -rf&lt;/span&gt;&lt;span&gt; .beads&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; --shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Bootstrapped&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Shared&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; started&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; beads_global&lt;/span&gt;&lt;span&gt; available&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; schema&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Configured&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote:&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; →&lt;/span&gt;&lt;span&gt; git+https://github.com/coffeegoddd/evolving_demo.git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 76062c1e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; 642acc6d98a2785e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Shared&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; enabled&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  AGENTS.md&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; has&lt;/span&gt;&lt;span&gt; current&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Hook&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; registered:&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Updated&lt;/span&gt;&lt;span&gt; existing&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; section&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/evolving_demo/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; remote!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Server:&lt;/span&gt;&lt;span&gt; root@127.0.0.1:3308&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⚠&lt;/span&gt;&lt;span&gt; Server&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; defaulted&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; 127.0.0.1.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    If&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; BEADS_DOLT_SERVER_HOST&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; pass&lt;/span&gt;&lt;span&gt; --server-host.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; evolving_demo-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;evolving_demo-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the role is ‘maintainer’ and ‘auto-export’ is disabled.&lt;/p&gt;
&lt;p&gt;Now I can restore from my &lt;code&gt;--server&lt;/code&gt; backup.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; backup&lt;/span&gt;&lt;span&gt; restore&lt;/span&gt;&lt;span&gt; ../ed_backup_2&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Restore&lt;/span&gt;&lt;span&gt; complete&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And once I do that, I’m successfully running in Shared-server mode!&lt;/p&gt;
&lt;h1 id="bonus"&gt;Bonus&lt;a class="anchor-link" aria-label="Link to heading" href="#bonus"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;As I mentioned earlier, Beads are scoped to a single Git repository and single Dolt database, so there is currently no way to share beads across projects.&lt;/p&gt;
&lt;p&gt;Except actually, there &lt;em&gt;kinda&lt;/em&gt; is… As a maintainer of Beads I snuck in a unique feature to Beads Shared-server mode which seemed like it needed, but didn’t have a way to share beads across projects.&lt;/p&gt;
&lt;p&gt;In Shared-server mode there is a unique &lt;code&gt;global&lt;/code&gt; beads database that works like a normal Beads database, except it is readable and writeable by all clients of the Shared server. This database is not tied to any specific Git project, so it does not have the same restrictions as ones that are tied to a specific Git project.&lt;/p&gt;
&lt;p&gt;For this reason, if you did need to share beads between projects, you can do so by reading and writing beads with the &lt;code&gt;--global&lt;/code&gt; flag, which will route the &lt;code&gt;bd&lt;/code&gt; command to the global database instead of the project scoped one.&lt;/p&gt;
&lt;p&gt;Here’s an example. First let’s delete the old migration bead we made.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; delete&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;span&gt; --force&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Deleted&lt;/span&gt;&lt;span&gt; evolving_demo-pz8&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Removed&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; dependency&lt;/span&gt;&lt;span&gt; link&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Updated&lt;/span&gt;&lt;span&gt; text&lt;/span&gt;&lt;span&gt; references&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; issue&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we’ll make another Beads project on our host and register it on the shared server by initializing Beads with &lt;code&gt;--shared-server&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ..&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; mkdir&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  repros&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; cd&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Initialized&lt;/span&gt;&lt;span&gt; empty&lt;/span&gt;&lt;span&gt; Git&lt;/span&gt;&lt;span&gt; repository&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/.git/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;echo&lt;/span&gt;&lt;span&gt; "# different project"&lt;/span&gt;&lt;span&gt; &gt;&gt;&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;✗&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; commit&lt;/span&gt;&lt;span&gt; -m&lt;/span&gt;&lt;span&gt; 'README.md'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;[main (root&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;commit) a11c0f1] README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; file&lt;/span&gt;&lt;span&gt; changed,&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; insertion&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; 100644&lt;/span&gt;&lt;span&gt; README.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; init&lt;/span&gt;&lt;span&gt; --shared-server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; beads_global&lt;/span&gt;&lt;span&gt; available&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Global&lt;/span&gt;&lt;span&gt; database&lt;/span&gt;&lt;span&gt; schema&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Repository&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; ad3c7c9e&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Clone&lt;/span&gt;&lt;span&gt; ID:&lt;/span&gt;&lt;span&gt; d9436fdceeb5a843&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Shared&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;span&gt; enabled&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Already&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;span&gt; as:&lt;/span&gt;&lt;span&gt; maintainer&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Change&lt;/span&gt;&lt;span&gt; role?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; can&lt;/span&gt;&lt;span&gt; keep&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; up&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; date&lt;/span&gt;&lt;span&gt; after&lt;/span&gt;&lt;span&gt; write&lt;/span&gt;&lt;span&gt; commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  This&lt;/span&gt;&lt;span&gt; optional&lt;/span&gt;&lt;span&gt; JSONL&lt;/span&gt;&lt;span&gt; export&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; useful&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; viewers&lt;/span&gt;&lt;span&gt; (bv), interchange, and issue-level migration.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Dolt&lt;/span&gt;&lt;span&gt; remotes/backups&lt;/span&gt;&lt;span&gt; handle&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; backup.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Enable&lt;/span&gt;&lt;span&gt; auto-export?&lt;/span&gt;&lt;span&gt; [y/N]: n&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Auto-export&lt;/span&gt;&lt;span&gt; disabled&lt;/span&gt;&lt;span&gt; (enable &lt;/span&gt;&lt;span&gt;later&lt;/span&gt;&lt;span&gt; with:&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; config&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; export.auto&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;span&gt; to:&lt;/span&gt;&lt;span&gt; .beads/hooks/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; AGENTS.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Registered&lt;/span&gt;&lt;span&gt; SessionStart&lt;/span&gt;&lt;span&gt; hook&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; new&lt;/span&gt;&lt;span&gt; CLAUDE.md&lt;/span&gt;&lt;span&gt; with&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/CLAUDE.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; additional&lt;/span&gt;&lt;span&gt; configuration&lt;/span&gt;&lt;span&gt; needed!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; integration&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Settings:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/.claude/settings.json&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Claude&lt;/span&gt;&lt;span&gt; Code&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; changes&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; take&lt;/span&gt;&lt;span&gt; effect.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Beads&lt;/span&gt;&lt;span&gt; agent&lt;/span&gt;&lt;span&gt; skill&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Skill:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/.agents/skills/beads/SKILL.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; native&lt;/span&gt;&lt;span&gt; hooks&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Installing&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt; project...&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; instructions&lt;/span&gt;&lt;span&gt; installed&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  File:&lt;/span&gt;&lt;span&gt; /home/dustin/cursor_src/repros/different_project/AGENTS.md&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Restart&lt;/span&gt;&lt;span&gt; Codex&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; it&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; already&lt;/span&gt;&lt;span&gt; running.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; Committed&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; files&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;⚠&lt;/span&gt;&lt;span&gt; No&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; remote&lt;/span&gt;&lt;span&gt; configured&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; are&lt;/span&gt;&lt;span&gt; stored&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; local&lt;/span&gt;&lt;span&gt; Dolt.&lt;/span&gt;&lt;span&gt; .beads/issues.jsonl&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; an&lt;/span&gt;&lt;span&gt; export,&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  not&lt;/span&gt;&lt;span&gt; cross-machine&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; source&lt;/span&gt;&lt;span&gt; of&lt;/span&gt;&lt;span&gt; truth.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  To&lt;/span&gt;&lt;span&gt; enable&lt;/span&gt;&lt;span&gt; durable&lt;/span&gt;&lt;span&gt; sync,&lt;/span&gt;&lt;span&gt; add&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt; git&lt;/span&gt;&lt;span&gt; origin&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;span&gt; then&lt;/span&gt;&lt;span&gt; run:&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    bd&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;span&gt; push&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; initialized&lt;/span&gt;&lt;span&gt; successfully!&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Backend:&lt;/span&gt;&lt;span&gt; dolt&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Mode:&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Server:&lt;/span&gt;&lt;span&gt; root@127.0.0.1:3308&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  ⚠&lt;/span&gt;&lt;span&gt; Server&lt;/span&gt;&lt;span&gt; host&lt;/span&gt;&lt;span&gt; defaulted&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; 127.0.0.1.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;    If&lt;/span&gt;&lt;span&gt; your&lt;/span&gt;&lt;span&gt; Dolt&lt;/span&gt;&lt;span&gt; server&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;span&gt; remote,&lt;/span&gt;&lt;span&gt; set&lt;/span&gt;&lt;span&gt; BEADS_DOLT_SERVER_HOST&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; pass&lt;/span&gt;&lt;span&gt; --server-host.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Database:&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issue&lt;/span&gt;&lt;span&gt; prefix:&lt;/span&gt;&lt;span&gt; different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Issues&lt;/span&gt;&lt;span&gt; will&lt;/span&gt;&lt;span&gt; be&lt;/span&gt;&lt;span&gt; named:&lt;/span&gt;&lt;span&gt; different_project-&lt;/span&gt;&lt;span&gt;&amp;#x3C;&lt;/span&gt;&lt;span&gt;has&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; (e.g., &lt;/span&gt;&lt;span&gt;different_project-a3f2dd&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Run&lt;/span&gt;&lt;span&gt; bd&lt;/span&gt;&lt;span&gt; quickstart&lt;/span&gt;&lt;span&gt; to&lt;/span&gt;&lt;span&gt; get&lt;/span&gt;&lt;span&gt; started.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we can use the project as normal, and beads will route to their project scoped database.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; "my first different project bead"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; different_project-s9i&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; different&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;💡&lt;/span&gt;&lt;span&gt; Tip:&lt;/span&gt;&lt;span&gt; Install&lt;/span&gt;&lt;span&gt; the&lt;/span&gt;&lt;span&gt; beads&lt;/span&gt;&lt;span&gt; plugin&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; automatic&lt;/span&gt;&lt;span&gt; workflow&lt;/span&gt;&lt;span&gt; context,&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;span&gt; 'bd setup claude'&lt;/span&gt;&lt;span&gt; for&lt;/span&gt;&lt;span&gt; CLI-only&lt;/span&gt;&lt;span&gt; mode&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; different_project-s9i&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; different&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we return to our earlier project which also uses this shared-server, you’ll see that it won’t be able to see the bead created and scoped to &lt;code&gt;different_project&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ../evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Buuuuuuuut, if we go back to &lt;code&gt;different_project&lt;/code&gt; and create a bead using &lt;code&gt;--global&lt;/code&gt;, we’ll create a global bead that all shared-server projects can access.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ../different_project&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; create&lt;/span&gt;&lt;span&gt; --global&lt;/span&gt;&lt;span&gt; "my first global bead"&lt;/span&gt;&lt;span&gt; -p&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; Created&lt;/span&gt;&lt;span&gt; issue:&lt;/span&gt;&lt;span&gt; global-wqk&lt;/span&gt;&lt;span&gt; —&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; global&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Priority:&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  Status:&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the different output of &lt;code&gt;bd list&lt;/code&gt; with and without the &lt;code&gt;--global&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; different_project-s9i&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; different&lt;/span&gt;&lt;span&gt; project&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt; --global&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; global-wqk&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; global&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And similarly, if we return to the previous project we see the scoped beads
versus the global ones, by using the &lt;code&gt;--global&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="bash"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  different_project&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; ../evolving_demo&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;No&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; found.&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;➜&lt;/span&gt;&lt;span&gt;  evolving_demo&lt;/span&gt;&lt;span&gt; git:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;bd&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt; --global&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;○&lt;/span&gt;&lt;span&gt; global-wqk&lt;/span&gt;&lt;span&gt; ●&lt;/span&gt;&lt;span&gt; P2&lt;/span&gt;&lt;span&gt; my&lt;/span&gt;&lt;span&gt; first&lt;/span&gt;&lt;span&gt; global&lt;/span&gt;&lt;span&gt; bead&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Total:&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt; issues&lt;/span&gt;&lt;span&gt; (1 &lt;/span&gt;&lt;span&gt;open,&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; in&lt;/span&gt;&lt;span&gt; progress&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;Status:&lt;/span&gt;&lt;span&gt; ○&lt;/span&gt;&lt;span&gt; open&lt;/span&gt;&lt;span&gt;  ◐&lt;/span&gt;&lt;span&gt; in_progress&lt;/span&gt;&lt;span&gt;  ●&lt;/span&gt;&lt;span&gt; blocked&lt;/span&gt;&lt;span&gt;  ✓&lt;/span&gt;&lt;span&gt; closed&lt;/span&gt;&lt;span&gt;  ❄&lt;/span&gt;&lt;span&gt; deferred&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I hope this helps clarify some common usage patterns for Beads, and we encourage you to give it a try if you haven’t already.&lt;/p&gt;
&lt;p&gt;Also, feel free to join both the &lt;a href="https://discord.gg/xHpUGUzZp2"&gt;Gaslandia Discord&lt;/a&gt; and the &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;Dolt Discord&lt;/a&gt; if you haven’t already. We’d love to chat with you and discuss building for the agentic future.&lt;/p&gt;</content:encoded>
      <dc:creator>Dustin Brown</dc:creator>
      <category>ai</category>
    </item>
    <item>
      <title>How TPC-C Works</title>
      <link>https://dolthub.com/blog/2026-05-14-how-tpcc-works/</link>
      <guid isPermaLink="true">https://dolthub.com/blog/2026-05-14-how-tpcc-works/</guid>
      <description>A detailed description of Dolt's TPC-C benchmarking.</description>
      <pubDate>Thu, 14 May 2026 00:00:00 GMT</pubDate>
      <content:encoded>&lt;p&gt;Dolt is a version-controlled database that works as a drop-in MySQL replacement.
In addition to correctness parity with MySQL, we are also determined to reach performance parity with MySQL.
For years now, we’ve been improving Dolt performance on both Sysbench and TPC-C benchmarks.
Towards the end of 2025, Dolt reached &lt;a href="https://www.dolthub.com/blog/2025-12-04-dolt-is-as-fast-as-mysql/"&gt;parity with MySQL on Sysbench&lt;/a&gt; when averaging reads and writes.
Shortly after, we managed to reach &lt;a href="https://www.dolthub.com/blog/2026-01-06-more-read-performance-wins/"&gt;MySQL parity on both read and writes&lt;/a&gt;.
Now, we &lt;a href="https://dolthub.com/docs/sql-reference/benchmarks/latency"&gt;surpass MySQL on Sysbench reads and writes&lt;/a&gt; with a &lt;code&gt;0.95&lt;/code&gt; reads mean multiplier and &lt;code&gt;0.87&lt;/code&gt; write mean multiplier.&lt;/p&gt;
&lt;p&gt;While we are proud of our accomplishments on Sysbench, TPC-C Benchmarks are arguably more important to the average user experience.
This blog will go into detail about the TPC-C benchmarks and the kinds of queries run against the database.&lt;/p&gt;
&lt;h1 id="what-is-tpc-c"&gt;What is TPC-C&lt;a class="anchor-link" aria-label="Link to heading" href="#what-is-tpc-c"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://www.tpc.org/tpcc/"&gt;TPC-C&lt;/a&gt; stands for Transaction Processing Performance Council Benchmark C.
It is the industry standard benchmark used for OLTP databases.
TPC-C simulates real-world usage of a database by modeling transactions for a wholesale supplier.
Dolt actually uses a slightly modified version of the official TPC-C benchmarks from &lt;a href="https://github.com/Percona-Lab/sysbench-tpcc"&gt;Percona Labs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="settings"&gt;Settings&lt;a class="anchor-link" aria-label="Link to heading" href="#settings"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We run TPC-C with these settings:&lt;/p&gt;
&lt;pre class="astro-code github-dark" tabindex="0" data-language="shell"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span&gt;./tpcc.lua&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --db-driver=&lt;/span&gt;&lt;span&gt;"mysql"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-db=&lt;/span&gt;&lt;span&gt;"sbtest"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-host=&lt;/span&gt;&lt;span&gt;"127.0.0.1"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-port=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;$PORT&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-user=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;$USER&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --mysql-password=&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt;$PASS&lt;/span&gt;&lt;span&gt;"&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --time=800&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --report_interval=10&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --threads=1&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --tables=1&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --scale=1&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class="line"&gt;&lt;span&gt;  --trx_level=&lt;/span&gt;&lt;span&gt;"RR"&lt;/span&gt;&lt;span&gt; run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The benchmarks are run with a single thread for &lt;code&gt;800&lt;/code&gt; seconds with &lt;code&gt;autocommit&lt;/code&gt; and &lt;code&gt;foreign_key_checks&lt;/code&gt; disabled.
&lt;code&gt;trx_level="RR"&lt;/code&gt; is &lt;code&gt;REPEATABLE_READ&lt;/code&gt; (the MySQL/Innodb default), which means that &lt;code&gt;SELECT&lt;/code&gt; results are isolated within a transaction.
Uncommitted writes to a table from another transaction will not be visible to this transaction.
We compare the 95th percentile latency and number of transactions per second (tps) against MySQL.&lt;/p&gt;
&lt;h2 id="tables"&gt;Tables&lt;a class="anchor-link" aria-label="Link to heading" href="#tables"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is a brief summary of the tables created.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;warehouse&lt;/code&gt; with &lt;code&gt;1&lt;/code&gt; row&lt;/li&gt;
&lt;li&gt;&lt;code&gt;district&lt;/code&gt; with &lt;code&gt;10&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;customer&lt;/code&gt; with &lt;code&gt;30000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;orders&lt;/code&gt; with &lt;code&gt;30000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;new_orders&lt;/code&gt; with &lt;code&gt;9000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order_line&lt;/code&gt; with &lt;code&gt;299293&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;item&lt;/code&gt; with &lt;code&gt;100000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stock&lt;/code&gt; with &lt;code&gt;100000&lt;/code&gt; rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;history&lt;/code&gt; with &lt;code&gt;30000&lt;/code&gt; rows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these tables have primary keys, secondary keys, and foreign keys (even though &lt;code&gt;foreign_key_checks&lt;/code&gt; are disabled).&lt;/p&gt;
&lt;h2 id="transactions"&gt;Transactions&lt;a class="anchor-link" aria-label="Link to heading" href="#transactions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TPC-C randomly selects between &lt;code&gt;5&lt;/code&gt; different transaction types with varying odds.
Each transaction starts with a &lt;code&gt;BEGIN&lt;/code&gt; and ends with &lt;code&gt;COMMIT&lt;/code&gt;.
Without spelling out every query run within a transaction, here is a high-level overview of each transaction.&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;trx_type&lt;/th&gt;&lt;th&gt;run_percent&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;new_order&lt;/code&gt;&lt;/td&gt;&lt;td&gt;43.48%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;payment&lt;/code&gt;&lt;/td&gt;&lt;td&gt;43.48%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;order_status&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4.35%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;delivery&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4.35%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;payment&lt;/code&gt;&lt;/td&gt;&lt;td&gt;4.35%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TOTAL&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;≈100.00%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id="1-new_order"&gt;1. &lt;code&gt;new_order&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#1-new_order"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer order of &lt;code&gt;5&lt;/code&gt; - &lt;code&gt;15&lt;/code&gt; quantity of an item.
The new order is logged in the &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;, and &lt;code&gt;order_line&lt;/code&gt; tables, and the &lt;code&gt;item&lt;/code&gt; and &lt;code&gt;stock&lt;/code&gt; tables are updated accordingly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;43.49% (10/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;25&lt;/code&gt; - &lt;code&gt;65&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;district&lt;/code&gt;, &lt;code&gt;item&lt;/code&gt;, &lt;code&gt;stock&lt;/code&gt;, &lt;code&gt;warehouse&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;district&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;, &lt;code&gt;stock&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="2-payment"&gt;2. &lt;code&gt;payment&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#2-payment"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer making a purchase.
It reads the customer’s payment details (name, address, etc.) from the &lt;code&gt;customer&lt;/code&gt; table, update their account balance, and logs the transaction in the &lt;code&gt;history&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;43.48% (10/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;6&lt;/code&gt; - &lt;code&gt;10&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;district&lt;/code&gt;, &lt;code&gt;warehouse&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;district&lt;/code&gt;, &lt;code&gt;history&lt;/code&gt;, &lt;code&gt;warehouse&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="3-order_status"&gt;3. &lt;code&gt;order_status&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#3-order_status"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer inquiring about their order details.
It performs a series of &lt;code&gt;SELECT&lt;/code&gt; queries into the &lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt; and &lt;code&gt;order_line&lt;/code&gt; tables.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;4.34% (1/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;3&lt;/code&gt; - &lt;code&gt;4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;NONE&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="4-delivery"&gt;4. &lt;code&gt;delivery&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#4-delivery"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a customer’s order getting delivered.
An order is removed from the &lt;code&gt;new_orders&lt;/code&gt; table and the appropriate entries are updated in &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt; and &lt;code&gt;customer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;4.34% (1/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;1&lt;/code&gt; - &lt;code&gt;6&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;customer&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;, &lt;code&gt;new_orders&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="5-stocklevel"&gt;5. &lt;code&gt;stocklevel&lt;/code&gt;&lt;a class="anchor-link" aria-label="Link to heading" href="#5-stocklevel"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:
This transaction simulates a query over existing inventory.
It is a few &lt;code&gt;SELECT&lt;/code&gt; queries that aggregate over the &lt;code&gt;order_line&lt;/code&gt; and &lt;code&gt;stock&lt;/code&gt; tables that count the quantity of certain items.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Percent Run&lt;/strong&gt;:
&lt;code&gt;4.34% (1/23)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;# of SQL Statements&lt;/strong&gt;:
&lt;code&gt;3+&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reads Tables&lt;/strong&gt;:
&lt;code&gt;district&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;stock&lt;/code&gt;, &lt;code&gt;order_line&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writes Tables&lt;/strong&gt;:
&lt;code&gt;NONE&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can explore the TPC-C database in more detail here:
&lt;a href="https://www.dolthub.com/repositories/jcor/sbtest"&gt;https://www.dolthub.com/repositories/jcor/sbtest&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;a class="anchor-link" aria-label="Link to heading" href="#conclusion"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We have been focused on Dolt performance on TPC-C, which aims to simulate a real user experience with an OLTP database.
Over the last few months we have made substantial improvements to TPC-C.
Stay tuned for a future blog describing how we’ve broken the 2x MySQL multiplier on TPC-C.
Have any performance issues? Cut a bug on our &lt;a href="https://github.com/dolthub/dolt/issues"&gt;GitHub issues page&lt;/a&gt;.
Want to talk to anyone on our team? Join &lt;a href="https://discord.gg/gqr7K4VNKe"&gt;our Discord&lt;/a&gt;.&lt;/p&gt;</content:encoded>
      <dc:creator>James Cor</dc:creator>
      <category>technical</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
