New AI tools by IFTTT
Discussion | Link
Browse all AI articles. Use filters to narrow down results.
Discussion | Link
Joshua Achiam spent nearly nine years at OpenAI researching AI safety and made a memorable appearance in the Musk v. Altman trial.
City officials in Cheyenne, Wyoming, said a Meta data center under construction caused the contamination of the city's wastewater treatment facility. Cheyenne Board of Public Utilities Meta is building a 715,000-square-foot data center campus in Cheyenne, Wyoming. The city said the project is responsible for contaminating part of its recycled water system, used only for irrigation purposes. Meta is working with its contractor to resolve the issue. The city stopped accepting industrial wastewater from all data centers. Officials in the city of Cheyenne, Wyoming, say a massive, under-construction Meta data center campus located just south of the city is responsible for contaminating part of its recycled water system. Cheyenne's Board of Public Utilities said in recent public notices that water discharged by Goat Systems, a Meta contractor at the site, contaminated the city's wastewater treatment facility with a rare bacterium. That facility includes Cheyenne's reuse water system, which is used for irrigation purposes only, a board spokesperson said. The system cleans used water so it can be safely released back into the environment or reused for watering things like parks and golf courses. The bacterium did not enter the city's drinking supply, city officials said. "We were able to connect the Meta Data Center campus to this through sampling their site and it was determined to be through their fill-and-flush discharge that the bacteria was introduced to the system," Erin Lamb, a spokesperson for the Board of Public Utilities, told Business Insider on Tuesday. Fill-and-flush operations are a cooling system for data centers in which water is periodically flushed from pipes, discarded, and then replenished with new water. Some data centers now use a "closed-loop" system that recycles the same water within the facility. The board's public notice characterized the infraction as "significant noncompliance" and revoked Goat Systems' "industrial discharge privileges for fill and flush operations." While the board posted the notice on July 2, it said the operations were halted on March 24. Goat Systems, the Meta contractor, "immediately ceased discharge of wastewater from the fill and flush operation" after it was notified of the pollutant, Cheyenne's Board of Public Utilities said. A representative for Goat Systems could not be reached for comment by Business Insider. A Meta spokesperson told Business Insider the company is working with its general contractor, Fortis, to resolve the issue. "When the board shared that it found a substance in the city's wastewater — not public drinking water — Fortis immediately stopped discharging industrial wastewater and began hauling it offsite," the spokesperson said. "Fortis also began its own water testing with an independent environmental specialist, which has found no trace of the substance." A spokesperson for Fortis said the company "takes its environmental obligations seriously and will continue to work constructively with BOPU and all relevant authorities as this matter is fully resolved." The Cheyenne Board of Public Utilities said in its notice that it would pause accepting any industrial water discharge from any data center, whether it's a fill-and-flush or closed-loop system. The board said the bacterium it found in the wastewater was Cupriavidus gilardii. Although infections are rare, direct exposure can pose a risk to older people or those who are immunocompromised. Laboratory staff identified the bacterium during a wastewater sampling in February, the board said. "Over the past two months, BOPU staff have undertaken significant remediation efforts, including draining and disinfecting the entire reuse water system and Prairie View Pond to eliminate any remaining bacterial presence," the board said in its notice. "To prevent potential migration throughout the reuse distribution network, all affected irrigation systems were temporarily converted to potable water supplies." Lamb, the spokesperson for BOPU, told Business Insider that the agency plans to hold a press conference on the matter in the next week or so. Meta announced the $800 million, 715,000-square-foot data center development in 2024. Once the campus is fully operational, Meta says it will be wholly sustainable. The company said it aims to be water-positive by 2030, meaning it will restore more water than it consumes. "The Cheyenne Data Center will be optimized for our AI workloads and help people connect, build communities, and grow their businesses," Meta said at the time of its announcement. Data centers have become a divisive topic. Tech companies are spending billions of dollars to develop the facilities that power their AI products. They say data centers can generate economic growth, create jobs, and push the US ahead in the AI race against China. Critics, however, are much less enthused. Many Americans are pushing back against data centers and don't want them anywhere near their communities. They're concerned that the sprawling facilities will negatively impact water resources, worsen air quality, increase noise levels, and interfere with their quality of life. Some protesters have swarmed local planning meetings, created petitions, and taken legal action to stop construction. In response, a handful of legislators have taken steps to place parameters around data center developments or ban them altogether. At the federal level, Sens. Bernie Sanders of Vermont and Alexandria Ocasio-Cortez of New York proposed a moratorium on AI data centers. The data center industry is still speeding full steam ahead, however. By the end of 2025, there were over 1,400 data centers built or approved for construction in 45 states and Washington, DC. Read the original article on Business Insider
Squeeze on Rust Belt electricity bills threatens Trump’s manufacturing plan.
The phishing campaign uses several tactics, including nested redirects, to evade detection and steal credentials from unsuspecting targets.
Apple and Broadcom extended their chip partnership through 2031 as AI hardware demand raises pressure on suppliers, pricing, and device costs. The post Apple Extends Broadcom Deal Through 2031: What It Means for AI appeared first on TechRepublic.
Varonis reported the flaw to Google in late 2025 and it has been addressed, but it reminds defenders to take a fresh look at their AI Infrastructure security.
There's still a slew of questions about why some people develop alpha-gal syndrome.
Meta: Meta launches Muse Image in Meta AI, Instagram, and WhatsApp, and previews Muse Video, the first media generation models from its Superintelligence Labs — We're excited to launch Muse Image and preview Muse Video, the first media generation models developed by Meta Superintelligence Labs.
Rebecca Yarros is working on the fourth "Empyrean" novel. Casey Paul/MLB Photos via Getty Images Rebecca Yarros announced that she is writing book four of the "Empyrean" series. The "Fourth Wing" author published the latest book in the series, "Onyx Storm," in January 2025. The author has offered hints about how Violet Sorrengail's story will continue. Spoilers ahead. Rebecca Yarros' next "Fourth Wing" novel is on the way. It's been over a year since Yarros released "Onyx Storm," the third installment in her "Empyrean" series. Following "Fourth Wing" and "Iron Flame," the novel continues the story of Violet Sorrengail's journey to become a dragon rider and fight forces of dark magic at Basgiath War College. The series is set to comprise five novels, all published by Entangled's fantasy imprint, Red Tower. "Onyx Storm" — the fastest-selling adult novel released in 20 years — ended on a cliffhanger, so Yarros' readers have been clamoring to get their hands on the next romantasy novel in the series since the moment they finished book three. In a March 2026 Instagram post, Yarros said she's officially writing book four. She's been sharing updates on her progress since then, building excitement for what's to come. The rest of this article has spoilers for the "Empyrean" series. Yarros started writing the fourth 'Empyrean' novel in March 2026 Yarros released the first three books in the "Empyrean" series in under two years. "Fourth Wing" came out in April 2023, "Iron Flame" was released in October 2023, and "Onyx Storm" hit shelves in January 2025. Yarros made clear she wouldn't be writing book four at the same pace. Speaking at an engagement in Philadelphia on January 25, 2025, Yarros said she wouldn't commit to a release date, as she was planning to write a contemporary novel and spend time with her family first. Yarros later told Elle that she intended to rest before returning to writing in part because the amount of work she did in recent years wasn't good for her mentally or physically, as she has chronic medical conditions, including Ehlers-Danlos syndrome, a connective tissue disorder, and POTS, an autonomic nervous system disorder. She kept her word, keeping largely quiet about book four for the rest of 2025. Then, on February 8, 2026, she shared on Instagram that she had begun plotting, and on March 19, 2026, she posted a Reel announcing she had begun writing the next "Empyrean" novel. Rebecca Yarros. Rebecca Yarros/Red Tower Books In the Reel, Yarros walks up to a board and writes "#4" at the top. "And now that my latest contemporary novel is off to my editor, I'm back writing in the Empyrean world for the foreseeable future," Yarros captioned the post. "Let's ride." The author has posted a few updates about her progress since then, most notably on June 13. She shared a short video clip on Instagram of an ocean view and said in her caption that she would be spending the summer writing at the beach. "Our home is undergoing distractingly noisy work, which gives us the perfect excuse to pack up our kids and spend the summer on Deverelli time while I'm writing book 4," she said. Deverelli is an isle that Violet visits in "Onyx Storm," and it plays a key role in the book's plot. "I've already got my desk set up here (pink binders and all), and I'll be spending these beautiful days with some riders you may know, and their dragons," Yarros continued her caption. "I feel so lucky to have such a breathtaking view for inspiration while I'm writing!" It will still be a while before the fourth "Empyrean" book hits bookshelves, but fans can rest assured that Yarros will be focused on the novel in the coming months, as she has continued to tease on her Instagram. On July 1, she posted dates for "Fourth Wing" nights at baseball games in the coming months, noting in the caption that she could attend only two of the 12 events listed because she is "concentrating on writing book 4." Then, on July 3, she posted a black and white photo of a calendar page with "Happy birthday Violet!" written on it and sunglasses sitting atop it. Yarros had drawn 12 empty boxes in a list below the message, and she wrote in her caption, "Time to check these boxes off with word count for the day!" The boxes may be her writing checklist, but some fans think Yarros' list may be nodding to the 12 hours Violet can't remember from the final pages of "Onyx Storm." The missing hours are just one element of the dramatic end of "Onyx Storm" that left fans reeling. The fourth book will hopefully address unanswered questions from 'Onyx Storm' There was no shortage of drama at the end of "Onyx Storm." First, Xaden Riorson took more power from the earth, speeding up his transition into a dark magic wielding venin, one of of the main antagonists in the series, and sending him down a path toward evil; another unnamed dragon rider turned venin; the dragon Andarna returned to Violet after her time away with the irid dragons; and Violet woke up with a wedding ring and blessing of her marriage to Xaden from the goddess Dunne, with no memory of the last 12 hours of her life. In the book's final line, her fellow rider Imogen Cardulo reveals she used her signet power to wipe Violet's memory of the night — at her request. Violet's brother, Brennan, also revealed that six dragon eggs and four riders, including Xaden and his best friend, Garrick Tavis, are missing. "Onyx Storm" by Rebecca Yarros. Red Tower Hopefully, the fourth book in the "Empyrean" series will reveal what happened between Violet and Xaden, where Xaden and the other missing riders are, the location of the missing eggs, what Andarna learned from her time with the irids, and how Xaden's additional use of his venin powers harmed his soul. Likewise, Violet will likely still be searching for a cure to save Xaden from being venin, but as his wife, she also becomes the Duchess of Tyrrendor. She will have new power and responsibility in his absence, and readers will have to wait to see how she balances her new role as she develops her signets. Yarros shared some clues for book four while promoting 'Onyx Storm' Yarros went on an "Onyx Storm" book tour after the book's January 2025 release, offering some insight into the series' future as she connected with fans. For instance, at an event in Los Angeles on January 21, 2025, Yarros said, "Someone you love won't make it in book four." That comment isn't that surprising, as beloved characters have died in each installment of the series. However, Yarros got more specific with her hints as her book tour continued. At an event in St. Louis on January 31, 2025, Yarros shared that readers have more to discover about the isles Violet explores in "Onyx Storm." When host Lexi Ryan asked her why there was no map of the isles included in "Onyx Storm," Yarros said it "was deemed to be too spoilery" by her editorial team, suggesting Violet doesn't know all she will about the isles by the end of book three. Rebecca Yarros in January 2025. CJ Rivera/Invision/AP Then, speaking at an event in Denver on February 2, 2025, Yarros shared clues about who Xaden's new venin brother could be. "I would pay attention to who's missing at the end," she said. "I would pay attention to someone who feels like whatever they have given is not enough, which is always the case when you turn venin." Fans think Xaden's cousin Bodhi Durran, Garrick, or even Violet's brother Brennan could fit that description at the end of "Onyx Storm." Yarros also discussed a plot device she uses that may have consequences for the series. After riders bond a dragon at threshing at Basgiath, the rider announces the dragon's name to the Scribes so it can be recorded. However, Yarros pointed out to fans that the dragons never speak their names directly to the Scribes. It's possible some riders don't share their real names or that dragons lie to their riders, which could help the children of rebels bond dragons their relatives previously bonded, giving them second signet powers. The potential for faux dragon identities could also have other ramifications for the series. Speaking more on signet powers in Denver, Yarros said readers had only seen "like 10%" of Violet's dream-walking abilities, in part because others who developed the power would have been killed, making it difficult for Violet to learn how to use the signet. "There's probably one person alive that can train her," Yarros said, though she gave no information about who that person is. She also said Xaden's "inntinnsic" signet has only reached "like 50%" of its potential, so his mind-reading abilities will likely grow in book four. In addition, Yarros revealed at the Los Angeles Festival of Books in April 2025 that she has a title picked out for the fourth book, though she didn't say what it was. Yarros offered more hints about the next 'Empyrean' novel in late 2025 On October 24, 2025, Yarros appeared at Romantasy Bookcon in Orlando, hosted by Fabled Fantasy Events. She spoke with the hosts of the "Fantasy Fangirls" podcast, Lexi Ayala and Nicole Holleman, about the "Empyrean" series, and Yarros offered hints and sneak peeks at book four. For instance, Yarros discussed how the dramatic ending of "Onyx Storm" will impact the next book, telling Ayala and Holleman that readers will know what happened to Violet during her 12 missing hours by the novel's end. Likewise, when the duo asked Yarros about a scene she was excited to write in the next "Empyrean" novel, she said, "I'm really excited to write the moment Violet realizes why Xaden married her. That I am pumped for." Of course, Xaden loves Violet, but considering he had turned venin and the marriage would give Violet political power as the Duchess of Tyrrendor, there is likely more to their union than meets the eye. Yarros also warned that readers "should really be prepared in book four to see Xaden enter his villain era," indicating his marriage to Violet won't stop him from going full venin in the next "Empyrean" novel. Rebecca Yarros has been offering hints about the next "Empyrean" novel. Jaiden Tripi/Getty Images The "Fantasy Fangirls" also asked Yarros if Imogen had been wiping Violet's memories at other times in the "Empyrean" series, which many readers had been wondering after the ending of "Onyx Storm." Rather than giving a direct answer, Yarros said, "I think it depends on what you believe of Imogen's character. What has Imogen shown you of her character? What has she told Violet about her signet?" In the "Empyrean" series, readers only see Imogen wipe memories when Violet or Xaden specifically asks her to. However, much of the series is only told from Violet's limited perspective, so there may have been occasions when Imogen wiped people's memories without Violet's knowledge. Likewise, Yarros addressed some of her readers' concerns surrounding Bodhi, as there is a contingent of "Empyrean" fans who think Xaden's cousin has feelings for Violet, saying, "Bodhi has a thing for what Xaden has. But he doesn't want to." Her response indicates that Bodhi may be jealous of Xaden rather than in love with Violet. And considering he is one of the potential candidates to have turned venin at the end of "Onyx Storm," Yarros' response is particularly eyebrow-raising. Yarros also gave some hints about the structure of the next book, telling Ayala and Holleman that she plans to offer multiple points of view in the narration of book four. She even specified that some portion of the book will be told from Sloane Mairi's perspective. Finally, Yarros told readers to pay attention to the black dragons in the "Empyrean" series, encouraging them to ask themselves why there are so few black dragons in the world, adding that it's "very relevant" that two new baby black dragons hatched in "Iron Flame." Hopefully, Yarros' clues can tide readers over until book four is published. In the meantime, they can read other romantasy novels to make the wait a bit more bearable. Read the original article on Business Insider
Texas win at 5th Circuit left in place as attempts to overturn age law continue.
Ivy League alums sat in the White House for 32 uninterrupted years until Joe Biden's presidency. Brooks Kraft LLC/Corbis via Getty Images Sixteen US presidents were educated at Ivy League colleges and universities. Joe Biden was the first US president since Ronald Reagan not to have attended an Ivy League school. During his presidency, Trump has taken on Harvard University, the alma mater of 8 former presidents. Admissions at some of the top colleges and universities in the US have become increasingly competitive as tuition costs continue to climb, but for the nation's top students, earning a spot next to a former president on the alumni list could be worth the hassle. The Ivy League has long been a breeding ground for world leaders, inspiring innovators, and many US presidents. Among the eight Ivy League schools, Harvard has educated the most US presidents — eight — followed by Yale, with five. On the other hand, a few of the Ivies have not yet seen one of their students become US president: Brown University, Cornell University, and Dartmouth College. Most presidents in recent US history graduated from an Ivy League school. In fact, from the end of Ronald Reagan's term in 1989 until the beginning of Joe Biden's in 2021, the presidency was occupied by Ivy League alums. Donald Trump's return to office in 2025 restored an Ivy League alum to the White House. Here are the presidents who attended Ivy League institutions and the universities they attended, ranked by the number of US presidents they have educated. Princeton University Two US presidents have graduated from Princeton. Photo Spirit/Shutterstock The Ivy League's ties with the US presidency go back to the nation's founding. In 1771, founding father James Madison, who served as the fourth US president from 1809 to 1817, graduated with a bachelor's degree from Princeton University, then called the College of New Jersey. Woodrow Wilson, who was president from 1913 to 1921, graduated from the College of New Jersey in 1879. University of Pennsylvania Two US presidents, including Donald Trump, have attended the University of Pennsylvania. f11photo/Shutterstock The ninth US president, William Henry Harrison, who served the shortest presidency in US history in 1841, attended the University of Pennsylvania, where he studied medicine, but he withdrew before his expected graduation date of 1793. In 1968, Trump graduated with a bachelor's in economics from Penn's Wharton School, which he had transferred to from Fordham University two years prior. Columbia University Three US presidents have attended Columbia University. peterspiro/Getty Images/iStockphoto After graduating from Harvard College — Harvard University's undergraduate school — in 1880, Theodore Roosevelt, the 26th US president, attended Columbia University's law school, from which he eventually withdrew. His fifth cousin, Franklin D. Roosevelt, the 32nd US president, attended Columbia Law School in 1904 after graduating from Harvard College a year prior, but he also withdrew from the program. In 1981, Barack Obama, then a junior at Occidental College, transferred to Columbia University, where he graduated with a bachelor's in political science in 1983. Yale University Five US presidents have graduated from Yale University. REUTERS/Shannon Stapleton The 27th US president, William Howard Taft, graduated from Yale University in 1878. His father, Alphonso Taft, who graduated from Yale in 1833, had founded the Skull and Bones secret society while at the school — his son, as well as two other US presidents, would become members of that society. In 1941, the 38th US president, Gerald Ford, graduated from Yale Law School. In 1973, Bill Clinton, who was the president from 1993 to 2001, graduated from the same school. George H. W. Bush, who was president from 1989 to 1993, graduated from Yale with a bachelor's degree in economics in 1948. His son George W. Bush, the 43rd US president, graduated from the school with a bachelor's in history in 1968. Both Bush presidents were members of the Skull and Bones secret society. Harvard University Eight US presidents have graduated from Harvard University, more than from any other school. miroslav_1/Getty Images Harvard University has ties to the US presidency dating back to the nation's founding. The first US vice president and second US president, John Adams, attended Harvard University, from which he graduated with a bachelor's degree in 1755 and a master's degree in 1758. His son John Quincy Adams, the sixth US president, graduated from Harvard College in 1787. In 1845, Rutherford B. Hayes, who was president from 1877 to 1881, graduated from Harvard Law School. The 26th US president, Theodore Roosevelt, graduated from Harvard College with a bachelor's degree in 1880, as did the 32nd US president, Franklin D. Roosevelt, in 1903. In 1940, the 35th US president, John F. Kennedy, graduated from Harvard with a bachelor's in international affairs. In his college essay, he famously expressed his desire to attend the school from which his father, Joseph P. Kennedy, graduated in 1912: "To be a 'Harvard man' is an enviable distinction, and one that I sincerely hope I shall attain." In 1975, George W. Bush graduated from the school with an MBA, the only US president to have earned this degree. In 1991, Obama graduated from Harvard Law School, the most recent US president to attend the school. Editor's note: This story was originally published in June 2025. It was most recently updated in July 2026. Correction: June 10, 2025 — An earlier version of this story misstated when Theodore Roosevelt graduated from Harvard College. It was in 1880, not 1876. It also misstated when William Howard Taft graduated from Yale University. It was in 1878, not 1978. Read the original article on Business Insider
Open source models’ success isn’t coming at the expense of frontier labs. Instead, they each seem to capture two phases of the same life cycle.
Microsoft is the latest Silicon Valley giant to cut back on its AI spending.
As much as 50 percent of some teams affected by reductions, and more could be coming.
<p>This morning I released <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0">sqlite-utils 4.0</a>, the 124th release of that project and the first major version bump since <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v3-0">3.0</a> in November 2020. In addition to some small but significant breaking changes (described in <a href="https://sqlite-utils.datasette.io/en/stable/upgrading.html">this upgrade guide</a>), this version introduces three major features: <strong>database migrations</strong>, <strong>nested transactions</strong> (via a new <code>db.atomic()</code> method), and support for <strong>compound foreign keys</strong>.</p> <h4 id="database-schema-migrations-using-sqlite-utils">Database schema migrations using sqlite-utils</h4> <p>Schema migrations define a sequence of changes to be made to a SQLite database, plus a mechanism for tracking which migrations have been applied and applying any that are found to be pending.</p> <p>Migrations are defined in Python files using the <a href="https://sqlite-utils.datasette.io/en/stable/python-api.html">sqlite-utils Python library</a>, which includes a powerful <code>table.transform()</code> method providing <a href="https://sqlite-utils.datasette.io/en/stable/python-api.html#transforming-a-table">enhanced alter table capabilities</a> that are not supported by SQLite's <code>ALTER TABLE</code> statement.</p> <p>(<code>table.transform()</code> implements the pattern <a href="https://www.sqlite.org/lang_altertable.html#otheralter">recommended by the SQLite documentation</a> - create a new temporary table with the new schema, copy across the data, then drop the old table and rename the temporary one in its place.)</p> <p>Here's an example migration file which creates a table called <code>creatures</code>, adds an additional column to it in a second step, then changes the types of two of the columns in a third:</p> <pre><span class="pl-k">from</span> <span class="pl-s1">sqlite_utils</span> <span class="pl-k">import</span> <span class="pl-v">Migrations</span> <span class="pl-s1">migrations</span> <span class="pl-c1">=</span> <span class="pl-en">Migrations</span>(<span class="pl-s">"creatures"</span>) <span class="pl-en">@<span class="pl-en">migrations</span>()</span> <span class="pl-k">def</span> <span class="pl-en">create_table</span>(<span class="pl-s1">db</span>): <span class="pl-s1">db</span>[<span class="pl-s">"creatures"</span>].<span class="pl-c1">create</span>( {<span class="pl-s">"id"</span>: <span class="pl-s1">int</span>, <span class="pl-s">"name"</span>: <span class="pl-s1">str</span>, <span class="pl-s">"species"</span>: <span class="pl-s1">str</span>}, <span class="pl-s1">pk</span><span class="pl-c1">=</span><span class="pl-s">"id"</span>, ) <span class="pl-en">@<span class="pl-en">migrations</span>()</span> <span class="pl-k">def</span> <span class="pl-en">add_weight</span>(<span class="pl-s1">db</span>): <span class="pl-s1">db</span>[<span class="pl-s">"creatures"</span>].<span class="pl-c1">add_column</span>(<span class="pl-s">"weight"</span>, <span class="pl-s1">float</span>) <span class="pl-en">@<span class="pl-en">migrations</span>()</span> <span class="pl-k">def</span> <span class="pl-en">change_column_types</span>(<span class="pl-s1">db</span>): <span class="pl-s1">db</span>[<span class="pl-s">"creatures"</span>].<span class="pl-c1">transform</span>(<span class="pl-s1">types</span><span class="pl-c1">=</span>{<span class="pl-s">"species"</span>: <span class="pl-s1">int</span>, <span class="pl-s">"weight"</span>: <span class="pl-s1">str</span>})</pre> <p>Save that as <code>migrations.py</code> and run it against a fresh database like this:</p> <div class="highlight highlight-source-shell"><pre>uvx sqlite-utils migrate data.db migrations.py</pre></div> <p>Then if you check the schema of that database:</p> <div class="highlight highlight-source-shell"><pre>uvx sqlite-utils schema data.db</pre></div> <p>You'll see this SQL:</p> <div class="highlight highlight-source-sql"><pre><span class="pl-k">CREATE</span> <span class="pl-k">TABLE</span> "<span class="pl-en">_sqlite_migrations</span>" ( <span class="pl-s"><span class="pl-pds">"</span>id<span class="pl-pds">"</span></span> <span class="pl-k">INTEGER</span> <span class="pl-k">PRIMARY KEY</span>, <span class="pl-s"><span class="pl-pds">"</span>migration_set<span class="pl-pds">"</span></span> <span class="pl-k">TEXT</span>, <span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span> <span class="pl-k">TEXT</span>, <span class="pl-s"><span class="pl-pds">"</span>applied_at<span class="pl-pds">"</span></span> <span class="pl-k">TEXT</span> ); <span class="pl-k">CREATE</span> <span class="pl-k">UNIQUE INDEX</span> "<span class="pl-en">idx__sqlite_migrations_migration_set_name</span>" <span class="pl-k">ON</span> <span class="pl-s"><span class="pl-pds">"</span>_sqlite_migrations<span class="pl-pds">"</span></span> (<span class="pl-s"><span class="pl-pds">"</span>migration_set<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span>); <span class="pl-k">CREATE</span> <span class="pl-k">TABLE</span> "<span class="pl-en">creatures</span>" ( <span class="pl-s"><span class="pl-pds">"</span>id<span class="pl-pds">"</span></span> <span class="pl-k">INTEGER</span> <span class="pl-k">PRIMARY KEY</span>, <span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span> <span class="pl-k">TEXT</span>, <span class="pl-s"><span class="pl-pds">"</span>species<span class="pl-pds">"</span></span> <span class="pl-k">INTEGER</span>, <span class="pl-s"><span class="pl-pds">"</span>weight<span class="pl-pds">"</span></span> <span class="pl-k">TEXT</span> );</pre></div> <p>The <code>_sqlite_migrations</code> table is used to keep track of which migration functions have been run. The <code>creatures</code> table above is the schema after all three migrations have been applied.</p> <p>To see a list of migrations, both pending and applied, run this:</p> <div class="highlight highlight-source-shell"><pre>uvx sqlite-utils migrate data.db migrations.py --list</pre></div> <p>Output:</p> <pre><code>Migrations for: creatures Applied: create_table - 2026-07-07 17:58:41.360051+00:00 add_weight - 2026-07-07 17:58:41.360608+00:00 change_column_types - 2026-07-07 18:01:15.802000+00:00 Pending: (none) </code></pre> <p>If you don't specify a migrations file, the <code>sqlite-utils migrate data.db</code> command will scan the current directory and its subdirectories for files called <code>migrations.py</code> and apply any <code>Migrations()</code> instances it finds in them.</p> <p>You can also execute migrations <a href="https://sqlite-utils.datasette.io/en/stable/migrations.html#applying-migrations-in-python">from Python code</a> using the <code>migrations.apply(db)</code> method, which is useful for building tools that manage their own database schemas over multiple versions. My own <a href="https://llm.datasette.io/">LLM tool</a> has been using a version of this pattern for several years now, as shown in <a href="https://github.com/simonw/llm/blob/0.31/llm/embeddings_migrations.py">llm/embeddings_migrations.py</a>.</p> <h4 id="prior-art">Prior art</h4> <p>My favorite implementation of this pattern remains <a href="https://docs.djangoproject.com/en/6.0/topics/migrations/">Django's Migrations</a>, developed by Andrew Godwin based on his earlier project <a href="https://github.com/andrewgodwin/south">South</a>. Fun fact: Andrew, Russ Keith-Magee, and I presented our competing approaches to schema migrations for Django on the <a href="https://www.youtube.com/watch?v=VSq8m00p1FM">Schema Evolution panel</a> at the very first DjangoCon back in 2008! My attempt was called <a href="https://simonwillison.net/2008/Sep/3/dmigrations/">dmigrations</a>, developed with a team at Global Radio in London.</p> <p>Django's migrations can be automatically generated from model definitions and include the ability to roll back to a previous version. The <code>sqlite-utils</code> approach is deliberately simpler: unlike Django, <code>sqlite-utils</code> encourages programmatic table creation rather than a model definition ORM, so there isn't anything we can use to automatically generate migrations.</p> <p>I decided to skip rollback, since in my experience it's a feature that is rarely used. With a SQLite project, an easy way to achieve rollback is to create a copy of your database file before you apply the migrations!</p> <h4 id="migrating-from-sqlite-migrate">Migrating from sqlite-migrate</h4> <p>The design of <code>sqlite-utils</code> migrations is three years old now - I had originally released it as a separate package called <a href="https://github.com/simonw/sqlite-migrate">sqlite-migrate</a>, which never quite graduated beyond a beta release.</p> <p>I've used that package in enough places now that I'm confident in the design, so I've decided to promote it to a feature of <code>sqlite-utils</code> to make it available by default to all of the other tools in the growing sqlite-utils/Datasette/LLM ecosystem.</p> <p>I made <a href="https://github.com/simonw/sqlite-migrate/releases/tag/0.2">one last release</a> of <code>sqlite-migrate</code>, which switches it to depend on <code>sqlite-utils>=4</code> and replaces the <code>__init__.py</code> file with the following:</p> <pre><span class="pl-k">from</span> <span class="pl-s1">sqlite_utils</span> <span class="pl-k">import</span> <span class="pl-v">Migrations</span> <span class="pl-s1">__all__</span> <span class="pl-c1">=</span> [<span class="pl-s">"Migrations"</span>]</pre> <p>Any existing project that depends on <code>sqlite-migrate</code> should continue to work without alterations.</p> <h4 id="everything-else-in-sqlite-utils-4-0">Everything else in sqlite-utils 4.0</h4> <p>Here are the release notes for this version, with some inline annotations:</p> <blockquote> <p>The 4.0 release includes some minor backwards-incompatible fixes (hence the major version number bump) and introduces three major new features:</p> <ul> <li> <a href="https://sqlite-utils.datasette.io/en/stable/migrations.html#migrations">Database migrations</a>, providing a structured mechanism for evolving a project’s schema over time. (<a href="https://github.com/simonw/sqlite-utils/issues/752">#752</a>)</li> </ul> </blockquote> <p>I think of migrations as the signature new feature, hence this blog post.</p> <blockquote> <ul> <li> <a href="https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-atomic">Nested transaction support</a> via <code>db.atomic()</code>, plus numerous improvements to how transactions work across the library. (<a href="https://github.com/simonw/sqlite-utils/issues/755">#755</a>)</li> </ul> </blockquote> <p><code>sqlite-utils</code> has long had a confused relationship with database transactions, partly because when I started designing the library back in 2018 I didn't yet have a great feel for how those worked in SQLite itself.</p> <p>Adding migrations to the core library made me determined to finally crack this nut, since transactions make migration systems a whole lot safer and easier to reason about.</p> <p>I ended up building this around a <code>db.atomic()</code> context manager which looks like this:</p> <pre><span class="pl-k">with</span> <span class="pl-s1">db</span>.<span class="pl-c1">atomic</span>(): <span class="pl-s1">db</span>.<span class="pl-c1">table</span>(<span class="pl-s">"dogs"</span>).<span class="pl-c1">insert</span>({<span class="pl-s">"id"</span>: <span class="pl-c1">1</span>, <span class="pl-s">"name"</span>: <span class="pl-s">"Cleo"</span>}, <span class="pl-s1">pk</span><span class="pl-c1">=</span><span class="pl-s">"id"</span>) <span class="pl-s1">db</span>.<span class="pl-c1">table</span>(<span class="pl-s">"dogs"</span>).<span class="pl-c1">insert</span>({<span class="pl-s">"id"</span>: <span class="pl-c1">2</span>, <span class="pl-s">"name"</span>: <span class="pl-s">"Pancakes"</span>})</pre> <p>SQLite supports <a href="https://sqlite.org/lang_savepoint.html">Savepoints</a>, and as a result <code>db.atomic()</code> can be nested to carry out transactions inside of transactions. It's pretty neat!</p> <blockquote> <ul> <li>Support for <a href="https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-compound-foreign-keys">compound foreign keys</a>, including creation, transformation and introspection through <a href="https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-introspection-foreign-keys">table.foreign_keys</a>. (<a href="https://github.com/simonw/sqlite-utils/issues/594">#594</a>)</li> </ul> </blockquote> <p>This came about when I asked a coding agent to review all open issues and PRs for things that should be included in a 4.0 release since they would represent breaking changes if I added them later, and it correctly identified that compound foreign keys were exactly that kind of feature.</p> <p>I started with a breaking change to the <a href="https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-introspection-foreign-keys">table.foreign_keys</a> introspection method, and then decided to see if Claude Fable 5 could handle the more fiddly job of integrating compound foreign key <em>creation</em> into the library. The API design it helped create felt <a href="https://sqlite-utils.datasette.io/en/stable/python-api.html#compound-foreign-keys">exactly right to me</a> - consistent with how the rest of the library worked already.</p> <blockquote> <p>Other notable changes include:</p> <ul> <li>Upserts now use SQLite’s <code>INSERT ... ON CONFLICT ... DO UPDATE SET</code> syntax, detect existing table primary keys automatically and reject records that are missing required primary key values. (<a href="https://github.com/simonw/sqlite-utils/issues/652">#652</a>)</li> </ul> </blockquote> <p>This was the change that first pushed me to consider a breaking-change 4.0 version bump. I built this to help support <a href="https://github.com/simonw/sqlite-chronicle">sqlite-chronicle</a>, which uses triggers to keep track of rows in a table that have been inserted, updated or deleted.</p> <blockquote> <ul> <li> <code>db.query()</code> now executes immediately and rejects statements that do not return rows; use <code>db.execute()</code> for writes and DDL.</li> </ul> </blockquote> <p>Probably the <a href="https://sqlite-utils.datasette.io/en/stable/upgrading.html#python-api-changes">most disruptive breaking change</a> - I've had to update a few places in my own code to switch from <code>db.query()</code> to <code>db.execute()</code> as a result.</p> <blockquote> <ul> <li>CSV and TSV imports now detect column types by default, while inserts into existing tables preserve those tables’ column types. (<a href="https://github.com/simonw/sqlite-utils/issues/679">#679</a>)</li> </ul> </blockquote> <p>The <code>sqlite-utils insert data.db creatures creatures.csv --detect-types</code> flag was a later addition to allow column types (text, integer, real) to be automatically detected based on the data in a CSV. It should be the default, and releasing a 4.0 means I can make it so.</p> <blockquote> <ul> <li> <code>table.extract()</code> and <code>extracts=</code> no longer create lookup table records for all-<code>null</code> values. (<a href="https://github.com/simonw/sqlite-utils/issues/186">#186</a>)</li> </ul> </blockquote> <p>The oldest issue addressed by this release - the underlying bug was opened (by me) in October 2020.</p> <blockquote> <p>See <a href="https://sqlite-utils.datasette.io/en/stable/upgrading.html#upgrading-3-to-4">Upgrading from 3.x to 4.0</a> for details on backwards-incompatible changes.</p> <p>The detailed release notes for the features and fixes shipped during the 4.0 pre-release cycle are available in <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0a0">4.0a0</a>, <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0a1">4.0a1</a>, <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0rc1">4.0rc1</a>, <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0rc2">4.0rc2</a>, <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0rc3">4.0rc3</a> and <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0rc4">4.0rc4</a>.</p> </blockquote> <p>The upgrade guide was entirely written by Claude Fable 5, Claude Opus 4.8 and GPT-5.5. The same is true of the release notes.</p> <p>This is the kind of documentation I've slowly become comfortable outsourcing to the robots. It doesn't need to convince people of anything, or express any opinions - its job is to be as accurate and detailed as possible. I've reviewed the release notes closely and can confirm they are accurate and comprehensive.</p> <h4 id="claude-fable-5-helped-a-lot">Claude Fable 5 helped a lot</h4> <p>I released the first alpha of sqlite-utils 4.0 <a href="https://sqlite-utils.datasette.io/en/stable/changelog.html#a0-2025-05-08">over a year ago</a>. I've been dragging my heels on the stable release because of the amount of work it would take to track down and clean up the many other minor design flaws that a major version number allowed me to take on.</p> <p>Assistance from Claude Fable 5 (and to a lesser extent Opus 4.8 and GPT-5.5) gave me just the boost I needed to overcome inertia and make the most of the time I could afford to spend on this library.</p> <p>Fable has <em>really good taste</em> in API design, and is <a href="https://simonwillison.net/2026/Jun/11/fable-is-relentlessly-proactive/">relentlessly proactive</a> if you give it a more open goal. My most successful prompt was a review task that I issued against what I thought was the last release candidate:</p> <blockquote> <p><code>review the changes on main since the last tagged 3.x release - I am about to ship them as sqlite-utils 4.0, a stable version that promises no backwards-incompatible fixes for a very long time.</code></p> <p><code>review the changelog and upgrade guide, and write yourself scratch scripts to try out all of the new features in v4 - save those scripts but don't commit them</code></p> </blockquote> <p>I tried this with GPT-5.5 xhigh in Codex Desktop and Fable 5 in Claude Code.</p> <p>GPT-5.5 <a href="https://gist.github.com/simonw/823fdecc031371d56dce39537adc0096">wrote 5 Python scripts</a> and didn't turn up anything particularly interesting - its <a href="https://github.com/simonw/sqlite-utils/issues/769#issuecomment-4899982463">final report is here</a>.</p> <p>Fable 5 <a href="https://gist.github.com/simonw/95800bf584f8e437f1cf0d48d9ef81e6">wrote 12 scripts</a>, identified 4 release blockers and 10 additional issues <a href="https://github.com/simonw/sqlite-utils/issues/769#issuecomment-4900034150">in its report</a>, and built a neat <a href="https://gist.githubusercontent.com/simonw/95800bf584f8e437f1cf0d48d9ef81e6/raw/c43918b36a129bba1d2f2a129117aa11c85146c0/12_bug_repros.py">combined repro script</a>, which, when run, output the following:</p> <pre><code>=== 1. Failed db.execute() write leaves an implicit transaction open === in_transaction after failed write: True BUG: table 'other' silently lost when connection closed === 2. Leading ';' bypasses the query() first-token scanner === BUG: raised OperationalError: no such savepoint: sqlite_utils_query BUG: row persisted despite rollback (count=1) === 3. Rejected write PRAGMA via query() still takes effect === BUG: user_version=5 after 'rejected' statement (docs say no effect) === 4. Implicit compound FK resolves pk columns in table order, not PK order === BUG: other_columns reported as ('b', 'a'), should be ('a', 'b') BUG: transform of valid data raised IntegrityError: FOREIGN KEY constraint failed === 5. ForeignKey (now a dataclass) is no longer hashable === BUG: cannot use 'sqlite_utils.db.ForeignKey' as a set element (unhashable type: 'ForeignKey') === 6. Mixed ForeignKey objects and tuples in foreign_keys= rejected === BUG: foreign_keys= should be a list of tuples === 7. insert --csv into an EXISTING table transforms its column types === BUG: existing zip '01234' is now 1234 (column type: int) === 8. insert(pk=, alter=True) regression: InvalidColumns before alter runs === BUG: InvalidColumns: Invalid primary key column ['id'] for table t with columns ['a'] === 9. migrate --stop-before an already-applied migration applies everything === BUG: m2 was applied despite --stop-before m1 (m1 already applied) === 10. ensure_autocommit_on() silently commits an open transaction === BUG: row survived rollback (count=1) - transaction was committed </code></pre> <p>I found myself agreeing with almost all of them. Here's <a href="https://github.com/simonw/sqlite-utils/pull/779">the PR with 16 commits</a> where we worked through them in turn.</p> <p>There's no doubt in my mind that sqlite-utils 4.0 is a significantly higher-quality release than if I had built it without the assistance of the latest frontier models.</p> <p>Tags: <a href="https://simonwillison.net/tags/schema-migrations">schema-migrations</a>, <a href="https://simonwillison.net/tags/projects">projects</a>, <a href="https://simonwillison.net/tags/sqlite">sqlite</a>, <a href="https://simonwillison.net/tags/ai">ai</a>, <a href="https://simonwillison.net/tags/sqlite-utils">sqlite-utils</a>, <a href="https://simonwillison.net/tags/annotated-release-notes">annotated-release-notes</a>, <a href="https://simonwillison.net/tags/generative-ai">generative-ai</a>, <a href="https://simonwillison.net/tags/llms">llms</a>, <a href="https://simonwillison.net/tags/ai-assisted-programming">ai-assisted-programming</a>, <a href="https://simonwillison.net/tags/anthropic">anthropic</a>, <a href="https://simonwillison.net/tags/claude">claude</a>, <a href="https://simonwillison.net/tags/agentic-engineering">agentic-engineering</a>, <a href="https://simonwillison.net/tags/claude-mythos-fable">claude-mythos-fable</a></p>
Discussion | Link
The company confirmed that the issue had been affecting accounts since May, with an additional 200 users banned over the weekend before its team identified and fixed the problem.
Discussion | Link