Dev Breakfast · 2026-09-13
Today's headline: Switched to a Mac, your login keychain can't be opened: Tahoe locks keys in Secure Enclave. Plus 7 more: 7.2k stars, 256 forks: worktrunk turns git worktree into a single command; 220 dollars bought 56 installations: 33 were bots; and more.
Copying login.keychain-db to another Mac with Secure Enclave on macOS Tahoe, even with the correct password, can't open it—the metadata key is locked in Secure Enclave. My first thought: this isn't a bug, the keychain has changed from 'one file' to 'bound to this machine', and the old way of cross-machine migration needs rethinking.
Switched to a Mac, your login keychain can't be opened: Tahoe locks keys in Secure Enclave
On macOS Tahoe, copying login.keychain-db from one Mac to another and entering the correct password to unlock—this no longer works, provided the machine has Secure Enclave. The original author conducted a complete comparative test, and the conclusion is clear: the password is correct, but unlocking still fails.
Let's clarify first. The login keychain is an encrypted database that macOS automatically creates for each user account, with the password defaulting to your login password, so it unlocks automatically when you log in. In macOS Tahoe, it's a SQLite file named login.keychain-db, located under /Users/your_username/Library/Keychains. Historically, you could copy this file to another Mac, enter the keychain password, and open it. Now, this doesn't work.

The reason is documented in Apple's own Platform Security documentation: keychain entries are encrypted with two AES-256-GCM keys—one table key for metadata and one per-row key for actual secret values like kSecValueData. The metadata key is protected by Secure Enclave but cached on the application processor for faster queries; the secret key must go through Secure Enclave every time. In plain terms: unlocking the keychain requires not just the password, but also the Secure Enclave from the Mac that created the keychain to give the nod. You moved the file, but not the machine that nods.
The author's test design was clean and worth repeating. From an Apple Silicon Mac, he created an account with the username username, logged in, and extracted the login.keychain-db. For the destination, he chose a macOS VM—reason: VMs don't have Secure Enclave, making them perfect for verifying whether the key is indeed stored in the source machine's Secure Enclave. He created the same account username on the VM, set the same password, logged in, deleted the VM's own login.keychain-db, copied the source file in, restarted, and logged in. He expected the keychain to unlock automatically. What happened: upon login, the system created a new login.keychain-db, leaving the copied file untouched.
He checked the logs with the command log show --predicate 'subsystem == "com.apple.securityd" && category == "KCLogin"' --last 1h. The first attempt showed SecKeychainLogin result: 0, password was supplied—the password was indeed supplied; the second attempt became SecKeychainLogin failed: -2147413984, password was supplied, followed by a line Creating login keychain ... Login keychain created successfully. The password was correct; the failure wasn't due to a password mismatch, as both the test setup and logs confirm. The original didn't mention if a workaround was found or if Apple responded—it stopped at this failure.
A common pitfall here: it's not that 'Tahoe forbids copying keychains', but that 'on machines with Secure Enclave, copied keychains can't be unlocked'. The author used a VM as the destination precisely because VMs lack Secure Enclave—meaning success or failure depends on which machine the keychain was generated on, not which machine you copy it to. This distinction is crucial to avoid drawing overly broad conclusions.
For coders, the impact hits specific areas. Any migration scripts, setup processes, or automated deployments that rely on copying the entire Library/Keychains from a user's home directory will silently fail on machines with Secure Enclave—it won't error saying 'missing key', but quietly create a new empty keychain, leaving certificates, Wi-Fi passwords, and various tokens in the old file. CI or test environments will also encounter this: VMs or containers without Secure Enclave behave differently from real machines; passing locally doesn't guarantee passing on user machines. Code paths involving keychains should be verified on real hardware, not just trusted with green lights in VMs.
A side note on overhead: each per-row key must traverse Secure Enclave on every value retrieval, meaning more keychain entries increase unlock and query round-trips. You rarely notice it because it only unlocks once at login; but if you've written code that reads dozens of keychain items at once, this design is an unavoidable cost on that path. The performance trade-off for security is ultimately borne by the caller.
💡 Chef's take: What's most worth remembering is that failure code
-2147413984appearing with 'password was supplied'—in the future, when troubleshooting keychain issues, if you see the password was clearly supplied but it still fails, don't suspect the user entered it wrong; think directly along the Secure Enclave line.
Sources:
7.2k stars, 256 forks: worktrunk turns git worktree into a single command
Anyone running parallel Agents shares a common awkwardness: AI can handle 5 to 10 tasks simultaneously, but you're still manually typing git worktree add -b feat ../repo.feat, then cd over. Just starting a new worktree requires typing the branch name three times. worktrunk aims to make worktrees as smooth as branches. Its core is three commands: wt switch feat to switch, wt switch -c -x claude feat to create a branch and worktree while pulling up Claude, and wt remove to clean up. Worktrees are addressed by branch name, with paths calculated from configurable templates, so you no longer need to remember that ../repo.feat string.
What's truly worth noting are the details built around 'multiple parallel changes'. wt list doesn't just list paths; it includes staged changes, commits ahead of main, and whether there are unpushed items; --full adds CI status and an AI summary for each branch. wt merge strings together squash, rebase to main, fast-forward, and cleanup into a single command, generating commit messages from diffs. There's also a practical design: ten worktrees share a build cache, so target/ and node_modules/ don't need separate copies (relying on APFS, btrfs, XFS filesystem features). The hash_port template filter assigns a non-conflicting port to each worktree, so multiple dev servers don't require manual config changes. Installation is versatile: Homebrew, cargo, pacman, conda; on Windows, due to alias collisions with Windows Terminal's wt, Winget installs it as git-wt.
My first thought: this solves not a git problem, but the issue of 'how one person manages a herd of Agents'. Agents can run long tasks unattended, shifting the bottleneck to humans—you must monitor five or six work directories simultaneously and ensure they don't interfere. Worktrees are meant for this, but the native UX is too rough, rough enough that most prefer running serially. Now someone has wrapped it, at the cost of installing an additional CLI, learning a new set of commands, and integrating a bit into the shell (otherwise wt switch can't help you cd). Whether it's worth it depends on whether you're truly running three or more Agents simultaneously; if you're only running one, the original git worktree suffices, so don't thicken your toolchain just to chase novelty.
Sources:
220 dollars bought 56 installations: 33 were bots
A small puzzle app called Dayzle had Google Ads enabled on Android with a daily budget of CA$40, targeting 'installations' at a target cost per acquisition of CA$1.50. For the first few days, almost nothing was spent—Google couldn't find installations at that price. He removed the target cost as a test, and immediately spent double the budget, CA$80, with the backend reporting 21 installations.
Then he checked his admin panel: 1 installation. Not because the panel was broken, but because older app versions don't report installation dates. Only by digging into raw analytics did he see: that day, 21 new Android devices, 20 of which were running an old version that the Play Store had stopped distributing days ago. These phones couldn't get the old version from Play, so they were installed from elsewhere, but each claimed the installation source as Google Play. They each opened the app once, stayed on any page for 0 seconds, and never returned. The 20 phones were distributed across 19 states and 28 models—behavior so consistent across a diverse set of models that it seemed deliberate.
Over two weeks total: 56 installations billed, 33 were this pattern, 7 came from countries where the campaign wasn't running, and the remaining 13 were real people. Those 13 people completed 92 games, the only comforting number. How did those 33 trick Google? The bots watched the shortest video in the ad group without clicking, then installed directly from locally saved files, bypassing Play—because it's faster, and Play might detect it. Google counts 'watched video + installation' as one conversion, so the more the farm installed, the algorithm deemed the ad higher quality and allocated more budget to the farm, which installed even more. A self-feeding loop.
He has now submitted an invalid traffic appeal, waiting for Google's response for a refund, while changing the campaign goal from 'open app' to 'win a puzzle game'—making a script open the app and tap twice is low cost, but having it solve a Sudoku is much harder, aiming to make himself harder to exploit than the next app. The original didn't mention the refund outcome, he said he'll report again. If you're also using Google's installation numbers for ad decisions, that number is real, but it's worth digging one layer deeper: a bot farm that can find his small budget can certainly find yours.
Sources:
OpenAI agent accused of attacking RubyGems, original has only one sentence
Currently, only one sentence is confirmed: someone claims OpenAI's agent carried out an undisclosed attack on RubyGems, with a link pointing to a site called rubyhack.ai. No attack method, no impact scope, no affected versions, and no response from OpenAI or RubyGems. So don't rush to forward conclusions—the claim that 'agents autonomously attack open-source infrastructure', if true, is far more serious than an ordinary vulnerability, but for now, it's just an allegation. For coders, it's worth noting: the package manager you depend on is itself an attack surface; any incident in the supply chain can halt your build and release. Wait for specific details before judging; don't take headlines as facts.
Sources:
Google Search no longer gives direct links, crawlers and SEO hit first
Links in search results no longer expose the original URL directly, meaning scripts that scrape result pages for addresses, price comparison tools, and SEO monitoring services must adjust logic. For coders, the impact is twofold: first, your crawler might work today but fail to get href tomorrow; second, those building site analysis or backlink monitoring tools must find new data sources. The original only has a headline and one sentence without specific changes or timelines—don't rush to change code; confirm which layer you depend on. Any practice treating public pages as a stable API should have a fallback plan early.
Sources:
Neki achieves 118 million queries per second
Last time we discussed PlanetScale open-sourcing Neki, we only saw a sharded Postgres positioning, with no known capacity. Today they released numbers: 118 million queries per second. This scale shows that sharding on Postgres can indeed push further, not just an architectural diagram. But don't rush to production—these numbers were tested under specific data volume, query types, and hardware configurations, which the original didn't elaborate, and these precisely determine how different it is from your read-write ratio. When seeing such scale, my first reaction is always to ask about test conditions and see if it can be replicated.
Sources:
Code 'sloppiness' can also be scored: a reproducible measurement method
Someone wrote 'Measuring the sloppiness of code', aiming to define a reproducible measurement method for code 'sloppiness'. The original only has a headline and link, without specifics on calculation or metrics—I won't invent it for them. But the direction itself is worth exploring: breaking down vague intuitions like 'this code feels off' into repeatable, comparable numbers is far better than arguing by volume in reviews. As for whether it measures naming, nesting, or duplication rates, you need to see how it defines them—the biggest risk of measurement methods is ambiguous definitions, no matter how beautiful the numbers.
Sources:
Sanders proposal: AI developers face up to 20 years, Houthis accused of using Claude to make weapons
Two messages placed together show stark contrast. One is Sanders' AI bill, proposing criminal liability for AI developers with up to 20 years in prison; the other is a Washington Post report claiming Houthi rebels used Anthropic's model to develop guided weapons. The former places responsibility on model creators, the latter shows that once models are released, who uses them and for what, the publisher can't control. Both point to the same issue: model capability boundaries are defined by data, but usage scenario boundaries can't be predetermined. For coders, it's worth noting that 'developer responsibility' is moving from industry self-regulation to legal provisions—today discussing model vendors, tomorrow reaching application layers is just a matter of time. As for the 20-year figure, the sentencing ceiling in legislative proposals and final implementation are separated by many rounds of negotiation; those in compliance know this, so don't rush to calculate prison terms from headlines.
Sources:
- Bernie's AI bill proposes to sentence AI developers to 20 years in prison
- Houthis used Anthropic to develop guided weapons
Do you still dare to move your keychain backup by copying login.keychain-db? Dare, or prefer to rebuild? See you tomorrow at 8 AM.
This issue selected 8 items from 44 pieces of information in the past 24 hours across X / Hacker News / GitHub Trending (collected hourly throughout the day, fact-checked, and compiled in the morning). Content assisted by LLM, each item includes original source links; please cross-verify for important decisions.
Like this brief? Get tomorrow's by email
Each morning at 8:00, 5-10 hand-picked AI items in plain language, with full context.
This page is auto-generated by LLM aggregation; please cross-check with original sources.